refactor: AST Visitor dispatch — sema analyze_expr switch→vtable

新增 src/ast/visit.h/c: AstDispatch 函数指针表 + ast_visit() 统一入口
analyze_expr 的 switch 替换为 dispatch 表, 10 个 handler 通过 SEMA_HANDLER 宏注册
新增 AST 节点: 在 analyze_expr_init() 加一行即可, 编译器会检查函数签名

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 20:36:13 +08:00
parent 3733b41453
commit b34ad17aad
5 changed files with 89 additions and 16 deletions
+41 -16
View File
@@ -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);
}