Files
spl/stage1/spl_sema.c
T

1196 lines
42 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.
#include "spl_sema.h"
void spl_scope_init(spl_scope_t *scope) {
vec_init(scope->scopes);
vec_push(scope->scopes, (spl_scope_node_t){0});
scope->current_scope = 0;
scope->root_scope = 0;
}
void spl_scope_drop(spl_scope_t *scope) {
for (usize i = 0; i < vec_size(scope->scopes); ++i) {
map_free(vec_at(scope->scopes, i).symbols);
}
vec_free(scope->scopes);
scope->current_scope = 0;
scope->root_scope = 0;
}
spl_scope_id_t spl_scope_alloc(spl_scope_t *scope) {
spl_scope_node_t n = {0};
n.parent = scope->current_scope;
map_init(n.symbols, MAP_HASH_STR, MAP_CMP_STR);
vec_push(scope->scopes, n);
return vec_size(scope->scopes) - 1;
}
bool spl_scope_insert(spl_scope_t *scope, spl_scope_id_t id, spl_symbol_t symbol) {
if (!id || id >= vec_size(scope->scopes)) {
LOG_FATAL("sema scope insert error");
return false;
}
spl_scope_node_t *node = &vec_at(scope->scopes, id);
spl_symbol_t old = {0};
if (map_get(node->symbols, symbol.name, &old)) {
SPL_ERROR(&(spl_dbg_node_t){0}, "duplicate symbol `%s`", symbol.name);
return false;
}
map_put(node->symbols, symbol.name, symbol);
return true;
}
bool spl_scope_find(spl_scope_t *scope, const char *name, spl_symbol_t *out) {
if (!scope || !name || !out)
return false;
for (spl_scope_id_t id = scope->current_scope; id != 0; id = vec_at(scope->scopes, id).parent) {
spl_scope_node_t *s = &vec_at(scope->scopes, id);
if (map_get(s->symbols, name, out)) {
Assert(out->kind != SPL_SYMBOL_KIND_ERROR);
return true;
}
}
return false;
}
static inline void sema_push_scope(spl_sema_t *sema) {
spl_scope_id_t new_scope = spl_scope_alloc(sema->scope);
sema->store_scope = sema->scope->current_scope;
sema->scope->current_scope = new_scope;
}
static inline void sema_pop_scope(spl_sema_t *sema) {
sema->scope->current_scope = sema->store_scope;
}
static spl_type_id_t sema_coerce(spl_sema_t *sema, spl_type_id_t to, spl_type_id_t from) {
if (to == 0 || from == 0)
return 0;
spl_type_node_t *to_node = spl_type_node(sema->type, to);
// 目标类型是待推断,直接采用源类型
if (to_node && to_node->lang_kind == SPL_LANG_TYPE_INFER) {
return from;
}
spl_type_node_t *from_node = spl_type_node(sema->type, from);
if (!to_node || !from_node)
return 0;
// 源类型为未指定数值(bits==0)时,根据目标类型具体化
if (from_node->kind == SPL_TYPE_INT && from_node->int_type.bits == 0) {
if (to_node->kind == SPL_TYPE_INT) {
return to;
}
} else if (from_node->kind == SPL_TYPE_FLOAT && from_node->float_type.bits == 0) {
if (to_node->kind == SPL_TYPE_FLOAT) {
return to;
}
}
// 数组协变:若目标与源都是数组,且元素类型能 coerce,则返回目标数组类型
if (to_node->kind == SPL_TYPE_ARRAY && from_node->kind == SPL_TYPE_ARRAY) {
spl_type_id_t to_elem = to_node->array_type.element;
spl_type_id_t from_elem = from_node->array_type.element;
if (sema_coerce(sema, to_elem, from_elem) != 0) {
return to;
}
}
// 常规子类型检查
if (spl_type_is_subtype(sema->type, from, to)) {
return to;
}
return 0;
}
static spl_type_id_t sema_coerce_balance(spl_sema_t *sema, spl_type_id_t t1, spl_type_id_t t2) {
if (t1 == 0 || t2 == 0)
return 0;
if (t1 == t2)
return t1;
spl_type_node_t *n1 = spl_type_node(sema->type, t1);
spl_type_node_t *n2 = spl_type_node(sema->type, t2);
if (!n1 || !n2)
return 0;
// 处理 ANY(top)
if (n1->kind == SPL_TYPE_ANY || n2->kind == SPL_TYPE_ANY)
return spl_type_make_any(sema->type);
// 处理 NEVER(bottom)
if (n1->kind == SPL_TYPE_NEVER)
return t2;
if (n2->kind == SPL_TYPE_NEVER)
return t1;
// 其余逻辑保持原样,但最好改为使用子类型判断
if (spl_type_is_subtype(sema->type, t1, t2))
return t2;
if (spl_type_is_subtype(sema->type, t2, t1))
return t1;
return 0;
}
static bool sema_coerce_for_bool(spl_sema_t *sema, spl_type_id_t from) {
spl_type_id_t bool_tid = spl_type_make_bool(sema->type);
return sema_coerce(sema, bool_tid, from) == bool_tid;
}
static spl_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_type_id_t tid) {
spl_type_node_t *n = spl_type_node(sema->type, tid);
if (!n)
return 0;
switch (n->lang_kind) {
case SPL_LANG_TYPE_SLICE: {
const spl_type_member_t *ptr_member = spl_type_agg_member(sema->type, tid, "ptr");
if (!ptr_member)
return 0;
spl_type_node_t *ptr_node = spl_type_node(sema->type, ptr_member->type_id);
if (!ptr_node || ptr_node->kind != SPL_TYPE_PTR)
return 0;
return ptr_node->ptr_type.pointee;
}
default:
switch (n->kind) {
case SPL_TYPE_ARRAY:
return n->array_type.element;
case SPL_TYPE_PTR:
return n->ptr_type.pointee;
default:
return 0;
}
}
}
static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) {
spl_ast_node_t *n = spl_ast_node(sema->ast, ref);
if (!n)
return;
switch (n->kind) {
case SPL_AST_CONTAINER_MEMBERS: {
spl_symbol_t file_sym = {.name = "$file", .kind = SPL_SYMBOL_KIND_TYPE};
file_sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, "$file", n->dbg, ref);
n->resolved_def_id = file_sym.node;
spl_scope_id_t root_scope = spl_scope_alloc(sema->scope);
sema->scope->current_scope = root_scope;
sema->scope->root_scope = root_scope;
spl_scope_insert(sema->scope, root_scope, file_sym);
for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) {
sema_collect(sema, vec_at(n->container_members.declarations, i));
}
break;
}
case SPL_AST_TYPE_DECL: {
spl_symbol_t sym = {.name = n->type_decl.name, .kind = SPL_SYMBOL_KIND_TYPE};
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
if (!te) {
SPL_ERROR(&n->dbg, "type declaration `%s` missing type expression", n->type_decl.name);
sema->error_count++;
return;
}
if (te->kind == SPL_AST_TYPE_AGGREGATE) {
sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, sym.name, te->dbg, ref);
n->resolved_def_id = sym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
spl_scope_id_t old_scope = sema->scope->current_scope;
spl_scope_id_t inner_scope = spl_scope_alloc(sema->scope);
sema->scope->current_scope = inner_scope;
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
sema_collect(sema, vec_at(te->type_aggregate.members, i));
}
sema->scope->current_scope = old_scope;
} else {
sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, sym.name, te->dbg, ref);
n->resolved_def_id = sym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
}
break;
}
case SPL_AST_FN_DECL: {
spl_symbol_t sym = {.name = n->fn_decl.name, .kind = SPL_SYMBOL_KIND_FN};
sym.node = spl_def_alloc(sema->type, SPL_DEF_FN, sym.name, n->dbg, ref);
n->resolved_def_id = sym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
break;
}
case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL: {
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern);
if (pat && pat->kind == SPL_AST_PATTERN_IDENT) {
const char *name = pat->pattern_ident.name;
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR};
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, ref);
n->resolved_def_id = sym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
} else {
SPL_ERROR(&n->dbg, "unsupported variable pattern (only simple identifier)");
sema->error_count++;
}
break;
}
case SPL_AST_TOP_LEVEL_BLOCK:
if (n->top_level_block.block) {
sema_collect(sema, n->top_level_block.block);
}
break;
default:
break;
}
}
static spl_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (ref == 0)
return 0;
spl_ast_node_t *n = spl_ast_node(sema->ast, ref);
if (!n)
return 0;
switch (n->kind) {
case SPL_AST_CONTAINER_MEMBERS:
for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) {
sema_parse(sema, vec_at(n->container_members.declarations, i));
}
return 0;
case SPL_AST_FN_DECL: {
if (n->resolved_def_id == 0) {
Panic("fn `%s` not collected", n->fn_decl.name);
}
spl_type_id_vec_t param_types;
vec_init(param_types);
for (usize i = 0; i < vec_size(n->fn_decl.params); ++i) {
spl_ast_node_t *pd = spl_ast_node(sema->ast, vec_at(n->fn_decl.params, i));
if (pd && pd->kind == SPL_AST_PARAM_DECL && pd->param_decl.type_expr) {
vec_push(param_types, sema_parse(sema, pd->param_decl.type_expr));
} else {
vec_push(param_types, 0);
}
}
spl_type_id_t ret_tid = sema_parse(sema, n->fn_decl.ret_type);
spl_type_id_t fn_tid = spl_type_make_fn(
sema->type, ret_tid, vec_unsafe_get_data(param_types), vec_size(param_types));
vec_free(param_types);
spl_def_resolve(sema->type, n->resolved_def_id, fn_tid);
if (n->fn_decl.body) {
sema_push_scope(sema);
for (usize i = 0; i < vec_size(n->fn_decl.params); ++i) {
spl_ast_node_t *pd = spl_ast_node(sema->ast, vec_at(n->fn_decl.params, i));
if (pd && pd->kind == SPL_AST_PARAM_DECL) {
spl_symbol_t psym = {.name = pd->param_decl.name, .kind = SPL_SYMBOL_KIND_VAR};
psym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, psym.name, pd->dbg,
vec_at(n->fn_decl.params, i));
spl_type_id_t p_tid = sema_parse(sema, pd->param_decl.type_expr);
spl_def_resolve(sema->type, psym.node, p_tid);
pd->resolved_def_id = psym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, psym);
}
}
spl_type_id_t old_ret = sema->current_fn_ret_tid;
sema->current_fn_ret_tid = ret_tid;
sema_parse(sema, n->fn_decl.body);
sema->current_fn_ret_tid = old_ret;
sema_pop_scope(sema);
}
return fn_tid;
}
case SPL_AST_TYPE_DECL: {
if (!n->type_decl.type_expr)
break;
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
if (!te)
break;
if (te->kind == SPL_AST_TYPE_AGGREGATE) {
spl_type_member_vec_t members;
vec_init(members);
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i));
if (mn && mn->kind == SPL_AST_MEMBER_DECL) {
spl_type_id_t mtid = sema_parse(sema, mn->member_decl.type_expr);
spl_type_member_t m = {.name = mn->member_decl.name,
.type_id = mtid,
.ast_node_ref = vec_at(te->type_aggregate.members, i)};
vec_push(members, m);
}
}
spl_type_node_kind_t tk;
if (strcmp(te->type_aggregate.kind_name, "struct") == 0)
tk = SPL_TYPE_STRUCT;
else if (strcmp(te->type_aggregate.kind_name, "union") == 0)
tk = SPL_TYPE_UNION;
else if (strcmp(te->type_aggregate.kind_name, "enum") == 0)
tk = SPL_TYPE_ENUM;
else
tk = SPL_TYPE_STRUCT;
spl_type_layout_t layout = {.mode = SPL_TYPE_LAYOUT_AUTO};
spl_type_id_t agg_tid = spl_type_make_agg(
sema->type, tk, &members,
spl_type_make_int(sema->type, 32, 1), // 默认索引类型 i32 TODO check i32
layout);
vec_free(members);
spl_def_resolve(sema->type, n->resolved_def_id, agg_tid);
// 处理聚合内部的函数声明
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i));
if (mn && mn->kind == SPL_AST_FN_DECL) {
sema_parse(sema, vec_at(te->type_aggregate.members, i));
}
}
} else {
// 标量类型别名,仍然使用 def_resolve 关联已有类型
spl_type_id_t tid = sema_parse(sema, n->type_decl.type_expr);
spl_def_resolve(sema->type, n->resolved_def_id, tid);
}
break;
}
case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL: {
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern);
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT) {
SPL_ERROR(&n->dbg, "unsupported variable pattern");
sema->error_count++;
return 0;
}
const char *name = pat->pattern_ident.name;
if (n->resolved_def_id == 0) {
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR};
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, ref);
n->resolved_def_id = sym.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
}
spl_type_id_t decl_tid;
if (n->var_const_decl.type) {
decl_tid = sema_parse(sema, n->var_const_decl.type);
} else {
decl_tid = spl_type_make_infer(sema->type);
}
if (n->var_const_decl.init_expr == 0) {
SPL_ERROR(&n->dbg, "variable `%s` must be initialized", name);
sema->error_count++;
return 0;
}
spl_type_id_t init_tid = sema_parse(sema, n->var_const_decl.init_expr);
decl_tid = sema_coerce(sema, decl_tid, init_tid);
if (decl_tid == 0) {
SPL_ERROR(&n->dbg, "cannot infer type for variable `%s`", name);
sema->error_count++;
return 0;
}
spl_def_resolve(sema->type, n->resolved_def_id, decl_tid);
return decl_tid;
}
case SPL_AST_MEMBER_DECL: {
if (n->member_decl.type_expr) {
return sema_parse(sema, n->member_decl.type_expr);
}
return 0;
}
case SPL_AST_PARAM_DECL: {
if (n->param_decl.type_expr) {
return sema_parse(sema, n->param_decl.type_expr);
}
return 0;
}
case SPL_AST_EXPR_INT_LIT: {
spl_type_id_t ct = spl_type_make_int(sema->type, 0, true);
n->resolved_type_id = ct;
return ct;
}
case SPL_AST_EXPR_FLOAT_LIT: {
spl_type_id_t ct = spl_type_make_float(sema->type, 0);
n->resolved_type_id = ct;
return ct;
}
case SPL_AST_EXPR_CHAR_LIT: {
spl_type_id_t u8 = spl_type_make_int(sema->type, 8, false);
n->resolved_type_id = u8;
return u8;
}
case SPL_AST_EXPR_STRING_LIT: {
spl_type_id_t u8_tid = spl_type_make_int(sema->type, 8, false);
spl_type_id_t slice_tid = spl_type_make_slice(sema->type, u8_tid);
n->resolved_type_id = slice_tid;
return slice_tid;
}
case SPL_AST_EXPR_BOOL_LIT: {
spl_type_id_t bt = spl_type_make_bool(sema->type);
n->resolved_type_id = bt;
return bt;
}
case SPL_AST_EXPR_NULL_LIT: {
spl_type_id_t t = spl_type_make_ptr(sema->type, spl_type_make_never(sema->type));
n->resolved_type_id = t;
return t;
}
case SPL_AST_EXPR_UNDEFINED_LIT: {
spl_type_id_t t = spl_type_make_never(sema->type);
n->resolved_type_id = t;
return t;
}
case SPL_AST_EXPR_IDENT: {
const char *name = n->ident.name;
spl_symbol_t sym;
if (!spl_scope_find(sema->scope, name, &sym)) {
SPL_ERROR(&n->dbg, "undefined identifier `%s`", name);
sema->error_count++;
return 0;
}
if (sym.node == 0) {
SPL_ERROR(&n->dbg, "identifier `%s` has no definition", name);
sema->error_count++;
return 0;
}
n->resolved_def_id = sym.node;
spl_def_node_t *def = spl_def_node(sema->type, sym.node);
if (!def) {
SPL_ERROR(&n->dbg, "definition for `%s` not found", name);
sema->error_count++;
return 0;
}
return def->type_id;
}
case SPL_AST_EXPR_UNARY: {
spl_type_id_t operand_tid = sema_parse(sema, n->unary.operand);
if (operand_tid == 0)
return 0;
spl_type_node_t *tn = spl_type_node(sema->type, operand_tid);
if (!tn)
return 0;
switch (n->unary.op) {
case SPL_UNARY_OP_MINUS:
if (tn->kind != SPL_TYPE_INT && tn->kind != SPL_TYPE_FLOAT) {
SPL_ERROR(&n->dbg, "unary minus requires numeric operand");
sema->error_count++;
return 0;
}
n->resolved_type_id = operand_tid;
return operand_tid;
case SPL_UNARY_OP_NOT:
if (tn->kind != SPL_TYPE_BOOL) {
SPL_ERROR(&n->dbg, "logical not requires bool operand");
sema->error_count++;
return 0;
}
{
spl_type_id_t bt = spl_type_make_bool(sema->type);
n->resolved_type_id = bt;
return bt;
}
case SPL_UNARY_OP_BIT_NOT:
if (tn->kind != SPL_TYPE_INT) {
SPL_ERROR(&n->dbg, "bitwise not requires integer operand");
sema->error_count++;
return 0;
}
n->resolved_type_id = operand_tid;
return operand_tid;
case SPL_UNARY_OP_ADDRESS: {
spl_type_id_t ptr_tid = spl_type_make_ptr(sema->type, operand_tid);
n->resolved_type_id = ptr_tid;
return ptr_tid;
}
default:
UNREACHABLE();
}
break;
}
case SPL_AST_EXPR_BINARY: {
spl_type_id_t lt = sema_parse(sema, n->binary.left);
spl_type_id_t rt = sema_parse(sema, n->binary.right);
spl_binary_op_t op = n->binary.op;
switch (op) {
case SPL_OP_ASSIGN:
if (sema_coerce(sema, lt, rt) == 0) {
SPL_ERROR(&n->dbg, "assignment type mismatch");
sema->error_count++;
return 0;
}
n->resolved_type_id = lt;
return lt;
case SPL_OP_ASSIGN_ADD:
case SPL_OP_ASSIGN_SUB:
case SPL_OP_ASSIGN_MUL:
case SPL_OP_ASSIGN_DIV:
case SPL_OP_ASSIGN_MOD:
case SPL_OP_ASSIGN_AND:
case SPL_OP_ASSIGN_OR:
case SPL_OP_ASSIGN_XOR:
case SPL_OP_ASSIGN_LSHIFT:
case SPL_OP_ASSIGN_RSHIFT: {
spl_type_id_t balanced = sema_coerce_balance(sema, lt, rt);
if (balanced == 0 || balanced != lt) {
SPL_ERROR(&n->dbg, "compound assignment type mismatch");
sema->error_count++;
return 0;
}
n->resolved_type_id = lt;
return lt;
}
case SPL_OP_BOOL_OR:
case SPL_OP_BOOL_AND: {
spl_type_node_t *ln = spl_type_node(sema->type, lt);
spl_type_node_t *rn = spl_type_node(sema->type, rt);
if (!ln || ln->kind != SPL_TYPE_BOOL || !rn || rn->kind != SPL_TYPE_BOOL) {
SPL_ERROR(&n->dbg, "logical operands must be bool");
sema->error_count++;
return 0;
}
spl_type_id_t bt = spl_type_make_bool(sema->type);
n->resolved_type_id = bt;
return bt;
}
case SPL_OP_BIT_OR:
case SPL_OP_BIT_XOR:
case SPL_OP_BIT_AND: {
spl_type_id_t bal = sema_coerce_balance(sema, lt, rt);
spl_type_node_t *bn = spl_type_node(sema->type, bal);
if (!bn || bn->kind != SPL_TYPE_INT) {
SPL_ERROR(&n->dbg, "bitwise operands must be integers");
sema->error_count++;
return 0;
}
n->resolved_type_id = bal;
return bal;
}
case SPL_OP_CMP_EQ:
case SPL_OP_CMP_NE:
case SPL_OP_CMP_LE:
case SPL_OP_CMP_GE:
case SPL_OP_CMP_LT:
case SPL_OP_CMP_GT: {
if (sema_coerce_balance(sema, lt, rt) == 0) {
SPL_ERROR(&n->dbg, "comparison operands type mismatch");
sema->error_count++;
return 0;
}
spl_type_id_t bt = spl_type_make_bool(sema->type);
n->resolved_type_id = bt;
return bt;
}
case SPL_OP_LSHIFT:
case SPL_OP_RSHIFT: {
spl_type_node_t *ln = spl_type_node(sema->type, lt);
spl_type_node_t *rn = spl_type_node(sema->type, rt);
if (!ln || ln->kind != SPL_TYPE_INT || !rn || rn->kind != SPL_TYPE_INT) {
SPL_ERROR(&n->dbg, "shift operands must be integers");
sema->error_count++;
return 0;
}
n->resolved_type_id = lt;
return lt;
}
case SPL_OP_ADD:
case SPL_OP_SUB:
case SPL_OP_MUL:
case SPL_OP_DIV:
case SPL_OP_MOD: {
spl_type_id_t bal = sema_coerce_balance(sema, lt, rt);
spl_type_node_t *bn = spl_type_node(sema->type, bal);
if (!bn || (bn->kind != SPL_TYPE_INT && bn->kind != SPL_TYPE_FLOAT)) {
SPL_ERROR(&n->dbg, "arithmetic operands type mismatch");
sema->error_count++;
return 0;
}
n->resolved_type_id = bal;
return bal;
}
case SPL_OP_RANGE: {
spl_type_id_t i64 = spl_type_make_int(sema->type, 64, true);
n->resolved_type_id = i64;
return i64;
}
default:
break;
}
break;
}
case SPL_AST_EXPR_CALL: {
spl_type_id_t callee_tid = sema_parse(sema, n->call.callee);
spl_type_node_t *fn = spl_type_node(sema->type, callee_tid);
if (!fn || fn->kind != SPL_TYPE_FN) {
SPL_ERROR(&n->dbg, "callee is not a function");
sema->error_count++;
return 0;
}
if (vec_size(n->call.args) != vec_size(fn->fn_type.params)) {
SPL_ERROR(&n->dbg, "argument count mismatch");
sema->error_count++;
} else {
for (usize i = 0; i < vec_size(n->call.args); ++i) {
spl_type_id_t arg_tid = sema_parse(sema, vec_at(n->call.args, i));
spl_type_id_t param_tid = vec_at(fn->fn_type.params, i);
if (sema_coerce(sema, param_tid, arg_tid) == 0) {
SPL_ERROR(&n->dbg, "argument %zu type mismatch", i + 1);
sema->error_count++;
}
}
}
spl_type_id_t ret_tid = fn->fn_type.ret;
n->resolved_type_id = ret_tid;
return ret_tid;
}
case SPL_AST_EXPR_FIELD: {
spl_type_id_t obj_tid = sema_parse(sema, n->field.obj);
spl_type_node_t *obj_node = spl_type_node(sema->type, obj_tid);
if (!obj_node)
return 0;
spl_type_id_t agg_tid = obj_tid;
if (obj_node->kind == SPL_TYPE_PTR) {
agg_tid = obj_node->ptr_type.pointee;
}
spl_type_node_t *agg_node = spl_type_node(sema->type, agg_tid);
if (!agg_node || (agg_node->kind != SPL_TYPE_STRUCT && agg_node->kind != SPL_TYPE_UNION)) {
SPL_ERROR(&n->dbg, "field access on non-aggregate type");
sema->error_count++;
return 0;
}
const spl_type_member_t *member = spl_type_agg_member(sema->type, agg_tid, n->field.field);
if (!member) {
SPL_ERROR(&n->dbg, "no field `%s`", n->field.field);
sema->error_count++;
return 0;
}
n->resolved_type_id = member->type_id;
return member->type_id;
}
case SPL_AST_EXPR_INDEX: {
spl_type_id_t obj_tid = sema_parse(sema, n->index.obj);
spl_type_id_t idx_tid = sema_parse(sema, n->index.index);
spl_type_node_t *obj_node = spl_type_node(sema->type, obj_tid);
if (!obj_node)
return 0;
spl_type_id_t elem_tid = 0;
switch (obj_node->lang_kind) {
case SPL_LANG_TYPE_SLICE: {
const spl_type_member_t *ptr_member = spl_type_agg_member(sema->type, obj_tid, "ptr");
if (!ptr_member) {
SPL_ERROR(&n->dbg, "slice missing ptr member");
sema->error_count++;
return 0;
}
spl_type_node_t *ptr_node = spl_type_node(sema->type, ptr_member->type_id);
if (!ptr_node || ptr_node->kind != SPL_TYPE_PTR) {
SPL_ERROR(&n->dbg, "slice ptr member not pointer");
sema->error_count++;
return 0;
}
elem_tid = ptr_node->ptr_type.pointee;
break;
}
case SPL_LANG_TYPE_TUPLE: {
// 对于元组索引,需要常量索引,暂简化为返回第一个成员类型
if (vec_size(obj_node->agg_type.variants) > 0)
elem_tid = vec_at(obj_node->agg_type.variants, 0).type_id;
else {
SPL_ERROR(&n->dbg, "empty tuple");
sema->error_count++;
return 0;
}
break;
}
default:
switch (obj_node->kind) {
case SPL_TYPE_ARRAY:
elem_tid = obj_node->array_type.element;
break;
case SPL_TYPE_PTR:
elem_tid = obj_node->ptr_type.pointee;
break;
default:
SPL_ERROR(&n->dbg, "index base must be array, pointer, slice, or tuple");
sema->error_count++;
return 0;
}
break;
}
(void)idx_tid;
n->resolved_type_id = elem_tid;
return elem_tid;
}
case SPL_AST_EXPR_SLICE: {
spl_type_id_t obj_tid = sema_parse(sema, n->slice.obj);
if (n->slice.begin)
sema_parse(sema, n->slice.begin);
if (n->slice.end)
sema_parse(sema, n->slice.end);
spl_type_node_t *obj_node = spl_type_node(sema->type, obj_tid);
if (!obj_node)
return 0;
spl_type_id_t elem_tid = 0;
if (obj_node->kind == SPL_TYPE_ARRAY) {
elem_tid = obj_node->array_type.element;
} else if (obj_node->kind == SPL_TYPE_PTR) {
elem_tid = obj_node->ptr_type.pointee;
} else if (obj_node->lang_kind == SPL_LANG_TYPE_SLICE) {
// 对 slice 再切片,元素类型保持不变
const spl_type_member_t *ptr_member = spl_type_agg_member(sema->type, obj_tid, "ptr");
if (ptr_member) {
spl_type_node_t *ptr_node = spl_type_node(sema->type, ptr_member->type_id);
if (ptr_node && ptr_node->kind == SPL_TYPE_PTR)
elem_tid = ptr_node->ptr_type.pointee;
}
} else {
SPL_ERROR(&n->dbg, "slice base must be array, pointer, or slice");
sema->error_count++;
return 0;
}
spl_type_id_t slice_tid = spl_type_make_slice(sema->type, elem_tid);
n->resolved_type_id = slice_tid;
return slice_tid;
}
case SPL_AST_EXPR_CAST: {
spl_type_id_t src_tid = sema_parse(sema, n->cast.expr);
spl_type_id_t dst_tid = sema_parse(sema, n->cast.type);
spl_type_node_t *src_node = spl_type_node(sema->type, src_tid);
if (!src_node)
return 0;
if (src_node->kind != SPL_TYPE_INT && src_node->kind != SPL_TYPE_FLOAT &&
src_node->kind != SPL_TYPE_BOOL) {
SPL_ERROR(&n->dbg, "invalid cast from non-primitive type");
sema->error_count++;
return 0;
}
n->resolved_type_id = dst_tid;
return dst_tid;
}
case SPL_AST_EXPR_TUPLE: {
for (usize i = 0; i < vec_size(n->tuple.elems); ++i) {
sema_parse(sema, vec_at(n->tuple.elems, i));
}
return 0;
}
case SPL_AST_EXPR_ARRAY_LIT: {
spl_type_id_t elem_tid = 0;
if (n->array_literal.elem_type) {
elem_tid = sema_parse(sema, n->array_literal.elem_type);
}
for (usize i = 0; i < vec_size(n->array_literal.elems); ++i) {
spl_type_id_t et = sema_parse(sema, vec_at(n->array_literal.elems, i));
if (elem_tid == 0)
elem_tid = et;
else if (sema_coerce(sema, elem_tid, et) == 0) {
SPL_ERROR(&n->dbg, "array element type mismatch");
sema->error_count++;
}
}
usize len;
if (n->array_literal.is_underscore_len) {
len = vec_size(n->array_literal.elems);
} else {
len =
n->array_literal.has_len ? n->array_literal.len : vec_size(n->array_literal.elems);
}
spl_type_id_t arr_tid = spl_type_make_array(sema->type, elem_tid, len);
n->resolved_type_id = arr_tid;
return arr_tid;
}
case SPL_AST_EXPR_ANON_ARRAY_LIT: {
spl_type_id_t elem_tid = 0;
for (usize i = 0; i < vec_size(n->anon_array_literal.elems); ++i) {
spl_type_id_t et = sema_parse(sema, vec_at(n->anon_array_literal.elems, i));
if (elem_tid == 0)
elem_tid = et;
else if (sema_coerce(sema, elem_tid, et) == 0) {
SPL_ERROR(&n->dbg, "array element type mismatch");
sema->error_count++;
}
}
usize len = vec_size(n->anon_array_literal.elems);
spl_type_id_t arr_tid = spl_type_make_array(sema->type, elem_tid, len);
n->resolved_type_id = arr_tid;
return arr_tid;
}
case SPL_AST_EXPR_AGGREGATE_LIT: {
const char *type_name = n->aggregate_literal.name;
if (!type_name) {
SPL_ERROR(&n->dbg, "anonymous aggregate literal not supported yet");
sema->error_count++;
return 0;
}
spl_symbol_t sym;
if (!spl_scope_find(sema->scope, type_name, &sym)) {
SPL_ERROR(&n->dbg, "unknown type `%s`", type_name);
sema->error_count++;
return 0;
}
spl_def_node_t *def = spl_def_node(sema->type, sym.node);
spl_type_id_t tid = def ? def->type_id : 0;
spl_type_node_t *tn = spl_type_node(sema->type, tid);
if (!tn || (tn->kind != SPL_TYPE_STRUCT && tn->kind != SPL_TYPE_UNION)) {
SPL_ERROR(&n->dbg, "`%s` is not a struct/union", type_name);
sema->error_count++;
return 0;
}
for (usize i = 0; i < vec_size(n->aggregate_literal.fields); ++i) {
spl_ast_node_t *item = spl_ast_node(sema->ast, vec_at(n->aggregate_literal.fields, i));
if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM)
continue;
const char *fname = item->struct_init_item.name;
spl_type_id_t field_tid = 0;
if (item->struct_init_item.expr) {
field_tid = sema_parse(sema, item->struct_init_item.expr);
}
const spl_type_member_t *member = spl_type_agg_member(sema->type, tid, fname);
if (!member) {
SPL_ERROR(&item->dbg, "no field `%s` in `%s`", fname, type_name);
sema->error_count++;
continue;
}
if (sema_coerce(sema, member->type_id, field_tid) == 0) {
SPL_ERROR(&item->dbg, "field `%s` type mismatch", fname);
sema->error_count++;
}
}
n->resolved_type_id = tid;
return tid;
}
case SPL_AST_EXPR_COMPTIME_CALL:
return 0;
case SPL_AST_EXPR_BLOCK: {
for (usize i = 0; i < vec_size(n->block.stmts); ++i) {
sema_parse(sema, vec_at(n->block.stmts, i));
}
if (n->block.tail_expr) {
return sema_parse(sema, n->block.tail_expr);
}
return 0;
}
case SPL_AST_EXPR_IF: {
spl_type_id_t cond_tid = sema_parse(sema, n->if_expr.cond);
if (!sema_coerce_for_bool(sema, cond_tid)) {
SPL_ERROR(&n->dbg, "if condition must be bool");
sema->error_count++;
}
sema_parse(sema, n->if_expr.then_block);
if (n->if_expr.else_branch) {
sema_parse(sema, n->if_expr.else_branch);
}
return 0;
}
case SPL_AST_EXPR_IFVAR: {
sema_parse(sema, n->ifvar_expr.var_decl);
sema_parse(sema, n->ifvar_expr.then_block);
if (n->ifvar_expr.else_branch) {
sema_parse(sema, n->ifvar_expr.else_branch);
}
return 0;
}
case SPL_AST_EXPR_WHILE: {
spl_type_id_t cond_tid = sema_parse(sema, n->while_expr.cond);
if (!sema_coerce_for_bool(sema, cond_tid)) {
SPL_ERROR(&n->dbg, "while condition must be bool");
sema->error_count++;
}
sema_parse(sema, n->while_expr.body);
if (n->while_expr.else_branch) {
sema_parse(sema, n->while_expr.else_branch);
}
return 0;
}
case SPL_AST_EXPR_LOOP: {
sema_parse(sema, n->loop_expr.body);
return 0;
}
case SPL_AST_EXPR_FOR: {
sema_push_scope(sema);
for (usize i = 0; i < vec_size(n->for_expr.iter_exprs); ++i) {
spl_type_id_t container_tid = sema_parse(sema, vec_at(n->for_expr.iter_exprs, i));
spl_type_id_t elem_tid = sema_for_elem_type(sema, container_tid);
if (i < vec_size(n->for_expr.idents)) {
spl_ast_node_t *id_node = spl_ast_node(sema->ast, vec_at(n->for_expr.idents, i));
if (id_node && id_node->kind == SPL_AST_EXPR_IDENT) {
const char *var_name = id_node->ident.name;
if (strcmp(var_name, "_") != 0) {
spl_symbol_t sym = {.name = var_name, .kind = SPL_SYMBOL_KIND_VAR};
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, var_name, id_node->dbg,
vec_at(n->for_expr.idents, i));
spl_def_resolve(sema->type, sym.node, elem_tid);
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
id_node->resolved_def_id = sym.node;
}
}
}
}
sema_parse(sema, n->for_expr.body);
if (n->for_expr.else_branch) {
sema_parse(sema, n->for_expr.else_branch);
}
sema_pop_scope(sema);
return 0;
}
case SPL_AST_EXPR_MATCH: {
sema_parse(sema, n->match_expr.matched_expr);
for (usize i = 0; i < vec_size(n->match_expr.arms); ++i) {
spl_ast_node_t *arm = spl_ast_node(sema->ast, vec_at(n->match_expr.arms, i));
if (arm && arm->kind == SPL_AST_MATCH_ARM) {
sema_parse(sema, arm->match_arm.pattern);
sema_parse(sema, arm->match_arm.body);
}
}
return 0;
}
case SPL_AST_EXPR_FN_TYPE: {
spl_type_id_vec_t params;
vec_init(params);
for (usize i = 0; i < vec_size(n->fn_type.params); ++i) {
vec_push(params, sema_parse(sema, vec_at(n->fn_type.params, i)));
}
spl_type_id_t ret_tid = sema_parse(sema, n->fn_type.ret_type);
spl_type_id_t fn_tid =
spl_type_make_fn(sema->type, ret_tid, vec_unsafe_get_data(params), vec_size(params));
vec_free(params);
n->resolved_type_id = fn_tid;
return fn_tid;
}
case SPL_AST_TYPE_PATH: {
const char *name = n->type_path.name;
// 先询问 type 模块是否为内建类型
spl_type_id_t builtin = spl_type_lookup_builtin(sema->type, name);
if (builtin != 0) {
n->resolved_type_id = builtin;
return builtin;
}
// 否则查找用户定义类型
spl_symbol_t sym;
if (!spl_scope_find(sema->scope, name, &sym)) {
SPL_ERROR(&n->dbg, "type `%s` not found", name);
sema->error_count++;
return 0;
}
spl_def_node_t *def = spl_def_node(sema->type, sym.node);
if (!def)
return 0;
n->resolved_type_id = def->type_id;
return def->type_id;
}
case SPL_AST_TYPE_POINTER: {
spl_type_id_t pointee_tid = sema_parse(sema, n->type_pointer.pointee);
spl_type_id_t ptr_tid = spl_type_make_ptr(sema->type, pointee_tid);
n->resolved_type_id = ptr_tid;
return ptr_tid;
}
case SPL_AST_TYPE_ARRAY: {
spl_type_id_t elem_tid = sema_parse(sema, n->type_array.elem_type);
usize len = n->type_array.has_len ? (usize)n->type_array.len : 0;
spl_type_id_t arr_tid = spl_type_make_array(sema->type, elem_tid, len);
n->resolved_type_id = arr_tid;
return arr_tid;
}
case SPL_AST_TYPE_SLICE: {
spl_type_id_t elem_tid = sema_parse(sema, n->type_slice.elem_type);
spl_type_id_t slice_tid = spl_type_make_slice(sema->type, elem_tid);
n->resolved_type_id = slice_tid;
return slice_tid;
}
case SPL_AST_TYPE_FN: {
spl_type_id_vec_t params;
vec_init(params);
for (usize i = 0; i < vec_size(n->type_fn.params); ++i) {
vec_push(params, sema_parse(sema, vec_at(n->type_fn.params, i)));
}
spl_type_id_t ret_tid = sema_parse(sema, n->type_fn.ret_type);
spl_type_id_t fn_tid =
spl_type_make_fn(sema->type, ret_tid, vec_unsafe_get_data(params), vec_size(params));
vec_free(params);
n->resolved_type_id = fn_tid;
return fn_tid;
}
case SPL_AST_TYPE_PAREN: {
usize count = vec_size(n->type_paren.types);
if (count == 0) {
spl_type_id_t unit = spl_type_make_unit(sema->type);
n->resolved_type_id = unit;
return unit;
}
if (count == 1) {
return sema_parse(sema, vec_at(n->type_paren.types, 0));
}
spl_type_member_vec_t members;
vec_init(members);
char name_buf[32]; // TODO string builder
for (usize i = 0; i < count; ++i) {
spl_type_id_t tid = sema_parse(sema, vec_at(n->type_paren.types, i));
snprintf(name_buf, sizeof(name_buf), "%zu", i);
spl_type_member_t m = {.name = strdup(name_buf), .type_id = tid, .ast_node_ref = 0};
vec_push(members, m);
}
spl_type_id_t tuple_tid = spl_type_make_tuple(sema->type, &members);
vec_free(members);
n->resolved_type_id = tuple_tid;
return tuple_tid;
}
case SPL_AST_TYPE_AGGREGATE: {
return 0;
}
case SPL_AST_TYPE_COMPTIME_CALL:
return 0;
case SPL_AST_STATEMENT_RET: {
if (n->statement_ret.expr) {
spl_type_id_t ret_tid = sema_parse(sema, n->statement_ret.expr);
if (sema->current_fn_ret_tid != 0 &&
sema_coerce(sema, sema->current_fn_ret_tid, ret_tid) == 0) {
SPL_ERROR(&n->dbg, "return type mismatch");
sema->error_count++;
}
}
return 0;
}
case SPL_AST_STATEMENT_BREAK:
case SPL_AST_STATEMENT_CONTINUE:
return 0;
case SPL_AST_STATEMENT_DEFER:
if (n->statement_defer.body) {
sema_parse(sema, n->statement_defer.body);
}
return 0;
case SPL_AST_STATEMENT_COMPTIME:
if (n->statement_comptime.body) {
sema_parse(sema, n->statement_comptime.body);
}
return 0;
case SPL_AST_STATEMENT_DECL:
if (n->statement_decl.decl) {
sema_parse(sema, n->statement_decl.decl);
}
return 0;
case SPL_AST_STATEMENT_EXPR:
if (n->statement_expr.expr) {
sema_parse(sema, n->statement_expr.expr);
}
return 0;
default:
return 0;
}
return 0;
}
void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope) {
Assert(sema && ast && type && scope);
sema->ast = ast;
sema->type = type;
sema->scope = scope;
sema->error_count = 0;
sema->current_fn_ret_tid = 0;
sema->root = (spl_symbol_t){0};
sema->store_scope = 0;
}
void spl_sema_drop(spl_sema_t *sema) { (void)sema; }
void spl_sema_run(spl_sema_t *sema) {
if (!sema->ast || !sema->ast->root)
return;
spl_ast_node_t *root = spl_ast_node(sema->ast, sema->ast->root);
Assert(root && root->kind == SPL_AST_ROOT);
spl_ast_node_t *container = spl_ast_node(sema->ast, root->root.members);
Assert(container && container->kind == SPL_AST_CONTAINER_MEMBERS);
sema_collect(sema, root->root.members);
sema_parse(sema, root->root.members);
}
void spl_sema_dump(spl_sema_t *sema) {
printf("Scopes:\n");
for (usize i = 0; i < vec_size(sema->scope->scopes); ++i) {
if (i == 0)
continue;
spl_scope_node_t *scope = &vec_at(sema->scope->scopes, i);
printf("scope[%zu] parent=%zu\n", i, scope->parent);
map_for(scope->symbols, j) {
spl_symbol_t *symbol = &unsafe_map_at(scope->symbols, j).val;
printf(" %s -> def`%s`#%zu\n", unsafe_map_at(scope->symbols, j).key, symbol->name,
symbol->node);
}
}
printf("TypeTable:\n");
for (usize i = 0; i < vec_size(sema->type->type_table); ++i) {
printf(" id#%zu ", i);
spl_type_pure_dump(sema->type, i);
printf("\n");
}
printf("DefTable:\n");
for (usize i = 0; i < vec_size(sema->type->def_table); ++i) {
printf(" def#%zu ", i);
spl_type_def_dump(sema->type, i);
printf("\n");
}
}