2610 lines
98 KiB
C
2610 lines
98 KiB
C
#include "spl_sema.h"
|
|
#include "spl_intrin.h"
|
|
#include "spl_type.h"
|
|
|
|
void spl_scope_init(spl_scope_t *scope) {
|
|
vec_init(scope->scopes);
|
|
vec_push(scope->scopes, (spl_scope_node_t){0});
|
|
scope->current_scope = 0;
|
|
scope->root_scope = 0;
|
|
}
|
|
|
|
void spl_scope_drop(spl_scope_t *scope) {
|
|
for (usize i = 0; i < vec_size(scope->scopes); ++i) {
|
|
map_free(vec_at(scope->scopes, i).symbols);
|
|
}
|
|
vec_free(scope->scopes);
|
|
scope->current_scope = 0;
|
|
scope->root_scope = 0;
|
|
}
|
|
|
|
spl_scope_id_t spl_scope_alloc(spl_scope_t *scope) {
|
|
spl_scope_node_t n = {0};
|
|
n.parent = scope->current_scope;
|
|
map_init(n.symbols, MAP_HASH_STR, MAP_CMP_STR);
|
|
vec_push(scope->scopes, n);
|
|
return vec_size(scope->scopes) - 1;
|
|
}
|
|
|
|
bool spl_scope_insert(spl_scope_t *scope, spl_scope_id_t id, spl_symbol_t symbol) {
|
|
if (!id || id >= vec_size(scope->scopes)) {
|
|
LOG_FATAL("sema scope insert error");
|
|
return false;
|
|
}
|
|
spl_scope_node_t *node = &vec_at(scope->scopes, id);
|
|
spl_symbol_t old = {0};
|
|
if (map_get(node->symbols, symbol.name, &old)) {
|
|
SPL_ERROR(&(spl_dbg_node_t){0}, "duplicate symbol `%s`", symbol.name);
|
|
return false;
|
|
}
|
|
map_put(node->symbols, symbol.name, symbol);
|
|
return true;
|
|
}
|
|
|
|
bool spl_scope_find(spl_scope_t *scope, const char *name, spl_symbol_t *out) {
|
|
if (!scope || !name || !out)
|
|
return false;
|
|
for (spl_scope_id_t id = scope->current_scope; id != 0; id = vec_at(scope->scopes, id).parent) {
|
|
spl_scope_node_t *s = &vec_at(scope->scopes, id);
|
|
if (map_get(s->symbols, name, out)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref);
|
|
static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref);
|
|
static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref,
|
|
spl_lang_type_id_t expected);
|
|
static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in,
|
|
spl_ast_node_ref_vec_t *args);
|
|
static spl_lang_type_id_t sema_intrin_field(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in);
|
|
|
|
static bool sema_is_infer(spl_sema_t *sema, spl_lang_type_id_t tid) {
|
|
spl_lang_type_node_t *n = spl_lang_type_node(sema->type, tid);
|
|
return n && n->kind == SPL_LANG_TYPE_INFER;
|
|
}
|
|
|
|
static spl_lang_type_id_t sema_lang_from_ir(spl_sema_t *sema, spl_type_id_t ir) {
|
|
for (usize i = 1; i < vec_size(sema->type->lang_table); ++i) {
|
|
spl_lang_type_node_t *ln = &vec_at(sema->type->lang_table, i);
|
|
if (ln->ir_type_id == ir)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static bool sema_is_literal(spl_ast_node_t *n) {
|
|
switch (n->kind) {
|
|
case SPL_AST_EXPR_INT_LIT:
|
|
case SPL_AST_EXPR_FLOAT_LIT:
|
|
case SPL_AST_EXPR_CHAR_LIT:
|
|
case SPL_AST_EXPR_STRING_LIT:
|
|
case SPL_AST_EXPR_BOOL_LIT:
|
|
case SPL_AST_EXPR_NULL_LIT:
|
|
case SPL_AST_EXPR_UNDEFINED_LIT:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool sema_is_numeric(spl_sema_t *sema, spl_lang_type_id_t tid) {
|
|
spl_lang_type_node_t *n = spl_lang_type_node(sema->type, tid);
|
|
return n && (n->kind == SPL_LANG_TYPE_INT || n->kind == SPL_LANG_TYPE_FLOAT);
|
|
}
|
|
|
|
static inline void sema_push_scope(spl_sema_t *sema) {
|
|
spl_scope_id_t new_scope = spl_scope_alloc(sema->scope);
|
|
sema->store_scope = sema->scope->current_scope;
|
|
sema->scope->current_scope = new_scope;
|
|
}
|
|
|
|
static inline void sema_pop_scope(spl_sema_t *sema) {
|
|
sema->scope->current_scope = sema->store_scope;
|
|
}
|
|
|
|
static spl_lang_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_lang_type_id_t lang_tid) {
|
|
spl_lang_type_node_t *n = spl_lang_type_node(sema->type, lang_tid);
|
|
if (!n)
|
|
return 0;
|
|
switch (n->kind) {
|
|
case SPL_LANG_TYPE_ARRAY:
|
|
case SPL_LANG_TYPE_SLICE:
|
|
case SPL_LANG_TYPE_RANGE:
|
|
case SPL_LANG_TYPE_PTR:
|
|
return n->extra.elem;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
|
spl_ast_node_t *n = spl_ast_node(sema->ast, ref);
|
|
if (!n)
|
|
return;
|
|
|
|
switch (n->kind) {
|
|
case SPL_AST_CONTAINER_MEMBERS: {
|
|
/* root_scope 只在第一次创建,后续 module 复用 */
|
|
if (sema->scope->root_scope == 0) {
|
|
spl_scope_id_t root = spl_scope_alloc(sema->scope);
|
|
sema->scope->root_scope = root;
|
|
}
|
|
|
|
/* 进入 root_scope,再为当前 module 开一个子 scope */
|
|
sema->scope->current_scope = sema->scope->root_scope;
|
|
spl_scope_id_t mod_scope = spl_scope_alloc(sema->scope);
|
|
sema->scope->current_scope = mod_scope;
|
|
|
|
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_insert(sema->scope, mod_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));
|
|
}
|
|
|
|
/* 故意不恢复 current_scope
|
|
保持 mod_scope 交给随后的 sema_parse 使用。
|
|
恢复由 spl_sema_run_module 统一负责 */
|
|
break;
|
|
}
|
|
case SPL_AST_TYPE_DECL: {
|
|
spl_symbol_t sym = {.name = n->type_decl.name, .kind = SPL_SYMBOL_KIND_TYPE};
|
|
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
|
|
if (!te) {
|
|
SPL_ERROR(&n->dbg, "type declaration `%s` missing type expression", n->type_decl.name);
|
|
sema->error_count++;
|
|
return;
|
|
}
|
|
|
|
if (te->kind == SPL_AST_TYPE_AGGREGATE) {
|
|
sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, sym.name, te->dbg, ref);
|
|
n->resolved_def_id = sym.node;
|
|
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
|
|
|
|
spl_scope_id_t old_scope = sema->scope->current_scope;
|
|
spl_scope_id_t inner_scope = spl_scope_alloc(sema->scope);
|
|
sema->scope->current_scope = inner_scope;
|
|
|
|
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
|
|
sema_collect(sema, vec_at(te->type_aggregate.members, i));
|
|
}
|
|
sema->scope->current_scope = old_scope;
|
|
} else {
|
|
sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, sym.name, te->dbg, ref);
|
|
n->resolved_def_id = sym.node;
|
|
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
|
|
}
|
|
break;
|
|
}
|
|
case SPL_AST_FN_DECL: {
|
|
spl_symbol_t sym = {.name = n->fn_decl.name, .kind = SPL_SYMBOL_KIND_FN};
|
|
sym.node = spl_def_alloc(sema->type, SPL_DEF_FN, sym.name, n->dbg, ref);
|
|
n->resolved_def_id = sym.node;
|
|
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
|
|
break;
|
|
}
|
|
case SPL_AST_VAR_DECL:
|
|
case SPL_AST_CONST_DECL: {
|
|
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern);
|
|
if (pat && pat->kind == SPL_AST_PATTERN_IDENT) {
|
|
const char *name = pat->pattern_ident.name;
|
|
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR};
|
|
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, ref);
|
|
n->resolved_def_id = sym.node;
|
|
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
|
|
} else {
|
|
SPL_ERROR(&n->dbg, "unsupported variable pattern (only simple identifier)");
|
|
sema->error_count++;
|
|
}
|
|
break;
|
|
}
|
|
case SPL_AST_TOP_LEVEL_BLOCK:
|
|
if (n->top_level_block.block) {
|
|
sema_collect(sema, n->top_level_block.block);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref);
|
|
|
|
static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in,
|
|
spl_ast_node_ref_vec_t *args) {
|
|
const spl_intrin_info_t *info = spl_intrin_info(in);
|
|
usize nargs = vec_size(*args);
|
|
if ((int)nargs < info->min_args || (info->max_args >= 0 && (int)nargs > info->max_args)) {
|
|
SPL_ERROR(&n->dbg, "`%s` expects %d..%d args, got %zu", info->name, info->min_args,
|
|
info->max_args, nargs);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
switch (in) {
|
|
case SPL_INTRIN_SIZEOF:
|
|
case SPL_INTRIN_ALIGNOF: {
|
|
sema_infer(sema, vec_at(*args, 0)); /* 求类型表达式的值 */
|
|
return spl_lang_make_int(sema->type, sizeof(void *) * 8, 0);
|
|
}
|
|
case SPL_INTRIN_ASSERT: {
|
|
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
|
|
sema_check(sema, vec_at(*args, 0), bt);
|
|
if (nargs == 2)
|
|
sema_infer(sema, vec_at(*args, 1));
|
|
return spl_lang_make_unit(sema->type);
|
|
}
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static spl_lang_type_id_t sema_intrin_field(spl_sema_t *sema, spl_ast_node_t *n, spl_intrin_t in) {
|
|
const spl_intrin_info_t *info = spl_intrin_info(in);
|
|
switch (info->result) {
|
|
case SPL_INTRIN_RESULT_USIZE:
|
|
return spl_lang_make_int(sema->type, sizeof(void *) * 8, 0);
|
|
case SPL_INTRIN_RESULT_BOOL:
|
|
return spl_lang_make_bool(sema->type);
|
|
case SPL_INTRIN_RESULT_UNIT:
|
|
return spl_lang_make_unit(sema->type);
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
(void)n;
|
|
return 0;
|
|
}
|
|
|
|
static spl_lang_type_id_t sema_check(spl_sema_t *sema, spl_ast_node_ref_t ref,
|
|
spl_lang_type_id_t expected) {
|
|
if (!ref || !expected)
|
|
return 0;
|
|
spl_ast_node_t *n = spl_ast_node(sema->ast, ref);
|
|
if (!n)
|
|
return 0;
|
|
|
|
/* ============ 类 1:构造性节点 —— 就地定型为 expected ============ */
|
|
switch (n->kind) {
|
|
|
|
case SPL_AST_EXPR_UNARY: {
|
|
if (n->unary.op == SPL_UNARY_OP_ADDRESS)
|
|
return sema_infer(sema, ref); /* &x 没有"被 check 到某类型"的语义 */
|
|
if (!sema_check(sema, n->unary.operand, expected))
|
|
return 0;
|
|
n->resolved_lang_tid = expected;
|
|
n->expected_lang_tid = 0;
|
|
return expected;
|
|
}
|
|
|
|
case SPL_AST_EXPR_BINARY: {
|
|
spl_binary_op_t op = n->binary.op;
|
|
|
|
/* 赋值 / 复合赋值:右侧 check 到左侧类型 */
|
|
if (op == SPL_OP_ASSIGN || (op >= SPL_OP_ASSIGN_ADD && op <= SPL_OP_ASSIGN_RSHIFT)) {
|
|
spl_lang_type_id_t lt = sema_infer(sema, n->binary.left);
|
|
if (!lt)
|
|
return 0;
|
|
if (!sema_check(sema, n->binary.right, lt))
|
|
return 0;
|
|
n->resolved_lang_tid = lt;
|
|
n->expected_lang_tid = 0;
|
|
return lt;
|
|
}
|
|
|
|
/* 逻辑运算:两侧 check 到 bool */
|
|
if (op == SPL_OP_BOOL_OR || op == SPL_OP_BOOL_AND) {
|
|
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
|
|
if (!sema_check(sema, n->binary.left, bt))
|
|
return 0;
|
|
if (!sema_check(sema, n->binary.right, bt))
|
|
return 0;
|
|
n->resolved_lang_tid = bt;
|
|
n->expected_lang_tid = 0;
|
|
return bt;
|
|
}
|
|
|
|
if (op == SPL_OP_CMP_EQ || op == SPL_OP_CMP_NE || op == SPL_OP_CMP_LT ||
|
|
op == SPL_OP_CMP_LE || op == SPL_OP_CMP_GT || op == SPL_OP_CMP_GE) {
|
|
/* 比较:结果 bool,节点存操作数类型;不依赖 expected */
|
|
spl_lang_type_id_t lt = sema_infer(sema, n->binary.left);
|
|
spl_lang_type_id_t rt = sema_infer(sema, n->binary.right);
|
|
if (!lt || !rt)
|
|
return 0;
|
|
|
|
spl_lang_type_id_t common = 0;
|
|
if (lt == rt)
|
|
common = lt;
|
|
else
|
|
common = spl_lang_type_balance(sema->type, lt, rt);
|
|
if (!common) {
|
|
SPL_ERROR(&n->dbg, "comparison operands type mismatch");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
sema_check(sema, n->binary.left, common);
|
|
sema_check(sema, n->binary.right, common);
|
|
|
|
n->resolved_lang_tid = common;
|
|
return spl_lang_make_bool(sema->type);
|
|
}
|
|
/* 算术 / 位 / 移位:两侧 check 到 expected */
|
|
if (!sema_check(sema, n->binary.left, expected))
|
|
return 0;
|
|
if (!sema_check(sema, n->binary.right, expected))
|
|
return 0;
|
|
n->resolved_lang_tid = expected;
|
|
n->expected_lang_tid = 0;
|
|
return expected;
|
|
}
|
|
|
|
case SPL_AST_EXPR_ARRAY_LIT: {
|
|
spl_lang_type_node_t *en = spl_lang_type_node(sema->type, expected);
|
|
if (en && en->kind == SPL_LANG_TYPE_ARRAY) {
|
|
spl_lang_type_id_t et = en->extra.elem;
|
|
for (usize i = 0; i < vec_size(n->array_literal.elems); ++i)
|
|
if (!sema_check(sema, vec_at(n->array_literal.elems, i), et))
|
|
return 0;
|
|
n->resolved_lang_tid = expected;
|
|
n->expected_lang_tid = 0;
|
|
return expected;
|
|
}
|
|
break; /* 非数组 expected:退回通用逻辑 */
|
|
}
|
|
|
|
case SPL_AST_EXPR_AGGREGATE_LIT: {
|
|
spl_lang_type_node_t *en = spl_lang_type_node(sema->type, expected);
|
|
if (!en || (en->kind != SPL_LANG_TYPE_STRUCT && en->kind != SPL_LANG_TYPE_UNION))
|
|
break;
|
|
|
|
if (n->aggregate_literal.name) {
|
|
spl_symbol_t sym;
|
|
if (!spl_scope_find(sema->scope, n->aggregate_literal.name, &sym)) {
|
|
SPL_ERROR(&n->dbg, "unknown type `%s`", n->aggregate_literal.name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_def_node_t *def = spl_def_node(sema->type, sym.node);
|
|
if (!def || def->lang_id != expected) {
|
|
SPL_ERROR(&n->dbg, "aggregate `%s` does not match expected type",
|
|
n->aggregate_literal.name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, expected);
|
|
spl_type_node_t *irn = spl_type_node(sema->type, agg_ir);
|
|
if (!irn)
|
|
return 0;
|
|
usize nfields = vec_size(irn->agg_type.variants);
|
|
bool *seen = calloc(nfields ? nfields : 1, sizeof(bool));
|
|
|
|
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;
|
|
usize idx = 0;
|
|
if (!spl_type_agg_member_idx(sema->type, agg_ir, item->struct_init_item.name, &idx)) {
|
|
SPL_ERROR(&item->dbg, "no field `%s`", item->struct_init_item.name);
|
|
sema->error_count++;
|
|
continue;
|
|
}
|
|
if (seen[idx]) {
|
|
SPL_ERROR(&item->dbg, "duplicate field `%s`", item->struct_init_item.name);
|
|
sema->error_count++;
|
|
continue;
|
|
}
|
|
seen[idx] = true;
|
|
spl_type_member_t *m = &vec_at(irn->agg_type.variants, idx);
|
|
spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id);
|
|
if (!ft)
|
|
continue;
|
|
if (!item->struct_init_item.expr) {
|
|
SPL_ERROR(&item->dbg, "field `%s` requires initializer",
|
|
item->struct_init_item.name);
|
|
sema->error_count++;
|
|
continue;
|
|
}
|
|
sema_check(sema, item->struct_init_item.expr, ft);
|
|
}
|
|
for (usize i = 0; i < nfields; ++i) {
|
|
if (!seen[i]) {
|
|
SPL_ERROR(&n->dbg, "missing field `%s`", vec_at(irn->agg_type.variants, i).name);
|
|
sema->error_count++;
|
|
}
|
|
}
|
|
free(seen);
|
|
n->resolved_lang_tid = expected;
|
|
n->expected_lang_tid = 0;
|
|
return expected;
|
|
}
|
|
|
|
case SPL_AST_EXPR_IF: {
|
|
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
|
|
sema_check(sema, n->if_expr.cond, bt);
|
|
if (n->if_expr.then_block)
|
|
sema_check(sema, n->if_expr.then_block, expected);
|
|
if (n->if_expr.else_branch)
|
|
sema_check(sema, n->if_expr.else_branch, expected);
|
|
n->resolved_lang_tid = expected;
|
|
n->expected_lang_tid = 0;
|
|
return expected;
|
|
}
|
|
|
|
case SPL_AST_EXPR_BLOCK: {
|
|
for (usize i = 0; i < vec_size(n->block.stmts); ++i)
|
|
sema_infer(sema, vec_at(n->block.stmts, i));
|
|
if (n->block.tail_expr) {
|
|
spl_lang_type_id_t t = sema_check(sema, n->block.tail_expr, expected);
|
|
if (!t)
|
|
return 0;
|
|
n->resolved_lang_tid = t;
|
|
n->expected_lang_tid = 0;
|
|
return t;
|
|
}
|
|
spl_lang_type_id_t u = spl_lang_make_unit(sema->type);
|
|
n->resolved_lang_tid = u;
|
|
n->expected_lang_tid = 0;
|
|
return u;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* ============ 类 2:字面量 —— 就地定型 ============ */
|
|
if (sema_is_literal(n)) {
|
|
spl_lang_type_id_t from = n->resolved_lang_tid;
|
|
if (!from) {
|
|
from = sema_infer(sema, ref);
|
|
if (!from)
|
|
return 0;
|
|
}
|
|
if (from == expected)
|
|
return expected;
|
|
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, expected, from);
|
|
if (!r) {
|
|
SPL_ERROR(&n->dbg, "literal cannot coerce to expected type");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->resolved_lang_tid = r;
|
|
n->expected_lang_tid = 0;
|
|
return r;
|
|
}
|
|
|
|
/* ============ 类 3:引用性节点 —— 只记 expected ============ */
|
|
{
|
|
spl_lang_type_id_t from = sema_infer(sema, ref);
|
|
if (!from)
|
|
return 0;
|
|
if (from == expected) {
|
|
n->expected_lang_tid = 0;
|
|
return expected;
|
|
}
|
|
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, expected, from);
|
|
if (!r) {
|
|
SPL_ERROR(&n->dbg, "type mismatch: cannot coerce to expected type");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->expected_lang_tid = expected; /* 只记,不改 natural */
|
|
return expected;
|
|
}
|
|
}
|
|
|
|
static spl_lang_type_id_t sema_infer(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_EXPR_INT_LIT: {
|
|
spl_lang_type_id_t t = spl_lang_make_int(sema->type, 0, 1); /* comptime_int */
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
case SPL_AST_EXPR_FLOAT_LIT: {
|
|
spl_lang_type_id_t t = spl_lang_make_float(sema->type, 0); /* comptime_float */
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
case SPL_AST_EXPR_CHAR_LIT: {
|
|
spl_lang_type_id_t t = spl_lang_make_int(sema->type, 8, 0);
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
case SPL_AST_EXPR_STRING_LIT: {
|
|
spl_lang_type_id_t u8 = spl_lang_make_int(sema->type, 8, 0);
|
|
spl_lang_type_id_t s = spl_lang_make_slice(sema->type, u8);
|
|
n->resolved_lang_tid = s;
|
|
return s;
|
|
}
|
|
case SPL_AST_EXPR_BOOL_LIT: {
|
|
spl_lang_type_id_t t = spl_lang_make_bool(sema->type);
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
case SPL_AST_EXPR_NULL_LIT: {
|
|
spl_lang_type_id_t nv = spl_lang_make_never(sema->type);
|
|
spl_lang_type_id_t p = spl_lang_make_ptr(sema->type, nv);
|
|
n->resolved_lang_tid = p;
|
|
return p;
|
|
}
|
|
case SPL_AST_EXPR_UNDEFINED_LIT: {
|
|
spl_lang_type_id_t t = spl_lang_make_never(sema->type);
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
|
|
/* ---------- IDENT:同时写 def_id 和 lang_tid 副本 ---------- */
|
|
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;
|
|
}
|
|
n->resolved_lang_tid = def->lang_id;
|
|
return def->lang_id;
|
|
}
|
|
|
|
/* ---------- UNARY ---------- */
|
|
case SPL_AST_EXPR_UNARY: {
|
|
spl_lang_type_id_t op = sema_infer(sema, n->unary.operand);
|
|
if (op == 0)
|
|
return 0;
|
|
spl_lang_type_node_t *tn = spl_lang_type_node(sema->type, op);
|
|
if (!tn)
|
|
return 0;
|
|
|
|
switch (n->unary.op) {
|
|
case SPL_UNARY_OP_MINUS:
|
|
if (tn->kind != SPL_LANG_TYPE_INT && tn->kind != SPL_LANG_TYPE_FLOAT) {
|
|
SPL_ERROR(&n->dbg, "unary minus requires numeric operand");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->resolved_lang_tid = op;
|
|
return op;
|
|
case SPL_UNARY_OP_BIT_NOT:
|
|
if (tn->kind != SPL_LANG_TYPE_INT) {
|
|
SPL_ERROR(&n->dbg, "bitwise not requires integer operand");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->resolved_lang_tid = op;
|
|
return op;
|
|
case SPL_UNARY_OP_NOT: {
|
|
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
|
|
sema_check(sema, n->unary.operand, bt);
|
|
n->resolved_lang_tid = bt;
|
|
return bt;
|
|
}
|
|
case SPL_UNARY_OP_ADDRESS: {
|
|
spl_lang_type_id_t p = spl_lang_make_ptr(sema->type, op);
|
|
n->resolved_lang_tid = p;
|
|
return p;
|
|
}
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
/* ---------- BINARY ---------- */
|
|
case SPL_AST_EXPR_BINARY: {
|
|
spl_binary_op_t op = n->binary.op;
|
|
|
|
/* 赋值 / 复合赋值 */
|
|
if (op == SPL_OP_ASSIGN || (op >= SPL_OP_ASSIGN_ADD && op <= SPL_OP_ASSIGN_RSHIFT)) {
|
|
spl_lang_type_id_t lt = sema_infer(sema, n->binary.left);
|
|
if (!lt)
|
|
return 0;
|
|
sema_check(sema, n->binary.right, lt);
|
|
n->resolved_lang_tid = lt;
|
|
return lt;
|
|
}
|
|
|
|
/* 逻辑 */
|
|
if (op == SPL_OP_BOOL_OR || op == SPL_OP_BOOL_AND) {
|
|
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
|
|
sema_check(sema, n->binary.left, bt);
|
|
sema_check(sema, n->binary.right, bt);
|
|
n->resolved_lang_tid = bt;
|
|
return bt;
|
|
}
|
|
|
|
if (op == SPL_OP_CMP_EQ || op == SPL_OP_CMP_NE || op == SPL_OP_CMP_LT ||
|
|
op == SPL_OP_CMP_LE || op == SPL_OP_CMP_GT || op == SPL_OP_CMP_GE) {
|
|
spl_lang_type_id_t lt = sema_infer(sema, n->binary.left);
|
|
spl_lang_type_id_t rt = sema_infer(sema, n->binary.right);
|
|
if (!lt || !rt)
|
|
return 0;
|
|
|
|
spl_lang_type_id_t common = 0;
|
|
if (lt == rt)
|
|
common = lt;
|
|
else
|
|
common = spl_lang_type_balance(sema->type, lt, rt);
|
|
if (!common) {
|
|
SPL_ERROR(&n->dbg, "comparison operands type mismatch");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
sema_check(sema, n->binary.left, common);
|
|
sema_check(sema, n->binary.right, common);
|
|
|
|
n->resolved_lang_tid = common;
|
|
return spl_lang_make_bool(sema->type);
|
|
}
|
|
|
|
/* Range */
|
|
if (op == SPL_OP_RANGE) {
|
|
sema_infer(sema, n->binary.left);
|
|
sema_infer(sema, n->binary.right);
|
|
spl_lang_type_id_t i64 = spl_lang_make_int(sema->type, 64, 1);
|
|
spl_lang_type_id_t r = spl_lang_make_range(sema->type, i64);
|
|
n->resolved_lang_tid = r;
|
|
return r;
|
|
}
|
|
|
|
/* 移位:结果 = 左类型 */
|
|
if (op == SPL_OP_LSHIFT || op == SPL_OP_RSHIFT) {
|
|
spl_lang_type_id_t lt = sema_infer(sema, n->binary.left);
|
|
if (!lt)
|
|
return 0;
|
|
spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt);
|
|
if (!ln || ln->kind != SPL_LANG_TYPE_INT) {
|
|
SPL_ERROR(&n->dbg, "shift requires integer operands");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
sema_infer(sema, n->binary.right);
|
|
n->resolved_lang_tid = lt;
|
|
return lt;
|
|
}
|
|
|
|
/* 算术 / 位运算 */
|
|
spl_lang_type_id_t lt = sema_infer(sema, n->binary.left);
|
|
spl_lang_type_id_t rt = sema_infer(sema, n->binary.right);
|
|
if (!lt || !rt)
|
|
return 0;
|
|
|
|
spl_lang_type_id_t common = 0;
|
|
if (lt == rt)
|
|
common = lt;
|
|
else
|
|
common = spl_lang_type_balance(sema->type, lt, rt);
|
|
|
|
/* balance 失败:comptime + 具体时取具体 */
|
|
if (!common) {
|
|
spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt);
|
|
spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt);
|
|
if (ln && ln->kind == SPL_LANG_TYPE_INT && rn && rn->kind == SPL_LANG_TYPE_INT) {
|
|
spl_type_node_t *lir = spl_type_node(sema->type, ln->ir_type_id);
|
|
spl_type_node_t *rir = spl_type_node(sema->type, rn->ir_type_id);
|
|
if (lir && lir->int_type.bits == 0)
|
|
common = rt;
|
|
else if (rir && rir->int_type.bits == 0)
|
|
common = lt;
|
|
} else if (ln && ln->kind == SPL_LANG_TYPE_FLOAT && rn &&
|
|
rn->kind == SPL_LANG_TYPE_FLOAT) {
|
|
spl_type_node_t *lir = spl_type_node(sema->type, ln->ir_type_id);
|
|
spl_type_node_t *rir = spl_type_node(sema->type, rn->ir_type_id);
|
|
if (lir && lir->float_type.bits == 0)
|
|
common = rt;
|
|
else if (rir && rir->float_type.bits == 0)
|
|
common = lt;
|
|
}
|
|
}
|
|
if (!common) {
|
|
SPL_ERROR(&n->dbg, "arithmetic operands type mismatch");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
sema_check(sema, n->binary.left, common);
|
|
sema_check(sema, n->binary.right, common);
|
|
n->resolved_lang_tid = common;
|
|
return common;
|
|
}
|
|
|
|
/* ---------- CALL ---------- */
|
|
case SPL_AST_EXPR_CALL: {
|
|
spl_ast_node_t *callee = spl_ast_node(sema->ast, n->call.callee);
|
|
if (callee && callee->kind == SPL_AST_EXPR_IDENT) {
|
|
spl_intrin_t in = spl_intrin_lookup_call(callee->ident.name);
|
|
if (in != SPL_INTRIN_NONE) {
|
|
spl_lang_type_id_t t = sema_intrin_call(sema, n, in, &n->call.args);
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
}
|
|
|
|
spl_lang_type_id_t callee_tid = sema_infer(sema, n->call.callee);
|
|
spl_lang_type_node_t *fn = spl_lang_type_node(sema->type, callee_tid);
|
|
if (!fn || fn->kind != SPL_LANG_TYPE_FN) {
|
|
SPL_ERROR(&n->dbg, "callee is not a function");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
bool has_varargs = false;
|
|
usize fixed = vec_size(fn->extra.fn.params);
|
|
if (fixed > 0) {
|
|
spl_lang_type_id_t last = vec_at(fn->extra.fn.params, fixed - 1);
|
|
spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, last);
|
|
if (ln && ln->kind == SPL_LANG_TYPE_VARARGS) {
|
|
has_varargs = true;
|
|
fixed--;
|
|
}
|
|
}
|
|
|
|
usize nargs = vec_size(n->call.args);
|
|
if (has_varargs) {
|
|
if (nargs < fixed) {
|
|
SPL_ERROR(&n->dbg, "too few arguments (expected at least %zu)", fixed);
|
|
sema->error_count++;
|
|
}
|
|
} else if (nargs != fixed) {
|
|
SPL_ERROR(&n->dbg, "argument count mismatch (expected %zu, got %zu)", fixed, nargs);
|
|
sema->error_count++;
|
|
}
|
|
|
|
/* 固定参数:check 到形参类型 */
|
|
for (usize i = 0; i < nargs && i < fixed; ++i) {
|
|
spl_lang_type_id_t pt = vec_at(fn->extra.fn.params, i);
|
|
sema_check(sema, vec_at(n->call.args, i), pt);
|
|
}
|
|
/* varargs:默认提升到 isize */
|
|
if (has_varargs) {
|
|
spl_lang_type_id_t vt = spl_lang_make_int(sema->type, sizeof(void *) * 8, 1);
|
|
for (usize i = fixed; i < nargs; ++i)
|
|
sema_check(sema, vec_at(n->call.args, i), vt);
|
|
}
|
|
|
|
spl_lang_type_id_t ret = fn->extra.fn.ret;
|
|
n->resolved_lang_tid = ret;
|
|
return ret;
|
|
}
|
|
|
|
/* ---------- FIELD ---------- */
|
|
case SPL_AST_EXPR_FIELD: {
|
|
spl_lang_type_id_t obj_tid = sema_infer(sema, n->field.obj);
|
|
spl_lang_type_node_t *obj = spl_lang_type_node(sema->type, obj_tid);
|
|
if (!obj)
|
|
return 0;
|
|
|
|
spl_intrin_t in = spl_intrin_lookup_field(obj->kind, n->field.field);
|
|
if (in != SPL_INTRIN_NONE) {
|
|
spl_lang_type_id_t t = sema_intrin_field(sema, n, in);
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
|
|
spl_lang_type_id_t agg_lang = obj_tid;
|
|
if (obj->kind == SPL_LANG_TYPE_PTR)
|
|
agg_lang = obj->extra.elem;
|
|
spl_lang_type_node_t *agg = spl_lang_type_node(sema->type, agg_lang);
|
|
if (!agg || (agg->kind != SPL_LANG_TYPE_STRUCT && agg->kind != SPL_LANG_TYPE_UNION)) {
|
|
SPL_ERROR(&n->dbg, "field access on non-aggregate type");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg_lang);
|
|
const spl_type_member_t *m = spl_type_agg_member(sema->type, agg_ir, n->field.field);
|
|
if (!m) {
|
|
SPL_ERROR(&n->dbg, "no field `%s`", n->field.field);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id);
|
|
if (!ft) {
|
|
SPL_ERROR(&n->dbg, "cannot resolve field type");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->resolved_lang_tid = ft;
|
|
return ft;
|
|
}
|
|
|
|
/* ---------- INDEX ---------- */
|
|
case SPL_AST_EXPR_INDEX: {
|
|
spl_lang_type_id_t obj_tid = sema_infer(sema, n->index.obj);
|
|
sema_infer(sema, n->index.index);
|
|
spl_lang_type_node_t *obj = spl_lang_type_node(sema->type, obj_tid);
|
|
if (!obj)
|
|
return 0;
|
|
spl_lang_type_id_t elem = 0;
|
|
switch (obj->kind) {
|
|
case SPL_LANG_TYPE_ARRAY:
|
|
case SPL_LANG_TYPE_SLICE:
|
|
case SPL_LANG_TYPE_RANGE:
|
|
case SPL_LANG_TYPE_PTR:
|
|
elem = obj->extra.elem;
|
|
break;
|
|
case SPL_LANG_TYPE_TUPLE:
|
|
if (vec_size(obj->extra.elems) > 0)
|
|
elem = vec_at(obj->extra.elems, 0);
|
|
break;
|
|
default:
|
|
SPL_ERROR(&n->dbg, "index base must be array/slice/ptr/range/tuple");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->resolved_lang_tid = elem;
|
|
return elem;
|
|
}
|
|
|
|
/* ---------- SLICE ---------- */
|
|
case SPL_AST_EXPR_SLICE: {
|
|
spl_lang_type_id_t obj_tid = sema_infer(sema, n->slice.obj);
|
|
if (n->slice.begin)
|
|
sema_infer(sema, n->slice.begin);
|
|
if (n->slice.end)
|
|
sema_infer(sema, n->slice.end);
|
|
spl_lang_type_node_t *obj = spl_lang_type_node(sema->type, obj_tid);
|
|
if (!obj)
|
|
return 0;
|
|
spl_lang_type_id_t elem = 0;
|
|
if (obj->kind == SPL_LANG_TYPE_ARRAY || obj->kind == SPL_LANG_TYPE_PTR ||
|
|
obj->kind == SPL_LANG_TYPE_SLICE) {
|
|
elem = obj->extra.elem;
|
|
} else {
|
|
SPL_ERROR(&n->dbg, "slice base must be array/ptr/slice");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_lang_type_id_t s = spl_lang_make_slice(sema->type, elem);
|
|
n->resolved_lang_tid = s;
|
|
return s;
|
|
}
|
|
|
|
/* ---------- CAST ---------- */
|
|
case SPL_AST_EXPR_CAST: {
|
|
spl_lang_type_id_t src = sema_infer(sema, n->cast.expr);
|
|
spl_lang_type_id_t dst = sema_infer(sema, n->cast.type);
|
|
if (!src || !dst)
|
|
return 0;
|
|
spl_lang_type_node_t *sn = spl_lang_type_node(sema->type, src);
|
|
if (sn && !(sn->kind == SPL_LANG_TYPE_INT || sn->kind == SPL_LANG_TYPE_FLOAT ||
|
|
sn->kind == SPL_LANG_TYPE_BOOL || sn->kind == SPL_LANG_TYPE_PTR)) {
|
|
SPL_ERROR(&n->dbg, "invalid cast from non-primitive type");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->resolved_lang_tid = dst;
|
|
return dst;
|
|
}
|
|
|
|
/* ---------- TUPLE ---------- */
|
|
case SPL_AST_EXPR_TUPLE: {
|
|
spl_lang_type_id_vec_t es;
|
|
vec_init(es);
|
|
for (usize i = 0; i < vec_size(n->tuple.elems); ++i)
|
|
vec_push(es, sema_infer(sema, vec_at(n->tuple.elems, i)));
|
|
spl_lang_type_id_t t =
|
|
spl_lang_make_tuple(sema->type, vec_unsafe_get_data(es), vec_size(es));
|
|
vec_free(es);
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
|
|
/* ---------- ARRAY_LIT ---------- */
|
|
case SPL_AST_EXPR_ARRAY_LIT: {
|
|
spl_lang_type_id_t elem_t = 0;
|
|
if (n->array_literal.elem_type)
|
|
elem_t = sema_infer(sema, n->array_literal.elem_type);
|
|
|
|
usize nelems = vec_size(n->array_literal.elems);
|
|
for (usize i = 0; i < nelems; ++i) {
|
|
spl_lang_type_id_t et = sema_infer(sema, vec_at(n->array_literal.elems, i));
|
|
if (!et)
|
|
return 0;
|
|
if (elem_t == 0)
|
|
elem_t = et;
|
|
else {
|
|
spl_lang_type_id_t c = spl_lang_type_balance(sema->type, elem_t, et);
|
|
if (c)
|
|
elem_t = c;
|
|
}
|
|
}
|
|
if (elem_t == 0)
|
|
elem_t = spl_lang_make_infer(sema->type);
|
|
usize len = n->array_literal.is_underscore_len ? nelems
|
|
: n->array_literal.has_len ? (usize)n->array_literal.len
|
|
: nelems;
|
|
spl_lang_type_id_t arr = spl_lang_make_array(sema->type, elem_t, len);
|
|
n->resolved_lang_tid = arr;
|
|
return arr;
|
|
}
|
|
|
|
/* ---------- AGGREGATE_LIT ---------- */
|
|
case SPL_AST_EXPR_AGGREGATE_LIT: {
|
|
const char *type_name = n->aggregate_literal.name;
|
|
if (!type_name) {
|
|
spl_lang_type_id_t inf = spl_lang_make_infer(sema->type);
|
|
n->resolved_lang_tid = inf;
|
|
return inf;
|
|
}
|
|
spl_symbol_t sym;
|
|
if (!spl_scope_find(sema->scope, type_name, &sym)) {
|
|
SPL_ERROR(&n->dbg, "unknown type `%s`", type_name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_def_node_t *def = spl_def_node(sema->type, sym.node);
|
|
if (!def || !def->lang_id) {
|
|
SPL_ERROR(&n->dbg, "type `%s` not resolved", type_name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_lang_type_id_t agg = def->lang_id;
|
|
spl_lang_type_node_t *an = spl_lang_type_node(sema->type, agg);
|
|
if (!an || (an->kind != SPL_LANG_TYPE_STRUCT && an->kind != SPL_LANG_TYPE_UNION)) {
|
|
SPL_ERROR(&n->dbg, "`%s` is not a struct/union", type_name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg);
|
|
spl_type_node_t *irn = spl_type_node(sema->type, agg_ir);
|
|
if (irn) {
|
|
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;
|
|
usize idx = 0;
|
|
if (!spl_type_agg_member_idx(sema->type, agg_ir, item->struct_init_item.name,
|
|
&idx)) {
|
|
SPL_ERROR(&item->dbg, "no field `%s`", item->struct_init_item.name);
|
|
sema->error_count++;
|
|
continue;
|
|
}
|
|
spl_type_member_t *m = &vec_at(irn->agg_type.variants, idx);
|
|
spl_lang_type_id_t ft = sema_lang_from_ir(sema, m->type_id);
|
|
if (ft && item->struct_init_item.expr)
|
|
sema_check(sema, item->struct_init_item.expr, ft);
|
|
}
|
|
}
|
|
n->resolved_lang_tid = agg;
|
|
return agg;
|
|
}
|
|
|
|
/* ---------- COMPTIME_CALL ---------- */
|
|
case SPL_AST_EXPR_COMPTIME_CALL: {
|
|
spl_intrin_t in = spl_intrin_lookup_call(n->comptime_call.name);
|
|
if (in == SPL_INTRIN_NONE) {
|
|
SPL_ERROR(&n->dbg, "unknown comptime call `@%s`", n->comptime_call.name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_lang_type_id_t t = sema_intrin_call(sema, n, in, &n->comptime_call.args);
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
|
|
/* ---------- BLOCK ---------- */
|
|
case SPL_AST_EXPR_BLOCK: {
|
|
spl_lang_type_id_t last = 0;
|
|
for (usize i = 0; i < vec_size(n->block.stmts); ++i)
|
|
last = sema_infer(sema, vec_at(n->block.stmts, i));
|
|
if (n->block.tail_expr)
|
|
last = sema_infer(sema, n->block.tail_expr);
|
|
n->resolved_lang_tid = last;
|
|
return last;
|
|
}
|
|
|
|
/* ---------- IF ---------- */
|
|
case SPL_AST_EXPR_IF: {
|
|
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
|
|
sema_check(sema, n->if_expr.cond, bt);
|
|
|
|
spl_lang_type_id_t then_t =
|
|
n->if_expr.then_block ? sema_infer(sema, n->if_expr.then_block) : 0;
|
|
spl_lang_type_id_t else_t =
|
|
n->if_expr.else_branch ? sema_infer(sema, n->if_expr.else_branch) : 0;
|
|
spl_lang_type_id_t result = 0;
|
|
if (then_t && else_t)
|
|
result = spl_lang_type_balance(sema->type, then_t, else_t);
|
|
else
|
|
result = then_t ? then_t : else_t;
|
|
n->resolved_lang_tid = result;
|
|
return result;
|
|
}
|
|
|
|
/* ---------- IFVAR / WHILE / LOOP / FOR / MATCH ---------- */
|
|
case SPL_AST_EXPR_IFVAR:
|
|
sema_infer(sema, n->ifvar_expr.var_decl);
|
|
if (n->ifvar_expr.then_block)
|
|
sema_infer(sema, n->ifvar_expr.then_block);
|
|
if (n->ifvar_expr.else_branch)
|
|
sema_infer(sema, n->ifvar_expr.else_branch);
|
|
return 0;
|
|
case SPL_AST_EXPR_WHILE: {
|
|
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
|
|
sema_check(sema, n->while_expr.cond, bt);
|
|
if (n->while_expr.body)
|
|
sema_infer(sema, n->while_expr.body);
|
|
if (n->while_expr.else_branch)
|
|
sema_infer(sema, n->while_expr.else_branch);
|
|
return 0;
|
|
}
|
|
case SPL_AST_EXPR_LOOP:
|
|
if (n->loop_expr.body)
|
|
sema_infer(sema, n->loop_expr.body);
|
|
return 0;
|
|
case SPL_AST_EXPR_FOR: {
|
|
sema_push_scope(sema);
|
|
for (usize i = 0; i < vec_size(n->for_expr.iter_exprs); ++i) {
|
|
spl_lang_type_id_t container_tid = sema_infer(sema, vec_at(n->for_expr.iter_exprs, i));
|
|
spl_lang_type_id_t elem_tid = sema_for_elem_type(sema, container_tid);
|
|
if (i < vec_size(n->for_expr.idents)) {
|
|
spl_ast_node_t *id_node = spl_ast_node(sema->ast, vec_at(n->for_expr.idents, i));
|
|
if (id_node && id_node->kind == SPL_AST_EXPR_IDENT) {
|
|
const char *var_name = id_node->ident.name;
|
|
if (strcmp(var_name, "_") != 0) {
|
|
spl_symbol_t sym = {.name = var_name, .kind = SPL_SYMBOL_KIND_VAR};
|
|
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, var_name, id_node->dbg,
|
|
vec_at(n->for_expr.idents, i));
|
|
spl_def_resolve(sema->type, sym.node, elem_tid);
|
|
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
|
|
id_node->resolved_def_id = sym.node;
|
|
id_node->resolved_lang_tid = elem_tid;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (n->for_expr.body)
|
|
sema_infer(sema, n->for_expr.body);
|
|
if (n->for_expr.else_branch)
|
|
sema_infer(sema, n->for_expr.else_branch);
|
|
sema_pop_scope(sema);
|
|
return 0;
|
|
}
|
|
case SPL_AST_EXPR_MATCH:
|
|
sema_infer(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_infer(sema, arm->match_arm.pattern);
|
|
sema_infer(sema, arm->match_arm.body);
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
/* ---------- FN_TYPE ---------- */
|
|
case SPL_AST_EXPR_FN_TYPE: {
|
|
spl_lang_type_id_vec_t ps;
|
|
vec_init(ps);
|
|
for (usize i = 0; i < vec_size(n->fn_type.params); ++i)
|
|
vec_push(ps, sema_infer(sema, vec_at(n->fn_type.params, i)));
|
|
spl_lang_type_id_t ret = sema_infer(sema, n->fn_type.ret_type);
|
|
spl_lang_type_id_t fn =
|
|
spl_lang_make_fn(sema->type, ret, vec_unsafe_get_data(ps), vec_size(ps));
|
|
vec_free(ps);
|
|
n->resolved_lang_tid = fn;
|
|
return fn;
|
|
}
|
|
|
|
/* ---------- 类型表达式 ---------- */
|
|
case SPL_AST_TYPE_PATH: {
|
|
const char *name = n->type_path.name;
|
|
spl_lang_type_id_t b = spl_type_lookup_builtin(sema->type, name);
|
|
if (b) {
|
|
n->resolved_lang_tid = b;
|
|
return b;
|
|
}
|
|
spl_symbol_t sym;
|
|
if (!spl_scope_find(sema->scope, name, &sym)) {
|
|
SPL_ERROR(&n->dbg, "type `%s` not found", name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_def_node_t *def = spl_def_node(sema->type, sym.node);
|
|
if (!def || !def->lang_id)
|
|
return 0;
|
|
n->resolved_lang_tid = def->lang_id;
|
|
return def->lang_id;
|
|
}
|
|
case SPL_AST_TYPE_POINTER: {
|
|
spl_lang_type_id_t p = sema_infer(sema, n->type_pointer.pointee);
|
|
spl_lang_type_id_t r = spl_lang_make_ptr(sema->type, p);
|
|
n->resolved_lang_tid = r;
|
|
return r;
|
|
}
|
|
case SPL_AST_TYPE_ARRAY: {
|
|
spl_lang_type_id_t e = sema_infer(sema, n->type_array.elem_type);
|
|
usize len = n->type_array.has_len ? (usize)n->type_array.len : 0;
|
|
spl_lang_type_id_t r = spl_lang_make_array(sema->type, e, len);
|
|
n->resolved_lang_tid = r;
|
|
return r;
|
|
}
|
|
case SPL_AST_TYPE_SLICE: {
|
|
spl_lang_type_id_t e = sema_infer(sema, n->type_slice.elem_type);
|
|
spl_lang_type_id_t r = spl_lang_make_slice(sema->type, e);
|
|
n->resolved_lang_tid = r;
|
|
return r;
|
|
}
|
|
case SPL_AST_TYPE_FN: {
|
|
spl_lang_type_id_vec_t ps;
|
|
vec_init(ps);
|
|
for (usize i = 0; i < vec_size(n->type_fn.params); ++i)
|
|
vec_push(ps, sema_infer(sema, vec_at(n->type_fn.params, i)));
|
|
spl_lang_type_id_t ret = sema_infer(sema, n->type_fn.ret_type);
|
|
spl_lang_type_id_t r =
|
|
spl_lang_make_fn(sema->type, ret, vec_unsafe_get_data(ps), vec_size(ps));
|
|
vec_free(ps);
|
|
n->resolved_lang_tid = r;
|
|
return r;
|
|
}
|
|
case SPL_AST_TYPE_PAREN: {
|
|
usize c = vec_size(n->type_paren.types);
|
|
if (c == 0) {
|
|
spl_lang_type_id_t u = spl_lang_make_unit(sema->type);
|
|
n->resolved_lang_tid = u;
|
|
return u;
|
|
}
|
|
if (c == 1) {
|
|
spl_lang_type_id_t t = sema_infer(sema, vec_at(n->type_paren.types, 0));
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
spl_lang_type_id_vec_t es;
|
|
vec_init(es);
|
|
for (usize i = 0; i < c; ++i)
|
|
vec_push(es, sema_infer(sema, vec_at(n->type_paren.types, i)));
|
|
spl_lang_type_id_t t =
|
|
spl_lang_make_tuple(sema->type, vec_unsafe_get_data(es), vec_size(es));
|
|
vec_free(es);
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
case SPL_AST_TYPE_AGGREGATE:
|
|
case SPL_AST_TYPE_COMPTIME_CALL:
|
|
return 0;
|
|
|
|
/* ---------- 顶层声明 ---------- */
|
|
case SPL_AST_CONTAINER_MEMBERS:
|
|
for (usize i = 0; i < vec_size(n->container_members.declarations); ++i)
|
|
sema_infer(sema, vec_at(n->container_members.declarations, i));
|
|
return 0;
|
|
|
|
case SPL_AST_FN_DECL: {
|
|
if (n->resolved_def_id == 0)
|
|
Panic("fn `%s` not collected", n->fn_decl.name);
|
|
|
|
spl_lang_type_id_vec_t param_types;
|
|
vec_init(param_types);
|
|
for (usize i = 0; i < vec_size(n->fn_decl.params); ++i) {
|
|
spl_ast_node_t *pd = spl_ast_node(sema->ast, vec_at(n->fn_decl.params, i));
|
|
if (pd && pd->kind == SPL_AST_PARAM_DECL && pd->param_decl.type_expr)
|
|
vec_push(param_types, sema_infer(sema, pd->param_decl.type_expr));
|
|
else
|
|
vec_push(param_types, spl_lang_make_varargs(sema->type));
|
|
}
|
|
spl_lang_type_id_t ret_tid = sema_infer(sema, n->fn_decl.ret_type);
|
|
if (ret_tid == 0)
|
|
ret_tid = spl_lang_make_unit(sema->type);
|
|
spl_lang_type_id_t fn_tid = spl_lang_make_fn(
|
|
sema->type, ret_tid, vec_unsafe_get_data(param_types), vec_size(param_types));
|
|
vec_free(param_types);
|
|
spl_def_resolve(sema->type, n->resolved_def_id, fn_tid);
|
|
|
|
if (n->fn_decl.body) {
|
|
sema_push_scope(sema);
|
|
for (usize i = 0; i < vec_size(n->fn_decl.params); ++i) {
|
|
spl_ast_node_t *pd = spl_ast_node(sema->ast, vec_at(n->fn_decl.params, i));
|
|
if (pd && pd->kind == SPL_AST_PARAM_DECL) {
|
|
spl_symbol_t psym = {.name = pd->param_decl.name, .kind = SPL_SYMBOL_KIND_VAR};
|
|
psym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, psym.name, pd->dbg,
|
|
vec_at(n->fn_decl.params, i));
|
|
spl_lang_type_id_t p_tid = sema_infer(sema, pd->param_decl.type_expr);
|
|
spl_def_resolve(sema->type, psym.node, p_tid);
|
|
pd->resolved_def_id = psym.node;
|
|
spl_scope_insert(sema->scope, sema->scope->current_scope, psym);
|
|
}
|
|
}
|
|
spl_lang_type_id_t old_ret = sema->current_fn_ret_tid;
|
|
sema->current_fn_ret_tid = ret_tid;
|
|
sema_infer(sema, n->fn_decl.body);
|
|
sema->current_fn_ret_tid = old_ret;
|
|
sema_pop_scope(sema);
|
|
}
|
|
return fn_tid;
|
|
}
|
|
|
|
case SPL_AST_TYPE_DECL: {
|
|
if (!n->type_decl.type_expr)
|
|
break;
|
|
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
|
|
if (!te)
|
|
break;
|
|
|
|
if (te->kind == SPL_AST_TYPE_AGGREGATE) {
|
|
spl_type_member_vec_t members;
|
|
vec_init(members);
|
|
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
|
|
spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i));
|
|
if (mn && mn->kind == SPL_AST_MEMBER_DECL) {
|
|
spl_lang_type_id_t mtid = sema_infer(sema, mn->member_decl.type_expr);
|
|
spl_type_member_t m = {.name = mn->member_decl.name,
|
|
.type_id = spl_lang_type_get_ir_type(sema->type, mtid),
|
|
.ast_node_ref = vec_at(te->type_aggregate.members, i)};
|
|
vec_push(members, m);
|
|
}
|
|
}
|
|
spl_type_node_kind_t tk;
|
|
if (strcmp(te->type_aggregate.kind_name, "struct") == 0)
|
|
tk = SPL_TYPE_STRUCT;
|
|
else if (strcmp(te->type_aggregate.kind_name, "union") == 0)
|
|
tk = SPL_TYPE_UNION;
|
|
else if (strcmp(te->type_aggregate.kind_name, "enum") == 0)
|
|
tk = SPL_TYPE_ENUM;
|
|
else
|
|
tk = SPL_TYPE_STRUCT;
|
|
|
|
spl_type_layout_t layout = {.mode = SPL_TYPE_LAYOUT_AUTO};
|
|
spl_type_id_t agg_ir = spl_type_builder_agg(
|
|
sema->type, tk, &members, spl_type_builder_int(sema->type, 32, 1), layout);
|
|
vec_free(members);
|
|
|
|
spl_lang_type_kind_t lk;
|
|
switch (tk) {
|
|
case SPL_TYPE_STRUCT:
|
|
lk = SPL_LANG_TYPE_STRUCT;
|
|
break;
|
|
case SPL_TYPE_UNION:
|
|
lk = SPL_LANG_TYPE_UNION;
|
|
break;
|
|
case SPL_TYPE_ENUM:
|
|
lk = SPL_LANG_TYPE_ENUM;
|
|
break;
|
|
case SPL_TYPE_SHAPE:
|
|
lk = SPL_LANG_TYPE_SHAPE;
|
|
break;
|
|
default:
|
|
lk = SPL_LANG_TYPE_STRUCT;
|
|
break;
|
|
}
|
|
spl_lang_type_node_t ln = {0};
|
|
ln.kind = lk;
|
|
ln.ir_type_id = agg_ir;
|
|
spl_lang_type_id_t agg_lang = spl_lang_node_push(sema->type, &ln);
|
|
spl_def_resolve(sema->type, n->resolved_def_id, agg_lang);
|
|
n->resolved_lang_tid = agg_lang;
|
|
|
|
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_infer(sema, vec_at(te->type_aggregate.members, i));
|
|
}
|
|
} else {
|
|
spl_lang_type_id_t tid = sema_infer(sema, n->type_decl.type_expr);
|
|
spl_def_resolve(sema->type, n->resolved_def_id, tid);
|
|
n->resolved_lang_tid = tid;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* ---------- VAR / CONST ---------- */
|
|
case SPL_AST_VAR_DECL:
|
|
case SPL_AST_CONST_DECL: {
|
|
spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern);
|
|
if (!pat || pat->kind != SPL_AST_PATTERN_IDENT) {
|
|
SPL_ERROR(&n->dbg, "unsupported variable pattern");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
const char *name = pat->pattern_ident.name;
|
|
|
|
if (n->resolved_def_id == 0) {
|
|
spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR};
|
|
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, ref);
|
|
n->resolved_def_id = sym.node;
|
|
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
|
|
}
|
|
|
|
spl_lang_type_id_t decl_tid = 0;
|
|
if (n->var_const_decl.type)
|
|
decl_tid = sema_infer(sema, n->var_const_decl.type);
|
|
|
|
if (!n->var_const_decl.init_expr) {
|
|
SPL_ERROR(&n->dbg, "variable `%s` must be initialized", name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
if (decl_tid) {
|
|
sema_check(sema, n->var_const_decl.init_expr, decl_tid);
|
|
} else {
|
|
decl_tid = sema_infer(sema, n->var_const_decl.init_expr);
|
|
if (!decl_tid || sema_is_infer(sema, decl_tid)) {
|
|
SPL_ERROR(&n->dbg, "cannot infer type of `%s`", name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
spl_def_resolve(sema->type, n->resolved_def_id, decl_tid);
|
|
n->resolved_lang_tid = decl_tid;
|
|
return decl_tid;
|
|
}
|
|
|
|
/* ---------- MEMBER / PARAM ---------- */
|
|
case SPL_AST_MEMBER_DECL:
|
|
if (n->member_decl.type_expr)
|
|
return sema_infer(sema, n->member_decl.type_expr);
|
|
return 0;
|
|
case SPL_AST_PARAM_DECL:
|
|
if (n->param_decl.type_expr)
|
|
return sema_infer(sema, n->param_decl.type_expr);
|
|
return 0;
|
|
|
|
/* ---------- 语句 ---------- */
|
|
case SPL_AST_STATEMENT_RET: {
|
|
if (n->statement_ret.expr) {
|
|
if (sema->current_fn_ret_tid)
|
|
sema_check(sema, n->statement_ret.expr, sema->current_fn_ret_tid);
|
|
else
|
|
sema_infer(sema, n->statement_ret.expr);
|
|
} else if (sema->current_fn_ret_tid) {
|
|
spl_lang_type_id_t u = spl_lang_make_unit(sema->type);
|
|
if (sema->current_fn_ret_tid != u) {
|
|
SPL_ERROR(&n->dbg, "function must return a value");
|
|
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_infer(sema, n->statement_defer.body);
|
|
return 0;
|
|
case SPL_AST_STATEMENT_COMPTIME:
|
|
if (n->statement_comptime.body)
|
|
sema_infer(sema, n->statement_comptime.body);
|
|
return 0;
|
|
case SPL_AST_STATEMENT_DECL:
|
|
if (n->statement_decl.decl)
|
|
sema_infer(sema, n->statement_decl.decl);
|
|
return 0;
|
|
case SPL_AST_STATEMENT_EXPR:
|
|
if (n->statement_expr.expr)
|
|
sema_infer(sema, n->statement_expr.expr);
|
|
return 0;
|
|
|
|
case SPL_AST_TOP_LEVEL_BLOCK:
|
|
if (n->top_level_block.block)
|
|
sema_infer(sema, n->top_level_block.block);
|
|
return 0;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
|
if (ref == 0)
|
|
return 0;
|
|
spl_ast_node_t *n = spl_ast_node(sema->ast, ref);
|
|
if (!n)
|
|
return 0;
|
|
|
|
switch (n->kind) {
|
|
case SPL_AST_CONTAINER_MEMBERS:
|
|
for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) {
|
|
sema_parse(sema, vec_at(n->container_members.declarations, i));
|
|
}
|
|
return 0;
|
|
|
|
case SPL_AST_FN_DECL: {
|
|
if (n->resolved_def_id == 0) {
|
|
Panic("fn `%s` not collected", n->fn_decl.name);
|
|
}
|
|
|
|
spl_lang_type_id_vec_t param_types;
|
|
vec_init(param_types);
|
|
for (usize i = 0; i < vec_size(n->fn_decl.params); ++i) {
|
|
spl_ast_node_t *pd = spl_ast_node(sema->ast, vec_at(n->fn_decl.params, i));
|
|
if (pd && pd->kind == SPL_AST_PARAM_DECL && pd->param_decl.type_expr) {
|
|
vec_push(param_types, sema_parse(sema, pd->param_decl.type_expr));
|
|
} else {
|
|
vec_push(param_types, spl_lang_make_varargs(sema->type));
|
|
}
|
|
}
|
|
spl_lang_type_id_t ret_tid = sema_parse(sema, n->fn_decl.ret_type);
|
|
if (ret_tid == 0) {
|
|
ret_tid = spl_lang_make_unit(sema->type);
|
|
}
|
|
spl_lang_type_id_t fn_tid = spl_lang_make_fn(
|
|
sema->type, ret_tid, vec_unsafe_get_data(param_types), vec_size(param_types));
|
|
Assert(fn_tid != 0);
|
|
vec_free(param_types);
|
|
spl_def_resolve(sema->type, n->resolved_def_id, fn_tid);
|
|
|
|
if (n->fn_decl.body) {
|
|
sema_push_scope(sema);
|
|
for (usize i = 0; i < vec_size(n->fn_decl.params); ++i) {
|
|
spl_ast_node_t *pd = spl_ast_node(sema->ast, vec_at(n->fn_decl.params, i));
|
|
if (pd && pd->kind == SPL_AST_PARAM_DECL) {
|
|
spl_symbol_t psym = {.name = pd->param_decl.name, .kind = SPL_SYMBOL_KIND_VAR};
|
|
psym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, psym.name, pd->dbg,
|
|
vec_at(n->fn_decl.params, i));
|
|
spl_lang_type_id_t p_tid = sema_parse(sema, pd->param_decl.type_expr);
|
|
spl_def_resolve(sema->type, psym.node, p_tid);
|
|
pd->resolved_def_id = psym.node;
|
|
spl_scope_insert(sema->scope, sema->scope->current_scope, psym);
|
|
}
|
|
}
|
|
spl_lang_type_id_t old_ret = sema->current_fn_ret_tid;
|
|
sema->current_fn_ret_tid = ret_tid;
|
|
sema_parse(sema, n->fn_decl.body);
|
|
sema->current_fn_ret_tid = old_ret;
|
|
sema_pop_scope(sema);
|
|
}
|
|
return fn_tid;
|
|
}
|
|
|
|
case SPL_AST_TYPE_DECL: {
|
|
if (!n->type_decl.type_expr)
|
|
break;
|
|
spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr);
|
|
if (!te)
|
|
break;
|
|
|
|
if (te->kind == SPL_AST_TYPE_AGGREGATE) {
|
|
spl_type_member_vec_t members;
|
|
vec_init(members);
|
|
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
|
|
spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i));
|
|
if (mn && mn->kind == SPL_AST_MEMBER_DECL) {
|
|
spl_lang_type_id_t mtid = sema_parse(sema, mn->member_decl.type_expr);
|
|
spl_type_member_t m = {.name = mn->member_decl.name,
|
|
.type_id = spl_lang_type_get_ir_type(sema->type, mtid),
|
|
.ast_node_ref = vec_at(te->type_aggregate.members, i)};
|
|
vec_push(members, m);
|
|
}
|
|
}
|
|
|
|
spl_type_node_kind_t tk;
|
|
if (strcmp(te->type_aggregate.kind_name, "struct") == 0)
|
|
tk = SPL_TYPE_STRUCT;
|
|
else if (strcmp(te->type_aggregate.kind_name, "union") == 0)
|
|
tk = SPL_TYPE_UNION;
|
|
else if (strcmp(te->type_aggregate.kind_name, "enum") == 0)
|
|
tk = SPL_TYPE_ENUM;
|
|
else
|
|
tk = SPL_TYPE_STRUCT;
|
|
|
|
spl_type_layout_t layout = {.mode = SPL_TYPE_LAYOUT_AUTO};
|
|
spl_type_id_t agg_ir = spl_type_builder_agg(
|
|
sema->type, tk, &members, spl_type_builder_int(sema->type, 32, 1), layout);
|
|
vec_free(members);
|
|
|
|
spl_lang_type_kind_t lk;
|
|
switch (tk) {
|
|
case SPL_TYPE_STRUCT:
|
|
lk = SPL_LANG_TYPE_STRUCT;
|
|
break;
|
|
case SPL_TYPE_UNION:
|
|
lk = SPL_LANG_TYPE_UNION;
|
|
break;
|
|
case SPL_TYPE_ENUM:
|
|
lk = SPL_LANG_TYPE_ENUM;
|
|
break;
|
|
case SPL_TYPE_SHAPE:
|
|
lk = SPL_LANG_TYPE_SHAPE;
|
|
break;
|
|
default:
|
|
lk = SPL_LANG_TYPE_STRUCT;
|
|
break;
|
|
}
|
|
|
|
spl_lang_type_node_t lang_node = {0};
|
|
lang_node.kind = lk;
|
|
lang_node.ir_type_id = agg_ir;
|
|
spl_lang_type_id_t agg_lang = spl_lang_node_push(sema->type, &lang_node);
|
|
spl_def_resolve(sema->type, n->resolved_def_id, agg_lang);
|
|
n->resolved_lang_tid = agg_lang;
|
|
|
|
/* 聚合内部函数:方法后续单独处理,这里暂只做函数体的语义解析 */
|
|
for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) {
|
|
spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i));
|
|
if (mn && mn->kind == SPL_AST_FN_DECL) {
|
|
sema_parse(sema, vec_at(te->type_aggregate.members, i));
|
|
}
|
|
}
|
|
} else {
|
|
spl_lang_type_id_t tid = sema_parse(sema, n->type_decl.type_expr);
|
|
spl_def_resolve(sema->type, n->resolved_def_id, tid);
|
|
n->resolved_lang_tid = 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_lang_type_id_t decl_tid;
|
|
if (n->var_const_decl.type) {
|
|
decl_tid = sema_parse(sema, n->var_const_decl.type);
|
|
} else {
|
|
decl_tid = spl_lang_make_infer(sema->type);
|
|
}
|
|
if (n->var_const_decl.init_expr == 0) {
|
|
SPL_ERROR(&n->dbg, "variable `%s` must be initialized", name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
spl_ast_node_t *init_node = spl_ast_node(sema->ast, n->var_const_decl.init_expr);
|
|
spl_lang_type_id_t init_tid = sema_parse(sema, n->var_const_decl.init_expr);
|
|
spl_lang_type_id_t coerce_result = spl_lang_type_coerce_to(sema->type, decl_tid, init_tid);
|
|
if (coerce_result == 0) {
|
|
SPL_ERROR(&n->dbg, "cannot coerce initializer to declared type");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
init_node->resolved_lang_tid = coerce_result;
|
|
decl_tid = coerce_result;
|
|
|
|
spl_def_resolve(sema->type, n->resolved_def_id, decl_tid);
|
|
n->resolved_lang_tid = 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_lang_type_id_t ct = spl_lang_make_int(sema->type, 0, 1);
|
|
n->resolved_lang_tid = ct;
|
|
return ct;
|
|
}
|
|
case SPL_AST_EXPR_FLOAT_LIT: {
|
|
spl_lang_type_id_t ct = spl_lang_make_float(sema->type, 0);
|
|
n->resolved_lang_tid = ct;
|
|
return ct;
|
|
}
|
|
case SPL_AST_EXPR_CHAR_LIT: {
|
|
spl_lang_type_id_t u8 = spl_lang_make_int(sema->type, 8, 0);
|
|
n->resolved_lang_tid = u8;
|
|
return u8;
|
|
}
|
|
case SPL_AST_EXPR_STRING_LIT: {
|
|
spl_lang_type_id_t u8 = spl_lang_make_int(sema->type, 8, 0);
|
|
spl_lang_type_id_t slice = spl_lang_make_slice(sema->type, u8);
|
|
n->resolved_lang_tid = slice;
|
|
return slice;
|
|
}
|
|
case SPL_AST_EXPR_BOOL_LIT: {
|
|
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
|
|
n->resolved_lang_tid = bt;
|
|
return bt;
|
|
}
|
|
case SPL_AST_EXPR_NULL_LIT: {
|
|
spl_lang_type_id_t never = spl_lang_make_never(sema->type);
|
|
spl_lang_type_id_t ptr = spl_lang_make_ptr(sema->type, never);
|
|
n->resolved_lang_tid = ptr;
|
|
return ptr;
|
|
}
|
|
case SPL_AST_EXPR_UNDEFINED_LIT: {
|
|
spl_lang_type_id_t t = spl_lang_make_never(sema->type);
|
|
n->resolved_lang_tid = 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;
|
|
}
|
|
n->resolved_lang_tid = def->lang_id;
|
|
return def->lang_id;
|
|
}
|
|
|
|
case SPL_AST_EXPR_UNARY: {
|
|
spl_lang_type_id_t operand_tid = sema_parse(sema, n->unary.operand);
|
|
if (operand_tid == 0)
|
|
return 0;
|
|
spl_lang_type_node_t *tn = spl_lang_type_node(sema->type, operand_tid);
|
|
if (!tn)
|
|
return 0;
|
|
|
|
switch (n->unary.op) {
|
|
case SPL_UNARY_OP_MINUS:
|
|
if (tn->kind != SPL_LANG_TYPE_INT && tn->kind != SPL_LANG_TYPE_FLOAT) {
|
|
SPL_ERROR(&n->dbg, "unary minus requires numeric operand");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->resolved_lang_tid = operand_tid;
|
|
return operand_tid;
|
|
case SPL_UNARY_OP_NOT:
|
|
if (tn->kind != SPL_LANG_TYPE_BOOL) {
|
|
SPL_ERROR(&n->dbg, "logical not requires bool operand");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
{
|
|
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
|
|
n->resolved_lang_tid = bt;
|
|
return bt;
|
|
}
|
|
case SPL_UNARY_OP_BIT_NOT:
|
|
if (tn->kind != SPL_LANG_TYPE_INT) {
|
|
SPL_ERROR(&n->dbg, "bitwise not requires integer operand");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->resolved_lang_tid = operand_tid;
|
|
return operand_tid;
|
|
case SPL_UNARY_OP_ADDRESS: {
|
|
spl_lang_type_id_t ptr_tid = spl_lang_make_ptr(sema->type, operand_tid);
|
|
n->resolved_lang_tid = ptr_tid;
|
|
return ptr_tid;
|
|
}
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SPL_AST_EXPR_BINARY: {
|
|
spl_lang_type_id_t lt = sema_parse(sema, n->binary.left);
|
|
spl_lang_type_id_t rt = sema_parse(sema, n->binary.right);
|
|
spl_binary_op_t op = n->binary.op;
|
|
|
|
switch (op) {
|
|
case SPL_OP_ASSIGN: {
|
|
spl_ast_node_t *rhs = spl_ast_node(sema->ast, n->binary.right);
|
|
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, lt, rt);
|
|
if (r == 0) {
|
|
SPL_ERROR(&n->dbg, "assignment type mismatch");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
rhs->resolved_lang_tid = r;
|
|
n->resolved_lang_tid = lt;
|
|
return lt;
|
|
}
|
|
|
|
case SPL_OP_ASSIGN_ADD:
|
|
case SPL_OP_ASSIGN_SUB:
|
|
case SPL_OP_ASSIGN_MUL:
|
|
case SPL_OP_ASSIGN_DIV:
|
|
case SPL_OP_ASSIGN_MOD:
|
|
case SPL_OP_ASSIGN_AND:
|
|
case SPL_OP_ASSIGN_OR:
|
|
case SPL_OP_ASSIGN_XOR:
|
|
case SPL_OP_ASSIGN_LSHIFT:
|
|
case SPL_OP_ASSIGN_RSHIFT: {
|
|
spl_lang_type_id_t balanced = spl_lang_type_balance(sema->type, lt, rt);
|
|
if (balanced == 0 || balanced != lt) {
|
|
SPL_ERROR(&n->dbg, "compound assignment type mismatch");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_ast_node_t *rhs = spl_ast_node(sema->ast, n->binary.right);
|
|
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, lt, rt);
|
|
if (r == 0) {
|
|
SPL_ERROR(&n->dbg, "compound assignment right type mismatch");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
rhs->resolved_lang_tid = r;
|
|
n->resolved_lang_tid = lt;
|
|
return lt;
|
|
}
|
|
|
|
case SPL_OP_BOOL_OR:
|
|
case SPL_OP_BOOL_AND: {
|
|
spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt);
|
|
spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt);
|
|
if (!ln || ln->kind != SPL_LANG_TYPE_BOOL || !rn || rn->kind != SPL_LANG_TYPE_BOOL) {
|
|
SPL_ERROR(&n->dbg, "logical operands must be bool");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
|
|
n->resolved_lang_tid = bt;
|
|
return bt;
|
|
}
|
|
|
|
case SPL_OP_BIT_OR:
|
|
case SPL_OP_BIT_XOR:
|
|
case SPL_OP_BIT_AND: {
|
|
spl_lang_type_id_t bal = spl_lang_type_balance(sema->type, lt, rt);
|
|
spl_lang_type_node_t *bn = spl_lang_type_node(sema->type, bal);
|
|
if (!bn || bn->kind != SPL_LANG_TYPE_INT) {
|
|
SPL_ERROR(&n->dbg, "bitwise operands must be integers");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
/* 两边都 coerce 到 bal */
|
|
if (lt != bal) {
|
|
spl_ast_node_t *ln = spl_ast_node(sema->ast, n->binary.left);
|
|
ln->resolved_lang_tid = spl_lang_type_coerce_to(sema->type, bal, lt);
|
|
}
|
|
if (rt != bal) {
|
|
spl_ast_node_t *rn = spl_ast_node(sema->ast, n->binary.right);
|
|
rn->resolved_lang_tid = spl_lang_type_coerce_to(sema->type, bal, rt);
|
|
}
|
|
n->resolved_lang_tid = 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: {
|
|
spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt);
|
|
spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt);
|
|
bool numeric =
|
|
(ln && (ln->kind == SPL_LANG_TYPE_INT || ln->kind == SPL_LANG_TYPE_FLOAT)) &&
|
|
(rn && (rn->kind == SPL_LANG_TYPE_INT || rn->kind == SPL_LANG_TYPE_FLOAT));
|
|
if (!numeric && spl_lang_type_balance(sema->type, lt, rt) == 0) {
|
|
SPL_ERROR(&n->dbg, "comparison operands type mismatch");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_lang_type_id_t bt = spl_lang_make_bool(sema->type);
|
|
n->resolved_lang_tid = bt;
|
|
return bt;
|
|
}
|
|
|
|
case SPL_OP_LSHIFT:
|
|
case SPL_OP_RSHIFT: {
|
|
spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt);
|
|
spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt);
|
|
if (!ln || ln->kind != SPL_LANG_TYPE_INT || !rn || rn->kind != SPL_LANG_TYPE_INT) {
|
|
SPL_ERROR(&n->dbg, "shift operands must be integers");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->resolved_lang_tid = lt;
|
|
return lt;
|
|
}
|
|
|
|
case SPL_OP_ADD:
|
|
case SPL_OP_SUB:
|
|
case SPL_OP_MUL:
|
|
case SPL_OP_DIV:
|
|
case SPL_OP_MOD: {
|
|
spl_lang_type_id_t bal = spl_lang_type_balance(sema->type, lt, rt);
|
|
spl_lang_type_node_t *bn = spl_lang_type_node(sema->type, bal);
|
|
if (!bn || (bn->kind != SPL_LANG_TYPE_INT && bn->kind != SPL_LANG_TYPE_FLOAT)) {
|
|
SPL_ERROR(&n->dbg, "arithmetic operands type mismatch");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
if (lt != bal) {
|
|
spl_ast_node_t *ln = spl_ast_node(sema->ast, n->binary.left);
|
|
ln->resolved_lang_tid = spl_lang_type_coerce_to(sema->type, bal, lt);
|
|
}
|
|
if (rt != bal) {
|
|
spl_ast_node_t *rn = spl_ast_node(sema->ast, n->binary.right);
|
|
rn->resolved_lang_tid = spl_lang_type_coerce_to(sema->type, bal, rt);
|
|
}
|
|
n->resolved_lang_tid = bal;
|
|
return bal;
|
|
}
|
|
|
|
case SPL_OP_RANGE: {
|
|
spl_lang_type_id_t i64 = spl_lang_make_int(sema->type, 64, 1);
|
|
spl_lang_type_id_t range = spl_lang_make_range(sema->type, i64);
|
|
n->resolved_lang_tid = range;
|
|
return range;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SPL_AST_EXPR_CALL: {
|
|
spl_ast_node_t *callee = spl_ast_node(sema->ast, n->call.callee);
|
|
if (callee && callee->kind == SPL_AST_EXPR_IDENT) {
|
|
spl_intrin_t in = spl_intrin_lookup_call(callee->ident.name);
|
|
if (in != SPL_INTRIN_NONE) {
|
|
spl_lang_type_id_t t = sema_intrin_call(sema, n, in, &n->call.args);
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
}
|
|
|
|
spl_lang_type_id_t callee_tid = sema_parse(sema, n->call.callee);
|
|
spl_lang_type_node_t *fn = spl_lang_type_node(sema->type, callee_tid);
|
|
if (!fn || fn->kind != SPL_LANG_TYPE_FN) {
|
|
SPL_ERROR(&n->dbg, "callee is not a function");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
// 检查函数是否可变参数:最后一个参数是否为 VARARGS
|
|
bool has_varargs = false;
|
|
usize fixed_param_count = vec_size(fn->extra.fn.params);
|
|
if (fixed_param_count > 0) {
|
|
spl_lang_type_id_t last_param = vec_at(fn->extra.fn.params, fixed_param_count - 1);
|
|
spl_lang_type_node_t *last_node = spl_lang_type_node(sema->type, last_param);
|
|
if (last_node && last_node->kind == SPL_LANG_TYPE_VARARGS) {
|
|
has_varargs = true;
|
|
fixed_param_count--; // 排除 VARARGS 参数
|
|
}
|
|
}
|
|
|
|
if (has_varargs) {
|
|
if (vec_size(n->call.args) < fixed_param_count) {
|
|
SPL_ERROR(&n->dbg, "too few arguments (expected at least %zu)", fixed_param_count);
|
|
sema->error_count++;
|
|
} else {
|
|
for (usize i = 0; i < fixed_param_count; ++i) {
|
|
spl_ast_node_ref_t arg_ref = vec_at(n->call.args, i);
|
|
spl_ast_node_t *arg_node = spl_ast_node(sema->ast, arg_ref);
|
|
spl_lang_type_id_t arg_tid = sema_parse(sema, arg_ref);
|
|
spl_lang_type_id_t param_tid = vec_at(fn->extra.fn.params, i);
|
|
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, param_tid, arg_tid);
|
|
if (r == 0) {
|
|
SPL_ERROR(&n->dbg, "argument %zu type mismatch", i + 1);
|
|
sema->error_count++;
|
|
} else {
|
|
arg_node->resolved_lang_tid = r;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (vec_size(n->call.args) != vec_size(fn->extra.fn.params)) {
|
|
SPL_ERROR(&n->dbg, "argument count mismatch (expected %zu, got %zu)",
|
|
vec_size(fn->extra.fn.params), vec_size(n->call.args));
|
|
sema->error_count++;
|
|
} else {
|
|
for (usize i = 0; i < vec_size(n->call.args); ++i) {
|
|
spl_ast_node_ref_t arg_ref = vec_at(n->call.args, i);
|
|
spl_ast_node_t *arg_node = spl_ast_node(sema->ast, arg_ref);
|
|
spl_lang_type_id_t arg_tid = sema_parse(sema, arg_ref);
|
|
spl_lang_type_id_t param_tid = vec_at(fn->extra.fn.params, i);
|
|
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, param_tid, arg_tid);
|
|
if (r == 0) {
|
|
SPL_ERROR(&n->dbg, "argument %zu type mismatch", i + 1);
|
|
sema->error_count++;
|
|
} else {
|
|
arg_node->resolved_lang_tid = r;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
spl_lang_type_id_t ret_tid = fn->extra.fn.ret;
|
|
n->resolved_lang_tid = ret_tid;
|
|
return ret_tid;
|
|
}
|
|
|
|
case SPL_AST_EXPR_FIELD: {
|
|
spl_lang_type_id_t obj_tid = sema_parse(sema, n->field.obj);
|
|
spl_lang_type_node_t *obj_node = spl_lang_type_node(sema->type, obj_tid);
|
|
if (!obj_node)
|
|
return 0;
|
|
|
|
spl_intrin_t in = spl_intrin_lookup_field(obj_node->kind, n->field.field);
|
|
if (in != SPL_INTRIN_NONE) {
|
|
spl_lang_type_id_t t = sema_intrin_field(sema, n, in);
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
|
|
// 自动解引用
|
|
spl_lang_type_id_t agg_lang = obj_tid;
|
|
if (obj_node->kind == SPL_LANG_TYPE_PTR) {
|
|
agg_lang = obj_node->extra.elem;
|
|
}
|
|
spl_lang_type_node_t *agg_node = spl_lang_type_node(sema->type, agg_lang);
|
|
if (!agg_node ||
|
|
(agg_node->kind != SPL_LANG_TYPE_STRUCT && agg_node->kind != SPL_LANG_TYPE_UNION)) {
|
|
SPL_ERROR(&n->dbg, "field access on non-aggregate type");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg_lang);
|
|
const spl_type_member_t *member = spl_type_agg_member(sema->type, agg_ir, n->field.field);
|
|
if (!member) {
|
|
SPL_ERROR(&n->dbg, "no field `%s`", n->field.field);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
// 将底层字段类型映射回语言级类型
|
|
spl_lang_type_id_t field_lang = 0;
|
|
for (usize i = 1; i < vec_size(sema->type->lang_table); ++i) {
|
|
spl_lang_type_node_t *ln = &vec_at(sema->type->lang_table, i);
|
|
if (ln->ir_type_id == member->type_id) {
|
|
field_lang = i;
|
|
break;
|
|
}
|
|
}
|
|
if (!field_lang) {
|
|
SPL_ERROR(&n->dbg, "cannot resolve field type for `%s`", n->field.field);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->resolved_lang_tid = field_lang;
|
|
return field_lang;
|
|
}
|
|
|
|
case SPL_AST_EXPR_INDEX: {
|
|
spl_lang_type_id_t obj_tid = sema_parse(sema, n->index.obj);
|
|
spl_lang_type_id_t idx_tid = sema_parse(sema, n->index.index);
|
|
spl_lang_type_node_t *obj_node = spl_lang_type_node(sema->type, obj_tid);
|
|
if (!obj_node)
|
|
return 0;
|
|
|
|
spl_lang_type_id_t elem_lang = 0;
|
|
switch (obj_node->kind) {
|
|
case SPL_LANG_TYPE_ARRAY:
|
|
case SPL_LANG_TYPE_SLICE:
|
|
case SPL_LANG_TYPE_RANGE:
|
|
case SPL_LANG_TYPE_PTR:
|
|
elem_lang = obj_node->extra.elem;
|
|
break;
|
|
case SPL_LANG_TYPE_TUPLE:
|
|
if (vec_size(obj_node->extra.elems) > 0)
|
|
elem_lang = vec_at(obj_node->extra.elems, 0);
|
|
else {
|
|
SPL_ERROR(&n->dbg, "empty tuple");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
break;
|
|
default:
|
|
SPL_ERROR(&n->dbg, "index base must be array, pointer, slice, or tuple");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
(void)idx_tid;
|
|
n->resolved_lang_tid = elem_lang;
|
|
return elem_lang;
|
|
}
|
|
|
|
case SPL_AST_EXPR_SLICE: {
|
|
spl_lang_type_id_t obj_tid = sema_parse(sema, n->slice.obj);
|
|
if (n->slice.begin)
|
|
sema_parse(sema, n->slice.begin);
|
|
if (n->slice.end)
|
|
sema_parse(sema, n->slice.end);
|
|
|
|
spl_lang_type_node_t *obj_node = spl_lang_type_node(sema->type, obj_tid);
|
|
if (!obj_node)
|
|
return 0;
|
|
|
|
spl_lang_type_id_t elem_lang = 0;
|
|
if (obj_node->kind == SPL_LANG_TYPE_ARRAY || obj_node->kind == SPL_LANG_TYPE_PTR ||
|
|
obj_node->kind == SPL_LANG_TYPE_SLICE) {
|
|
elem_lang = obj_node->extra.elem;
|
|
} else {
|
|
SPL_ERROR(&n->dbg, "slice base must be array, pointer, or slice");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
spl_lang_type_id_t slice_tid = spl_lang_make_slice(sema->type, elem_lang);
|
|
n->resolved_lang_tid = slice_tid;
|
|
return slice_tid;
|
|
}
|
|
|
|
case SPL_AST_EXPR_CAST: {
|
|
spl_lang_type_id_t src_tid = sema_parse(sema, n->cast.expr);
|
|
spl_lang_type_id_t dst_tid = sema_parse(sema, n->cast.type);
|
|
spl_lang_type_node_t *src_node = spl_lang_type_node(sema->type, src_tid);
|
|
if (!src_node)
|
|
return 0;
|
|
if (src_node->kind != SPL_LANG_TYPE_INT && src_node->kind != SPL_LANG_TYPE_FLOAT &&
|
|
src_node->kind != SPL_LANG_TYPE_BOOL) {
|
|
SPL_ERROR(&n->dbg, "invalid cast from non-primitive type");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
n->resolved_lang_tid = dst_tid;
|
|
return dst_tid;
|
|
}
|
|
|
|
case SPL_AST_EXPR_TUPLE: {
|
|
spl_lang_type_id_vec_t elems;
|
|
vec_init(elems);
|
|
for (usize i = 0; i < vec_size(n->tuple.elems); ++i) {
|
|
vec_push(elems, sema_parse(sema, vec_at(n->tuple.elems, i)));
|
|
}
|
|
spl_lang_type_id_t tuple =
|
|
spl_lang_make_tuple(sema->type, vec_unsafe_get_data(elems), vec_size(elems));
|
|
vec_free(elems);
|
|
n->resolved_lang_tid = tuple;
|
|
return tuple;
|
|
}
|
|
|
|
case SPL_AST_EXPR_ARRAY_LIT: {
|
|
/* elem_type 可空:匿名 .[...] 时从元素推导 */
|
|
spl_lang_type_id_t elem_tid = 0;
|
|
if (n->array_literal.elem_type) {
|
|
elem_tid = sema_parse(sema, n->array_literal.elem_type);
|
|
}
|
|
|
|
for (usize i = 0; i < vec_size(n->array_literal.elems); ++i) {
|
|
spl_ast_node_ref_t elem_ref = vec_at(n->array_literal.elems, i);
|
|
spl_ast_node_t *elem_node = spl_ast_node(sema->ast, elem_ref);
|
|
spl_lang_type_id_t et = sema_parse(sema, elem_ref);
|
|
if (elem_tid == 0) {
|
|
elem_tid = et;
|
|
} else {
|
|
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, elem_tid, et);
|
|
if (r == 0) {
|
|
SPL_ERROR(&n->dbg, "array element type mismatch");
|
|
sema->error_count++;
|
|
} else {
|
|
elem_node->resolved_lang_tid = r;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (elem_tid == 0) {
|
|
SPL_ERROR(&n->dbg, "cannot infer array element type "
|
|
"(empty literal without element type annotation)");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
usize len;
|
|
if (n->array_literal.is_underscore_len) {
|
|
len = vec_size(n->array_literal.elems);
|
|
} else if (n->array_literal.has_len) {
|
|
len = (usize)n->array_literal.len;
|
|
if (len != vec_size(n->array_literal.elems)) {
|
|
SPL_ERROR(&n->dbg, "array literal length mismatch: declared %zu, got %zu", len,
|
|
vec_size(n->array_literal.elems));
|
|
sema->error_count++;
|
|
}
|
|
} else {
|
|
len = vec_size(n->array_literal.elems);
|
|
}
|
|
|
|
spl_lang_type_id_t arr_tid = spl_lang_make_array(sema->type, elem_tid, len);
|
|
n->resolved_lang_tid = arr_tid;
|
|
return arr_tid;
|
|
}
|
|
case SPL_AST_EXPR_AGGREGATE_LIT: {
|
|
const char *type_name = n->aggregate_literal.name;
|
|
|
|
/* 匿名 .{...}:需要类型上下文。
|
|
SEMA 当前为自底向上,尚无"预期类型"传播机制;
|
|
待上层注解散布到 init_expr 之前时启用。
|
|
结构上已统一,只需在这里读取 n->resolved_type_id 即可。 */
|
|
if (!type_name) {
|
|
SPL_ERROR(&n->dbg, "anonymous aggregate literal requires expected type context "
|
|
"(not yet supported)");
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
spl_symbol_t sym;
|
|
if (!spl_scope_find(sema->scope, type_name, &sym)) {
|
|
SPL_ERROR(&n->dbg, "unknown type `%s`", type_name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_def_node_t *def = spl_def_node(sema->type, sym.node);
|
|
if (!def || !def->lang_id) {
|
|
SPL_ERROR(&n->dbg, "type `%s` not resolved", type_name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_lang_type_id_t agg_lang = def->lang_id;
|
|
spl_lang_type_node_t *agg_node = spl_lang_type_node(sema->type, agg_lang);
|
|
if (!agg_node ||
|
|
(agg_node->kind != SPL_LANG_TYPE_STRUCT && agg_node->kind != SPL_LANG_TYPE_UNION)) {
|
|
SPL_ERROR(&n->dbg, "`%s` is not a struct/union", type_name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
|
|
spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg_lang);
|
|
spl_type_node_t *agg_ir_node = spl_type_node(sema->type, agg_ir);
|
|
if (!agg_ir_node) {
|
|
SPL_ERROR(&n->dbg, "aggregate IR type `%s` not found", type_name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
usize total_fields = vec_size(agg_ir_node->agg_type.variants);
|
|
|
|
/* 记录每个字段是否被初始化,最后检查缺省 */
|
|
bool *seen = calloc(total_fields, sizeof(bool));
|
|
if (!seen) {
|
|
SPL_ERROR(&n->dbg, "out of memory");
|
|
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;
|
|
usize field_idx = 0;
|
|
if (!spl_type_agg_member_idx(sema->type, agg_ir, fname, &field_idx)) {
|
|
SPL_ERROR(&item->dbg, "no field `%s` in `%s`", fname, type_name);
|
|
sema->error_count++;
|
|
continue;
|
|
}
|
|
if (seen[field_idx]) {
|
|
SPL_ERROR(&item->dbg, "duplicate field `%s` in `%s`", fname, type_name);
|
|
sema->error_count++;
|
|
continue;
|
|
}
|
|
seen[field_idx] = true;
|
|
|
|
const spl_type_member_t *member = &vec_at(agg_ir_node->agg_type.variants, field_idx);
|
|
|
|
/* 通过字段的 ir 类型反查 lang 类型 */
|
|
spl_lang_type_id_t expected_lang = 0;
|
|
for (usize j = 1; j < vec_size(sema->type->lang_table); ++j) {
|
|
spl_lang_type_node_t *ln = &vec_at(sema->type->lang_table, j);
|
|
if (ln->ir_type_id == member->type_id) {
|
|
expected_lang = j;
|
|
break;
|
|
}
|
|
}
|
|
if (!expected_lang) {
|
|
SPL_ERROR(&item->dbg, "cannot resolve lang type for field `%s`", fname);
|
|
sema->error_count++;
|
|
continue;
|
|
}
|
|
|
|
if (!item->struct_init_item.expr) {
|
|
SPL_ERROR(&item->dbg, "field `%s` requires an initializer", fname);
|
|
sema->error_count++;
|
|
continue;
|
|
}
|
|
|
|
spl_ast_node_t *fv = spl_ast_node(sema->ast, item->struct_init_item.expr);
|
|
spl_lang_type_id_t field_lang = sema_parse(sema, item->struct_init_item.expr);
|
|
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, expected_lang, field_lang);
|
|
if (r == 0) {
|
|
SPL_ERROR(&item->dbg, "field `%s` type mismatch", fname);
|
|
sema->error_count++;
|
|
} else {
|
|
fv->resolved_lang_tid = r;
|
|
}
|
|
}
|
|
|
|
/* 检查缺省字段 */
|
|
for (usize i = 0; i < total_fields; ++i) {
|
|
if (!seen[i]) {
|
|
const spl_type_member_t *m = &vec_at(agg_ir_node->agg_type.variants, i);
|
|
SPL_ERROR(&n->dbg, "missing field `%s` in `%s`", m->name, type_name);
|
|
sema->error_count++;
|
|
}
|
|
}
|
|
free(seen);
|
|
|
|
n->resolved_lang_tid = agg_lang;
|
|
return agg_lang;
|
|
}
|
|
|
|
case SPL_AST_EXPR_COMPTIME_CALL: {
|
|
spl_intrin_t in = spl_intrin_lookup_call(n->comptime_call.name);
|
|
if (in == SPL_INTRIN_NONE) {
|
|
SPL_ERROR(&n->dbg, "unknown comptime call `@%s`", n->comptime_call.name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_lang_type_id_t t = sema_intrin_call(sema, n, in, &n->comptime_call.args);
|
|
n->resolved_lang_tid = t;
|
|
return t;
|
|
}
|
|
|
|
case SPL_AST_EXPR_BLOCK: {
|
|
for (usize i = 0; i < vec_size(n->block.stmts); ++i) {
|
|
sema_parse(sema, vec_at(n->block.stmts, i));
|
|
}
|
|
if (n->block.tail_expr) {
|
|
return sema_parse(sema, n->block.tail_expr);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case SPL_AST_EXPR_IF: {
|
|
spl_lang_type_id_t cond_tid = sema_parse(sema, n->if_expr.cond);
|
|
spl_lang_type_id_t bool_tid = spl_lang_make_bool(sema->type);
|
|
if (spl_lang_type_coerce_to(sema->type, bool_tid, cond_tid) == 0) {
|
|
SPL_ERROR(&n->dbg, "if condition must be bool");
|
|
sema->error_count++;
|
|
}
|
|
|
|
spl_lang_type_id_t then_t =
|
|
n->if_expr.then_block ? sema_parse(sema, n->if_expr.then_block) : 0;
|
|
spl_lang_type_id_t else_t =
|
|
n->if_expr.else_branch ? sema_parse(sema, n->if_expr.else_branch) : 0;
|
|
|
|
spl_lang_type_id_t result_t = 0;
|
|
if (then_t && else_t) {
|
|
result_t = spl_lang_type_balance(sema->type, then_t, else_t);
|
|
if (result_t == 0) {
|
|
SPL_ERROR(&n->dbg, "if branches type mismatch");
|
|
sema->error_count++;
|
|
} else {
|
|
if (then_t != result_t) {
|
|
spl_ast_node_t *tn = spl_ast_node(sema->ast, n->if_expr.then_block);
|
|
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, result_t, then_t);
|
|
if (r)
|
|
tn->resolved_lang_tid = r;
|
|
}
|
|
if (else_t != result_t) {
|
|
spl_ast_node_t *en = spl_ast_node(sema->ast, n->if_expr.else_branch);
|
|
spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, result_t, else_t);
|
|
if (r)
|
|
en->resolved_lang_tid = r;
|
|
}
|
|
}
|
|
} else {
|
|
result_t = then_t ? then_t : else_t;
|
|
}
|
|
|
|
n->resolved_lang_tid = result_t;
|
|
return result_t;
|
|
}
|
|
|
|
case SPL_AST_EXPR_IFVAR: {
|
|
sema_parse(sema, n->ifvar_expr.var_decl);
|
|
sema_parse(sema, n->ifvar_expr.then_block);
|
|
if (n->ifvar_expr.else_branch) {
|
|
sema_parse(sema, n->ifvar_expr.else_branch);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case SPL_AST_EXPR_WHILE: {
|
|
spl_lang_type_id_t cond_tid = sema_parse(sema, n->while_expr.cond);
|
|
spl_lang_type_id_t bool_tid = spl_lang_make_bool(sema->type);
|
|
if (spl_lang_type_coerce_to(sema->type, bool_tid, cond_tid) == 0) {
|
|
SPL_ERROR(&n->dbg, "while condition must be bool");
|
|
sema->error_count++;
|
|
}
|
|
sema_parse(sema, n->while_expr.body);
|
|
if (n->while_expr.else_branch) {
|
|
sema_parse(sema, n->while_expr.else_branch);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case SPL_AST_EXPR_LOOP: {
|
|
sema_parse(sema, n->loop_expr.body);
|
|
return 0;
|
|
}
|
|
|
|
case SPL_AST_EXPR_FOR: {
|
|
sema_push_scope(sema);
|
|
for (usize i = 0; i < vec_size(n->for_expr.iter_exprs); ++i) {
|
|
spl_lang_type_id_t container_tid = sema_parse(sema, vec_at(n->for_expr.iter_exprs, i));
|
|
spl_lang_type_id_t elem_tid = sema_for_elem_type(sema, container_tid);
|
|
if (i < vec_size(n->for_expr.idents)) {
|
|
spl_ast_node_t *id_node = spl_ast_node(sema->ast, vec_at(n->for_expr.idents, i));
|
|
if (id_node && id_node->kind == SPL_AST_EXPR_IDENT) {
|
|
const char *var_name = id_node->ident.name;
|
|
if (strcmp(var_name, "_") != 0) {
|
|
spl_symbol_t sym = {.name = var_name, .kind = SPL_SYMBOL_KIND_VAR};
|
|
sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, var_name, id_node->dbg,
|
|
vec_at(n->for_expr.idents, i));
|
|
spl_def_resolve(sema->type, sym.node, elem_tid);
|
|
spl_scope_insert(sema->scope, sema->scope->current_scope, sym);
|
|
id_node->resolved_def_id = sym.node;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sema_parse(sema, n->for_expr.body);
|
|
if (n->for_expr.else_branch) {
|
|
sema_parse(sema, n->for_expr.else_branch);
|
|
}
|
|
sema_pop_scope(sema);
|
|
return 0;
|
|
}
|
|
|
|
case SPL_AST_EXPR_MATCH: {
|
|
sema_parse(sema, n->match_expr.matched_expr);
|
|
for (usize i = 0; i < vec_size(n->match_expr.arms); ++i) {
|
|
spl_ast_node_t *arm = spl_ast_node(sema->ast, vec_at(n->match_expr.arms, i));
|
|
if (arm && arm->kind == SPL_AST_MATCH_ARM) {
|
|
sema_parse(sema, arm->match_arm.pattern);
|
|
sema_parse(sema, arm->match_arm.body);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
case SPL_AST_EXPR_FN_TYPE: {
|
|
spl_lang_type_id_vec_t params;
|
|
vec_init(params);
|
|
for (usize i = 0; i < vec_size(n->fn_type.params); ++i) {
|
|
vec_push(params, sema_parse(sema, vec_at(n->fn_type.params, i)));
|
|
}
|
|
spl_lang_type_id_t ret_tid = sema_parse(sema, n->fn_type.ret_type);
|
|
spl_lang_type_id_t fn_tid =
|
|
spl_lang_make_fn(sema->type, ret_tid, vec_unsafe_get_data(params), vec_size(params));
|
|
vec_free(params);
|
|
n->resolved_lang_tid = fn_tid;
|
|
return fn_tid;
|
|
}
|
|
|
|
case SPL_AST_TYPE_PATH: {
|
|
const char *name = n->type_path.name;
|
|
|
|
spl_lang_type_id_t builtin = spl_type_lookup_builtin(sema->type, name);
|
|
if (builtin != 0) {
|
|
n->resolved_lang_tid = builtin;
|
|
return builtin;
|
|
}
|
|
|
|
spl_symbol_t sym;
|
|
if (!spl_scope_find(sema->scope, name, &sym)) {
|
|
SPL_ERROR(&n->dbg, "type `%s` not found", name);
|
|
sema->error_count++;
|
|
return 0;
|
|
}
|
|
spl_def_node_t *def = spl_def_node(sema->type, sym.node);
|
|
if (!def || !def->lang_id)
|
|
return 0;
|
|
n->resolved_lang_tid = def->lang_id;
|
|
return def->lang_id;
|
|
}
|
|
|
|
case SPL_AST_TYPE_POINTER: {
|
|
spl_lang_type_id_t pointee_tid = sema_parse(sema, n->type_pointer.pointee);
|
|
spl_lang_type_id_t ptr_tid = spl_lang_make_ptr(sema->type, pointee_tid);
|
|
n->resolved_lang_tid = ptr_tid;
|
|
return ptr_tid;
|
|
}
|
|
|
|
case SPL_AST_TYPE_ARRAY: {
|
|
spl_lang_type_id_t elem_tid = sema_parse(sema, n->type_array.elem_type);
|
|
usize len = n->type_array.has_len ? (usize)n->type_array.len : 0;
|
|
spl_lang_type_id_t arr_tid = spl_lang_make_array(sema->type, elem_tid, len);
|
|
n->resolved_lang_tid = arr_tid;
|
|
return arr_tid;
|
|
}
|
|
|
|
case SPL_AST_TYPE_SLICE: {
|
|
spl_lang_type_id_t elem_tid = sema_parse(sema, n->type_slice.elem_type);
|
|
spl_lang_type_id_t slice_tid = spl_lang_make_slice(sema->type, elem_tid);
|
|
n->resolved_lang_tid = slice_tid;
|
|
return slice_tid;
|
|
}
|
|
|
|
case SPL_AST_TYPE_FN: {
|
|
spl_lang_type_id_vec_t params;
|
|
vec_init(params);
|
|
for (usize i = 0; i < vec_size(n->type_fn.params); ++i) {
|
|
vec_push(params, sema_parse(sema, vec_at(n->type_fn.params, i)));
|
|
}
|
|
spl_lang_type_id_t ret_tid = sema_parse(sema, n->type_fn.ret_type);
|
|
spl_lang_type_id_t fn_tid =
|
|
spl_lang_make_fn(sema->type, ret_tid, vec_unsafe_get_data(params), vec_size(params));
|
|
vec_free(params);
|
|
n->resolved_lang_tid = fn_tid;
|
|
return fn_tid;
|
|
}
|
|
|
|
case SPL_AST_TYPE_PAREN: {
|
|
usize count = vec_size(n->type_paren.types);
|
|
if (count == 0) {
|
|
spl_lang_type_id_t unit = spl_lang_make_unit(sema->type);
|
|
n->resolved_lang_tid = unit;
|
|
return unit;
|
|
}
|
|
if (count == 1) {
|
|
return sema_parse(sema, vec_at(n->type_paren.types, 0));
|
|
}
|
|
|
|
spl_lang_type_id_vec_t elems;
|
|
vec_init(elems);
|
|
for (usize i = 0; i < count; ++i) {
|
|
vec_push(elems, sema_parse(sema, vec_at(n->type_paren.types, i)));
|
|
}
|
|
spl_lang_type_id_t tuple =
|
|
spl_lang_make_tuple(sema->type, vec_unsafe_get_data(elems), vec_size(elems));
|
|
vec_free(elems);
|
|
n->resolved_lang_tid = tuple;
|
|
return tuple;
|
|
}
|
|
|
|
case SPL_AST_TYPE_AGGREGATE: {
|
|
return 0;
|
|
}
|
|
|
|
case SPL_AST_TYPE_COMPTIME_CALL:
|
|
return 0;
|
|
|
|
case SPL_AST_STATEMENT_RET: {
|
|
if (n->statement_ret.expr) {
|
|
spl_ast_node_t *en = spl_ast_node(sema->ast, n->statement_ret.expr);
|
|
spl_lang_type_id_t ret_tid = sema_parse(sema, n->statement_ret.expr);
|
|
if (sema->current_fn_ret_tid != 0) {
|
|
spl_lang_type_id_t r =
|
|
spl_lang_type_coerce_to(sema->type, sema->current_fn_ret_tid, ret_tid);
|
|
if (r == 0) {
|
|
SPL_ERROR(&n->dbg, "return type mismatch");
|
|
sema->error_count++;
|
|
} else {
|
|
en->resolved_lang_tid = r;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
case SPL_AST_STATEMENT_BREAK:
|
|
case SPL_AST_STATEMENT_CONTINUE:
|
|
return 0;
|
|
|
|
case SPL_AST_STATEMENT_DEFER:
|
|
if (n->statement_defer.body) {
|
|
sema_parse(sema, n->statement_defer.body);
|
|
}
|
|
return 0;
|
|
|
|
case SPL_AST_STATEMENT_COMPTIME:
|
|
if (n->statement_comptime.body) {
|
|
sema_parse(sema, n->statement_comptime.body);
|
|
}
|
|
return 0;
|
|
|
|
case SPL_AST_STATEMENT_DECL:
|
|
if (n->statement_decl.decl) {
|
|
sema_parse(sema, n->statement_decl.decl);
|
|
}
|
|
return 0;
|
|
|
|
case SPL_AST_STATEMENT_EXPR:
|
|
if (n->statement_expr.expr) {
|
|
sema_parse(sema, n->statement_expr.expr);
|
|
}
|
|
return 0;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope) {
|
|
sema->ast = ast;
|
|
sema->type = type;
|
|
sema->scope = scope;
|
|
sema->error_count = 0;
|
|
sema->current_fn_ret_tid = 0;
|
|
sema->root = (spl_symbol_t){0};
|
|
sema->store_scope = 0;
|
|
}
|
|
|
|
void spl_sema_drop(spl_sema_t *sema) { (void)sema; }
|
|
|
|
void spl_sema_run_module(spl_sema_t *sema, spl_ast_node_ref_t module_ref) {
|
|
if (!sema->ast || !module_ref)
|
|
return;
|
|
spl_ast_node_t *mod = spl_ast_node(sema->ast, module_ref);
|
|
if (!mod || mod->kind != SPL_AST_CONTAINER_MEMBERS)
|
|
return;
|
|
spl_scope_id_t saved = sema->scope->current_scope;
|
|
sema_collect(sema, module_ref);
|
|
sema_infer(sema, module_ref); /* 原 sema_parse */
|
|
sema->scope->current_scope = saved;
|
|
}
|
|
|
|
void spl_sema_run(spl_sema_t *sema) {
|
|
if (!sema->ast || !sema->ast->root)
|
|
return;
|
|
|
|
spl_ast_node_t *root = spl_ast_node(sema->ast, sema->ast->root);
|
|
if (!root || root->kind != SPL_AST_ROOT)
|
|
return;
|
|
|
|
spl_sema_run_module(sema, root->root.members);
|
|
}
|
|
|
|
void spl_sema_dump(spl_sema_t *sema) {
|
|
printf("Scopes:\n");
|
|
for (usize i = 1; i < vec_size(sema->scope->scopes); ++i) {
|
|
spl_scope_node_t *scope = &vec_at(sema->scope->scopes, i);
|
|
printf("scope[%zu] parent=%zu\n", i, scope->parent);
|
|
map_for(scope->symbols, j) {
|
|
spl_symbol_t *symbol = &unsafe_map_at(scope->symbols, j).val;
|
|
printf(" %s -> def`%s`#%zu\n", unsafe_map_at(scope->symbols, j).key, symbol->name,
|
|
symbol->node);
|
|
}
|
|
}
|
|
printf("LangTypeTable:\n");
|
|
for (usize i = 1; i < vec_size(sema->type->lang_table); ++i) {
|
|
printf(" lang_id#%zu ", i);
|
|
spl_lang_type_dump(sema->type, i);
|
|
printf("\n");
|
|
}
|
|
printf("TypeTable:\n");
|
|
for (usize i = 1; i < vec_size(sema->type->type_table); ++i) {
|
|
printf(" type_id#%zu ", i);
|
|
spl_type_pure_dump(sema->type, i);
|
|
printf("\n");
|
|
}
|
|
printf("DefTable:\n");
|
|
for (usize i = 1; i < vec_size(sema->type->def_table); ++i) {
|
|
printf(" def#%zu ", i);
|
|
spl_type_def_dump(sema->type, i);
|
|
printf("\n");
|
|
}
|
|
}
|