Files
spl/stage1/spl_sema.c

1143 lines
42 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "spl_sema.h"
void spl_scope_init(spl_scope_t *scope) {
vec_init(scope->scopes);
vec_push(scope->scopes, (spl_scope_node_t){0});
scope->current_scope = 0;
scope->root_scope = 0;
}
void spl_scope_drop(spl_scope_t *scope) {
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;
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_symbol_t old = {0};
spl_scope_node_t *node = &vec_at(scope->scopes, id);
if (map_get(node->symbols, symbol.name, &old)) {
// spl_type_def(sema->type, old); TODO debug node
SPL_ERROR(&(spl_dbg_node_t){0}, "find same 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 == NULL || name == NULL || out == NULL) {
return false;
}
for (spl_scope_id_t id = scope->current_scope; id != 0; id = vec_at(scope->scopes, id).parent) {
spl_scope_node_t *s = &vec_at(scope->scopes, id);
if (map_get(s->symbols, name, out)) {
Assert(out->kind != SPL_SYMBOL_KIND_ERROR);
return true;
}
}
return false;
}
// Parse once
static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) {
Assert(sema != NULL && ref != 0);
spl_ast_node_t *n = spl_ast_node(sema->ast, ref);
spl_symbol_t symbol = {0};
Assert(n != NULL);
switch (n->kind) {
case SPL_AST_CONTAINER_MEMBERS: {
symbol.name = "$file";
symbol.kind = SPL_SYMBOL_KIND_TYPE;
symbol.node = spl_type_def_alloc(sema->type, SPL_DEF_AGG, "$file", n->dbg, ref);
n->resolved_def_id = symbol.node;
spl_scope_id_t scope_id = spl_scope_alloc(sema->scope);
sema->scope->current_scope = scope_id;
sema->scope->root_scope = scope_id;
spl_scope_insert(sema->scope, scope_id, symbol);
vec_for(n->container_members, i) { sema_collect(sema, vec_at(n->container_members, i)); }
break;
}
case SPL_AST_TYPE_DECL: {
symbol.name = n->type_decl.name;
symbol.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_decl must have type_expr");
sema->error_count++;
return;
}
switch (te->kind) {
case SPL_AST_TYPE_STRUCT:
case SPL_AST_TYPE_UNION:
case SPL_AST_TYPE_ENUM:
case SPL_AST_TYPE_SHAPE: /* TODO for shape */
symbol.node = spl_type_def_alloc(sema->type, SPL_DEF_AGG, symbol.name, te->dbg, ref);
n->resolved_def_id = symbol.node;
spl_scope_id_t scope_id = spl_scope_alloc(sema->scope);
spl_scope_id_t old_id = sema->scope->current_scope;
spl_scope_insert(sema->scope, old_id, symbol);
sema->scope->current_scope = scope_id;
vec_for(te->type_expr.aggregate_list, i) {
spl_ast_node_ref_t mref = vec_at(te->type_expr.aggregate_list, i);
sema_collect(sema, mref);
}
sema->scope->current_scope = old_id;
break;
default:
symbol.node = spl_type_def_alloc(sema->type, SPL_DEF_SCALAR, symbol.name, te->dbg, ref);
n->resolved_def_id = symbol.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, symbol);
break;
}
} break;
case SPL_AST_FN_DECL:
case SPL_AST_FN_DEFINE: {
symbol.name = n->fn_decl.name;
symbol.kind = SPL_SYMBOL_KIND_FN;
symbol.node = spl_type_def_alloc(sema->type, SPL_DEF_FN_PARAMS, symbol.name, n->dbg, ref);
n->resolved_def_id = symbol.node;
// TODO same type avaliable insert twice for decl and define but define must only once
spl_scope_insert(sema->scope, sema->scope->current_scope, symbol);
} break;
case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL: {
symbol.name = n->var_const_decl.name;
symbol.kind = SPL_SYMBOL_KIND_VAR;
symbol.node = spl_type_def_alloc(sema->type, SPL_DEF_VAR, symbol.name, n->dbg, ref);
n->resolved_def_id = symbol.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, symbol);
} break;
default:
break;
}
}
// Parse twice
// use for assign_expr as_expr
static spl_type_id_t sema_coerce(spl_sema_t *sema, spl_type_id_t to, spl_type_id_t from) {
// var := from
if (to == 0) {
return from;
}
// error
if (from == 0) {
return 0;
}
// same
if (to == from) {
return to;
}
spl_type_node_t *tn = spl_type_node(sema->type, to);
spl_type_node_t *fn = spl_type_node(sema->type, from);
Assert(tn != NULL && fn != NULL);
switch (fn->kind) {
case SPL_TYPE_UNDEFINED:
return to;
case SPL_TYPE_NULL:
if (tn->kind == SPL_TYPE_PTR || tn->kind == SPL_TYPE_SLICE) {
return to;
}
break;
case SPL_TYPE_INT:
if (tn->kind != SPL_TYPE_INT) {
break;
}
// var = comptime_int
if (tn->int_type.bits > 0 && fn->int_type.bits == 0) {
return to;
}
// not same signed
if (tn->int_type.is_signed != fn->int_type.is_signed) {
break;
}
// var i32 = i32/i16
if (tn->int_type.bits >= fn->int_type.bits) {
return to;
}
break;
case SPL_TYPE_FLOAT:
// TODO
break;
case SPL_TYPE_ARRAY:
// TODO
break;
default:
break;
}
return 0;
}
// use for op_expr
static spl_type_id_t sema_coerce_balance(spl_sema_t *sema, spl_type_id_t t1, spl_type_id_t t2) {
// error
if (t1 == 0 || t2 == 0) {
return 0;
}
// same
if (t1 == t2) {
return t1;
}
spl_type_node_t *n1 = spl_type_node(sema->type, t1);
spl_type_node_t *n2 = spl_type_node(sema->type, t2);
Assert(n1 != NULL && n2 != NULL);
// TODO 应该推导类型
if (n1->kind == SPL_TYPE_UNDEFINED && n1->kind == SPL_TYPE_UNDEFINED) {
return 0;
}
if (n1->kind == SPL_TYPE_UNDEFINED) {
return t2;
}
if (n2->kind == SPL_TYPE_UNDEFINED) {
return t1;
}
if (n1->kind == SPL_TYPE_NULL) {
return (n2->kind == SPL_TYPE_PTR || n2->kind == SPL_TYPE_SLICE) ? t2 : 0;
}
if (n2->kind == SPL_TYPE_NULL) {
return (n1->kind == SPL_TYPE_PTR || n1->kind == SPL_TYPE_SLICE) ? t1 : 0;
}
if (n1->kind != n2->kind) {
return 0;
}
switch (n1->kind) {
case SPL_TYPE_INT:
if (n1->int_type.is_signed != n2->int_type.is_signed) {
return 0;
}
return n1->int_type.bits >= n2->int_type.bits ? t1 : t2;
case SPL_TYPE_FLOAT:
return n1->float_type.bits >= n2->float_type.bits ? t1 : t2;
default:
break;
}
return 0;
}
static bool sema_coerce_for_bool(spl_sema_t *sema, spl_type_id_t from) {
spl_type_id_t bool_tid = spl_type_builder_simple(sema->type, SPL_TYPE_BOOL);
return sema_coerce(sema, bool_tid, from) == bool_tid;
}
// FIXME using lib ops
static spl_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_type_id_t tid) {
spl_type_node_t *n = spl_type_node(sema->type, tid);
if (!n)
return 0;
switch (n->kind) {
case SPL_TYPE_SLICE:
return n->slice_element;
case SPL_TYPE_ARRAY:
return n->array_type.element;
case SPL_TYPE_PTR:
return n->ptr_pointee;
case SPL_TYPE_RANGE:
return n->range_element;
default:
return 0;
}
}
static inline void sema_push_scope(spl_sema_t *sema) {
spl_scope_id_t scope_id = spl_scope_alloc(sema->scope);
sema->store_scope = sema->scope->current_scope;
sema->scope->current_scope = scope_id;
}
static inline void sema_pop_scope(spl_sema_t *sema) {
sema->scope->current_scope = sema->store_scope;
}
static spl_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) {
if (ref == 0) {
return 0;
}
Assert(sema != NULL);
spl_ast_node_t *n = spl_ast_node(sema->ast, ref);
Assert(n != NULL);
switch (n->kind) {
case SPL_AST_NONE:
UNREACHABLE();
break;
case SPL_AST_CONTAINER_MEMBERS: {
vec_for(n->container_members, i) { sema_parse(sema, vec_at(n->container_members, i)); }
} break;
case SPL_AST_FN_DECL: {
if (n->resolved_def_id == 0) {
Panic("fn `%s` don't collect", n->fn_decl.name);
}
/* 前向/extern 声明:只解析签名并构建 fn 类型,不进入 scope */
spl_type_id_vec_t params_type;
vec_init(params_type);
vec_for(n->fn_decl.param_list, i) {
spl_ast_node_ref_t ref = vec_at(n->fn_decl.param_list, i);
spl_ast_node_t *pd = spl_ast_node(sema->ast, ref);
if (pd && pd->kind == SPL_AST_PARAM_DECL && pd->param_decl.type_expr) {
vec_push(params_type, sema_parse(sema, pd->param_decl.type_expr));
} else {
// TODO variadic
}
}
spl_type_id_t ret_id = sema_parse(sema, n->fn_decl.type_expr);
spl_type_id_t fntid = spl_type_builder_fn(
sema->type, ret_id, vec_unsafe_get_data(params_type), vec_size(params_type));
// Move params_type don't need free
spl_type_def_resolve(sema->type, n->resolved_def_id, fntid);
break;
}
case SPL_AST_FN_DEFINE: {
if (n->resolved_def_id == 0) {
Panic("fn `%s` don't collect", n->fn_decl.name);
}
sema_push_scope(sema);
spl_type_id_vec_t params_type;
vec_init(params_type);
vec_for(n->fn_decl.param_list, i) {
spl_ast_node_ref_t ref = vec_at(n->fn_decl.param_list, i);
spl_ast_node_t *node = spl_ast_node(sema->ast, ref);
if (!node || node->kind != SPL_AST_PARAM_DECL || !node->param_decl.type_expr) {
// TODO variadic
continue;
}
spl_type_id_t tid = sema_parse(sema, ref);
Assert(node->kind == SPL_AST_PARAM_DECL);
vec_push(params_type, tid);
if (node->resolved_def_id) {
spl_type_def_resolve(sema->type, node->resolved_def_id, tid);
}
}
spl_type_id_t ret_id = sema_parse(sema, n->fn_decl.type_expr);
spl_type_id_t fntid = spl_type_builder_fn(
sema->type, ret_id, vec_unsafe_get_data(params_type), vec_size(params_type));
// Move params_type don't need free
spl_type_def_resolve(sema->type, n->resolved_def_id, fntid);
spl_type_id_t old_ret = sema->current_fn_ret_tid;
sema->current_fn_ret_tid = ret_id;
vec_for(n->fn_decl.block, i) { sema_parse(sema, vec_at(n->fn_decl.block, i)); }
sema->current_fn_ret_tid = old_ret;
sema_pop_scope(sema);
} break;
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;
}
switch (te->kind) {
case SPL_AST_TYPE_STRUCT:
case SPL_AST_TYPE_UNION:
case SPL_AST_TYPE_ENUM: {
spl_type_member_vec_t members;
vec_init(members);
/* 第一遍:只收字段(MEMBER_DECL)的类型,构建容器类型并 resolve
* 方法(fn)留到类型 resolve 后再处理,否则方法体引用自身类型会拿到未解析的 0 */
vec_for(te->type_expr.aggregate_list, i) {
spl_ast_node_ref_t mref = vec_at(te->type_expr.aggregate_list, i);
spl_ast_node_t *mn = spl_ast_node(sema->ast, mref);
if (!mn || mn->kind != SPL_AST_MEMBER_DECL)
continue;
spl_type_id_t mtid = sema_parse(sema, mref);
spl_type_member_t m = {0};
m.name = mn->member_decl.name;
m.type_id = mtid;
m.ast_node_ref = mref;
vec_push(members, m);
}
spl_type_node_kind_t tk = te->kind == SPL_AST_TYPE_UNION ? SPL_TYPE_UNION
: te->kind == SPL_AST_TYPE_ENUM ? SPL_TYPE_ENUM
: SPL_TYPE_STRUCT;
spl_type_layout_t layout = {.mode = SPL_TYPE_LAYOUT_AUTO, .fixed_align_bits = 0};
// TODO tag type
spl_type_id_t tid = spl_type_builder_agg(
sema->type, tk, vec_unsafe_get_data(members), vec_size(members),
spl_type_builder_int(sema->type, 32, 1), layout);
// Move members don't need free
spl_type_def_resolve(sema->type, n->resolved_def_id, tid);
/* 第二遍:方法 bodystruct 类型已 resolve可引用自身类型 */
vec_for(te->type_expr.aggregate_list, i) {
spl_ast_node_ref_t mref = vec_at(te->type_expr.aggregate_list, i);
spl_ast_node_t *mn = spl_ast_node(sema->ast, mref);
if (mn && mn->kind == SPL_AST_FN_DEFINE)
sema_parse(sema, mref);
}
break;
}
case SPL_AST_TYPE_SHAPE: /* TODO */
vec_for(te->type_expr.aggregate_list, i) {
sema_parse(sema, vec_at(te->type_expr.aggregate_list, i));
}
break;
default: {
spl_type_id_t tid = sema_parse(sema, n->type_decl.type_expr);
spl_type_def_resolve(sema->type, n->resolved_def_id, tid);
break;
}
}
} break;
case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL: {
if (n->resolved_def_id == 0) {
spl_symbol_t symbol = {0};
symbol.name = n->var_const_decl.name;
symbol.kind = SPL_SYMBOL_KIND_VAR;
symbol.node = spl_type_def_alloc(sema->type, SPL_DEF_VAR, symbol.name, n->dbg, ref);
n->resolved_def_id = symbol.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, symbol);
}
spl_type_id_t decl_tid = 0;
if (n->var_const_decl.type_expr) {
decl_tid = sema_parse(sema, n->var_const_decl.type_expr);
}
if (n->var_const_decl.expr == 0) {
SPL_ERROR(&n->dbg, "must be assign");
return 0;
}
spl_type_id_t et = sema_parse(sema, n->var_const_decl.expr);
decl_tid = sema_coerce(sema, decl_tid, et);
if (decl_tid == 0) {
SPL_ERROR(&n->dbg, "decl type must not none %d");
sema->error_count += 1;
}
spl_type_def_resolve(sema->type, n->resolved_def_id, decl_tid);
} break;
case SPL_AST_MEMBER_DECL: {
/* 字段/变体不建 def, 类型由 TYPE_DECL 组装成员时统一构造 */
spl_type_id_t mtid = 0;
if (n->member_decl.type_expr) {
mtid = sema_parse(sema, n->member_decl.type_expr);
}
return mtid;
} break;
case SPL_AST__COMPTIME_STMT:
case SPL_AST__DIRECTIVE_BLOCK:
break;
case SPL_AST_PARAM_DECL: {
if (n->resolved_def_id == 0) {
spl_symbol_t symbol = {0};
symbol.name = n->param_decl.name;
symbol.kind = SPL_SYMBOL_KIND_VAR;
symbol.node = spl_type_def_alloc(sema->type, SPL_DEF_VAR, symbol.name, n->dbg, ref);
n->resolved_def_id = symbol.node;
spl_scope_insert(sema->scope, sema->scope->current_scope, symbol);
}
spl_type_id_t ptid = 0;
if (n->param_decl.type_expr) {
ptid = sema_parse(sema, n->param_decl.type_expr);
}
spl_type_def_resolve(sema->type, n->resolved_def_id, ptid);
return ptid;
} break;
case SPL_AST_ATTR_ITEM:
vec_for(n->attr_item.expr_list, i) { sema_parse(sema, vec_at(n->attr_item.expr_list, i)); }
break;
case SPL_AST_ARGG_INIT_ITEM: {
if (n->aggregate_init_item.expr) {
sema_parse(sema, n->aggregate_init_item.expr);
}
} break;
case SPL_AST_IF_STATEMENT: {
if (!n->if_statement.expr) {
SPL_ERROR(&n->dbg, "if statement not have condition expr");
return 0;
}
spl_type_id_t ct = sema_parse(sema, n->if_statement.expr);
if (!sema_coerce_for_bool(sema, ct)) {
SPL_ERROR(&n->dbg, "if condition must be bool");
sema->error_count++;
}
vec_for(n->if_statement.if_block, i) {
sema_parse(sema, vec_at(n->if_statement.if_block, i));
}
vec_for(n->if_statement.else_block, i) {
sema_parse(sema, vec_at(n->if_statement.else_block, i));
}
} break;
case SPL_AST_IFVAR_STATEMENT: {
if (n->ifvar_statement.packed_expr) {
sema_parse(sema, n->ifvar_statement.packed_expr);
}
vec_for(n->ifvar_statement.if_block, i) {
sema_parse(sema, vec_at(n->ifvar_statement.if_block, i));
}
vec_for(n->ifvar_statement.else_block, i) {
sema_parse(sema, vec_at(n->ifvar_statement.else_block, i));
}
} break;
case SPL_AST_WHILE_STATEMENT: {
if (!n->while_statement.expr) {
SPL_ERROR(&n->dbg, "while statement not have condition expr");
return 0;
}
spl_type_id_t ct = sema_parse(sema, n->while_statement.expr);
if (!sema_coerce_for_bool(sema, ct)) {
SPL_ERROR(&n->dbg, "while condition must be bool");
sema->error_count++;
}
vec_for(n->while_statement.while_block, i) {
sema_parse(sema, vec_at(n->while_statement.while_block, i));
}
} break;
case SPL_AST_LOOP_STATEMENT: {
vec_for(n->loop_statement.loop_block, i) {
sema_parse(sema, vec_at(n->loop_statement.loop_block, i));
}
} break;
case SPL_AST_FOR_STATEMENT: {
sema_push_scope(sema);
vec_for(n->for_statement.expr_vec, i) {
spl_ast_node_ref_t eref = vec_at(n->for_statement.expr_vec, i);
spl_type_id_t stid = sema_parse(sema, eref);
spl_type_id_t etid = sema_for_elem_type(sema, stid);
if (i < vec_size(n->for_statement.ident_vec)) {
const char *vname = vec_at(n->for_statement.ident_vec, i);
spl_symbol_t symbol = {0};
symbol.name = vname;
symbol.kind = SPL_SYMBOL_KIND_VAR;
symbol.node = spl_type_def_alloc(sema->type, SPL_DEF_VAR, vname, n->dbg, eref);
spl_type_def_resolve(sema->type, symbol.node, etid);
spl_scope_insert(sema->scope, sema->scope->current_scope, symbol);
}
}
vec_for(n->for_statement.block, j) { sema_parse(sema, vec_at(n->for_statement.block, j)); }
sema_pop_scope(sema);
} break;
case SPL_AST_MATCH_STATEMENT: {
if (n->match_statement.expr) {
sema_parse(sema, n->match_statement.expr);
}
vec_for(n->match_statement.paced_exprs, i) {
sema_parse(sema, vec_at(n->match_statement.paced_exprs, i));
}
vec_for(n->match_statement.match_block, i) {
sema_parse(sema, vec_at(n->match_statement.match_block, i));
}
} break;
case SPL_AST_RET_STATEMENT: {
if (n->ret_statement.expr) {
spl_type_id_t tid = sema_parse(sema, n->ret_statement.expr);
if (sema_coerce(sema, sema->current_fn_ret_tid, tid) != sema->current_fn_ret_tid) {
SPL_ERROR(&n->dbg, "return type not match");
sema->error_count += 1;
}
n->resolved_type_id = sema->current_fn_ret_tid;
}
} break;
case SPL_AST_BREAK_STATEMENT:
case SPL_AST_CONTINUE_STATEMENT:
case SPL_AST_DEFER_STATEMENT: {
vec_for(n->defer_statement.block_or_statement, i) {
sema_parse(sema, vec_at(n->defer_statement.block_or_statement, i));
}
} break;
case SPL_AST_TRY_STATEMENT:
case SPL_AST_CATCH_STATEMENT:
case SPL_AST_ERRDEFER_STATEMEMT:
case SPL_AST_EXPR_STATEMENT:
break;
case SPL_AST_PACKED_EXPR: {
if (n->packed_expr.expr)
sema_parse(sema, n->packed_expr.expr);
} break;
case SPL_AST_ASSIGN_EXPR: {
spl_type_id_t lt = sema_parse(sema, n->op_expr.left);
if (lt == 0) {
SPL_ERROR(&n->dbg, "assign target has no type");
sema->error_count++;
break;
}
spl_type_id_t rt = sema_parse(sema, n->op_expr.right);
if (sema_coerce(sema, lt, rt) == 0) {
SPL_ERROR(&n->dbg, "assign type mismatch");
sema->error_count++;
break;
}
n->resolved_type_id = lt;
return lt;
}
case SPL_AST_ASSIGN_ADD_EXPR:
case SPL_AST_ASSIGN_SUB_EXPR:
case SPL_AST_ASSIGN_MUL_EXPR:
case SPL_AST_ASSIGN_DIV_EXPR:
case SPL_AST_ASSIGN_MOD_EXPR:
case SPL_AST_ASSIGN_AND_EXPR:
case SPL_AST_ASSIGN_OR_EXPR:
case SPL_AST_ASSIGN_XOR_EXPR:
case SPL_AST_ASSIGN_LSHIFT_EXPR:
case SPL_AST_ASSIGN_USHIFT_EXPR: {
spl_type_id_t lt = sema_parse(sema, n->op_expr.left);
spl_type_id_t rt = sema_parse(sema, n->op_expr.right);
if (lt == 0) {
SPL_ERROR(&n->dbg, "assign target has no type");
sema->error_count++;
break;
}
if (sema_coerce_balance(sema, lt, rt) != lt) {
SPL_ERROR(&n->dbg, "compound assign result would narrow or mismatch lhs type");
sema->error_count++;
break;
}
n->resolved_type_id = lt;
return lt;
}
case SPL_AST_BOOL_OR_EXPR:
case SPL_AST_BOOL_AND_EXPR: {
spl_type_id_t lt = sema_parse(sema, n->op_expr.left);
spl_type_id_t rt = sema_parse(sema, n->op_expr.right);
spl_type_node_t *ln = spl_type_node(sema->type, lt);
spl_type_node_t *rn = spl_type_node(sema->type, rt);
if (!ln || ln->kind != SPL_TYPE_BOOL || !rn || rn->kind != SPL_TYPE_BOOL) {
SPL_ERROR(&n->dbg, "logical operands must be bool");
sema->error_count++;
break;
}
spl_type_id_t bt = spl_type_builder_simple(sema->type, SPL_TYPE_BOOL);
n->resolved_type_id = bt;
return bt;
}
case SPL_AST_BIT_OR_EXPR:
case SPL_AST_BIT_XOR_EXPR:
case SPL_AST_BIT_AND_EXPR: {
spl_type_id_t lt = sema_parse(sema, n->op_expr.left);
spl_type_id_t rt = sema_parse(sema, n->op_expr.right);
spl_type_id_t peer = sema_coerce_balance(sema, lt, rt);
spl_type_node_t *pn = spl_type_node(sema->type, peer);
if (!pn || pn->kind != SPL_TYPE_INT) {
SPL_ERROR(&n->dbg, "bitwise operands must be integers");
sema->error_count++;
break;
}
n->resolved_type_id = peer;
return peer;
}
case SPL_AST_CMP_EQ_EXPR:
case SPL_AST_CMP_NE_EXPR:
case SPL_AST_CMP_LE_EXPR:
case SPL_AST_CMP_GE_EXPR:
case SPL_AST_CMP_LT_EXPR:
case SPL_AST_CMP_GT_EXPR: {
spl_type_id_t lt = sema_parse(sema, n->op_expr.left);
spl_type_id_t rt = sema_parse(sema, n->op_expr.right);
if (sema_coerce_balance(sema, lt, rt) == 0) {
SPL_ERROR(&n->dbg, "comparison operands type mismatch");
sema->error_count++;
break;
}
spl_type_id_t bt = spl_type_builder_simple(sema->type, SPL_TYPE_BOOL);
n->resolved_type_id = bt;
return bt;
}
case SPL_AST_RANGE_EXPR: {
if (n->op_expr.left)
sema_parse(sema, n->op_expr.left);
if (n->op_expr.right)
sema_parse(sema, n->op_expr.right);
spl_type_id_t i64 = spl_type_builder_int(sema->type, 64, true);
spl_type_id_t rt = spl_type_builder_range(sema->type, i64);
n->resolved_type_id = rt;
return rt;
}
case SPL_AST_LSHIFT_EXPR:
case SPL_AST_RSHIFT_EXPR: {
spl_type_id_t lt = sema_parse(sema, n->op_expr.left);
spl_type_id_t rt = sema_parse(sema, n->op_expr.right);
spl_type_node_t *ln = spl_type_node(sema->type, lt);
spl_type_node_t *rn = spl_type_node(sema->type, rt);
if (!ln || ln->kind != SPL_TYPE_INT || !rn || rn->kind != SPL_TYPE_INT) {
SPL_ERROR(&n->dbg, "shift operands must be integers");
sema->error_count++;
break;
}
n->resolved_type_id = lt;
return lt;
}
case SPL_AST_ADD_EXPR:
case SPL_AST_SUB_EXPR:
case SPL_AST_MUL_EXPR:
case SPL_AST_DIV_EXPR:
case SPL_AST_MOD_EXPR: {
spl_type_id_t lt = sema_parse(sema, n->op_expr.left);
spl_type_id_t rt = sema_parse(sema, n->op_expr.right);
spl_type_node_t *ln = spl_type_node(sema->type, lt);
spl_type_node_t *rn = spl_type_node(sema->type, rt);
spl_type_id_t peer = sema_coerce_balance(sema, lt, rt);
spl_type_node_t *pn = spl_type_node(sema->type, peer);
if (!pn || (pn->kind != SPL_TYPE_INT && pn->kind != SPL_TYPE_FLOAT)) {
SPL_ERROR(&n->dbg, "arithmetic operands type mismatch");
sema->error_count++;
break;
}
n->resolved_type_id = peer;
return peer;
}
case SPL_AST_MINUS_EXPR: {
spl_ast_node_t *op = spl_ast_node(sema->ast, n->prefix_expr.postfix_expr);
if (op && op->kind == SPL_AST_EXPR_INTEGER_LIT) {
spl_type_id_t ct = spl_type_builder_int(sema->type, 0, true);
n->resolved_type_id = ct;
return ct;
}
if (op && op->kind == SPL_AST_EXPR_FLOAT_LIT) {
spl_type_id_t ct = spl_type_builder_float(sema->type, 0);
n->resolved_type_id = ct;
return ct;
}
spl_type_id_t t = sema_parse(sema, n->prefix_expr.postfix_expr);
spl_type_node_t *tn = spl_type_node(sema->type, t);
if (!tn || (tn->kind != SPL_TYPE_INT && tn->kind != SPL_TYPE_FLOAT)) {
SPL_ERROR(&n->dbg, "unary minus requires numeric operand");
sema->error_count++;
break;
}
n->resolved_type_id = t;
return t;
}
case SPL_AST_NOT_EXPR: {
spl_type_id_t t = sema_parse(sema, n->prefix_expr.postfix_expr);
spl_type_node_t *tn = spl_type_node(sema->type, t);
if (!tn || tn->kind != SPL_TYPE_BOOL) {
SPL_ERROR(&n->dbg, "`not` requires bool operand");
sema->error_count++;
break;
}
spl_type_id_t bt = spl_type_builder_simple(sema->type, SPL_TYPE_BOOL);
n->resolved_type_id = bt;
return bt;
}
case SPL_AST_BIT_NOT_EXPR: {
spl_type_id_t t = sema_parse(sema, n->prefix_expr.postfix_expr);
spl_type_node_t *tn = spl_type_node(sema->type, t);
if (!tn || tn->kind != SPL_TYPE_INT) {
SPL_ERROR(&n->dbg, "bitnot requires integer operand");
sema->error_count++;
break;
}
n->resolved_type_id = t;
return t;
}
case SPL_AST_ADDRESS_EXPR:
if (n->prefix_expr.postfix_expr)
sema_parse(sema, n->prefix_expr.postfix_expr);
break;
case SPL_AST_CALL_EXPR: {
spl_type_id_t fnt = sema_parse(sema, n->postfix_expr.primary_expr);
spl_type_node_t *fn = spl_type_node(sema->type, fnt);
if (!fn || fn->kind != SPL_TYPE_FN) {
SPL_ERROR(&n->dbg, "call target is not a function");
sema->error_count++;
break;
}
// TODO type check
vec_for(n->postfix_expr.call_expr, i) {
spl_type_id_t at = sema_parse(sema, vec_at(n->postfix_expr.call_expr, i));
if (sema_coerce(sema, vec_at(fn->fn_type.params, i), at) == 0) {
SPL_ERROR(&n->dbg, "call argument type mismatch");
sema->error_count++;
}
}
n->resolved_type_id = fn->fn_type.ret;
return fn->fn_type.ret;
}
case SPL_AST_DEREF_EXPR: {
spl_type_id_t btid = sema_parse(sema, n->postfix_expr.primary_expr);
spl_type_node_t *bn = spl_type_node(sema->type, btid);
if (!bn || bn->kind != SPL_TYPE_PTR) {
SPL_ERROR(&n->dbg, "deref requires pointer");
sema->error_count++;
break;
}
n->resolved_type_id = bn->ptr_pointee;
return bn->ptr_pointee;
}
case SPL_AST_FIELD_EXPR: {
spl_type_id_t btid = sema_parse(sema, n->postfix_expr.primary_expr);
spl_type_node_t *bn = spl_type_node(sema->type, btid);
spl_type_id_t agg_tid = btid;
if (bn && bn->kind == SPL_TYPE_PTR)
agg_tid = bn->ptr_pointee; /* 自动单层解引用 */
spl_type_node_t *an = spl_type_node(sema->type, agg_tid);
const char *fname = n->postfix_expr.field_expr;
const spl_type_member_t *m = NULL;
if (an && (an->kind == SPL_TYPE_STRUCT || an->kind == SPL_TYPE_UNION))
m = spl_type_agg_member(sema->type, agg_tid, fname);
if (!m) {
SPL_ERROR(&n->dbg, "no field `%s`", fname);
sema->error_count++;
break;
}
n->resolved_type_id = m->type_id;
return m->type_id;
}
case SPL_AST_INDEX_EXPR: {
spl_type_id_t btid = sema_parse(sema, n->postfix_expr.primary_expr);
if (n->postfix_expr.index_expr)
sema_parse(sema, n->postfix_expr.index_expr);
spl_type_node_t *bn = spl_type_node(sema->type, btid);
spl_type_id_t etid = 0;
if (bn) {
switch (bn->kind) {
case SPL_TYPE_SLICE:
etid = bn->slice_element;
break;
case SPL_TYPE_ARRAY:
etid = bn->array_type.element;
break;
case SPL_TYPE_PTR:
etid = bn->ptr_pointee;
break;
default:
break;
}
}
if (etid == 0) {
SPL_ERROR(&n->dbg, "index base must be slice/array/ptr");
sema->error_count++;
break;
}
n->resolved_type_id = etid;
return etid;
}
case SPL_AST_SLICE_EXPR:
if (n->postfix_expr.primary_expr)
sema_parse(sema, n->postfix_expr.primary_expr);
if (n->postfix_expr.slice_expr.begin)
sema_parse(sema, n->postfix_expr.slice_expr.begin);
if (n->postfix_expr.slice_expr.end)
sema_parse(sema, n->postfix_expr.slice_expr.end);
break;
case SPL_AST_AS_EXPR: {
spl_type_id_t st = sema_parse(sema, n->postfix_expr.primary_expr);
spl_type_id_t tt = sema_parse(sema, n->postfix_expr.type_expr);
spl_type_node_t *sn = spl_type_node(sema->type, st);
if (tt == 0 || !sn ||
(sn->kind != SPL_TYPE_INT && sn->kind != SPL_TYPE_FLOAT && sn->kind != SPL_TYPE_BOOL)) {
SPL_ERROR(&n->dbg, "invalid `as` cast");
sema->error_count++;
break;
}
n->resolved_type_id = tt;
return tt;
}
case SPL_AST_EXPR_INTEGER_LIT: {
spl_type_id_t ct = spl_type_builder_int(sema->type, 0, true);
n->resolved_type_id = ct;
return ct;
}
case SPL_AST_EXPR_FLOAT_LIT: {
spl_type_id_t ct = spl_type_builder_float(sema->type, 0);
n->resolved_type_id = ct;
return ct;
}
case SPL_AST_EXPR_CHAR_LIT:
break;
case SPL_AST_EXPR_STRING_LIT: {
/* SPL.md: 字符串字面量 -> []u8 */
spl_type_id_t u8 = spl_type_builder_int(sema->type, 8, false);
spl_type_id_t st = spl_type_builder_slice(sema->type, u8);
n->resolved_type_id = st;
return st;
}
case SPL_AST_EXPR_NULL: {
spl_type_id_t nt = spl_type_builder_simple(sema->type, SPL_TYPE_NULL);
n->resolved_type_id = nt;
return nt;
}
case SPL_AST_EXPR_TRUE:
case SPL_AST_EXPR_FALSE: {
spl_type_id_t bt = spl_type_builder_simple(sema->type, SPL_TYPE_BOOL);
n->resolved_type_id = bt;
return bt;
}
case SPL_AST_EXPR_UNDEFINED: {
spl_type_id_t ut = spl_type_builder_simple(sema->type, SPL_TYPE_UNDEFINED);
n->resolved_type_id = ut;
return ut;
}
case SPL_AST_EXPR_IDENT: {
spl_symbol_t symbol = {0};
if (!spl_scope_find(sema->scope, n->primary_expr.ident, &symbol)) {
SPL_ERROR(&n->dbg, "can't find ident `%s`", n->primary_expr.ident);
sema->error_count++;
return 0;
}
Assert(symbol.node != 0);
n->resolved_def_id = symbol.node;
spl_def_node_t *d = spl_type_def(sema->type, symbol.node);
Assert(d != 0);
return d->type_id;
}
case SPL_AST_ARGGREGATE_INIT: {
const char *tname = n->primary_expr.aggregate_init.name;
if (!tname) {
SPL_ERROR(&n->dbg, "anonymous aggregate init TODO");
sema->error_count++;
break;
}
spl_symbol_t sym = {0};
if (!spl_scope_find(sema->scope, tname, &sym)) {
SPL_ERROR(&n->dbg, "aggregate init: unknown type `%s`", tname);
sema->error_count++;
break;
}
spl_def_node_t *d = spl_type_def(sema->type, sym.node);
spl_type_id_t tid = d ? d->type_id : 0;
spl_type_node_t *tn = spl_type_node(sema->type, tid);
if (!tn || (tn->kind != SPL_TYPE_STRUCT && tn->kind != SPL_TYPE_UNION)) {
SPL_ERROR(&n->dbg, "aggregate init: `%s` is not a struct", tname);
sema->error_count++;
break;
}
usize got = 0;
vec_for(n->primary_expr.aggregate_init.expr, i) {
spl_ast_node_t *item =
spl_ast_node(sema->ast, vec_at(n->primary_expr.aggregate_init.expr, i));
if (!item || item->kind != SPL_AST_ARGG_INIT_ITEM)
continue;
got++;
const char *fname = item->aggregate_init_item.ident;
spl_type_id_t etid = item->aggregate_init_item.expr
? sema_parse(sema, item->aggregate_init_item.expr)
: 0;
const spl_type_member_t *m = spl_type_agg_member(sema->type, tid, fname);
if (!m) {
SPL_ERROR(&item->dbg, "aggregate init: no field `%s` in `%s`", fname, tname);
sema->error_count++;
continue;
}
if (sema_coerce(sema, m->type_id, etid) == 0) {
SPL_ERROR(&item->dbg, "aggregate init: field `%s` type mismatch", fname);
sema->error_count++;
}
}
if (tn->kind == SPL_TYPE_STRUCT && got != vec_size(tn->agg_members)) {
SPL_ERROR(&n->dbg, "aggregate init: field count mismatch (%zu/%zu)", got,
vec_size(tn->agg_members));
sema->error_count++;
}
n->resolved_type_id = tid;
return tid;
}
case SPL_AST_EXPR_EXPR: {
spl_type_id_t t = sema_parse(sema, n->primary_expr.expr);
n->resolved_type_id = t;
return t;
}
case SPL_AST_ARRAY_LIT:
if (n->primary_expr.array_lit_expr.type_expr)
sema_parse(sema, n->primary_expr.array_lit_expr.type_expr);
vec_for(n->primary_expr.array_lit_expr.expr_list, i) {
sema_parse(sema, vec_at(n->primary_expr.array_lit_expr.expr_list, i));
}
break;
case SPL_AST_BUILTIN_EXPR:
vec_for(n->primary_expr.builtin_expr.expr_list, i) {
sema_parse(sema, vec_at(n->primary_expr.builtin_expr.expr_list, i));
}
break;
case SPL_AST_BLOCK_EXPR:
vec_for(n->primary_expr.block_expr, i) {
sema_parse(sema, vec_at(n->primary_expr.block_expr, i));
}
break;
case SPL_AST_BASE_TYPE_FN:
vec_for(n->type_expr.attr_list, i) { sema_parse(sema, vec_at(n->type_expr.attr_list, i)); }
vec_for(n->type_expr.fn_type.param_list, i) {
sema_parse(sema, vec_at(n->type_expr.fn_type.param_list, i));
}
if (n->type_expr.fn_type.type_expr)
sema_parse(sema, n->type_expr.fn_type.type_expr);
break;
case SPL_AST_BASE_TYPE_PATH: {
vec_for(n->type_expr.attr_list, i) { sema_parse(sema, vec_at(n->type_expr.attr_list, i)); }
if (vec_size(n->type_expr.type_path.ident_vec) == 0)
break;
const char *tname = vec_at(n->type_expr.type_path.ident_vec, 0);
if (vec_size(n->type_expr.type_path.ident_vec) == 1) {
spl_symbol_t sym = {0};
if (spl_scope_find(sema->scope, tname, &sym)) {
spl_def_node_t *d = spl_type_def(sema->type, sym.node);
if (d && d->type_id) {
n->resolved_type_id = d->type_id;
return d->type_id;
}
}
SPL_ERROR(&n->dbg, "type `%s` not found", tname);
sema->error_count++;
break;
}
/* 多段命名空间路径(如 Str.InnerTODO */
SPL_ERROR(&n->dbg, "nested type path TODO");
sema->error_count++;
break;
}
case SPL_AST_TYPE_POINTER: {
vec_for(n->type_expr.attr_list, i) { sema_parse(sema, vec_at(n->type_expr.attr_list, i)); }
spl_type_id_t ptid = 0;
if (n->type_expr.pointer_type.pointee)
ptid = sema_parse(sema, n->type_expr.pointer_type.pointee);
spl_type_id_t tid = spl_type_builder_ptr(sema->type, ptid);
n->resolved_type_id = tid;
return tid;
}
case SPL_AST_TYPE_ARRAY: {
vec_for(n->type_expr.attr_list, i) { sema_parse(sema, vec_at(n->type_expr.attr_list, i)); }
spl_type_id_t etid = 0;
if (n->type_expr.array_type.element)
etid = sema_parse(sema, n->type_expr.array_type.element);
usize len = 0;
if (n->type_expr.array_type.size) {
spl_ast_node_t *sz = spl_ast_node(sema->ast, n->type_expr.array_type.size);
if (sz && sz->kind == SPL_AST_EXPR_INTEGER_LIT) {
len = (usize)sz->primary_expr.integer_expr;
} else {
sema_parse(sema, n->type_expr.array_type.size);
}
}
spl_type_id_t tid = spl_type_builder_array(sema->type, etid, len);
n->resolved_type_id = tid;
return tid;
}
case SPL_AST_TYPE_SLICE: {
vec_for(n->type_expr.attr_list, i) { sema_parse(sema, vec_at(n->type_expr.attr_list, i)); }
spl_type_id_t etid = 0;
if (n->type_expr.slice_type.element)
etid = sema_parse(sema, n->type_expr.slice_type.element);
spl_type_id_t tid = spl_type_builder_slice(sema->type, etid);
n->resolved_type_id = tid;
return tid;
}
case SPL_AST_TYPE_STRUCT:
case SPL_AST_TYPE_UNION:
case SPL_AST_TYPE_SHAPE:
case SPL_AST_TYPE_ENUM:
vec_for(n->type_expr.attr_list, i) { sema_parse(sema, vec_at(n->type_expr.attr_list, i)); }
vec_for(n->type_expr.aggregate_list, i) {
sema_parse(sema, vec_at(n->type_expr.aggregate_list, i));
}
break;
case SPL_AST_TYPE_VOID:
return spl_type_builder_simple(sema->type, SPL_TYPE_VOID);
case SPL_AST_TYPE_BOOL:
return spl_type_builder_simple(sema->type, SPL_TYPE_BOOL);
case SPL_AST_TYPE_OPAQUE:
return 0;
case SPL_AST_TYPE_I8:
return spl_type_builder_int(sema->type, 8, true);
case SPL_AST_TYPE_U8:
return spl_type_builder_int(sema->type, 8, false);
case SPL_AST_TYPE_I16:
return spl_type_builder_int(sema->type, 16, true);
case SPL_AST_TYPE_U16:
return spl_type_builder_int(sema->type, 16, false);
case SPL_AST_TYPE_I32:
return spl_type_builder_int(sema->type, 32, true);
case SPL_AST_TYPE_U32:
return spl_type_builder_int(sema->type, 32, false);
case SPL_AST_TYPE_I64:
return spl_type_builder_int(sema->type, 64, true);
case SPL_AST_TYPE_U64:
return spl_type_builder_int(sema->type, 64, false);
case SPL_AST_TYPE_ISIZE:
return spl_type_builder_int(sema->type, sizeof(void *) * 8, true); /* FIXME */
case SPL_AST_TYPE_USIZE:
return spl_type_builder_int(sema->type, sizeof(void *) * 8, false); /* FIXME */
case SPL_AST_TYPE__F32:
return spl_type_builder_float(sema->type, 32);
case SPL_AST_TYPE__F64:
return spl_type_builder_float(sema->type, 64);
case SPL_AST_TYPE_ANY:
case SPL_AST_TYPE_IDENT:
break;
case SPL_AST_COUNT:
UNREACHABLE();
break;
}
return 0;
}
void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope) {
Assert(sema && ast && type && scope);
sema->ast = ast;
sema->type = type;
sema->scope = scope;
sema->error_count = 0;
sema->current_fn_ret_tid = 0;
sema->root = (spl_symbol_t){0};
}
void spl_sema_drop(spl_sema_t *sema) { (void)sema; }
void spl_sema_run(spl_sema_t *sema) {
if (!sema->ast || !sema->ast->root)
return;
spl_ast_node_t *ast_node = spl_ast_node(sema->ast, sema->ast->root);
Assert(ast_node != NULL && ast_node->kind == SPL_AST_CONTAINER_MEMBERS);
// 第一趟 实现顺序无关地相互引用
sema_collect(sema, sema->ast->root);
// 第二趟 正式解析
sema_parse(sema, sema->ast->root);
}
void spl_sema_dump(spl_sema_t *sema) {
printf("Scopes:\n");
vec_for(sema->scope->scopes, i) {
if (i == 0)
continue;
spl_scope_node_t scope = vec_at(sema->scope->scopes, i);
printf("scope[%zu] parent=%zu\n", i, scope.parent);
map_for(scope.symbols, j) {
spl_symbol_t *symbol = &unsafe_map_at(scope.symbols, j).val;
printf(" %s -> def`%s`#%zu\n", unsafe_map_at(scope.symbols, j).key, symbol->name,
symbol->node);
}
}
printf("TypeTable:\n");
vec_for(sema->type->type_table, i) {
printf(" id#%zu type=", i);
spl_type_pure_dump(sema->type, i);
printf("\n");
}
printf("DefTable:\n");
vec_for(sema->type->def_table, i) {
printf(" def#%zu ", i);
spl_type_def_dump(sema->type, i);
spl_def_node_t *d = spl_type_def(sema->type, i);
printf("\n");
}
}