stage1 重新实现ast2ir
This commit is contained in:
1 parent
bcd26d3021
commit
ab6e99c958
10 files changed
+1175
-677
No files matched your search
+225
-163
@@ -62,98 +62,6 @@ static inline void sema_pop_scope(spl_sema_t *sema) {
|
||||
sema->scope->current_scope = sema->store_scope;
|
||||
}
|
||||
|
||||
static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_lang_type_id_t to,
|
||||
spl_lang_type_id_t from) {
|
||||
if (to == 0 || from == 0)
|
||||
return 0;
|
||||
|
||||
spl_lang_type_node_t *to_node = spl_lang_type_node(sema->type, to);
|
||||
if (!to_node)
|
||||
return 0;
|
||||
|
||||
if (to_node->kind == SPL_LANG_TYPE_INFER)
|
||||
return from;
|
||||
|
||||
spl_lang_type_node_t *from_node = spl_lang_type_node(sema->type, from);
|
||||
if (!from_node)
|
||||
return 0;
|
||||
|
||||
if (from_node->kind == SPL_LANG_TYPE_INT) {
|
||||
spl_type_id_t from_ir = spl_lang_type_get_ir_type(sema->type, from);
|
||||
spl_type_node_t *from_ir_node = spl_type_node(sema->type, from_ir);
|
||||
if (from_ir_node && from_ir_node->int_type.bits == 0 && to_node->kind == SPL_LANG_TYPE_INT)
|
||||
return to;
|
||||
}
|
||||
if (from_node->kind == SPL_LANG_TYPE_FLOAT) {
|
||||
spl_type_id_t from_ir = spl_lang_type_get_ir_type(sema->type, from);
|
||||
spl_type_node_t *from_ir_node = spl_type_node(sema->type, from_ir);
|
||||
if (from_ir_node && from_ir_node->float_type.bits == 0 &&
|
||||
to_node->kind == SPL_LANG_TYPE_FLOAT)
|
||||
return to;
|
||||
}
|
||||
|
||||
if (to_node->kind == SPL_LANG_TYPE_ARRAY && from_node->kind == SPL_LANG_TYPE_ARRAY) {
|
||||
spl_lang_type_id_t to_elem = to_node->extra.elem;
|
||||
spl_lang_type_id_t from_elem = from_node->extra.elem;
|
||||
if (sema_coerce(sema, to_elem, from_elem) != 0)
|
||||
return to;
|
||||
}
|
||||
|
||||
if (spl_lang_type_is_subtype(sema->type, from, to))
|
||||
return to;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static spl_lang_type_id_t sema_coerce_balance(spl_sema_t *sema, spl_lang_type_id_t t1,
|
||||
spl_lang_type_id_t t2) {
|
||||
if (t1 == 0 || t2 == 0)
|
||||
return 0;
|
||||
if (t1 == t2)
|
||||
return t1;
|
||||
|
||||
spl_lang_type_node_t *n1 = spl_lang_type_node(sema->type, t1);
|
||||
spl_lang_type_node_t *n2 = spl_lang_type_node(sema->type, t2);
|
||||
if (!n1 || !n2)
|
||||
return 0;
|
||||
|
||||
if (n1->kind == SPL_LANG_TYPE_ANY || n2->kind == SPL_LANG_TYPE_ANY)
|
||||
return spl_lang_make_any(sema->type);
|
||||
if (n1->kind == SPL_LANG_TYPE_NEVER)
|
||||
return t2;
|
||||
if (n2->kind == SPL_LANG_TYPE_NEVER)
|
||||
return t1;
|
||||
|
||||
if (spl_lang_type_is_subtype(sema->type, t1, t2))
|
||||
return t2;
|
||||
if (spl_lang_type_is_subtype(sema->type, t2, t1))
|
||||
return t1;
|
||||
|
||||
if (n1->kind == SPL_LANG_TYPE_INT && n2->kind == SPL_LANG_TYPE_INT) {
|
||||
// 如果一个是另一个的子类型,直接返回父类型(已在前面通用检查中处理)
|
||||
// 否则符号不同且无法安全提升,返回 0
|
||||
return 0;
|
||||
}
|
||||
if (n1->kind == SPL_LANG_TYPE_FLOAT && n2->kind == SPL_LANG_TYPE_FLOAT) {
|
||||
spl_type_id_t ir1 = spl_lang_type_get_ir_type(sema->type, t1);
|
||||
spl_type_id_t ir2 = spl_lang_type_get_ir_type(sema->type, t2);
|
||||
spl_type_node_t *irn1 = spl_type_node(sema->type, ir1);
|
||||
spl_type_node_t *irn2 = spl_type_node(sema->type, ir2);
|
||||
if (irn1 && irn2) {
|
||||
usize bits = irn1->float_type.bits > irn2->float_type.bits ? irn1->float_type.bits
|
||||
: irn2->float_type.bits;
|
||||
return spl_lang_make_float(sema->type, bits);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool sema_coerce_for_bool(spl_sema_t *sema, spl_lang_type_id_t from) {
|
||||
spl_lang_type_id_t bool_tid = spl_lang_make_bool(sema->type);
|
||||
return sema_coerce(sema, bool_tid, from) == bool_tid;
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -176,18 +84,29 @@ static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
|
||||
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_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);
|
||||
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: {
|
||||
@@ -417,15 +336,19 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
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);
|
||||
decl_tid = sema_coerce(sema, decl_tid, init_tid);
|
||||
if (decl_tid == 0) {
|
||||
SPL_ERROR(&n->dbg, "cannot infer type for variable `%s`", name);
|
||||
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_type_id = coerce_result;
|
||||
decl_tid = coerce_result;
|
||||
|
||||
spl_def_resolve(sema->type, n->resolved_def_id, decl_tid);
|
||||
n->resolved_type_id = decl_tid; // 存储 lang_id
|
||||
n->resolved_type_id = decl_tid;
|
||||
return decl_tid;
|
||||
}
|
||||
|
||||
@@ -500,6 +423,7 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
}
|
||||
n->resolved_type_id = def->lang_id;
|
||||
return def->lang_id;
|
||||
}
|
||||
|
||||
@@ -556,14 +480,18 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
spl_binary_op_t op = n->binary.op;
|
||||
|
||||
switch (op) {
|
||||
case SPL_OP_ASSIGN:
|
||||
if (sema_coerce(sema, lt, rt) == 0) {
|
||||
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_type_id = r;
|
||||
n->resolved_type_id = lt;
|
||||
return lt;
|
||||
}
|
||||
|
||||
case SPL_OP_ASSIGN_ADD:
|
||||
case SPL_OP_ASSIGN_SUB:
|
||||
@@ -575,12 +503,20 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
case SPL_OP_ASSIGN_XOR:
|
||||
case SPL_OP_ASSIGN_LSHIFT:
|
||||
case SPL_OP_ASSIGN_RSHIFT: {
|
||||
spl_lang_type_id_t balanced = sema_coerce_balance(sema, lt, rt);
|
||||
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_type_id = r;
|
||||
n->resolved_type_id = lt;
|
||||
return lt;
|
||||
}
|
||||
@@ -602,13 +538,22 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
case SPL_OP_BIT_OR:
|
||||
case SPL_OP_BIT_XOR:
|
||||
case SPL_OP_BIT_AND: {
|
||||
spl_lang_type_id_t bal = sema_coerce_balance(sema, lt, rt);
|
||||
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_type_id = 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_type_id = spl_lang_type_coerce_to(sema->type, bal, rt);
|
||||
}
|
||||
n->resolved_type_id = bal;
|
||||
return bal;
|
||||
}
|
||||
@@ -619,13 +564,12 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
case SPL_OP_CMP_GE:
|
||||
case SPL_OP_CMP_LT:
|
||||
case SPL_OP_CMP_GT: {
|
||||
// FIXME 不一定合理
|
||||
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 && sema_coerce_balance(sema, lt, rt) == 0) {
|
||||
if (!numeric && spl_lang_type_balance(sema->type, lt, rt) == 0) {
|
||||
SPL_ERROR(&n->dbg, "comparison operands type mismatch");
|
||||
sema->error_count++;
|
||||
return 0;
|
||||
@@ -653,13 +597,21 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
case SPL_OP_MUL:
|
||||
case SPL_OP_DIV:
|
||||
case SPL_OP_MOD: {
|
||||
spl_lang_type_id_t bal = sema_coerce_balance(sema, lt, rt);
|
||||
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_type_id = 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_type_id = spl_lang_type_coerce_to(sema->type, bal, rt);
|
||||
}
|
||||
n->resolved_type_id = bal;
|
||||
return bal;
|
||||
}
|
||||
@@ -699,35 +651,41 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
}
|
||||
|
||||
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_lang_type_id_t arg_tid = sema_parse(sema, vec_at(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);
|
||||
if (sema_coerce(sema, param_tid, arg_tid) == 0) {
|
||||
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_type_id = 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_lang_type_id_t arg_tid = sema_parse(sema, vec_at(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);
|
||||
if (sema_coerce(sema, param_tid, arg_tid) == 0) {
|
||||
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_type_id = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -880,56 +838,68 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
}
|
||||
|
||||
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_lang_type_id_t et = sema_parse(sema, vec_at(n->array_literal.elems, i));
|
||||
if (elem_tid == 0)
|
||||
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 if (sema_coerce(sema, elem_tid, et) == 0) {
|
||||
SPL_ERROR(&n->dbg, "array element type mismatch");
|
||||
sema->error_count++;
|
||||
} 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_type_id = 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 {
|
||||
len =
|
||||
n->array_literal.has_len ? n->array_literal.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_type_id = arr_tid;
|
||||
return arr_tid;
|
||||
}
|
||||
|
||||
case SPL_AST_EXPR_ANON_ARRAY_LIT: {
|
||||
spl_lang_type_id_t elem_tid = 0;
|
||||
for (usize i = 0; i < vec_size(n->anon_array_literal.elems); ++i) {
|
||||
spl_lang_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");
|
||||
} 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);
|
||||
}
|
||||
usize len = vec_size(n->anon_array_literal.elems);
|
||||
|
||||
spl_lang_type_id_t arr_tid = spl_lang_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;
|
||||
|
||||
/* 匿名 .{...}:需要类型上下文。
|
||||
SEMA 当前为自底向上,尚无"预期类型"传播机制;
|
||||
待上层注解散布到 init_expr 之前时启用。
|
||||
结构上已统一,只需在这里读取 n->resolved_type_id 即可。 */
|
||||
if (!type_name) {
|
||||
SPL_ERROR(&n->dbg, "anonymous aggregate literal not supported yet");
|
||||
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);
|
||||
@@ -952,23 +922,44 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
}
|
||||
|
||||
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;
|
||||
spl_lang_type_id_t field_lang = 0;
|
||||
if (item->struct_init_item.expr) {
|
||||
field_lang = sema_parse(sema, item->struct_init_item.expr);
|
||||
}
|
||||
const spl_type_member_t *member = spl_type_agg_member(sema->type, agg_ir, fname);
|
||||
if (!member) {
|
||||
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);
|
||||
@@ -978,15 +969,37 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
}
|
||||
}
|
||||
if (!expected_lang) {
|
||||
SPL_ERROR(&item->dbg, "cannot resolve field type for `%s`", fname);
|
||||
SPL_ERROR(&item->dbg, "cannot resolve lang type for field `%s`", fname);
|
||||
sema->error_count++;
|
||||
continue;
|
||||
}
|
||||
if (sema_coerce(sema, expected_lang, field_lang) == 0) {
|
||||
|
||||
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_type_id = 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_type_id = agg_lang;
|
||||
return agg_lang;
|
||||
@@ -1007,15 +1020,43 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
|
||||
case SPL_AST_EXPR_IF: {
|
||||
spl_lang_type_id_t cond_tid = sema_parse(sema, n->if_expr.cond);
|
||||
if (!sema_coerce_for_bool(sema, cond_tid)) {
|
||||
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++;
|
||||
}
|
||||
sema_parse(sema, n->if_expr.then_block);
|
||||
if (n->if_expr.else_branch) {
|
||||
sema_parse(sema, n->if_expr.else_branch);
|
||||
|
||||
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_type_id = 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_type_id = r;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result_t = then_t ? then_t : else_t;
|
||||
}
|
||||
return 0;
|
||||
|
||||
n->resolved_type_id = result_t;
|
||||
return result_t;
|
||||
}
|
||||
|
||||
case SPL_AST_EXPR_IFVAR: {
|
||||
@@ -1029,7 +1070,8 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
|
||||
case SPL_AST_EXPR_WHILE: {
|
||||
spl_lang_type_id_t cond_tid = sema_parse(sema, n->while_expr.cond);
|
||||
if (!sema_coerce_for_bool(sema, cond_tid)) {
|
||||
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++;
|
||||
}
|
||||
@@ -1189,16 +1231,21 @@ static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
|
||||
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 &&
|
||||
sema_coerce(sema, sema->current_fn_ret_tid, ret_tid) == 0) {
|
||||
SPL_ERROR(&n->dbg, "return type mismatch");
|
||||
sema->error_count++;
|
||||
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_type_id = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case SPL_AST_STATEMENT_BREAK:
|
||||
case SPL_AST_STATEMENT_CONTINUE:
|
||||
return 0;
|
||||
@@ -1245,6 +1292,22 @@ void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope
|
||||
|
||||
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);
|
||||
/* 此时 current_scope == 该 module 的 mod_scope */
|
||||
sema_parse(sema, module_ref);
|
||||
|
||||
sema->scope->current_scope = saved;
|
||||
}
|
||||
|
||||
void spl_sema_run(spl_sema_t *sema) {
|
||||
if (!sema->ast || !sema->ast->root)
|
||||
return;
|
||||
@@ -1253,8 +1316,7 @@ void spl_sema_run(spl_sema_t *sema) {
|
||||
if (!root || root->kind != SPL_AST_ROOT)
|
||||
return;
|
||||
|
||||
sema_collect(sema, root->root.members);
|
||||
sema_parse(sema, root->root.members);
|
||||
spl_sema_run_module(sema, root->root.members);
|
||||
}
|
||||
|
||||
void spl_sema_dump(spl_sema_t *sema) {
|
||||
|
||||
Reference in new issue
Block a user