#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"); } }