diff --git a/App/lib/core/Gen/MatchGenMixin.vp b/App/lib/core/Gen/MatchGenMixin.vp index d33bc31..df96740 100644 --- a/App/lib/core/Gen/MatchGenMixin.vp +++ b/App/lib/core/Gen/MatchGenMixin.vp @@ -1,1304 +1,1307 @@ -import lib.core.Gen.GenTypes as GenTypes -import lib.core.Gen.Generator as Generator -import t, c -from stdint import * -import ast -import llvmlite -import memhub -import string -import viperlib -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesExpr as HandlesExpr - - -# ============================================================ -# MatchGenMixin - match 语句翻译 Mixin(P6 方法化) -# -# 从 HandlesMatch.vp 的 MatchHandle 类迁移(纯移动,逻辑零改动): -# Handle → translate_match(签名加 trans 首参,方法体 self.Trans → trans) -# 类内辅助方法 self._xxx → 保持 self.xxx,一并搬入成方法 -# 模块级辅助函数 _case_tail_unreachable → 搬入成方法 -# (原 HandlesMatch 模块级常量 MAX_MATCH_CASES/SCOPE_MATCH 一并复制) -# -# 迁移原则(与 P1-P6 一致,行为零变化): -# 1. 方法保留原逻辑,仅函数体内的 self.Trans 改为 trans 首参 -# 2. 外部模块调用(HandlesExpr.xxx/HandlesBody.xxx 等)保留模块前缀 -# 3. 原 HandlesMatch.translate_match 保留为"委托":本地模块级单例 _g_gen -# (BuildPipeline/main 注入)cast 成 Generator 类型 -# -# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 -# ============================================================ - - -# match case 数量上限(原 HandlesMatch.MAX_MATCH_CASES) -MAX_MATCH_CASES: t.CDefine = 32 - -# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分,原 HandlesMatch.SCOPE_MATCH) -SCOPE_MATCH: t.CDefine = 6 - - -@t.NoVTable -class MatchGenMixin: - """match 语句翻译 Mixin(P6 方法化)""" - - # ============================================================ - # _case_tail_unreachable - case 体末尾结构性不可达判定 - # - # case 体翻译后当前块若未终止,且末句是控制流语句(If/While/For/Match) - # 且其 merge 结构性不可达(全分支 return,如 case Int(bits): if ... return) - # 时,当前块是控制流的 merge(无 terminator),与 HandlesIf L309-315/ - # ClassGenVTable L1084 同语义补 unreachable。返回 1= 已补 unreachable - # (调用方不应 br end_bb);0= 正常收尾(应 br end_bb)。 - # - # 根因(ClassGenEnum._get_type_align):case 体末句 If 全 return 时,If - # 处理器把 builder 停在无 terminator 的 merge 块,case 循环的 - # is_terminated 检查误判"未终止" → 补 br end_bb → rm_merge_reach=1 → - # 全 case return 的 match 被误判 merge 可达 → 函数收尾 fail-fast - # "流程掉出末尾"。不含 Try/With:其处理器不维护 _ctrl_merge_reachable, - # 避免残留值误判。 - # ============================================================ - Gen: Generator.Generator | t.CPtr - def _case_tail_unreachable(self, trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - body_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: - if trans is None or builder is None: - return 0 - if llvmlite.builder_cur_block_is_terminated(builder) != 0: - return 0 - if body_list is None or len(body_list) == 0: - return 0 - lst: ast.AST | t.CPtr = body_list.get(len(body_list) - 1) - if lst is None: - return 0 - lk: int = lst.kind() - if lk != ast.ASTKind.If and lk != ast.ASTKind.While \ - and lk != ast.ASTKind.For and lk != ast.ASTKind.Match: - return 0 - if trans._ctrl_merge_reachable != 0: - return 0 - llvmlite.build_unreachable(builder) - return 1 - - # ============================================================ - # translate_match - match 语句主入口,返回 0 - # (迁移自 HandlesMatch.MatchHandle.Handle) - # ============================================================ - def translate_match(self, trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - if node is None: - return 0 - 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 - - # 追加90:match merge 可达性重置(分派前初始化为 0;各处理函数 - # renum/sequence/simple 内部用各自的局部标志记录 br end_bb 并在 - # 收尾覆盖,见 _handle_renum_match/_handle_sequence_match/ - # _handle_simple_match——切勿把标志声明在 Handle 这里(分派函数), - # 否则子函数引用的同名变量会退化为隐式全局,跨 match 互相污染)。 - trans._ctrl_merge_reachable = 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 - # 序列匹配(match (a, b): case (x, y): ...)走独立路径: - # Tuple/List subject 无法用 translate_value 求值(会返回 None), - # 提前分派到 _handle_sequence_match,避免 fail-fast 误报。 - sk_seq: int = subject_node.kind() - if sk_seq == ast.ASTKind.Tuple or sk_seq == ast.ASTKind.List: - return self._handle_sequence_match(trans, m_node, subject_node) - subject_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, trans.Module, subject_node, - trans._funcs, trans._func_count, trans) - if subject_val is None: - # fail-fast: match subject 翻译失败 - self.Gen.TypeGenErr.fatal_error(subject_node, "match subject 翻译失败", "TypeError") - - # 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: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( - trans.SymTab, nm.id) - if entry is not None and entry.AnnotClassName is not None \ - and self.Gen.ClassGenEnum._is_renum_class_name( - entry.AnnotClassName) != 0: - is_renum = 1 - renum_name = entry.AnnotClassName - subject_ptr = self.Gen.VarGen.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 = len(cases_list) - 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 \ - and 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 \ - and pat.kind() == ast.ASTKind.MatchClass: - rnm: str = self._extract_renum_name_from_cls(pat) - if rnm is not None \ - and self.Gen.ClassGenEnum._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(trans, m_node, renum_name, subject_ptr) - return self._handle_simple_match(trans, 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 类名 - # - # P5-2 后 REnum 变体表迁入 gen 字段(RenumClassNames/RenumClassCount), - # 模块级 _renum_class_* 已失效,统一委托到 gen._lookup_renum_variant。 - # ============================================================ - def _find_renum_class_for_variant(self, variant_name: str) -> str: - if variant_name is None: - return None - return self.Gen.ClassGenEnum._lookup_renum_variant(variant_name) - - # ============================================================ - # _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 = len(body_list) - i: int = 0 - while i < n: - stmt: ast.AST | t.CPtr = body_list.get(i) - if stmt is not None and 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 \ - and 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 \ - and string.strcmp(base_nm.id, "c") == 0 \ - and at.attr is not None \ - and 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, trans: HT.Translator | t.CPtr, - node: ast.Match | t.CPtr, - renum_name: str, - subject_ptr: llvmlite.Value | t.CPtr) -> int: - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - # 局部记录本 renum match 是否有 br 进入 end_bb,收尾时覆盖 - # _ctrl_merge_reachable(case 体内嵌套 If 无 else + return 会把全局 - # 标志置 1,全 case return 的 match 被误判 merge 可达 → 函数收尾 - # fail-fast "流程掉出末尾"。声明必须在本函数内——放 Handle 分派 - # 函数里会使本函数引用退化为隐式全局,跨 match 污染)。 - rm_merge_reach: int = 0 - - # 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 self.Gen.ExprGenBase.is_ptr_type(subj_ty) != 0 \ - and subj_ty.Pointee is not None \ - and self.Gen.ExprGenBase.is_ptr_type(subj_ty.Pointee) != 0: - # 情况1: T** → load 一次得 T* - loaded_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, subj_ty.Pointee, 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 self.Gen.ExprGenBase.is_ptr_type(subject_ptr.Ty) == 0: - renum_se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.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: - # fail-fast: REnum 结构体未注册,无法构造 - self.Gen.TypeGenErr.fatal_error( - node, - f"REnum 结构体 '{renum_name}' 未注册", - "NameError") - 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 self.Gen.ExprGenBase.get_llvm_type_bits(subj_ty) != 64 \ - and self.Gen.ExprGenBase.is_ptr_type(subj_ty) == 0: - if self.Gen.ExprGenBase.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: - # fail-fast: REnum tag 指针转换失败 - self.Gen.TypeGenErr.fatal_error(node, "REnum tag 指针转换失败", "TypeError") - tag_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i32_ty, tag_ptr) - if tag_val is None: - # fail-fast: REnum tag 读取失败 - self.Gen.TypeGenErr.fatal_error(node, "REnum tag 读取失败", "TypeError") - - # 2. 创建 default/end BB - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - if name_buf is None: - # fail-fast: 标签缓冲区分配失败 - self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError") - 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: - # fail-fast: match cases 缺失 - self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError") - case_count: t.CSizeT = len(cases_list) - - # 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: - # fail-fast: match 分派数组分配失败 - self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError") - - 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 = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( - renum_name, vnm) - if tag >= 0: - tag_buf: str = 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 = self.Gen.ExprGen.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 len(pats) > 0: - first_pat: ast.AST | t.CPtr = pats.get(0) - if first_pat is not None \ - and first_pat.kind() == ast.ASTKind.MatchValue: - mv2: ast.MatchValue | t.CPtr = ( - ast.MatchValue | t.CPtr)(first_pat) - cv = self.Gen.ExprGen.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: GenTypes.StructEntry | t.CPtr = None - renum_ty: llvmlite.LLVMType | t.CPtr = None - se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.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 作用域(变体字段绑定隔离) - self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) - - # 变体字段绑定(MatchClass) - if pat is not None and pat.kind() == ast.ASTKind.MatchClass \ - and 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 = len(body_list) - bi: int = 0 - while bi < bc: - stmt: ast.AST | t.CPtr = body_list.get(bi) - if stmt is not None: - self.Gen.StmtGen.translate_stmt(trans, stmt) - bi = bi + 1 - - # 退出 case 作用域 - self.Gen.VarGen.exit_scope(trans.SymTab) - - # 若未终止且无 NoBreak,跳到 end - # 末句控制流全 return(结构性不可达)时补 unreachable,不 br end_bb - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and nb == 0 \ - and self._case_tail_unreachable(trans, builder, body_list) == 0: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - rm_merge_reach = 1 - - 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) - trans._ctrl_merge_reachable = 1 - rm_merge_reach = 1 - else: - # 有显式 default:翻译 default case body(找到 is_def==1 的 case) - dbody: list[ast.AST | t.CPtr] | t.CPtr = None - 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) - self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) - dbody = dmc.children - if dbody is not None: - dn: t.CSizeT = len(dbody) - dj: int = 0 - while dj < dn: - stmt: ast.AST | t.CPtr = dbody.get(dj) - if stmt is not None: - self.Gen.StmtGen.translate_stmt(trans, stmt) - dj = dj + 1 - self.Gen.VarGen.exit_scope(trans.SymTab) - break - di = di + 1 - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and self._case_tail_unreachable(trans, builder, dbody) == 0: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - rm_merge_reach = 1 - - # 9. 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 用本 match 自身的 br 记录覆盖,消除 case 体内嵌套控制流对 - # _ctrl_merge_reachable 的污染(全 case return 时应为不可达) - trans._ctrl_merge_reachable = rm_merge_reach - 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: GenTypes.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 = len(pats) - j: int = 0 - while j < pn: - sub_pat: ast.AST | t.CPtr = pats.get(j) - if sub_pat is not None and 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: - # class_name 用 CSizeT 指针值比较:必须传 renum_entry.Name - # (注册时 _update_renum_alias_class_ptr 统一后的 perm_pool - # 指针);renum_name(AnnotClassName 等)是不同指针恒不匹配 - # → 恒 -1 → fail-fast 误报(追加73d 同款指针陷阱) - alt_idx: int = self.Gen.ClassGenEnum._lookup_renum_field_alias( - renum_entry.Name, bind_name) - if alt_idx >= 1: - payload_idx = alt_idx - else: - # fail-fast: payload 越界且别名查找失败 - # (node 在本函数不存在——参数是 pat/sub_pat,用 sub_pat - # 定位到具体 MatchAs 模式;TPC Python 语义下未定义名只在 - # 运行时求值才报错,TPV 惰性编译方法体时即 NameError) - self.Gen.TypeGenErr.fatal_error( - sub_pat, - f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败", - "TypeError") - # 获取字段类型 - fe: GenTypes.FieldEntry | t.CPtr = ( - self.Gen.StructGen._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: - # fail-fast: 变体字段类型缺失,禁止兜底 i8 - self.Gen.TypeGenErr.fatal_error( - sub_pat, - f"REnum 变体字段类型缺失: {bind_name}", - "TypeError") - # GEP 取字段地址 - elem_ptr: llvmlite.Value | t.CPtr = ( - llvmlite.build_gep_struct( - builder, renum_ty, field_ty, - casted_ptr, payload_idx)) - if elem_ptr is None: - # fail-fast: 变体字段地址计算失败 - self.Gen.TypeGenErr.fatal_error( - sub_pat, - f"REnum 变体字段 '{bind_name}' 地址计算失败", - "TypeError") - # 变体成员实际类型(对齐 TPC class_members L300-307/L376-382): - # 注册时别名表存了成员注解解析出的类型(perm_pool 深拷贝)。 - # 用它把槽位地址 bitcast 成 Ptr(成员类型),使绑定变量按成员 - # 类型读 payload——Struct.Name: t.CChar|t.CPtr = i8*,否则按 - # 槽位 i64 读 → is 比较/下标/strlen 等字符串操作翻译失败 - # (CallGenMixin L4631 type_name_sp is not None 根因)。 - # 注意:必须按 (class, 变体名, 位置) 定位——MatchAs 名是局部 - # 变量名(type_name_sp),不是变体字段名(Name),按字段名 - # 查恒不匹配(追加76 第一次修复失效根因);同一 payload 位置 - # 跨变体类型也不同(Int.Bits=i32 vs Struct.Fields=Ptr)。 - # 自引用类型(如 Pointee: LLVMType|t.CPtr)注册期解析失败 → - # 查不到类型 → 回退槽位类型(原始位宽在嵌套 match 中经 - # subject bitcast 仍可用)。 - mem_ty_m: llvmlite.LLVMType | t.CPtr = None - vnt_m: str = self._extract_variant_name_from_cls(pat) - if vnt_m is not None and renum_entry is not None \ - and renum_entry.Name is not None: - mem_ty_m = self.Gen.ClassGenEnum._lookup_renum_member_ty( - renum_entry.Name, vnt_m, payload_idx) - if mem_ty_m is not None: - mem_ptr_m: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, mem_ty_m) - if mem_ptr_m is not None: - cast_m: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, elem_ptr, mem_ptr_m) - if cast_m is not None: - elem_ptr = cast_m - self.Gen.VarGen.define_var( - trans.SymTab, bind_name, elem_ptr) - j = j + 1 - - # ============================================================ - # _seq_cmp_eq - 序列匹配元素相等比较 - # - # 对齐 lhs/rhs(指针统一 ptrtoint i64,整数位宽统一到较宽者)后 - # 生成 icmp eq,返回 i1 条件。 - # ============================================================ - def _seq_cmp_eq(self, trans: HT.Translator | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - lhs: llvmlite.Value | t.CPtr, - rhs: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """对齐 lhs/rhs 后生成 icmp eq(指针统一 ptrtoint i64)""" - if lhs is None or rhs is None or builder is None: - return None - pool: memhub.MemBuddy | t.CPtr = trans.Pool - if self.Gen.ExprGenBase.is_ptr_type(lhs.Ty) != 0 \ - or self.Gen.ExprGenBase.is_ptr_type(rhs.Ty) != 0: - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - if self.Gen.ExprGenBase.is_ptr_type(lhs.Ty) != 0: - lhs = llvmlite.build_ptrtoint(builder, lhs, i64_ty) - if self.Gen.ExprGenBase.is_ptr_type(rhs.Ty) != 0: - rhs = llvmlite.build_ptrtoint(builder, rhs, i64_ty) - lb: int = self.Gen.ExprGenBase.get_llvm_type_bits(lhs.Ty) - rb: int = self.Gen.ExprGenBase.get_llvm_type_bits(rhs.Ty) - if lb != rb and lb != 0 and rb != 0: - if lb < rb: - if lb == 1: - lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) - else: - lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) - else: - if rb == 1: - rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) - else: - rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) - return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, lhs, rhs) - - # ============================================================ - # _handle_sequence_match - 序列匹配(match (a, b): case (x, y): ...) - # - # subject 是 Tuple/List、case 是 MatchSequence 时走此路径(对齐 Python - # 语义,按声明顺序取首个全部元素匹配且 guard 为真的 case 执行): - # 元素 pattern: - # MatchValue v → subject[i] == v - # MatchAs(pattern=None) → _ 通配(恒真) - # MatchStar → 剩余元素通配(恒真) - # IR 结构(check/body 链): - # entry → check0 - # check_i: 匹配条件 → body_i(不满足 → check_{i+1}) - # body_i: → end(c.NoBreak 时 fallthrough 到下一 case body) - # 全不匹配 → default → end - # ============================================================ - def _handle_sequence_match(self, trans: HT.Translator | t.CPtr, - node: ast.Match | t.CPtr, - subject_node: ast.AST | t.CPtr) -> int: - 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 - # 同主路径:局部记录本 sequence match 的 br end_bb,收尾覆盖 - # _ctrl_merge_reachable,消除 case 体内嵌套控制流污染 - sq_merge_reach: int = 0 - - # 1. 求值 subject 各元素 - elts: list[ast.AST | t.CPtr] | t.CPtr = None - if subject_node.kind() == ast.ASTKind.Tuple: - st: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(subject_node) - if st is not None: - elts = st.elts - elif subject_node.kind() == ast.ASTKind.List: - sl2: ast.List | t.CPtr = (ast.List | t.CPtr)(subject_node) - if sl2 is not None: - elts = sl2.elts - if elts is None: - return 0 - ecount: t.CSizeT = len(elts) - if ecount == 0: - return 0 - subj_vals: t.CSizeT | t.CPtr = pool.alloc(8 * ecount) - if subj_vals is None: - return 0 - for ei in range(ecount): - elt: ast.AST | t.CPtr = elts.get(ei) - sv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, trans.Module, elt, - trans._funcs, trans._func_count, trans) - if sv is None: - self.Gen.TypeGenErr.fatal_error( - elt, f"match 序列元素 {ei} 翻译失败", "TypeError") - subj_vals[ei] = t.CSizeT(sv) - - # 2. 创建 default/end BB - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - if name_buf is None: - return 0 - viperlib.snprintf(name_buf, 32, "match.seq.default.%d", cnt) - default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "match.seq.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - - # 3. 第一遍:收集 case 信息(check/body BB、default 标记、nobreak、guard) - cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases - if cases_list is None: - return 0 - case_count: t.CSizeT = len(cases_list) - check_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) - body_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) - guard_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) - if check_arr is None or body_arr is None or def_arr is None \ - or nb_arr is None or guard_arr is None: - return 0 - collected: int = 0 - has_default: int = 0 - first_check: int = -1 - i: int = 0 - while i < case_count: - case_node: ast.AST | t.CPtr = cases_list.get(i) - if case_node is None or 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 - if pat is not None: - pk: int = pat.kind() - if pk == ast.ASTKind.MatchAs: - ma0: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) - if ma0.pattern is None: - is_def = 1 - elif pk != ast.ASTKind.MatchSequence: - # fail-fast:序列匹配只接受 MatchSequence / 顶层 _ 通配 - self.Gen.TypeGenErr.fatal_error( - pat, "序列匹配 case 只支持 (元素) 或 _ 模式", "TypeError") - if is_def == 1: - has_default = 1 - check_arr[collected] = 0 - body_arr[collected] = t.CSizeT(default_bb) - else: - if collected >= MAX_MATCH_CASES: - break - viperlib.snprintf(name_buf, 32, "match.seq.check.%d.%d", cnt, i) - cbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "match.seq.body.%d.%d", cnt, i) - bbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, func, name_buf) - check_arr[collected] = t.CSizeT(cbb) - body_arr[collected] = t.CSizeT(bbb) - if first_check < 0: - first_check = collected - body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children - nb: int = self._has_no_break(body_list) - def_arr[collected] = is_def - nb_arr[collected] = nb - guard_arr[collected] = t.CSizeT(mc.guard) - collected = collected + 1 - i = i + 1 - - # 4. 入口 → 第一个 check(或 default/end) - if first_check >= 0: - head_bb: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)( - t.CVoid(check_arr[first_check], t.CPtr)) - llvmlite.build_br(builder, head_bb) - elif has_default == 1: - llvmlite.build_br(builder, default_bb) - else: - llvmlite.build_br(builder, end_bb) - - # 5. 发射 check 链 - ci: int = 0 - while ci < collected: - if def_arr[ci] == 1: - ci = ci + 1 - continue - cbb2: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)( - t.CVoid(check_arr[ci], t.CPtr)) - bbb2: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)( - t.CVoid(body_arr[ci], t.CPtr)) - llvmlite.position_at_end(builder, cbb2) - - # 计算匹配条件(元素比较 && guard) - cond: llvmlite.Value | t.CPtr = None - cnode: ast.AST | t.CPtr = cases_list.get(ci) - mc2: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(cnode) - ms: ast.MatchSequence | t.CPtr = ( - ast.MatchSequence | t.CPtr)(mc2.pattern) - pats: list[ast.AST | t.CPtr] | t.CPtr = None - if ms is not None: - pats = ms.patterns - pcount: t.CSizeT = 0 - if pats is not None: - pcount = len(pats) - if pcount != ecount: - # 元素数量不匹配 → 恒假(对齐 Python 语义) - cond = llvmlite.const_int(pool, 1, 0) - else: - for pi in range(ecount): - pat1: ast.AST | t.CPtr = pats.get(pi) - if pat1 is None: - continue - pk1: int = pat1.kind() - if pk1 == ast.ASTKind.MatchValue: - mv: ast.MatchValue | t.CPtr = ( - ast.MatchValue | t.CPtr)(pat1) - pv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, trans.Module, mv.value, - trans._funcs, trans._func_count, trans) - if pv is None: - self.Gen.TypeGenErr.fatal_error( - pat1, f"序列模式元素 {pi} 翻译失败", "TypeError") - sv1: llvmlite.Value | t.CPtr = ( - llvmlite.Value | t.CPtr)( - t.CVoid(subj_vals[pi], t.CPtr)) - c1: llvmlite.Value | t.CPtr = self._seq_cmp_eq( - trans, builder, sv1, pv) - if c1 is None: - self.Gen.TypeGenErr.fatal_error( - pat1, "序列模式元素比较失败", "TypeError") - if cond is None: - cond = c1 - else: - cond = llvmlite.build_and(builder, cond, c1) - elif pk1 == ast.ASTKind.MatchAs: - ma2: ast.MatchAs | t.CPtr = ( - ast.MatchAs | t.CPtr)(pat1) - if ma2.pattern is None: - continue # _ 通配:恒真 - if ma2.name is not None: - # fail-fast:序列模式变量绑定暂不支持 - self.Gen.TypeGenErr.fatal_error( - pat1, "序列模式变量绑定暂不支持", "NotImplementedError") - elif pk1 == ast.ASTKind.MatchStar: - continue # 剩余元素通配:恒真 - else: - self.Gen.TypeGenErr.fatal_error( - pat1, "序列模式不支持的 pattern 类型", "TypeError") - # guard(若有):匹配成立且 guard 非零 - g_addr: t.CSizeT = guard_arr[ci] - if g_addr != 0: - gnode: ast.AST | t.CPtr = ( - ast.AST | t.CPtr)(t.CVoid(g_addr, t.CPtr)) - gv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( - builder, pool, trans.Module, gnode, - trans._funcs, trans._func_count, trans) - if gv is None: - self.Gen.TypeGenErr.fatal_error( - gnode, "match guard 翻译失败", "TypeError") - gbits: int = self.Gen.ExprGenBase.get_llvm_type_bits(gv.Ty) - if gbits == 1: - g1: llvmlite.Value | t.CPtr = gv - else: - gzero: llvmlite.Value | t.CPtr = llvmlite.const_int( - pool, gbits if gbits > 0 else 32, 0) - g1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, gv, gzero) - if cond is None: - cond = g1 - else: - cond = llvmlite.build_and(builder, cond, g1) - if cond is None: - cond = llvmlite.const_int(pool, 1, 1) - - # 下一个 check(或 default/end) - nxt: llvmlite.BasicBlock | t.CPtr = None - nj: int = ci + 1 - while nj < collected and def_arr[nj] == 1: - nj = nj + 1 - if nj < collected: - nxt = (llvmlite.BasicBlock | t.CPtr)( - t.CVoid(check_arr[nj], t.CPtr)) - elif has_default == 1: - nxt = default_bb - else: - nxt = end_bb - llvmlite.build_cond_br(builder, cond, bbb2, nxt) - ci = ci + 1 - - # 6. 翻译 case body - ci = 0 - while ci < collected: - if def_arr[ci] == 1: - ci = ci + 1 - continue - bbb3: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)( - t.CVoid(body_arr[ci], t.CPtr)) - llvmlite.position_at_end(builder, bbb3) - cnode2: ast.AST | t.CPtr = cases_list.get(ci) - mc3: ast.MatchCase | t.CPtr = ( - ast.MatchCase | t.CPtr)(cnode2) - self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) - body_list2: list[ast.AST | t.CPtr] | t.CPtr = mc3.children - if body_list2 is not None: - bc: t.CSizeT = len(body_list2) - bi: int = 0 - while bi < bc: - stmt: ast.AST | t.CPtr = body_list2.get(bi) - if stmt is not None: - self.Gen.StmtGen.translate_stmt(trans, stmt) - bi = bi + 1 - self.Gen.VarGen.exit_scope(trans.SymTab) - # 末句控制流全 return → 补 unreachable(不 br end,无 fallthrough) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and self._case_tail_unreachable(trans, builder, body_list2) == 0: - if nb_arr[ci] == 0: - llvmlite.build_br(builder, end_bb) - else: - # c.NoBreak:fallthrough 到下一个 case body(跳过模式检查) - nj2: int = ci + 1 - while nj2 < collected and def_arr[nj2] == 1: - nj2 = nj2 + 1 - if nj2 < collected: - nbb: llvmlite.BasicBlock | t.CPtr = ( - llvmlite.BasicBlock | t.CPtr)( - t.CVoid(body_arr[nj2], t.CPtr)) - llvmlite.build_br(builder, nbb) - elif has_default == 1: - llvmlite.build_br(builder, default_bb) - else: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - sq_merge_reach = 1 - ci = ci + 1 - - # 7. default 块 - llvmlite.position_at_end(builder, default_bb) - dbody: list[ast.AST | t.CPtr] | t.CPtr = None - if has_default == 1: - di: int = 0 - while di < collected: - if def_arr[di] == 1: - dnode: ast.AST | t.CPtr = cases_list.get(di) - if dnode is not None: - dmc: ast.MatchCase | t.CPtr = ( - ast.MatchCase | t.CPtr)(dnode) - self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) - dbody = dmc.children - if dbody is not None: - dn: t.CSizeT = len(dbody) - dj: int = 0 - while dj < dn: - stmt: ast.AST | t.CPtr = dbody.get(dj) - if stmt is not None: - self.Gen.StmtGen.translate_stmt(trans, stmt) - dj = dj + 1 - self.Gen.VarGen.exit_scope(trans.SymTab) - break - di = di + 1 - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and self._case_tail_unreachable(trans, builder, dbody) == 0: - llvmlite.build_br(builder, end_bb) - sq_merge_reach = 1 - - # 8. 定位到 end - llvmlite.position_at_end(builder, end_bb) - # 覆盖嵌套控制流污染(同主路径) - trans._ctrl_merge_reachable = sq_merge_reach - return 0 - - # ============================================================ - # _handle_simple_match - 非 REnum 路径 - # - # subject ptrtoint 到 i32 + switch 分派 - # ============================================================ - def _handle_simple_match(self, trans: HT.Translator | t.CPtr, - node: ast.Match | t.CPtr, - subject_val: llvmlite.Value | t.CPtr) -> int: - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - func: llvmlite.Function | t.CPtr = trans._cur_func - # 同主路径:局部记录本 simple match 的 br end_bb,收尾覆盖 - # _ctrl_merge_reachable,消除 case 体内嵌套控制流污染 - sm_merge_reach: int = 0 - - # 1. subject 转 i32(若已 i32 直接用,否则 ptrtoint) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - subj_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(subject_val.Ty) - subj_val: llvmlite.Value | t.CPtr = subject_val - if subj_bits != 32: - if self.Gen.ExprGenBase.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: - # fail-fast: subject 转 i32 失败 - self.Gen.TypeGenErr.fatal_error(node, "match subject 转换为 i32 失败", "TypeError") - - # 2. 创建 default/end BB - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - if name_buf is None: - # fail-fast: 标签缓冲区分配失败 - self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError") - 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: - # fail-fast: match cases 缺失 - self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError") - case_count: t.CSizeT = len(cases_list) - - 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: - # fail-fast: match 分派数组分配失败 - self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError") - - 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 = self.Gen.ExprGen.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 len(pats) > 0: - first_pat: ast.AST | t.CPtr = pats.get(0) - if first_pat is not None \ - and first_pat.kind() == ast.ASTKind.MatchValue: - mv2: ast.MatchValue | t.CPtr = ( - ast.MatchValue | t.CPtr)(first_pat) - cv = self.Gen.ExprGen.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) - - self.Gen.VarGen.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 = len(body_list) - bi: int = 0 - while bi < bc: - stmt: ast.AST | t.CPtr = body_list.get(bi) - if stmt is not None: - self.Gen.StmtGen.translate_stmt(trans, stmt) - bi = bi + 1 - - self.Gen.VarGen.exit_scope(trans.SymTab) - - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and nb == 0 \ - and self._case_tail_unreachable(trans, builder, body_list) == 0: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - sm_merge_reach = 1 - - 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) - trans._ctrl_merge_reachable = 1 - sm_merge_reach = 1 - else: - dbody: list[ast.AST | t.CPtr] | t.CPtr = None - 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) - self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) - dbody = dmc.children - if dbody is not None: - dn: t.CSizeT = len(dbody) - dj: int = 0 - while dj < dn: - stmt: ast.AST | t.CPtr = dbody.get(dj) - if stmt is not None: - self.Gen.StmtGen.translate_stmt(trans, stmt) - dj = dj + 1 - self.Gen.VarGen.exit_scope(trans.SymTab) - break - di = di + 1 - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and self._case_tail_unreachable(trans, builder, dbody) == 0: - llvmlite.build_br(builder, end_bb) - trans._ctrl_merge_reachable = 1 - sm_merge_reach = 1 - - # 8. 定位到 end - llvmlite.position_at_end(builder, end_bb) - # 覆盖嵌套控制流污染(同主路径) - trans._ctrl_merge_reachable = sm_merge_reach - return 0 +import lib.core.Gen.GenTypes as GenTypes +import lib.core.Gen.Generator as Generator +import t, c +from stdint import * +import ast +import llvmlite +import memhub +import string +import viperlib +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesExpr as HandlesExpr + + +# ============================================================ +# MatchGenMixin - match 语句翻译 Mixin(P6 方法化) +# +# 从 HandlesMatch.vp 的 MatchHandle 类迁移(纯移动,逻辑零改动): +# Handle → translate_match(签名加 trans 首参,方法体 self.Trans → trans) +# 类内辅助方法 self._xxx → 保持 self.xxx,一并搬入成方法 +# 模块级辅助函数 _case_tail_unreachable → 搬入成方法 +# (原 HandlesMatch 模块级常量 MAX_MATCH_CASES/SCOPE_MATCH 一并复制) +# +# 迁移原则(与 P1-P6 一致,行为零变化): +# 1. 方法保留原逻辑,仅函数体内的 self.Trans 改为 trans 首参 +# 2. 外部模块调用(HandlesExpr.xxx/HandlesBody.xxx 等)保留模块前缀 +# 3. 原 HandlesMatch.translate_match 保留为"委托":本地模块级单例 _g_gen +# (BuildPipeline/main 注入)cast 成 Generator 类型 +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# match case 数量上限(原 HandlesMatch.MAX_MATCH_CASES) +MAX_MATCH_CASES: t.CDefine = 32 + +# 作用域种类常量(与 HandlesVar 的 Scope.Kind 区分,原 HandlesMatch.SCOPE_MATCH) +SCOPE_MATCH: t.CDefine = 6 + + +@t.NoVTable +class MatchGenMixin: + """match 语句翻译 Mixin(P6 方法化)""" + + # ============================================================ + # _case_tail_unreachable - case 体末尾结构性不可达判定 + # + # case 体翻译后当前块若未终止,且末句是控制流语句(If/While/For/Match) + # 且其 merge 结构性不可达(全分支 return,如 case Int(bits): if ... return) + # 时,当前块是控制流的 merge(无 terminator),与 HandlesIf L309-315/ + # ClassGenVTable L1084 同语义补 unreachable。返回 1= 已补 unreachable + # (调用方不应 br end_bb);0= 正常收尾(应 br end_bb)。 + # + # 根因(ClassGenEnum._get_type_align):case 体末句 If 全 return 时,If + # 处理器把 builder 停在无 terminator 的 merge 块,case 循环的 + # is_terminated 检查误判"未终止" → 补 br end_bb → rm_merge_reach=1 → + # 全 case return 的 match 被误判 merge 可达 → 函数收尾 fail-fast + # "流程掉出末尾"。不含 Try/With:其处理器不维护 _ctrl_merge_reachable, + # 避免残留值误判。 + # ============================================================ + Gen: Generator.Generator | t.CPtr + def _case_tail_unreachable(self, trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + body_list: list[ast.AST | t.CPtr] | t.CPtr) -> int: + if trans is None or builder is None: + return 0 + if llvmlite.builder_cur_block_is_terminated(builder) != 0: + return 0 + if body_list is None or len(body_list) == 0: + return 0 + lst: ast.AST | t.CPtr = body_list.get(len(body_list) - 1) + if lst is None: + return 0 + lk: int = lst.kind() + if lk != ast.ASTKind.If and lk != ast.ASTKind.While \ + and lk != ast.ASTKind.For and lk != ast.ASTKind.Match: + return 0 + if trans._ctrl_merge_reachable != 0: + return 0 + llvmlite.build_unreachable(builder) + return 1 + + # ============================================================ + # translate_match - match 语句主入口,返回 0 + # (迁移自 HandlesMatch.MatchHandle.Handle) + # ============================================================ + def translate_match(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + if node is None: + return 0 + 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 + + # 追加90:match merge 可达性重置(分派前初始化为 0;各处理函数 + # renum/sequence/simple 内部用各自的局部标志记录 br end_bb 并在 + # 收尾覆盖,见 _handle_renum_match/_handle_sequence_match/ + # _handle_simple_match——切勿把标志声明在 Handle 这里(分派函数), + # 否则子函数引用的同名变量会退化为隐式全局,跨 match 互相污染)。 + trans._ctrl_merge_reachable = 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 + # 序列匹配(match (a, b): case (x, y): ...)走独立路径: + # Tuple/List subject 无法用 translate_value 求值(会返回 None), + # 提前分派到 _handle_sequence_match,避免 fail-fast 误报。 + sk_seq: int = subject_node.kind() + if sk_seq == ast.ASTKind.Tuple or sk_seq == ast.ASTKind.List: + return self._handle_sequence_match(trans, m_node, subject_node) + subject_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, subject_node, + trans._funcs, trans._func_count, trans) + if subject_val is None: + # fail-fast: match subject 翻译失败 + self.Gen.TypeGenErr.fatal_error(subject_node, "match subject 翻译失败", "TypeError") + + # 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: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, nm.id) + if entry is not None and entry.AnnotClassName is not None \ + and self.Gen.ClassGenEnum._is_renum_class_name( + entry.AnnotClassName) != 0: + is_renum = 1 + renum_name = entry.AnnotClassName + subject_ptr = self.Gen.VarGen.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 = len(cases_list) + 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 \ + and 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 \ + and pat.kind() == ast.ASTKind.MatchClass: + rnm: str = self._extract_renum_name_from_cls(pat) + if rnm is not None \ + and self.Gen.ClassGenEnum._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(trans, m_node, renum_name, subject_ptr) + return self._handle_simple_match(trans, 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 类名 + # + # P5-2 后 REnum 变体表迁入 gen 字段(RenumClassNames/RenumClassCount), + # 模块级 _renum_class_* 已失效,统一委托到 gen._lookup_renum_variant。 + # ============================================================ + def _find_renum_class_for_variant(self, variant_name: str) -> str: + if variant_name is None: + return None + return self.Gen.ClassGenEnum._lookup_renum_variant(variant_name) + + # ============================================================ + # _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 = len(body_list) + i: int = 0 + while i < n: + stmt: ast.AST | t.CPtr = body_list.get(i) + if stmt is not None and 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 \ + and 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 \ + and string.strcmp(base_nm.id, "c") == 0 \ + and at.attr is not None \ + and 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, trans: HT.Translator | t.CPtr, + node: ast.Match | t.CPtr, + renum_name: str, + subject_ptr: llvmlite.Value | t.CPtr) -> int: + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + # 局部记录本 renum match 是否有 br 进入 end_bb,收尾时覆盖 + # _ctrl_merge_reachable(case 体内嵌套 If 无 else + return 会把全局 + # 标志置 1,全 case return 的 match 被误判 merge 可达 → 函数收尾 + # fail-fast "流程掉出末尾"。声明必须在本函数内——放 Handle 分派 + # 函数里会使本函数引用退化为隐式全局,跨 match 污染)。 + rm_merge_reach: int = 0 + + # 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 self.Gen.ExprGenBase.is_ptr_type(subj_ty) != 0 \ + and subj_ty.Pointee is not None \ + and self.Gen.ExprGenBase.is_ptr_type(subj_ty.Pointee) != 0: + # 情况1: T** → load 一次得 T* + loaded_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, subj_ty.Pointee, 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 self.Gen.ExprGenBase.is_ptr_type(subject_ptr.Ty) == 0: + renum_se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.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: + # fail-fast: REnum 结构体未注册,无法构造 + self.Gen.TypeGenErr.fatal_error( + node, + f"REnum 结构体 '{renum_name}' 未注册", + "NameError") + 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 self.Gen.ExprGenBase.get_llvm_type_bits(subj_ty) != 64 \ + and self.Gen.ExprGenBase.is_ptr_type(subj_ty) == 0: + if self.Gen.ExprGenBase.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: + # fail-fast: REnum tag 指针转换失败 + self.Gen.TypeGenErr.fatal_error(node, "REnum tag 指针转换失败", "TypeError") + tag_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i32_ty, tag_ptr) + if tag_val is None: + # fail-fast: REnum tag 读取失败 + self.Gen.TypeGenErr.fatal_error(node, "REnum tag 读取失败", "TypeError") + + # 2. 创建 default/end BB + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: str = pool.alloc(32) + if name_buf is None: + # fail-fast: 标签缓冲区分配失败 + self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError") + 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: + # fail-fast: match cases 缺失 + self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError") + case_count: t.CSizeT = len(cases_list) + + # 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: + # fail-fast: match 分派数组分配失败 + self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError") + + 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 = self.Gen.ClassGenEnum._lookup_renum_variant_in_class( + renum_name, vnm) + if tag >= 0: + tag_buf: str = 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 = self.Gen.ExprGen.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 len(pats) > 0: + first_pat: ast.AST | t.CPtr = pats.get(0) + if first_pat is not None \ + and first_pat.kind() == ast.ASTKind.MatchValue: + mv2: ast.MatchValue | t.CPtr = ( + ast.MatchValue | t.CPtr)(first_pat) + cv = self.Gen.ExprGen.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: GenTypes.StructEntry | t.CPtr = None + renum_ty: llvmlite.LLVMType | t.CPtr = None + se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.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 作用域(变体字段绑定隔离) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) + + # 变体字段绑定(MatchClass) + if pat is not None and pat.kind() == ast.ASTKind.MatchClass \ + and 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 = len(body_list) + bi: int = 0 + while bi < bc: + stmt: ast.AST | t.CPtr = body_list.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + bi = bi + 1 + + # 退出 case 作用域 + self.Gen.VarGen.exit_scope(trans.SymTab) + + # 若未终止且无 NoBreak,跳到 end + # 末句控制流全 return(结构性不可达)时补 unreachable,不 br end_bb + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and nb == 0 \ + and self._case_tail_unreachable(trans, builder, body_list) == 0: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + rm_merge_reach = 1 + + 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) + trans._ctrl_merge_reachable = 1 + rm_merge_reach = 1 + else: + # 有显式 default:翻译 default case body(找到 is_def==1 的 case) + dbody: list[ast.AST | t.CPtr] | t.CPtr = None + 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) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) + dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children + dbody = dbody2 + if dbody is not None: + dn: t.CSizeT = len(dbody) + dj: int = 0 + while dj < dn: + stmt: ast.AST | t.CPtr = dbody.get(dj) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + dj = dj + 1 + self.Gen.VarGen.exit_scope(trans.SymTab) + break + di = di + 1 + # 末句控制流全 return → 补 unreachable(不 br end_bb) + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and self._case_tail_unreachable(trans, builder, dbody) == 0: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + rm_merge_reach = 1 + + # 9. 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 用本 match 自身的 br 记录覆盖,消除 case 体内嵌套控制流对 + # _ctrl_merge_reachable 的污染(全 case return 时应为不可达) + trans._ctrl_merge_reachable = rm_merge_reach + 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: GenTypes.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 = len(pats) + j: int = 0 + while j < pn: + sub_pat: ast.AST | t.CPtr = pats.get(j) + if sub_pat is not None and 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: + # class_name 用 CSizeT 指针值比较:必须传 renum_entry.Name + # (注册时 _update_renum_alias_class_ptr 统一后的 perm_pool + # 指针);renum_name(AnnotClassName 等)是不同指针恒不匹配 + # → 恒 -1 → fail-fast 误报(追加73d 同款指针陷阱) + alt_idx: int = self.Gen.ClassGenEnum._lookup_renum_field_alias( + renum_entry.Name, bind_name) + if alt_idx >= 1: + payload_idx = alt_idx + else: + # fail-fast: payload 越界且别名查找失败 + # (node 在本函数不存在——参数是 pat/sub_pat,用 sub_pat + # 定位到具体 MatchAs 模式;TPC Python 语义下未定义名只在 + # 运行时求值才报错,TPV 惰性编译方法体时即 NameError) + self.Gen.TypeGenErr.fatal_error( + sub_pat, + f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败", + "TypeError") + # 获取字段类型 + fe: GenTypes.FieldEntry | t.CPtr = ( + self.Gen.StructGen._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: + # fail-fast: 变体字段类型缺失,禁止兜底 i8 + self.Gen.TypeGenErr.fatal_error( + sub_pat, + f"REnum 变体字段类型缺失: {bind_name}", + "TypeError") + # GEP 取字段地址 + elem_ptr: llvmlite.Value | t.CPtr = ( + llvmlite.build_gep_struct( + builder, renum_ty, field_ty, + casted_ptr, payload_idx)) + if elem_ptr is None: + # fail-fast: 变体字段地址计算失败 + self.Gen.TypeGenErr.fatal_error( + sub_pat, + f"REnum 变体字段 '{bind_name}' 地址计算失败", + "TypeError") + # 变体成员实际类型(对齐 TPC class_members L300-307/L376-382): + # 注册时别名表存了成员注解解析出的类型(perm_pool 深拷贝)。 + # 用它把槽位地址 bitcast 成 Ptr(成员类型),使绑定变量按成员 + # 类型读 payload——Struct.Name: t.CChar|t.CPtr = i8*,否则按 + # 槽位 i64 读 → is 比较/下标/strlen 等字符串操作翻译失败 + # (CallGenMixin L4631 type_name_sp is not None 根因)。 + # 注意:必须按 (class, 变体名, 位置) 定位——MatchAs 名是局部 + # 变量名(type_name_sp),不是变体字段名(Name),按字段名 + # 查恒不匹配(追加76 第一次修复失效根因);同一 payload 位置 + # 跨变体类型也不同(Int.Bits=i32 vs Struct.Fields=Ptr)。 + # 自引用类型(如 Pointee: LLVMType|t.CPtr)注册期解析失败 → + # 查不到类型 → 回退槽位类型(原始位宽在嵌套 match 中经 + # subject bitcast 仍可用)。 + mem_ty_m: llvmlite.LLVMType | t.CPtr = None + vnt_m: str = self._extract_variant_name_from_cls(pat) + if vnt_m is not None and renum_entry is not None \ + and renum_entry.Name is not None: + mem_ty_m = self.Gen.ClassGenEnum._lookup_renum_member_ty( + renum_entry.Name, vnt_m, payload_idx) + if mem_ty_m is not None: + mem_ptr_m: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, mem_ty_m) + if mem_ptr_m is not None: + cast_m: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, elem_ptr, mem_ptr_m) + if cast_m is not None: + elem_ptr = cast_m + self.Gen.VarGen.define_var( + trans.SymTab, bind_name, elem_ptr) + j = j + 1 + + # ============================================================ + # _seq_cmp_eq - 序列匹配元素相等比较 + # + # 对齐 lhs/rhs(指针统一 ptrtoint i64,整数位宽统一到较宽者)后 + # 生成 icmp eq,返回 i1 条件。 + # ============================================================ + def _seq_cmp_eq(self, trans: HT.Translator | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + lhs: llvmlite.Value | t.CPtr, + rhs: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """对齐 lhs/rhs 后生成 icmp eq(指针统一 ptrtoint i64)""" + if lhs is None or rhs is None or builder is None: + return None + pool: memhub.MemBuddy | t.CPtr = trans.Pool + if self.Gen.ExprGenBase.is_ptr_type(lhs.Ty) != 0 \ + or self.Gen.ExprGenBase.is_ptr_type(rhs.Ty) != 0: + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + if self.Gen.ExprGenBase.is_ptr_type(lhs.Ty) != 0: + lhs = llvmlite.build_ptrtoint(builder, lhs, i64_ty) + if self.Gen.ExprGenBase.is_ptr_type(rhs.Ty) != 0: + rhs = llvmlite.build_ptrtoint(builder, rhs, i64_ty) + lb: int = self.Gen.ExprGenBase.get_llvm_type_bits(lhs.Ty) + rb: int = self.Gen.ExprGenBase.get_llvm_type_bits(rhs.Ty) + if lb != rb and lb != 0 and rb != 0: + if lb < rb: + if lb == 1: + lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) + else: + lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) + else: + if rb == 1: + rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) + else: + rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) + return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, lhs, rhs) + + # ============================================================ + # _handle_sequence_match - 序列匹配(match (a, b): case (x, y): ...) + # + # subject 是 Tuple/List、case 是 MatchSequence 时走此路径(对齐 Python + # 语义,按声明顺序取首个全部元素匹配且 guard 为真的 case 执行): + # 元素 pattern: + # MatchValue v → subject[i] == v + # MatchAs(pattern=None) → _ 通配(恒真) + # MatchStar → 剩余元素通配(恒真) + # IR 结构(check/body 链): + # entry → check0 + # check_i: 匹配条件 → body_i(不满足 → check_{i+1}) + # body_i: → end(c.NoBreak 时 fallthrough 到下一 case body) + # 全不匹配 → default → end + # ============================================================ + def _handle_sequence_match(self, trans: HT.Translator | t.CPtr, + node: ast.Match | t.CPtr, + subject_node: ast.AST | t.CPtr) -> int: + 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 + # 同主路径:局部记录本 sequence match 的 br end_bb,收尾覆盖 + # _ctrl_merge_reachable,消除 case 体内嵌套控制流污染 + sq_merge_reach: int = 0 + + # 1. 求值 subject 各元素 + elts: list[ast.AST | t.CPtr] | t.CPtr = None + if subject_node.kind() == ast.ASTKind.Tuple: + st: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(subject_node) + if st is not None: + elts = st.elts + elif subject_node.kind() == ast.ASTKind.List: + sl2: ast.List | t.CPtr = (ast.List | t.CPtr)(subject_node) + if sl2 is not None: + elts = sl2.elts + if elts is None: + return 0 + ecount: t.CSizeT = len(elts) + if ecount == 0: + return 0 + subj_vals: t.CSizeT | t.CPtr = pool.alloc(8 * ecount) + if subj_vals is None: + return 0 + for ei in range(ecount): + elt: ast.AST | t.CPtr = elts.get(ei) + sv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, elt, + trans._funcs, trans._func_count, trans) + if sv is None: + self.Gen.TypeGenErr.fatal_error( + elt, f"match 序列元素 {ei} 翻译失败", "TypeError") + subj_vals[ei] = t.CSizeT(sv) + + # 2. 创建 default/end BB + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: str = pool.alloc(32) + if name_buf is None: + return 0 + viperlib.snprintf(name_buf, 32, "match.seq.default.%d", cnt) + default_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "match.seq.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + + # 3. 第一遍:收集 case 信息(check/body BB、default 标记、nobreak、guard) + cases_list: list[ast.AST | t.CPtr] | t.CPtr = node.cases + if cases_list is None: + return 0 + case_count: t.CSizeT = len(cases_list) + check_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + body_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) + guard_arr: t.CSizeT | t.CPtr = pool.alloc(8 * MAX_MATCH_CASES) + if check_arr is None or body_arr is None or def_arr is None \ + or nb_arr is None or guard_arr is None: + return 0 + collected: int = 0 + has_default: int = 0 + first_check: int = -1 + i: int = 0 + while i < case_count: + case_node: ast.AST | t.CPtr = cases_list.get(i) + if case_node is None or 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 + if pat is not None: + pk: int = pat.kind() + if pk == ast.ASTKind.MatchAs: + ma0: ast.MatchAs | t.CPtr = (ast.MatchAs | t.CPtr)(pat) + if ma0.pattern is None: + is_def = 1 + elif pk != ast.ASTKind.MatchSequence: + # fail-fast:序列匹配只接受 MatchSequence / 顶层 _ 通配 + self.Gen.TypeGenErr.fatal_error( + pat, "序列匹配 case 只支持 (元素) 或 _ 模式", "TypeError") + if is_def == 1: + has_default = 1 + check_arr[collected] = 0 + body_arr[collected] = t.CSizeT(default_bb) + else: + if collected >= MAX_MATCH_CASES: + break + viperlib.snprintf(name_buf, 32, "match.seq.check.%d.%d", cnt, i) + cbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "match.seq.body.%d.%d", cnt, i) + bbb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, func, name_buf) + check_arr[collected] = t.CSizeT(cbb) + body_arr[collected] = t.CSizeT(bbb) + if first_check < 0: + first_check = collected + body_list: list[ast.AST | t.CPtr] | t.CPtr = mc.children + nb: int = self._has_no_break(body_list) + def_arr[collected] = is_def + nb_arr[collected] = nb + guard_arr[collected] = t.CSizeT(mc.guard) + collected = collected + 1 + i = i + 1 + + # 4. 入口 → 第一个 check(或 default/end) + if first_check >= 0: + head_bb: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)( + t.CVoid(check_arr[first_check], t.CPtr)) + llvmlite.build_br(builder, head_bb) + elif has_default == 1: + llvmlite.build_br(builder, default_bb) + else: + llvmlite.build_br(builder, end_bb) + + # 5. 发射 check 链 + ci: int = 0 + while ci < collected: + if def_arr[ci] == 1: + ci = ci + 1 + continue + cbb2: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)( + t.CVoid(check_arr[ci], t.CPtr)) + bbb2: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)( + t.CVoid(body_arr[ci], t.CPtr)) + llvmlite.position_at_end(builder, cbb2) + + # 计算匹配条件(元素比较 && guard) + cond: llvmlite.Value | t.CPtr = None + cnode: ast.AST | t.CPtr = cases_list.get(ci) + mc2: ast.MatchCase | t.CPtr = (ast.MatchCase | t.CPtr)(cnode) + ms: ast.MatchSequence | t.CPtr = ( + ast.MatchSequence | t.CPtr)(mc2.pattern) + pats: list[ast.AST | t.CPtr] | t.CPtr = None + if ms is not None: + pats = ms.patterns + pcount: t.CSizeT = 0 + if pats is not None: + pcount = len(pats) + if pcount != ecount: + # 元素数量不匹配 → 恒假(对齐 Python 语义) + cond = llvmlite.const_int(pool, 1, 0) + else: + for pi in range(ecount): + pat1: ast.AST | t.CPtr = pats.get(pi) + if pat1 is None: + continue + pk1: int = pat1.kind() + if pk1 == ast.ASTKind.MatchValue: + mv: ast.MatchValue | t.CPtr = ( + ast.MatchValue | t.CPtr)(pat1) + pv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, mv.value, + trans._funcs, trans._func_count, trans) + if pv is None: + self.Gen.TypeGenErr.fatal_error( + pat1, f"序列模式元素 {pi} 翻译失败", "TypeError") + sv1: llvmlite.Value | t.CPtr = ( + llvmlite.Value | t.CPtr)( + t.CVoid(subj_vals[pi], t.CPtr)) + c1: llvmlite.Value | t.CPtr = self._seq_cmp_eq( + trans, builder, sv1, pv) + if c1 is None: + self.Gen.TypeGenErr.fatal_error( + pat1, "序列模式元素比较失败", "TypeError") + if cond is None: + cond = c1 + else: + cond = llvmlite.build_and(builder, cond, c1) + elif pk1 == ast.ASTKind.MatchAs: + ma2: ast.MatchAs | t.CPtr = ( + ast.MatchAs | t.CPtr)(pat1) + if ma2.pattern is None: + continue # _ 通配:恒真 + if ma2.name is not None: + # fail-fast:序列模式变量绑定暂不支持 + self.Gen.TypeGenErr.fatal_error( + pat1, "序列模式变量绑定暂不支持", "NotImplementedError") + elif pk1 == ast.ASTKind.MatchStar: + continue # 剩余元素通配:恒真 + else: + self.Gen.TypeGenErr.fatal_error( + pat1, "序列模式不支持的 pattern 类型", "TypeError") + # guard(若有):匹配成立且 guard 非零 + g_addr: t.CSizeT = guard_arr[ci] + if g_addr != 0: + gnode: ast.AST | t.CPtr = ( + ast.AST | t.CPtr)(t.CVoid(g_addr, t.CPtr)) + gv: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( + builder, pool, trans.Module, gnode, + trans._funcs, trans._func_count, trans) + if gv is None: + self.Gen.TypeGenErr.fatal_error( + gnode, "match guard 翻译失败", "TypeError") + gbits: int = self.Gen.ExprGenBase.get_llvm_type_bits(gv.Ty) + if gbits == 1: + g1: llvmlite.Value | t.CPtr = gv + else: + gzero: llvmlite.Value | t.CPtr = llvmlite.const_int( + pool, gbits if gbits > 0 else 32, 0) + g1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, gv, gzero) + if cond is None: + cond = g1 + else: + cond = llvmlite.build_and(builder, cond, g1) + if cond is None: + cond = llvmlite.const_int(pool, 1, 1) + + # 下一个 check(或 default/end) + nxt: llvmlite.BasicBlock | t.CPtr = None + nj: int = ci + 1 + while nj < collected and def_arr[nj] == 1: + nj = nj + 1 + if nj < collected: + nxt = (llvmlite.BasicBlock | t.CPtr)( + t.CVoid(check_arr[nj], t.CPtr)) + elif has_default == 1: + nxt = default_bb + else: + nxt = end_bb + llvmlite.build_cond_br(builder, cond, bbb2, nxt) + ci = ci + 1 + + # 6. 翻译 case body + ci = 0 + while ci < collected: + if def_arr[ci] == 1: + ci = ci + 1 + continue + bbb3: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)( + t.CVoid(body_arr[ci], t.CPtr)) + llvmlite.position_at_end(builder, bbb3) + cnode2: ast.AST | t.CPtr = cases_list.get(ci) + mc3: ast.MatchCase | t.CPtr = ( + ast.MatchCase | t.CPtr)(cnode2) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) + body_list2: list[ast.AST | t.CPtr] | t.CPtr = mc3.children + if body_list2 is not None: + bc: t.CSizeT = len(body_list2) + bi: int = 0 + while bi < bc: + stmt: ast.AST | t.CPtr = body_list2.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + bi = bi + 1 + self.Gen.VarGen.exit_scope(trans.SymTab) + # 末句控制流全 return → 补 unreachable(不 br end,无 fallthrough) + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and self._case_tail_unreachable(trans, builder, body_list2) == 0: + if nb_arr[ci] == 0: + llvmlite.build_br(builder, end_bb) + else: + # c.NoBreak:fallthrough 到下一个 case body(跳过模式检查) + nj2: int = ci + 1 + while nj2 < collected and def_arr[nj2] == 1: + nj2 = nj2 + 1 + if nj2 < collected: + nbb: llvmlite.BasicBlock | t.CPtr = ( + llvmlite.BasicBlock | t.CPtr)( + t.CVoid(body_arr[nj2], t.CPtr)) + llvmlite.build_br(builder, nbb) + elif has_default == 1: + llvmlite.build_br(builder, default_bb) + else: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + sq_merge_reach = 1 + ci = ci + 1 + + # 7. default 块 + llvmlite.position_at_end(builder, default_bb) + dbody: list[ast.AST | t.CPtr] | t.CPtr = None + if has_default == 1: + di: int = 0 + while di < collected: + if def_arr[di] == 1: + dnode: ast.AST | t.CPtr = cases_list.get(di) + if dnode is not None: + dmc: ast.MatchCase | t.CPtr = ( + ast.MatchCase | t.CPtr)(dnode) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) + dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children + dbody = dbody2 + if dbody is not None: + dn: t.CSizeT = len(dbody) + dj: int = 0 + while dj < dn: + stmt: ast.AST | t.CPtr = dbody.get(dj) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + dj = dj + 1 + self.Gen.VarGen.exit_scope(trans.SymTab) + break + di = di + 1 + # 末句控制流全 return → 补 unreachable(不 br end_bb) + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and self._case_tail_unreachable(trans, builder, dbody) == 0: + llvmlite.build_br(builder, end_bb) + sq_merge_reach = 1 + + # 8. 定位到 end + llvmlite.position_at_end(builder, end_bb) + # 覆盖嵌套控制流污染(同主路径) + trans._ctrl_merge_reachable = sq_merge_reach + return 0 + + # ============================================================ + # _handle_simple_match - 非 REnum 路径 + # + # subject ptrtoint 到 i32 + switch 分派 + # ============================================================ + def _handle_simple_match(self, trans: HT.Translator | t.CPtr, + node: ast.Match | t.CPtr, + subject_val: llvmlite.Value | t.CPtr) -> int: + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + # 同主路径:局部记录本 simple match 的 br end_bb,收尾覆盖 + # _ctrl_merge_reachable,消除 case 体内嵌套控制流污染 + sm_merge_reach: int = 0 + + # 1. subject 转 i32(若已 i32 直接用,否则 ptrtoint) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + subj_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(subject_val.Ty) + subj_val: llvmlite.Value | t.CPtr = subject_val + if subj_bits != 32: + if self.Gen.ExprGenBase.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: + # fail-fast: subject 转 i32 失败 + self.Gen.TypeGenErr.fatal_error(node, "match subject 转换为 i32 失败", "TypeError") + + # 2. 创建 default/end BB + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: str = pool.alloc(32) + if name_buf is None: + # fail-fast: 标签缓冲区分配失败 + self.Gen.TypeGenErr.fatal_error(node, "标签缓冲区分配失败", "TypeError") + 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: + # fail-fast: match cases 缺失 + self.Gen.TypeGenErr.fatal_error(node, "match cases 缺失", "TypeError") + case_count: t.CSizeT = len(cases_list) + + 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: + # fail-fast: match 分派数组分配失败 + self.Gen.TypeGenErr.fatal_error(node, "match 分派数组分配失败", "TypeError") + + 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 = self.Gen.ExprGen.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 len(pats) > 0: + first_pat: ast.AST | t.CPtr = pats.get(0) + if first_pat is not None \ + and first_pat.kind() == ast.ASTKind.MatchValue: + mv2: ast.MatchValue | t.CPtr = ( + ast.MatchValue | t.CPtr)(first_pat) + cv = self.Gen.ExprGen.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) + + self.Gen.VarGen.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 = len(body_list) + bi: int = 0 + while bi < bc: + stmt: ast.AST | t.CPtr = body_list.get(bi) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + bi = bi + 1 + + self.Gen.VarGen.exit_scope(trans.SymTab) + + # 末句控制流全 return → 补 unreachable(不 br end_bb) + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and nb == 0 \ + and self._case_tail_unreachable(trans, builder, body_list) == 0: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + sm_merge_reach = 1 + + 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) + trans._ctrl_merge_reachable = 1 + sm_merge_reach = 1 + else: + dbody: list[ast.AST | t.CPtr] | t.CPtr = None + 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) + self.Gen.VarGen.enter_scope(trans.SymTab, SCOPE_MATCH) + dbody2: list[ast.AST | t.CPtr] | t.CPtr = dmc.children + dbody = dbody2 + if dbody is not None: + dn: t.CSizeT = len(dbody) + dj: int = 0 + while dj < dn: + stmt: ast.AST | t.CPtr = dbody.get(dj) + if stmt is not None: + self.Gen.StmtGen.translate_stmt(trans, stmt) + dj = dj + 1 + self.Gen.VarGen.exit_scope(trans.SymTab) + break + di = di + 1 + # 末句控制流全 return → 补 unreachable(不 br end_bb) + if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ + and self._case_tail_unreachable(trans, builder, dbody) == 0: + llvmlite.build_br(builder, end_bb) + trans._ctrl_merge_reachable = 1 + sm_merge_reach = 1 + + # 8. 定位到 end + llvmlite.position_at_end(builder, end_bb) + # 覆盖嵌套控制流污染(同主路径) + trans._ctrl_merge_reachable = sm_merge_reach + return 0