2019 lines
83 KiB
C
2019 lines
83 KiB
C
// 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 <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(聚合/别名/内置为 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;
|
||
}
|