Files
spl/stage1/spl_sema.c
2026-08-06 19:26:30 +08:00

2019 lines
83 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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_tdef 第一公民);匿名类型放 type_table
* 命名实体放 def_table两张表 id 空间完全独立。
*/
#include "spl_sema.h"
#include "spl_builtin.h"
#include <stdio.h>
#include <string.h>
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聚合/别名/内置为 0ast2ir 据此直接取类型) */
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_defdef_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 可赋给 dstis_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 引用 → 其符号 defvar 用 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:
/* 字符串字面量:底层为 *u8NUL 终止。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 realloct 会失效,须每次刷新 */
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;
}