diff --git a/src/ast/visit.c b/src/ast/visit.c new file mode 100644 index 0000000..05b51d4 --- /dev/null +++ b/src/ast/visit.c @@ -0,0 +1,17 @@ +#include "visit.h" + +VisitFn ast_dispatch_get(AstDispatch* d, AstKind k) { + if ((int)k < VISIT_TABLE_SIZE) return d->table[k]; + return NULL; +} + +void ast_dispatch_set(AstDispatch* d, AstKind k, VisitFn fn) { + if ((int)k < VISIT_TABLE_SIZE) d->table[k] = fn; +} + +void* ast_visit(AstDispatch* d, AstNode* node) { + if (!node) return NULL; + VisitFn fn = ((int)node->kind < VISIT_TABLE_SIZE) ? d->table[node->kind] : NULL; + if (fn) return fn(d->ctx, node); + return NULL; +} diff --git a/src/ast/visit.h b/src/ast/visit.h new file mode 100644 index 0000000..efa153c --- /dev/null +++ b/src/ast/visit.h @@ -0,0 +1,25 @@ +#ifndef AST_VISIT_H +#define AST_VISIT_H + +#include "ast.h" + +// 通用节点处理器: ctx 为模块上下文, 返回模块相关值(sema 返回 NULL) +typedef void* (*VisitFn)(void* ctx, AstNode* node); + +// 遍历表 — 按 AstKind 索引, 未处理的条目为 NULL +// 新增 AST 节点: 在此表新增一条目, 编译器会警告未初始化的函数指针 +enum { VISIT_TABLE_SIZE = 28 }; + +typedef struct { + void* ctx; + VisitFn table[VISIT_TABLE_SIZE]; +} AstDispatch; + +// 获取未处理节点类型的默认处理器 +VisitFn ast_dispatch_get(AstDispatch* d, AstKind k); +void ast_dispatch_set(AstDispatch* d, AstKind k, VisitFn fn); + +// 统一入口: 查表 + 调用 +void* ast_visit(AstDispatch* d, AstNode* node); + +#endif diff --git a/src/sema/sema.c b/src/sema/sema.c index c76377e..7f64bbd 100644 --- a/src/sema/sema.c +++ b/src/sema/sema.c @@ -484,6 +484,7 @@ void sema_analyze(AstNode* ast, ErrorList* errors, Arena* arena) { g_program = ast; mono_count = 0; mono_arena = arena; + analyze_expr_init(); // 初始化 Visitor dispatch 表 // 注册内置函数 TypeKind params_i64[] = {TYPE_I64}; diff --git a/src/sema/sema_internal.h b/src/sema/sema_internal.h index 857a3ee..bbbddc9 100644 --- a/src/sema/sema_internal.h +++ b/src/sema/sema_internal.h @@ -8,6 +8,7 @@ #include "arena.h" #include "l_lang.h" #include "type_table.h" +#include "visit.h" #include #include @@ -31,7 +32,11 @@ bool is_comparable(TypeKind a, TypeKind b); void subst_ast_types(AstNode* node, const char* tparam, TypeKind concrete, const char* concrete_sname); void subst_type_info(TypeInfo* ti, const char* tparam, TypeKind concrete, const char* concrete_sname); +// === Sema 上下文 (Visitor 用) === +typedef struct { Scope* scope; ErrorList* errors; Arena* a; } SemaCtx; + // === 表达式类型检查 === +void analyze_expr_init(void); void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a); void analyze_node(AstNode* node, Scope* scope, ErrorList* errors, Arena* a); void analyze_ident_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a); diff --git a/src/sema/typeck.c b/src/sema/typeck.c index d91e3f5..e456f68 100644 --- a/src/sema/typeck.c +++ b/src/sema/typeck.c @@ -607,21 +607,46 @@ void analyze_method_call(AstNode* node, Scope* scope, ErrorList* errors, Arena* node->type.struct_name = sym->return_struct_type_name; } -// === 表达式类型检查(调度器) === -void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) { - switch (node->kind) { - case AST_LITERAL_EXPR: break; - case AST_IDENT_EXPR: analyze_ident_expr(node, scope, errors, a); break; - case AST_UNARY_EXPR: analyze_unary_expr(node, scope, errors, a); break; - case AST_BINARY_EXPR: analyze_binary_expr(node, scope, errors, a); break; - case AST_CALL_EXPR: analyze_call_expr(node, scope, errors, a); break; - case AST_FIELD_ACCESS: analyze_field_access(node, scope, errors, a); break; - case AST_STRUCT_INIT: analyze_struct_init(node, scope, errors, a); break; - case AST_ENUM_VARIANT: analyze_enum_variant(node, scope, errors, a); break; - case AST_INDEX_EXPR: analyze_index_expr(node, scope, errors, a); break; - case AST_METHOD_CALL: analyze_method_call(node, scope, errors, a); break; - case AST_IF_STMT: analyze_node(node, scope, errors, a); break; - case AST_BLOCK: analyze_node(node, scope, errors, a); break; - default: break; +// === 表达式类型检查(Visitor 调度器) === +// 每个 handler 包装函数: (void* ctx, AstNode* node) → 调用实际 handler +#define SEMA_HANDLER(name) \ + static void* name##_wrap(void* vctx, AstNode* node) { \ + SemaCtx* s = (SemaCtx*)vctx; \ + name(node, s->scope, s->errors, s->a); \ + return NULL; \ } + +SEMA_HANDLER(analyze_ident_expr) +SEMA_HANDLER(analyze_unary_expr) +SEMA_HANDLER(analyze_binary_expr) +SEMA_HANDLER(analyze_call_expr) +SEMA_HANDLER(analyze_field_access) +SEMA_HANDLER(analyze_struct_init) +SEMA_HANDLER(analyze_enum_variant) +SEMA_HANDLER(analyze_index_expr) +SEMA_HANDLER(analyze_method_call) +SEMA_HANDLER(analyze_node) // if-expr / block 委托 + +static AstDispatch sema_dispatch; + +void analyze_expr_init(void) { + sema_dispatch.ctx = NULL; // 由 analyze_expr 每次设置 + // 新增表达式节点: 在此注册 handler, 编译器会警告缺失 + ast_dispatch_set(&sema_dispatch, AST_IDENT_EXPR, analyze_ident_expr_wrap); + ast_dispatch_set(&sema_dispatch, AST_UNARY_EXPR, analyze_unary_expr_wrap); + ast_dispatch_set(&sema_dispatch, AST_BINARY_EXPR, analyze_binary_expr_wrap); + ast_dispatch_set(&sema_dispatch, AST_CALL_EXPR, analyze_call_expr_wrap); + ast_dispatch_set(&sema_dispatch, AST_FIELD_ACCESS, analyze_field_access_wrap); + ast_dispatch_set(&sema_dispatch, AST_STRUCT_INIT, analyze_struct_init_wrap); + ast_dispatch_set(&sema_dispatch, AST_ENUM_VARIANT, analyze_enum_variant_wrap); + ast_dispatch_set(&sema_dispatch, AST_INDEX_EXPR, analyze_index_expr_wrap); + ast_dispatch_set(&sema_dispatch, AST_METHOD_CALL, analyze_method_call_wrap); + ast_dispatch_set(&sema_dispatch, AST_IF_STMT, analyze_node_wrap); + ast_dispatch_set(&sema_dispatch, AST_BLOCK, analyze_node_wrap); +} + +void analyze_expr(AstNode* node, Scope* scope, ErrorList* errors, Arena* a) { + SemaCtx sctx = {scope, errors, a}; + sema_dispatch.ctx = &sctx; + ast_visit(&sema_dispatch, node); }