import t, c from stdint import * import ast import llvmlite import memhub import string import viperlib import lib.core.Handles.HandlesBase as HandlesBase import lib.core.Handles.HandlesTranslator as HT import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesBody as HandlesBody import lib.core.Handles.HandlesVar as HandlesVar import lib.core.Handles.HandlesClassDef as HandlesClassDef import lib.core.Handles.HandlesStruct as HandlesStruct # ============================================================ # HandlesMatch - match 语句处理(Mixin 继承模式) # # 逻辑移植自 TPC 的 HandlesMatch.py,用 Viper 语法重写。 # 两条路径: # 1. REnum 路径:bitcast subject 到 i32* 读 __tag + switch 分派 # 2. 非 REnum 路径:subject ptrtoint 到 i32 + switch 分派 # # IR 模式(REnum): # %tag_ptr = bitcast * %subj to i32* # %tag = load i32, i32* %tag_ptr # switch i32 %tag, label %default [ i32 , label %case1 ... ] # case1: # ... body ... # br label %end (若无 c.NoBreak) # end: # ============================================================ # match case 数量上限 MAX_MATCH_CASES: t.CDefine = 32 # 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分) SCOPE_MATCH: t.CDefine = 6 @t.NoVTable class MatchHandle(HandlesBase.Mixin): """match 语句处理器:REnum + 非 REnum 两条路径""" def __init__(self, trans: HT.Translator | t.CPtr): self.Trans = trans # ============================================================ # Handle - match 语句主入口,返回 0 # ============================================================ def Handle(self, node: ast.AST | t.CPtr) -> int: if node is None: return 0 trans: HT.Translator | t.CPtr = self.Trans pool: memhub.MemBuddy | t.CPtr = trans.Pool builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder func: llvmlite.Function | t.CPtr = trans._cur_func if builder is None or func is None: return 0 m_node: ast.Match | t.CPtr = (ast.Match | t.CPtr)(node) # 1. 求值 subject subject_node: ast.AST | t.CPtr = m_node.subject if subject_node is None: return 0 subject_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, trans.Module, subject_node, trans._funcs, trans._func_count, trans) if subject_val is None: return 0 # 2. 检测是否 REnum match is_renum: int = 0 renum_name: str = None subject_ptr: llvmlite.Value | t.CPtr = None # 2a. 若 subject 是 Name,查变量注解类名 if subject_node.kind() == ast.ASTKind.Name: nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(subject_node) if nm.id is not None: entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( trans.SymTab, nm.id) if entry is not None and entry.AnnotClassName is not None: rn_chk: int = HandlesClassDef._is_renum_class_name( entry.AnnotClassName) if rn_chk != 0: is_renum = 1 renum_name = entry.AnnotClassName subject_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) # 2b. 若未确定,遍历 cases 查 MatchClass 变体 if is_renum == 0: cases_list: list[ast.AST | t.CPtr] | t.CPtr = m_node.cases if cases_list is not None: cn: t.CSizeT = cases_list.__len__() ci: int = 0 while ci < cn and is_renum == 0: case_node: ast.AST | t.CPtr = cases_list.get(ci) if case_node is not None: if case_node.kind() == ast.ASTKind.MatchCase: mc: ast.MatchCase | t.CPtr = ( ast.MatchCase | t.CPtr)(case_node) pat: ast.AST | t.CPtr = mc.pattern if pat is not None: if pat.kind() == ast.ASTKind.MatchClass: rnm: str = self._extract_renum_name_from_cls(pat) if rnm is not None: if HandlesClassDef._is_renum_class_name(rnm) != 0: is_renum = 1 renum_name = rnm if subject_ptr is None: subject_ptr = subject_val ci = ci + 1 # 3. 分派 if is_renum != 0 and subject_ptr is not None: return self._handle_renum_match(m_node, renum_name, subject_ptr) return self._handle_simple_match(m_node, subject_val) # ============================================================ # _extract_renum_name_from_cls - 从 MatchClass.cls 提取 REnum 类名 # # LLVMType.Ptr -> Attribute(value=Name('LLVMType'), attr='Ptr') -> 'LLVMType' # llvmlite.LLVMType.Ptr -> Attribute(Attribute(Name('llvmlite'),'LLVMType'),'Ptr') -> 'LLVMType' # Ptr -> Name('Ptr') -> 遍历查找 # ============================================================ def _extract_renum_name_from_cls(self, pattern: ast.AST | t.CPtr) -> str: if pattern is None: return None mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern) cls_node: ast.AST | t.CPtr = mc.cls if cls_node is None: return None # Attribute 形式 if cls_node.kind() == ast.ASTKind.Attribute: at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node) if at.value is not None: if at.value.kind() == ast.ASTKind.Name: inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) return inner_nm.id if at.value.kind() == ast.ASTKind.Attribute: inner_at: ast.Attribute | t.CPtr = ( ast.Attribute | t.CPtr)(at.value) return inner_at.attr # Name 形式:遍历所有 REnum 类反查 if cls_node.kind() == ast.ASTKind.Name: nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cls_node) return self._find_renum_class_for_variant(nm.id) return None # ============================================================ # _extract_variant_name_from_cls - 从 MatchClass.cls 提取变体名 # ============================================================ def _extract_variant_name_from_cls(self, pattern: ast.AST | t.CPtr) -> str: if pattern is None: return None mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pattern) cls_node: ast.AST | t.CPtr = mc.cls if cls_node is None: return None if cls_node.kind() == ast.ASTKind.Attribute: at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cls_node) return at.attr if cls_node.kind() == ast.ASTKind.Name: nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cls_node) return nm.id return None # ============================================================ # _find_renum_class_for_variant - 从变体名反查 REnum 类名 # ============================================================ def _find_renum_class_for_variant(self, variant_name: str) -> str: if variant_name is None: return None i: int = 0 while i < HandlesClassDef._renum_class_count: cls_nm: str = HandlesClassDef._renum_class_names[i] if cls_nm is not None: tag: int = HandlesClassDef._lookup_renum_variant_in_class( cls_nm, variant_name) if tag >= 0: return cls_nm i = i + 1 return None # ============================================================ # _has_no_break - 检测 case body 是否含 c.NoBreak() 调用 # # 遍历 case body 顶层语句,查找 Expr(Call(Attribute(Name('c'), 'NoBreak'))) # ============================================================ def _has_no_break(self, body_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: if body_list is None: return 0 n: t.CSizeT = body_list.__len__() i: int = 0 while i < n: stmt: ast.AST | t.CPtr = body_list.get(i) if stmt is not None: if stmt.kind() == ast.ASTKind.Expr: expr_node: ast.Expr | t.CPtr = (ast.Expr | t.CPtr)(stmt) val: ast.AST | t.CPtr = expr_node.value if val is not None and val.kind() == ast.ASTKind.Call: call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val) fn: ast.AST | t.CPtr = call_node.func if fn is not None and fn.kind() == ast.ASTKind.Attribute: at: ast.Attribute | t.CPtr = ( ast.Attribute | t.CPtr)(fn) if at.value is not None: if at.value.kind() == ast.ASTKind.Name: base_nm: ast.Name | t.CPtr = ( ast.Name | t.CPtr)(at.value) if base_nm.id is not None: if string.strcmp(base_nm.id, "c") == 0: if at.attr is not None: if string.strcmp(at.attr, "NoBreak") == 0: return 1 i = i + 1 return 0 # ============================================================ # _handle_renum_match - REnum 路径 # # 1. bitcast subject 到 i32* 读 __tag # 2. 收集 case 值 + 创建 BB + 构建 SwitchCase 链表 # 3. 发射 build_switch # 4. 翻译每个 case body(含作用域隔离 + 变体字段绑定) # ============================================================ def _handle_renum_match(self, node: ast.Match | t.CPtr, renum_name: str, subject_ptr: llvmlite.Value | t.CPtr) -> int: trans: HT.Translator | t.CPtr = self.Trans pool: memhub.MemBuddy | t.CPtr = trans.Pool builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder func: llvmlite.Function | t.CPtr = trans._cur_func # 0. subject 归一化:确保 subject_ptr 是指向 REnum 结构体的指针 # (对齐 TPC HandlesMatch.py:238-259 的 _HandleRenumMatchLlvm) # 情况1: subject_ptr 是 T**(变量 alloca)→ load 一次得 T* # 情况2: subject_ptr 不是指针(值型,如 REnum payload 槽位 load 出的 i64) # → alloca REnum 结构体 + store 值 + 用 alloca 指针 # 情况3: 指针但 pointee 不是结构体 → bitcast 到 REnum 结构体指针 subj_ty: llvmlite.LLVMType | t.CPtr = subject_ptr.Ty if subj_ty is not None and HandlesExpr.is_ptr_type(subj_ty) != 0: pointee_ty: llvmlite.LLVMType | t.CPtr = subj_ty.Pointee if pointee_ty is not None: if HandlesExpr.is_ptr_type(pointee_ty) != 0: # 情况1: T** → load 一次得 T* load_sub_ty: llvmlite.LLVMType | t.CPtr = pointee_ty loaded_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( builder, load_sub_ty, subject_ptr) if loaded_sub is not None: subject_ptr = loaded_sub # 情况2: 值型 subject(非指针)→ inttoptr 转回指针 # 值型 subject 来自 REnum payload 槽位 load(槽位类型 i64,存的是指针), # 所以直接 inttoptr 到 renum_sty* 即可,无需 alloca+store if subject_ptr.Ty is None or HandlesExpr.is_ptr_type(subject_ptr.Ty) == 0: renum_se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( renum_name) renum_sty: llvmlite.LLVMType | t.CPtr = None if renum_se is not None: renum_sty = renum_se.Ty if renum_sty is None: # 找不到结构体类型时无法构造,直接放弃 REnum 路径 return 0 i64_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) int_val: llvmlite.Value | t.CPtr = subject_ptr # 非 i64 整数值先扩展/截断到 i64(inttoptr 要求同宽) # 仅当 subj_ty 是已知整数类型时转换;类型未知时保持原值 if subj_ty is not None and HandlesExpr.get_llvm_type_bits(subj_ty) != 64: if HandlesExpr.is_ptr_type(subj_ty) == 0: if HandlesExpr.get_llvm_type_bits(subj_ty) > 64: int_val = llvmlite.build_trunc(builder, subject_ptr, i64_ty0) else: int_val = llvmlite.build_zext(builder, subject_ptr, i64_ty0) renum_ptr_ty0: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, renum_sty) subj_ptr0: llvmlite.Value | t.CPtr = llvmlite.build_inttoptr( builder, int_val, renum_ptr_ty0) if subj_ptr0 is not None: subject_ptr = subj_ptr0 # 1. bitcast subject 到 i32* 读 __tag i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) i32_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i32_ty) tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( builder, subject_ptr, i32_ptr_ty) if tag_ptr is None: return 0 tag_val: llvmlite.Value | t.CPtr = llvmlite.build_load( builder, i32_ty, tag_ptr) if tag_val is None: return 0 # 2. 创建 default/end BB cnt: int = trans._label_counter trans._label_counter = cnt + 1 name_buf: t.CChar | t.CPtr = pool.alloc(32) if name_buf is None: return 0 viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( pool, func, name_buf) viperlib.snprintf(name_buf, 32, "match.end.%d", cnt) end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( pool, func, name_buf) # 3. 准备收集数组(用 CSizeT 数组存指针) cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases if cases_list is None: return 0 case_count: t.CSizeT = cases_list.__len__() # BB 指针数组、case 值指针数组、default 标记数组、nobreak 标记数组 bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None: return 0 collected: int = 0 has_default: int = 0 # SwitchCase 链表 sw_head: llvmlite.SwitchCase | t.CPtr = None sw_tail: llvmlite.SwitchCase | t.CPtr = None sw_count: int = 0 # 4. 第一遍:收集 case 信息 + 创建 BB + 构建链表 i: int = 0 while i < case_count: case_node: ast.AST | t.CPtr = cases_list.get(i) if case_node is None: i = i + 1 continue if case_node.kind() != ast.ASTKind.MatchCase: i = i + 1 continue mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) pat: ast.AST | t.CPtr = mc.pattern is_def: int = 0 cv: llvmlite.Value | t.CPtr = None if pat is not None: pk: int = pat.kind() if pk == ast.ASTKind.MatchClass: vnm: str = self._extract_variant_name_from_cls(pat) if vnm is not None: tag: int = HandlesClassDef._lookup_renum_variant_in_class( renum_name, vnm) if tag >= 0: tag_buf: t.CChar | t.CPtr = pool.alloc(32) if tag_buf is not None: viperlib.snprintf(tag_buf, 32, "%d", tag) cv = llvmlite.ConstInt(pool, i32_ty, tag, tag_buf if tag_buf is not None else "0") elif pk == ast.ASTKind.MatchAs: ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) if ma.pattern is None: is_def = 1 has_default = 1 elif pk == ast.ASTKind.MatchValue: mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat) cv = HandlesExpr.translate_value( builder, pool, trans.Module, mv.value, trans._funcs, trans._func_count, trans) elif pk == ast.ASTKind.MatchOr: # MatchOr: 多个值共享一个 BB(取第一个值做 case) mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat) pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns if pats is not None and pats.__len__() > 0: first_pat: ast.AST | t.CPtr = pats.get(0) if first_pat is not None: if first_pat.kind() == ast.ASTKind.MatchValue: mv2: ast.MatchValue | t.CPtr = ( ast.MatchValue | t.CPtr)(first_pat) cv = HandlesExpr.translate_value( builder, pool, trans.Module, mv2.value, trans._funcs, trans._func_count, trans) # 创建 case BB if is_def == 0: if collected >= MAX_MATCH_CASES: break viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i) bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( pool, func, name_buf) else: bb = default_bb # 检测 NoBreak body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children nb: int = self._has_no_break(body_list) # 存入数组 if collected < MAX_MATCH_CASES: bb_arr[collected] = t.CSizeT(bb) cv_arr[collected] = t.CSizeT(cv) def_arr[collected] = is_def nb_arr[collected] = nb collected = collected + 1 # 构建 SwitchCase 链表(非 default case 且有值) if is_def == 0 and cv is not None: sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case( pool, cv, bb) if sc is not None: if sw_head is None: sw_head = sc sw_tail = sc else: sw_tail.Next = sc sw_tail = sc sw_count = sw_count + 1 i = i + 1 # 5. 发射 switch 指令 llvmlite.build_switch(builder, tag_val, default_bb, sw_head, sw_count) # 6. 查找 REnum 结构体类型(用于变体字段绑定的 GEP) renum_entry: HandlesStruct.StructEntry | t.CPtr = None renum_ty: llvmlite.LLVMType | t.CPtr = None se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(renum_name) if se is not None: renum_entry = se renum_ty = se.Ty # 7. 第二遍:翻译每个 case body i = 0 while i < collected: case_node: ast.AST | t.CPtr = cases_list.get(i) if case_node is None: i = i + 1 continue mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) pat: ast.AST | t.CPtr = mc.pattern # 取 BB bb_addr: t.CSizeT = bb_arr[i] case_bb: llvmlite.BasicBlock | t.CPtr = ( llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr)) is_def: int = def_arr[i] nb: int = nb_arr[i] # default case 的 body 在 step 8 单独翻译,这里跳过避免重复 if is_def == 1: i = i + 1 continue # 定位到 case BB llvmlite.position_at_end(builder, case_bb) # 进入 case 作用域(变体字段绑定隔离) HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) # 变体字段绑定(MatchClass) if pat is not None and pat.kind() == ast.ASTKind.MatchClass: if renum_entry is not None and renum_ty is not None: self._bind_variant_fields( pat, renum_name, renum_entry, renum_ty, subject_ptr, trans, pool, builder) # 翻译 case body body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children if body_list is not None: bc: t.CSizeT = body_list.__len__() bi: int = 0 while bi < bc: stmt: ast.AST | t.CPtr = body_list.get(bi) if stmt is not None: HandlesBody.translate_stmt(trans, stmt) bi = bi + 1 # 退出 case 作用域 HandlesVar.exit_scope(trans.SymTab) # 若未终止且无 NoBreak,跳到 end if llvmlite.builder_cur_block_is_terminated(builder) == 0: if nb == 0: llvmlite.build_br(builder, end_bb) i = i + 1 # 8. 处理 default 块 llvmlite.position_at_end(builder, default_bb) if has_default == 0: # 无显式 default:default 直接跳 end if llvmlite.builder_cur_block_is_terminated(builder) == 0: llvmlite.build_br(builder, end_bb) else: # 有显式 default:翻译 default case body(找到 is_def==1 的 case) di: int = 0 while di < collected: if def_arr[di] == 1: dcase: ast.AST | t.CPtr = cases_list.get(di) if dcase is not None: dmc: ast.MatchCase | t.CPtr = ( ast.MatchCase | t.CPtr)(dcase) HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children if dbody is not None: dn: t.CSizeT = dbody.__len__() dj: int = 0 while dj < dn: stmt: ast.AST | t.CPtr = dbody.get(dj) if stmt is not None: HandlesBody.translate_stmt(trans, stmt) dj = dj + 1 HandlesVar.exit_scope(trans.SymTab) break di = di + 1 if llvmlite.builder_cur_block_is_terminated(builder) == 0: llvmlite.build_br(builder, end_bb) # 9. 定位到 end 块 llvmlite.position_at_end(builder, end_bb) return 0 # ============================================================ # _bind_variant_fields - 绑定 MatchClass 的变体字段 # # case LLVMType.Ptr(pointee) 中的 pointee 绑定到 subject 的 payload 字段 # ============================================================ def _bind_variant_fields(self, pat: ast.AST | t.CPtr, renum_name: str, renum_entry: HandlesStruct.StructEntry | t.CPtr, renum_ty: llvmlite.LLVMType | t.CPtr, subject_ptr: llvmlite.Value | t.CPtr, trans: HT.Translator | t.CPtr, pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr): if pat is None or renum_entry is None or renum_ty is None: return mc: ast.MatchClass | t.CPtr = (ast.MatchClass | t.CPtr)(pat) pats: list[ast.AST | t.CPtr] | t.CPtr = mc.patterns if pats is None: return # bitcast subject_ptr 到 renum_ptr_ty(确保 GEP 类型匹配) renum_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, renum_ty) casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( builder, subject_ptr, renum_ptr_ty) if casted_ptr is None: casted_ptr = subject_ptr pn: t.CSizeT = pats.__len__() j: int = 0 while j < pn: sub_pat: ast.AST | t.CPtr = pats.get(j) if sub_pat is not None: if sub_pat.kind() == ast.ASTKind.MatchAs: ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(sub_pat) bind_name: str = ma.name if bind_name is not None: # 按位置绑定:MatchClass 第 j 个参数 → payload 索引 j+1 # 对应 TPC HandlesMatch.py:305-306(不依赖字段名大小写匹配) payload_idx: int = j + 1 # 字段名查找作为回退(若字段名与 MatchAs 名一致可直接命中) if payload_idx >= renum_entry.FieldCount: alt_idx: int = HandlesClassDef._lookup_renum_field_alias( renum_name, bind_name) if alt_idx >= 1: payload_idx = alt_idx else: j = j + 1 continue # 获取字段类型 fe: HandlesStruct.FieldEntry | t.CPtr = ( HandlesStruct._get_field_entry( renum_entry, payload_idx)) field_ty: llvmlite.LLVMType | t.CPtr = None if fe is not None: field_ty = fe.Ty if field_ty is None: field_ty = llvmlite.Int8(pool) # GEP 取字段地址 elem_ptr: llvmlite.Value | t.CPtr = ( llvmlite.build_gep_struct( builder, renum_ty, field_ty, casted_ptr, payload_idx)) if elem_ptr is not None: HandlesVar.define_var( trans.SymTab, bind_name, elem_ptr) j = j + 1 # ============================================================ # _handle_simple_match - 非 REnum 路径 # # subject ptrtoint 到 i32 + switch 分派 # ============================================================ def _handle_simple_match(self, node: ast.Match | t.CPtr, subject_val: llvmlite.Value | t.CPtr) -> int: trans: HT.Translator | t.CPtr = self.Trans pool: memhub.MemBuddy | t.CPtr = trans.Pool builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder func: llvmlite.Function | t.CPtr = trans._cur_func # 1. subject 转 i32(若已 i32 直接用,否则 ptrtoint) i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) subj_bits: int = HandlesExpr.get_llvm_type_bits(subject_val.Ty) subj_val: llvmlite.Value | t.CPtr = subject_val if subj_bits != 32: if HandlesExpr.is_ptr_type(subject_val.Ty) != 0: subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty) elif subj_bits > 32: # trunc 到 i32 subj_val = llvmlite.build_trunc(builder, subject_val, i32_ty) elif subj_bits == 0: # 未知类型,尝试 ptrtoint subj_val = llvmlite.build_ptrtoint(builder, subject_val, i32_ty) if subj_val is None: return 0 # 2. 创建 default/end BB cnt: int = trans._label_counter trans._label_counter = cnt + 1 name_buf: t.CChar | t.CPtr = pool.alloc(32) if name_buf is None: return 0 viperlib.snprintf(name_buf, 32, "match.default.%d", cnt) default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( pool, func, name_buf) viperlib.snprintf(name_buf, 32, "match.end.%d", cnt) end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( pool, func, name_buf) # 3. 收集 case 信息 cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases if cases_list is None: return 0 case_count: t.CSizeT = cases_list.__len__() bb_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) cv_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) def_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) nb_arr: t.CInt | t.CPtr = pool.alloc(4 * MAX_MATCH_CASES) if bb_arr is None or cv_arr is None or def_arr is None or nb_arr is None: return 0 collected: int = 0 has_default: int = 0 sw_head: llvmlite.SwitchCase | t.CPtr = None sw_tail: llvmlite.SwitchCase | t.CPtr = None sw_count: int = 0 # 4. 第一遍:收集 + 创建 BB + 构建链表 i: int = 0 while i < case_count: case_node: ast.AST | t.CPtr = cases_list.get(i) if case_node is None: i = i + 1 continue if case_node.kind() != ast.ASTKind.MatchCase: i = i + 1 continue mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) pat: ast.AST | t.CPtr = mc.pattern is_def: int = 0 cv: llvmlite.Value | t.CPtr = None if pat is not None: pk: int = pat.kind() if pk == ast.ASTKind.MatchValue: mv: ast.MatchValue | t.CPtr = (ast.MatchValue | t.CPtr)(pat) cv = HandlesExpr.translate_value( builder, pool, trans.Module, mv.value, trans._funcs, trans._func_count, trans) elif pk == ast.ASTKind.MatchSingleton: ms: ast.MatchSingleton | t.CPtr = ( ast.MatchSingleton | t.CPtr)(pat) # None -> 0 cv = llvmlite.const_int32(pool, 0) elif pk == ast.ASTKind.MatchAs: ma: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) if ma.pattern is None: is_def = 1 has_default = 1 elif pk == ast.ASTKind.MatchOr: mo: ast.MatchOr | t.CPtr = (ast.MatchOr | t.CPtr)(pat) pats: list[ast.AST | t.CPtr] | t.CPtr = mo.patterns if pats is not None and pats.__len__() > 0: first_pat: ast.AST | t.CPtr = pats.get(0) if first_pat is not None: if first_pat.kind() == ast.ASTKind.MatchValue: mv2: ast.MatchValue | t.CPtr = ( ast.MatchValue | t.CPtr)(first_pat) cv = HandlesExpr.translate_value( builder, pool, trans.Module, mv2.value, trans._funcs, trans._func_count, trans) if is_def == 0: if collected >= MAX_MATCH_CASES: break viperlib.snprintf(name_buf, 32, "match.case.%d.%d", cnt, i) bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( pool, func, name_buf) else: bb = default_bb body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children nb: int = self._has_no_break(body_list) if collected < MAX_MATCH_CASES: bb_arr[collected] = t.CSizeT(bb) cv_arr[collected] = t.CSizeT(cv) def_arr[collected] = is_def nb_arr[collected] = nb collected = collected + 1 if is_def == 0 and cv is not None: sc: llvmlite.SwitchCase | t.CPtr = llvmlite.new_switch_case( pool, cv, bb) if sc is not None: if sw_head is None: sw_head = sc sw_tail = sc else: sw_tail.Next = sc sw_tail = sc sw_count = sw_count + 1 i = i + 1 # 5. 发射 switch llvmlite.build_switch(builder, subj_val, default_bb, sw_head, sw_count) # 6. 第二遍:翻译 case body i = 0 while i < collected: case_node: ast.AST | t.CPtr = cases_list.get(i) if case_node is None: i = i + 1 continue mc: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(case_node) bb_addr: t.CSizeT = bb_arr[i] case_bb: llvmlite.BasicBlock | t.CPtr = ( llvmlite.BasicBlock | t.CPtr)(t.CVoid(bb_addr, t.CPtr)) is_def: int = def_arr[i] nb: int = nb_arr[i] # default case 的 body 在 step 7 单独翻译,这里跳过避免重复 if is_def == 1: i = i + 1 continue llvmlite.position_at_end(builder, case_bb) HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children if body_list is not None: bc: t.CSizeT = body_list.__len__() bi: int = 0 while bi < bc: stmt: ast.AST | t.CPtr = body_list.get(bi) if stmt is not None: HandlesBody.translate_stmt(trans, stmt) bi = bi + 1 HandlesVar.exit_scope(trans.SymTab) if llvmlite.builder_cur_block_is_terminated(builder) == 0: if nb == 0: llvmlite.build_br(builder, end_bb) i = i + 1 # 7. default 块 llvmlite.position_at_end(builder, default_bb) if has_default == 0: if llvmlite.builder_cur_block_is_terminated(builder) == 0: llvmlite.build_br(builder, end_bb) else: di: int = 0 while di < collected: if def_arr[di] == 1: dcase: ast.AST | t.CPtr = cases_list.get(di) if dcase is not None: dmc: ast.MatchCase | t.CPtr = ( ast.MatchCase | t.CPtr)(dcase) HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH) dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children if dbody is not None: dn: t.CSizeT = dbody.__len__() dj: int = 0 while dj < dn: stmt: ast.AST | t.CPtr = dbody.get(dj) if stmt is not None: HandlesBody.translate_stmt(trans, stmt) dj = dj + 1 HandlesVar.exit_scope(trans.SymTab) break di = di + 1 if llvmlite.builder_cur_block_is_terminated(builder) == 0: llvmlite.build_br(builder, end_bb) # 8. 定位到 end llvmlite.position_at_end(builder, end_bb) return 0 # ============================================================ # NewMatchHandle - 工厂函数 # ============================================================ def NewMatchHandle(pool: memhub.MemBuddy | t.CPtr, trans: HT.Translator | t.CPtr) -> MatchHandle | t.CPtr: h: MatchHandle | t.CPtr = pool.alloc(MatchHandle.__sizeof__()) if h is None: return None string.memset(h, 0, MatchHandle.__sizeof__()) h.Trans = trans return h