Files
spl/stage1/spl_sema.c
2026-08-16 23:23:56 +08:00

328 lines
10 KiB
C

#include "spl_sema.h"
// Scope part
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
LOG_ERROR("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;
}
spl_symbol_t symbol = {0};
for (spl_scope_node_t *s = &vec_at(scope->scopes, scope->current_scope); s->parent != 0;
s = &vec_at(scope->scopes, s->parent)) {
if (map_get(s->symbols, name, &symbol) == true) {
Assert(symbol.kind != SPL_SYMBOL_KIND_ERROR);
break;
}
}
if (symbol.kind == SPL_SYMBOL_KIND_ERROR) {
return false;
}
return true;
}
// 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};
spl_def_id_t def = 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);
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)); }
spl_def_node_t *def = spl_type_def(sema->type, symbol.node);
def->kind = SPL_DEF_AGG;
break;
}
case SPL_AST_TYPE_DECL: {
symbol.name = n->type_decl.name;
symbol.kind = SPL_SYMBOL_KIND_TYPE;
symbol.node = spl_type_def_alloc(sema->type);
n->resolved_def_id = symbol.node;
n = spl_ast_node(sema->ast, n->type_decl.type_expr);
if (!n) {
SPL_FATAL(&n->dbg, "type_decl must have type_expr");
return;
}
spl_def_node_t *def = spl_type_def(sema->type, symbol.node);
switch (n->kind) {
case SPL_AST_TYPE_STRUCT:
case SPL_AST_TYPE_UNION:
case SPL_AST_TYPE_ENUM:
case SPL_AST_TYPE_SHAPE: /* TODO for shape */
def->kind = SPL_DEF_AGG;
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(n->type_expr.aggregate_list, i) {
sema_collect(sema, vec_at(n->type_expr.aggregate_list, i));
}
sema->scope->current_scope = old_id;
break;
default:
def->kind = SPL_DEF_SCALAR;
break;
}
spl_scope_insert(sema->scope, sema->scope->current_scope, symbol);
} 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);
n->resolved_def_id = symbol.node;
spl_def_node_t *def = spl_type_def(sema->type, symbol.node);
def->kind = SPL_DEF_FN_PARAMS;
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);
n->resolved_def_id = symbol.node;
spl_def_node_t *def = spl_type_def(sema->type, symbol.node);
def->kind = SPL_DEF_VAR;
spl_scope_insert(sema->scope, sema->scope->current_scope, symbol);
} break;
case SPL_AST_MEMBER_DECL: {
symbol.name = n->member_decl.name;
symbol.kind = SPL_SYMBOL_KIND_MEMBER;
symbol.node = spl_type_def_alloc(sema->type);
n->resolved_def_id = symbol.node;
spl_def_node_t *def = spl_type_def(sema->type, symbol.node);
def->kind = SPL_DEF_MEMBER;
spl_scope_insert(sema->scope, sema->scope->current_scope, symbol);
} break;
default:
break;
}
}
// Parse twice
static void sema_parse(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};
spl_def_id_t def = 0;
Assert(n != NULL);
switch (n->kind) {
case SPL_AST_NONE:
case SPL_AST_CONTAINER_MEMBERS:
case SPL_AST_FN_DECL:
case SPL_AST_FN_DEFINE:
case SPL_AST_TYPE_DECL:
case SPL_AST_VAR_DECL:
case SPL_AST_CONST_DECL:
case SPL_AST_MEMBER_DECL:
case SPL_AST__COMPTIME_STMT:
case SPL_AST__DIRECTIVE_BLOCK:
case SPL_AST_PARAM_DECL:
case SPL_AST_ATTR_ITEM:
case SPL_AST_ARGG_INIT_ITEM:
case SPL_AST_IF_STATEMENT:
case SPL_AST_IFVAR_STATEMENT:
case SPL_AST_WHILE_STATEMENT:
case SPL_AST_LOOP_STATEMENT:
case SPL_AST_FOR_STATEMENT:
case SPL_AST_MATCH_STATEMENT:
case SPL_AST_RET_STATEMENT:
case SPL_AST_BREAK_STATEMENT:
case SPL_AST_CONTINUE_STATEMENT:
case SPL_AST_DEFER_STATEMENT:
case SPL_AST_TRY_STATEMENT:
case SPL_AST_CATCH_STATEMENT:
case SPL_AST_ERRDEFER_STATEMEMT:
case SPL_AST_EXPR_STATEMENT:
case SPL_AST_PACKED_EXPR:
case SPL_AST_ASSIGN_EXPR:
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:
case SPL_AST_BOOL_OR_EXPR:
case SPL_AST_BOOL_AND_EXPR:
case SPL_AST_BIT_OR_EXPR:
case SPL_AST_BIT_XOR_EXPR:
case SPL_AST_BIT_AND_EXPR:
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:
case SPL_AST_RANGE_EXPR:
case SPL_AST_LSHIFT_EXPR:
case SPL_AST_RSHIFT_EXPR:
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:
case SPL_AST_MINUS_EXPR:
case SPL_AST_NOT_EXPR:
case SPL_AST_BIT_NOT_EXPR:
case SPL_AST_ADDRESS_EXPR:
case SPL_AST_CALL_EXPR:
case SPL_AST_FIELD_EXPR:
case SPL_AST_DEREF_EXPR:
case SPL_AST_INDEX_EXPR:
case SPL_AST_SLICE_EXPR:
case SPL_AST_AS_EXPR:
case SPL_AST_EXPR_INTEGER_LIT:
case SPL_AST_EXPR_FLOAT_LIT:
case SPL_AST_EXPR_CHAR_LIT:
case SPL_AST_EXPR_STRING_LIT:
case SPL_AST_EXPR_TRUE:
case SPL_AST_EXPR_FALSE:
case SPL_AST_EXPR_NULL:
case SPL_AST_EXPR_UNDEFINED:
case SPL_AST_EXPR_IDENT:
case SPL_AST_ARGGREGATE_INIT:
case SPL_AST_EXPR_EXPR:
case SPL_AST_ARRAY_LIT:
case SPL_AST_BUILTIN_EXPR:
case SPL_AST_BLOCK_EXPR:
case SPL_AST_BASE_TYPE_FN:
case SPL_AST_BASE_TYPE_PATH:
case SPL_AST_TYPE_POINTER:
case SPL_AST_TYPE_ARRAY:
case SPL_AST_TYPE_SLICE:
case SPL_AST_TYPE_STRUCT:
case SPL_AST_TYPE_UNION:
case SPL_AST_TYPE_SHAPE:
case SPL_AST_TYPE_ENUM:
case SPL_AST_TYPE_VOID:
case SPL_AST_TYPE_BOOL:
case SPL_AST_TYPE_OPAQUE:
case SPL_AST_TYPE_I8:
case SPL_AST_TYPE_U8:
case SPL_AST_TYPE_I16:
case SPL_AST_TYPE_U16:
case SPL_AST_TYPE_I32:
case SPL_AST_TYPE_U32:
case SPL_AST_TYPE_I64:
case SPL_AST_TYPE_U64:
case SPL_AST_TYPE_ISIZE:
case SPL_AST_TYPE_USIZE:
case SPL_AST_TYPE__F32:
case SPL_AST_TYPE__F64:
case SPL_AST_TYPE_ANY:
case SPL_AST_TYPE_IDENT:
break;
case SPL_AST_COUNT:
UNREACHABLE();
break;
}
}
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->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);
printf("\n");
}
}