// WRITE BY AI /* spl_sema.c SPL 语义分析 * * 两趟 AST 遍历(splc0 显式先 run 再 check): * spl_sema_run —— Pass1:预登记顶层名字(聚合壳/别名/fn/var),使兄弟前向引用成立 * spl_sema_check —— Pass2:边构建聚合成员与方法 def,边检查函数体(类型检查) * * scope 符号表存 spl_def_id_t(def 第一公民);匿名类型放 type_table, * 命名实体放 def_table,两张表 id 空间完全独立。 */ #include "spl_sema.h" #include "spl_builtin.h" #include #include typedef struct { spl_type_id_t ret; } spl_sema_ctx_t; static spl_ast_node_t *node_at(spl_ast_t *ast, spl_ast_node_ref_t ref) { if (!ref || ref >= ast->buckets.size) return NULL; return &ast->buckets.data[ref]; } static void sema_error(spl_sema_t *sema, spl_ast_node_ref_t ref, const char *msg) { spl_ast_node_t *n = node_at(sema->ast, ref); sema->error_count++; if (n) { LOG_ERROR("%s error: %s (%s:%d:%d)", "sema", msg, n->loc.fname ? n->loc.fname : "?", n->loc.line, n->loc.col); } else { LOG_ERROR("%s error: %s", "sema", msg); } } static void sema_warn(spl_sema_t *sema, spl_ast_node_ref_t ref, const char *msg) { spl_ast_node_t *n = node_at(sema->ast, ref); if (n) { LOG_WARN("%s warning: %s (%s:%d:%d)", "sema", msg, n->loc.fname ? n->loc.fname : "?", n->loc.line, n->loc.col); } else { LOG_WARN("%s warning: %s", "sema", msg); } } /* ---- def/type 快捷访问 ---- */ static spl_def_node_t *def_at(spl_sema_t *sema, spl_def_id_t id) { return spl_type_def(&sema->type, id); } static spl_type_id_t def_type(spl_sema_t *sema, spl_def_id_t id) { spl_def_node_t *d = def_at(sema, id); return d ? d->type_id : 0; } /* 由匿名类型 id 反查拥有它的 def(聚合优先;别名/ distinct 次之) */ static spl_def_id_t def_for_type(spl_sema_t *sema, spl_type_id_t tid) { if (!tid) return 0; spl_def_id_t fallback = 0; for (usize i = 1; i < sema->type.def_table.size; i++) { spl_def_node_t *d = &sema->type.def_table.data[i]; if (d->type_id == tid) { if (d->kind == SPL_DEF_AGG) return i; if (!fallback && (d->kind == SPL_DEF_ALIAS || d->kind == SPL_DEF_DISTINCT)) fallback = i; } } return fallback; } static spl_def_id_t def_alloc(spl_sema_t *sema, int kind) { spl_def_id_t id = spl_type_def_alloc(&sema->type); def_at(sema, id)->kind = kind; return id; } static spl_def_id_t new_var_def(spl_sema_t *sema, const char *name, spl_type_id_t type, spl_scope_id_t scope) { spl_def_id_t id = def_alloc(sema, SPL_DEF_VAR); spl_def_node_t *d = def_at(sema, id); d->type_id = type; d->var_def.name = name; d->var_def.def_id = id; d->var_def.type_id = type; d->var_def.scope_id = scope; return id; } /* 裸名查找:从 current_scope 沿父链到 root(字段名不在 symbols,天然不命中) */ static spl_def_id_t find_bare(spl_sema_t *sema, const char *name) { spl_scope_id_t cur = sema->current_scope; while (cur) { if (cur >= sema->scopes.size) break; spl_def_id_t val = 0; if (map_get(sema->scopes.data[cur].symbols, name, &val)) return val; cur = sema->scopes.data[cur].parent; } return 0; } /* 名字 → 其类型(def → type_id) */ static spl_type_id_t find_type(spl_sema_t *sema, const char *name) { return def_type(sema, find_bare(sema, name)); } /* ---- 聚合成员登记(def 层 agg_def) ---- */ static void agg_add_member(spl_sema_t *sema, spl_def_id_t def, const char *name, spl_type_id_t type, spl_scope_id_t scope, spl_def_id_t member_def) { spl_def_node_t *d = def_at(sema, def); if (!d || d->kind != SPL_DEF_AGG) return; spl_var_def_t v = {name, member_def, type, scope}; vec_push(d->agg_def, v); } /* 聚合/枚举成员查找:匿名类型 id → 拥有它的 def → agg_def */ static spl_type_id_t agg_member_type(spl_sema_t *sema, spl_type_id_t agg_tid, const char *name) { spl_def_id_t d = def_for_type(sema, agg_tid); if (!d) return 0; spl_def_node_t *def = def_at(sema, d); for (usize i = 0; i < def->agg_def.size; i++) { if (def->agg_def.data[i].name && strcmp(def->agg_def.data[i].name, name) == 0) return def->agg_def.data[i].type_id; } return 0; } /* ---- 类型解析 ---- */ static spl_type_id_t resolve_type_expr(spl_sema_t *sema, spl_ast_node_ref_t ref); static spl_type_id_t resolve_type_atom(spl_sema_t *sema, spl_ast_node_ref_t ref); static spl_type_id_t build_agg(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t parent, const char *name); /* 路径类型:首段裸名(含内置),后续段逐级查聚合 agg_def */ static spl_type_id_t resolve_type_path(spl_sema_t *sema, spl_ast_node_ref_vec_t *path) { if (!path->size) return 0; spl_type_id_t tid = resolve_type_atom(sema, path->data[0]); if (!tid) return 0; for (usize i = 1; i < path->size; i++) { spl_ast_node_t *atom = node_at(sema->ast, path->data[i]); if (!atom) { sema_error(sema, path->data[i], "bad type path segment"); return 0; } spl_type_id_t mt = agg_member_type(sema, tid, atom->type_atom.ident); if (!mt) { char buf[128]; snprintf(buf, sizeof buf, "no member '%s' in type", atom->type_atom.ident); sema_error(sema, path->data[i], buf); return 0; } tid = mt; } return tid; } static spl_type_id_t resolve_type_atom(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_ast_node_t *n = node_at(sema->ast, ref); if (!n) return 0; switch (n->type_atom.kind) { case SPL_AST_TYPE_VOID: return spl_type_void(&sema->type); case SPL_AST_TYPE_BOOL: return spl_type_bool(&sema->type); case SPL_AST_TYPE_I8: return spl_type_int(&sema->type, 8, 1); case SPL_AST_TYPE_U8: return spl_type_int(&sema->type, 8, 0); case SPL_AST_TYPE_I16: return spl_type_int(&sema->type, 16, 1); case SPL_AST_TYPE_U16: return spl_type_int(&sema->type, 16, 0); case SPL_AST_TYPE_I32: return spl_type_int(&sema->type, 32, 1); case SPL_AST_TYPE_U32: return spl_type_int(&sema->type, 32, 0); case SPL_AST_TYPE_I64: return spl_type_int(&sema->type, 64, 1); case SPL_AST_TYPE_U64: return spl_type_int(&sema->type, 64, 0); case SPL_AST_TYPE_ISIZE: return spl_type_int(&sema->type, sizeof(isize) * 8, 1); case SPL_AST_TYPE_USIZE: return spl_type_int(&sema->type, sizeof(usize) * 8, 0); case SPL_AST_TYPE__F32: return spl_type_float(&sema->type, 32); case SPL_AST_TYPE__F64: return spl_type_float(&sema->type, 64); case SPL_AST_TYPE_PTR: case SPL_AST_TYPE_ANY: /* `_`/`ptr` 均为通配:只能作为指针目标,等于 *void。 * 裸用(无 * 前缀)由 resolve_type_expr 报错;ptr 关键字暂不使用 */ return spl_type_void(&sema->type); case SPL_AST_TYPE_IDENT: { spl_type_id_t tid = find_type(sema, n->type_atom.ident); if (!tid) { char buf[160]; snprintf(buf, sizeof buf, "unknown type '%s'", n->type_atom.ident); sema_error(sema, ref, buf); return 0; } return tid; } } return 0; } static spl_type_id_t resolve_type_expr(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_ast_node_t *n = node_at(sema->ast, ref); if (!n) return 0; spl_type_id_t base = 0; switch (n->type_expr.kind) { case SPL_AST_BASE_TYPE_PATH: base = resolve_type_path(sema, &n->type_expr.type_path); break; case SPL_AST_BASE_TYPE_FN: { spl_type_id_vec_t params; vec_init(params); for (usize i = 0; i < n->type_expr.fn_type.param_list.size; i++) { spl_ast_node_t *pd = node_at(sema->ast, n->type_expr.fn_type.param_list.data[i]); spl_type_id_t pt = 0; if (pd && pd->param_decl.type_expr) pt = resolve_type_expr(sema, pd->param_decl.type_expr); vec_push(params, pt); } spl_type_id_t ret = 0; if (n->type_expr.fn_type.type_expr) ret = resolve_type_expr(sema, n->type_expr.fn_type.type_expr); else ret = spl_type_void(&sema->type); base = spl_type_fn(&sema->type, params, ret); break; } case SPL_AST_TYPE_STRUCT: case SPL_AST_TYPE_UNION: case SPL_AST_TYPE_ENUM: /* 内联匿名聚合:构建聚合类型(不注册名字,parent 为当前 scope) */ base = build_agg(sema, ref, sema->current_scope, NULL); break; default: return 0; } /* 前缀修饰:* → ptr,[] → slice,[n] → array(逆序包裹) */ for (usize i = n->type_expr.type_prefixs.size; i > 0; i--) { spl_ast_node_t *pf = node_at(sema->ast, n->type_expr.type_prefixs.data[i - 1]); if (!pf) continue; if (pf->prefix_type.pointer == 1) { base = spl_type_ptr(&sema->type, base); } else if (pf->prefix_type.pointer == 2) { if (pf->prefix_type.array_size > 0) base = spl_type_array(&sema->type, base, (usize)pf->prefix_type.array_size); else base = spl_type_slice(&sema->type, base); } } /* `_`/`ptr` 只能在指针目标位置(*_ = *void);裸用是无类型值,报错 */ if (n->type_expr.kind == SPL_AST_BASE_TYPE_PATH && n->type_expr.type_path.size) { spl_ast_node_t *atom = node_at(sema->ast, n->type_expr.type_path.data[n->type_expr.type_path.size - 1]); int ptr_pre = 0; for (usize i = 0; i < n->type_expr.type_prefixs.size; i++) { spl_ast_node_t *pf = node_at(sema->ast, n->type_expr.type_prefixs.data[i]); if (pf && pf->prefix_type.pointer == 1) ptr_pre = 1; } if (atom && !ptr_pre && (atom->type_atom.kind == SPL_AST_TYPE_ANY || atom->type_atom.kind == SPL_AST_TYPE_PTR)) sema_error(sema, ref, "bare `_` type only allowed as pointer target `*_`"); } /* AST 注解:该 type_expr 解析到的 def(聚合/别名/内置为 0;ast2ir 据此直接取类型) */ if (base) n->resolved_def_id = def_for_type(sema, base); return base; } /* ---- 声明处理 ---- */ static void sema_fn_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, spl_def_id_t agg_def); static void sema_type_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, spl_def_id_t agg_def); static void sema_var_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, spl_def_id_t agg_def); static void sema_const_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, spl_def_id_t agg_def); static void check_fn_body(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_def_id_t fdef, spl_scope_id_t parent_scope); typedef struct { spl_type_id_t tid; spl_def_id_t def; } agg_handle_t; /* 只建匿名聚合类型 + AGG def(名字由调用方注册到目标 scope),不做成员解析。 * 用于顶层聚合在 Pass1 预登记,使兄弟/自引用 `type Node{next:*Node}` 成立。 */ static agg_handle_t agg_prepare(spl_sema_t *sema, spl_ast_node_ref_t ref) { agg_handle_t h = {0, 0}; spl_ast_node_t *te = node_at(sema->ast, ref); if (!te) return h; spl_type_id_t tid = spl_type_alloc(&sema->type); spl_type_node_t *tn = spl_type_node(&sema->type, tid); switch (te->type_expr.kind) { case SPL_AST_TYPE_STRUCT: tn->kind = SPL_TYPE_STRUCT; vec_init(tn->agg_field_types); break; case SPL_AST_TYPE_UNION: tn->kind = SPL_TYPE_UNION; vec_init(tn->agg_field_types); break; case SPL_AST_TYPE_ENUM: tn->kind = SPL_TYPE_ENUM; vec_init(tn->enum_type.variants); tn->enum_type.tag_type = 0; break; default: return h; /* 非聚合 */ } spl_def_id_t def = def_alloc(sema, SPL_DEF_AGG); def_at(sema, def)->type_id = tid; vec_init(def_at(sema, def)->agg_def); te->resolved_def_id = def; /* 注解:该 type_expr 解析到的 def */ h.tid = tid; h.def = def; return h; } /* 聚合成员解析:建聚合 scope(自名注册)→ 嵌套类型 pass1 → 成员/方法 pass2 → 方法体 pass3 */ static void agg_resolve(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_type_id_t tid, spl_def_id_t def, spl_scope_id_t parent, const char *name) { spl_ast_node_t *te = node_at(sema->ast, ref); if (!te) return; spl_scope_id_t agg_scope = spl_sema_scope_alloc(sema); sema->scopes.data[agg_scope].parent = parent; if (name) spl_sema_scope_insert(sema, agg_scope, name, def); spl_scope_id_t save = sema->current_scope; sema->current_scope = agg_scope; /* pass1: 先构建嵌套类型(type 声明),使字段类型可前向引用嵌套类型 */ for (usize i = 0; i < te->type_expr.aggregate_list.size; i++) { spl_ast_node_t *m = node_at(sema->ast, te->type_expr.aggregate_list.data[i]); if (m && m->kind == SPL_AST_TYPE_DECL) sema_type_decl(sema, te->type_expr.aggregate_list.data[i], agg_scope, def); } /* pass2: 成员 + 方法 def(兄弟方法全部登记后再检查体) */ for (usize i = 0; i < te->type_expr.aggregate_list.size; i++) { spl_ast_node_ref_t mref = te->type_expr.aggregate_list.data[i]; spl_ast_node_t *m = node_at(sema->ast, mref); if (!m) continue; switch (m->kind) { case SPL_AST_MEMBER_DECL: { spl_type_id_t ft = m->member_decl.type_expr ? resolve_type_expr(sema, m->member_decl.type_expr) : 0; /* resolve_type_expr 可能 alloc 新类型 → 两表 realloc,须重新取节点 */ spl_type_node_t *tn = spl_type_node(&sema->type, tid); /* 每个 MEMBER_DECL 建一个 SPL_DEF_MEMBER def(结构字段/枚举变体) */ spl_type_id_t mtype = 0; if (tn->kind == SPL_TYPE_ENUM) { mtype = ft ? ft : tid; /* 哨兵:无载荷变体 = 枚举自身 tid */ vec_push(tn->enum_type.variants, mtype); } else { mtype = ft; vec_push(tn->agg_field_types, ft); } spl_def_id_t mdef = def_alloc(sema, SPL_DEF_MEMBER); def_at(sema, mdef)->type_id = mtype; def_at(sema, mdef)->var_def.name = m->member_decl.name; agg_add_member(sema, def, m->member_decl.name, mtype, agg_scope, mdef); m->resolved_def_id = mdef; /* 注解:member_decl → 其 SPL_DEF_MEMBER def */ break; } case SPL_AST_FN_DECL: case SPL_AST_FN_DEFINE: sema_fn_decl(sema, mref, agg_scope, def); break; case SPL_AST_TYPE_DECL: /* 已在 pass1 处理 */ break; case SPL_AST_VAR_DECL: sema_var_decl(sema, mref, agg_scope, def); break; case SPL_AST_CONST_DECL: sema_const_decl(sema, mref, agg_scope, def); break; default: break; } } /* pass3: 检查方法体(当前聚合所有方法已登记,兄弟可互调) */ for (usize i = 0; i < te->type_expr.aggregate_list.size; i++) { spl_ast_node_ref_t mref = te->type_expr.aggregate_list.data[i]; spl_ast_node_t *m = node_at(sema->ast, mref); if (m && m->kind == SPL_AST_FN_DEFINE) { spl_def_id_t mdef = find_bare(sema, m->fn_decl.name); check_fn_body(sema, mref, mdef, agg_scope); } } sema->current_scope = save; } /* 嵌套/内联聚合:prepare + resolve 一步完成 */ static spl_type_id_t build_agg(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t parent, const char *name) { agg_handle_t h = agg_prepare(sema, ref); if (!h.tid) return 0; agg_resolve(sema, ref, h.tid, h.def, parent, name); return h.tid; } /* 变量/常量/绑定节点:建 VAR def(不包 SPL_TYPE_ID) */ static void register_binding(spl_sema_t *sema, const char *name, spl_ast_node_ref_t type_expr, spl_scope_id_t scope, spl_def_id_t agg_def, spl_ast_node_ref_t node_ref) { spl_type_id_t t = type_expr ? resolve_type_expr(sema, type_expr) : 0; spl_def_id_t def = new_var_def(sema, name, t, scope); if (!spl_sema_scope_insert(sema, scope, name, def)) sema_error(sema, 0, "duplicate symbol"); if (agg_def) agg_add_member(sema, agg_def, name, t, scope, def); if (node_ref) { spl_ast_node_t *nn = node_at(sema->ast, node_ref); if (nn) nn->resolved_def_id = def; /* 注解:var/const 声明 → 其 VAR def */ } } static void sema_var_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, spl_def_id_t agg_def) { spl_ast_node_t *n = node_at(sema->ast, ref); if (!n) return; register_binding(sema, n->var_decl.name, n->var_decl.type_expr, scope, agg_def, ref); } static void sema_const_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, spl_def_id_t agg_def) { spl_ast_node_t *n = node_at(sema->ast, ref); if (!n) return; register_binding(sema, n->const_decl.name, n->const_decl.type_expr, scope, agg_def, ref); /* 标记 const:赋值检查拒绝写入 */ spl_ast_node_t *nn = node_at(sema->ast, ref); if (nn && nn->resolved_def_id) { spl_def_node_t *d = def_at(sema, nn->resolved_def_id); if (d) d->var_def.is_const = 1; } } /* fn 声明:建 fn type + FN_PARAMS def + 登记名字。不建 fn_scope(由 check 新建)。 * 形参只把 name/type 记入 fn_params_def(def_id=0),实际参数 def 在 check 时创建。 */ static void sema_fn_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, spl_def_id_t agg_def) { spl_ast_node_t *n = node_at(sema->ast, ref); if (!n) return; spl_type_id_vec_t params; vec_init(params); for (usize i = 0; i < n->fn_decl.param_list.size; i++) { spl_ast_node_t *pd = node_at(sema->ast, n->fn_decl.param_list.data[i]); spl_type_id_t pt = 0; if (pd && pd->param_decl.type_expr) pt = resolve_type_expr(sema, pd->param_decl.type_expr); vec_push(params, pt); } spl_type_id_t ret = 0; if (n->fn_decl.type_expr) ret = resolve_type_expr(sema, n->fn_decl.type_expr); else ret = spl_type_void(&sema->type); spl_type_id_t fid = spl_type_fn(&sema->type, params, ret); spl_def_id_t fdef = def_alloc(sema, SPL_DEF_FN_PARAMS); spl_def_node_t *d = def_at(sema, fdef); d->type_id = fid; vec_init(d->fn_params_def); for (usize i = 0; i < n->fn_decl.param_list.size; i++) { spl_ast_node_t *pd = node_at(sema->ast, n->fn_decl.param_list.data[i]); if (!pd) continue; spl_var_def_t pv = {pd->param_decl.name, 0, params.data[i], 0}; vec_push(d->fn_params_def, pv); } if (!spl_sema_scope_insert(sema, scope, n->fn_decl.name, fdef)) sema_error(sema, ref, "duplicate function name"); if (agg_def) agg_add_member(sema, agg_def, n->fn_decl.name, fid, scope, fdef); n->resolved_def_id = fdef; /* 注解:fn 声明 → 其 FN_PARAMS def */ } static void sema_type_decl(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_scope_id_t scope, spl_def_id_t agg_def) { spl_ast_node_t *n = node_at(sema->ast, ref); if (!n) return; spl_ast_node_t *te = node_at(sema->ast, n->type_decl.type_expr); spl_type_id_t tid = 0; spl_def_id_t def = 0; if (te && (te->type_expr.kind == SPL_AST_TYPE_STRUCT || te->type_expr.kind == SPL_AST_TYPE_UNION || te->type_expr.kind == SPL_AST_TYPE_ENUM)) { agg_handle_t h = agg_prepare(sema, n->type_decl.type_expr); tid = h.tid; def = h.def; agg_resolve(sema, n->type_decl.type_expr, h.tid, h.def, scope, n->type_decl.name); } else if (te) { tid = resolve_type_expr(sema, n->type_decl.type_expr); def = def_alloc(sema, SPL_DEF_ALIAS); spl_def_node_t *d = def_at(sema, def); d->type_id = tid; d->type_def.name = n->type_decl.name; d->type_def.def_id = def; d->type_def.type_id = tid; d->type_def.scope_id = scope; } if (!tid || !def) return; if (!spl_sema_scope_insert(sema, scope, n->type_decl.name, def)) sema_error(sema, ref, "duplicate type name"); if (agg_def) agg_add_member(sema, agg_def, n->type_decl.name, tid, scope, def); /* 嵌套类型提升到文件作用域:兄弟聚合可裸名引用(如 Lexer 方法内 Tag.eof) */ if (agg_def) spl_sema_scope_insert(sema, sema->root_scope, n->type_decl.name, def); n->resolved_def_id = def; /* 注解:type_decl → 其 AGG/ALIAS def */ } /* ================================================================ * 类型检查(阶段 B) * ================================================================ */ static spl_type_id_t infer_expr(spl_sema_t *sema, spl_ast_node_ref_t ref); /* 类型节点快捷查询 */ static spl_type_node_t *type_node(spl_sema_t *sema, spl_type_id_t tid) { return spl_type_node(&sema->type, tid); } static bool is_int_tid(spl_sema_t *sema, spl_type_id_t tid) { spl_type_node_t *t = type_node(sema, tid); return t && t->kind == SPL_TYPE_INT; } static bool is_numeric_tid(spl_sema_t *sema, spl_type_id_t tid) { spl_type_node_t *t = type_node(sema, tid); return t && (t->kind == SPL_TYPE_INT || t->kind == SPL_TYPE_FLOAT); } static bool is_agg_tid(spl_sema_t *sema, spl_type_id_t tid) { spl_type_node_t *t = type_node(sema, tid); return t && (t->kind == SPL_TYPE_STRUCT || t->kind == SPL_TYPE_UNION || t->kind == SPL_TYPE_ENUM); } /* 表达式是否为整数字面量(含一元负号) */ static bool expr_is_int_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_ast_node_t *n = node_at(sema->ast, ref); if (!n || n->kind != SPL_AST_EXPR) return false; switch (n->expr.op) { case SPL_AST_PRIMARY_EXPR: { spl_ast_node_t *pn = node_at(sema->ast, n->expr.op_expr.left); int k = pn && pn->kind == SPL_AST_EXPR ? (int)pn->primary_expr.kind : -1; return k == SPL_AST_INTEGER || k == SPL_AST_CHAR_LIT; } case SPL_AST_PREFIX_EXPR: return expr_is_int_literal(sema, n->expr.op_expr.left); default: return false; } } /* 浮点字面量(含负号前缀):允许拓宽/窄化到目标浮点类型 */ static bool expr_is_float_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_ast_node_t *n = node_at(sema->ast, ref); if (!n || n->kind != SPL_AST_EXPR) return false; switch (n->expr.op) { case SPL_AST_PRIMARY_EXPR: { spl_ast_node_t *pn = node_at(sema->ast, n->expr.op_expr.left); int k = pn && pn->kind == SPL_AST_EXPR ? (int)pn->primary_expr.kind : -1; return k == SPL_AST_FLOAT; } case SPL_AST_PREFIX_EXPR: return expr_is_float_literal(sema, n->expr.op_expr.left); default: return false; } } /* 字面量(整型或浮点):检查时允许类型拓宽 */ static bool expr_is_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) { return expr_is_int_literal(sema, ref) || expr_is_float_literal(sema, ref); } /* 打开 SPL_TYPE_ID 绑定节点,返回真实类型(newtype 预留;当前无调用产生该节点) */ static spl_type_id_t underlying(spl_sema_t *sema, spl_type_id_t tid) { spl_type_node_t *t = type_node(sema, tid); if (t && t->kind == SPL_TYPE_ID) return t->type_id; return tid; } /* 结构递归相等:ptr/slice/array/fn 等构造类型按结构比较, * 因为 spl_type_ptr/slice/array 不去重,相同结构可能有不同 id */ static int type_same(spl_sema_t *sema, spl_type_id_t a, spl_type_id_t b) { if (a == b) return 1; a = underlying(sema, a); b = underlying(sema, b); if (a == b) return 1; spl_type_node_t *na = type_node(sema, a); spl_type_node_t *nb = type_node(sema, b); if (!na || !nb || na->kind != nb->kind) return 0; switch (na->kind) { case SPL_TYPE_INT: return na->int_type.bits == nb->int_type.bits && na->int_type.is_signed == nb->int_type.is_signed; case SPL_TYPE_FLOAT: return na->float_type.bits == nb->float_type.bits; case SPL_TYPE_PTR: return type_same(sema, na->ptr_pointee, nb->ptr_pointee); case SPL_TYPE_SLICE: return type_same(sema, na->slice_element, nb->slice_element); case SPL_TYPE_RANGE: return type_same(sema, na->range_element, nb->range_element); case SPL_TYPE_ARRAY: return na->array_type.len == nb->array_type.len && type_same(sema, na->array_type.element, nb->array_type.element); case SPL_TYPE_FN: { if (na->fn_type.params.size != nb->fn_type.params.size) return 0; for (usize i = 0; i < na->fn_type.params.size; i++) if (!type_same(sema, na->fn_type.params.data[i], nb->fn_type.params.data[i])) return 0; return type_same(sema, na->fn_type.ret, nb->fn_type.ret); } default: return 0; } } /* 兼容性检查:src 可赋给 dst?is_literal 表示 src 是整数字面量 */ /* 返回值:1 兼容,0 不兼容 */ static int type_compatible(spl_sema_t *sema, spl_type_id_t dst, spl_type_id_t src, int is_literal, int *warned) { if (warned) *warned = 0; if (!dst || !src) return 0; dst = underlying(sema, dst); src = underlying(sema, src); spl_type_node_t *d = type_node(sema, dst); spl_type_node_t *s = type_node(sema, src); if (!d || !s) return 0; if (type_same(sema, dst, src)) return 1; /* 整数字面量可拓宽到目标整数 */ if (is_literal && d->kind == SPL_TYPE_INT && s->kind == SPL_TYPE_INT) { /* 字面量值已隐含满足范围(检查时由调用方保证),此处允许拓宽 */ return 1; } /* 浮点字面量可赋值到目标浮点(f64 字面量 → f32 变量,值可表示则允许) */ if (is_literal && d->kind == SPL_TYPE_FLOAT && s->kind == SPL_TYPE_FLOAT) return 1; /* isize/usize(机器字宽)与 i32 混合:比较/算术/传参可用(splc1 与旧测试事实标准) */ if (d->kind == SPL_TYPE_INT && s->kind == SPL_TYPE_INT) { int dbits = d->int_type.bits, sbits = s->int_type.bits; int word = (int)(sizeof(usize) * 8); if ((dbits == word && sbits == 32) || (dbits == 32 && sbits == word)) { if (warned) *warned = 1; return 1; } } /* 数组 [N]T -> 切片 []T */ if (d->kind == SPL_TYPE_SLICE && s->kind == SPL_TYPE_ARRAY) { if (d->slice_element == s->array_type.element) return 1; } /* *T -> *_ 与 *_ -> *T(警告转换;*_ 即 *void) */ if (d->kind == SPL_TYPE_PTR && s->kind == SPL_TYPE_PTR) { spl_type_id_t void_t = spl_type_void(&sema->type); if (d->ptr_pointee == void_t && s->ptr_pointee != void_t) { if (warned) *warned = 1; return 1; } if (s->ptr_pointee == void_t && d->ptr_pointee != void_t) { if (warned) *warned = 1; return 1; } /* *T -> *u8:字节指针视图(splc1 事实标准,如 vm_fwrite(buf:*u8, &x)) */ spl_type_node_t *dtn = type_node(sema, d->ptr_pointee); if (dtn && dtn->kind == SPL_TYPE_INT && dtn->int_type.bits == 8 && dtn->int_type.is_signed == 0 && !type_same(sema, d->ptr_pointee, s->ptr_pointee)) { if (warned) *warned = 1; return 1; } } return 0; } /* expr 是否为 null 字面量(不参与类型推导,需上下文) */ static bool expr_is_null_literal(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_ast_node_t *n = node_at(sema->ast, ref); if (!n || n->kind != SPL_AST_EXPR) return false; if (n->expr.op == SPL_AST_PRIMARY_EXPR) return expr_is_null_literal(sema, n->expr.op_expr.left); return n->primary_expr.kind == SPL_AST_NULL; } /* 二元算术/位运算:两侧类型一致,或整数字面量拓宽;含指针算术 *T + int */ static spl_type_id_t infer_binary_arith(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *e) { spl_type_id_t l = infer_expr(sema, e->expr.op_expr.left); spl_type_id_t r = infer_expr(sema, e->expr.op_expr.right); if (!l || !r) { sema_error(sema, ref, "bad operand in arithmetic"); return 0; } l = underlying(sema, l); r = underlying(sema, r); /* 指针算术:*T + int / int + *T / *T - int → *T */ if (e->expr.op == SPL_AST_ADD_EXPR || e->expr.op == SPL_AST_SUB_EXPR) { spl_type_node_t *lt = type_node(sema, l); spl_type_node_t *rt = type_node(sema, r); if (lt && lt->kind == SPL_TYPE_PTR && rt && is_int_tid(sema, r)) return l; if (rt && rt->kind == SPL_TYPE_PTR && lt && is_int_tid(sema, l) && e->expr.op == SPL_AST_ADD_EXPR) return r; } if (l == r) { if (!is_numeric_tid(sema, l)) { sema_error(sema, ref, "arithmetic requires numeric operands"); return 0; } return l; } int ll = expr_is_int_literal(sema, e->expr.op_expr.left); int rl = expr_is_int_literal(sema, e->expr.op_expr.right); if (ll && is_int_tid(sema, r)) { int w = 0; if (type_compatible(sema, r, l, 1, &w)) return r; } if (rl && is_int_tid(sema, l)) { int w = 0; if (type_compatible(sema, l, r, 1, &w)) return l; } /* isize/usize 与 i32 混合算术:结果取左操作数类型 */ if (is_int_tid(sema, l) && is_int_tid(sema, r)) { int w = 0; if (type_compatible(sema, l, r, 0, &w)) return l; } sema_error(sema, ref, "type mismatch in arithmetic"); return 0; } /* 比较运算:兼容则返回 bool */ static spl_type_id_t infer_binary_cmp(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *e) { spl_type_id_t l = infer_expr(sema, e->expr.op_expr.left); spl_type_id_t r = infer_expr(sema, e->expr.op_expr.right); /* null 与指针比较合法 */ if (expr_is_null_literal(sema, e->expr.op_expr.left)) { if (r && type_node(sema, underlying(sema, r))->kind == SPL_TYPE_PTR) return spl_type_bool(&sema->type); sema_error(sema, ref, "null can only compare with pointers"); return 0; } if (expr_is_null_literal(sema, e->expr.op_expr.right)) { if (l && type_node(sema, underlying(sema, l))->kind == SPL_TYPE_PTR) return spl_type_bool(&sema->type); sema_error(sema, ref, "null can only compare with pointers"); return 0; } if (!l || !r) { sema_error(sema, ref, "bad operand in comparison"); return 0; } int w = 0; if (type_compatible(sema, l, r, expr_is_literal(sema, e->expr.op_expr.right), &w) || type_compatible(sema, r, l, expr_is_literal(sema, e->expr.op_expr.left), &w)) { return spl_type_bool(&sema->type); } sema_error(sema, ref, "type mismatch in comparison"); return 0; } /* 逻辑运算:两侧 bool */ static spl_type_id_t infer_binary_logic(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *e) { spl_type_id_t l = infer_expr(sema, e->expr.op_expr.left); spl_type_id_t r = infer_expr(sema, e->expr.op_expr.right); if (underlying(sema, l) != underlying(sema, spl_type_bool(&sema->type)) || underlying(sema, r) != underlying(sema, spl_type_bool(&sema->type))) { sema_error(sema, ref, "logical operators require bool operands"); return 0; } return spl_type_bool(&sema->type); } /* 位运算:两侧整数同型或字面量拓宽 */ static spl_type_id_t infer_binary_bit(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *e) { spl_type_id_t l = infer_expr(sema, e->expr.op_expr.left); spl_type_id_t r = infer_expr(sema, e->expr.op_expr.right); if (!l || !r) { sema_error(sema, ref, "bad operand in bitwise"); return 0; } l = underlying(sema, l); r = underlying(sema, r); if (l == r) { if (!is_int_tid(sema, l)) { sema_error(sema, ref, "bitwise requires integer operands"); return 0; } return l; } int ll = expr_is_int_literal(sema, e->expr.op_expr.left); int rl = expr_is_int_literal(sema, e->expr.op_expr.right); if (ll && is_int_tid(sema, r)) return r; if (rl && is_int_tid(sema, l)) return l; sema_error(sema, ref, "type mismatch in bitwise"); return 0; } static spl_type_id_t infer_binary(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *e) { switch (e->expr.op) { case SPL_AST_ADD_EXPR: case SPL_AST_SUB_EXPR: case SPL_AST_MUL_EXPR: case SPL_AST_DIV_EXPR: case SPL_AST_MOD_EXPR: return infer_binary_arith(sema, ref, e); case SPL_AST_CMPEQ_EXPR: case SPL_AST_CMPNE_EXPR: case SPL_AST_CMP_LE_EXPR: case SPL_AST_CMP_GE_EXPR: case SPL_AST_CMP_LT_EXPR: case SPL_AST_CMP_GT_EXPR: return infer_binary_cmp(sema, ref, e); case SPL_AST_BOOLOR_EXPR: case SPL_AST_BOOLAND_EXPR: return infer_binary_logic(sema, ref, e); case SPL_AST_BITOR_EXPR: case SPL_AST_BITXOR_EXPR: case SPL_AST_BITAND_EXPR: case SPL_AST_LSHIFT_EXPR: case SPL_AST_RSHIFT_EXPR: return infer_binary_bit(sema, ref, e); default: return 0; } } /* 聚合初始化字面量:目标类型已知时校验字段 */ static spl_type_id_t infer_agg_init(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { spl_ast_node_t *pn = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; if (!pn || pn->primary_expr.kind != SPL_AST_ARGGREGATE_INIT) return 0; spl_type_id_t tid = 0; if (pn->primary_expr.aggregate_init.name) { tid = find_type(sema, pn->primary_expr.aggregate_init.name); if (!tid) { sema_error(sema, ref, "unknown aggregate type in literal"); return 0; } } else { /* 匿名 .{} 依赖上下文,由调用方(赋值/初始化)填充 */ return 0; } spl_type_node_t *tn = type_node(sema, tid); if (!tn || !is_agg_tid(sema, tid)) { sema_error(sema, ref, "aggregate literal target is not a struct/union/enum"); return 0; } /* 枚举无载荷初始化如 Color { .Red }:仅一个成员且为变体 */ if (tn->kind == SPL_TYPE_ENUM) { usize nitems = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left)->primary_expr.aggregate_init.expr.size : pn->primary_expr.aggregate_init.expr.size; for (usize i = 0; i < nitems; i++) { spl_ast_node_ref_t iref = (n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left)->primary_expr.aggregate_init.expr : pn->primary_expr.aggregate_init.expr) .data[i]; spl_ast_node_t *item = node_at(sema->ast, iref); if (!item) continue; spl_type_id_t mt = agg_member_type(sema, tid, item->aggregate_init_item.ident); if (!mt) { sema_error(sema, iref, "unknown variant in enum literal"); continue; } if (item->aggregate_init_item.expr) infer_expr(sema, item->aggregate_init_item.expr); } return tid; } /* struct/union:逐字段校验 */ for (usize i = 0; i < (n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left)->primary_expr.aggregate_init.expr.size : pn->primary_expr.aggregate_init.expr.size); i++) { spl_ast_node_ref_t iref = (n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left)->primary_expr.aggregate_init.expr : pn->primary_expr.aggregate_init.expr) .data[i]; spl_ast_node_t *item = node_at(sema->ast, iref); if (!item) continue; spl_type_id_t mt = agg_member_type(sema, tid, item->aggregate_init_item.ident); if (!mt) { sema_error(sema, iref, "unknown field in aggregate literal"); continue; } if (item->aggregate_init_item.expr) { spl_type_id_t et = infer_expr(sema, item->aggregate_init_item.expr); int w = 0; if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et && !type_compatible(sema, mt, et, expr_is_literal(sema, item->aggregate_init_item.expr), &w)) { sema_error(sema, iref, "field type mismatch in aggregate literal"); } } } return tid; } /* 数组字面量 [N]T{...} */ static spl_type_id_t infer_array_lit(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { spl_ast_node_t *pn = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; spl_type_id_t elem = 0; if (pn->primary_expr.array_lit_expr.type_expr) { elem = resolve_type_expr(sema, pn->primary_expr.array_lit_expr.type_expr); if (!elem) sema_error(sema, ref, "bad array literal element type"); } for (usize i = 0; i < pn->primary_expr.array_lit_expr.expr_list.size; i++) { spl_type_id_t et = infer_expr(sema, pn->primary_expr.array_lit_expr.expr_list.data[i]); if (elem) { int w = 0; if (!type_compatible( sema, elem, et, expr_is_literal(sema, pn->primary_expr.array_lit_expr.expr_list.data[i]), &w)) { sema_error(sema, pn->primary_expr.array_lit_expr.expr_list.data[i], "element type mismatch in array literal"); } } } return spl_type_array(&sema->type, elem ? elem : 0, (usize)pn->primary_expr.array_lit_expr.integer); } /* 标识符:scope 查找(def → 类型) */ static spl_type_id_t infer_ident(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { spl_ast_node_t *pn = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; spl_def_id_t def = find_bare(sema, pn->primary_expr.ident); spl_type_id_t t = def_type(sema, def); if (!t) { sema_error(sema, ref, "undefined identifier"); return 0; } /* 注解:IDENT 引用 → 其符号 def(var 用 VAR、fn 用 FN_PARAMS 等) */ pn->resolved_def_id = def; return t; } /* 表达式 ref 解析到的 def:取内层节点注解;裸 ident 兜底 find_bare */ static spl_def_id_t expr_def_at(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_ast_node_t *n = node_at(sema->ast, ref); if (!n || n->kind != SPL_AST_EXPR) return 0; spl_ast_node_t *inner = node_at(sema->ast, n->expr.op_expr.left); if (!inner) return 0; if (inner->resolved_def_id) return inner->resolved_def_id; if (n->expr.op == SPL_AST_PRIMARY_EXPR && inner->primary_expr.kind == SPL_AST_IDENT) return find_bare(sema, inner->primary_expr.ident); return 0; } static spl_type_id_t infer_postfix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n); static spl_type_id_t infer_prefix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n); static void check_stmt(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_sema_ctx_t ctx); static spl_type_id_t infer_primary(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { spl_ast_node_t *pn = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; if (!pn) { sema_error(sema, ref, "invalid primary expression"); return 0; } switch (pn->primary_expr.kind) { case SPL_AST_INTEGER: return spl_type_int(&sema->type, 32, 1); case SPL_AST_FLOAT: return spl_type_float(&sema->type, 64); case SPL_AST_CHAR_LIT: /* 字符字面量即字节立即数(u8),经字面量宽化可赋给任意整数类型 */ return spl_type_int(&sema->type, 8, 0); case SPL_AST_STRING_LIT: /* 字符串字面量:底层为 *u8(NUL 终止)。splc1 自举源中一律传 *u8, * SPL.md 建议 []u8,但 IR 层按 *u8 处理,此处与实现一致 */ return spl_type_ptr(&sema->type, spl_type_int(&sema->type, 8, 0)); case SPL_AST_TRUE: case SPL_AST_FALSE: return spl_type_bool(&sema->type); case SPL_AST_NULL: return 0; /* null 无独立类型,需上下文 */ case SPL_AST_IDENT: return infer_ident(sema, ref, n); case SPL_AST_ARGGREGATE_INIT: return infer_agg_init(sema, ref, n); case SPL_AST_EXPR_EXPR: return infer_expr(sema, pn->primary_expr.expr); case SPL_AST_ARRAY_LIT: return infer_array_lit(sema, ref, n); case SPL_AST_BUILTIN_EXPR: { /* 内置调用:类型按注册表约定,参数按需推断(offsetof 字段名参数非表达式) */ const spl_builtin_t *bi = spl_builtin_lookup(pn->primary_expr.builtin_expr.ident); if (!bi) { sema_error(sema, ref, "unknown builtin"); return 0; } usize nargs = pn->primary_expr.builtin_expr.expr_list.size; if (nargs < (usize)bi->min_args || (bi->max_args >= 0 && nargs > (usize)bi->max_args)) { char buf[96]; snprintf(buf, sizeof buf, "builtin @%s: arg count mismatch", bi->name); sema_error(sema, ref, buf); return 0; } for (usize i = 0; i < nargs; i++) { /* offsetof 第二参数为字段标识符,不按表达式推断 */ if (bi->kind == SPL_BUILTIN_OFFSET_OF && i == 1) continue; infer_expr(sema, pn->primary_expr.builtin_expr.expr_list.data[i]); } if (bi->ret_is_void) return spl_type_void(&sema->type); if (bi->kind == SPL_BUILTIN_SIZE_OF || bi->kind == SPL_BUILTIN_BITSIZE_OF || bi->kind == SPL_BUILTIN_ALIGN_OF || bi->kind == SPL_BUILTIN_OFFSET_OF || bi->kind == SPL_BUILTIN_FIELD_COUNT) return spl_type_int(&sema->type, sizeof(usize) * 8, 0); sema_error(sema, ref, "unsupported builtin"); return 0; } case SPL_AST_BLOCK_EXPR: { /* 块表达式:有独立 scope;逐语句检查,返回末尾表达式类型(无则 void) */ spl_ast_node_ref_vec_t *items = &pn->primary_expr.block_expr; spl_scope_id_t scope = spl_sema_scope_alloc(sema); sema->scopes.data[scope].parent = sema->current_scope; spl_scope_id_t save = sema->current_scope; sema->current_scope = scope; spl_type_id_t rt = spl_type_void(&sema->type); spl_sema_ctx_t vctx = {0}; /* 表达式块内的 ret 暂不强制(罕见) */ for (usize i = 0; i < items->size; i++) { if (i + 1 == items->size) { spl_ast_node_t *last = node_at(sema->ast, items->data[i]); if (last && last->kind == SPL_AST_EXPR && !(last->expr.op == SPL_AST_PRIMARY_EXPR)) { rt = infer_expr(sema, items->data[i]); continue; } if (last && last->expr.op == SPL_AST_PRIMARY_EXPR) { spl_ast_node_t *in = node_at(sema->ast, last->expr.op_expr.left); if (in && in->primary_expr.kind == SPL_AST_BLOCK_EXPR) { rt = infer_primary(sema, items->data[i], last); continue; } } } check_stmt(sema, items->data[i], vctx); } sema->current_scope = save; return rt; } default: return 0; } } /* 前缀运算 */ static spl_type_id_t infer_prefix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { spl_ast_node_t *pf = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; if (!pf) return 0; spl_type_id_t inner = infer_expr(sema, pf->prefix_expr.postfix_expr); if (!inner) return 0; inner = underlying(sema, inner); switch (pf->prefix_expr.kind) { case SPL_AST_MINUS_EXPR: if (!is_numeric_tid(sema, inner)) { sema_error(sema, ref, "unary minus requires numeric"); return 0; } return inner; case SPL_AST_BANG_EXPR: if (inner != underlying(sema, spl_type_bool(&sema->type))) { sema_error(sema, ref, "! requires bool"); return 0; } return spl_type_bool(&sema->type); case SPL_AST_TILDE_EXPR: if (!is_int_tid(sema, inner)) { sema_error(sema, ref, "~ requires integer"); return 0; } return inner; case SPL_AST_AMPERSAND_EXPR: if (type_node(sema, inner) && type_node(sema, inner)->kind == SPL_TYPE_FN) return inner; /* &foo 为函数值(fn 类型),非常规指针 */ return spl_type_ptr(&sema->type, inner); case SPL_AST_ASTERISK_EXPR: /* 前缀 * 不在 SPL 中使用(解引用为后缀 .*),忽略 */ return inner; default: return 0; } } /* 后缀运算 */ static spl_type_id_t infer_postfix(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *n) { spl_ast_node_t *pf = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; if (!pf) return 0; spl_type_id_t base = infer_expr(sema, pf->postfix_expr.primary_expr); if (!base) return 0; base = underlying(sema, base); switch (pf->postfix_expr.kind) { case SPL_AST_FIELD_EXPR: { spl_type_node_t *t = type_node(sema, base); /* 指针自动解引用一层 */ if (t && t->kind == SPL_TYPE_PTR) base = underlying(sema, t->ptr_pointee); /* 注解:FIELD 节点 → 被访问聚合(自动解引用后)的 AGG def;非聚合为 0 */ pf->resolved_def_id = def_for_type(sema, base); t = type_node(sema, base); if (!t) { sema_error(sema, ref, "field access on non-aggregate"); return 0; } /* 切片字段 len/ptr 优先于聚合检查 */ if (t->kind == SPL_TYPE_SLICE) { if (strcmp(pf->postfix_expr.field_expr, "len") == 0) return spl_type_int(&sema->type, sizeof(usize) * 8, 0); if (strcmp(pf->postfix_expr.field_expr, "ptr") == 0) return spl_type_ptr(&sema->type, t->slice_element); sema_error(sema, ref, "unknown slice field"); return 0; } /* Range 内置字段 begin/end:元素类型 */ if (t->kind == SPL_TYPE_RANGE) { if (strcmp(pf->postfix_expr.field_expr, "begin") == 0 || strcmp(pf->postfix_expr.field_expr, "end") == 0) return t->range_element; sema_error(sema, ref, "unknown range field"); return 0; } if (!is_agg_tid(sema, base)) { sema_error(sema, ref, "field access on non-aggregate"); return 0; } spl_type_id_t mt = agg_member_type(sema, base, pf->postfix_expr.field_expr); if (!mt) { sema_error(sema, ref, "unknown field"); return 0; } /* 枚举变体表达式:带载荷变体(payload 为 struct/整数)整体值为枚举类型; * 方法(fn)/嵌套类型/无载荷固标保持 member 类型 */ spl_type_node_t *mtt = mt ? type_node(sema, underlying(sema, mt)) : NULL; if (t && t->kind == SPL_TYPE_ENUM && mtt && (mtt->kind == SPL_TYPE_STRUCT || mtt->kind == SPL_TYPE_INT)) return base; return mt; } case SPL_AST_DEREF_EXPR: { spl_type_node_t *t = type_node(sema, base); if (!t || t->kind != SPL_TYPE_PTR) { sema_error(sema, ref, ".* requires pointer"); return 0; } /* *_(即 *void)类型已丢失,不可解引用,须先转换为具体指针 */ spl_type_id_t pt = underlying(sema, t->ptr_pointee); spl_type_node_t *ptn = type_node(sema, pt); if (ptn && ptn->kind == SPL_TYPE_VOID) { sema_error(sema, ref, "cannot dereference `*_`; cast to a concrete pointer first"); return 0; } return underlying(sema, t->ptr_pointee); } case SPL_AST_INDEX_EXPR: { spl_type_node_t *t = type_node(sema, base); spl_type_id_t idx = infer_expr(sema, pf->postfix_expr.index_expr); t = type_node(sema, base); if (!is_int_tid(sema, underlying(sema, idx))) { sema_error(sema, ref, "index requires integer"); return 0; } if (t && t->kind == SPL_TYPE_ARRAY) return t->array_type.element; if (t && t->kind == SPL_TYPE_SLICE) return t->slice_element; if (t && t->kind == SPL_TYPE_PTR) return underlying(sema, t->ptr_pointee); sema_error(sema, ref, "index requires array/slice/pointer"); return 0; } case SPL_AST_SLICE_EXPR: { spl_type_node_t *t = type_node(sema, base); if (pf->postfix_expr.slice_expr.begin) infer_expr(sema, pf->postfix_expr.slice_expr.begin); if (pf->postfix_expr.slice_expr.end) infer_expr(sema, pf->postfix_expr.slice_expr.end); t = type_node(sema, base); if (t && t->kind == SPL_TYPE_ARRAY) return spl_type_slice(&sema->type, t->array_type.element); if (t && t->kind == SPL_TYPE_SLICE) return spl_type_slice(&sema->type, t->slice_element); sema_error(sema, ref, "slice requires array/slice"); return 0; } case SPL_AST_CALL_EXPR: { spl_type_node_t *t = type_node(sema, base); if (!t || t->kind != SPL_TYPE_FN) { sema_error(sema, ref, "call requires function type"); return 0; } /* 注解:CALL 节点 → 被调 fn 的 def(从 callee primary 节点/裸名解析) */ pf->resolved_def_id = expr_def_at(sema, pf->postfix_expr.primary_expr); spl_ast_node_ref_vec_t *args = &pf->postfix_expr.call_expr; /* 变参 fn(如 vm_printf)最后一个形参 name=NULL 且类型可为 0 */ /* 注意:infer_expr 可能新分配类型使 type_table realloc,t 会失效,须每次刷新 */ usize nparams = t->fn_type.params.size; for (usize i = 0; i < args->size; i++) { spl_type_id_t at = infer_expr(sema, args->data[i]); t = type_node(sema, base); if (i < nparams && t && t->fn_type.params.data[i]) { int w = 0; if (!expr_is_null_literal(sema, args->data[i]) && at && !type_compatible(sema, t->fn_type.params.data[i], at, expr_is_literal(sema, args->data[i]), &w)) { sema_error(sema, args->data[i], "argument type mismatch"); } } } t = type_node(sema, base); return t ? t->fn_type.ret : 0; } case SPL_AST_AS_EXPR: { spl_type_id_t st = infer_expr(sema, pf->postfix_expr.primary_expr); if (!st) return 0; spl_type_id_t dt = 0; if (pf->postfix_expr.type_expr) { /* 未知类型已由 resolve_type_atom 报错,此处不重复报"缺目标类型" */ dt = resolve_type_expr(sema, pf->postfix_expr.type_expr); } else { sema_error(sema, ref, "as requires a target type"); } if (!dt) return 0; return dt; } default: return 0; } } /* 表达式类型推断 */ static spl_type_id_t infer_expr(spl_sema_t *sema, spl_ast_node_ref_t ref) { if (!ref) return 0; spl_ast_node_t *n = node_at(sema->ast, ref); if (!n) return 0; spl_type_id_t tid = 0; if (n->kind == SPL_AST_EXPR) { switch (n->expr.op) { case SPL_AST_PRIMARY_EXPR: tid = infer_primary(sema, ref, n); break; case SPL_AST_PREFIX_EXPR: tid = infer_prefix(sema, ref, n); break; case SPL_AST_POSTFIX_EXPR: tid = infer_postfix(sema, ref, n); break; case SPL_AST_RANGE_EXPR: { spl_type_id_t l = 0, r = 0; if (n->expr.op_expr.left) l = underlying(sema, infer_expr(sema, n->expr.op_expr.left)); if (n->expr.op_expr.right) r = underlying(sema, infer_expr(sema, n->expr.op_expr.right)); if ((l && !is_int_tid(sema, l)) || (r && !is_int_tid(sema, r)) || (!l && !r)) { sema_error(sema, ref, "range bounds must be integers"); return 0; } return spl_type_range(&sema->type, r ? r : l); } case SPL_AST_ASSIGN_EXPR: case SPL_AST_ASSIGN_ADD_EXPR: case SPL_AST_ASSIGN_sUB_EXPR: case SPL_AST_ASSIGN_MUL_EXPR: case SPL_AST_ASSIGN_DIV_EXPR: case SPL_AST_ASSIGN_MOD_EXPR: case SPL_AST_ASSIGN_AND_EXPR: case SPL_AST_ASSIGN_OR_EXPR: case SPL_AST_ASSIGN_XOR_EXPR: case SPL_AST_ASSIGN_LSHIFT_EXPR: case SPL_AST_ASSIGN_USHIFT_EXPR: { spl_type_id_t l = infer_expr(sema, n->expr.op_expr.left); spl_type_id_t r = infer_expr(sema, n->expr.op_expr.right); if (!l || (!r && !expr_is_null_literal(sema, n->expr.op_expr.right))) { sema_error(sema, ref, "bad assignment"); return 0; } /* 不可写检查:赋值目标为 const 变量时拒绝 */ { spl_ast_node_t *lhs = node_at(sema->ast, n->expr.op_expr.left); if (lhs && lhs->kind == SPL_AST_EXPR && lhs->expr.op == SPL_AST_PRIMARY_EXPR) { spl_ast_node_t *lpn = node_at(sema->ast, lhs->expr.op_expr.left); if (lpn && lpn->kind == SPL_AST_EXPR && lpn->primary_expr.kind == SPL_AST_IDENT && lpn->resolved_def_id) { spl_def_node_t *ld = def_at(sema, lpn->resolved_def_id); if (ld && ld->kind == SPL_DEF_VAR && ld->var_def.is_const) { sema_error(sema, ref, "cannot assign to const"); return 0; } } } } int w = 0; if (!expr_is_null_literal(sema, n->expr.op_expr.right) && !type_compatible(sema, l, r, expr_is_literal(sema, n->expr.op_expr.right), &w)) { sema_error(sema, ref, "assignment type mismatch"); return 0; } return l; } default: tid = infer_binary(sema, ref, n); break; } } return tid; } /* ---- 语句类型检查 ---- */ static void check_stmt(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_sema_ctx_t ctx); static void check_block(spl_sema_t *sema, spl_ast_node_ref_vec_t *block, spl_scope_id_t parent, spl_sema_ctx_t ctx); static spl_type_id_t infer_agg_init_with_type(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_type_id_t expect); /* var/const 初始化与类型注解兼容性检查;name 用于 `var x := e` 推导类型回写 */ static void check_var_init(spl_sema_t *sema, spl_ast_node_ref_t ref, const char *name, spl_ast_node_ref_t type_expr, spl_ast_node_ref_t init_expr, spl_sema_ctx_t ctx) { (void)ctx; (void)type_expr; /* dt 取自已登记 def 的类型(check_block 已预登记),避免二次解析重复报错 */ spl_type_id_t dt = 0; if (name) { spl_scope_id_t cur = sema->current_scope; while (cur) { spl_def_id_t val = 0; if (map_get(sema->scopes.data[cur].symbols, name, &val)) { dt = def_type(sema, val); break; } cur = sema->scopes.data[cur].parent; } } spl_type_id_t it = 0; if (init_expr) { it = infer_expr(sema, init_expr); if (!it && !expr_is_null_literal(sema, init_expr)) { /* 匿名聚合依赖上下文类型 */ spl_ast_node_t *in = node_at(sema->ast, init_expr); if (in && in->kind == SPL_AST_EXPR && in->expr.op == SPL_AST_PRIMARY_EXPR) { spl_ast_node_t *pn = node_at(sema->ast, in->expr.op_expr.left); if (pn && pn->primary_expr.kind == SPL_AST_ARGGREGATE_INIT && dt) { spl_type_id_t save_scope = sema->current_scope; it = infer_agg_init_with_type(sema, init_expr, dt); sema->current_scope = save_scope; } } } if (dt) { int w = 0; if (!expr_is_null_literal(sema, init_expr) && it && !type_compatible(sema, dt, it, expr_is_literal(sema, init_expr), &w)) { sema_error(sema, ref, "initializer type mismatch"); } else if (w) { sema_warn(sema, ref, "pointer conversion involves wildcard"); } } else if (it && name) { /* `var x := e` 推导类型回写 binding def */ spl_scope_id_t cur = sema->current_scope; while (cur) { spl_def_id_t val = 0; if (map_get(sema->scopes.data[cur].symbols, name, &val)) { spl_def_node_t *d = def_at(sema, val); if (d && d->kind == SPL_DEF_VAR) { d->type_id = it; d->var_def.type_id = it; } break; } cur = sema->scopes.data[cur].parent; } } } } /* 带期望类型的匿名聚合推断 */ static spl_type_id_t infer_agg_init_with_type(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_type_id_t expect) { spl_ast_node_t *n = node_at(sema->ast, ref); spl_ast_node_t *pn = n->kind == SPL_AST_EXPR ? node_at(sema->ast, n->expr.op_expr.left) : n; if (!pn || pn->primary_expr.kind != SPL_AST_ARGGREGATE_INIT) return 0; spl_type_id_t tid = underlying(sema, expect); if (!type_node(sema, tid)) return 0; for (usize i = 0; i < pn->primary_expr.aggregate_init.expr.size; i++) { spl_ast_node_ref_t iref = pn->primary_expr.aggregate_init.expr.data[i]; spl_ast_node_t *item = node_at(sema->ast, iref); if (!item) continue; spl_type_node_t *tn = type_node(sema, tid); spl_type_id_t mt = 0; /* 切片 {} 字面量支持 .ptr/.len */ if (tn->kind == SPL_TYPE_SLICE) { if (strcmp(item->aggregate_init_item.ident, "ptr") == 0) mt = spl_type_ptr(&sema->type, tn->slice_element); else if (strcmp(item->aggregate_init_item.ident, "len") == 0) mt = spl_type_int(&sema->type, sizeof(usize) * 8, 0); else { sema_error(sema, iref, "unknown field in slice literal"); continue; } } else if (is_agg_tid(sema, tid)) { mt = agg_member_type(sema, tid, item->aggregate_init_item.ident); if (!mt) { sema_error(sema, iref, "unknown field in aggregate literal"); continue; } } else { sema_error(sema, iref, "literal target not an aggregate"); continue; } if (item->aggregate_init_item.expr) { spl_type_id_t et = infer_expr(sema, item->aggregate_init_item.expr); int w = 0; if (!expr_is_null_literal(sema, item->aggregate_init_item.expr) && et && !type_compatible(sema, mt, et, expr_is_literal(sema, item->aggregate_init_item.expr), &w)) { sema_error(sema, iref, "field type mismatch in aggregate literal"); } } } return tid; } /* for 循环:序列类型 Range/[]T/[N]T,变量个数匹配 */ static void check_for(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *b, spl_sema_ctx_t ctx) { spl_ast_node_ref_vec_t *expr_vec = &b->block_item.for_statement.expr_vec; char **id_data = b->block_item.for_statement.ident_vec.data; usize id_size = b->block_item.for_statement.ident_vec.size; if (expr_vec->size != id_size) { sema_error(sema, ref, "for: sequence/variable count mismatch"); return; } spl_scope_id_t scope = spl_sema_scope_alloc(sema); sema->scopes.data[scope].parent = sema->current_scope; spl_scope_id_t save = sema->current_scope; sema->current_scope = scope; for (usize i = 0; i < expr_vec->size; i++) { spl_type_id_t et = infer_expr(sema, expr_vec->data[i]); et = underlying(sema, et); spl_type_node_t *t = type_node(sema, et); spl_type_id_t elem = 0; if (t && t->kind == SPL_TYPE_SLICE) elem = t->slice_element; else if (t && t->kind == SPL_TYPE_ARRAY) elem = t->array_type.element; else if (t && t->kind == SPL_TYPE_RANGE) /* Range 遍历绑定元素类型(0..n 通常为 usize 索引遍历) */ elem = t->range_element; else { sema_error(sema, expr_vec->data[i], "for: sequence must be Range/[]T/[N]T"); continue; } spl_def_id_t vdef = new_var_def(sema, id_data[i], elem, scope); spl_sema_scope_insert(sema, scope, id_data[i], vdef); } check_block(sema, &b->block_item.for_statement.block, scope, ctx); sema->current_scope = save; } /* match:被匹配表达式须为枚举/union;臂体类型一致性本轮简化为逐臂检查 */ static void check_match(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_ast_node_t *b, spl_sema_ctx_t ctx) { spl_type_id_t mtype = infer_expr(sema, b->block_item.match_statement.expr); mtype = underlying(sema, mtype); spl_type_node_t *t = type_node(sema, mtype); /* 指针自动解引用 */ if (t && t->kind == SPL_TYPE_PTR) mtype = underlying(sema, t->ptr_pointee); t = type_node(sema, mtype); if (t && t->kind != SPL_TYPE_ENUM && t->kind != SPL_TYPE_UNION && !is_int_tid(sema, mtype)) { sema_error(sema, b->block_item.match_statement.expr, "match subject must be enum/union/integer"); } spl_ast_node_ref_vec_t *arms = &b->block_item.match_statement.paced_exprs; spl_ast_node_ref_vec_t *bodies = &b->block_item.match_statement.match_block; if (arms->size != bodies->size) { sema_error(sema, ref, "match: arm pattern/body count mismatch"); return; } /* 穷举检查:enum 必须覆盖所有变体,或含通配 _(含表达式的整数 match 免检) */ { spl_def_id_t adef = def_for_type(sema, mtype); spl_def_node_t *ad = adef ? &sema->type.def_table.data[adef] : NULL; int is_enum_agg = ad && ad->kind == SPL_DEF_AGG; if (is_enum_agg) { int has_wild = 0; usize covered = 0; for (usize i = 0; i < arms->size; i++) { spl_ast_node_t *pk = node_at(sema->ast, arms->data[i]); if (!pk) continue; /* _ 通配:ident 与 expr 均为空 */ if (!pk->packed_expr.ident && !pk->packed_expr.expr) { has_wild = 1; break; } if (pk->packed_expr.ident) { /* 变体被覆盖:匹配臂中出现的合法变体计数 */ if (agg_member_type(sema, mtype, pk->packed_expr.ident)) covered++; } } if (!has_wild && covered < ad->agg_def.size) sema_error(sema, ref, "match must be exhaustive"); } } for (usize i = 0; i < arms->size; i++) { spl_ast_node_t *pk = node_at(sema->ast, arms->data[i]); if (!pk) continue; /* 每个臂体是 BLOCK_EXPR,有自己的 scope */ spl_scope_id_t scope = spl_sema_scope_alloc(sema); sema->scopes.data[scope].parent = sema->current_scope; spl_scope_id_t save = sema->current_scope; sema->current_scope = scope; if (pk->packed_expr.ident) { /* 变体模式:若带绑定则登记绑定变量 */ if (is_agg_tid(sema, mtype) && pk->packed_expr.bind_ident) { spl_type_id_t vt = agg_member_type(sema, mtype, pk->packed_expr.ident); if (vt && vt != mtype) { spl_def_id_t vdef = new_var_def(sema, pk->packed_expr.bind_ident, vt, scope); spl_sema_scope_insert(sema, scope, pk->packed_expr.bind_ident, vdef); } } else if (is_agg_tid(sema, mtype)) { if (!agg_member_type(sema, mtype, pk->packed_expr.ident)) sema_error(sema, arms->data[i], "unknown variant in match arm"); } } else if (pk->packed_expr.expr) { spl_type_id_t et = infer_expr(sema, pk->packed_expr.expr); int w = 0; if (is_int_tid(sema, mtype) && et && !type_compatible(sema, mtype, et, expr_is_literal(sema, pk->packed_expr.expr), &w)) { sema_error(sema, pk->packed_expr.expr, "match arm pattern type mismatch"); } } /* 检查臂体 */ spl_ast_node_t *body = node_at(sema->ast, bodies->data[i]); if (body && body->kind == SPL_AST_EXPR && body->expr.op == SPL_AST_PRIMARY_EXPR) { spl_ast_node_t *pn = node_at(sema->ast, body->expr.op_expr.left); if (pn && pn->primary_expr.kind == SPL_AST_BLOCK_EXPR) { check_block(sema, &pn->primary_expr.block_expr, scope, ctx); } else { infer_expr(sema, bodies->data[i]); } } sema->current_scope = save; } } /* 单个语句检查 */ static void check_stmt(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_sema_ctx_t ctx) { spl_ast_node_t *b = node_at(sema->ast, ref); if (!b) return; if (b->kind == SPL_AST_EXPR) { /* 裸 { } 块作为语句:不产生值,仅检查其内部 */ if (b->expr.op == SPL_AST_PRIMARY_EXPR) { spl_ast_node_t *pn = node_at(sema->ast, b->expr.op_expr.left); if (pn && pn->primary_expr.kind == SPL_AST_BLOCK_EXPR) { check_block(sema, &pn->primary_expr.block_expr, sema->current_scope, ctx); return; } } infer_expr(sema, ref); return; } switch (b->block_item.kind) { case SPL_AST_VARDECL: { spl_ast_node_t *vd = node_at(sema->ast, b->block_item.var_decl); if (vd) check_var_init(sema, b->block_item.var_decl, vd->var_decl.name, vd->var_decl.type_expr, vd->var_decl.expr, ctx); break; } case SPL_AST_CONSTDECL: { spl_ast_node_t *cd = node_at(sema->ast, b->block_item.const_decl); if (cd) check_var_init(sema, b->block_item.const_decl, cd->const_decl.name, cd->const_decl.type_expr, cd->const_decl.expr, ctx); break; } case SPL_AST_TYPEDECL: break; case SPL_AST_IF_STATEMENT: { spl_type_id_t c = infer_expr(sema, b->block_item.if_statement.expr); c = underlying(sema, c); if (c && c != underlying(sema, spl_type_bool(&sema->type))) sema_error(sema, b->block_item.if_statement.expr, "if condition must be bool"); spl_scope_id_t sc = sema->current_scope; check_block(sema, &b->block_item.if_statement.if_block, sc, ctx); if (b->block_item.if_statement.else_block.size) check_block(sema, &b->block_item.if_statement.else_block, sc, ctx); break; } case SPL_AST_IFVAR_STATEMENT: { spl_ast_node_t *pk = node_at(sema->ast, b->block_item.ifvar_statement.packed_expr); spl_type_id_t vt = 0; if (pk && pk->packed_expr.expr) vt = infer_expr(sema, pk->packed_expr.expr); spl_scope_id_t sc = sema->current_scope; if (pk && pk->packed_expr.bind_ident && vt) { spl_scope_id_t s2 = spl_sema_scope_alloc(sema); sema->scopes.data[s2].parent = sc; spl_def_id_t vdef = new_var_def(sema, pk->packed_expr.bind_ident, underlying(sema, vt), s2); spl_sema_scope_insert(sema, s2, pk->packed_expr.bind_ident, vdef); sema->current_scope = s2; } check_block(sema, &b->block_item.ifvar_statement.if_block, sema->current_scope, ctx); sema->current_scope = sc; if (b->block_item.ifvar_statement.else_block.size) check_block(sema, &b->block_item.ifvar_statement.else_block, sc, ctx); break; } case SPL_AST_WHILE_STATEMENT: { spl_type_id_t c = infer_expr(sema, b->block_item.while_statement.expr); c = underlying(sema, c); if (c && c != underlying(sema, spl_type_bool(&sema->type))) sema_error(sema, b->block_item.while_statement.expr, "while condition must be bool"); check_block(sema, &b->block_item.while_statement.while_block, sema->current_scope, ctx); break; } case SPL_AST_LOOP_STATEMENT: check_block(sema, &b->block_item.loop_statement.loop_block, sema->current_scope, ctx); break; case SPL_AST_FOR_STATEMENT: check_for(sema, ref, b, ctx); break; case SPL_AST_MATCH_STATEMENT: check_match(sema, ref, b, ctx); break; case SPL_AST_RET_STATEMENT: { spl_ast_node_t *rd = b; if (rd->block_item.ret_statement.expr) { spl_type_id_t et = infer_expr(sema, rd->block_item.ret_statement.expr); if (ctx.ret) { if (!expr_is_null_literal(sema, rd->block_item.ret_statement.expr) && et && !type_compatible(sema, ctx.ret, et, expr_is_literal(sema, rd->block_item.ret_statement.expr), NULL)) { sema_error(sema, rd->block_item.ret_statement.expr, "ret type mismatch"); } } } break; } case SPL_AST_BREAK_STATEMENT: case SPL_AST_CONTINUE_STATEMENT: break; case SPL_AST_DEFER_STATEMENT: check_block(sema, &b->block_item.defer_statement.block_or_statement, sema->current_scope, ctx); break; case SPL_AST_EXPR_STATEMENT: if (b->block_item.expr_statement) infer_expr(sema, b->block_item.expr_statement); break; default: break; } } /* 块检查:为块建子 scope 并检查其中语句 */ static void check_block(spl_sema_t *sema, spl_ast_node_ref_vec_t *block, spl_scope_id_t parent, spl_sema_ctx_t ctx) { spl_scope_id_t scope = spl_sema_scope_alloc(sema); sema->scopes.data[scope].parent = parent; spl_scope_id_t save = sema->current_scope; sema->current_scope = scope; /* 变量声明先登记进本块 scope,随后语句检查 */ for (usize i = 0; i < block->size; i++) { spl_ast_node_t *b = node_at(sema->ast, block->data[i]); if (!b || b->kind == SPL_AST_EXPR) continue; if (b->block_item.kind == SPL_AST_VARDECL) { spl_ast_node_t *vd = node_at(sema->ast, b->block_item.var_decl); if (vd) register_binding(sema, vd->var_decl.name, vd->var_decl.type_expr, scope, 0, b->block_item.var_decl); } else if (b->block_item.kind == SPL_AST_CONSTDECL) { spl_ast_node_t *cd = node_at(sema->ast, b->block_item.const_decl); if (cd) { register_binding(sema, cd->const_decl.name, cd->const_decl.type_expr, scope, 0, b->block_item.const_decl); /* 标记 const:赋值检查拒绝写入 */ spl_ast_node_t *cn = node_at(sema->ast, b->block_item.const_decl); if (cn && cn->resolved_def_id) { spl_def_node_t *cdd = def_at(sema, cn->resolved_def_id); if (cdd) cdd->var_def.is_const = 1; } } } else if (b->block_item.kind == SPL_AST_TYPEDECL) { spl_ast_node_t *td = node_at(sema->ast, b->block_item.type_decl); if (td) sema_type_decl(sema, b->block_item.type_decl, scope, 0); } } for (usize i = 0; i < block->size; i++) check_stmt(sema, block->data[i], ctx); sema->current_scope = save; } /* 函数体检查:新建 fn_scope、登记形参(复用 def 里的 fn_params_def 类型),随后检查块 */ static void check_fn_body(spl_sema_t *sema, spl_ast_node_ref_t ref, spl_def_id_t fdef, spl_scope_id_t parent_scope) { spl_ast_node_t *n = node_at(sema->ast, ref); if (!n || !fdef) return; spl_type_id_t fid = def_type(sema, fdef); spl_type_id_t ret = 0; spl_type_node_t *ft = type_node(sema, fid); if (ft && ft->kind == SPL_TYPE_FN) ret = ft->fn_type.ret; spl_sema_ctx_t ctx = {ret}; spl_scope_id_t fn_scope = spl_sema_scope_alloc(sema); sema->scopes.data[fn_scope].parent = parent_scope; spl_scope_id_t save = sema->current_scope; sema->current_scope = fn_scope; /* 先复制参数信息,避免 new_var_def 触发 def_table 扩容使指针失效 */ spl_def_node_t *d = def_at(sema, fdef); usize nparams = d ? d->fn_params_def.size : 0; for (usize i = 0; i < nparams; i++) { d = def_at(sema, fdef); spl_var_def_t *pv = &d->fn_params_def.data[i]; if (pv->name) { spl_def_id_t pdef = new_var_def(sema, pv->name, pv->type_id, fn_scope); spl_sema_scope_insert(sema, fn_scope, pv->name, pdef); /* 注解:param_decl → 其在 fn_scope 的 VAR def */ spl_ast_node_t *pd = node_at(sema->ast, n->fn_decl.param_list.data[i]); if (pd) pd->resolved_def_id = pdef; } } check_block(sema, &n->fn_decl.block, fn_scope, ctx); sema->current_scope = save; } void spl_sema_init(spl_sema_t *sema) { memset(sema, 0, sizeof *sema); spl_type_init(&sema->type); vec_init(sema->scopes); /* scope id 0 保留为 error */ spl_scope_node_t s0; memset(&s0, 0, sizeof s0); map_init(s0.symbols, MAP_HASH_STR, MAP_CMP_STR); vec_push(sema->scopes, s0); sema->root_scope = spl_sema_scope_alloc(sema); sema->current_scope = sema->root_scope; /* 文件聚合根:$root 即文件聚合(root_def = AGG,成员为顶层声明) */ spl_type_id_t root_type = spl_type_alloc(&sema->type); spl_type_node_t *rn = spl_type_node(&sema->type, root_type); rn->kind = SPL_TYPE_STRUCT; vec_init(rn->agg_field_types); sema->root_def = def_alloc(sema, SPL_DEF_AGG); def_at(sema, sema->root_def)->type_id = root_type; vec_init(def_at(sema, sema->root_def)->agg_def); /* 关键字类型注册进 root(每个关键字一个 BUILTIN def) */ #define SPL_REG_KEYWORD(nm, tid) \ do { \ spl_def_id_t _d = def_alloc(sema, SPL_DEF_BUILTIN); \ def_at(sema, _d)->type_id = (tid); \ spl_sema_scope_insert(sema, sema->root_scope, (nm), _d); \ } while (0) SPL_REG_KEYWORD("void", spl_type_void(&sema->type)); SPL_REG_KEYWORD("bool", spl_type_bool(&sema->type)); SPL_REG_KEYWORD("i8", spl_type_int(&sema->type, 8, 1)); SPL_REG_KEYWORD("u8", spl_type_int(&sema->type, 8, 0)); SPL_REG_KEYWORD("i16", spl_type_int(&sema->type, 16, 1)); SPL_REG_KEYWORD("u16", spl_type_int(&sema->type, 16, 0)); SPL_REG_KEYWORD("i32", spl_type_int(&sema->type, 32, 1)); SPL_REG_KEYWORD("u32", spl_type_int(&sema->type, 32, 0)); SPL_REG_KEYWORD("i64", spl_type_int(&sema->type, 64, 1)); SPL_REG_KEYWORD("u64", spl_type_int(&sema->type, 64, 0)); SPL_REG_KEYWORD("isize", spl_type_int(&sema->type, sizeof(isize) * 8, 1)); SPL_REG_KEYWORD("usize", spl_type_int(&sema->type, sizeof(usize) * 8, 0)); SPL_REG_KEYWORD("f32", spl_type_float(&sema->type, 32)); SPL_REG_KEYWORD("f64", spl_type_float(&sema->type, 64)); #undef SPL_REG_KEYWORD } void spl_sema_drop(spl_sema_t *sema) { for (usize i = 0; i < sema->scopes.size; i++) map_free(sema->scopes.data[i].symbols); vec_free(sema->scopes); spl_type_drop(&sema->type); } /* Pass1:预登记顶层名字,使兄弟/自引用成立(不解析成员、不检查函数体) */ void spl_sema_run(spl_sema_t *sema) { if (!sema->ast || !sema->ast->root) return; spl_ast_node_t *c = node_at(sema->ast, sema->ast->root); if (!c || c->kind != SPL_AST_CONTAINER_ITEM) return; LOG_DEBUG("sema_run root=%zu kind=%d members=%zu", sema->ast->root, c->kind, c->container_item.members.size); sema->current_scope = sema->root_scope; /* 1a. 聚合壳 + 别名(类型名先全部登记,兄弟聚合可互引) */ for (usize i = 0; i < c->container_item.members.size; i++) { spl_ast_node_ref_t mref = c->container_item.members.data[i]; spl_ast_node_t *m = node_at(sema->ast, mref); if (!m || m->kind != SPL_AST_TYPE_DECL) continue; spl_ast_node_t *te = node_at(sema->ast, m->type_decl.type_expr); if (te && (te->type_expr.kind == SPL_AST_TYPE_STRUCT || te->type_expr.kind == SPL_AST_TYPE_UNION || te->type_expr.kind == SPL_AST_TYPE_ENUM)) { agg_handle_t h = agg_prepare(sema, m->type_decl.type_expr); if (!h.def) continue; if (!spl_sema_scope_insert(sema, sema->root_scope, m->type_decl.name, h.def)) sema_error(sema, mref, "duplicate type name"); agg_add_member(sema, sema->root_def, m->type_decl.name, h.tid, sema->root_scope, h.def); } else if (te) { spl_type_id_t tid = resolve_type_expr(sema, m->type_decl.type_expr); spl_def_id_t def = def_alloc(sema, SPL_DEF_ALIAS); spl_def_node_t *d = def_at(sema, def); d->type_id = tid; d->type_def.name = m->type_decl.name; d->type_def.def_id = def; d->type_def.type_id = tid; d->type_def.scope_id = sema->root_scope; if (!spl_sema_scope_insert(sema, sema->root_scope, m->type_decl.name, def)) sema_error(sema, mref, "duplicate type name"); agg_add_member(sema, sema->root_def, m->type_decl.name, tid, sema->root_scope, def); } } /* 1b. fn 名(建 fn type + def) */ for (usize i = 0; i < c->container_item.members.size; i++) { spl_ast_node_ref_t mref = c->container_item.members.data[i]; spl_ast_node_t *m = node_at(sema->ast, mref); if (!m) continue; if (m->kind == SPL_AST_FN_DECL || m->kind == SPL_AST_FN_DEFINE) sema_fn_decl(sema, mref, sema->root_scope, sema->root_def); } /* 1c. 顶层 var/const */ for (usize i = 0; i < c->container_item.members.size; i++) { spl_ast_node_ref_t mref = c->container_item.members.data[i]; spl_ast_node_t *m = node_at(sema->ast, mref); if (!m) continue; if (m->kind == SPL_AST_VAR_DECL) sema_var_decl(sema, mref, sema->root_scope, sema->root_def); else if (m->kind == SPL_AST_CONST_DECL) sema_const_decl(sema, mref, sema->root_scope, sema->root_def); else if (m->kind == SPL_AST_MEMBER_DECL && m->member_decl.name) register_binding(sema, m->member_decl.name, m->member_decl.type_expr, sema->root_scope, sema->root_def, mref); } sema->current_scope = sema->root_scope; } /* Pass2:构建聚合成员(含方法 def)并检查函数体,一次遍历完成 */ void spl_sema_check(spl_sema_t *sema) { if (!sema->ast || !sema->ast->root) return; spl_ast_node_t *c = node_at(sema->ast, sema->ast->root); if (!c || c->kind != SPL_AST_CONTAINER_ITEM) return; sema->current_scope = sema->root_scope; /* 构建所有顶层聚合成员 */ for (usize i = 0; i < c->container_item.members.size; i++) { spl_ast_node_ref_t mref = c->container_item.members.data[i]; spl_ast_node_t *m = node_at(sema->ast, mref); if (!m || m->kind != SPL_AST_TYPE_DECL) continue; spl_ast_node_t *te = node_at(sema->ast, m->type_decl.type_expr); if (te && (te->type_expr.kind == SPL_AST_TYPE_STRUCT || te->type_expr.kind == SPL_AST_TYPE_UNION || te->type_expr.kind == SPL_AST_TYPE_ENUM)) { spl_def_id_t def = find_bare(sema, m->type_decl.name); if (!def) continue; agg_resolve(sema, m->type_decl.type_expr, def_type(sema, def), def, sema->root_scope, m->type_decl.name); } } /* 检查顶层函数体 */ for (usize i = 0; i < c->container_item.members.size; i++) { spl_ast_node_ref_t mref = c->container_item.members.data[i]; spl_ast_node_t *m = node_at(sema->ast, mref); if (!m || m->kind != SPL_AST_FN_DEFINE) continue; spl_def_id_t def = find_bare(sema, m->fn_decl.name); check_fn_body(sema, mref, def, sema->root_scope); } sema->current_scope = sema->root_scope; } spl_scope_id_t spl_sema_scope_alloc(spl_sema_t *sema) { spl_scope_node_t n; memset(&n, 0, sizeof n); map_init(n.symbols, MAP_HASH_STR, MAP_CMP_STR); vec_push(sema->scopes, n); return sema->scopes.size - 1; } bool spl_sema_scope_insert(spl_sema_t *sema, spl_scope_id_t id, const char *symbol_name, spl_def_id_t symbol_val) { if (!id || id >= sema->scopes.size) return false; spl_def_id_t old = 0; if (map_get(sema->scopes.data[id].symbols, symbol_name, &old)) return false; map_put(sema->scopes.data[id].symbols, symbol_name, symbol_val); return true; } spl_def_id_t spl_sema_scope_find(spl_sema_t *sema, spl_symbol_path_t path) { if (!path.size) return 0; spl_def_id_t def = find_bare(sema, path.data[0]); if (!def) return 0; for (usize i = 1; i < path.size; i++) { spl_type_id_t t = def_type(sema, def); spl_def_id_t owner = def_for_type(sema, t); if (!owner) return 0; spl_def_node_t *od = def_at(sema, owner); spl_def_id_t next = 0; for (usize j = 0; j < od->agg_def.size; j++) { if (od->agg_def.data[j].name && strcmp(od->agg_def.data[j].name, path.data[i]) == 0) { next = od->agg_def.data[j].def_id ? od->agg_def.data[j].def_id : def_for_type(sema, od->agg_def.data[j].type_id); break; } } if (!next) return 0; def = next; } return def; }