1143 lines
42 KiB
C
1143 lines
42 KiB
C
#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);
|
||
/* 第二遍:方法 body(struct 类型已 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.Inner):TODO */
|
||
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");
|
||
}
|
||
}
|