diff --git a/App/lib/core/BuildPipeline.vp b/App/lib/core/BuildPipeline.vp index 8af1882..417f426 100644 --- a/App/lib/core/BuildPipeline.vp +++ b/App/lib/core/BuildPipeline.vp @@ -34,6 +34,7 @@ import lib.core.Handles.HandlesMatch as HandlesMatch import lib.core.Handles.HandlesEnum as HandlesEnum import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign import lib.core.Handles.HandlesAugAssign as HandlesAugAssign +import lib.core.Handles.HandlesAssign as HandlesAssign import lib.core.Handles.HandlesVar as HandlesVar import lib.core.Handles.HandlesMain as HandlesMain import lib.core.StubMerger as StubMerger @@ -194,6 +195,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, HandlesEnum._g_gen = gen HandlesAnnAssign._g_gen = gen HandlesAugAssign._g_gen = gen + HandlesAssign._g_gen = gen HandlesVar._g_gen = gen HandlesTranslator._g_gen = gen HandlesMain._g_gen = gen diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index ef56171..58a78a1 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -12,6 +12,14 @@ import lib.core.VLogger as VLogger import lib.core.Handles.HandlesTranslator as HT import lib.core.Handles.HandlesType as HandlesType import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.ExprCallBase as ExprCallBase +import lib.core.Handles.ExprCallCall as ExprCallCall +import lib.core.Handles.ExprCallCtor as ExprCallCtor +import lib.core.StubMergerStore as StubMergerStore # ============================================================ @@ -696,3 +704,1530 @@ class AssignGenMixin: return llvmlite.build_lshr(builder, lhs, rhs) return llvmlite.build_ashr(builder, lhs, rhs) return None + + # ============================================================ + # translate_augassign - 增强赋值语句翻译(迁移自 HandlesAugAssign.AugAssignHandle.Handle) + # + # 支持 += -= *= /= %= &= |= ^= <<= >>=,local/global/nonlocal 三种作用域 + # ============================================================ + def translate_augassign(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译增强赋值语句 (x += 1, y -= 2, etc.)""" + if node is None: + return 0 + + aug: ast.AugAssign | t.CPtr = (ast.AugAssign | t.CPtr)(node) + if aug is None: + return 0 + + target: ast.AST | t.CPtr = aug.target + if target is None: + return 0 + + tk: int = target.kind() + + # Attribute 目标: self.field += 1 + # 流程: get_attribute_ptr → load → binop → store + if tk == ast.ASTKind.Attribute: + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 1. 获取字段指针 + field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( + builder, pool, mod, target, trans) + if field_ptr is None: + # fail-fast: 属性指针解析失败 + HandlesType.fatal_error(target, "attribute ptr is None", "TypeError") + + # 2. 确定字段类型并加载当前值 + target_ty: llvmlite.LLVMType | t.CPtr = None + if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None: + target_ty = field_ptr.Ty.Pointee + if target_ty is None: + # fail-fast: 字段类型信息缺失,禁止兜底 i32 + HandlesType.fatal_error(target, "字段类型信息缺失", "TypeError") + cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, target_ty, field_ptr) + if cur_val is None: + # fail-fast: 属性当前值加载失败 + HandlesType.fatal_error(target, "无法加载 attribute 当前值", "TypeError") + + # 3. 翻译 RHS 值 + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aug.value, None, 0, trans) + if rhs_val is None: + # fail-fast: RHS 翻译失败 + HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") + + # 4. 应用二元运算 + result: llvmlite.Value | t.CPtr = self._apply_aug_op( + pool, builder, aug.op, cur_val, rhs_val, node, trans, target) + if result is None: + # fail-fast: attribute 二元运算失败 + HandlesType.fatal_error(target, f"attribute 二元运算失败 op={aug.op}", "TypeError") + + # 5. 类型对齐并存储 + result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) + if result is None: + # fail-fast: 类型对齐失败 + HandlesType.fatal_error(target, "类型对齐失败", "TypeError") + llvmlite.build_store(builder, result, field_ptr) + return 0 + + # Subscript 目标: self.state[i] += x / arr[i] += x + # 流程: get_subscript_ptr → load → binop → store + if tk == ast.ASTKind.Subscript: + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 1. 获取元素指针 + elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr( + builder, pool, mod, target, trans) + if elem_ptr is None: + # fail-fast: 下标指针解析失败 + HandlesType.fatal_error(target, "subscript ptr is None", "TypeError") + + # 2. 确定元素类型并加载当前值 + target_ty: llvmlite.LLVMType | t.CPtr = None + if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: + target_ty = elem_ptr.Ty.Pointee + if target_ty is None: + # fail-fast: 元素类型信息缺失,禁止兜底 i32 + HandlesType.fatal_error(target, "元素类型信息缺失", "TypeError") + cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, target_ty, elem_ptr) + if cur_val is None: + # fail-fast: 元素当前值加载失败 + HandlesType.fatal_error(target, "无法加载 subscript 元素当前值", "TypeError") + + # 3. 翻译 RHS 值 + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aug.value, None, 0, trans) + if rhs_val is None: + # fail-fast: RHS 翻译失败 + HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") + + # 4. 应用二元运算 + result: llvmlite.Value | t.CPtr = self._apply_aug_op( + pool, builder, aug.op, cur_val, rhs_val, node, trans, target) + if result is None: + # fail-fast: subscript 二元运算失败 + HandlesType.fatal_error(target, f"subscript 二元运算失败 op={aug.op}", "TypeError") + + # 5. 类型对齐并存储 + result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) + if result is None: + # fail-fast: 类型对齐失败 + HandlesType.fatal_error(target, "类型对齐失败", "TypeError") + llvmlite.build_store(builder, result, elem_ptr) + return 0 + + if tk != ast.ASTKind.Name: + # fail-fast: 不支持的 AugAssign 目标类型 + HandlesType.fatal_error( + target, "AugAssign 目标类型不支持,仅支持 Name/Attribute/Subscript", "TypeError") + + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + if nm is None or nm.id is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 1. 确定变量作用域类型: 0=local, 1=global, 2=nonlocal + scope_type: int = 0 + if HT.is_global_name(trans, nm.id) != 0: + scope_type = 1 + elif HT.is_nonlocal_name(trans, nm.id) != 0: + scope_type = 2 + + # 2. 加载当前值 + cur_val: llvmlite.Value | t.CPtr = None + target_alloca: llvmlite.Value | t.CPtr = None + target_ty: llvmlite.LLVMType | t.CPtr = None + + if scope_type == 1: + # global 变量 + target_alloca = HandlesVar.lookup_module_var( + trans.SymTab, nm.id) + if target_alloca is not None: + if target_alloca.Ty is None: + # fail-fast: 变量类型信息缺失,禁止兜底 i32 + HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError") + target_ty = target_alloca.Ty.Pointee + cur_val = llvmlite.build_load(builder, target_ty, target_alloca) + elif scope_type == 2: + # nonlocal 变量(通过闭包 env) + cur_val = HandlesNonlocal.load_nonlocal_var(trans, nm.id) + if cur_val is not None: + target_ty = cur_val.Ty + else: + # 普通局部变量 + target_alloca = HandlesVar.lookup_var(trans.SymTab, nm.id) + if target_alloca is not None: + if target_alloca.Ty is None: + # fail-fast: 变量类型信息缺失,禁止兜底 i32 + HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError") + target_ty = target_alloca.Ty.Pointee + cur_val = llvmlite.build_load(builder, target_ty, target_alloca) + + if cur_val is None: + # fail-fast: 目标变量当前值加载失败 + HandlesType.fatal_error( + target, + f"无法加载目标变量 '{nm.id}' 的当前值", + "TypeError") + + # 3. 翻译 RHS 值 + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aug.value, None, 0, trans) + if rhs_val is None: + # fail-fast: RHS 翻译失败 + HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") + + # 4. 类型对齐 + 应用二元运算 + # 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__) + result: llvmlite.Value | t.CPtr = self._apply_aug_op( + pool, builder, aug.op, cur_val, rhs_val, node, trans, target) + if result is None: + # fail-fast: 二元运算失败 + HandlesType.fatal_error( + target, + f"对变量 '{nm.id}' 应用二元运算失败 op={aug.op}", + "TypeError") + + # 5. 存储结果 + result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) + if result is None: + # fail-fast: 类型对齐失败 + HandlesType.fatal_error(target, "类型对齐失败", "TypeError") + + if scope_type == 1: + # global 变量 + if target_alloca is not None: + llvmlite.build_store(builder, result, target_alloca) + elif scope_type == 2: + # nonlocal 变量 + nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( + trans, nm.id) + if nl_ptr is not None: + llvmlite.build_store(builder, result, nl_ptr) + else: + # 普通局部变量 + if target_alloca is not None: + llvmlite.build_store(builder, result, target_alloca) + + return 0 + + # ============================================================ + # is_ctypedef_annotation - 检测注解是否为 t.CTypedef + # + # 迁移自 HandlesAnnAssign.is_ctypedef_annotation(模块级委托壳); + # 真实实现 TypeGenCType._is_ctypedef_annotation 在另一 Mixin,经 + # gen 单例(HandlesExpr._g_gen 镜像)跨链调用。 + # ============================================================ + def is_ctypedef_annotation(self, annot: ast.AST | t.CPtr) -> int: + """检测注解是否为 t.CTypedef,返回 1 表示是,0 表示否""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( + t.CVoid(HandlesExpr._g_gen, t.CPtr)) + if g is not None: + return g._is_ctypedef_annotation(annot) + return 0 + + # ============================================================ + # _is_single_param_carray_annot - 检查注解是否为单参 t.CArray[elem_ty] + # + # 单参形式(t.CArray[elem_ty])与 count=None 形式(t.CArray[elem_ty, None]) + # 都解析为 Ptr(elem_ty)。当 RHS 是列表字面量时,按 TPC 语义应推断为 + # 静态数组 [len x elem_ty](对齐 TPC ParseListAnnotation 的 is_pointer 分支: + # "单参数 list[type] → 指针,但如果有列表字面量初始化值则按数组 list[type, N] 处理")。 + # ============================================================ + def _is_single_param_carray_annot(self, annot: ast.AST | t.CPtr) -> int: + """检查注解是否为单参/None 长度 t.CArray[...],返回 1=是 0=否 + + 支持两种书写形式: + 1. 模块限定 t.CArray[...](Attribute value) + 2. 裸名 CArray[...](from t import * 后使用,如 Termination4K3 core.vp + 的 `__python_suffix__: CArray[str] = ["py", ...]`) + """ + if annot is None or annot.kind() != ast.ASTKind.Subscript: + return 0 + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) + if sub.value is None or sub.slice is None: + return 0 + if sub.value.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value) + if at.attr is None or string.strcmp(at.attr, "CArray") != 0: + return 0 + if at.value is None or at.value.kind() != ast.ASTKind.Name: + return 0 + mv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mv.id is None or string.strcmp(mv.id, "t") != 0: + return 0 + elif sub.value.kind() == ast.ASTKind.Name: + # 裸名 CArray(from t import *):与 t.CArray 等价 + bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if bn.id is None or string.strcmp(bn.id, "CArray") != 0: + return 0 + else: + return 0 + # 单参形式:slice 非 Tuple(如 t.CArray[u64] / CArray[str]) + if sub.slice.kind() != ast.ASTKind.Tuple: + return 1 + # 双参形式:count=None(t.CArray[u64, None])→ 等价单参 + tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) + if tup.elts is None or len(tup.elts) < 2: + return 0 + cnt_node: ast.AST | t.CPtr = tup.elts.get(1) + if cnt_node is not None and cnt_node.kind() == ast.ASTKind.Constant: + cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(cnt_node) + if cn0.const_kind == ast.CONST_NONE: + return 1 + return 0 + + # ============================================================ + # _infer_static_array_ty_from_literal - 单参 CArray + 列表字面量 → 静态数组 + # + # 单参 t.CArray[elem_ty] 解析为 Ptr(elem_ty),但当 RHS 是列表字面量时, + # 按 TPC 语义应推断为 [len x elem_ty](对齐 TPC ParseListAnnotation): + # 避免误走动态 list 构造(_find_pool_var 兜底引用外部 @_mbuddy → 链接期 + # undefined)。PreScan 与 Handle 都调用(PreScan 预创建 alloca 的类型必须 + # 与 Handle 一致,否则 get_or_create_sym 复用旧 alloca 使推断失效)。 + # ============================================================ + def _infer_static_array_ty_from_literal(self, pool: memhub.MemBuddy | t.CPtr, + annot: ast.AST | t.CPtr, + value: ast.AST | t.CPtr, + resolved_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """单参 CArray + 列表字面量 → Array(elem_ty, len);否则返回原类型""" + if value is not None and value.kind() == ast.ASTKind.List and resolved_ty is not None: + if self._is_single_param_carray_annot(annot) != 0: + elem_ty_arr: llvmlite.LLVMType | t.CPtr = resolved_ty.Pointee + lst_arr: ast.List | t.CPtr = (ast.List | t.CPtr)(value) + cnt_arr: int = 0 + if lst_arr.elts is not None: + cnt_arr = len(lst_arr.elts) + if elem_ty_arr is not None and cnt_arr > 0: + return llvmlite.Array(pool, elem_ty_arr, cnt_arr) + return resolved_ty + + # ============================================================ + # translate_annassign_prescan - 预扫描 AnnAssign(迁移自 + # HandlesAnnAssign.AnnAssignHandle.PreScan) + # + # 为有类型注解的变量提前创建 alloca 到 entry block 顶部;返回新增的变量数 + # ============================================================ + def translate_annassign_prescan(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """预扫描 AnnAssign,提前创建 alloca 到 entry block 顶部""" + if node is None: + return 0 + k: int = node.kind() + if k != ast.ASTKind.AnnAssign: + return 0 + + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa is None or aa.target is None: + return 0 + target: ast.AST | t.CPtr = aa.target + if target.kind() != ast.ASTKind.Name: + return 0 + + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + if nm.id is None: + return 0 + + # CDefine 注解: 不创建 alloca,但注册常量到全局表 + # 供后续 t.CArray[elem_ty, NAME] 编译期解析使用 + # 浮点/整数自动识别(与 Handle/handle_module_level_var 路径一致) + if self.is_cdefine_annotation(aa.annotation) != 0: + pool_ps: memhub.MemBuddy | t.CPtr = trans.Pool + self._register_cdefine_from_value(pool_ps, nm.id, aa.value) + return 0 + + # CTypedef 注解: 类型别名(ScanCTypedefDeclarations 已注册到 CTypedef 表), + # 不创建全局/局部存储——否则 stdint.vp 的 float64_t: t.CTypedef = t.CFloat64T + # 等生成 @float64_t 符号,链接 duplicate symbol warning + if self.is_ctypedef_annotation(aa.annotation) != 0: + return 0 + + # global/nonlocal 变量不需要局部 alloca + if HT.is_global_name(trans, nm.id) != 0: + return 0 + if HT.is_nonlocal_name(trans, nm.id) != 0: + return 0 + + # 模块级全局变量已由 handle_module_level_var 注册到模块作用域。 + # Python 语义:仅模块级代码(Current == Root)时跳过局部 alloca; + # 函数内无 global 声明时应创建局部变量(不遮蔽全局)。 + if HandlesVar.is_module_scope(trans.SymTab) != 0: + if HandlesVar.lookup_module_var(trans.SymTab, nm.id) is not None: + return 0 + + # 检查是否已存在 + existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( + trans.SymTab, nm.id) + if existing is not None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + + # 从 annotation 推断类型(修复:原硬编码 i32 导致 str 等类型错误) + var_ty: llvmlite.LLVMType | t.CPtr = None + annot: ast.AST | t.CPtr = aa.annotation + if annot is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, annot, trans._imported_modules, trans._from_imports, trans) + if resolved is None: + # 尝试特化泛型类注解(如 list[str]) + # resolve_annotation_type 返回 None 可能是因为泛型类未特化 + if annot.kind() == ast.ASTKind.Subscript: + sub_annot: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) + if sub_annot.value is not None and sub_annot.value.kind() == ast.ASTKind.Name: + sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_annot.value) + if sub_nm.id is not None: + template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(sub_nm.id) + spec_name_ps: str = None + if template_cd is not None: + type_args_ps: list[str] | t.CPtr = ExprCallCtor._extract_type_args_from_slice(pool, sub_annot.slice) + if type_args_ps is not None and len(type_args_ps) > 0: + spec_name_ps = HandlesClassDef._specialize_generic_class( + trans, sub_nm.id, type_args_ps) + if spec_name_ps is not None: + resolved = HandlesType.resolve_annotation_type( + pool, annot, trans._imported_modules, trans._from_imports, trans) + if resolved is not None: + var_ty = resolved + # 单参 t.CArray[elem_ty] + 列表字面量 → 静态数组(与 Handle 推断一致)。 + # PreScan 预创建的 alloca 类型必须与 Handle 期望一致,否则 Handle 的 + # get_or_create_sym 复用旧 alloca,数组推断失效仍走动态 list → _mbuddy。 + var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty) + else: + # fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32) + HandlesType.fatal_error( + aa, + f"变量类型注解解析失败,变量名: {nm.id}", + "TypeError") + else: + # fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32) + HandlesType.fatal_error( + aa, + f"AnnAssign 缺少类型注解,变量名: {nm.id}", + "SyntaxError") + + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + HandlesStruct.ensure_struct_def_in_module(pool, trans.Module, var_ty) + alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, var_ty) + if alloca is not None: + if HandlesVar.define_var( + trans.SymTab, nm.id, alloca) == 0: + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + # 传 pool:泛型 Subscript 返回 mangled name(GSList[BasicBlock] → 特化 + # struct 名),否则 pool=None 只返回裸类名(GSList → 泛型模板未注册 + # → 属性访问 lookup_field_by_class("GSList") 报"类未注册",LLVMLiteTest + # __function.vp blocks.Tail 根因;对齐 ClassGenMixin L3159 BUG 1 方案3) + if annot is not None: + cls_nm_ps: str = HandlesType.extract_class_name_from_annotation( + annot, trans._imported_modules, pool) + if cls_nm_ps is not None: + HandlesVar.set_var_annot_class_name( + trans.SymTab, nm.id, cls_nm_ps) + # 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长) + if self._is_ptr_element_annotation(annot) != 0: + HandlesVar.set_var_ptr_element( + trans.SymTab, nm.id) + return 0 + return 0 + + # ============================================================ + # translate_annassign - 翻译 AnnAssign 语句(迁移自 + # HandlesAnnAssign.AnnAssignHandle.Handle) + # + # 返回新增的变量数 + # ============================================================ + def translate_annassign(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 AnnAssign(target=Name, annotation=..., value=expr)""" + aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) + if aa is None: + return 0 + + target: ast.AST | t.CPtr = aa.target + if target is None or target.kind() != ast.ASTKind.Name: + return 0 + + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + if nm.id is None: + return 0 + + # CDefine 注解: 编译期常量,不生成运行时代码 + # 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析 + # 注: PreScan 已注册过,此处保证即使跳过 PreScan 也能正确注册 + if self.is_cdefine_annotation(aa.annotation) != 0: + pool_cd: memhub.MemBuddy | t.CPtr = trans.Pool + self._register_cdefine_from_value(pool_cd, nm.id, aa.value) + return 0 + + # CTypedef 注解: 类型别名(mode_t: t.CTypedef = t.CUInt32T 等)。 + # 翻译期 CTypedef 表已被 clear_ctypedefs 清空(每文件隔离;表字符串 + # pool 分配,reset_to(mark1) 回收后悬空,不能跨文件累积),必须在此 + # 按需注册,否则 posix.vp S_ISREG(mode: mode_t) 等普通函数参数注解 + # 解析查表失败 → NameError: mode_t。仅登记类型表达式,不创建全局/ + # 局部存储——否则生成 @mode_t 符号,链接 duplicate symbol warning。 + if self.is_ctypedef_annotation(aa.annotation) != 0: + pool_ct: memhub.MemBuddy | t.CPtr = trans.Pool + ctd_str: str = HandlesType._get_type_name_from_annotation(pool_ct, aa.value) + if ctd_str is not None: + HandlesType.register_ctypedef(pool_ct, nm.id, ctd_str) + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 确定类型(从 annotation 推断) + var_ty: llvmlite.LLVMType | t.CPtr = None + annot: ast.AST | t.CPtr = aa.annotation + if annot is not None: + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, annot, trans._imported_modules, trans._from_imports, trans) + if resolved is not None: + var_ty = resolved + else: + # fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32) + HandlesType.fatal_error( + aa, + f"变量类型注解解析失败,变量名: {nm.id}", + "TypeError") + else: + # fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32) + HandlesType.fatal_error( + aa, + f"AnnAssign 缺少类型注解,变量名: {nm.id}", + "SyntaxError") + + # t.Callable 函数指针:注册返回类型签名(供函数指针间接调用精确返回类型) + callable_ret: llvmlite.LLVMType | t.CPtr = HandlesType.try_extract_callable_ret( + pool, annot, trans._imported_modules, trans._from_imports, trans) + if callable_ret is not None: + ExprCallCall.register_func_ptr_sig(nm.id, callable_ret) + + # global 变量:写入模块作用域中的全局变量 + if HT.is_global_name(trans, nm.id) != 0: + mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( + trans.SymTab, nm.id) + if mod_alloca is not None and aa.value is not None: + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aa.value, + None, 0, trans) + if rhs_val is not None: + target_ty: llvmlite.LLVMType | t.CPtr = None + if mod_alloca.Ty is not None: + target_ty = mod_alloca.Ty.Pointee + if target_ty is not None: + rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) + llvmlite.build_store(builder, rhs_val, mod_alloca) + return 0 + + # nonlocal 变量:通过闭包 env 写入 + if HT.is_nonlocal_name(trans, nm.id) != 0: + if aa.value is not None: + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aa.value, + None, 0, trans) + if rhs_val is not None: + nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( + trans, nm.id) + if nl_ptr is not None: + # 从 nl_ptr 的类型推断 nonlocal 变量实际类型, + # 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏) + nl_target_ty: llvmlite.LLVMType | t.CPtr = None + if nl_ptr.Ty is not None: + nl_target_ty = nl_ptr.Ty.Pointee + if nl_target_ty is None: + # fast-fail: nl_ptr 类型信息丢失,无法安全 store + VLogger.error( + f"nonlocal 变量类型信息丢失,无法写入: {nm.id}", + "HandlesAnnAssign") + return 0 + rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, rhs_val, nl_target_ty, node) + llvmlite.build_store(builder, rhs_coerced, nl_ptr) + return 0 + + # 模块级全局变量(由 handle_module_level_var 注册到模块作用域) + # Python 语义:仅模块级代码(Current == Root)时修改全局变量; + # 函数内无 global 声明时应创建局部变量(走后面的 get_or_create_sym 路径)。 + if HandlesVar.is_module_scope(trans.SymTab) != 0: + mod_glob: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( + trans.SymTab, nm.id) + else: + mod_glob = None + if mod_glob is not None: + if aa.value is not None: + # 列表字面量 → 逐元素 GEP + store 初始化数组 + if aa.value.kind() == ast.ASTKind.List: + self._init_global_array_from_list( + builder, pool, mod, mod_glob, aa.value, trans) + else: + rhs_val_mg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aa.value, + None, 0, trans) + if rhs_val_mg is not None: + target_ty_mg: llvmlite.LLVMType | t.CPtr = None + if mod_glob.Ty is not None: + target_ty_mg = mod_glob.Ty.Pointee + if target_ty_mg is not None: + rhs_val_mg = HandlesExpr.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node) + llvmlite.build_store(builder, rhs_val_mg, mod_glob) + return 0 + + # 单参 t.CArray[elem_ty] + 列表字面量 → 按静态数组处理(count 从字面量长度推断) + # 与 PreScan 推断一致:get_or_create_sym 复用 PreScan 创建的 alloca, + # 类型一致才能命中局部数组快路径,避免 _find_pool_var 兜底引用 @_mbuddy。 + var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty) + + # 普通局部变量 + # 创建 alloca + alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( + trans.SymTab, pool, builder, nm.id, var_ty) + if alloca is None: + # fail-fast: 存储创建失败,立即终止(禁止静默跳过) + HandlesType.fatal_error( + aa, + f"无法为变量 {nm.id} 创建存储", + "TypeError") + # FakeDuck: str 变量创建影子结构体 {var}__meta__(per-instance 字段存储) + # 仅裸 str 注解(Name("str"))且 _str 已注册时创建;bytes / t.CChar|t.CPtr 不创建。 + # a 保持为 i8*(可 printf/len),a__meta__ 存 __data__/__mbuddy__ 等字段, + # 属性读写(fd3)与方法调用(fd5)均通过该影子解析。 + fd_str_ty: llvmlite.LLVMType | t.CPtr = None + fd_meta_alloca: llvmlite.Value | t.CPtr = None + fd_meta_name: str = None + if annot is not None and annot.kind() == ast.ASTKind.Name: + fd_annot: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot) + if fd_annot is not None and fd_annot.id is not None: + if string.strcmp(fd_annot.id, "str") == 0: + fd_str_ty = HandlesStruct.get_struct_type("_str") + if fd_str_ty is not None: + # 确保 _str 完整类型定义在当前模块可用:跨模块结构体默认 opaque, + # 直接 alloca opaque 类型 → llc "Cannot allocate unsized type" + HandlesStruct.ensure_struct_def_in_module(pool, mod, fd_str_ty) + # 影子变量名必须用 pool 持久缓冲:f-string 生成栈缓冲,在 AnnAssign + # 返回后被覆盖,符号表注册的名字内容损坏 → 后续 lookup 找不到。 + fd_meta_name = pool.alloc(256) + if fd_meta_name is not None: + viperlib.snprintf(fd_meta_name, 256, "%s__meta__", nm.id) + fd_meta_alloca = HandlesVar.get_or_create_sym( + trans.SymTab, pool, builder, fd_meta_name, fd_str_ty) + if fd_meta_alloca is None: + # fail-fast: 影子存储创建失败,立即终止 + HandlesType.fatal_error( + aa, + f"无法为 str 影子变量 {fd_meta_name} 创建存储", + "TypeError") + # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) + # 传 pool:泛型 Subscript 返回 mangled name(对齐 L401 同根因修复) + if annot is not None: + cls_nm_hd: str = HandlesType.extract_class_name_from_annotation( + annot, trans._imported_modules, pool) + if cls_nm_hd is not None: + HandlesVar.set_var_annot_class_name( + trans.SymTab, nm.id, cls_nm_hd) + # 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长) + if self._is_ptr_element_annotation(annot) != 0: + HandlesVar.set_var_ptr_element( + trans.SymTab, nm.id) + + new_vars: int = 0 + existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( + trans.SymTab, nm.id) + if existing is None: + new_vars = 1 + + # 如果有初始值,store + if aa.value is not None: + # 局部数组:列表字面量 → 逐元素 GEP + store 初始化 + # 修复:此前局部 CArray[...] = [x, y] 会走 translate_list_literal, + # 错误触发 list[T] 泛型特化(堆对象)导致崩溃(如 this.vp 的 + # t.CArray[t.CChar, 256] = [0])。局部 alloca 未零初始化, + # 先整体置零再写列表元素(与全局数组默认零初始化语义一致)。 + local_arr_ty: llvmlite.LLVMType | t.CPtr = None + if aa.value.kind() == ast.ASTKind.List and alloca.Ty is not None: + pt_l: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if HandlesExpr.is_array_type(pt_l) != 0: + local_arr_ty = pt_l + if local_arr_ty is not None: + zero_arr: llvmlite.Value | t.CPtr = llvmlite.ConstZero( + pool, local_arr_ty) + if zero_arr is not None: + llvmlite.build_store(builder, zero_arr, alloca) + self._init_global_array_from_list( + builder, pool, mod, alloca, aa.value, trans) + else: + # 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → 读 i32 + # CurAssignNode 记录 RHS 节点:translate_c_deref 据此判定 Deref + # 是否为赋值直接 RHS(对齐 TPC _infer_deref_target_type)。 + trans.CurAssignAnnot = aa.annotation + trans.CurAssignNode = aa.value + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, aa.value, + None, 0, trans) + if rhs_val is not None: + # 注解退化修复(对齐 TPC 从构造结果推断类型): + # 无实参泛型模板类注解(如 vi: vector.Vector | CPtr,模板 + # 未注册 struct → resolve 退化)会让 alloca 类型退化为 + # Ptr(i8),但 rhs 构造返回精确结构体指针(如 Ptr(Vector[int] + # 结构))。此时按退化 alloca store 会丢失特化类型,后续 + # vi.push 方法调用按 Ptr(i8) 查不到类名 → AnnotClassName + # 回退到模板名(无实参)→ vpi 查不到返回类型 fail-fast。 + # 用 rhs 精确类型重建 alloca 并更新符号表注册,使方法调用 + # 按精确特化类名解析。旧退化 alloca 行残留为 entry block + # 死代码(文本 IR 即时生成,无法删除,无害)。 + precise_rhs_ty: llvmlite.LLVMType | t.CPtr = None + if rhs_val.Ty is not None: + match rhs_val.Ty: + case llvmlite.LLVMType.Ptr(inner_struct): + match inner_struct: + case llvmlite.LLVMType.Struct(_, _, _): + precise_rhs_ty = rhs_val.Ty + case _: + pass + case _: + pass + if precise_rhs_ty is not None and alloca.Ty is not None: + alloca_pt: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if alloca_pt is not None and \ + t.CUInt64T(alloca_pt) != t.CUInt64T(precise_rhs_ty): + new_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry( + builder, precise_rhs_ty) + if new_alloca is not None: + v_entry_rb: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm.id) + if v_entry_rb is not None: + v_entry_rb.Alloca = new_alloca + alloca = new_alloca + # 类型转换:将 rhs_val 转换为 alloca 的 pointee 类型 + # 修复:整数字面量是 i32,但变量可能是 i8/i16/i64,需 trunc/sext + target_ty: llvmlite.LLVMType | t.CPtr = None + if alloca.Ty is not None: + target_ty = alloca.Ty.Pointee + if target_ty is not None: + rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) + llvmlite.build_store(builder, rhs_val, alloca) + # FakeDuck: 初始化影子结构体 __data__ 字段 = 初始字符串指针 + # (对齐 TPC HandlesAnnAssign.py: 仅当有初值时写入 __data__) + if fd_str_ty is not None and fd_meta_alloca is not None: + fd_data_fe: HandlesStruct.FieldEntry | t.CPtr = \ + HandlesStruct.lookup_field(fd_str_ty, "__data__") + if fd_data_fe is not None: + fd_data_ptr: llvmlite.Value | t.CPtr = \ + llvmlite.build_gep_struct( + builder, fd_str_ty, fd_data_fe.Ty, + fd_meta_alloca, fd_data_fe.Index) + if fd_data_ptr is not None: + llvmlite.build_store(builder, rhs_val, fd_data_ptr) + # 清除赋值上下文(防残留):CurAssignAnnot/CurAssignNode 只在该 + # AnnAssign 的 RHS 翻译期间有效,否则后续 while 条件/比较等处的 + # c.Deref 会被残留注解误判读取宽度(i8* 被 bitcast i32* 读 4 字节)。 + trans.CurAssignAnnot = None + trans.CurAssignNode = None + + # FakeDuck: __mbuddy__ 字段初始化为 NULL。 + # with 上下文提供的 __mbuddy__ 注入由 _inject_requires_fields(fd4)完成, + # 此处仅确保影子结构体初始为空指针(对齐 TPC HandlesAnnAssign.py L667-670)。 + if fd_str_ty is not None and fd_meta_alloca is not None: + fd_buddy_fe: HandlesStruct.FieldEntry | t.CPtr = \ + HandlesStruct.lookup_field(fd_str_ty, "__mbuddy__") + if fd_buddy_fe is not None and fd_buddy_fe.Ty is not None: + fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, fd_buddy_fe.Ty, "null") + fd_buddy_ptr: llvmlite.Value | t.CPtr = \ + llvmlite.build_gep_struct( + builder, fd_str_ty, fd_buddy_fe.Ty, + fd_meta_alloca, fd_buddy_fe.Index) + if fd_buddy_ptr is not None and fd_null is not None: + llvmlite.build_store(builder, fd_null, fd_buddy_ptr) + # FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__)。 + # 经全局 gen 单例委托 CallGenMixin._inject_requires_fields。 + import lib.core.Gen.Generator as Generator + g_fda: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( + t.CVoid(HandlesExpr._g_gen, t.CPtr)) + if g_fda is not None: + g_fda._inject_requires_fields( + trans, pool, builder, mod, fd_meta_alloca, "_str") + + return 0 + + # ============================================================ + # translate_assign - 处理 Assign 语句,返回新增变量数(0 或 1) + # + # 迁移自 HandlesAssign.AssignHandle.Handle(对应 TransPyC + # AssignHandle._HandleAssignLlvm)。共享状态从 trans 获取。 + # ============================================================ + def translate_assign(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 Assign 语句,返回新增变量数(0 或 1)""" + asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) + if asgn is None: + VLogger.error("cast failed", "ASGN") + return 0 + + targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets + if targets is None: + VLogger.error("targets is None", "ASGN") + return 0 + + # 从 trans 取共享状态(替代 11 个参数) + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + # 翻译 RHS 值 + # 无注解赋值无目标类型可推断,清空 CurAssignAnnot/CurAssignNode + # (防残留误判 c.Deref 宽度) + trans.CurAssignAnnot = None + trans.CurAssignNode = None + rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, asgn.value, None, 0, trans) + if rhs_val is None: + # Phase A 依赖未就绪(_deps_pending=1):跨模块函数/方法因 text.ll + # 未生成返回类型退化为 void/None(CallGenMixin L4493 + # g_vta._resolve_attr_field_class 根因)。此时整文件不写盘、下遍重译 + # (Phase2.vp L590-599),跳过本语句不报错——否则 fatal 使多遍 + # 重试机制永远无法收敛(本语句只是"本遍保持默认类型"的退化结果, + # 下遍依赖已生成即可精确解析)。依赖就绪时 _deps_pending=0, + # 此处仍 fail-fast,不掩盖真实错误。 + if trans is not None and trans._deps_pending != 0: + return 0 + # 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位 + fb: str = VLogger.fmt_buf() + if fb is not None and asgn.value is not None: + sha1: str = trans.ModuleSha1 + val_kind: int = asgn.value.kind() + val_line: t.CInt = asgn.value.lineno + # 通过 sha1 查找文件名(人类可读) + rel_path: str = None + if sha1 is not None: + rel_path = StubMergerStore.LookupSha1RelPath(sha1) + # 根据 AST 节点类型提取详情 + if val_kind == ast.ASTKind.Attribute: + at_nv: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(asgn.value) + attr_nm: str = at_nv.attr + target_nm: str = "?" + if at_nv.value is not None: + if at_nv.value.kind() == ast.ASTKind.Name: + tn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_nv.value) + target_nm = tn_nm.id + if rel_path is not None: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: %s:%d '%s.%s' 属性访问失败", + rel_path, val_line, target_nm, attr_nm) + else: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: sha1=%s:%d '%s.%s' 属性访问失败", + sha1, val_line, target_nm, attr_nm) + elif val_kind == ast.ASTKind.Name: + nm_nv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(asgn.value) + if rel_path is not None: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: %s:%d 变量 '%s' 未找到", + rel_path, val_line, nm_nv.id) + else: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: sha1=%s:%d 变量 '%s' 未找到", + sha1, val_line, nm_nv.id) + elif val_kind == ast.ASTKind.Call: + cl_nv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(asgn.value) + func_nm: str = "?" + if cl_nv.func is not None: + if cl_nv.func.kind() == ast.ASTKind.Name: + fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_nv.func) + func_nm = fn_nm.id + if rel_path is not None: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: %s:%d 调用 '%s(...)' 返回 None", + rel_path, val_line, func_nm) + else: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: sha1=%s:%d 调用 '%s(...)' 返回 None", + sha1, val_line, func_nm) + else: + if rel_path is not None: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: %s:%d [kind=%d]", + rel_path, val_line, val_kind) + else: + viperlib.snprintf(fb, 1024, + "赋值右侧为 None: sha1=%s:%d [kind=%d]", + sha1, val_line, val_kind) + VLogger.error(fb, "ASGN") + else: + VLogger.error("赋值右侧为 None (asgn.value 为空)", "ASGN") + return 0 + + new_vars: int = 0 + tn: t.CSizeT = len(targets) + for ti in range(tn): + target: ast.AST | t.CPtr = targets.get(ti) + if target is None: + continue + + tk: int = target.kind() + + # Tuple 赋值: a, b = f() 多返回值解包 + # rhs_val 是匿名 struct 值(函数返回 tuple[T1,T2] 打包)→ alloca + + # store + GEP 逐字段 load → store 到各 Name 目标。 + if tk == ast.ASTKind.Tuple: + tgt_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) + tgt_elts: list[ast.AST | t.CPtr] | t.CPtr = tgt_tup.elts + # 守卫:rhs 不是 struct(tuple 打包)时跳过本 target + if tgt_elts is None or rhs_val is None or rhs_val.Ty is None: + continue + match rhs_val.Ty: + case llvmlite.LLVMType.Struct(_, _, _): + tgt_n: t.CSizeT = len(tgt_elts) + tmp_s: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, rhs_val.Ty) + if tmp_s is not None: + llvmlite.build_store(builder, rhs_val, tmp_s) + fchain: llvmlite.ParamNode | t.CPtr = llvmlite.get_struct_fields(rhs_val.Ty) + fcur: llvmlite.ParamNode | t.CPtr = fchain + fti: t.CSizeT + for fti in range(tgt_n): + tgt_elt: ast.AST | t.CPtr = tgt_elts.get(fti) + if tgt_elt is None or fcur is None: + break + fty: llvmlite.LLVMType | t.CPtr = llvmlite.paramnode_get_ty(fcur) + fcur = llvmlite.paramnode_get_next(fcur) + if fty is None: + # fail-fast: 字段类型缺失,立即终止 + HandlesType.fatal_error(target, "元组解包字段类型缺失", "TypeError") + # 守卫:非 Name 元素无法解包,跳过 + if tgt_elt.kind() != ast.ASTKind.Name: + continue + tgt_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_elt) + if tgt_nm2.id is None: + continue + fp2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, rhs_val.Ty, fty, tmp_s, fti) + if fp2 is None: + continue + fv2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, fty, fp2) + tgt_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, tgt_nm2.id) + if tgt_alloca is None: + tgt_alloca = HandlesVar.get_or_create_sym( + trans.SymTab, pool, builder, tgt_nm2.id, fty) + if tgt_alloca is None: + continue + sval: llvmlite.Value | t.CPtr = fv2 + if tgt_alloca.Ty is not None and tgt_alloca.Ty.Pointee is not None: + sval = HandlesExpr.coerce_to_type( + builder, fv2, tgt_alloca.Ty.Pointee, node) + llvmlite.build_store(builder, sval, tgt_alloca) + case _: + pass + continue + + # Subscript 赋值: arr[i] = val / ptr[i] = val / list[i] = val + if tk == ast.ASTKind.Subscript: + # 检查是否是 list[T] 类型的 Subscript(泛型类不注册 struct) + # list 的 subscript 赋值走 __setitem__ 内联路径 + list_obj: llvmlite.Value | t.CPtr = HandlesExpr.is_list_subscript( + target, trans) + if list_obj is not None: + # list[T] 类型: 内联生成 __setitem__ 逻辑 + sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target) + if sub_node is not None and sub_node.slice is not None: + list_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, sub_node.slice, None, 0, trans) + if list_idx_val is None: + # fail-fast: list 下标翻译失败,立即终止 + HandlesType.fatal_error(target, "list 下标翻译失败", "TypeError") + HandlesExpr.list_setitem_inline( + builder, pool, list_obj, list_idx_val, rhs_val, target) + continue + # 普通 Subscript 赋值 + elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr( + builder, pool, mod, target, trans) + if elem_ptr is not None: + store_val: llvmlite.Value | t.CPtr = rhs_val + # 守卫短路:elem 类型完整才做类型转换 + if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: + store_val = HandlesExpr.coerce_to_type( + builder, rhs_val, elem_ptr.Ty.Pointee, node) + llvmlite.build_store(builder, store_val, elem_ptr) + continue + # get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载 + # 适用于自定义类(如 hashtable[key]=val → hashtable.__setitem__(key, val)) + sub_asgn: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target) + setitem_done: int = 0 + if sub_asgn is not None and sub_asgn.value is not None: + if sub_asgn.value.kind() == ast.ASTKind.Name: + sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_asgn.value) + if sub_nm.id is not None: + sub_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, sub_nm.id) + if sub_alloca is not None and sub_alloca.Ty is not None \ + and sub_alloca.Ty.Pointee is not None \ + and HandlesExpr.is_ptr_type(sub_alloca.Ty) != 0: + sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee + cls_nm_set: str = HandlesStruct.get_class_name_by_type(pool, sub_pointee) + obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, sub_pointee, sub_alloca) + # 指针类型变量 (X|t.CPtr): sub_pointee 是 Ptr(Struct), + # 需 load 获取 Ptr(Struct) 再检查 inner struct + if cls_nm_set is None and obj_val_set is not None \ + and HandlesExpr.is_ptr_type(sub_pointee) != 0 \ + and sub_pointee.Pointee is not None: + cls_nm_set = HandlesStruct.get_class_name_by_type( + pool, sub_pointee.Pointee) + if cls_nm_set is not None and obj_val_set is not None: + key_val_set: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, sub_asgn.slice, None, 0, trans) + if key_val_set is not None: + arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16) + if arg_vals_set is not None: + arg_vals_set[0] = t.CSizeT(key_val_set) + arg_vals_set[1] = t.CSizeT(rhs_val) + ExprCallCtor._call_method_on_ptr( + pool, builder, mod, cls_nm_set, "__setitem__", + obj_val_set, arg_vals_set, 2, trans) + setitem_done = 1 + elif sub_asgn.value.kind() == ast.ASTKind.Attribute: + # self._ht[key] = val → self._ht.__setitem__(key, val) + # 通过 get_attribute_ptr 获取字段指针,再调用 __setitem__ + field_ptr_set: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( + builder, pool, mod, sub_asgn.value, trans) + if field_ptr_set is not None and field_ptr_set.Ty is not None \ + and field_ptr_set.Ty.Pointee is not None \ + and HandlesExpr.is_ptr_type(field_ptr_set.Ty) != 0: + field_pointee_set: llvmlite.LLVMType | t.CPtr = field_ptr_set.Ty.Pointee + cls_nm_attr: str = HandlesStruct.get_class_name_by_type(pool, field_pointee_set) + obj_val_attr: llvmlite.Value | t.CPtr = field_ptr_set + # field_ptr 是 Ptr(Ptr(Struct)) (X|t.CPtr 字段): + # load 解引用获取 Ptr(Struct) + if cls_nm_attr is None \ + and HandlesExpr.is_ptr_type(field_pointee_set) != 0 \ + and field_pointee_set.Pointee is not None: + cls_nm_attr = HandlesStruct.get_class_name_by_type( + pool, field_pointee_set.Pointee) + if cls_nm_attr is not None: + obj_val_attr = llvmlite.build_load( + builder, field_pointee_set, field_ptr_set) + if cls_nm_attr is not None and obj_val_attr is not None: + key_val_attr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, sub_asgn.slice, None, 0, trans) + if key_val_attr is not None: + arg_vals_attr: t.CSizeT | t.CPtr = pool.alloc(16) + if arg_vals_attr is not None: + arg_vals_attr[0] = t.CSizeT(key_val_attr) + arg_vals_attr[1] = t.CSizeT(rhs_val) + ExprCallCtor._call_method_on_ptr( + pool, builder, mod, cls_nm_attr, "__setitem__", + obj_val_attr, arg_vals_attr, 2, trans) + setitem_done = 1 + if setitem_done == 0: + # 通用 fallback: 翻译 sub.value 并尝试 __setitem__ 或直接 GEP+store + # 处理 Name/Attribute 之外的节点以及 SymTab 查找失败的情况 + if sub_asgn is not None and sub_asgn.value is not None: + obj_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, sub_asgn.value, None, 0, trans) + key_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, sub_asgn.slice, None, 0, trans) + if obj_val_gen is not None and key_val_gen is not None \ + and obj_val_gen.Ty is not None: + # 内联 _get_custom_struct_cls_nm 逻辑(避免依赖新函数) + cls_nm_gen: str = HandlesStruct.get_class_name_by_type( + pool, obj_val_gen.Ty) + if cls_nm_gen is None and HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0 \ + and obj_val_gen.Ty.Pointee is not None: + cls_nm_gen = HandlesStruct.get_class_name_by_type( + pool, obj_val_gen.Ty.Pointee) + if cls_nm_gen is not None: + # 自定义结构体: 调用 __setitem__ + arg_vals_gen: t.CSizeT | t.CPtr = pool.alloc(16) + if arg_vals_gen is not None: + arg_vals_gen[0] = t.CSizeT(key_val_gen) + arg_vals_gen[1] = t.CSizeT(rhs_val) + ExprCallCtor._call_method_on_ptr( + pool, builder, mod, cls_nm_gen, "__setitem__", + obj_val_gen, arg_vals_gen, 2, trans) + setitem_done = 1 + elif HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0 \ + and obj_val_gen.Ty.Pointee is not None: + # 非自定义结构体: 直接 GEP + store + # 处理 get_subscript_ptr 因边界情况返回 None 的指针下标 + elem_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee + store_val_gen: llvmlite.Value | t.CPtr = rhs_val + elem_ptr_gen: llvmlite.Value | t.CPtr = None + match elem_gen: + case llvmlite.LLVMType.Array(arr_elem_gen, _): + elem_ptr_gen = llvmlite.build_gep_array( + builder, elem_gen, arr_elem_gen, + obj_val_gen, key_val_gen) + case _: + elem_ptr_gen = llvmlite.build_gep( + builder, elem_gen, obj_val_gen, key_val_gen) + if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None: + if elem_ptr_gen.Ty.Pointee is not None: + store_val_gen = HandlesExpr.coerce_to_type( + builder, rhs_val, elem_ptr_gen.Ty.Pointee, node) + llvmlite.build_store(builder, store_val_gen, elem_ptr_gen) + setitem_done = 1 + if setitem_done == 0: + HandlesType.fatal_error(target, "subscript ptr is None") + continue + + # Attribute 赋值: obj.field = val + if tk == ast.ASTKind.Attribute: + # property setter 拦截: obj.attr = v 且 attr 是 @x.setter 方法时, + # 生成 call Class.attr$set(obj, v),跳过字段存储 + # 注意参数顺序:_try_property_setter(pool, builder, mod, ...)—— + # 旧代码传 (builder, pool, ...) 导致 pool/builder 错位,pool 参数 + # 实际是 IRBuilder 对象,pool.alloc 虚调用读 IRBuilder[0] 当 vtable + # 跳到垃圾地址崩溃(BuiltinDecoratorTest Phase A 崩溃根因)。 + if ExprCallCtor._try_property_setter( + pool, builder, mod, target, rhs_val, trans) == 1: + continue + # FakeDuck: 影子结构体属性写入 (str 变量的 per-instance 字段) + # a.__data__ = v → GEP {a}__meta__[field] 并 store + # 对齐 TPC HandlesAssign.py L67-76:对象是 Name 变量且存在 + # {var}__meta__ 影子(fd2 创建)时,属性写入改走影子结构体。 + fd_an: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target) + if fd_an is not None and fd_an.value is not None and fd_an.attr is not None: + if fd_an.value.kind() == ast.ASTKind.Name: + fd_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_an.value) + if fd_obj_nm.id is not None: + # pool 持久缓冲(f-string 栈缓冲在函数返回后失效) + fd_meta_w: str = pool.alloc(256) + if fd_meta_w is not None: + viperlib.snprintf(fd_meta_w, 256, "%s__meta__", fd_obj_nm.id) + fd_meta_vw: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( + trans.SymTab, fd_meta_w) + if fd_meta_vw is not None: + fd_sty_w: llvmlite.LLVMType | t.CPtr = \ + HandlesStruct.get_struct_type("_str") + if fd_sty_w is not None: + fd_fe_w: HandlesStruct.FieldEntry | t.CPtr = \ + HandlesStruct.lookup_field(fd_sty_w, fd_an.attr) + if fd_fe_w is not None and fd_fe_w.Ty is not None: + fd_fp_w: llvmlite.Value | t.CPtr = \ + llvmlite.build_gep_struct( + builder, fd_sty_w, fd_fe_w.Ty, + fd_meta_vw, fd_fe_w.Index) + if fd_fp_w is not None: + sv_fd: llvmlite.Value | t.CPtr = \ + HandlesExpr.coerce_to_type( + builder, rhs_val, fd_fe_w.Ty, node) + llvmlite.build_store(builder, sv_fd, fd_fp_w) + continue + # VTABLE 直接写入:obj.method = func(serial0_file.open = serial0_open) + # vtable 方法不是数据字段(FieldEntry),get_attribute_ptr 查不到会 + # fatal_error;此处对齐 TPC HandlesAssign.py L905-949 的写时复制, + # 检测到 vtable 方法时直接生成槽位写入并跳过字段路径。 + import lib.core.Gen.Generator as Generator + g_vtw: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( + t.CVoid(HandlesExpr._g_gen, t.CPtr)) + if g_vtw is not None: + if g_vtw._write_vtable_attr( + builder, pool, mod, target, rhs_val, trans) == 1: + continue + field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( + builder, pool, mod, target, trans) + if field_ptr is not None: + # 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64) + store_val: llvmlite.Value | t.CPtr = rhs_val + if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None: + store_val = HandlesExpr.coerce_to_type( + builder, rhs_val, field_ptr.Ty.Pointee, node) + llvmlite.build_store(builder, store_val, field_ptr) + continue + # 守卫:field_ptr 为 None → 构造详细错误信息 + # Phase A 依赖未就绪(_deps_pending):get_attribute_ptr 已因 + # 父类/依赖类未注册跳过字段,此处同样跳过不报错,整文件下遍重译 + # (对齐 HandlesAssign L69-78 与 get_attribute_ptr 的 pending 容忍) + if trans is not None and trans._deps_pending != 0: + continue + attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target) + attr_name: str = "(unknown)" + obj_name: str = "(unknown)" + if attr_node is not None: + attr_name = attr_node.attr + if attr_node.value is not None and attr_node.value.kind() == ast.ASTKind.Name: + obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(attr_node.value) + obj_name = obj_nm.id + err_buf: str = pool.alloc(256) + if err_buf is not None: + viperlib.snprintf(err_buf, 256, + "attribute ptr is None: %s.%s", + obj_name, attr_name) + HandlesType.fatal_error(target, err_buf) + else: + HandlesType.fatal_error(target, "attribute ptr is None") + continue + + # Name 赋值: var = val + if tk == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + # 守卫:target 名缺失时跳过 + if nm.id is None: + continue + # global 变量:写入模块作用域中的全局变量 + if HT.is_global_name(trans, nm.id) != 0: + mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( + trans.SymTab, nm.id) + if mod_alloca is None: + # fail-fast: global 变量未注册,无法赋值 + HandlesType.fatal_error( + target, + f"global 变量 '{nm.id}' 未注册,无法赋值", + "NameError") + target_ty: llvmlite.LLVMType | t.CPtr = None + if mod_alloca.Ty is not None: + target_ty = mod_alloca.Ty.Pointee + if target_ty is not None: + rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) + llvmlite.build_store(builder, rhs_val, mod_alloca) + continue + + # nonlocal 变量:通过闭包 env 写入 + if HT.is_nonlocal_name(trans, nm.id) != 0: + nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( + trans, nm.id) + if nl_ptr is None: + # fail-fast: nonlocal 变量指针解析失败 + HandlesType.fatal_error( + target, + f"nonlocal 变量 '{nm.id}' 指针解析失败", + "NameError") + # 从 nl_ptr 的类型推断 nonlocal 变量实际类型, + # 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏) + nl_target_ty: llvmlite.LLVMType | t.CPtr = None + if nl_ptr.Ty is not None: + nl_target_ty = nl_ptr.Ty.Pointee + if nl_target_ty is None: + # fail-fast: nl_ptr 类型信息丢失,无法安全 store + HandlesType.fatal_error( + target, + f"nonlocal 变量 '{nm.id}' 类型信息丢失,无法写入", + "TypeError") + rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, rhs_val, nl_target_ty, node) + llvmlite.build_store(builder, rhs_coerced, nl_ptr) + continue + + # 拦截:函数内对模块级全局变量赋值但没 global 声明 + # 否则静默创建局部变量遮蔽全局,全局保持 null 导致运行时崩溃 + # (_mbuddy = mb 缺 global 声明即此类 bug:Int32 解引用 null 崩溃) + if HandlesVar.is_module_scope(trans.SymTab) == 0: + mod_gv: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( + trans.SymTab, nm.id) + if mod_gv is not None: + fb_g: str = VLogger.fmt_buf() + msg_g: str = "global 声明缺失" + if fb_g is not None: + viperlib.snprintf(fb_g, 1024, "变量 '%s' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", nm.id) + msg_g = fb_g + HandlesType.fatal_error(target, msg_g, "SyntaxError") + + # 普通局部变量 + alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( + trans.SymTab, pool, builder, nm.id, rhs_val.Ty) + if alloca is not None: + # 无注解赋值:从 RHS 表达式推断类名设置变量注解 + # (联合类型 X|t.CPtr 简化为 Ptr(i8),属性访问按需过滤需要 + # AnnotClassName 才能定位结构体字段) + cls_inf: str = self._infer_rhs_annot(pool, mod, asgn.value, trans, rhs_val) + if cls_inf is not None: + HandlesVar.set_var_annot_class_name( + trans.SymTab, nm.id, cls_inf) + # 按 alloca 类型对值进行转换(如 double → float) + store_val: llvmlite.Value | t.CPtr = rhs_val + if alloca.Ty is not None and alloca.Ty.Pointee is not None: + store_val = HandlesExpr.coerce_to_type( + builder, rhs_val, alloca.Ty.Pointee, node) + llvmlite.build_store(builder, store_val, alloca) + # lambda 表达式赋给变量:注册为闭包变量名, + # 调用分派(is_closure_name)才走闭包间接调用路径; + # 否则 i8** alloca 被 _is_func_ptr_alloca 误判为 + # 函数指针,无参 call 直接跳闭包数据崩溃 + if asgn.value is not None \ + and asgn.value.kind() == ast.ASTKind.Lambda: + ExprCallCall.register_closure_name(nm.id) + existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( + trans.SymTab, nm.id) + if existing is None: + new_vars += 1 + else: + # fail-fast: 变量存储创建失败,立即终止 + HandlesType.fatal_error( + target, + f"变量 '{nm.id}' 存储创建失败", + "TypeError") + + return new_vars + + # ============================================================ + # _infer_rhs_annot - 从 RHS 表达式推断变量注解类名 + # + # 无注解赋值(如 v = Vec2(...) / v3 = v1 + v2)时,变量 AnnotClassName + # 缺失会导致后续属性访问(.x)无法"按需过滤":联合类型 X|t.CPtr 在 LLVM + # 中简化为 Ptr(i8),不携带类名,无法定位结构体字段(字段未找到 → fast-fail)。 + # 此函数按 RHS 结构推断类名: + # Call → 类实例化(func 为已注册结构体名才采用,避免普通函数误标); + # func 为 Attribute 时是方法调用(a.cross()),obj 类名 + + # 方法存在 + rhs_val 为指针类型(联合对象)三条件判定 + # Name → 源变量的 AnnotClassName + # BinOp/UnaryOp → lhs 类名 + 该类存在对应 dunder 方法(运算符重载返回同类对象) + # Attribute → 字段注解类名(委托 Generator 单例 _resolve_attr_field_class) + # 仅当目标为已注册结构体时采用,与"按需过滤,找不到 fast-fail"原则一致。 + # ============================================================ + def _infer_rhs_annot(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr, + rhs_val: llvmlite.Value | t.CPtr = None) -> str: + """从 RHS 表达式推断类名,无法推断返回 None""" + if node is None or trans is None: + return None + k: int = node.kind() + # Call: 类实例化 / 方法调用 + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl is None or cl.func is None: + return None + if cl.func.kind() == ast.ASTKind.Name: + # 类实例化:func 为已注册结构体名才采用 + cand: str = ((ast.Name | t.CPtr)(cl.func)).id + if cand is None: + return None + se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(cand) + if se is not None: + return cand + return None + if cl.func.kind() == ast.ASTKind.Attribute: + # 方法调用 a.cross(b):从 vpi 返回注解缓存精确解析返回类名 + # (方法可返回非同类对象,如 Transform.world_position → 'Vec3', + # 启发式取 obj 类名会 GEP 错字段)。vpi 未命中时返回 None, + # 由后续属性访问 fast-fail 暴露 vpi 缺失根因(不静默回退)。 + ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if ca is None or ca.attr is None or ca.value is None: + return None + obj_cls: str = self._infer_rhs_annot(pool, mod, ca.value, trans) + if obj_cls is None: + # 模块级函数调用(requests.get):ca.value 是已导入模块名 + # 而非对象变量(模块名 lookup_var_entry 返回 None → 上面 + # 对象类名推断失败)。从该模块 vpi 的返回注解缓存解析返回 + # 类名(键 {sha1}.{func},cls_name=None 即模块级函数,与 + # CallGenMixin 跨模块返回类型解析一致)。 + # WebTest resp = requests.get(...) 根因:无注解赋值变量 + # AnnotClassName 推断失败(annot=None)→ 属性访问按需过滤 + # (依赖 AnnotClassName)失效 → "属性访问失败: .status_code"。 + if ca.value.kind() == ast.ASTKind.Name: + mod_nm_rhs: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value) + if mod_nm_rhs.id is not None: + mod_sha1_rhs: str = ExprCallBase._lookup_module_sha1( + mod_nm_rhs.id) + if mod_sha1_rhs is not None: + import lib.StubGen.VpiReader as VpiReader + temp_dir_rhs: str = None + import lib.core.Gen.Generator as Generator + g_rhs: Generator.Generator | t.CPtr = ( + Generator.Generator | t.CPtr)( + t.CVoid(HandlesExpr._g_gen, t.CPtr)) + if g_rhs is not None and g_rhs.TempDir is not None: + temp_dir_rhs = g_rhs.TempDir + if temp_dir_rhs is not None: + VpiReader._ensure_vpi_ret_annot_loaded( + mod_sha1_rhs, temp_dir_rhs) + annot_rhs: str = VpiReader._lookup_vpi_ret_annot( + mod_sha1_rhs, None, ca.attr) + if annot_rhs is not None: + ret_cls_rhs: str = self._extract_annot_class_name( + pool, annot_rhs) + if ret_cls_rhs is not None: + return ret_cls_rhs + return None + if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0: + return None + # 方法定义所在模块 SHA1(优先 struct entry,回退当前模块 sha1) + cls_sha1: str = HandlesStruct.get_struct_sha1(obj_cls) + if cls_sha1 is None and trans.ModuleSha1 is not None: + cls_sha1 = trans.ModuleSha1 + ret_cls: str = None + if cls_sha1 is not None: + import lib.StubGen.VpiReader as VpiReader + temp_dir: str = None + import lib.core.Gen.Generator as Generator + g2: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( + t.CVoid(HandlesExpr._g_gen, t.CPtr)) + if g2 is not None and g2.TempDir is not None: + temp_dir = g2.TempDir + if temp_dir is not None: + VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir) + annot_ret: str = VpiReader._lookup_vpi_ret_annot( + cls_sha1, obj_cls, ca.attr) + if annot_ret is not None: + ret_cls = self._extract_annot_class_name(pool, annot_ret) + return ret_cls + return None + # Name: 源变量注解 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm is None or nm.id is None: + return None + ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm.id) + if ve is None: + return None + return ve.AnnotClassName + # BinOp/UnaryOp: 运算符重载返回同类对象 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop is None or bop.left is None: + return None + dunder: str = self._op_to_dunder(bop.op) + if dunder is None: + return None + lhs_cls: str = self._infer_rhs_annot(pool, mod, bop.left, trans) + if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0: + return None + return lhs_cls + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uop is None or uop.operand is None: + return None + dunder: str = self._op_to_dunder(uop.op) + if dunder is None: + return None + opr_cls: str = self._infer_rhs_annot(pool, mod, uop.operand, trans) + if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0: + return None + return opr_cls + # Attribute: 字段注解类名(属性链递归,如 p = r.origin) + if k == ast.ASTKind.Attribute: + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( + t.CVoid(HandlesExpr._g_gen, t.CPtr)) + if g is not None: + return g._resolve_attr_field_class(pool, trans, node) + return None + return None + + # ============================================================ + # _extract_annot_class_name - 从返回注解文本提取结构体类名 + # + # vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除 + # 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/ + # CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合 + # 多候选时取首个命中段。 + # ============================================================ + def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr, + annot: str) -> str: + """从返回注解文本提取已注册结构体类名,无命中返回 None""" + if pool is None or annot is None: + return None + alen: t.CSizeT = string.strlen(annot) + if alen == 0: + return None + seg: str = pool.alloc(256) + if seg is None: + return None + start: t.CSizeT = 0 + i: t.CSizeT + for i in range(alen): + if annot[i] == '|': + seglen: t.CSizeT = i - start + # 段 [start, i):去除首尾空格与引号后查注册表 + s: t.CSizeT = start + e: t.CSizeT = i + while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): + s += 1 + while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): + e -= 1 + seglen = e - s + if seglen > 0 and seglen < 256: + string.strncpy(seg, annot + s, seglen) + seg[seglen] = '\0' + se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(seg) + if se is not None: + return seg + start = i + 1 + # 最后一段(无 '|' 后缀) + s: t.CSizeT = start + e: t.CSizeT = alen + while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): + s += 1 + while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): + e -= 1 + seglen: t.CSizeT = e - s + if seglen > 0 and seglen < 256: + string.strncpy(seg, annot + s, seglen) + seg[seglen] = '\0' + se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(seg) + if se is not None: + return seg + return None + + # ============================================================ + # _op_to_dunder - 运算符 → dunder 方法名(本地副本,避免跨 Mixin 调用) + # ============================================================ + def _op_to_dunder(self, op: int) -> str: + """BinOp/UnaryOp 运算符 → dunder 方法名,无映射返回 None""" + if op == ast.OpKind.Add: return "__add__" + if op == ast.OpKind.Sub: return "__sub__" + if op == ast.OpKind.Mult: return "__mul__" + if op == ast.OpKind.Div: return "__truediv__" + if op == ast.OpKind.FloorDiv: return "__floordiv__" + if op == ast.OpKind.Mod: return "__mod__" + if op == ast.OpKind.Pow: return "__pow__" + if op == ast.OpKind.BitAnd: return "__and__" + if op == ast.OpKind.BitOr: return "__or__" + if op == ast.OpKind.BitXor: return "__xor__" + if op == ast.OpKind.LShift: return "__lshift__" + if op == ast.OpKind.RShift: return "__rshift__" + if op == ast.OpKind.USub: return "__neg__" + if op == ast.OpKind.UAdd: return "__pos__" + if op == ast.OpKind.Invert: return "__invert__" + return None + + # ============================================================ + # _cls_has_dunder - 检查类(含继承链)是否存在 dunder 方法 + # + # 与 ExprGenMixin.try_operator_overload 的查找一致:当前模块内定义 + # 或跨模块类有 SHA1(stub 中声明)即视为存在。仅在确实存在时 + # 才采用运算符重载推断的类名,避免把原生运算误标为类类型。 + # ============================================================ + def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, dunder: str) -> int: + """类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1""" + if class_name is None or dunder is None or mod is None: + return 0 + lookup_name: str = pool.alloc(128) + if lookup_name is None: + return 0 + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) + if ExprCallBase.find_func_in_module(mod, lookup_name) is not None: + return 1 + # 继承链祖先查找 + mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) + mi: int = 1 + while mro_ptr is not None and mro_ptr[mi] != 0: + anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) + if anc is not None: + anc_lookup: str = pool.alloc(128) + if anc_lookup is not None: + viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder) + if ExprCallBase.find_func_in_module(mod, anc_lookup) is not None: + return 1 + mi += 1 + # 跨模块:类有 SHA1(stub 中声明该方法)视为存在 + if HandlesStruct.get_struct_sha1(class_name) is not None: + return 1 + return 0 diff --git a/App/lib/core/Gen/Generator.vp b/App/lib/core/Gen/Generator.vp index e45a580..61b5b79 100644 --- a/App/lib/core/Gen/Generator.vp +++ b/App/lib/core/Gen/Generator.vp @@ -42,6 +42,7 @@ import lib.core.Gen.ClassGenVTable as ClassGenVTable import lib.core.Gen.ClassGenDef as ClassGenDef import lib.core.Gen.ImportsGenMixin as ImportsGenMixin import lib.core.Gen.StmtGenMixin as StmtGenMixin +import lib.core.Gen.MatchGenMixin as MatchGenMixin import lib.core.Gen.AssignGenMixin as AssignGenMixin import lib.core.Gen.VarGenMixin as VarGenMixin import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin @@ -83,7 +84,8 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin, ClassGenEnum.ClassGenEnum, ClassGenGeneric.ClassGenGeneric, ClassGenVTable.ClassGenVTable, ClassGenDef.ClassGenDef, ImportsGenMixin.ImportsGenMixin, - StmtGenMixin.StmtGenMixin, AssignGenMixin.AssignGenMixin, + StmtGenMixin.StmtGenMixin, MatchGenMixin.MatchGenMixin, + AssignGenMixin.AssignGenMixin, VarGenMixin.VarGenMixin, TranslatorGenMixin.TranslatorGenMixin): """生成器:多继承 Mixin 组合(对象化迁移宿主)""" diff --git a/App/lib/core/Gen/ImportsGenMixin.vp b/App/lib/core/Gen/ImportsGenMixin.vp index 6a64e6b..ed3cc58 100644 --- a/App/lib/core/Gen/ImportsGenMixin.vp +++ b/App/lib/core/Gen/ImportsGenMixin.vp @@ -11,6 +11,8 @@ import w32.fileio as fileio import lib.core.StubMerger as StubMerger import lib.core.CompilerFactory as CompilerFactory import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesTranslator as HT +import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.StubMergerStore as StubMergerStore @@ -632,3 +634,119 @@ class ImportsGenMixin: else: self._report_import_error(node, "导入模块 SHA1 未注册(includes 扫描未找到该模块)") return 1 + + # ============================================================ + # translate_import - 处理 import 语句,更新 trans._imported_modules + # (迁移自 HandlesImports.ImportsHandle.HandleImport) + # ============================================================ + def translate_import(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """处理 import 语句,返回 0""" + imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(node) + if imp is None: + return 0 + names: list[ast.AST | t.CPtr] | t.CPtr = imp.names + if names is None: + return 0 + nn: t.CSizeT = len(names) + for ni in range(nn): + alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) + if alias is not None and alias.name is not None: + # 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查) + # declare_only=1/2 是 struct 预注册/import 扫描阶段:此时 SHA1 表 + # 尚未包含后续才追加的模块(如 App 源文件),检查会造成误报 + if trans._declare_only == 0: + self._check_import_sha1(node, alias.name) + pool_val: memhub.MemBuddy | t.CPtr = trans.Pool + im_val: str = trans._imported_modules + trans._imported_modules = self.add_imported_module( + pool_val, im_val, alias.name) + # 别名也加入导入模块列表(用于模块限定构造器检查 Module.Class()) + if alias.asname is not None: + trans._imported_modules = self.add_imported_module( + pool_val, trans._imported_modules, alias.asname) + # 别名也加入 from_imports(asname:fullname), + # 使 HT.func() 跨模块调用能通过 from_imports 查找别名→完整模块名→SHA1 + # 否则 _lookup_module_sha1("HT") 找不到(mod_arr 只存文件名 HandlesTranslator) + trans._from_imports = self.add_from_import( + pool_val, trans._from_imports, alias.asname, alias.name) + else: + # 无别名时(import a.b.c),将顶层包名 "a" 也加入 _imported_modules, + # 使 a.b.c 作为属性访问的 base 被翻译时能通过 is_module_imported("a") 检查 + dot_ptr: str = string.strstr(alias.name, '.') + if dot_ptr is not None: + pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_ptr) - t.CUInt64T(alias.name)) + if pkg_len > 0 and pkg_len < 256: + pkg_buf: bytes = pool_val.alloc(pkg_len + 1) + if pkg_buf is not None: + string.strncpy(pkg_buf, alias.name, pkg_len) + pkg_buf[pkg_len] = '\0' + trans._imported_modules = self.add_imported_module( + pool_val, trans._imported_modules, pkg_buf) + return 0 + + # ============================================================ + # translate_import_from_module - 处理 from X import Y 的模块部分 + # (迁移自 HandlesImports.ImportsHandle.HandleImportFromModule) + # + # 对相对导入(level > 0),使用 trans.CurrentPackage 解析为 + # 完整模块名(如 __types → llvmlite.__types),确保 .deps.txt + # 记录的模块名与 SHA1 映射表一致。 + # ============================================================ + def translate_import_from_module(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """处理 from X import Y 的模块部分,更新 trans._imported_modules""" + impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node) + if impf is None: + return 0 + # 解析模块名:相对导入需补充包前缀 + resolved: str = self._resolve_relative_module( + trans.Pool, trans.CurrentPackage, + impf.level, impf.module) + if resolved is not None: + # 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查) + if trans._declare_only == 0: + self._check_import_sha1(node, resolved) + trans._imported_modules = self.add_imported_module( + trans.Pool, trans._imported_modules, resolved) + return 0 + + # ============================================================ + # translate_import_from_names - 处理 from X import Y 的名称部分 + # (迁移自 HandlesImports.ImportsHandle.HandleImportFromNames) + # + # 同样使用解析后的完整模块名,确保 from-import 映射 + # (如 LLVMType:llvmlite.__types)能正确查到 SHA1。 + # ============================================================ + def translate_import_from_names(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """处理 from X import Y 的名称部分,更新 trans._from_imports""" + impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node) + if impf is None: + return 0 + # 解析模块名:相对导入需补充包前缀 + resolved: str = self._resolve_relative_module( + trans.Pool, trans.CurrentPackage, + impf.level, impf.module) + if resolved is not None: + names: list[ast.AST | t.CPtr] | t.CPtr = impf.names + if names is not None: + nn: t.CSizeT = len(names) + for ni in range(nn): + alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) + if alias is not None and alias.name is not None: + local_name: str = alias.name + orig_name: str = None + if alias.asname is not None: + local_name = alias.asname + orig_name = alias.name + trans._from_imports = self.add_from_import( + trans.Pool, trans._from_imports, + local_name, resolved, orig_name) + # 命名空间隔离:from-import 的名称标记为可见结构体 + HandlesStruct.add_visible_struct(trans.Pool, local_name) + # 注册 re-export 映射:当前模块 re-export 了 local_name,源模块为 resolved + # 使跨模块调用 module.func() 能解析到正确的源模块 SHA1 + if trans.ModuleSha1 is not None: + self.register_reexport(trans.ModuleSha1, local_name, resolved) + return 0 diff --git a/App/lib/core/Gen/MatchGenMixin.vp b/App/lib/core/Gen/MatchGenMixin.vp new file mode 100644 index 0000000..29cf6f9 --- /dev/null +++ b/App/lib/core/Gen/MatchGenMixin.vp @@ -0,0 +1,1306 @@ +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 +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 +import lib.core.Handles.HandlesType as HandlesType + + +# ============================================================ +# 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, + # 避免残留值误判。 + # ============================================================ + 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 = HandlesExpr.translate_value( + builder, pool, trans.Module, subject_node, + trans._funcs, trans._func_count, trans) + if subject_val is None: + # fail-fast: match subject 翻译失败 + HandlesType.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: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm.id) + if entry is not None and entry.AnnotClassName is not None \ + and HandlesClassDef._is_renum_class_name( + entry.AnnotClassName) != 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 = 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 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(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 HandlesClassDef._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 HandlesExpr.is_ptr_type(subj_ty) != 0 \ + and subj_ty.Pointee is not None \ + and HandlesExpr.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 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: + # fail-fast: REnum 结构体未注册,无法构造 + HandlesType.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 HandlesExpr.get_llvm_type_bits(subj_ty) != 64 \ + and 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: + # fail-fast: REnum tag 指针转换失败 + HandlesType.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 读取失败 + HandlesType.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: 标签缓冲区分配失败 + HandlesType.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 缺失 + HandlesType.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 分派数组分配失败 + HandlesType.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 = HandlesClassDef._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 = 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 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 = 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 \ + 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: + HandlesBody.translate_stmt(trans, stmt) + bi = bi + 1 + + # 退出 case 作用域 + HandlesVar.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) + HandlesVar.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: + HandlesBody.translate_stmt(trans, stmt) + dj = dj + 1 + HandlesVar.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: 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 = 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 = HandlesClassDef._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) + HandlesType.fatal_error( + sub_pat, + f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败", + "TypeError") + # 获取字段类型 + 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: + # fail-fast: 变体字段类型缺失,禁止兜底 i8 + HandlesType.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: 变体字段地址计算失败 + HandlesType.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 = HandlesClassDef._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 + HandlesVar.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 HandlesExpr.is_ptr_type(lhs.Ty) != 0 \ + or HandlesExpr.is_ptr_type(rhs.Ty) != 0: + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + if HandlesExpr.is_ptr_type(lhs.Ty) != 0: + lhs = llvmlite.build_ptrtoint(builder, lhs, i64_ty) + if HandlesExpr.is_ptr_type(rhs.Ty) != 0: + rhs = llvmlite.build_ptrtoint(builder, rhs, i64_ty) + lb: int = HandlesExpr.get_llvm_type_bits(lhs.Ty) + rb: int = HandlesExpr.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 = HandlesExpr.translate_value( + builder, pool, trans.Module, elt, + trans._funcs, trans._func_count, trans) + if sv is None: + HandlesType.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 / 顶层 _ 通配 + HandlesType.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 = HandlesExpr.translate_value( + builder, pool, trans.Module, mv.value, + trans._funcs, trans._func_count, trans) + if pv is None: + HandlesType.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: + HandlesType.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:序列模式变量绑定暂不支持 + HandlesType.fatal_error( + pat1, "序列模式变量绑定暂不支持", "NotImplementedError") + elif pk1 == ast.ASTKind.MatchStar: + continue # 剩余元素通配:恒真 + else: + HandlesType.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 = HandlesExpr.translate_value( + builder, pool, trans.Module, gnode, + trans._funcs, trans._func_count, trans) + if gv is None: + HandlesType.fatal_error( + gnode, "match guard 翻译失败", "TypeError") + gbits: int = HandlesExpr.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) + HandlesVar.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: + HandlesBody.translate_stmt(trans, stmt) + bi = bi + 1 + HandlesVar.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) + HandlesVar.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: + HandlesBody.translate_stmt(trans, stmt) + dj = dj + 1 + HandlesVar.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 = 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: + # fail-fast: subject 转 i32 失败 + HandlesType.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: 标签缓冲区分配失败 + HandlesType.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 缺失 + HandlesType.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 分派数组分配失败 + HandlesType.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 = 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 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 = 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 = len(body_list) + 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) + + # 末句控制流全 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) + HandlesVar.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: + HandlesBody.translate_stmt(trans, stmt) + dj = dj + 1 + HandlesVar.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 diff --git a/App/lib/core/Gen/StmtGenCifMixin.vp b/App/lib/core/Gen/StmtGenCifMixin.vp index 0b8fd00..f24ac04 100644 --- a/App/lib/core/Gen/StmtGenCifMixin.vp +++ b/App/lib/core/Gen/StmtGenCifMixin.vp @@ -17,6 +17,7 @@ import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesFunctions as HandlesFunctions import lib.core.Handles.HandlesClassDef as HandlesClassDef import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesBody as HandlesBody import lib.core.Handles.HandlesIf as HandlesIf import lib.core.Handles.HandlesWhile as HandlesWhile import lib.core.Handles.HandlesFor as HandlesFor @@ -462,58 +463,2054 @@ class StmtGenCifMixin: # CIfndef return 0 if defined != 0 else 1 - def NewIfHandle(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> HandlesIf.IfHandle | t.CPtr: - """创建 IfHandle 实例(迁移自 HandlesIf.NewIfHandle)""" - h: HandlesIf.IfHandle | t.CPtr = pool.alloc(HandlesIf.IfHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, HandlesIf.IfHandle.__sizeof__()) - h.Trans = trans - return h + # ============================================================ + # translate_return - Return 语句翻译(迁移自 HandlesReturn.ReturnHandle.Handle) + # + # 翻译返回值(若有)并生成 ret 指令;裸 return 按函数返回类型生成 + # 默认零值(void→ret void,ptr→null,float→0.0,其余→零值)。 + # ============================================================ + def translate_return(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 Return 语句""" + rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node) + if rt is None: + return 0 + + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + val: llvmlite.Value | t.CPtr = None + if rt.value is not None: + # return a, b → 打包匿名 struct 值(多返回值,函数返回类型 tuple[T1,T2]) + if rt.value.kind() == ast.ASTKind.Tuple: + rtp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(rt.value) + rtp_elts: list[ast.AST | t.CPtr] | t.CPtr = rtp.elts + rt_n: t.CSizeT = 0 + if rtp_elts is not None: + rt_n = len(rtp_elts) + if rt_n > 0 and rt_n <= 16: + rt_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 16) + if rt_vals is not None: + rt_val_ok: int = 1 + rt_head: llvmlite.ParamNode | t.CPtr = None + rt_tail: llvmlite.ParamNode | t.CPtr = None + rvi: t.CSizeT + for rvi in range(rt_n): + ev_i: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, rtp_elts.get(rvi), + trans._funcs, trans._func_count, trans) + if ev_i is None: + rt_val_ok = 0 + break + rt_vals[rvi] = t.CSizeT(ev_i) + if rt_val_ok != 0: + # 构建匿名 struct 类型(字段类型 = 元素值类型) + rvi2: t.CSizeT + for rvi2 in range(rt_n): + rv_i: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)( + t.CVoid(rt_vals[rvi2], t.CPtr)) + if rv_i is None or rv_i.Ty is None: + rt_val_ok = 0 + break + rn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, rv_i.Ty) + if rn is None: + rt_val_ok = 0 + break + if rt_head is None: + rt_head = rn + else: + llvmlite.paramnode_set_next(rt_tail, rn) + rt_tail = rn + rt_struct_ty: llvmlite.LLVMType | t.CPtr = None + if rt_val_ok != 0 and rt_head is not None: + rt_struct_ty = llvmlite.Struct(pool, rt_head, rt_n, None) + rt_tmp: llvmlite.Value | t.CPtr = None + if rt_struct_ty is not None: + rt_tmp = llvmlite.build_alloca(builder, rt_struct_ty) + if rt_tmp is not None: + rvi3: t.CSizeT + for rvi3 in range(rt_n): + rv3: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)( + t.CVoid(rt_vals[rvi3], t.CPtr)) + rfp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, rt_struct_ty, rv3.Ty, rt_tmp, rvi3) + if rfp is None: + rt_val_ok = 0 + break + llvmlite.build_store(builder, rv3, rfp) + if rt_val_ok != 0: + val = llvmlite.build_load(builder, rt_struct_ty, rt_tmp) + # return self: 返回 self 指针本身(Ptr(StructTy)),而非结构体值 + # translate_value 会 load 得到结构体值,但 return self 需要指针 + # 注意: lookup_var 返回的是存储 self 的 alloca (Ptr(Ptr(StructTy))) + # 需要 load 得到实际的 self 指针 (Ptr(StructTy)) + if rt.value.kind() == ast.ASTKind.Name: + ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rt.value) + if ret_nm is not None and ret_nm.id is not None \ + and string.strcmp(ret_nm.id, "self") == 0: + self_ptr: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, "self") + if self_ptr is not None: + # 检查 self_ptr 是否是 Ptr(Ptr(...))(alloca 存储指针) + self_pointee_ty: llvmlite.LLVMType | t.CPtr = None + match self_ptr.Ty: + case llvmlite.LLVMType.Ptr(inner_ty): + self_pointee_ty = inner_ty + if self_pointee_ty is not None and HandlesExpr.is_ptr_type(self_pointee_ty) != 0: + # Ptr(Ptr(StructTy)) → load 得到 Ptr(StructTy) + val = llvmlite.build_load(builder, self_pointee_ty, self_ptr) + else: + val = self_ptr + if val is None: + val = HandlesExpr.translate_value( + builder, pool, mod, rt.value, + trans._funcs, trans._func_count, trans) + + # val 为 None 时(裸 return):检查当前函数返回类型 + # void 函数(如 __init__/__before_init__)生成 ret void, + # ptr 函数生成 ret ptr null,浮点函数生成 ConstFloat(0.0), + # 否则 ret i32 0(浮点漏处理会报 llc: value doesn't match function result type) + if val is None: + cur_func: llvmlite.Function | t.CPtr = trans._cur_func + is_void_ret: int = 0 + is_ptr_ret: int = 0 + is_float_ret: int = 0 + ret_ty: llvmlite.LLVMType | t.CPtr = None + if cur_func is not None: + ret_ty = llvmlite.function_get_ret_ty(cur_func) + if ret_ty is not None: + match ret_ty: + case llvmlite.LLVMType.Void(): + is_void_ret = 1 + case llvmlite.LLVMType.Ptr(_pe): + is_ptr_ret = 1 + case llvmlite.LLVMType.Float(_fb): + is_float_ret = 1 + if is_void_ret != 0: + llvmlite.build_ret_void(builder) + return 0 + if is_ptr_ret != 0: + null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null") + llvmlite.build_ret(builder, null_val) + return 0 + if is_float_ret != 0: + zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0) + llvmlite.build_ret(builder, zero_f) + return 0 + if ret_ty is None: + # fail-fast: 裸 return 无法确定函数返回类型,禁止硬编码 i32 零值兜底 + HandlesType.fatal_error(rt, "函数返回类型无法确定", "TypeError") + val = llvmlite.ConstZero(pool, ret_ty) + if val is None: + # fail-fast: 无法按返回类型构造零值 + HandlesType.fatal_error(rt, "函数返回类型无法确定", "TypeError") + + # 类型转换:确保 val 类型与函数返回类型匹配 + # 处理 i1(bool 比较结果)→ i8(t.CBool)等情况 + # i1 → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF) + # 注意:当 val 是整数而 ret_ty 是 ptr 时(即使 bits 相同,如 i64 vs ptr), + # 也必须 inttoptr 转换,否则 llc 报 "value doesn't match function result type" + cur_func_rt: llvmlite.Function | t.CPtr = trans._cur_func + ret_ty_rt: llvmlite.LLVMType | t.CPtr = None + if cur_func_rt is not None and val is not None and val.Ty is not None: + ret_ty_rt = llvmlite.function_get_ret_ty(cur_func_rt) + if ret_ty_rt is not None: + val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty) + ret_bits: int = HandlesExpr.get_llvm_type_bits(ret_ty_rt) + val_is_ptr: int = HandlesExpr.is_ptr_type(val.Ty) + ret_is_ptr: int = HandlesExpr.is_ptr_type(ret_ty_rt) + # ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换 + if val_is_ptr != ret_is_ptr: + val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node) + elif val_is_ptr != 0 and ret_is_ptr != 0: + # 指针 → 指针且元素类型不同(如 t.CVoid(x, CPtr) 得到 i8*, + # 函数返回类型是类指针 Circle* 时)需 bitcast 回, + # 否则 llc 报 "value doesn't match function result type"。 + val_pointee: llvmlite.LLVMType | t.CPtr = None + ret_pointee: llvmlite.LLVMType | t.CPtr = None + match val.Ty: + case llvmlite.LLVMType.Ptr(v_inner): + val_pointee = v_inner + match ret_ty_rt: + case llvmlite.LLVMType.Ptr(r_inner): + ret_pointee = r_inner + if val_pointee is not None and ret_pointee is not None \ + and t.CUInt64T(val_pointee) != t.CUInt64T(ret_pointee): + val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node) + elif val_bits != 0 and ret_bits != 0 and val_bits != ret_bits: + if val_bits == 1 and val_bits < ret_bits: + val = llvmlite.build_zext(builder, val, ret_ty_rt) + else: + val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node) + llvmlite.build_ret(builder, val) + return 0 # ============================================================ - # 簇 C:循环/return/match 子 Handle 工厂(迁移自 - # HandlesWhile/HandlesFor/HandlesReturn/HandlesMatch) + # translate_if - if/elif/else 语句翻译(迁移自 HandlesIf.IfHandle.Handle) + # + # 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...) + # 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归 + # 求值失败(运行时变量等)→ 回退运行时翻译。 + # 运行时翻译 if 语句为 LLVM IR 控制流: + # br i1 %cond, label %then, label %else + # then: + # ... body ... + # br label %end + # else: + # ... orelse ... + # br label %end + # end: # ============================================================ + def translate_if(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 if/elif/else 语句""" + if node is None: + return 0 - def NewWhileHandle(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> HandlesWhile.WhileHandle | t.CPtr: - """创建 WhileHandle 实例(迁移自 HandlesWhile.NewWhileHandle)""" - h: HandlesWhile.WhileHandle | t.CPtr = pool.alloc(HandlesWhile.WhileHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, HandlesWhile.WhileHandle.__sizeof__()) - h.Trans = trans - return h + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func - def NewForHandle(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> HandlesFor.ForHandle | t.CPtr: - """创建 ForHandle 实例(迁移自 HandlesFor.NewForHandle)""" - h: HandlesFor.ForHandle | t.CPtr = pool.alloc(HandlesFor.ForHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, HandlesFor.ForHandle.__sizeof__()) - h.Trans = trans - return h + if builder is None or func is None: + return 0 - def NewReturnHandle(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> HandlesReturn.ReturnHandle | t.CPtr: - """创建 ReturnHandle 实例(迁移自 HandlesReturn.NewReturnHandle)""" - h: HandlesReturn.ReturnHandle | t.CPtr = pool.alloc(HandlesReturn.ReturnHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, HandlesReturn.ReturnHandle.__sizeof__()) - h.Trans = trans - return h + if_node: ast.If | t.CPtr = (ast.If | t.CPtr)(node) - def NewMatchHandle(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> HandlesMatch.MatchHandle | t.CPtr: - """创建 MatchHandle 实例(迁移自 HandlesMatch.NewMatchHandle)""" - h: HandlesMatch.MatchHandle | t.CPtr = pool.alloc(HandlesMatch.MatchHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, HandlesMatch.MatchHandle.__sizeof__()) - h.Trans = trans - return h + # 0. 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...) + # 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归 + # 求值失败(运行时变量等)→ 回退运行时翻译 + if self._is_cif_call(if_node.test) == 1: + cif_val: int = self._evaluate_cif_test(pool, trans, if_node.test) + if self.CifEvalOk != 0: + if cif_val != 0: + body_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.children + if body_cif is not None: + bc_cif: t.CSizeT = len(body_cif) + bi_cif: t.CSizeT + for bi_cif in range(bc_cif): + stmt_cif: ast.AST | t.CPtr = body_cif.get(bi_cif) + if stmt_cif is not None: + HandlesBody.translate_stmt(trans, stmt_cif) + else: + orelse_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse + if orelse_cif is not None and len(orelse_cif) == 1: + sub_cif: ast.AST | t.CPtr = orelse_cif.get(0) + if sub_cif is not None and sub_cif.kind() == ast.ASTKind.If: + # elif: 递归(子 If 的 test 仍会走 CIf 判定或运行时翻译) + self.translate_if(trans, sub_cif) + elif sub_cif is not None: + HandlesBody.translate_stmt(trans, sub_cif) + elif orelse_cif is not None: + oc_cif: t.CSizeT = len(orelse_cif) + oi_cif: t.CSizeT + for oi_cif in range(oc_cif): + stmt_cif2: ast.AST | t.CPtr = orelse_cif.get(oi_cif) + if stmt_cif2 is not None: + HandlesBody.translate_stmt(trans, stmt_cif2) + return 0 + + # 1. 求值条件表达式 + cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, if_node.test, + trans._funcs, trans._func_count, trans) + + # 2. 转换为 i1 条件 + # Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较 + if cond_val is None: + # fail-fast: if 条件表达式翻译失败 + HandlesType.fatal_error(if_node.test, "if 条件表达式翻译失败", "TypeError") + cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty) + if cond_bits == 1: + cond_i1: llvmlite.Value | t.CPtr = cond_val + elif HandlesExpr.is_ptr_type(cond_val.Ty) != 0: + # 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type") + null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null") + cond_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cond_val, null_cond) + else: + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + cond_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cond_val, zero) + + # 3. 创建基本块(使用 trans._label_counter 生成唯一标签名,不与 SSA 名共享) + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "if.then.%d", cnt) + then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "if.end.%d", cnt) + merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 检查是否有 else 分支 + has_else: int = 0 + orelse_list: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse + if orelse_list is not None: + if len(orelse_list) > 0: + has_else = 1 + + else_bb: llvmlite.BasicBlock | t.CPtr = None + if has_else == 1: + viperlib.snprintf(name_buf, 32, "if.else.%d", cnt) + else_bb = llvmlite.create_block(pool, func, name_buf) + + # 4. 发射条件分支 + if has_else == 1: + llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb) + else: + llvmlite.build_cond_br(builder, cond_i1, then_bb, merge_bb) + + # 5. 翻译 then body + # 重置 merge 可达标志:分支内嵌套控制流会覆盖该标志,分支末尾判定依据 + # "分支最后语句的控制流状态",须防进入本 If 前的残留值污染(append90 + # 末句 If 全 return 被 fail-fast 误判"流程掉出末尾"的根因链一环) + trans._ctrl_merge_reachable = 1 + llvmlite.position_at_end(builder, then_bb) + body: list[ast.AST | t.CPtr] | t.CPtr = if_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + # then 块未终止则跳到 merge(记录 then 是否 br 到 merge) + then_branches_merge: int = 0 + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + if trans._ctrl_merge_reachable == 0: + # 分支末尾是嵌套控制流且 merge 结构性不可达(全分支 return): + # 当前块是嵌套的 merge(无 terminator),补 unreachable 收尾。 + # 不补 br merge——否则外层 If 的"分支是否 br merge"判定把不可达 + # 分支当可达,函数末句 If 全 return 被误判"流程掉出末尾" + # (vipermath.vp atan2 根因;对齐 FuncGenDef append90 unreachable) + llvmlite.build_unreachable(builder) + else: + llvmlite.build_br(builder, merge_bb) + then_branches_merge = 1 + + # 6. 翻译 else body(若有) + else_branches_merge: int = 0 + if has_else == 1: + # 同 then:重置标志防残留(else 是普通语句时不被 then 的嵌套控制流值污染) + trans._ctrl_merge_reachable = 1 + llvmlite.position_at_end(builder, else_bb) + else_count: t.CSizeT = len(orelse_list) + for ei in range(else_count): + stmt: ast.AST | t.CPtr = orelse_list.get(ei) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + if trans._ctrl_merge_reachable == 0: + # 嵌套控制流全分支 return:补 unreachable,不 br merge(同 then 分支) + llvmlite.build_unreachable(builder) + else: + llvmlite.build_br(builder, merge_bb) + else_branches_merge = 1 + + # 7. merge 块可达性(追加90,末句控制流收尾判定用): + # 无 else 时 cond_br 直接跳 merge(恒可达);有 else 时任一分支 + # br 到 merge 即可达;全分支 return(无 br)才结构性不可达。 + # 经 HandlesBase 模块级全局传递(避免依赖 Translator 字段表) + trans._ctrl_merge_reachable = 1 + if has_else == 1 and then_branches_merge == 0 and else_branches_merge == 0: + trans._ctrl_merge_reachable = 0 + + # 8. 定位到 merge 块继续后续代码 + llvmlite.position_at_end(builder, merge_bb) + return 0 + + # ============================================================ + # translate_while - while 循环语句翻译(迁移自 HandlesWhile.WhileHandle.Handle) + # + # 翻译 while 语句为 LLVM IR 控制流: + # br label %cond + # cond: + # %t = + # %c = icmp ne i32 %t, 0 + # br i1 %c, label %body, label %end + # body: + # ... body ... + # br label %cond + # end: + # ============================================================ + def translate_while(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 while 循环语句""" + 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 + + while_node: ast.While | t.CPtr = (ast.While | t.CPtr)(node) + + # 1. 创建基本块: cond / body / end(使用 trans._label_counter,不与 SSA 名共享) + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "while.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "while.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "while.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 2. 跳转到 cond 块 + llvmlite.build_br(builder, cond_bb) + + # 3. cond 块: 求值条件,条件分支 + llvmlite.position_at_end(builder, cond_bb) + cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, while_node.test, + trans._funcs, trans._func_count, trans) + if cond_val is None: + # fail-fast: while 条件表达式翻译失败 + HandlesType.fatal_error(while_node.test, "while 条件表达式翻译失败", "TypeError") + + # Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较 + cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty) + if cond_bits == 1: + cond_i1: llvmlite.Value | t.CPtr = cond_val + elif HandlesExpr.is_ptr_type(cond_val.Ty) != 0: + # 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type") + null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null") + cond_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cond_val, null_cond) + else: + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + cond_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cond_val, zero) + llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb) + + # 4. body 块: 翻译循环体,跳回 cond + llvmlite.position_at_end(builder, body_bb) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = cond_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = while_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + # 恢复旧循环上下文 + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, cond_bb) + + # 5. 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:while 的 cond_br 恒引用 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + # 无限循环(条件常量真 1/True)且循环体无本层 break → 运行时无任何边 + # 到达 end 块(merge 结构性不可达)→ 置 0,函数收尾对末句 While 生成 + # unreachable(追加90:无 br 到达 merge 时才安全;否则 llc O2 把 + # br-to-unreachable 优化为 fall-through → 双分支执行崩溃)。 + # 修复 vrandom.gammavariate 的 while 1 全 return 被误判"流程掉出末尾"。 + if self._IsConstTrue(while_node.test) != 0 and self._StmtHasBreak(body) == 0: + trans._ctrl_merge_reachable = 0 + return 0 + + # ============================================================ + # 无限循环判定辅助(merge 可达性,迁移自 HandlesWhile 模块级函数) + # + # _IsConstTrue: while 条件为常量真(CONST_INT 非 0 / CONST_BOOL 真) + # _NodeHasBreak / _StmtHasBreak: 扫描本层 break(跳过嵌套 While/For + # 子树——嵌套循环的 break 归内层,不影响外层 merge 可达性) + # ============================================================ + def _IsConstTrue(self, test: ast.AST | t.CPtr) -> int: + """while 条件为常量真(1 / True)返回 1""" + if test is None: + return 0 + if test.kind() == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(test) + if cn.const_kind == ast.CONST_INT and cn.int_val != 0: + return 1 + if cn.const_kind == ast.CONST_BOOL and cn.int_val != 0: + return 1 + return 0 + + def _NodeHasBreak(self, node: ast.AST | t.CPtr) -> int: + """递归扫描节点子树(跳过嵌套 While/For 子树),含 Break 返回 1""" + if node is None: + return 0 + ch: list[ast.AST | t.CPtr] | t.CPtr = node.children + if ch is not None: + n: t.CSizeT = len(ch) + for bi in range(n): + c: ast.AST | t.CPtr = ch.get(bi) + if c is None: + continue + k: int = c.kind() + if k == ast.ASTKind.Break: + return 1 + if k == ast.ASTKind.While or k == ast.ASTKind.For: + continue + if self._NodeHasBreak(c) != 0: + return 1 + return 0 + + def _StmtHasBreak(self, body: list[ast.AST | t.CPtr] | t.CPtr) -> int: + """语句列表是否含本层 break(嵌套循环的 break 归内层)""" + if body is None: + return 0 + n: t.CSizeT = len(body) + for bi in range(n): + s: ast.AST | t.CPtr = body.get(bi) + if s is None: + continue + k: int = s.kind() + if k == ast.ASTKind.Break: + return 1 + if k == ast.ASTKind.While or k == ast.ASTKind.For: + continue + if self._NodeHasBreak(s) != 0: + return 1 + return 0 + + # ============================================================ + # translate_for - for 循环语句翻译(迁移自 HandlesFor.ForHandle.Handle) + # + # 支持 for i in range(start, stop, step) 模式: + # %i = alloca i32 + # store i32 start, i32* %i + # br label %cond + # cond: + # %cur = load i32, i32* %i + # %cmp = icmp slt i32 %cur, stop + # br i1 %cmp, label %body, label %end + # body: + # ... body ... + # br label %incr + # incr: + # %cur2 = load i32, i32* %i + # %next = add i32 %cur2, step + # store i32 %next, i32* %i + # br label %cond + # end: + # ============================================================ + def translate_for(self, trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 for i in range(...) 循环语句""" + 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 + + for_node: ast.For | t.CPtr = (ast.For | t.CPtr)(node) + + # 1. 获取循环变量(Name 单变量 / Tuple 多变量) + target: ast.AST | t.CPtr = for_node.target + if target is None: + return 0 + tk: int = target.kind() + if tk != ast.ASTKind.Name and tk != ast.ASTKind.Tuple: + return 0 + var_name: str = None + if tk == ast.ASTKind.Name: + target_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) + var_name = target_nm.id + if var_name is None: + return 0 + + # 2. 解析迭代器:支持 range() 和指针迭代 + iter_node: ast.AST | t.CPtr = for_node.iter + if iter_node is None: + return 0 + + # 检查是否是 range() 调用 + is_range_iter: int = 0 + if iter_node.kind() == ast.ASTKind.Call: + call_pre: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) + fn_pre: str = HandlesExpr.get_func_name(call_pre.func) + if fn_pre is not None: + if string.strcmp(fn_pre, "range") == 0: + is_range_iter = 1 + elif string.strcmp(fn_pre, "enumerate") == 0 or string.strcmp(fn_pre, "zip") == 0: + pass # 多变量迭代,在下方非 range 分支处理 + else: + err_msg: str = pool.alloc(256) + if err_msg is not None: + viperlib.snprintf(err_msg, 256, "仅支持 range()/enumerate()/zip() 或指针迭代,got call '%s'", fn_pre) + HandlesType.fatal_error(iter_node, err_msg) + HandlesType.fatal_error(iter_node, "仅支持 range()/enumerate()/zip() 或指针迭代") + + # 非范围迭代:走指针/数组/列表字面量/容器/多变量迭代路径 + if is_range_iter == 0: + # 列表字面量:按元素顺序迭代(for x in [1, 2, 3]) + if iter_node.kind() == ast.ASTKind.List: + return self._handle_list_literal_iter(trans, for_node, var_name, iter_node) + # enumerate(x):for i, v in enumerate(x)(多变量迭代) + if iter_node.kind() == ast.ASTKind.Call: + call_mi: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) + fn_mi: str = HandlesExpr.get_func_name(call_mi.func) + if fn_mi is not None and string.strcmp(fn_mi, "enumerate") == 0: + if tk != ast.ASTKind.Tuple: + HandlesType.fatal_error(iter_node, "enumerate 迭代需要两个循环变量 (for i, v in enumerate(x))") + tup_ie: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) + t1_buf_ie: bytes = pool.alloc(128) + t2_buf_ie: bytes = pool.alloc(128) + if t1_buf_ie is None or t2_buf_ie is None: + return 0 + t1_buf_ie[0] = '\0' + t2_buf_ie[0] = '\0' + if self._extract_tuple_names(tup_ie, t1_buf_ie, t2_buf_ie) == 0: + HandlesType.fatal_error(iter_node, "enumerate 迭代变量必须是简单名称") + return self._handle_enumerate_iter(trans, for_node, t1_buf_ie, t2_buf_ie, call_mi) + if fn_mi is not None and string.strcmp(fn_mi, "zip") == 0: + if tk != ast.ASTKind.Tuple: + HandlesType.fatal_error(iter_node, "zip 迭代需要两个循环变量 (for a, b in zip(...))") + tup_iz: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) + t1_buf_iz: bytes = pool.alloc(128) + t2_buf_iz: bytes = pool.alloc(128) + if t1_buf_iz is None or t2_buf_iz is None: + return 0 + t1_buf_iz[0] = '\0' + t2_buf_iz[0] = '\0' + if self._extract_tuple_names(tup_iz, t1_buf_iz, t2_buf_iz) == 0: + HandlesType.fatal_error(iter_node, "zip 迭代变量必须是简单名称") + return self._handle_zip_iter(trans, for_node, t1_buf_iz, t2_buf_iz, call_mi) + # list[T] 容器变量:按 __count__ 动态长度迭代 + if iter_node.kind() == ast.ASTKind.Name and trans is not None: + nm_lst: ast.Name | t.CPtr = (ast.Name | t.CPtr)(iter_node) + if nm_lst.id is not None: + ve_lst: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm_lst.id) + if ve_lst is not None and ve_lst.AnnotClassName is not None: + # dict 容器变量:按 __count__/__keys__ 布局迭代(__iter__ 协议内联) + if string.strstr(ve_lst.AnnotClassName, "dict") is not None: + lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, iter_node, + trans._funcs, trans._func_count, trans) + if lst_val is not None and lst_val.Ty is not None \ + and HandlesExpr.is_ptr_type(lst_val.Ty) != 0: + return self._handle_dict_iter(trans, for_node, var_name, lst_val) + if string.strstr(ve_lst.AnnotClassName, "list") is not None: + lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, iter_node, + trans._funcs, trans._func_count, trans) + if lst_val is not None and lst_val.Ty is not None \ + and HandlesExpr.is_ptr_type(lst_val.Ty) != 0: + return self._handle_list_iter(trans, for_node, var_name, lst_val) + # OOP iter 协议:迭代源是类对象且类有 __iter__/__next__ 方法 → + # 走 __iter__/__next__ 调用迭代(对齐 TPC HandlesFor.py L142-166 + # _HandleForIterLlvm)。dict/list 是内置泛型容器已在上方内联处理。 + ov_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, iter_node, + trans._funcs, trans._func_count, trans) + if ov_val is not None and ov_val.Ty is not None \ + and HandlesExpr.is_ptr_type(ov_val.Ty) != 0: + ov_st: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value( + ov_val) + if ov_st is not None: + ov_cn: str = HandlesStruct.get_class_name_by_type(pool, ov_st) + if ov_cn is not None: + oi_lookup: str = pool.alloc(128) + if oi_lookup is not None: + viperlib.snprintf(oi_lookup, 128, "%s.__iter__", ov_cn) + oi_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( + trans.Module, oi_lookup) + if oi_fn is not None: + on_lookup: str = pool.alloc(128) + if on_lookup is not None: + viperlib.snprintf(on_lookup, 128, "%s.__next__", ov_cn) + on_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( + trans.Module, on_lookup) + if on_fn is not None: + return self._handle_oop_iter( + trans, for_node, var_name, ov_cn, ov_val) + # 其它不支持的字面量:fast-fail 显式报错, + # 避免 translate_value 触发 list[T] 特化崩溃或语义歧义。 + ik: int = iter_node.kind() + if ik == ast.ASTKind.Constant: + cn_ik: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(iter_node) + if cn_ik.const_kind != ast.CONST_STR: + HandlesType.fatal_error( + iter_node, + "for 迭代不支持该常量(仅支持字符串、数组、列表字面量、range())") + elif ik == ast.ASTKind.Dict or ik == ast.ASTKind.Set or ik == ast.ASTKind.Tuple \ + or ik == ast.ASTKind.SetComp or ik == ast.ASTKind.DictComp: + HandlesType.fatal_error( + iter_node, + "for 迭代不支持字典/集合/元组字面量,请使用 range()、t.CArray 数组或列表字面量") + return self._handle_ptr_iter(trans, for_node, var_name) + + call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) + + # 3. 解析 range 参数: range(stop) / range(start, stop) / range(start, stop, step) + args: list[ast.AST | t.CPtr] | t.CPtr = call.args + if args is None: + return 0 + arg_count: t.CSizeT = len(args) + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + start_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + stop_val: llvmlite.Value | t.CPtr = None + step_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + + if arg_count == 0: + # fail-fast: range 无参数,立即终止 + HandlesType.fatal_error(call, "range 需要至少一个参数", "SyntaxError") + elif arg_count == 1: + stop_val = HandlesExpr.translate_value( + builder, pool, trans.Module, args.get(0), + trans._funcs, trans._func_count, trans) + if stop_val is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError") + elif arg_count >= 2: + start_val = HandlesExpr.translate_value( + builder, pool, trans.Module, args.get(0), + trans._funcs, trans._func_count, trans) + if start_val is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError") + stop_val = HandlesExpr.translate_value( + builder, pool, trans.Module, args.get(1), + trans._funcs, trans._func_count, trans) + if stop_val is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(args.get(1), "range 参数翻译失败", "TypeError") + if arg_count >= 3: + step_val = HandlesExpr.translate_value( + builder, pool, trans.Module, args.get(2), + trans._funcs, trans._func_count, trans) + if step_val is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(args.get(2), "range 参数翻译失败", "TypeError") + # step 为负数字面量时循环条件反转(对齐 TPC HandlesFor.py L86-94): + # range(a, b, -1) → i > stop;range(a, b, +1) → i < stop。 + # TPC 仅识别负数字面量(UnaryOp USub 常量 / 负常量);变量 step 保守按正。 + # 修复 _find_provider 的 range(top-1, -1, -1) 循环体不执行(i < -1 恒假)。 + step_neg_const: int = 0 + if arg_count >= 3: + step_arg_node: ast.AST | t.CPtr = args.get(2) + if step_arg_node is not None: + skn: int = step_arg_node.kind() + if skn == ast.ASTKind.UnaryOp: + uop_r: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(step_arg_node) + if uop_r.op == ast.OpKind.USub and uop_r.operand is not None: + if uop_r.operand.kind() == ast.ASTKind.Constant: + uoc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_r.operand) + if uoc_r.int_val > 0: + step_neg_const = 1 + elif skn == ast.ASTKind.Constant: + skc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(step_arg_node) + if skc_r.int_val < 0: + step_neg_const = 1 + + # 4. 创建/查找循环变量 alloca + var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = HandlesVar._alloca_at_entry(builder, i32_ty) + if HandlesVar.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 获取循环变量的实际元素类型(alloca 是指针类型,需解引用 Pointee) + # 当循环变量已声明为 i64(如 t.CSizeT),使用 i64 而非硬编码 i32 + # 避免 load i32, i64* / store i32, i64* 类型不匹配 + loop_var_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if var_alloca is not None and var_alloca.Ty is not None: + match var_alloca.Ty: + case llvmlite.LLVMType.Ptr(pointee_ty): + if pointee_ty is not None: + loop_var_ty = pointee_ty + loop_var_bits: int = HandlesExpr.get_llvm_type_bits(loop_var_ty) + + # 5. 存储初始值 (类型对齐: start_val 可能是 i32/i64,需对齐到 loop_var_ty) + init_val: llvmlite.Value | t.CPtr = start_val + if start_val is not None and start_val.Ty is not None: + start_bits: int = HandlesExpr.get_llvm_type_bits(start_val.Ty) + if start_bits != 0 and start_bits != loop_var_bits: + if start_bits < loop_var_bits: + init_val = llvmlite.build_sext(builder, start_val, loop_var_ty) + else: + init_val = llvmlite.build_trunc(builder, start_val, loop_var_ty) + llvmlite.build_store(builder, init_val, var_alloca) + + # 6. 创建基本块: cond / body / incr / end(使用 trans._label_counter,不与 SSA 名共享) + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "for.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "for.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "for.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "for.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 7. 跳转到 cond 块 + llvmlite.build_br(builder, cond_bb) + + # 8. cond 块: load i, icmp slt i, stop, cond_br body/end + llvmlite.position_at_end(builder, cond_bb) + cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca) + # 类型对齐: stop_val 可能是 i64 (如 range(strlen(s))),需将 cur_i 提升到 stop_val 类型 + cmp_lhs: llvmlite.Value | t.CPtr = cur_i + cmp_rhs: llvmlite.Value | t.CPtr = stop_val + if stop_val is not None and stop_val.Ty is not None: + stop_bits: int = HandlesExpr.get_llvm_type_bits(stop_val.Ty) + cur_bits: int = HandlesExpr.get_llvm_type_bits(cur_i.Ty) + if stop_bits != 0 and cur_bits != 0 and stop_bits != cur_bits: + if cur_bits < stop_bits: + cmp_lhs = llvmlite.build_sext(builder, cur_i, stop_val.Ty) + else: + # 循环变量位宽 > stop 位宽(如 t.CSizeT 循环变量 + range(i32)): + # 应把 cur_i 截断到 stop_val 类型(低向高才 sext/zext,高向低用 + # trunc)。原实现反了——把小的 stop_val trunc 到大的 loop_var_ty, + # 生成 `trunc i32 to i64` 扩宽非法 IR,llc 报 + # "invalid cast opcode for cast from 'i32' to 'i64'" + # (VpiReader.vp range(arg_count) 追加86 根因)。 + cmp_lhs = llvmlite.build_trunc(builder, cur_i, stop_val.Ty) + # step 为负时条件反转:i > stop(ICMP_SGT);正/缺省 step 保持 i < stop + range_cmp_op: int = llvmlite.ICMP_SLT + if step_neg_const != 0: + range_cmp_op = llvmlite.ICMP_SGT + cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, range_cmp_op, cmp_lhs, cmp_rhs) + llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb) + + # 9. body 块: 翻译循环体,跳到 incr + llvmlite.position_at_end(builder, body_bb) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + # 恢复旧循环上下文 + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # 10. incr 块: i = i + step, 跳回 cond + llvmlite.position_at_end(builder, incr_bb) + cur_i2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca) + # 类型对齐: step_val 可能是 i32/i64,需对齐到 loop_var_ty 与 cur_i2 类型一致 + incr_step: llvmlite.Value | t.CPtr = step_val + if step_val is not None and step_val.Ty is not None: + step_bits: int = HandlesExpr.get_llvm_type_bits(step_val.Ty) + cur2_bits: int = HandlesExpr.get_llvm_type_bits(cur_i2.Ty) + if step_bits != 0 and cur2_bits != 0 and step_bits != cur2_bits: + if step_bits > cur2_bits: + incr_step = llvmlite.build_trunc(builder, step_val, loop_var_ty) + else: + incr_step = llvmlite.build_sext(builder, step_val, loop_var_ty) + next_i: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_i2, incr_step) + llvmlite.build_store(builder, next_i, var_alloca) + llvmlite.build_br(builder, cond_bb) + + # 11. 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + # ============================================================ + # 多变量迭代辅助(enumerate / zip,迁移自 ForHandleBase) + # + # 支持迭代源: range(start, stop, step) / 字符串(常量|变量) / list[T] + # enumerate(x) → for i, v in enumerate(x):i 为序号,v 为元素 + # zip(a, b) → for x, y in zip(a, b):任一源耗尽即终止 + # ============================================================ + def _extract_tuple_names(self, tup: ast.Tuple | t.CPtr, + out1: str | t.CPtr, out2: str | t.CPtr) -> int: + """从 Tuple target 提取前两个 Name 变量名,写入 out1/out2,成功返回 1""" + if tup is None or tup.elts is None or out1 is None or out2 is None: + return 0 + elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts + n: t.CSizeT = len(elts) + if n < 2: + return 0 + e0: ast.AST | t.CPtr = elts.get(0) + e1: ast.AST | t.CPtr = elts.get(1) + if e0 is None or e1 is None: + return 0 + if e0.kind() != ast.ASTKind.Name or e1.kind() != ast.ASTKind.Name: + return 0 + n0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e0) + n1: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e1) + if n0.id is None or n1.id is None: + return 0 + string.strcpy(out1, n0.id) + string.strcpy(out2, n1.id) + return 1 + + def _seq_kind(self, trans: HT.Translator | t.CPtr, + src: ast.AST | t.CPtr) -> int: + """判断迭代源类型: SEQ_KIND_RANGE / STR / LIST,不支持返回 0""" + if src is None: + return 0 + k: int = src.kind() + if k == ast.ASTKind.Call: + cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src) + fn_s: str = HandlesExpr.get_func_name(cl_s.func) + if fn_s is not None and string.strcmp(fn_s, "range") == 0: + return HandlesFor.SEQ_KIND_RANGE + return 0 + if k == ast.ASTKind.Constant: + cn_s: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(src) + if cn_s is not None and cn_s.const_kind == ast.CONST_STR: + return HandlesFor.SEQ_KIND_STR + return 0 + if k == ast.ASTKind.Name: + nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(src) + if nm_s.id is not None and trans is not None: + ve_s: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm_s.id) + if ve_s is not None and ve_s.AnnotClassName is not None: + if string.strstr(ve_s.AnnotClassName, "list") is not None: + return HandlesFor.SEQ_KIND_LIST + return HandlesFor.SEQ_KIND_STR + return 0 + + def _build_seq_loop(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + t1: str, t2: str, + src1: ast.AST | t.CPtr, + src2: ast.AST | t.CPtr, + n_srcs: int) -> int: + """生成序列迭代循环(enumerate: n_srcs=1 / zip: n_srcs=2) + + 循环变量 alloca 自动创建或复用;元素类型由源类型决定 + (RANGE→i32, STR→i8, LIST→i8*)。索引内部统一 i64。 + """ + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # ---- 源 1 准备 ---- + kind1: int = self._seq_kind(trans, src1) + if kind1 == 0: + HandlesType.fatal_error(for_node, "序列迭代: 源 1 类型不支持") + r1_start: llvmlite.Value | t.CPtr = None + r1_stop: llvmlite.Value | t.CPtr = None + r1_step: llvmlite.Value | t.CPtr = None + s1_ptr: llvmlite.Value | t.CPtr = None + l1_count: llvmlite.Value | t.CPtr = None + l1_data: llvmlite.Value | t.CPtr = None + l1_esize: llvmlite.Value | t.CPtr = None + elem1_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty + if kind1 == HandlesFor.SEQ_KIND_RANGE: + elem1_ty = i32_ty + r1_start = llvmlite.const_int64(pool, 0) + r1_step = llvmlite.const_int64(pool, 1) + r1_stop = llvmlite.const_int64(pool, 0) + # 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移) + call_src1: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src1) + cargs1: list[ast.AST | t.CPtr] | t.CPtr = call_src1.args + if cargs1 is not None: + n1: t.CSizeT = len(cargs1) + if n1 >= 1: + sv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, cargs1.get(0), + trans._funcs, trans._func_count, trans) + if sv is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs1.get(0), "range 参数翻译失败", "TypeError") + r1_stop = HandlesExpr.coerce_to_type(builder, sv, i64_ty, cargs1.get(0)) + if n1 >= 2: + sv2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, cargs1.get(1), + trans._funcs, trans._func_count, trans) + if sv2 is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs1.get(1), "range 参数翻译失败", "TypeError") + r1_start = HandlesExpr.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1)) + if n1 >= 3: + sv3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, cargs1.get(2), + trans._funcs, trans._func_count, trans) + if sv3 is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs1.get(2), "range 参数翻译失败", "TypeError") + r1_step = HandlesExpr.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2)) + elif kind1 == HandlesFor.SEQ_KIND_STR: + elem1_ty = i8_ty + s1_ptr = HandlesExpr.translate_value( + builder, pool, trans.Module, src1, + trans._funcs, trans._func_count, trans) + if s1_ptr is None: + HandlesType.fatal_error(for_node, "序列迭代: 字符串源翻译失败") + elif kind1 == HandlesFor.SEQ_KIND_LIST: + elem1_ty = i8_ptr_ty + l1_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, src1, + trans._funcs, trans._func_count, trans) + if l1_obj is None or l1_obj.Ty is None \ + or HandlesExpr.is_ptr_type(l1_obj.Ty) == 0: + HandlesType.fatal_error(for_node, "序列迭代: list 源不是指针类型") + l1_count = llvmlite.build_load(builder, i64_ty, + llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 1))) + l1_data = llvmlite.build_load(builder, i8_ptr_ty, + llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 0))) + l1_esize = llvmlite.build_load(builder, i64_ty, + llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 4))) + + # ---- 源 2 准备(zip)---- + kind2: int = 0 + elem2_ty: llvmlite.LLVMType | t.CPtr = elem1_ty + s2_ptr: llvmlite.Value | t.CPtr = None + l2_count: llvmlite.Value | t.CPtr = None + l2_data: llvmlite.Value | t.CPtr = None + l2_esize: llvmlite.Value | t.CPtr = None + r2_start: llvmlite.Value | t.CPtr = None + r2_stop: llvmlite.Value | t.CPtr = None + r2_step: llvmlite.Value | t.CPtr = None + if n_srcs >= 2: + kind2 = self._seq_kind(trans, src2) + if kind2 == 0: + HandlesType.fatal_error(for_node, "序列迭代: 源 2 类型不支持") + if kind2 == HandlesFor.SEQ_KIND_RANGE: + elem2_ty = i32_ty + r2_start = llvmlite.const_int64(pool, 0) + r2_step = llvmlite.const_int64(pool, 1) + r2_stop = llvmlite.const_int64(pool, 0) + # 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移) + call_src2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src2) + cargs2: list[ast.AST | t.CPtr] | t.CPtr = call_src2.args + if cargs2 is not None: + n2: t.CSizeT = len(cargs2) + if n2 >= 1: + svz: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, cargs2.get(0), + trans._funcs, trans._func_count, trans) + if svz is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs2.get(0), "range 参数翻译失败", "TypeError") + r2_stop = HandlesExpr.coerce_to_type(builder, svz, i64_ty, cargs2.get(0)) + if n2 >= 2: + svz2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, cargs2.get(1), + trans._funcs, trans._func_count, trans) + if svz2 is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs2.get(1), "range 参数翻译失败", "TypeError") + r2_start = HandlesExpr.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1)) + if n2 >= 3: + svz3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, cargs2.get(2), + trans._funcs, trans._func_count, trans) + if svz3 is None: + # fail-fast: range 参数翻译失败 + HandlesType.fatal_error(cargs2.get(2), "range 参数翻译失败", "TypeError") + r2_step = HandlesExpr.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2)) + elif kind2 == HandlesFor.SEQ_KIND_STR: + elem2_ty = i8_ty + s2_ptr = HandlesExpr.translate_value( + builder, pool, trans.Module, src2, + trans._funcs, trans._func_count, trans) + if s2_ptr is None: + HandlesType.fatal_error(for_node, "序列迭代: 字符串源 2 翻译失败") + elif kind2 == HandlesFor.SEQ_KIND_LIST: + elem2_ty = i8_ptr_ty + l2_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, src2, + trans._funcs, trans._func_count, trans) + if l2_obj is None or l2_obj.Ty is None \ + or HandlesExpr.is_ptr_type(l2_obj.Ty) == 0: + HandlesType.fatal_error(for_node, "序列迭代: list 源 2 不是指针类型") + l2_count = llvmlite.build_load(builder, i64_ty, + llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 1))) + l2_data = llvmlite.build_load(builder, i8_ptr_ty, + llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 0))) + l2_esize = llvmlite.build_load(builder, i64_ty, + llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 4))) + + # ---- 循环变量 alloca ---- + # t1: enumerate → 序号 (i32);zip → 源 1 元素 + t1_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, t1) + new_vars: int = 0 + if t1_alloca is None: + if n_srcs == 1: + t1_alloca = HandlesVar._alloca_at_entry(builder, i32_ty) + else: + t1_alloca = HandlesVar._alloca_at_entry(builder, elem1_ty) + if t1_alloca is not None: + if HandlesVar.define_var(trans.SymTab, t1, t1_alloca) == 0: + new_vars += 1 + # t2: 源 2 元素(enumerate 时 = 源 1 元素) + t2_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, t2) + if t2_alloca is None: + t2_alloca = HandlesVar._alloca_at_entry(builder, elem2_ty) + if t2_alloca is not None: + if HandlesVar.define_var(trans.SymTab, t2, t2_alloca) == 0: + new_vars += 1 + + # 隐式 index 变量 (i64) + idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) + + # 基本块: cond / body / incr / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "seq.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "seq.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "seq.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "seq.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + llvmlite.build_br(builder, cond_bb) + + # cond 块: 源 1 done 检查(zip 需源 2 也 done) + llvmlite.position_at_end(builder, cond_bb) + cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) + done1: llvmlite.Value | t.CPtr = None + if kind1 == HandlesFor.SEQ_KIND_RANGE: + done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r1_stop) + elif kind1 == HandlesFor.SEQ_KIND_STR: + ch_ptr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx) + ch1: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr1) + zero1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0) + done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch1, zero1) + elif kind1 == HandlesFor.SEQ_KIND_LIST: + done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l1_count) + cont: llvmlite.Value | t.CPtr = done1 + if n_srcs >= 2: + done2: llvmlite.Value | t.CPtr = None + if kind2 == HandlesFor.SEQ_KIND_RANGE: + done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r2_stop) + elif kind2 == HandlesFor.SEQ_KIND_STR: + ch_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx) + ch2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr2) + zero2: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0) + done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch2, zero2) + elif kind2 == HandlesFor.SEQ_KIND_LIST: + done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l2_count) + cont = llvmlite.build_and(builder, done1, done2) + llvmlite.build_cond_br(builder, cont, body_bb, end_bb) + + # body 块: 获取元素 → store → 循环体 + llvmlite.position_at_end(builder, body_bb) + # 源 1 元素 + v1: llvmlite.Value | t.CPtr = None + if kind1 == HandlesFor.SEQ_KIND_RANGE: + step1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r1_step) + v1 = llvmlite.build_add(builder, r1_start, step1) + elif kind1 == HandlesFor.SEQ_KIND_STR: + ch_ptr1b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx) + v1 = llvmlite.build_load(builder, i8_ty, ch_ptr1b) + elif kind1 == HandlesFor.SEQ_KIND_LIST: + off1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l1_esize) + addr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l1_data, off1) + v1 = llvmlite.build_load(builder, i8_ptr_ty, addr1) + # store t1 / t2 + if t1_alloca is not None and t1_alloca.Ty is not None: + t1_ty: llvmlite.LLVMType | t.CPtr = t1_alloca.Ty.Pointee + if n_srcs == 1: + # enumerate: t1 = 序号(trunc i64 → i32) + idx32: llvmlite.Value | t.CPtr = llvmlite.build_trunc(builder, cur_idx, i32_ty) + llvmlite.build_store(builder, idx32, t1_alloca) + if t2_alloca is not None and t2_alloca.Ty is not None and v1 is not None: + t2_ty: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee + v1c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v1, t2_ty, src1) + llvmlite.build_store(builder, v1c, t2_alloca) + else: + if v1 is not None: + v1c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v1, t1_ty, src1) + llvmlite.build_store(builder, v1c, t1_alloca) + # 源 2 元素 → t2 + v2: llvmlite.Value | t.CPtr = None + if kind2 == HandlesFor.SEQ_KIND_RANGE: + step2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r2_step) + v2 = llvmlite.build_add(builder, r2_start, step2) + elif kind2 == HandlesFor.SEQ_KIND_STR: + ch_ptr2b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx) + v2 = llvmlite.build_load(builder, i8_ty, ch_ptr2b) + elif kind2 == HandlesFor.SEQ_KIND_LIST: + off2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l2_esize) + addr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l2_data, off2) + v2 = llvmlite.build_load(builder, i8_ptr_ty, addr2) + if t2_alloca is not None and t2_alloca.Ty is not None and v2 is not None: + t2_ty2: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee + v2c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v2, t2_ty2, src2) + llvmlite.build_store(builder, v2c, t2_alloca) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # incr 块: index++ + llvmlite.position_at_end(builder, incr_bb) + one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) + llvmlite.build_store(builder, next_idx, idx_alloca) + llvmlite.build_br(builder, cond_bb) + + # 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + # ============================================================ + # _handle_ptr_iter - 指针迭代: for x in ptr:(迁移自 ForHandleIter) + # 遍历指针,依赖隐式 index,直到解引用为空(null 终止符) + # + # 生成 IR 结构: + # %idx = alloca i32 + # store i32 0, i32* %idx + # br label %cond + # cond: + # %i = load i32, i32* %idx + # %ep = getelementptr elem_ty, ptr_ty %ptr, i32 %i + # %ev = load elem_ty, elem_ty* %ep + # %null = icmp eq elem_ty %ev, 0 + # br i1 %null, label %end, label %body + # body: + # store elem_ty %ev, elem_ty* %var + # ... 循环体 ... + # br label %incr + # incr: + # %next = add i32 %i, 1 + # store i32 %next, i32* %idx + # br label %cond + # end: + # ============================================================ + def _handle_ptr_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str) -> int: + """指针迭代: for x in ptr: 直到解引用为空""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + # 翻译迭代器表达式,获取指针值 + ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, for_node.iter, + trans._funcs, trans._func_count, trans) + if ptr_val is None: + HandlesType.fatal_error(for_node, "指针迭代: 无法翻译迭代器表达式") + + # 检查迭代器类型 + if HandlesExpr.is_ptr_type(ptr_val.Ty) == 0: + # 数组迭代:for k in arr(定长数组按长度迭代,元素可为任意类型) + if HandlesExpr.is_array_type(ptr_val.Ty) != 0: + return self._handle_array_iter(trans, for_node, var_name, ptr_val) + HandlesType.fatal_error(for_node, "指针迭代: 迭代器不是指针类型") + + # 获取元素类型 + elem_ty: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if elem_ty is None: + HandlesType.fatal_error(for_node, "指针迭代: 无法获取元素类型") + + # 元素类型是数组(Ptr([N x T]),如 t.CArray 变量退化指针): + # load 出数组值后走数组迭代(按长度,非 null 终止) + if HandlesExpr.is_array_type(elem_ty) != 0: + arr_v2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, ptr_val) + if arr_v2 is not None: + return self._handle_array_iter(trans, for_node, var_name, arr_v2) + + # 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符) + elem_bits: int = HandlesExpr.get_llvm_type_bits(elem_ty) + if elem_bits == 0: + HandlesType.fatal_error(for_node, "指针迭代: 元素类型不是整数,无法检查 null 终止符") + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 创建循环变量 alloca(存储元素值) + var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty) + if HandlesVar.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 创建隐式 index 变量,初始为 0 + idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty) + llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca) + + # 创建基本块: cond / body / incr / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "ptr.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "ptr.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "ptr.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "ptr.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # 跳转到 cond + llvmlite.build_br(builder, cond_bb) + + # cond 块: load index, GEP, load elem, icmp eq 0 + llvmlite.position_at_end(builder, cond_bb) + cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca) + elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, elem_ty, ptr_val, cur_idx) + cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr) + null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0) + is_null: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, cur_elem, null_val) + llvmlite.build_cond_br(builder, is_null, end_bb, body_bb) + + # body 块: store elem to var, 翻译循环体 + llvmlite.position_at_end(builder, body_bb) + llvmlite.build_store(builder, cur_elem, var_alloca) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + # 恢复旧循环上下文 + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # incr 块: index++, br cond + llvmlite.position_at_end(builder, incr_bb) + one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) + llvmlite.build_store(builder, next_idx, idx_alloca) + llvmlite.build_br(builder, cond_bb) + + # 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + # ============================================================ + # _handle_array_iter - 数组迭代: for x in arr:(迁移自 ForHandleIter) + # 定长数组按长度迭代(元素可为任意类型,不做 null 终止符检查) + # + # 数组值是数组类型而非指针(如局部 t.CArray 修复后), + # 先拷到临时 alloca 获得地址,再按 [0, N) 迭代。 + # + # 生成 IR 结构: + # %tmp = alloca [N x elem_ty] + # store [N x elem_ty] %arr_val, [N x elem_ty]* %tmp + # %idx = alloca i32 ; store 0 + # br %cond + # cond: + # %i = load i32, i32* %idx + # %c = icmp slt i32 %i, N + # br i1 %c, %body, %end + # body: + # %ep = getelementptr [N x elem_ty], [N x elem_ty]* %tmp, i32 0, i32 %i + # %ev = load elem_ty, elem_ty* %ep + # store elem_ty %ev, elem_ty* %var + # ... 循环体 ... + # br %incr + # incr: + # %n = add i32 %i, 1 ; store %n ; br %cond + # end: + # ============================================================ + def _handle_array_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str, + array_val: llvmlite.Value | t.CPtr) -> int: + """数组迭代: for x in arr: 按数组长度迭代""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + # 解析数组类型 [N x elem_ty] + arr_ty: llvmlite.LLVMType | t.CPtr = array_val.Ty + elem_ty: llvmlite.LLVMType | t.CPtr = None + elem_count: int = 0 + match arr_ty: + case llvmlite.LLVMType.Array(et, n): + elem_ty = et + elem_count = n + if elem_ty is None or elem_count <= 0: + HandlesType.fatal_error(for_node, "数组迭代: 无法解析数组类型") + + # 数组值 → 临时 alloca(数组值不是指针,需拷贝后 GEP 迭代) + arr_tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty) + if arr_tmp is None: + HandlesType.fatal_error(for_node, "数组迭代: 临时存储分配失败") + llvmlite.build_store(builder, array_val, arr_tmp) + + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + + # 循环变量 alloca(存储元素值) + var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty) + if HandlesVar.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 隐式 index 变量,初始为 0 + idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty) + llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca) + + # 基本块: cond / body / incr / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "arr.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "arr.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "arr.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "arr.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + llvmlite.build_br(builder, cond_bb) + + # cond 块: load index, icmp slt idx, elem_count + llvmlite.position_at_end(builder, cond_bb) + cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca) + count_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, elem_count) + in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_SLT, cur_idx, count_val) + llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) + + # body 块: GEP(0, idx) → load elem → store to var → 循环体 + llvmlite.position_at_end(builder, body_bb) + elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_ty, elem_ty, arr_tmp, cur_idx) + cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr) + llvmlite.build_store(builder, cur_elem, var_alloca) + + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # incr 块: index++ + llvmlite.position_at_end(builder, incr_bb) + one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) + next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) + llvmlite.build_store(builder, next_idx, idx_alloca) + llvmlite.build_br(builder, cond_bb) + + # 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + # ============================================================ + # _handle_list_literal_iter - 列表字面量迭代: for x in [a, b, c]:(迁移自 ForHandleIter) + # 把列表字面量转成定长数组值,再复用数组迭代(按长度迭代)。 + # + # 元素类型取第一个元素的值类型,其余元素 coerce 到该类型。 + # ============================================================ + def _handle_list_literal_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str, + list_node: ast.AST | t.CPtr) -> int: + """列表字面量迭代: for x in [a, b, c]: 按元素顺序迭代""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + + lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node) + if lst is None or lst.elts is None: + HandlesType.fatal_error(for_node, "列表字面量迭代: 空列表") + elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts + elts_count: t.CSizeT = len(elts) + if elts_count <= 0: + HandlesType.fatal_error(for_node, "列表字面量迭代: 空列表") + + # 翻译第一个元素,确定元素类型 + first_el: ast.AST | t.CPtr = elts.get(0) + first_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, first_el, + trans._funcs, trans._func_count, trans) + if first_val is None or first_val.Ty is None: + HandlesType.fatal_error(first_el, "列表字面量迭代: 无法确定元素类型") + elem_ty: llvmlite.LLVMType | t.CPtr = first_val.Ty + + # 构建 [N x elem_ty] 数组值:临时 alloca 逐元素写入后 load + arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, elem_ty, elts_count) + tmp_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty) + if tmp_alloca is None: + HandlesType.fatal_error(for_node, "列表字面量迭代: 临时数组分配失败") + first_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_ty, elem_ty, tmp_alloca, llvmlite.const_int32(pool, 0)) + if first_ptr is not None: + llvmlite.build_store(builder, first_val, first_ptr) + # 写其余元素(coerce 到 elem_ty) + i: t.CSizeT = 1 + while i < elts_count: + el_node: ast.AST | t.CPtr = elts.get(i) + el_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, trans.Module, el_node, + trans._funcs, trans._func_count, trans) + if el_val is not None: + el_val = HandlesExpr.coerce_to_type(builder, el_val, elem_ty, el_node) + el_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_ty, elem_ty, tmp_alloca, + llvmlite.const_int32(pool, i)) + if el_ptr is not None: + llvmlite.build_store(builder, el_val, el_ptr) + i += 1 + # load 回数组值,复用数组迭代 + arr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, arr_ty, tmp_alloca) + if arr_val is None: + HandlesType.fatal_error(for_node, "列表字面量迭代: 数组加载失败") + return self._handle_array_iter(trans, for_node, var_name, arr_val) + + # ============================================================ + # _handle_list_iter - list[T] 容器迭代: for v in lst:(迁移自 ForHandleIter) + # 按 __count__ 动态长度迭代(元素任意类型,不做 null 终止符检查) + # + # list 结构布局 (6 字段 × 8 字节): + # __data__(0) __count__(8) __capacity__(16) __pool__(24) + # __elem_size__(32) __iter_index__(40) + # + # 生成 IR 结构: + # %count = load __count__ + # %idx = alloca i64 ; store 0 + # br %cond + # cond: + # %i = load i64, %idx + # %c = icmp slt i64 %i, %count + # br i1 %c, %body, %end + # body: + # %data = load __data__ (i8*) + # %es = load __elem_size__ (i64) + # %off = mul i64 %i, %es + # %addr = getelementptr i8, i8* %data, i64 %off + # %el = load i8*, i8** %addr + # store i8* %el, i8** %var + # ... 循环体 ... + # br %incr + # incr: + # %n = add i64 %i, 1 ; store ; br %cond + # end: + # ============================================================ + def _handle_list_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str, + list_val: llvmlite.Value | t.CPtr) -> int: + """list[T] 容器迭代: for v in lst: 按 __count__ 动态长度迭代""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # 读取 __count__ (偏移 8, GEP index 1) + cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty, list_val, llvmlite.const_int64(pool, 1)) + if cnt_ptr is None: + HandlesType.fatal_error(for_node, "list 迭代: 无法定位 __count__") + count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr) + + # 循环变量 alloca(元素类型 i8*,与 list.get 内联一致) + var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = HandlesVar._alloca_at_entry(builder, i8_ptr_ty) + if HandlesVar.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 隐式 index 变量 (i64,与 __count__ 类型对齐) + idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) + + # 基本块: cond / body / incr / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "lst.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "lst.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "lst.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "lst.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + llvmlite.build_br(builder, cond_bb) + + # cond 块: load index, icmp slt idx, count + llvmlite.position_at_end(builder, cond_bb) + cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) + in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_SLT, cur_idx, count_val) + llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) + + # body 块: __data__ + idx*__elem_size__ → load 元素 → store to var + llvmlite.position_at_end(builder, body_bb) + dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty, list_val, llvmlite.const_int64(pool, 0)) + data_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, dpp) + epp: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty, list_val, llvmlite.const_int64(pool, 4)) + esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, epp) + offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, esize) + elem_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ty, data_ptr, offset) + cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, elem_addr) + llvmlite.build_store(builder, cur_elem, var_alloca) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # incr 块: index++ + llvmlite.position_at_end(builder, incr_bb) + one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) + llvmlite.build_store(builder, next_idx, idx_alloca) + llvmlite.build_br(builder, cond_bb) + + # 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + def _handle_dict_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str, + dict_val: llvmlite.Value | t.CPtr) -> int: + """dict 容器迭代: for key in d: 按 __count__/__keys__ 布局迭代 + + _dict.vp 布局(8 字节槽):__keys__@0, __values__@1, __count__@2, + __capacity__@3, __mbuddy__@4, __iter_index__@5。 + __iter__ 协议(__iter__ 重置 iter_index + __next__ 取 key)内联为 + 循环:iter_idx < __count__ → key = __keys__[iter_idx]。 + """ + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + # 读取 __count__(槽 2,字节偏移 16) + cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty, dict_val, llvmlite.const_int64(pool, 2)) + if cnt_ptr is None: + HandlesType.fatal_error(for_node, "dict 迭代: 无法定位 __count__") + count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr) + + # 循环变量 alloca(元素类型 i8*,与 dict.__next__ 返回 str 一致) + var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = HandlesVar._alloca_at_entry(builder, i8_ptr_ty) + if HandlesVar.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 隐式 index 变量 (i64,与 __count__ 类型对齐) + idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) + + # 基本块: cond / body / incr / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "dict.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "dict.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "dict.incr.%d", cnt) + incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + viperlib.snprintf(name_buf, 32, "dict.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + llvmlite.build_br(builder, cond_bb) + + # cond 块: load index, icmp slt idx, count + llvmlite.position_at_end(builder, cond_bb) + cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) + in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_SLT, cur_idx, count_val) + llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) + + # body 块: __keys__ + idx*8 → load key (i8*) → store to var + llvmlite.position_at_end(builder, body_bb) + kpp: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty, dict_val, llvmlite.const_int64(pool, 0)) + keys_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, kpp) + eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 8) + key_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, eight_val) + key_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i8_ty, keys_ptr, key_offset) + cur_key: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, key_addr) + llvmlite.build_store(builder, cur_key, var_alloca) + + # 保存旧循环上下文,设置 break/continue 目标 + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = incr_bb + + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + + trans._break_bb = old_break + trans._continue_bb = old_continue + + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, incr_bb) + + # incr 块: index++ + llvmlite.position_at_end(builder, incr_bb) + one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) + llvmlite.build_store(builder, next_idx, idx_alloca) + llvmlite.build_br(builder, cond_bb) + + # 定位到 end 块 + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + # ============================================================ + # _handle_oop_iter - OOP 迭代协议: for x in obj:(迁移自 ForHandleIter) + # obj 的类有 __iter__/__next__ 方法时调用协议迭代 + # (对齐 TPC HandlesFor.py _HandleForIterLlvm L599-663) + # + # 生成 IR 结构: + # %it = call {Class}.__iter__(obj) + # %flag = alloca i1 ; store 0 + # br %cond + # cond: + # store 0, %flag + # %v = call {Class}.__next__(%it, %flag) + # %stop = load i1, %flag + # br i1 %stop==0, %body, %end + # body: + # store %v, %var + # ... 循环体 ... + # br %step + # step: + # br %cond + # end: + # + # __next__ 的隐藏参数 __stop_iter_flag__(i1*)由 ClassGenMixin + # _translate_method 注入,raise StopIteration 时置 1(translate_raise); + # VpiReader stub 声明同步该参数(_inject_method_declare)。 + # ============================================================ + def _handle_oop_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + var_name: str, + class_name: str, + obj_val: llvmlite.Value | t.CPtr) -> int: + """OOP iter 协议: for x in obj: 调用 __iter__/__next__ 迭代""" + pool: memhub.MemBuddy | t.CPtr = trans.Pool + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + func: llvmlite.Function | t.CPtr = trans._cur_func + mod: llvmlite.LLVMModule | t.CPtr = trans.Module + + if builder is None or func is None or mod is None: + return 0 + if obj_val is None or obj_val.Ty is None: + HandlesType.fatal_error(for_node, "OOP 迭代: 迭代源对象类型未知") + if HandlesExpr.is_ptr_type(obj_val.Ty) == 0: + HandlesType.fatal_error(for_node, "OOP 迭代: 迭代源对象不是指针类型") + + # 1. 查找 {Class}.__iter__ 并调用,得到迭代器 + iter_lookup: str = pool.alloc(128) + if iter_lookup is None: + return 0 + viperlib.snprintf(iter_lookup, 128, "%s.__iter__", class_name) + iter_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( + mod, iter_lookup) + if iter_fn is None: + HandlesType.fatal_error( + for_node, f"OOP 迭代: 类 '{class_name}' 没有 __iter__ 方法") + iter_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(iter_fn) + iter_fn_name: str = llvmlite.function_get_name(iter_fn) + if iter_ret_ty is None or iter_fn_name is None: + return 0 + # self 参数按 __iter__ 首参类型对齐(stub 声明 self 可能是 i8*) + iter_self: llvmlite.Value | t.CPtr = obj_val + iter_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(iter_fn) + if iter_first is not None: + iter_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(iter_first) + if iter_self_ty is not None: + iter_self = llvmlite.build_bitcast(builder, obj_val, iter_self_ty) + if iter_self is None: + return 0 + iter_self.Next = None + iter_result: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, iter_fn_name, iter_self, 1, iter_ret_ty, 0) + if iter_result is None: + return 0 + + # 2. 查找 {Class}.__next__(带隐藏 __stop_iter_flag__ i1* 参数) + next_lookup: str = pool.alloc(128) + if next_lookup is None: + return 0 + viperlib.snprintf(next_lookup, 128, "%s.__next__", class_name) + next_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( + mod, next_lookup) + if next_fn is None: + HandlesType.fatal_error( + for_node, f"OOP 迭代: 类 '{class_name}' 没有 __next__ 方法") + next_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(next_fn) + next_fn_name: str = llvmlite.function_get_name(next_fn) + if next_ret_ty is None or next_fn_name is None: + return 0 + + # 3. 循环变量 alloca(元素类型 = __next__ 返回类型) + var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, var_name) + new_vars: int = 0 + if var_alloca is None: + var_alloca = HandlesVar._alloca_at_entry(builder, next_ret_ty) + if var_alloca is not None: + if HandlesVar.define_var( + trans.SymTab, var_name, var_alloca) == 0: + new_vars = 1 + + # 4. stop flag alloca(i1,初始 0) + i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + flag_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i1_ty) + if flag_alloca is None: + return 0 + flag_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0") + if flag_zero is not None: + llvmlite.build_store(builder, flag_zero, flag_alloca) + + # 5. 创建基本块: cond / body / step / end + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: str = pool.alloc(32) + viperlib.snprintf(name_buf, 32, "oop.cond.%d", cnt) + cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "oop.body.%d", cnt) + body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "oop.step.%d", cnt) + step_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "oop.end.%d", cnt) + end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + if cond_bb is None or body_bb is None or step_bb is None or end_bb is None: + return 0 + + llvmlite.build_br(builder, cond_bb) + + # 6. cond 块: 重置 flag → 调 __next__(iter, flag) → 检查 flag 判结束 + llvmlite.position_at_end(builder, cond_bb) + if flag_zero is not None: + llvmlite.build_store(builder, flag_zero, flag_alloca) + # __next__ 参数 1:迭代器(按首参类型 bitcast) + next_self: llvmlite.Value | t.CPtr = iter_result + next_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(next_fn) + if next_first is not None: + next_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(next_first) + if next_self_ty is not None and iter_result.Ty is not None: + next_self = llvmlite.build_bitcast(builder, iter_result, next_self_ty) + if next_self is None: + return 0 + # 参数链表: arg1(iter).Next = arg2(flag);flag 独立 null 结尾防自链接 + next_self.Next = flag_alloca + flag_alloca.Next = None + next_val: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, next_fn_name, next_self, 2, next_ret_ty, 0) + if next_val is None: + return 0 + stop_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i1_ty, flag_alloca) + if stop_val is None: + return 0 + flag_zero2: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0") + continue_i1: llvmlite.Value | t.CPtr = None + if flag_zero2 is not None: + continue_i1 = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, stop_val, flag_zero2) + if continue_i1 is None: + return 0 + llvmlite.build_cond_br(builder, continue_i1, body_bb, end_bb) + + # 7. body 块: store 元素 → 翻译循环体 → br step + llvmlite.position_at_end(builder, body_bb) + if var_alloca is not None: + llvmlite.build_store(builder, next_val, var_alloca) + old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb + old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb + trans._break_bb = end_bb + trans._continue_bb = step_bb + body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children + if body is not None: + body_count: t.CSizeT = len(body) + for bi in range(body_count): + stmt: ast.AST | t.CPtr = body.get(bi) + if stmt is not None: + HandlesBody.translate_stmt(trans, stmt) + trans._break_bb = old_break + trans._continue_bb = old_continue + if llvmlite.builder_cur_block_is_terminated(builder) == 0: + llvmlite.build_br(builder, step_bb) + + # 8. step 块 → cond;定位到 end 块 + llvmlite.position_at_end(builder, step_bb) + llvmlite.build_br(builder, cond_bb) + llvmlite.position_at_end(builder, end_bb) + # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) + trans._ctrl_merge_reachable = 1 + return new_vars + + def _handle_enumerate_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + t1: str, t2: str, + call: ast.Call | t.CPtr) -> int: + """enumerate 迭代: for i, v in enumerate(x)""" + if call is None or call.args is None: + return 0 + cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args + if len(cargs) < 1: + HandlesType.fatal_error(for_node, "enumerate 需要至少一个参数") + return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), None, 1) + + def _handle_zip_iter(self, trans: HT.Translator | t.CPtr, + for_node: ast.For | t.CPtr, + t1: str, t2: str, + call: ast.Call | t.CPtr) -> int: + """zip 迭代: for a, b in zip(x, y)""" + if call is None or call.args is None: + # fail-fast: zip 参数缺失 + HandlesType.fatal_error(call, "zip 参数缺失", "SyntaxError") + cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args + if len(cargs) < 2: + HandlesType.fatal_error(for_node, "zip 需要至少两个参数") + return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), cargs.get(1), 2) diff --git a/App/lib/core/Gen/StmtGenDeclMixin.vp b/App/lib/core/Gen/StmtGenDeclMixin.vp index dc7d8d7..d6e5731 100644 --- a/App/lib/core/Gen/StmtGenDeclMixin.vp +++ b/App/lib/core/Gen/StmtGenDeclMixin.vp @@ -24,9 +24,11 @@ import lib.core.Handles.HandlesReturn as HandlesReturn import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesMatch as HandlesMatch import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign import lib.core.CompilerFactory as CompilerFactory import lib.Projectrans.Config as Config import lib.core.Gen.StmtGenCifMixin as StmtGenCifMixin +import lib.core.Handles.ExprCallCall as ExprCallCall # ============================================================ @@ -132,12 +134,16 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin): # printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf) if string.strcmp(func_name, "printf") == 0: - trans.ExprCallH.HandlePrintfCall(cl) + ExprCallCall.translate_printf_call( + trans.Pool, trans._cur_builder, trans.Module, cl, trans) elif string.strcmp(func_name, "print") == 0: - trans.ExprCallH.HandlePrintCall(cl) + ExprCallCall.translate_print_call( + trans.Pool, trans._cur_builder, trans.Module, cl, trans) else: # 通用函数调用(返回值丢弃) - trans.ExprCallH.HandleCall(call_node) + ExprCallCall.translate_call( + trans.Pool, trans._cur_builder, trans.Module, call_node, + trans._funcs, trans._func_count, trans) return 0 def pre_scan_allocas(self, trans: HT.Translator | t.CPtr, @@ -148,7 +154,7 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin): """ if node is None: return 0 - return trans.AnnAssignH.PreScan(node) + return HandlesAnnAssign.translate_annassign_prescan(trans, node) def pre_scan_scope_decls(self, trans: HT.Translator | t.CPtr, node: ast.AST | t.CPtr) -> int: diff --git a/App/lib/core/Gen/StmtGenMixin.vp b/App/lib/core/Gen/StmtGenMixin.vp index 51f9937..cd04f4a 100644 --- a/App/lib/core/Gen/StmtGenMixin.vp +++ b/App/lib/core/Gen/StmtGenMixin.vp @@ -29,6 +29,9 @@ import lib.Projectrans.Config as Config import lib.core.Gen.StmtGenDeclMixin as StmtGenDeclMixin import lib.core.Handles.ExprCallBase as ExprCallBase import lib.core.Handles.ExprCallCtor as ExprCallCtor +import lib.core.Handles.HandlesAssign as HandlesAssign +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.Handles.HandlesAugAssign as HandlesAugAssign # ============================================================ @@ -61,29 +64,29 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin): if k == ast.ASTKind.Expr: return self.translate_expr_stmt(trans, node) elif k == ast.ASTKind.Assign: - return trans.AssignH.Handle(node) + return HandlesAssign.translate_assign(trans, node) elif k == ast.ASTKind.AnnAssign: - return trans.AnnAssignH.Handle(node) + return HandlesAnnAssign.translate_annassign(trans, node) elif k == ast.ASTKind.FunctionDef: # 嵌套函数定义:提升为顶层函数 + 创建闭包 return HandlesFunctions.translate_nested_function_def(trans, node) elif k == ast.ASTKind.Return: - return trans.ReturnH.Handle(node) + return self.translate_return(trans, node) elif k == ast.ASTKind.If: - return trans.IfH.Handle(node) + return self.translate_if(trans, node) elif k == ast.ASTKind.While: - return trans.WhileH.Handle(node) + return self.translate_while(trans, node) elif k == ast.ASTKind.AugAssign: - return trans.AugAssignH.Handle(node) + return HandlesAugAssign.translate_augassign(trans, node) elif k == ast.ASTKind.For: - return trans.ForH.Handle(node) + return self.translate_for(trans, node) elif k == ast.ASTKind.ClassDef: return HandlesClassDef.translate_class_def(trans, node) elif k == ast.ASTKind.Import: - return trans.ImportsH.HandleImport(node) + return HandlesImports.translate_import(trans, node) elif k == ast.ASTKind.ImportFrom: - trans.ImportsH.HandleImportFromModule(node) - return trans.ImportsH.HandleImportFromNames(node) + HandlesImports.translate_import_from_module(trans, node) + return HandlesImports.translate_import_from_names(trans, node) elif k == ast.ASTKind.Global: return self.translate_global(trans, node) elif k == ast.ASTKind.Nonlocal: @@ -95,7 +98,7 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin): elif k == ast.ASTKind.Continue: return self.translate_continue(trans) elif k == ast.ASTKind.Match: - return trans.MatchH.Handle(node) + return HandlesMatch.translate_match(trans, node) elif k == ast.ASTKind.Delete: return self.translate_delete(trans, node) elif k == ast.ASTKind.Raise: diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index 40c2bdf..b3ae03c 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -119,10 +119,10 @@ class TranslatorGenMixin: if trans._declare_only == 0 and (kd == ast.ASTKind.Import or kd == ast.ASTKind.ImportFrom): continue if kd == ast.ASTKind.Import: - trans.ImportsH.HandleImport(child) + HandlesImports.translate_import(trans, child) elif kd == ast.ASTKind.ImportFrom: - trans.ImportsH.HandleImportFromModule(child) - trans.ImportsH.HandleImportFromNames(child) + HandlesImports.translate_import_from_module(trans, child) + HandlesImports.translate_import_from_names(trans, child) elif kd == ast.ASTKind.FunctionDef: # Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖) # Phase 1b 全量翻译:正常翻译函数体 diff --git a/App/lib/core/Handles/ForHandleBase.vp b/App/lib/core/Handles/ForHandleBase.vp index 3c0d3a8..278e717 100644 --- a/App/lib/core/Handles/ForHandleBase.vp +++ b/App/lib/core/Handles/ForHandleBase.vp @@ -1,394 +1,18 @@ import t, c from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import viperlib -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.ExprCallBase as ExprCallBase -from lib.core.Handles.HandlesFor import SEQ_KIND_RANGE, SEQ_KIND_STR, SEQ_KIND_LIST +import lib.core.Gen.Generator as Generator + # ============================================================ -# ForHandleBase - HandlesFor 拆分(阶段 E):ForHandleBase +# ForHandleBase - HandlesFor 拆分(迁移完成,仅保留 _g_gen 单例) # -# 类方法拆 Mixin:self 调用按 1 级父类解析(TPV 限制)。 -# @t.NoVTable:静态绑定。 +# P6 机械化迁移:ForHandleBase 全部方法(_extract_tuple_names/ +# _seq_kind/_build_seq_loop)→ StmtGenCifMixin 方法。 +# main/BuildPipeline 仍注入 _g_gen,不可删。 # ============================================================ -@t.NoVTable -class ForHandleBase(HandlesBase.Mixin): - """ForHandleBase""" - def __init__(self, trans: HT.Translator | t.CPtr): - self.Trans = trans - # ============================================================ - # 多变量迭代(enumerate / zip) - # - # 支持迭代源: range(start, stop, step) / 字符串(常量|变量) / list[T] - # enumerate(x) → for i, v in enumerate(x):i 为序号,v 为元素 - # zip(a, b) → for x, y in zip(a, b):任一源耗尽即终止 - # ============================================================ - def _extract_tuple_names(self, tup: ast.Tuple | t.CPtr, - out1: str | t.CPtr, out2: str | t.CPtr) -> int: - """从 Tuple target 提取前两个 Name 变量名,写入 out1/out2,成功返回 1""" - if tup is None or tup.elts is None or out1 is None or out2 is None: - return 0 - elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts - n: t.CSizeT = len(elts) - if n < 2: - return 0 - e0: ast.AST | t.CPtr = elts.get(0) - e1: ast.AST | t.CPtr = elts.get(1) - if e0 is None or e1 is None: - return 0 - if e0.kind() != ast.ASTKind.Name or e1.kind() != ast.ASTKind.Name: - return 0 - n0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e0) - n1: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e1) - if n0.id is None or n1.id is None: - return 0 - string.strcpy(out1, n0.id) - string.strcpy(out2, n1.id) - return 1 - def _seq_kind(self, src: ast.AST | t.CPtr) -> int: - """判断迭代源类型: SEQ_KIND_RANGE / STR / LIST,不支持返回 0""" - if src is None: - return 0 - k: int = src.kind() - if k == ast.ASTKind.Call: - cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src) - fn_s: str = HandlesExpr.get_func_name(cl_s.func) - if fn_s is not None and string.strcmp(fn_s, "range") == 0: - return SEQ_KIND_RANGE - return 0 - if k == ast.ASTKind.Constant: - cn_s: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(src) - if cn_s is not None and cn_s.const_kind == ast.CONST_STR: - return SEQ_KIND_STR - return 0 - if k == ast.ASTKind.Name: - nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(src) - if nm_s.id is not None and self.Trans is not None: - ve_s: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - self.Trans.SymTab, nm_s.id) - if ve_s is not None and ve_s.AnnotClassName is not None: - if string.strstr(ve_s.AnnotClassName, "list") is not None: - return SEQ_KIND_LIST - return SEQ_KIND_STR - return 0 - def _build_seq_loop(self, for_node: ast.For | t.CPtr, - t1: str, t2: str, - src1: ast.AST | t.CPtr, - src2: ast.AST | t.CPtr, - n_srcs: int) -> int: - """生成序列迭代循环(enumerate: n_srcs=1 / zip: n_srcs=2) - - 循环变量 alloca 自动创建或复用;元素类型由源类型决定 - (RANGE→i32, STR→i8, LIST→i8*)。索引内部统一 i64。 - """ - 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 - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # ---- 源 1 准备 ---- - kind1: int = self._seq_kind(src1) - if kind1 == 0: - HandlesType.fatal_error(for_node, "序列迭代: 源 1 类型不支持") - r1_start: llvmlite.Value | t.CPtr = None - r1_stop: llvmlite.Value | t.CPtr = None - r1_step: llvmlite.Value | t.CPtr = None - s1_ptr: llvmlite.Value | t.CPtr = None - l1_count: llvmlite.Value | t.CPtr = None - l1_data: llvmlite.Value | t.CPtr = None - l1_esize: llvmlite.Value | t.CPtr = None - elem1_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty - if kind1 == SEQ_KIND_RANGE: - elem1_ty = i32_ty - r1_start = llvmlite.const_int64(pool, 0) - r1_step = llvmlite.const_int64(pool, 1) - r1_stop = llvmlite.const_int64(pool, 0) - # 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移) - call_src1: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src1) - cargs1: list[ast.AST | t.CPtr] | t.CPtr = call_src1.args - if cargs1 is not None: - n1: t.CSizeT = len(cargs1) - if n1 >= 1: - sv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs1.get(0), - trans._funcs, trans._func_count, trans) - if sv is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs1.get(0), "range 参数翻译失败", "TypeError") - r1_stop = HandlesExpr.coerce_to_type(builder, sv, i64_ty, cargs1.get(0)) - if n1 >= 2: - sv2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs1.get(1), - trans._funcs, trans._func_count, trans) - if sv2 is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs1.get(1), "range 参数翻译失败", "TypeError") - r1_start = HandlesExpr.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1)) - if n1 >= 3: - sv3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs1.get(2), - trans._funcs, trans._func_count, trans) - if sv3 is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs1.get(2), "range 参数翻译失败", "TypeError") - r1_step = HandlesExpr.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2)) - elif kind1 == SEQ_KIND_STR: - elem1_ty = i8_ty - s1_ptr = HandlesExpr.translate_value( - builder, pool, trans.Module, src1, - trans._funcs, trans._func_count, trans) - if s1_ptr is None: - HandlesType.fatal_error(for_node, "序列迭代: 字符串源翻译失败") - elif kind1 == SEQ_KIND_LIST: - elem1_ty = i8_ptr_ty - l1_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, src1, - trans._funcs, trans._func_count, trans) - if l1_obj is None or l1_obj.Ty is None \ - or HandlesExpr.is_ptr_type(l1_obj.Ty) == 0: - HandlesType.fatal_error(for_node, "序列迭代: list 源不是指针类型") - l1_count = llvmlite.build_load(builder, i64_ty, - llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 1))) - l1_data = llvmlite.build_load(builder, i8_ptr_ty, - llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 0))) - l1_esize = llvmlite.build_load(builder, i64_ty, - llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 4))) - - # ---- 源 2 准备(zip)---- - kind2: int = 0 - elem2_ty: llvmlite.LLVMType | t.CPtr = elem1_ty - s2_ptr: llvmlite.Value | t.CPtr = None - l2_count: llvmlite.Value | t.CPtr = None - l2_data: llvmlite.Value | t.CPtr = None - l2_esize: llvmlite.Value | t.CPtr = None - r2_start: llvmlite.Value | t.CPtr = None - r2_stop: llvmlite.Value | t.CPtr = None - r2_step: llvmlite.Value | t.CPtr = None - if n_srcs >= 2: - kind2 = self._seq_kind(src2) - if kind2 == 0: - HandlesType.fatal_error(for_node, "序列迭代: 源 2 类型不支持") - if kind2 == SEQ_KIND_RANGE: - elem2_ty = i32_ty - r2_start = llvmlite.const_int64(pool, 0) - r2_step = llvmlite.const_int64(pool, 1) - r2_stop = llvmlite.const_int64(pool, 0) - # 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移) - call_src2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src2) - cargs2: list[ast.AST | t.CPtr] | t.CPtr = call_src2.args - if cargs2 is not None: - n2: t.CSizeT = len(cargs2) - if n2 >= 1: - svz: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs2.get(0), - trans._funcs, trans._func_count, trans) - if svz is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs2.get(0), "range 参数翻译失败", "TypeError") - r2_stop = HandlesExpr.coerce_to_type(builder, svz, i64_ty, cargs2.get(0)) - if n2 >= 2: - svz2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs2.get(1), - trans._funcs, trans._func_count, trans) - if svz2 is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs2.get(1), "range 参数翻译失败", "TypeError") - r2_start = HandlesExpr.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1)) - if n2 >= 3: - svz3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, cargs2.get(2), - trans._funcs, trans._func_count, trans) - if svz3 is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(cargs2.get(2), "range 参数翻译失败", "TypeError") - r2_step = HandlesExpr.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2)) - elif kind2 == SEQ_KIND_STR: - elem2_ty = i8_ty - s2_ptr = HandlesExpr.translate_value( - builder, pool, trans.Module, src2, - trans._funcs, trans._func_count, trans) - if s2_ptr is None: - HandlesType.fatal_error(for_node, "序列迭代: 字符串源 2 翻译失败") - elif kind2 == SEQ_KIND_LIST: - elem2_ty = i8_ptr_ty - l2_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, src2, - trans._funcs, trans._func_count, trans) - if l2_obj is None or l2_obj.Ty is None \ - or HandlesExpr.is_ptr_type(l2_obj.Ty) == 0: - HandlesType.fatal_error(for_node, "序列迭代: list 源 2 不是指针类型") - l2_count = llvmlite.build_load(builder, i64_ty, - llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 1))) - l2_data = llvmlite.build_load(builder, i8_ptr_ty, - llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 0))) - l2_esize = llvmlite.build_load(builder, i64_ty, - llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 4))) - - # ---- 循环变量 alloca ---- - # t1: enumerate → 序号 (i32);zip → 源 1 元素 - t1_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, t1) - new_vars: int = 0 - if t1_alloca is None: - if n_srcs == 1: - t1_alloca = HandlesVar._alloca_at_entry(builder, i32_ty) - else: - t1_alloca = HandlesVar._alloca_at_entry(builder, elem1_ty) - if t1_alloca is not None: - if HandlesVar.define_var(trans.SymTab, t1, t1_alloca) == 0: - new_vars += 1 - # t2: 源 2 元素(enumerate 时 = 源 1 元素) - t2_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, t2) - if t2_alloca is None: - t2_alloca = HandlesVar._alloca_at_entry(builder, elem2_ty) - if t2_alloca is not None: - if HandlesVar.define_var(trans.SymTab, t2, t2_alloca) == 0: - new_vars += 1 - - # 隐式 index 变量 (i64) - idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) - - # 基本块: cond / body / incr / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "seq.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "seq.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "seq.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "seq.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - llvmlite.build_br(builder, cond_bb) - - # cond 块: 源 1 done 检查(zip 需源 2 也 done) - llvmlite.position_at_end(builder, cond_bb) - cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) - done1: llvmlite.Value | t.CPtr = None - if kind1 == SEQ_KIND_RANGE: - done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r1_stop) - elif kind1 == SEQ_KIND_STR: - ch_ptr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx) - ch1: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr1) - zero1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0) - done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch1, zero1) - elif kind1 == SEQ_KIND_LIST: - done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l1_count) - cont: llvmlite.Value | t.CPtr = done1 - if n_srcs >= 2: - done2: llvmlite.Value | t.CPtr = None - if kind2 == SEQ_KIND_RANGE: - done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r2_stop) - elif kind2 == SEQ_KIND_STR: - ch_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx) - ch2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr2) - zero2: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0) - done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch2, zero2) - elif kind2 == SEQ_KIND_LIST: - done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l2_count) - cont = llvmlite.build_and(builder, done1, done2) - llvmlite.build_cond_br(builder, cont, body_bb, end_bb) - - # body 块: 获取元素 → store → 循环体 - llvmlite.position_at_end(builder, body_bb) - # 源 1 元素 - v1: llvmlite.Value | t.CPtr = None - if kind1 == SEQ_KIND_RANGE: - step1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r1_step) - v1 = llvmlite.build_add(builder, r1_start, step1) - elif kind1 == SEQ_KIND_STR: - ch_ptr1b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx) - v1 = llvmlite.build_load(builder, i8_ty, ch_ptr1b) - elif kind1 == SEQ_KIND_LIST: - off1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l1_esize) - addr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l1_data, off1) - v1 = llvmlite.build_load(builder, i8_ptr_ty, addr1) - # store t1 / t2 - if t1_alloca is not None and t1_alloca.Ty is not None: - t1_ty: llvmlite.LLVMType | t.CPtr = t1_alloca.Ty.Pointee - if n_srcs == 1: - # enumerate: t1 = 序号(trunc i64 → i32) - idx32: llvmlite.Value | t.CPtr = llvmlite.build_trunc(builder, cur_idx, i32_ty) - llvmlite.build_store(builder, idx32, t1_alloca) - if t2_alloca is not None and t2_alloca.Ty is not None and v1 is not None: - t2_ty: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee - v1c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v1, t2_ty, src1) - llvmlite.build_store(builder, v1c, t2_alloca) - else: - if v1 is not None: - v1c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v1, t1_ty, src1) - llvmlite.build_store(builder, v1c, t1_alloca) - # 源 2 元素 → t2 - v2: llvmlite.Value | t.CPtr = None - if kind2 == SEQ_KIND_RANGE: - step2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r2_step) - v2 = llvmlite.build_add(builder, r2_start, step2) - elif kind2 == SEQ_KIND_STR: - ch_ptr2b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx) - v2 = llvmlite.build_load(builder, i8_ty, ch_ptr2b) - elif kind2 == SEQ_KIND_LIST: - off2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l2_esize) - addr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l2_data, off2) - v2 = llvmlite.build_load(builder, i8_ptr_ty, addr2) - if t2_alloca is not None and t2_alloca.Ty is not None and v2 is not None: - t2_ty2: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee - v2c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v2, t2_ty2, src2) - llvmlite.build_store(builder, v2c, t2_alloca) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # incr 块: index++ - llvmlite.position_at_end(builder, incr_bb) - one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) - llvmlite.build_store(builder, next_idx, idx_alloca) - llvmlite.build_br(builder, cond_bb) - - # 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars +# ============================================================ +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) +# ============================================================ +_g_gen: Generator.Generator | t.CPtr = None diff --git a/App/lib/core/Handles/ForHandleIter.vp b/App/lib/core/Handles/ForHandleIter.vp index 1c6b68d..4db2155 100644 --- a/App/lib/core/Handles/ForHandleIter.vp +++ b/App/lib/core/Handles/ForHandleIter.vp @@ -1,820 +1,20 @@ import t, c from stdint import * -import ast -import llvmlite -import memhub -import string -import stdio -import viperlib -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.ExprCallBase as ExprCallBase +import lib.core.Gen.Generator as Generator -import lib.core.Handles.ForHandleBase as ForHandleBase # ============================================================ -# ForHandleIter - HandlesFor 拆分(阶段 E):ForHandleIter +# ForHandleIter - HandlesFor 拆分(迁移完成,仅保留 _g_gen 单例) # -# 类方法拆 Mixin:self 调用按 1 级父类解析(TPV 限制)。 -# @t.NoVTable:静态绑定。 +# P6 机械化迁移:ForHandleIter 全部方法(_handle_ptr_iter/ +# _handle_array_iter/_handle_list_literal_iter/_handle_list_iter/ +# _handle_dict_iter/_handle_oop_iter/_handle_enumerate_iter/ +# _handle_zip_iter)→ StmtGenCifMixin 方法。 +# main/BuildPipeline 仍注入 _g_gen,不可删。 # ============================================================ -@t.NoVTable -class ForHandleIter(ForHandleBase.ForHandleBase): - """ForHandleIter""" - # ============================================================ - # _handle_ptr_iter - 指针迭代: for x in ptr: - # 遍历指针,依赖隐式 index,直到解引用为空(null 终止符) - # - # 生成 IR 结构: - # %idx = alloca i32 - # store i32 0, i32* %idx - # br label %cond - # cond: - # %i = load i32, i32* %idx - # %ep = getelementptr elem_ty, ptr_ty %ptr, i32 %i - # %ev = load elem_ty, elem_ty* %ep - # %null = icmp eq elem_ty %ev, 0 - # br i1 %null, label %end, label %body - # body: - # store elem_ty %ev, elem_ty* %var - # ... 循环体 ... - # br label %incr - # incr: - # %next = add i32 %i, 1 - # store i32 %next, i32* %idx - # br label %cond - # end: - # ============================================================ - def _handle_ptr_iter(self, for_node: ast.For | t.CPtr, - var_name: str) -> int: - """指针迭代: for x in ptr: 直到解引用为空""" - 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 - # 翻译迭代器表达式,获取指针值 - ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, for_node.iter, - trans._funcs, trans._func_count, trans) - if ptr_val is None: - HandlesType.fatal_error(for_node, "指针迭代: 无法翻译迭代器表达式") - - # 检查迭代器类型 - if HandlesExpr.is_ptr_type(ptr_val.Ty) == 0: - # 数组迭代:for k in arr(定长数组按长度迭代,元素可为任意类型) - if HandlesExpr.is_array_type(ptr_val.Ty) != 0: - return self._handle_array_iter(for_node, var_name, ptr_val) - HandlesType.fatal_error(for_node, "指针迭代: 迭代器不是指针类型") - - # 获取元素类型 - elem_ty: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - if elem_ty is None: - HandlesType.fatal_error(for_node, "指针迭代: 无法获取元素类型") - - # 元素类型是数组(Ptr([N x T]),如 t.CArray 变量退化指针): - # load 出数组值后走数组迭代(按长度,非 null 终止) - if HandlesExpr.is_array_type(elem_ty) != 0: - arr_v2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, ptr_val) - if arr_v2 is not None: - return self._handle_array_iter(for_node, var_name, arr_v2) - - # 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符) - elem_bits: int = HandlesExpr.get_llvm_type_bits(elem_ty) - if elem_bits == 0: - HandlesType.fatal_error(for_node, "指针迭代: 元素类型不是整数,无法检查 null 终止符") - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 创建循环变量 alloca(存储元素值) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty) - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 创建隐式 index 变量,初始为 0 - idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty) - llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca) - - # 创建基本块: cond / body / incr / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "ptr.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "ptr.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "ptr.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "ptr.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # 跳转到 cond - llvmlite.build_br(builder, cond_bb) - - # cond 块: load index, GEP, load elem, icmp eq 0 - llvmlite.position_at_end(builder, cond_bb) - cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca) - elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, elem_ty, ptr_val, cur_idx) - cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr) - null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0) - is_null: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, cur_elem, null_val) - llvmlite.build_cond_br(builder, is_null, end_bb, body_bb) - - # body 块: store elem to var, 翻译循环体 - llvmlite.position_at_end(builder, body_bb) - llvmlite.build_store(builder, cur_elem, var_alloca) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - # 恢复旧循环上下文 - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # incr 块: index++, br cond - llvmlite.position_at_end(builder, incr_bb) - one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) - llvmlite.build_store(builder, next_idx, idx_alloca) - llvmlite.build_br(builder, cond_bb) - - # 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - # ============================================================ - # _handle_array_iter - 数组迭代: for x in arr: - # 定长数组按长度迭代(元素可为任意类型,不做 null 终止符检查) - # - # 数组值是数组类型而非指针(如局部 t.CArray 修复后), - # 先拷到临时 alloca 获得地址,再按 [0, N) 迭代。 - # - # 生成 IR 结构: - # %tmp = alloca [N x elem_ty] - # store [N x elem_ty] %arr_val, [N x elem_ty]* %tmp - # %idx = alloca i32 ; store 0 - # br %cond - # cond: - # %i = load i32, i32* %idx - # %c = icmp slt i32 %i, N - # br i1 %c, %body, %end - # body: - # %ep = getelementptr [N x elem_ty], [N x elem_ty]* %tmp, i32 0, i32 %i - # %ev = load elem_ty, elem_ty* %ep - # store elem_ty %ev, elem_ty* %var - # ... 循环体 ... - # br %incr - # incr: - # %n = add i32 %i, 1 ; store %n ; br %cond - # end: - # ============================================================ - def _handle_array_iter(self, for_node: ast.For | t.CPtr, - var_name: str, - array_val: llvmlite.Value | t.CPtr) -> int: - """数组迭代: for x in arr: 按数组长度迭代""" - 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 - - # 解析数组类型 [N x elem_ty] - arr_ty: llvmlite.LLVMType | t.CPtr = array_val.Ty - elem_ty: llvmlite.LLVMType | t.CPtr = None - elem_count: int = 0 - match arr_ty: - case llvmlite.LLVMType.Array(et, n): - elem_ty = et - elem_count = n - if elem_ty is None or elem_count <= 0: - HandlesType.fatal_error(for_node, "数组迭代: 无法解析数组类型") - - # 数组值 → 临时 alloca(数组值不是指针,需拷贝后 GEP 迭代) - arr_tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty) - if arr_tmp is None: - HandlesType.fatal_error(for_node, "数组迭代: 临时存储分配失败") - llvmlite.build_store(builder, array_val, arr_tmp) - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - - # 循环变量 alloca(存储元素值) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty) - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 隐式 index 变量,初始为 0 - idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty) - llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca) - - # 基本块: cond / body / incr / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "arr.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "arr.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "arr.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "arr.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - llvmlite.build_br(builder, cond_bb) - - # cond 块: load index, icmp slt idx, elem_count - llvmlite.position_at_end(builder, cond_bb) - cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca) - count_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, elem_count) - in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_SLT, cur_idx, count_val) - llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) - - # body 块: GEP(0, idx) → load elem → store to var → 循环体 - llvmlite.position_at_end(builder, body_bb) - elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_ty, elem_ty, arr_tmp, cur_idx) - cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr) - llvmlite.build_store(builder, cur_elem, var_alloca) - - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # incr 块: index++ - llvmlite.position_at_end(builder, incr_bb) - one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) - llvmlite.build_store(builder, next_idx, idx_alloca) - llvmlite.build_br(builder, cond_bb) - - # 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - # ============================================================ - # _handle_list_literal_iter - 列表字面量迭代: for x in [a, b, c]: - # 把列表字面量转成定长数组值,再复用数组迭代(按长度迭代)。 - # - # 元素类型取第一个元素的值类型,其余元素 coerce 到该类型。 - # ============================================================ - def _handle_list_literal_iter(self, for_node: ast.For | t.CPtr, - var_name: str, - list_node: ast.AST | t.CPtr) -> int: - """列表字面量迭代: for x in [a, b, c]: 按元素顺序迭代""" - trans: HT.Translator | t.CPtr = self.Trans - pool: memhub.MemBuddy | t.CPtr = trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - - lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node) - if lst is None or lst.elts is None: - HandlesType.fatal_error(for_node, "列表字面量迭代: 空列表") - elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts - elts_count: t.CSizeT = len(elts) - if elts_count <= 0: - HandlesType.fatal_error(for_node, "列表字面量迭代: 空列表") - - # 翻译第一个元素,确定元素类型 - first_el: ast.AST | t.CPtr = elts.get(0) - first_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, first_el, - trans._funcs, trans._func_count, trans) - if first_val is None or first_val.Ty is None: - HandlesType.fatal_error(first_el, "列表字面量迭代: 无法确定元素类型") - elem_ty: llvmlite.LLVMType | t.CPtr = first_val.Ty - - # 构建 [N x elem_ty] 数组值:临时 alloca 逐元素写入后 load - arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, elem_ty, elts_count) - tmp_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty) - if tmp_alloca is None: - HandlesType.fatal_error(for_node, "列表字面量迭代: 临时数组分配失败") - first_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_ty, elem_ty, tmp_alloca, llvmlite.const_int32(pool, 0)) - if first_ptr is not None: - llvmlite.build_store(builder, first_val, first_ptr) - # 写其余元素(coerce 到 elem_ty) - i: t.CSizeT = 1 - while i < elts_count: - el_node: ast.AST | t.CPtr = elts.get(i) - el_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, el_node, - trans._funcs, trans._func_count, trans) - if el_val is not None: - el_val = HandlesExpr.coerce_to_type(builder, el_val, elem_ty, el_node) - el_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, arr_ty, elem_ty, tmp_alloca, - llvmlite.const_int32(pool, i)) - if el_ptr is not None: - llvmlite.build_store(builder, el_val, el_ptr) - i += 1 - # load 回数组值,复用数组迭代 - arr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, arr_ty, tmp_alloca) - if arr_val is None: - HandlesType.fatal_error(for_node, "列表字面量迭代: 数组加载失败") - return self._handle_array_iter(for_node, var_name, arr_val) - # ============================================================ - # _handle_list_iter - list[T] 容器迭代: for v in lst: - # 按 __count__ 动态长度迭代(元素任意类型,不做 null 终止符检查) - # - # list 结构布局 (6 字段 × 8 字节): - # __data__(0) __count__(8) __capacity__(16) __pool__(24) - # __elem_size__(32) __iter_index__(40) - # - # 生成 IR 结构: - # %count = load __count__ - # %idx = alloca i64 ; store 0 - # br %cond - # cond: - # %i = load i64, %idx - # %c = icmp slt i64 %i, %count - # br i1 %c, %body, %end - # body: - # %data = load __data__ (i8*) - # %es = load __elem_size__ (i64) - # %off = mul i64 %i, %es - # %addr = getelementptr i8, i8* %data, i64 %off - # %el = load i8*, i8** %addr - # store i8* %el, i8** %var - # ... 循环体 ... - # br %incr - # incr: - # %n = add i64 %i, 1 ; store ; br %cond - # end: - # ============================================================ - def _handle_list_iter(self, for_node: ast.For | t.CPtr, - var_name: str, - list_val: llvmlite.Value | t.CPtr) -> int: - """list[T] 容器迭代: for v in lst: 按 __count__ 动态长度迭代""" - 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 - - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # 读取 __count__ (偏移 8, GEP index 1) - cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty, list_val, llvmlite.const_int64(pool, 1)) - if cnt_ptr is None: - HandlesType.fatal_error(for_node, "list 迭代: 无法定位 __count__") - count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr) - - # 循环变量 alloca(元素类型 i8*,与 list.get 内联一致) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, i8_ptr_ty) - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 隐式 index 变量 (i64,与 __count__ 类型对齐) - idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) - - # 基本块: cond / body / incr / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "lst.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "lst.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "lst.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "lst.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - llvmlite.build_br(builder, cond_bb) - - # cond 块: load index, icmp slt idx, count - llvmlite.position_at_end(builder, cond_bb) - cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) - in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_SLT, cur_idx, count_val) - llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) - - # body 块: __data__ + idx*__elem_size__ → load 元素 → store to var - llvmlite.position_at_end(builder, body_bb) - dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty, list_val, llvmlite.const_int64(pool, 0)) - data_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, dpp) - epp: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty, list_val, llvmlite.const_int64(pool, 4)) - esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, epp) - offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, esize) - elem_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i8_ty, data_ptr, offset) - cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, elem_addr) - llvmlite.build_store(builder, cur_elem, var_alloca) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # incr 块: index++ - llvmlite.position_at_end(builder, incr_bb) - one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) - llvmlite.build_store(builder, next_idx, idx_alloca) - llvmlite.build_br(builder, cond_bb) - - # 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - def _handle_dict_iter(self, for_node: ast.For | t.CPtr, - var_name: str, - dict_val: llvmlite.Value | t.CPtr) -> int: - """dict 容器迭代: for key in d: 按 __count__/__keys__ 布局迭代 - - _dict.vp 布局(8 字节槽):__keys__@0, __values__@1, __count__@2, - __capacity__@3, __mbuddy__@4, __iter_index__@5。 - __iter__ 协议(__iter__ 重置 iter_index + __next__ 取 key)内联为 - 循环:iter_idx < __count__ → key = __keys__[iter_idx]。 - """ - 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 - - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - # 读取 __count__(槽 2,字节偏移 16) - cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty, dict_val, llvmlite.const_int64(pool, 2)) - if cnt_ptr is None: - HandlesType.fatal_error(for_node, "dict 迭代: 无法定位 __count__") - count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr) - - # 循环变量 alloca(元素类型 i8*,与 dict.__next__ 返回 str 一致) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, i8_ptr_ty) - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 隐式 index 变量 (i64,与 __count__ 类型对齐) - idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca) - - # 基本块: cond / body / incr / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "dict.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "dict.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "dict.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "dict.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - llvmlite.build_br(builder, cond_bb) - - # cond 块: load index, icmp slt idx, count - llvmlite.position_at_end(builder, cond_bb) - cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca) - in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_SLT, cur_idx, count_val) - llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb) - - # body 块: __keys__ + idx*8 → load key (i8*) → store to var - llvmlite.position_at_end(builder, body_bb) - kpp: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty, dict_val, llvmlite.const_int64(pool, 0)) - keys_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, kpp) - eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 8) - key_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, eight_val) - key_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i8_ty, keys_ptr, key_offset) - cur_key: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, key_addr) - llvmlite.build_store(builder, cur_key, var_alloca) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # incr 块: index++ - llvmlite.position_at_end(builder, incr_bb) - one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val) - llvmlite.build_store(builder, next_idx, idx_alloca) - llvmlite.build_br(builder, cond_bb) - - # 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - # ============================================================ - # _handle_oop_iter - OOP 迭代协议: for x in obj: - # obj 的类有 __iter__/__next__ 方法时调用协议迭代 - # (对齐 TPC HandlesFor.py _HandleForIterLlvm L599-663) - # - # 生成 IR 结构: - # %it = call {Class}.__iter__(obj) - # %flag = alloca i1 ; store 0 - # br %cond - # cond: - # store 0, %flag - # %v = call {Class}.__next__(%it, %flag) - # %stop = load i1, %flag - # br i1 %stop==0, %body, %end - # body: - # store %v, %var - # ... 循环体 ... - # br %step - # step: - # br %cond - # end: - # - # __next__ 的隐藏参数 __stop_iter_flag__(i1*)由 ClassGenMixin - # _translate_method 注入,raise StopIteration 时置 1(translate_raise); - # VpiReader stub 声明同步该参数(_inject_method_declare)。 - # ============================================================ - def _handle_oop_iter(self, for_node: ast.For | t.CPtr, - var_name: str, - class_name: str, - obj_val: llvmlite.Value | t.CPtr) -> int: - """OOP iter 协议: for x in obj: 调用 __iter__/__next__ 迭代""" - 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 - mod: llvmlite.LLVMModule | t.CPtr = trans.Module - - if builder is None or func is None or mod is None: - return 0 - if obj_val is None or obj_val.Ty is None: - HandlesType.fatal_error(for_node, "OOP 迭代: 迭代源对象类型未知") - if HandlesExpr.is_ptr_type(obj_val.Ty) == 0: - HandlesType.fatal_error(for_node, "OOP 迭代: 迭代源对象不是指针类型") - - # 1. 查找 {Class}.__iter__ 并调用,得到迭代器 - iter_lookup: str = pool.alloc(128) - if iter_lookup is None: - return 0 - viperlib.snprintf(iter_lookup, 128, "%s.__iter__", class_name) - iter_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( - mod, iter_lookup) - if iter_fn is None: - HandlesType.fatal_error( - for_node, f"OOP 迭代: 类 '{class_name}' 没有 __iter__ 方法") - iter_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(iter_fn) - iter_fn_name: str = llvmlite.function_get_name(iter_fn) - if iter_ret_ty is None or iter_fn_name is None: - return 0 - # self 参数按 __iter__ 首参类型对齐(stub 声明 self 可能是 i8*) - iter_self: llvmlite.Value | t.CPtr = obj_val - iter_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(iter_fn) - if iter_first is not None: - iter_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(iter_first) - if iter_self_ty is not None: - iter_self = llvmlite.build_bitcast(builder, obj_val, iter_self_ty) - if iter_self is None: - return 0 - iter_self.Next = None - iter_result: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, iter_fn_name, iter_self, 1, iter_ret_ty, 0) - if iter_result is None: - return 0 - - # 2. 查找 {Class}.__next__(带隐藏 __stop_iter_flag__ i1* 参数) - next_lookup: str = pool.alloc(128) - if next_lookup is None: - return 0 - viperlib.snprintf(next_lookup, 128, "%s.__next__", class_name) - next_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( - mod, next_lookup) - if next_fn is None: - HandlesType.fatal_error( - for_node, f"OOP 迭代: 类 '{class_name}' 没有 __next__ 方法") - next_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(next_fn) - next_fn_name: str = llvmlite.function_get_name(next_fn) - if next_ret_ty is None or next_fn_name is None: - return 0 - - # 3. 循环变量 alloca(元素类型 = __next__ 返回类型) - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, next_ret_ty) - if var_alloca is not None: - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 4. stop flag alloca(i1,初始 0) - i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - flag_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i1_ty) - if flag_alloca is None: - return 0 - flag_zero: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0") - if flag_zero is not None: - llvmlite.build_store(builder, flag_zero, flag_alloca) - - # 5. 创建基本块: cond / body / step / end - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "oop.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "oop.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "oop.step.%d", cnt) - step_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "oop.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - if cond_bb is None or body_bb is None or step_bb is None or end_bb is None: - return 0 - - llvmlite.build_br(builder, cond_bb) - - # 6. cond 块: 重置 flag → 调 __next__(iter, flag) → 检查 flag 判结束 - llvmlite.position_at_end(builder, cond_bb) - if flag_zero is not None: - llvmlite.build_store(builder, flag_zero, flag_alloca) - # __next__ 参数 1:迭代器(按首参类型 bitcast) - next_self: llvmlite.Value | t.CPtr = iter_result - next_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(next_fn) - if next_first is not None: - next_self_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(next_first) - if next_self_ty is not None and iter_result.Ty is not None: - next_self = llvmlite.build_bitcast(builder, iter_result, next_self_ty) - if next_self is None: - return 0 - # 参数链表: arg1(iter).Next = arg2(flag);flag 独立 null 结尾防自链接 - next_self.Next = flag_alloca - flag_alloca.Next = None - next_val: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, next_fn_name, next_self, 2, next_ret_ty, 0) - if next_val is None: - return 0 - stop_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i1_ty, flag_alloca) - if stop_val is None: - return 0 - flag_zero2: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0") - continue_i1: llvmlite.Value | t.CPtr = None - if flag_zero2 is not None: - continue_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, stop_val, flag_zero2) - if continue_i1 is None: - return 0 - llvmlite.build_cond_br(builder, continue_i1, body_bb, end_bb) - - # 7. body 块: store 元素 → 翻译循环体 → br step - llvmlite.position_at_end(builder, body_bb) - if var_alloca is not None: - llvmlite.build_store(builder, next_val, var_alloca) - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = step_bb - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - trans._break_bb = old_break - trans._continue_bb = old_continue - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, step_bb) - - # 8. step 块 → cond;定位到 end 块 - llvmlite.position_at_end(builder, step_bb) - llvmlite.build_br(builder, cond_bb) - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - def _handle_enumerate_iter(self, for_node: ast.For | t.CPtr, - t1: str, t2: str, - call: ast.Call | t.CPtr) -> int: - """enumerate 迭代: for i, v in enumerate(x)""" - if call is None or call.args is None: - return 0 - cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args - if len(cargs) < 1: - HandlesType.fatal_error(for_node, "enumerate 需要至少一个参数") - return self._build_seq_loop(for_node, t1, t2, cargs.get(0), None, 1) - def _handle_zip_iter(self, for_node: ast.For | t.CPtr, - t1: str, t2: str, - call: ast.Call | t.CPtr) -> int: - """zip 迭代: for a, b in zip(x, y)""" - if call is None or call.args is None: - # fail-fast: zip 参数缺失 - HandlesType.fatal_error(call, "zip 参数缺失", "SyntaxError") - cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args - if len(cargs) < 2: - HandlesType.fatal_error(for_node, "zip 需要至少两个参数") - return self._build_seq_loop(for_node, t1, t2, cargs.get(0), cargs.get(1), 2) +# ============================================================ +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) +# ============================================================ +_g_gen: Generator.Generator | t.CPtr = None diff --git a/App/lib/core/Handles/HandlesAnnAssign.vp b/App/lib/core/Handles/HandlesAnnAssign.vp index 38b9b6d..3ab35c8 100644 --- a/App/lib/core/Handles/HandlesAnnAssign.vp +++ b/App/lib/core/Handles/HandlesAnnAssign.vp @@ -22,17 +22,22 @@ import lib.core.Handles.ExprCallCtor as ExprCallCtor import lib.core.Gen.Generator as Generator +# ============================================================ +# HandlesAnnAssign - AnnAssign 语句处理(迁移完成,保留跨 Mixin 委托壳) +# +# P6 机械化迁移:AnnAssignHandle 类 → AssignGenMixin.translate_annassign / +# translate_annassign_prescan。分派中枢(StmtGenMixin/StmtGenDeclMixin)经 +# 本壳跨链调用(Viper @t.NoVTable 静态绑定下跨 Mixin self. 调用 mangle +# 失败,须经模块级委托壳桥回 gen 单例)。迁移收尾后统一删除。 +# ============================================================ + + # ============================================================ # 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) # ============================================================ _g_gen: Generator.Generator | t.CPtr = None -# ============================================================ -# HandlesAnnAssign - AnnAssign 语句处理(Mixin 继承模式) -# ============================================================ - - # ============================================================ # is_cdefine_annotation - 检测注解是否为 t.CDefine(模块级函数) # @@ -153,58 +158,6 @@ def _is_ptr_element_annotation(annot: ast.AST | t.CPtr) -> int: return 0 -# ============================================================ -# _is_single_param_carray_annot - 检查注解是否为单参 t.CArray[elem_ty] -# -# 单参形式(t.CArray[elem_ty])与 count=None 形式(t.CArray[elem_ty, None]) -# 都解析为 Ptr(elem_ty)。当 RHS 是列表字面量时,按 TPC 语义应推断为 -# 静态数组 [len x elem_ty](对齐 TPC ParseListAnnotation 的 is_pointer 分支: -# "单参数 list[type] → 指针,但如果有列表字面量初始化值则按数组 list[type, N] 处理")。 -# ============================================================ -def _is_single_param_carray_annot(annot: ast.AST | t.CPtr) -> int: - """检查注解是否为单参/None 长度 t.CArray[...],返回 1=是 0=否 - - 支持两种书写形式: - 1. 模块限定 t.CArray[...](Attribute value) - 2. 裸名 CArray[...](from t import * 后使用,如 Termination4K3 core.vp - 的 `__python_suffix__: CArray[str] = ["py", ...]`) - """ - if annot is None or annot.kind() != ast.ASTKind.Subscript: - return 0 - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) - if sub.value is None or sub.slice is None: - return 0 - if sub.value.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value) - if at.attr is None or string.strcmp(at.attr, "CArray") != 0: - return 0 - if at.value is None or at.value.kind() != ast.ASTKind.Name: - return 0 - mv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mv.id is None or string.strcmp(mv.id, "t") != 0: - return 0 - elif sub.value.kind() == ast.ASTKind.Name: - # 裸名 CArray(from t import *):与 t.CArray 等价 - bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if bn.id is None or string.strcmp(bn.id, "CArray") != 0: - return 0 - else: - return 0 - # 单参形式:slice 非 Tuple(如 t.CArray[u64] / CArray[str]) - if sub.slice.kind() != ast.ASTKind.Tuple: - return 1 - # 双参形式:count=None(t.CArray[u64, None])→ 等价单参 - tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice) - if tup.elts is None or len(tup.elts) < 2: - return 0 - cnt_node: ast.AST | t.CPtr = tup.elts.get(1) - if cnt_node is not None and cnt_node.kind() == ast.ASTKind.Constant: - cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(cnt_node) - if cn0.const_kind == ast.CONST_NONE: - return 1 - return 0 - - # ============================================================ # _infer_static_array_ty_from_literal - 单参 CArray + 列表字面量 → 静态数组 # @@ -213,21 +166,17 @@ def _is_single_param_carray_annot(annot: ast.AST | t.CPtr) -> int: # 避免误走动态 list 构造(_find_pool_var 兜底引用外部 @_mbuddy → 链接期 # undefined)。PreScan 与 Handle 都调用(PreScan 预创建 alloca 的类型必须 # 与 Handle 一致,否则 get_or_create_sym 复用旧 alloca 使推断失效)。 +# 真实实现已迁移至 gen._infer_static_array_ty_from_literal,本壳保留供 +# ClassGenDef(Gen 侧字段类型推断)等跨模块调用方使用。 # ============================================================ def _infer_static_array_ty_from_literal(pool: memhub.MemBuddy | t.CPtr, annot: ast.AST | t.CPtr, value: ast.AST | t.CPtr, resolved_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """单参 CArray + 列表字面量 → Array(elem_ty, len);否则返回原类型""" - if value is not None and value.kind() == ast.ASTKind.List and resolved_ty is not None: - if _is_single_param_carray_annot(annot) != 0: - elem_ty_arr: llvmlite.LLVMType | t.CPtr = resolved_ty.Pointee - lst_arr: ast.List | t.CPtr = (ast.List | t.CPtr)(value) - cnt_arr: int = 0 - if lst_arr.elts is not None: - cnt_arr = len(lst_arr.elts) - if elem_ty_arr is not None and cnt_arr > 0: - return llvmlite.Array(pool, elem_ty_arr, cnt_arr) + """单参 CArray + 列表字面量 → Array(elem_ty, len);否则返回原类型(委托到 gen._infer_static_array_ty_from_literal)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._infer_static_array_ty_from_literal(pool, annot, value, resolved_ty) return resolved_ty @@ -261,467 +210,25 @@ def _init_global_array_from_list(builder: llvmlite.IRBuilder | t.CPtr, return 0 -@t.NoVTable -class AnnAssignHandle(HandlesBase.Mixin): - """AnnAssign 语句处理器:继承 Mixin 获得 Trans 回指针""" - - def __init__(self, trans: HT.Translator | t.CPtr): - self.Trans = trans - - # ============================================================ - # PreScan - 预扫描 AnnAssign,为有类型注解的变量提前创建 alloca - # - # 返回新增的变量数 - # ============================================================ - def PreScan(self, node: ast.AST | t.CPtr) -> int: - """预扫描 AnnAssign,提前创建 alloca 到 entry block 顶部""" - if node is None: - return 0 - k: int = node.kind() - if k != ast.ASTKind.AnnAssign: - return 0 - - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) - if aa is None or aa.target is None: - return 0 - target: ast.AST | t.CPtr = aa.target - if target.kind() != ast.ASTKind.Name: - return 0 - - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) - if nm.id is None: - return 0 - - # CDefine 注解: 不创建 alloca,但注册常量到全局表 - # 供后续 t.CArray[elem_ty, NAME] 编译期解析使用 - # 浮点/整数自动识别(与 Handle/handle_module_level_var 路径一致) - if is_cdefine_annotation(aa.annotation) != 0: - pool_ps: memhub.MemBuddy | t.CPtr = self.Trans.Pool - _register_cdefine_from_value(pool_ps, nm.id, aa.value) - return 0 - - # CTypedef 注解: 类型别名(ScanCTypedefDeclarations 已注册到 CTypedef 表), - # 不创建全局/局部存储——否则 stdint.vp 的 float64_t: t.CTypedef = t.CFloat64T - # 等生成 @float64_t 符号,链接 duplicate symbol warning - if is_ctypedef_annotation(aa.annotation) != 0: - return 0 - - # global/nonlocal 变量不需要局部 alloca - if HT.is_global_name(self.Trans, nm.id) != 0: - return 0 - if HT.is_nonlocal_name(self.Trans, nm.id) != 0: - return 0 - - # 模块级全局变量已由 handle_module_level_var 注册到模块作用域。 - # Python 语义:仅模块级代码(Current == Root)时跳过局部 alloca; - # 函数内无 global 声明时应创建局部变量(不遮蔽全局)。 - if HandlesVar.is_module_scope(self.Trans.SymTab) != 0: - if HandlesVar.lookup_module_var(self.Trans.SymTab, nm.id) is not None: - return 0 - - # 检查是否已存在 - existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - self.Trans.SymTab, nm.id) - if existing is not None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder - - # 从 annotation 推断类型(修复:原硬编码 i32 导致 str 等类型错误) - var_ty: llvmlite.LLVMType | t.CPtr = None - annot: ast.AST | t.CPtr = aa.annotation - if annot is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans) - if resolved is None: - # 尝试特化泛型类注解(如 list[str]) - # resolve_annotation_type 返回 None 可能是因为泛型类未特化 - if annot.kind() == ast.ASTKind.Subscript: - sub_annot: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) - if sub_annot.value is not None and sub_annot.value.kind() == ast.ASTKind.Name: - sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_annot.value) - if sub_nm.id is not None: - template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(sub_nm.id) - spec_name_ps: str = None - if template_cd is not None: - type_args_ps: list[str] | t.CPtr = ExprCallCtor._extract_type_args_from_slice(pool, sub_annot.slice) - if type_args_ps is not None and len(type_args_ps) > 0: - spec_name_ps = HandlesClassDef._specialize_generic_class( - self.Trans, sub_nm.id, type_args_ps) - if spec_name_ps is not None: - resolved = HandlesType.resolve_annotation_type( - pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans) - if resolved is not None: - var_ty = resolved - # 单参 t.CArray[elem_ty] + 列表字面量 → 静态数组(与 Handle 推断一致)。 - # PreScan 预创建的 alloca 类型必须与 Handle 期望一致,否则 Handle 的 - # get_or_create_sym 复用旧 alloca,数组推断失效仍走动态 list → _mbuddy。 - var_ty = _infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty) - else: - # fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32) - HandlesType.fatal_error( - aa, - f"变量类型注解解析失败,变量名: {nm.id}", - "TypeError") - else: - # fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32) - HandlesType.fatal_error( - aa, - f"AnnAssign 缺少类型注解,变量名: {nm.id}", - "SyntaxError") - - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, self.Trans.Module, var_ty) - alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, var_ty) - if alloca is not None: - if HandlesVar.define_var( - self.Trans.SymTab, nm.id, alloca) == 0: - # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) - # 传 pool:泛型 Subscript 返回 mangled name(GSList[BasicBlock] → 特化 - # struct 名),否则 pool=None 只返回裸类名(GSList → 泛型模板未注册 - # → 属性访问 lookup_field_by_class("GSList") 报"类未注册",LLVMLiteTest - # __function.vp blocks.Tail 根因;对齐 ClassGenMixin L3159 BUG 1 方案3) - if annot is not None: - cls_nm_ps: str = HandlesType.extract_class_name_from_annotation( - annot, self.Trans._imported_modules, pool) - if cls_nm_ps is not None: - HandlesVar.set_var_annot_class_name( - self.Trans.SymTab, nm.id, cls_nm_ps) - # 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长) - if _is_ptr_element_annotation(annot) != 0: - HandlesVar.set_var_ptr_element( - self.Trans.SymTab, nm.id) - return 0 - return 0 - - # ============================================================ - # Handle - 翻译 AnnAssign 语句 - # - # 返回新增的变量数 - # ============================================================ - def Handle(self, node: ast.AST | t.CPtr) -> int: - """翻译 AnnAssign(target=Name, annotation=..., value=expr)""" - aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node) - if aa is None: - return 0 - - target: ast.AST | t.CPtr = aa.target - if target is None or target.kind() != ast.ASTKind.Name: - return 0 - - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) - if nm.id is None: - return 0 - - # CDefine 注解: 编译期常量,不生成运行时代码 - # 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析 - # 注: PreScan 已注册过,此处保证即使跳过 PreScan 也能正确注册 - if is_cdefine_annotation(aa.annotation) != 0: - pool_cd: memhub.MemBuddy | t.CPtr = self.Trans.Pool - _register_cdefine_from_value(pool_cd, nm.id, aa.value) - return 0 - - # CTypedef 注解: 类型别名(mode_t: t.CTypedef = t.CUInt32T 等)。 - # 翻译期 CTypedef 表已被 clear_ctypedefs 清空(每文件隔离;表字符串 - # pool 分配,reset_to(mark1) 回收后悬空,不能跨文件累积),必须在此 - # 按需注册,否则 posix.vp S_ISREG(mode: mode_t) 等普通函数参数注解 - # 解析查表失败 → NameError: mode_t。仅登记类型表达式,不创建全局/ - # 局部存储——否则生成 @mode_t 符号,链接 duplicate symbol warning。 - if is_ctypedef_annotation(aa.annotation) != 0: - pool_ct: memhub.MemBuddy | t.CPtr = self.Trans.Pool - ctd_str: str = HandlesType._get_type_name_from_annotation(pool_ct, aa.value) - if ctd_str is not None: - HandlesType.register_ctypedef(pool_ct, nm.id, ctd_str) - return 0 - - pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module - - # 确定类型(从 annotation 推断) - var_ty: llvmlite.LLVMType | t.CPtr = None - annot: ast.AST | t.CPtr = aa.annotation - if annot is not None: - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans) - if resolved is not None: - var_ty = resolved - else: - # fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32) - HandlesType.fatal_error( - aa, - f"变量类型注解解析失败,变量名: {nm.id}", - "TypeError") - else: - # fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32) - HandlesType.fatal_error( - aa, - f"AnnAssign 缺少类型注解,变量名: {nm.id}", - "SyntaxError") - - # t.Callable 函数指针:注册返回类型签名(供函数指针间接调用精确返回类型) - callable_ret: llvmlite.LLVMType | t.CPtr = HandlesType.try_extract_callable_ret( - pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans) - if callable_ret is not None: - ExprCallCall.register_func_ptr_sig(nm.id, callable_ret) - - # global 变量:写入模块作用域中的全局变量 - if HT.is_global_name(self.Trans, nm.id) != 0: - mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - self.Trans.SymTab, nm.id) - if mod_alloca is not None and aa.value is not None: - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aa.value, - None, 0, self.Trans) - if rhs_val is not None: - target_ty: llvmlite.LLVMType | t.CPtr = None - if mod_alloca.Ty is not None: - target_ty = mod_alloca.Ty.Pointee - if target_ty is not None: - rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) - llvmlite.build_store(builder, rhs_val, mod_alloca) - return 0 - - # nonlocal 变量:通过闭包 env 写入 - if HT.is_nonlocal_name(self.Trans, nm.id) != 0: - if aa.value is not None: - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aa.value, - None, 0, self.Trans) - if rhs_val is not None: - nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( - self.Trans, nm.id) - if nl_ptr is not None: - # 从 nl_ptr 的类型推断 nonlocal 变量实际类型, - # 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏) - nl_target_ty: llvmlite.LLVMType | t.CPtr = None - if nl_ptr.Ty is not None: - nl_target_ty = nl_ptr.Ty.Pointee - if nl_target_ty is None: - # fast-fail: nl_ptr 类型信息丢失,无法安全 store - VLogger.error( - f"nonlocal 变量类型信息丢失,无法写入: {nm.id}", - "HandlesAnnAssign") - return 0 - rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, rhs_val, nl_target_ty, node) - llvmlite.build_store(builder, rhs_coerced, nl_ptr) - return 0 - - # 模块级全局变量(由 handle_module_level_var 注册到模块作用域) - # Python 语义:仅模块级代码(Current == Root)时修改全局变量; - # 函数内无 global 声明时应创建局部变量(走后面的 get_or_create_sym 路径)。 - if HandlesVar.is_module_scope(self.Trans.SymTab) != 0: - mod_glob: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - self.Trans.SymTab, nm.id) - else: - mod_glob = None - if mod_glob is not None: - if aa.value is not None: - # 列表字面量 → 逐元素 GEP + store 初始化数组 - if aa.value.kind() == ast.ASTKind.List: - _init_global_array_from_list( - builder, pool, mod, mod_glob, aa.value, self.Trans) - else: - rhs_val_mg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aa.value, - None, 0, self.Trans) - if rhs_val_mg is not None: - target_ty_mg: llvmlite.LLVMType | t.CPtr = None - if mod_glob.Ty is not None: - target_ty_mg = mod_glob.Ty.Pointee - if target_ty_mg is not None: - rhs_val_mg = HandlesExpr.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node) - llvmlite.build_store(builder, rhs_val_mg, mod_glob) - return 0 - - # 单参 t.CArray[elem_ty] + 列表字面量 → 按静态数组处理(count 从字面量长度推断) - # 与 PreScan 推断一致:get_or_create_sym 复用 PreScan 创建的 alloca, - # 类型一致才能命中局部数组快路径,避免 _find_pool_var 兜底引用 @_mbuddy。 - var_ty = _infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty) - - # 普通局部变量 - # 创建 alloca - alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( - self.Trans.SymTab, pool, builder, nm.id, var_ty) - if alloca is None: - # fail-fast: 存储创建失败,立即终止(禁止静默跳过) - HandlesType.fatal_error( - aa, - f"无法为变量 {nm.id} 创建存储", - "TypeError") - # FakeDuck: str 变量创建影子结构体 {var}__meta__(per-instance 字段存储) - # 仅裸 str 注解(Name("str"))且 _str 已注册时创建;bytes / t.CChar|t.CPtr 不创建。 - # a 保持为 i8*(可 printf/len),a__meta__ 存 __data__/__mbuddy__ 等字段, - # 属性读写(fd3)与方法调用(fd5)均通过该影子解析。 - fd_str_ty: llvmlite.LLVMType | t.CPtr = None - fd_meta_alloca: llvmlite.Value | t.CPtr = None - fd_meta_name: str = None - if annot is not None and annot.kind() == ast.ASTKind.Name: - fd_annot: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot) - if fd_annot is not None and fd_annot.id is not None: - if string.strcmp(fd_annot.id, "str") == 0: - fd_str_ty = HandlesStruct.get_struct_type("_str") - if fd_str_ty is not None: - # 确保 _str 完整类型定义在当前模块可用:跨模块结构体默认 opaque, - # 直接 alloca opaque 类型 → llc "Cannot allocate unsized type" - HandlesStruct.ensure_struct_def_in_module(pool, mod, fd_str_ty) - # 影子变量名必须用 pool 持久缓冲:f-string 生成栈缓冲,在 AnnAssign - # 返回后被覆盖,符号表注册的名字内容损坏 → 后续 lookup 找不到。 - fd_meta_name = pool.alloc(256) - if fd_meta_name is not None: - viperlib.snprintf(fd_meta_name, 256, "%s__meta__", nm.id) - fd_meta_alloca = HandlesVar.get_or_create_sym( - self.Trans.SymTab, pool, builder, fd_meta_name, fd_str_ty) - if fd_meta_alloca is None: - # fail-fast: 影子存储创建失败,立即终止 - HandlesType.fatal_error( - aa, - f"无法为 str 影子变量 {fd_meta_name} 创建存储", - "TypeError") - # 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体) - # 传 pool:泛型 Subscript 返回 mangled name(对齐 L401 同根因修复) - if annot is not None: - cls_nm_hd: str = HandlesType.extract_class_name_from_annotation( - annot, self.Trans._imported_modules, pool) - if cls_nm_hd is not None: - HandlesVar.set_var_annot_class_name( - self.Trans.SymTab, nm.id, cls_nm_hd) - # 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长) - if _is_ptr_element_annotation(annot) != 0: - HandlesVar.set_var_ptr_element( - self.Trans.SymTab, nm.id) - - new_vars: int = 0 - existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - self.Trans.SymTab, nm.id) - if existing is None: - new_vars = 1 - - # 如果有初始值,store - if aa.value is not None: - # 局部数组:列表字面量 → 逐元素 GEP + store 初始化 - # 修复:此前局部 CArray[...] = [x, y] 会走 translate_list_literal, - # 错误触发 list[T] 泛型特化(堆对象)导致崩溃(如 this.vp 的 - # t.CArray[t.CChar, 256] = [0])。局部 alloca 未零初始化, - # 先整体置零再写列表元素(与全局数组默认零初始化语义一致)。 - local_arr_ty: llvmlite.LLVMType | t.CPtr = None - if aa.value.kind() == ast.ASTKind.List and alloca.Ty is not None: - pt_l: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if HandlesExpr.is_array_type(pt_l) != 0: - local_arr_ty = pt_l - if local_arr_ty is not None: - zero_arr: llvmlite.Value | t.CPtr = llvmlite.ConstZero( - pool, local_arr_ty) - if zero_arr is not None: - llvmlite.build_store(builder, zero_arr, alloca) - _init_global_array_from_list( - builder, pool, mod, alloca, aa.value, self.Trans) - else: - # 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → 读 i32 - # CurAssignNode 记录 RHS 节点:translate_c_deref 据此判定 Deref - # 是否为赋值直接 RHS(对齐 TPC _infer_deref_target_type)。 - self.Trans.CurAssignAnnot = aa.annotation - self.Trans.CurAssignNode = aa.value - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aa.value, - None, 0, self.Trans) - if rhs_val is not None: - # 注解退化修复(对齐 TPC 从构造结果推断类型): - # 无实参泛型模板类注解(如 vi: vector.Vector | CPtr,模板 - # 未注册 struct → resolve 退化)会让 alloca 类型退化为 - # Ptr(i8),但 rhs 构造返回精确结构体指针(如 Ptr(Vector[int] - # 结构))。此时按退化 alloca store 会丢失特化类型,后续 - # vi.push 方法调用按 Ptr(i8) 查不到类名 → AnnotClassName - # 回退到模板名(无实参)→ vpi 查不到返回类型 fail-fast。 - # 用 rhs 精确类型重建 alloca 并更新符号表注册,使方法调用 - # 按精确特化类名解析。旧退化 alloca 行残留为 entry block - # 死代码(文本 IR 即时生成,无法删除,无害)。 - precise_rhs_ty: llvmlite.LLVMType | t.CPtr = None - if rhs_val.Ty is not None: - match rhs_val.Ty: - case llvmlite.LLVMType.Ptr(inner_struct): - match inner_struct: - case llvmlite.LLVMType.Struct(_, _, _): - precise_rhs_ty = rhs_val.Ty - case _: - pass - case _: - pass - if precise_rhs_ty is not None and alloca.Ty is not None: - alloca_pt: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if alloca_pt is not None and \ - t.CUInt64T(alloca_pt) != t.CUInt64T(precise_rhs_ty): - new_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry( - builder, precise_rhs_ty) - if new_alloca is not None: - v_entry_rb: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - self.Trans.SymTab, nm.id) - if v_entry_rb is not None: - v_entry_rb.Alloca = new_alloca - alloca = new_alloca - # 类型转换:将 rhs_val 转换为 alloca 的 pointee 类型 - # 修复:整数字面量是 i32,但变量可能是 i8/i16/i64,需 trunc/sext - target_ty: llvmlite.LLVMType | t.CPtr = None - if alloca.Ty is not None: - target_ty = alloca.Ty.Pointee - if target_ty is not None: - rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) - llvmlite.build_store(builder, rhs_val, alloca) - # FakeDuck: 初始化影子结构体 __data__ 字段 = 初始字符串指针 - # (对齐 TPC HandlesAnnAssign.py: 仅当有初值时写入 __data__) - if fd_str_ty is not None and fd_meta_alloca is not None: - fd_data_fe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_str_ty, "__data__") - if fd_data_fe is not None: - fd_data_ptr: llvmlite.Value | t.CPtr = \ - llvmlite.build_gep_struct( - builder, fd_str_ty, fd_data_fe.Ty, - fd_meta_alloca, fd_data_fe.Index) - if fd_data_ptr is not None: - llvmlite.build_store(builder, rhs_val, fd_data_ptr) - # 清除赋值上下文(防残留):CurAssignAnnot/CurAssignNode 只在该 - # AnnAssign 的 RHS 翻译期间有效,否则后续 while 条件/比较等处的 - # c.Deref 会被残留注解误判读取宽度(i8* 被 bitcast i32* 读 4 字节)。 - self.Trans.CurAssignAnnot = None - self.Trans.CurAssignNode = None - - # FakeDuck: __mbuddy__ 字段初始化为 NULL。 - # with 上下文提供的 __mbuddy__ 注入由 _inject_requires_fields(fd4)完成, - # 此处仅确保影子结构体初始为空指针(对齐 TPC HandlesAnnAssign.py L667-670)。 - if fd_str_ty is not None and fd_meta_alloca is not None: - fd_buddy_fe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_str_ty, "__mbuddy__") - if fd_buddy_fe is not None and fd_buddy_fe.Ty is not None: - fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, fd_buddy_fe.Ty, "null") - fd_buddy_ptr: llvmlite.Value | t.CPtr = \ - llvmlite.build_gep_struct( - builder, fd_str_ty, fd_buddy_fe.Ty, - fd_meta_alloca, fd_buddy_fe.Index) - if fd_buddy_ptr is not None and fd_null is not None: - llvmlite.build_store(builder, fd_null, fd_buddy_ptr) - # FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__)。 - # 经全局 gen 单例委托 CallGenMixin._inject_requires_fields。 - import lib.core.Gen.Generator as Generator - g_fda: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(_g_gen, t.CPtr)) - if g_fda is not None: - g_fda._inject_requires_fields( - self.Trans, pool, builder, mod, fd_meta_alloca, "_str") - - return 0 +# ============================================================ +# translate_annassign - AnnAssign 语句翻译(委托到 gen.translate_annassign) +# ============================================================ +def translate_annassign(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 AnnAssign 语句,返回新增变量数(委托到 gen.translate_annassign)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_annassign(trans, node) + return 0 # ============================================================ -# NewAnnAssignHandle - 工厂函数 +# translate_annassign_prescan - AnnAssign 预扫描(委托到 gen.translate_annassign_prescan) # ============================================================ -def NewAnnAssignHandle(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> AnnAssignHandle | t.CPtr: - h: AnnAssignHandle | t.CPtr = pool.alloc(AnnAssignHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, AnnAssignHandle.__sizeof__()) - h.Trans = trans - return h +def translate_annassign_prescan(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """预扫描 AnnAssign,提前创建 alloca 到 entry block 顶部(委托到 gen.translate_annassign_prescan)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_annassign_prescan(trans, node) + return 0 diff --git a/App/lib/core/Handles/HandlesAssign.vp b/App/lib/core/Handles/HandlesAssign.vp index ee11a3f..997d1c2 100644 --- a/App/lib/core/Handles/HandlesAssign.vp +++ b/App/lib/core/Handles/HandlesAssign.vp @@ -20,803 +20,32 @@ import lib.core.StubMergerStore as StubMergerStore import lib.core.Handles.ExprCallBase as ExprCallBase import lib.core.Handles.ExprCallCall as ExprCallCall import lib.core.Handles.ExprCallCtor as ExprCallCtor +import lib.core.Gen.Generator as Generator # ============================================================ -# HandlesAssign - Assign 语句处理(Mixin 继承模式) +# HandlesAssign - Assign 语句处理(迁移完成,保留跨 Mixin 委托壳) # -# 对应 TransPyC 的 class AssignHandle(BaseHandle): -# @t.NoVTable 继承 Mixin 获得 Trans 字段(展平嵌入,无 vtable) -# 通过 self.Trans 访问共享状态(Pool/Module/_cur_builder/SymTab/...) -# 通过 self.Trans.ExprH / self.Trans.IfH 等访问其他 Handle +# P6 机械化迁移:AssignHandle 类 → AssignGenMixin.translate_assign +# (lib.core.Gen.AssignGenMixin)。分派中枢(StmtGenMixin)经本壳跨链 +# 调用(Viper @t.NoVTable 静态绑定下跨 Mixin self. 调用 mangle 失败, +# 须经模块级委托壳桥回 gen 单例)。迁移收尾后统一删除。 # ============================================================ -@t.NoVTable -class AssignHandle(HandlesBase.Mixin): - """Assign 语句处理器:继承 Mixin 获得 Trans 回指针 + 共享方法""" - _CurrentClass: str # 模块私有状态 - - def __init__(self, trans: HT.Translator | t.CPtr): - self.Trans = trans - self._CurrentClass = None - - # ============================================================ - # Handle - 处理 Assign 语句,返回新增变量数(0 或 1) - # - # 对应 TransPyC AssignHandle._HandleAssignLlvm - # 共享状态从 self.Trans 获取,无需 11 个参数 - # ============================================================ - def Handle(self, node: ast.AST | t.CPtr) -> int: - asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node) - if asgn is None: - VLogger.error("cast failed", "ASGN") - return 0 - - targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets - if targets is None: - VLogger.error("targets is None", "ASGN") - return 0 - - # 从 self.Trans 取共享状态(替代 11 个参数) - pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module - - # 翻译 RHS 值 - # 无注解赋值无目标类型可推断,清空 CurAssignAnnot/CurAssignNode - # (防残留误判 c.Deref 宽度) - self.Trans.CurAssignAnnot = None - self.Trans.CurAssignNode = None - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, asgn.value, None, 0, self.Trans) - if rhs_val is None: - # Phase A 依赖未就绪(_deps_pending=1):跨模块函数/方法因 text.ll - # 未生成返回类型退化为 void/None(CallGenMixin L4493 - # g_vta._resolve_attr_field_class 根因)。此时整文件不写盘、下遍重译 - # (Phase2.vp L590-599),跳过本语句不报错——否则 fatal 使多遍 - # 重试机制永远无法收敛(本语句只是"本遍保持默认类型"的退化结果, - # 下遍依赖已生成即可精确解析)。依赖就绪时 _deps_pending=0, - # 此处仍 fail-fast,不掩盖真实错误。 - if self.Trans is not None and self.Trans._deps_pending != 0: - return 0 - # 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位 - fb: str = VLogger.fmt_buf() - if fb is not None and asgn.value is not None: - sha1: str = self.Trans.ModuleSha1 - val_kind: int = asgn.value.kind() - val_line: t.CInt = asgn.value.lineno - # 通过 sha1 查找文件名(人类可读) - rel_path: str = None - if sha1 is not None: - rel_path = StubMergerStore.LookupSha1RelPath(sha1) - # 根据 AST 节点类型提取详情 - if val_kind == ast.ASTKind.Attribute: - at_nv: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(asgn.value) - attr_nm: str = at_nv.attr - target_nm: str = "?" - if at_nv.value is not None: - if at_nv.value.kind() == ast.ASTKind.Name: - tn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_nv.value) - target_nm = tn_nm.id - if rel_path is not None: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: %s:%d '%s.%s' 属性访问失败", - rel_path, val_line, target_nm, attr_nm) - else: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: sha1=%s:%d '%s.%s' 属性访问失败", - sha1, val_line, target_nm, attr_nm) - elif val_kind == ast.ASTKind.Name: - nm_nv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(asgn.value) - if rel_path is not None: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: %s:%d 变量 '%s' 未找到", - rel_path, val_line, nm_nv.id) - else: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: sha1=%s:%d 变量 '%s' 未找到", - sha1, val_line, nm_nv.id) - elif val_kind == ast.ASTKind.Call: - cl_nv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(asgn.value) - func_nm: str = "?" - if cl_nv.func is not None: - if cl_nv.func.kind() == ast.ASTKind.Name: - fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_nv.func) - func_nm = fn_nm.id - if rel_path is not None: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: %s:%d 调用 '%s(...)' 返回 None", - rel_path, val_line, func_nm) - else: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: sha1=%s:%d 调用 '%s(...)' 返回 None", - sha1, val_line, func_nm) - else: - if rel_path is not None: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: %s:%d [kind=%d]", - rel_path, val_line, val_kind) - else: - viperlib.snprintf(fb, 1024, - "赋值右侧为 None: sha1=%s:%d [kind=%d]", - sha1, val_line, val_kind) - VLogger.error(fb, "ASGN") - else: - VLogger.error("赋值右侧为 None (asgn.value 为空)", "ASGN") - return 0 - - new_vars: int = 0 - tn: t.CSizeT = len(targets) - for ti in range(tn): - target: ast.AST | t.CPtr = targets.get(ti) - if target is None: - continue - - tk: int = target.kind() - - # Tuple 赋值: a, b = f() 多返回值解包 - # rhs_val 是匿名 struct 值(函数返回 tuple[T1,T2] 打包)→ alloca + - # store + GEP 逐字段 load → store 到各 Name 目标。 - if tk == ast.ASTKind.Tuple: - tgt_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) - tgt_elts: list[ast.AST | t.CPtr] | t.CPtr = tgt_tup.elts - # 守卫:rhs 不是 struct(tuple 打包)时跳过本 target - if tgt_elts is None or rhs_val is None or rhs_val.Ty is None: - continue - match rhs_val.Ty: - case llvmlite.LLVMType.Struct(_, _, _): - tgt_n: t.CSizeT = len(tgt_elts) - tmp_s: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, rhs_val.Ty) - if tmp_s is not None: - llvmlite.build_store(builder, rhs_val, tmp_s) - fchain: llvmlite.ParamNode | t.CPtr = llvmlite.get_struct_fields(rhs_val.Ty) - fcur: llvmlite.ParamNode | t.CPtr = fchain - fti: t.CSizeT - for fti in range(tgt_n): - tgt_elt: ast.AST | t.CPtr = tgt_elts.get(fti) - if tgt_elt is None or fcur is None: - break - fty: llvmlite.LLVMType | t.CPtr = llvmlite.paramnode_get_ty(fcur) - fcur = llvmlite.paramnode_get_next(fcur) - if fty is None: - # fail-fast: 字段类型缺失,立即终止 - HandlesType.fatal_error(target, "元组解包字段类型缺失", "TypeError") - # 守卫:非 Name 元素无法解包,跳过 - if tgt_elt.kind() != ast.ASTKind.Name: - continue - tgt_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_elt) - if tgt_nm2.id is None: - continue - fp2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, rhs_val.Ty, fty, tmp_s, fti) - if fp2 is None: - continue - fv2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, fty, fp2) - tgt_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - self.Trans.SymTab, tgt_nm2.id) - if tgt_alloca is None: - tgt_alloca = HandlesVar.get_or_create_sym( - self.Trans.SymTab, pool, builder, tgt_nm2.id, fty) - if tgt_alloca is None: - continue - sval: llvmlite.Value | t.CPtr = fv2 - if tgt_alloca.Ty is not None and tgt_alloca.Ty.Pointee is not None: - sval = HandlesExpr.coerce_to_type( - builder, fv2, tgt_alloca.Ty.Pointee, node) - llvmlite.build_store(builder, sval, tgt_alloca) - case _: - pass - continue - - # Subscript 赋值: arr[i] = val / ptr[i] = val / list[i] = val - if tk == ast.ASTKind.Subscript: - # 检查是否是 list[T] 类型的 Subscript(泛型类不注册 struct) - # list 的 subscript 赋值走 __setitem__ 内联路径 - list_obj: llvmlite.Value | t.CPtr = HandlesExpr.is_list_subscript( - target, self.Trans) - if list_obj is not None: - # list[T] 类型: 内联生成 __setitem__ 逻辑 - sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target) - if sub_node is not None and sub_node.slice is not None: - list_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_node.slice, None, 0, self.Trans) - if list_idx_val is None: - # fail-fast: list 下标翻译失败,立即终止 - HandlesType.fatal_error(target, "list 下标翻译失败", "TypeError") - HandlesExpr.list_setitem_inline( - builder, pool, list_obj, list_idx_val, rhs_val, target) - continue - # 普通 Subscript 赋值 - elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr( - builder, pool, mod, target, self.Trans) - if elem_ptr is not None: - store_val: llvmlite.Value | t.CPtr = rhs_val - # 守卫短路:elem 类型完整才做类型转换 - if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: - store_val = HandlesExpr.coerce_to_type( - builder, rhs_val, elem_ptr.Ty.Pointee, node) - llvmlite.build_store(builder, store_val, elem_ptr) - continue - # get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载 - # 适用于自定义类(如 hashtable[key]=val → hashtable.__setitem__(key, val)) - sub_asgn: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target) - setitem_done: int = 0 - if sub_asgn is not None and sub_asgn.value is not None: - if sub_asgn.value.kind() == ast.ASTKind.Name: - sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_asgn.value) - if sub_nm.id is not None: - sub_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - self.Trans.SymTab, sub_nm.id) - if sub_alloca is not None and sub_alloca.Ty is not None \ - and sub_alloca.Ty.Pointee is not None \ - and HandlesExpr.is_ptr_type(sub_alloca.Ty) != 0: - sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee - cls_nm_set: str = HandlesStruct.get_class_name_by_type(pool, sub_pointee) - obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, sub_pointee, sub_alloca) - # 指针类型变量 (X|t.CPtr): sub_pointee 是 Ptr(Struct), - # 需 load 获取 Ptr(Struct) 再检查 inner struct - if cls_nm_set is None and obj_val_set is not None \ - and HandlesExpr.is_ptr_type(sub_pointee) != 0 \ - and sub_pointee.Pointee is not None: - cls_nm_set = HandlesStruct.get_class_name_by_type( - pool, sub_pointee.Pointee) - if cls_nm_set is not None and obj_val_set is not None: - key_val_set: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_asgn.slice, None, 0, self.Trans) - if key_val_set is not None: - arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16) - if arg_vals_set is not None: - arg_vals_set[0] = t.CSizeT(key_val_set) - arg_vals_set[1] = t.CSizeT(rhs_val) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, cls_nm_set, "__setitem__", - obj_val_set, arg_vals_set, 2, self.Trans) - setitem_done = 1 - elif sub_asgn.value.kind() == ast.ASTKind.Attribute: - # self._ht[key] = val → self._ht.__setitem__(key, val) - # 通过 get_attribute_ptr 获取字段指针,再调用 __setitem__ - field_ptr_set: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, sub_asgn.value, self.Trans) - if field_ptr_set is not None and field_ptr_set.Ty is not None \ - and field_ptr_set.Ty.Pointee is not None \ - and HandlesExpr.is_ptr_type(field_ptr_set.Ty) != 0: - field_pointee_set: llvmlite.LLVMType | t.CPtr = field_ptr_set.Ty.Pointee - cls_nm_attr: str = HandlesStruct.get_class_name_by_type(pool, field_pointee_set) - obj_val_attr: llvmlite.Value | t.CPtr = field_ptr_set - # field_ptr 是 Ptr(Ptr(Struct)) (X|t.CPtr 字段): - # load 解引用获取 Ptr(Struct) - if cls_nm_attr is None \ - and HandlesExpr.is_ptr_type(field_pointee_set) != 0 \ - and field_pointee_set.Pointee is not None: - cls_nm_attr = HandlesStruct.get_class_name_by_type( - pool, field_pointee_set.Pointee) - if cls_nm_attr is not None: - obj_val_attr = llvmlite.build_load( - builder, field_pointee_set, field_ptr_set) - if cls_nm_attr is not None and obj_val_attr is not None: - key_val_attr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_asgn.slice, None, 0, self.Trans) - if key_val_attr is not None: - arg_vals_attr: t.CSizeT | t.CPtr = pool.alloc(16) - if arg_vals_attr is not None: - arg_vals_attr[0] = t.CSizeT(key_val_attr) - arg_vals_attr[1] = t.CSizeT(rhs_val) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, cls_nm_attr, "__setitem__", - obj_val_attr, arg_vals_attr, 2, self.Trans) - setitem_done = 1 - if setitem_done == 0: - # 通用 fallback: 翻译 sub.value 并尝试 __setitem__ 或直接 GEP+store - # 处理 Name/Attribute 之外的节点以及 SymTab 查找失败的情况 - if sub_asgn is not None and sub_asgn.value is not None: - obj_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_asgn.value, None, 0, self.Trans) - key_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sub_asgn.slice, None, 0, self.Trans) - if obj_val_gen is not None and key_val_gen is not None \ - and obj_val_gen.Ty is not None: - # 内联 _get_custom_struct_cls_nm 逻辑(避免依赖新函数) - cls_nm_gen: str = HandlesStruct.get_class_name_by_type( - pool, obj_val_gen.Ty) - if cls_nm_gen is None and HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0 \ - and obj_val_gen.Ty.Pointee is not None: - cls_nm_gen = HandlesStruct.get_class_name_by_type( - pool, obj_val_gen.Ty.Pointee) - if cls_nm_gen is not None: - # 自定义结构体: 调用 __setitem__ - arg_vals_gen: t.CSizeT | t.CPtr = pool.alloc(16) - if arg_vals_gen is not None: - arg_vals_gen[0] = t.CSizeT(key_val_gen) - arg_vals_gen[1] = t.CSizeT(rhs_val) - ExprCallCtor._call_method_on_ptr( - pool, builder, mod, cls_nm_gen, "__setitem__", - obj_val_gen, arg_vals_gen, 2, self.Trans) - setitem_done = 1 - elif HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0 \ - and obj_val_gen.Ty.Pointee is not None: - # 非自定义结构体: 直接 GEP + store - # 处理 get_subscript_ptr 因边界情况返回 None 的指针下标 - elem_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee - store_val_gen: llvmlite.Value | t.CPtr = rhs_val - elem_ptr_gen: llvmlite.Value | t.CPtr = None - match elem_gen: - case llvmlite.LLVMType.Array(arr_elem_gen, _): - elem_ptr_gen = llvmlite.build_gep_array( - builder, elem_gen, arr_elem_gen, - obj_val_gen, key_val_gen) - case _: - elem_ptr_gen = llvmlite.build_gep( - builder, elem_gen, obj_val_gen, key_val_gen) - if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None: - if elem_ptr_gen.Ty.Pointee is not None: - store_val_gen = HandlesExpr.coerce_to_type( - builder, rhs_val, elem_ptr_gen.Ty.Pointee, node) - llvmlite.build_store(builder, store_val_gen, elem_ptr_gen) - setitem_done = 1 - if setitem_done == 0: - HandlesType.fatal_error(target, "subscript ptr is None") - continue - - # Attribute 赋值: obj.field = val - if tk == ast.ASTKind.Attribute: - # property setter 拦截: obj.attr = v 且 attr 是 @x.setter 方法时, - # 生成 call Class.attr$set(obj, v),跳过字段存储 - # 注意参数顺序:_try_property_setter(pool, builder, mod, ...)—— - # 旧代码传 (builder, pool, ...) 导致 pool/builder 错位,pool 参数 - # 实际是 IRBuilder 对象,pool.alloc 虚调用读 IRBuilder[0] 当 vtable - # 跳到垃圾地址崩溃(BuiltinDecoratorTest Phase A 崩溃根因)。 - if ExprCallCtor._try_property_setter( - pool, builder, mod, target, rhs_val, self.Trans) == 1: - continue - # FakeDuck: 影子结构体属性写入 (str 变量的 per-instance 字段) - # a.__data__ = v → GEP {a}__meta__[field] 并 store - # 对齐 TPC HandlesAssign.py L67-76:对象是 Name 变量且存在 - # {var}__meta__ 影子(fd2 创建)时,属性写入改走影子结构体。 - fd_an: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target) - if fd_an is not None and fd_an.value is not None and fd_an.attr is not None: - if fd_an.value.kind() == ast.ASTKind.Name: - fd_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_an.value) - if fd_obj_nm.id is not None: - # pool 持久缓冲(f-string 栈缓冲在函数返回后失效) - fd_meta_w: str = pool.alloc(256) - if fd_meta_w is not None: - viperlib.snprintf(fd_meta_w, 256, "%s__meta__", fd_obj_nm.id) - fd_meta_vw: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - self.Trans.SymTab, fd_meta_w) - if fd_meta_vw is not None: - fd_sty_w: llvmlite.LLVMType | t.CPtr = \ - HandlesStruct.get_struct_type("_str") - if fd_sty_w is not None: - fd_fe_w: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_sty_w, fd_an.attr) - if fd_fe_w is not None and fd_fe_w.Ty is not None: - fd_fp_w: llvmlite.Value | t.CPtr = \ - llvmlite.build_gep_struct( - builder, fd_sty_w, fd_fe_w.Ty, - fd_meta_vw, fd_fe_w.Index) - if fd_fp_w is not None: - sv_fd: llvmlite.Value | t.CPtr = \ - HandlesExpr.coerce_to_type( - builder, rhs_val, fd_fe_w.Ty, node) - llvmlite.build_store(builder, sv_fd, fd_fp_w) - continue - # VTABLE 直接写入:obj.method = func(serial0_file.open = serial0_open) - # vtable 方法不是数据字段(FieldEntry),get_attribute_ptr 查不到会 - # fatal_error;此处对齐 TPC HandlesAssign.py L905-949 的写时复制, - # 检测到 vtable 方法时直接生成槽位写入并跳过字段路径。 - import lib.core.Gen.Generator as Generator - g_vtw: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g_vtw is not None: - if g_vtw._write_vtable_attr( - builder, pool, mod, target, rhs_val, self.Trans) == 1: - continue - field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, target, self.Trans) - if field_ptr is not None: - # 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64) - store_val: llvmlite.Value | t.CPtr = rhs_val - if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None: - store_val = HandlesExpr.coerce_to_type( - builder, rhs_val, field_ptr.Ty.Pointee, node) - llvmlite.build_store(builder, store_val, field_ptr) - continue - # 守卫:field_ptr 为 None → 构造详细错误信息 - # Phase A 依赖未就绪(_deps_pending):get_attribute_ptr 已因 - # 父类/依赖类未注册跳过字段,此处同样跳过不报错,整文件下遍重译 - # (对齐 HandlesAssign L69-78 与 get_attribute_ptr 的 pending 容忍) - if self.Trans is not None and self.Trans._deps_pending != 0: - continue - attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target) - attr_name: str = "(unknown)" - obj_name: str = "(unknown)" - if attr_node is not None: - attr_name = attr_node.attr - if attr_node.value is not None and attr_node.value.kind() == ast.ASTKind.Name: - obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(attr_node.value) - obj_name = obj_nm.id - err_buf: str = pool.alloc(256) - if err_buf is not None: - viperlib.snprintf(err_buf, 256, - "attribute ptr is None: %s.%s", - obj_name, attr_name) - HandlesType.fatal_error(target, err_buf) - else: - HandlesType.fatal_error(target, "attribute ptr is None") - continue - - # Name 赋值: var = val - if tk == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) - # 守卫:target 名缺失时跳过 - if nm.id is None: - continue - # global 变量:写入模块作用域中的全局变量 - if HT.is_global_name(self.Trans, nm.id) != 0: - mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - self.Trans.SymTab, nm.id) - if mod_alloca is None: - # fail-fast: global 变量未注册,无法赋值 - HandlesType.fatal_error( - target, - f"global 变量 '{nm.id}' 未注册,无法赋值", - "NameError") - target_ty: llvmlite.LLVMType | t.CPtr = None - if mod_alloca.Ty is not None: - target_ty = mod_alloca.Ty.Pointee - if target_ty is not None: - rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node) - llvmlite.build_store(builder, rhs_val, mod_alloca) - continue - - # nonlocal 变量:通过闭包 env 写入 - if HT.is_nonlocal_name(self.Trans, nm.id) != 0: - nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( - self.Trans, nm.id) - if nl_ptr is None: - # fail-fast: nonlocal 变量指针解析失败 - HandlesType.fatal_error( - target, - f"nonlocal 变量 '{nm.id}' 指针解析失败", - "NameError") - # 从 nl_ptr 的类型推断 nonlocal 变量实际类型, - # 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏) - nl_target_ty: llvmlite.LLVMType | t.CPtr = None - if nl_ptr.Ty is not None: - nl_target_ty = nl_ptr.Ty.Pointee - if nl_target_ty is None: - # fail-fast: nl_ptr 类型信息丢失,无法安全 store - HandlesType.fatal_error( - target, - f"nonlocal 变量 '{nm.id}' 类型信息丢失,无法写入", - "TypeError") - rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, rhs_val, nl_target_ty, node) - llvmlite.build_store(builder, rhs_coerced, nl_ptr) - continue - - # 拦截:函数内对模块级全局变量赋值但没 global 声明 - # 否则静默创建局部变量遮蔽全局,全局保持 null 导致运行时崩溃 - # (_mbuddy = mb 缺 global 声明即此类 bug:Int32 解引用 null 崩溃) - if HandlesVar.is_module_scope(self.Trans.SymTab) == 0: - mod_gv: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var( - self.Trans.SymTab, nm.id) - if mod_gv is not None: - fb_g: str = VLogger.fmt_buf() - msg_g: str = "global 声明缺失" - if fb_g is not None: - viperlib.snprintf(fb_g, 1024, "变量 '%s' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", nm.id) - msg_g = fb_g - HandlesType.fatal_error(target, msg_g, "SyntaxError") - - # 普通局部变量 - alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym( - self.Trans.SymTab, pool, builder, nm.id, rhs_val.Ty) - if alloca is not None: - # 无注解赋值:从 RHS 表达式推断类名设置变量注解 - # (联合类型 X|t.CPtr 简化为 Ptr(i8),属性访问按需过滤需要 - # AnnotClassName 才能定位结构体字段) - cls_inf: str = self._infer_rhs_annot(pool, mod, asgn.value, self.Trans, rhs_val) - if cls_inf is not None: - HandlesVar.set_var_annot_class_name( - self.Trans.SymTab, nm.id, cls_inf) - # 按 alloca 类型对值进行转换(如 double → float) - store_val: llvmlite.Value | t.CPtr = rhs_val - if alloca.Ty is not None and alloca.Ty.Pointee is not None: - store_val = HandlesExpr.coerce_to_type( - builder, rhs_val, alloca.Ty.Pointee, node) - llvmlite.build_store(builder, store_val, alloca) - # lambda 表达式赋给变量:注册为闭包变量名, - # 调用分派(is_closure_name)才走闭包间接调用路径; - # 否则 i8** alloca 被 _is_func_ptr_alloca 误判为 - # 函数指针,无参 call 直接跳闭包数据崩溃 - if asgn.value is not None \ - and asgn.value.kind() == ast.ASTKind.Lambda: - ExprCallCall.register_closure_name(nm.id) - existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - self.Trans.SymTab, nm.id) - if existing is None: - new_vars += 1 - else: - # fail-fast: 变量存储创建失败,立即终止 - HandlesType.fatal_error( - target, - f"变量 '{nm.id}' 存储创建失败", - "TypeError") - - return new_vars - - # ============================================================ - # _infer_rhs_annot - 从 RHS 表达式推断变量注解类名 - # - # 无注解赋值(如 v = Vec2(...) / v3 = v1 + v2)时,变量 AnnotClassName - # 缺失会导致后续属性访问(.x)无法"按需过滤":联合类型 X|t.CPtr 在 LLVM - # 中简化为 Ptr(i8),不携带类名,无法定位结构体字段(字段未找到 → fast-fail)。 - # 此函数按 RHS 结构推断类名: - # Call → 类实例化(func 为已注册结构体名才采用,避免普通函数误标); - # func 为 Attribute 时是方法调用(a.cross()),obj 类名 + - # 方法存在 + rhs_val 为指针类型(联合对象)三条件判定 - # Name → 源变量的 AnnotClassName - # BinOp/UnaryOp → lhs 类名 + 该类存在对应 dunder 方法(运算符重载返回同类对象) - # Attribute → 字段注解类名(委托 Generator 单例 _resolve_attr_field_class) - # 仅当目标为已注册结构体时采用,与"按需过滤,找不到 fast-fail"原则一致。 - # ============================================================ - def _infer_rhs_annot(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr, - rhs_val: llvmlite.Value | t.CPtr = None) -> str: - """从 RHS 表达式推断类名,无法推断返回 None""" - if node is None or trans is None: - return None - k: int = node.kind() - # Call: 类实例化 / 方法调用 - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl is None or cl.func is None: - return None - if cl.func.kind() == ast.ASTKind.Name: - # 类实例化:func 为已注册结构体名才采用 - cand: str = ((ast.Name | t.CPtr)(cl.func)).id - if cand is None: - return None - se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(cand) - if se is not None: - return cand - return None - if cl.func.kind() == ast.ASTKind.Attribute: - # 方法调用 a.cross(b):从 vpi 返回注解缓存精确解析返回类名 - # (方法可返回非同类对象,如 Transform.world_position → 'Vec3', - # 启发式取 obj 类名会 GEP 错字段)。vpi 未命中时返回 None, - # 由后续属性访问 fast-fail 暴露 vpi 缺失根因(不静默回退)。 - ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if ca is None or ca.attr is None or ca.value is None: - return None - obj_cls: str = self._infer_rhs_annot(pool, mod, ca.value, trans) - if obj_cls is None: - # 模块级函数调用(requests.get):ca.value 是已导入模块名 - # 而非对象变量(模块名 lookup_var_entry 返回 None → 上面 - # 对象类名推断失败)。从该模块 vpi 的返回注解缓存解析返回 - # 类名(键 {sha1}.{func},cls_name=None 即模块级函数,与 - # CallGenMixin 跨模块返回类型解析一致)。 - # WebTest resp = requests.get(...) 根因:无注解赋值变量 - # AnnotClassName 推断失败(annot=None)→ 属性访问按需过滤 - # (依赖 AnnotClassName)失效 → "属性访问失败: .status_code"。 - if ca.value.kind() == ast.ASTKind.Name: - mod_nm_rhs: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value) - if mod_nm_rhs.id is not None: - mod_sha1_rhs: str = ExprCallBase._lookup_module_sha1( - mod_nm_rhs.id) - if mod_sha1_rhs is not None: - import lib.StubGen.VpiReader as VpiReader - temp_dir_rhs: str = None - import lib.core.Gen.Generator as Generator - g_rhs: Generator.Generator | t.CPtr = ( - Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g_rhs is not None and g_rhs.TempDir is not None: - temp_dir_rhs = g_rhs.TempDir - if temp_dir_rhs is not None: - VpiReader._ensure_vpi_ret_annot_loaded( - mod_sha1_rhs, temp_dir_rhs) - annot_rhs: str = VpiReader._lookup_vpi_ret_annot( - mod_sha1_rhs, None, ca.attr) - if annot_rhs is not None: - ret_cls_rhs: str = self._extract_annot_class_name( - pool, annot_rhs) - if ret_cls_rhs is not None: - return ret_cls_rhs - return None - if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0: - return None - # 方法定义所在模块 SHA1(优先 struct entry,回退当前模块 sha1) - cls_sha1: str = HandlesStruct.get_struct_sha1(obj_cls) - if cls_sha1 is None and trans.ModuleSha1 is not None: - cls_sha1 = trans.ModuleSha1 - ret_cls: str = None - if cls_sha1 is not None: - import lib.StubGen.VpiReader as VpiReader - temp_dir: str = None - import lib.core.Gen.Generator as Generator - g2: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g2 is not None and g2.TempDir is not None: - temp_dir = g2.TempDir - if temp_dir is not None: - VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir) - annot_ret: str = VpiReader._lookup_vpi_ret_annot( - cls_sha1, obj_cls, ca.attr) - if annot_ret is not None: - ret_cls = self._extract_annot_class_name(pool, annot_ret) - return ret_cls - return None - # Name: 源变量注解 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm is None or nm.id is None: - return None - ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if ve is None: - return None - return ve.AnnotClassName - # BinOp/UnaryOp: 运算符重载返回同类对象 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if bop is None or bop.left is None: - return None - dunder: str = self._op_to_dunder(bop.op) - if dunder is None: - return None - lhs_cls: str = self._infer_rhs_annot(pool, mod, bop.left, trans) - if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0: - return None - return lhs_cls - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uop is None or uop.operand is None: - return None - dunder: str = self._op_to_dunder(uop.op) - if dunder is None: - return None - opr_cls: str = self._infer_rhs_annot(pool, mod, uop.operand, trans) - if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0: - return None - return opr_cls - # Attribute: 字段注解类名(属性链递归,如 p = r.origin) - if k == ast.ASTKind.Attribute: - import lib.core.Gen.Generator as Generator - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g is not None: - return g._resolve_attr_field_class(pool, trans, node) - return None - return None - - # ============================================================ - # _extract_annot_class_name - 从返回注解文本提取结构体类名 - # - # vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除 - # 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/ - # CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合 - # 多候选时取首个命中段。 - # ============================================================ - def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr, - annot: str) -> str: - """从返回注解文本提取已注册结构体类名,无命中返回 None""" - if pool is None or annot is None: - return None - alen: t.CSizeT = string.strlen(annot) - if alen == 0: - return None - seg: str = pool.alloc(256) - if seg is None: - return None - start: t.CSizeT = 0 - i: t.CSizeT - for i in range(alen): - if annot[i] == '|': - seglen: t.CSizeT = i - start - # 段 [start, i):去除首尾空格与引号后查注册表 - s: t.CSizeT = start - e: t.CSizeT = i - while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): - s += 1 - while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): - e -= 1 - seglen = e - s - if seglen > 0 and seglen < 256: - string.strncpy(seg, annot + s, seglen) - seg[seglen] = '\0' - se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(seg) - if se is not None: - return seg - start = i + 1 - # 最后一段(无 '|' 后缀) - s: t.CSizeT = start - e: t.CSizeT = alen - while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'): - s += 1 - while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'): - e -= 1 - seglen: t.CSizeT = e - s - if seglen > 0 and seglen < 256: - string.strncpy(seg, annot + s, seglen) - seg[seglen] = '\0' - se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(seg) - if se is not None: - return seg - return None - - # ============================================================ - # _op_to_dunder - 运算符 → dunder 方法名(本地副本,避免跨 Mixin 调用) - # ============================================================ - def _op_to_dunder(self, op: int) -> str: - """BinOp/UnaryOp 运算符 → dunder 方法名,无映射返回 None""" - if op == ast.OpKind.Add: return "__add__" - if op == ast.OpKind.Sub: return "__sub__" - if op == ast.OpKind.Mult: return "__mul__" - if op == ast.OpKind.Div: return "__truediv__" - if op == ast.OpKind.FloorDiv: return "__floordiv__" - if op == ast.OpKind.Mod: return "__mod__" - if op == ast.OpKind.Pow: return "__pow__" - if op == ast.OpKind.BitAnd: return "__and__" - if op == ast.OpKind.BitOr: return "__or__" - if op == ast.OpKind.BitXor: return "__xor__" - if op == ast.OpKind.LShift: return "__lshift__" - if op == ast.OpKind.RShift: return "__rshift__" - if op == ast.OpKind.USub: return "__neg__" - if op == ast.OpKind.UAdd: return "__pos__" - if op == ast.OpKind.Invert: return "__invert__" - return None - - # ============================================================ - # _cls_has_dunder - 检查类(含继承链)是否存在 dunder 方法 - # - # 与 ExprGenMixin.try_operator_overload 的查找一致:当前模块内定义 - # 或跨模块类有 SHA1(stub 中声明)即视为存在。仅在确实存在时 - # 才采用运算符重载推断的类名,避免把原生运算误标为类类型。 - # ============================================================ - def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, dunder: str) -> int: - """类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1""" - if class_name is None or dunder is None or mod is None: - return 0 - lookup_name: str = pool.alloc(128) - if lookup_name is None: - return 0 - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) - if ExprCallBase.find_func_in_module(mod, lookup_name) is not None: - return 1 - # 继承链祖先查找 - mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name) - mi: int = 1 - while mro_ptr is not None and mro_ptr[mi] != 0: - anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr)) - if anc is not None: - anc_lookup: str = pool.alloc(128) - if anc_lookup is not None: - viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder) - if ExprCallBase.find_func_in_module(mod, anc_lookup) is not None: - return 1 - mi += 1 - # 跨模块:类有 SHA1(stub 中声明该方法)视为存在 - if HandlesStruct.get_struct_sha1(class_name) is not None: - return 1 - return 0 +# ============================================================ +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) +# ============================================================ +_g_gen: Generator.Generator | t.CPtr = None # ============================================================ -# NewAssignHandle - 工厂函数:分配并初始化 AssignHandle +# translate_assign - Assign 语句翻译(委托到 gen.translate_assign) # ============================================================ -def NewAssignHandle(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> AssignHandle | t.CPtr: - h: AssignHandle | t.CPtr = pool.alloc(AssignHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, AssignHandle.__sizeof__()) - h.Trans = trans - return h +def translate_assign(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译赋值语句,返回新增变量数(委托到 gen.translate_assign)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_assign(trans, node) + return 0 diff --git a/App/lib/core/Handles/HandlesAugAssign.vp b/App/lib/core/Handles/HandlesAugAssign.vp index 4ca3829..19fbe29 100644 --- a/App/lib/core/Handles/HandlesAugAssign.vp +++ b/App/lib/core/Handles/HandlesAugAssign.vp @@ -1,21 +1,21 @@ import t, c from stdint import * import ast -import llvmlite import memhub -import stdio -import string -import viperlib -import lib.core.VLogger as VLogger -import lib.core.Handles.HandlesBase as HandlesBase import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesNonlocal as HandlesNonlocal -import lib.core.Handles.HandlesType as HandlesType import lib.core.Gen.Generator as Generator +# ============================================================ +# HandlesAugAssign - 增强赋值语句处理(迁移完成,保留跨 Mixin 委托壳) +# +# P6 机械化迁移:AugAssignHandle 类 → AssignGenMixin.translate_augassign。 +# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下 +# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。 +# 迁移收尾(编译器缺陷修复)后统一删除。 +# ============================================================ + + # ============================================================ # 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) # ============================================================ @@ -23,266 +23,12 @@ _g_gen: Generator.Generator | t.CPtr = None # ============================================================ -# HandlesAugAssign - 增强赋值语句处理(Mixin 继承模式) -# -# 处理 += -= *= /= %= &= |= ^= <<= >>= -# 流程: load target → apply binop → store result -# -# 支持 local/global/nonlocal 三种变量作用域 +# translate_augassign - 增强赋值翻译(委托到 gen.translate_augassign) # ============================================================ - - -@t.NoVTable -class AugAssignHandle(HandlesBase.Mixin): - """增强赋值处理器 (+=, -=, *=, etc.):继承 Mixin 获得 Trans 回指针""" - - def __init__(self, trans: HT.Translator | t.CPtr): - self.Trans = trans - - # ============================================================ - # Handle - 处理 AugAssign 语句,返回新增变量数(始终为 0) - # ============================================================ - def Handle(self, node: ast.AST | t.CPtr) -> int: - """翻译增强赋值语句 (x += 1, y -= 2, etc.)""" - if node is None: - return 0 - - aug: ast.AugAssign | t.CPtr = (ast.AugAssign | t.CPtr)(node) - if aug is None: - return 0 - - target: ast.AST | t.CPtr = aug.target - if target is None: - return 0 - - tk: int = target.kind() - - # Attribute 目标: self.field += 1 - # 流程: get_attribute_ptr → load → binop → store - if tk == ast.ASTKind.Attribute: - pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module - - # 1. 获取字段指针 - field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, target, self.Trans) - if field_ptr is None: - # fail-fast: 属性指针解析失败 - HandlesType.fatal_error(target, "attribute ptr is None", "TypeError") - - # 2. 确定字段类型并加载当前值 - target_ty: llvmlite.LLVMType | t.CPtr = None - if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None: - target_ty = field_ptr.Ty.Pointee - if target_ty is None: - # fail-fast: 字段类型信息缺失,禁止兜底 i32 - HandlesType.fatal_error(target, "字段类型信息缺失", "TypeError") - cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, target_ty, field_ptr) - if cur_val is None: - # fail-fast: 属性当前值加载失败 - HandlesType.fatal_error(target, "无法加载 attribute 当前值", "TypeError") - - # 3. 翻译 RHS 值 - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aug.value, None, 0, self.Trans) - if rhs_val is None: - # fail-fast: RHS 翻译失败 - HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") - - # 4. 应用二元运算 - result: llvmlite.Value | t.CPtr = _apply_aug_op( - pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target) - if result is None: - # fail-fast: attribute 二元运算失败 - HandlesType.fatal_error(target, f"attribute 二元运算失败 op={aug.op}", "TypeError") - - # 5. 类型对齐并存储 - result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) - if result is None: - # fail-fast: 类型对齐失败 - HandlesType.fatal_error(target, "类型对齐失败", "TypeError") - llvmlite.build_store(builder, result, field_ptr) - return 0 - - # Subscript 目标: self.state[i] += x / arr[i] += x - # 流程: get_subscript_ptr → load → binop → store - if tk == ast.ASTKind.Subscript: - pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module - - # 1. 获取元素指针 - elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr( - builder, pool, mod, target, self.Trans) - if elem_ptr is None: - # fail-fast: 下标指针解析失败 - HandlesType.fatal_error(target, "subscript ptr is None", "TypeError") - - # 2. 确定元素类型并加载当前值 - target_ty: llvmlite.LLVMType | t.CPtr = None - if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None: - target_ty = elem_ptr.Ty.Pointee - if target_ty is None: - # fail-fast: 元素类型信息缺失,禁止兜底 i32 - HandlesType.fatal_error(target, "元素类型信息缺失", "TypeError") - cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, target_ty, elem_ptr) - if cur_val is None: - # fail-fast: 元素当前值加载失败 - HandlesType.fatal_error(target, "无法加载 subscript 元素当前值", "TypeError") - - # 3. 翻译 RHS 值 - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aug.value, None, 0, self.Trans) - if rhs_val is None: - # fail-fast: RHS 翻译失败 - HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") - - # 4. 应用二元运算 - result: llvmlite.Value | t.CPtr = _apply_aug_op( - pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target) - if result is None: - # fail-fast: subscript 二元运算失败 - HandlesType.fatal_error(target, f"subscript 二元运算失败 op={aug.op}", "TypeError") - - # 5. 类型对齐并存储 - result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) - if result is None: - # fail-fast: 类型对齐失败 - HandlesType.fatal_error(target, "类型对齐失败", "TypeError") - llvmlite.build_store(builder, result, elem_ptr) - return 0 - - if tk != ast.ASTKind.Name: - # fail-fast: 不支持的 AugAssign 目标类型 - HandlesType.fatal_error( - target, "AugAssign 目标类型不支持,仅支持 Name/Attribute/Subscript", "TypeError") - - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) - if nm is None or nm.id is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module - - # 1. 确定变量作用域类型: 0=local, 1=global, 2=nonlocal - scope_type: int = 0 - if HT.is_global_name(self.Trans, nm.id) != 0: - scope_type = 1 - elif HT.is_nonlocal_name(self.Trans, nm.id) != 0: - scope_type = 2 - - # 2. 加载当前值 - cur_val: llvmlite.Value | t.CPtr = None - target_alloca: llvmlite.Value | t.CPtr = None - target_ty: llvmlite.LLVMType | t.CPtr = None - - if scope_type == 1: - # global 变量 - target_alloca = HandlesVar.lookup_module_var( - self.Trans.SymTab, nm.id) - if target_alloca is not None: - if target_alloca.Ty is None: - # fail-fast: 变量类型信息缺失,禁止兜底 i32 - HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError") - target_ty = target_alloca.Ty.Pointee - cur_val = llvmlite.build_load(builder, target_ty, target_alloca) - elif scope_type == 2: - # nonlocal 变量(通过闭包 env) - cur_val = HandlesNonlocal.load_nonlocal_var(self.Trans, nm.id) - if cur_val is not None: - target_ty = cur_val.Ty - else: - # 普通局部变量 - target_alloca = HandlesVar.lookup_var(self.Trans.SymTab, nm.id) - if target_alloca is not None: - if target_alloca.Ty is None: - # fail-fast: 变量类型信息缺失,禁止兜底 i32 - HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError") - target_ty = target_alloca.Ty.Pointee - cur_val = llvmlite.build_load(builder, target_ty, target_alloca) - - if cur_val is None: - # fail-fast: 目标变量当前值加载失败 - HandlesType.fatal_error( - target, - f"无法加载目标变量 '{nm.id}' 的当前值", - "TypeError") - - # 3. 翻译 RHS 值 - rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, aug.value, None, 0, self.Trans) - if rhs_val is None: - # fail-fast: RHS 翻译失败 - HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError") - - # 4. 类型对齐 + 应用二元运算 - # 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__) - result: llvmlite.Value | t.CPtr = _apply_aug_op( - pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target) - if result is None: - # fail-fast: 二元运算失败 - HandlesType.fatal_error( - target, - f"对变量 '{nm.id}' 应用二元运算失败 op={aug.op}", - "TypeError") - - # 5. 存储结果 - result = HandlesExpr.coerce_to_type(builder, result, target_ty, node) - if result is None: - # fail-fast: 类型对齐失败 - HandlesType.fatal_error(target, "类型对齐失败", "TypeError") - - if scope_type == 1: - # global 变量 - if target_alloca is not None: - llvmlite.build_store(builder, result, target_alloca) - elif scope_type == 2: - # nonlocal 变量 - nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr( - self.Trans, nm.id) - if nl_ptr is not None: - llvmlite.build_store(builder, result, nl_ptr) - else: - # 普通局部变量 - if target_alloca is not None: - llvmlite.build_store(builder, result, target_alloca) - - return 0 - - -# ============================================================ -# _apply_aug_op - 应用增强赋值的二元运算 -# -# 支持浮点运算、指针算术: ptr += int / ptr -= int -# 整数运算自动类型提升 -# ============================================================ -def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - op: int, - lhs: llvmlite.Value | t.CPtr, - rhs: llvmlite.Value | t.CPtr, - node: ast.AST | t.CPtr = None, - trans: HT.Translator | t.CPtr = None, - lhs_node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算,委托到 gen._apply_aug_op)""" +def translate_augassign(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译增强赋值语句,返回新增变量数(委托到 gen.translate_augassign)""" g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) if g is not None: - return g._apply_aug_op(pool, builder, op, lhs, rhs, node, trans, lhs_node) - return None - - -# ============================================================ -# NewAugAssignHandle - 工厂函数 -# ============================================================ -def NewAugAssignHandle(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> AugAssignHandle | t.CPtr: - h: AugAssignHandle | t.CPtr = pool.alloc(AugAssignHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, AugAssignHandle.__sizeof__()) - h.Trans = trans - return h + return g.translate_augassign(trans, node) + return 0 diff --git a/App/lib/core/Handles/HandlesFor.vp b/App/lib/core/Handles/HandlesFor.vp index 9b1df94..9dbe9f7 100644 --- a/App/lib/core/Handles/HandlesFor.vp +++ b/App/lib/core/Handles/HandlesFor.vp @@ -1,58 +1,33 @@ import t, c from stdint import * import ast -import llvmlite import memhub -import string -import stdio -import viperlib -import lib.core.Handles.HandlesBase as HandlesBase -import lib.core.Handles.ForHandleBase as ForHandleBase -import lib.core.Handles.ForHandleIter as ForHandleIter import lib.core.Handles.HandlesTranslator as HT -import lib.core.Handles.HandlesVar as HandlesVar -import lib.core.Handles.HandlesExpr as HandlesExpr -import lib.core.Handles.HandlesBody as HandlesBody -import lib.core.Handles.HandlesType as HandlesType -import lib.core.Handles.HandlesExprCall as HandlesExprCall -import lib.core.Handles.HandlesStruct as HandlesStruct -import lib.core.Handles.ExprCallBase as ExprCallBase import lib.core.Gen.Generator as Generator # ============================================================ -# HandlesFor - for 循环语句处理(P6 对象化后的委托层) +# HandlesFor - for 循环语句处理(迁移完成,保留跨 Mixin 委托壳) # -# NewForHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法 -# (ForHandle 类保留:trans.ForH 的类型,由 HandlesTranslator. -# _init_state 经 NewForHandle 委托创建)。 -# -# 支持 for i in range(start, stop, step) 模式: -# %i = alloca i32 -# store i32 start, i32* %i -# br label %cond -# cond: -# %cur = load i32, i32* %i -# %cmp = icmp slt i32 %cur, stop -# br i1 %cmp, label %body, label %end -# body: -# ... body ... -# br label %incr -# incr: -# %cur2 = load i32, i32* %i -# %next = add i32 %cur2, step -# store i32 %next, i32* %i -# br label %cond -# end: +# P6 机械化迁移:ForHandle/ForHandleBase/ForHandleIter 全部方法 → +# StmtGenCifMixin.translate_for 及辅助方法(_handle_ptr_iter/ +# _handle_array_iter/_handle_list_literal_iter/_handle_list_iter/ +# _handle_dict_iter/_handle_oop_iter/_handle_enumerate_iter/ +# _handle_zip_iter/_extract_tuple_names/_seq_kind/_build_seq_loop)。 +# SEQ_KIND_* 常量保留:StmtGenCifMixin._seq_kind/_build_seq_loop 经 +# HandlesFor.SEQ_KIND_* 访问。 +# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下 +# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。 +# 迁移收尾(编译器缺陷修复)后统一删除。 # ============================================================ # ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式) +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) # # 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 # 委托函数用本地 _g_gen(cast 成 Generator 类型)调 -# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。 +# StmtGenCifMixin 方法,避免函数体 import 包模块与类/模块名歧义。 # ============================================================ _g_gen: Generator.Generator | t.CPtr = None @@ -68,367 +43,13 @@ SEQ_KIND_STR: t.CDefine = 2 SEQ_KIND_LIST: t.CDefine = 3 -@t.NoVTable -class ForHandle(ForHandleBase.ForHandleBase, ForHandleIter.ForHandleIter): - """for 循环语句处理器:继承 Mixin 获得 Trans 回指针""" - - - # ============================================================ - # Handle - 处理 for 语句,返回新增变量数 - # ============================================================ - def Handle(self, node: ast.AST | t.CPtr) -> int: - """翻译 for i in range(...) 循环语句""" - 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 - - for_node: ast.For | t.CPtr = (ast.For | t.CPtr)(node) - - # 1. 获取循环变量(Name 单变量 / Tuple 多变量) - target: ast.AST | t.CPtr = for_node.target - if target is None: - return 0 - tk: int = target.kind() - if tk != ast.ASTKind.Name and tk != ast.ASTKind.Tuple: - return 0 - var_name: str = None - if tk == ast.ASTKind.Name: - target_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target) - var_name = target_nm.id - if var_name is None: - return 0 - - # 2. 解析迭代器:支持 range() 和指针迭代 - iter_node: ast.AST | t.CPtr = for_node.iter - if iter_node is None: - return 0 - - # 检查是否是 range() 调用 - is_range_iter: int = 0 - if iter_node.kind() == ast.ASTKind.Call: - call_pre: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) - fn_pre: str = HandlesExpr.get_func_name(call_pre.func) - if fn_pre is not None: - if string.strcmp(fn_pre, "range") == 0: - is_range_iter = 1 - elif string.strcmp(fn_pre, "enumerate") == 0 or string.strcmp(fn_pre, "zip") == 0: - pass # 多变量迭代,在下方非 range 分支处理 - else: - err_msg: str = pool.alloc(256) - if err_msg is not None: - viperlib.snprintf(err_msg, 256, "仅支持 range()/enumerate()/zip() 或指针迭代,got call '%s'", fn_pre) - HandlesType.fatal_error(iter_node, err_msg) - HandlesType.fatal_error(iter_node, "仅支持 range()/enumerate()/zip() 或指针迭代") - - # 非范围迭代:走指针/数组/列表字面量/容器/多变量迭代路径 - if is_range_iter == 0: - # 列表字面量:按元素顺序迭代(for x in [1, 2, 3]) - if iter_node.kind() == ast.ASTKind.List: - return self._handle_list_literal_iter(for_node, var_name, iter_node) - # enumerate(x):for i, v in enumerate(x)(多变量迭代) - if iter_node.kind() == ast.ASTKind.Call: - call_mi: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) - fn_mi: str = HandlesExpr.get_func_name(call_mi.func) - if fn_mi is not None and string.strcmp(fn_mi, "enumerate") == 0: - if tk != ast.ASTKind.Tuple: - HandlesType.fatal_error(iter_node, "enumerate 迭代需要两个循环变量 (for i, v in enumerate(x))") - tup_ie: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) - t1_buf_ie: bytes = pool.alloc(128) - t2_buf_ie: bytes = pool.alloc(128) - if t1_buf_ie is None or t2_buf_ie is None: - return 0 - t1_buf_ie[0] = '\0' - t2_buf_ie[0] = '\0' - if self._extract_tuple_names(tup_ie, t1_buf_ie, t2_buf_ie) == 0: - HandlesType.fatal_error(iter_node, "enumerate 迭代变量必须是简单名称") - return self._handle_enumerate_iter(for_node, t1_buf_ie, t2_buf_ie, call_mi) - if fn_mi is not None and string.strcmp(fn_mi, "zip") == 0: - if tk != ast.ASTKind.Tuple: - HandlesType.fatal_error(iter_node, "zip 迭代需要两个循环变量 (for a, b in zip(...))") - tup_iz: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target) - t1_buf_iz: bytes = pool.alloc(128) - t2_buf_iz: bytes = pool.alloc(128) - if t1_buf_iz is None or t2_buf_iz is None: - return 0 - t1_buf_iz[0] = '\0' - t2_buf_iz[0] = '\0' - if self._extract_tuple_names(tup_iz, t1_buf_iz, t2_buf_iz) == 0: - HandlesType.fatal_error(iter_node, "zip 迭代变量必须是简单名称") - return self._handle_zip_iter(for_node, t1_buf_iz, t2_buf_iz, call_mi) - # list[T] 容器变量:按 __count__ 动态长度迭代 - if iter_node.kind() == ast.ASTKind.Name and trans is not None: - nm_lst: ast.Name | t.CPtr = (ast.Name | t.CPtr)(iter_node) - if nm_lst.id is not None: - ve_lst: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm_lst.id) - if ve_lst is not None and ve_lst.AnnotClassName is not None: - # dict 容器变量:按 __count__/__keys__ 布局迭代(__iter__ 协议内联) - if string.strstr(ve_lst.AnnotClassName, "dict") is not None: - lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, iter_node, - trans._funcs, trans._func_count, trans) - if lst_val is not None and lst_val.Ty is not None \ - and HandlesExpr.is_ptr_type(lst_val.Ty) != 0: - return self._handle_dict_iter(for_node, var_name, lst_val) - if string.strstr(ve_lst.AnnotClassName, "list") is not None: - lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, iter_node, - trans._funcs, trans._func_count, trans) - if lst_val is not None and lst_val.Ty is not None \ - and HandlesExpr.is_ptr_type(lst_val.Ty) != 0: - return self._handle_list_iter(for_node, var_name, lst_val) - # OOP iter 协议:迭代源是类对象且类有 __iter__/__next__ 方法 → - # 走 __iter__/__next__ 调用迭代(对齐 TPC HandlesFor.py L142-166 - # _HandleForIterLlvm)。dict/list 是内置泛型容器已在上方内联处理。 - ov_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, iter_node, - trans._funcs, trans._func_count, trans) - if ov_val is not None and ov_val.Ty is not None \ - and HandlesExpr.is_ptr_type(ov_val.Ty) != 0: - ov_st: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value( - ov_val) - if ov_st is not None: - ov_cn: str = HandlesStruct.get_class_name_by_type(pool, ov_st) - if ov_cn is not None: - oi_lookup: str = pool.alloc(128) - if oi_lookup is not None: - viperlib.snprintf(oi_lookup, 128, "%s.__iter__", ov_cn) - oi_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( - trans.Module, oi_lookup) - if oi_fn is not None: - on_lookup: str = pool.alloc(128) - if on_lookup is not None: - viperlib.snprintf(on_lookup, 128, "%s.__next__", ov_cn) - on_fn: llvmlite.Function | t.CPtr = ExprCallBase.find_func_in_module( - trans.Module, on_lookup) - if on_fn is not None: - return self._handle_oop_iter( - for_node, var_name, ov_cn, ov_val) - # 其它不支持的字面量:fast-fail 显式报错, - # 避免 translate_value 触发 list[T] 特化崩溃或语义歧义。 - ik: int = iter_node.kind() - if ik == ast.ASTKind.Constant: - cn_ik: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(iter_node) - if cn_ik.const_kind != ast.CONST_STR: - HandlesType.fatal_error( - iter_node, - "for 迭代不支持该常量(仅支持字符串、数组、列表字面量、range())") - elif ik == ast.ASTKind.Dict or ik == ast.ASTKind.Set or ik == ast.ASTKind.Tuple \ - or ik == ast.ASTKind.SetComp or ik == ast.ASTKind.DictComp: - HandlesType.fatal_error( - iter_node, - "for 迭代不支持字典/集合/元组字面量,请使用 range()、t.CArray 数组或列表字面量") - return self._handle_ptr_iter(for_node, var_name) - - call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node) - - # 3. 解析 range 参数: range(stop) / range(start, stop) / range(start, stop, step) - args: list[ast.AST | t.CPtr] | t.CPtr = call.args - if args is None: - return 0 - arg_count: t.CSizeT = len(args) - - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - start_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - stop_val: llvmlite.Value | t.CPtr = None - step_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1) - - if arg_count == 0: - # fail-fast: range 无参数,立即终止 - HandlesType.fatal_error(call, "range 需要至少一个参数", "SyntaxError") - elif arg_count == 1: - stop_val = HandlesExpr.translate_value( - builder, pool, trans.Module, args.get(0), - trans._funcs, trans._func_count, trans) - if stop_val is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError") - elif arg_count >= 2: - start_val = HandlesExpr.translate_value( - builder, pool, trans.Module, args.get(0), - trans._funcs, trans._func_count, trans) - if start_val is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError") - stop_val = HandlesExpr.translate_value( - builder, pool, trans.Module, args.get(1), - trans._funcs, trans._func_count, trans) - if stop_val is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(args.get(1), "range 参数翻译失败", "TypeError") - if arg_count >= 3: - step_val = HandlesExpr.translate_value( - builder, pool, trans.Module, args.get(2), - trans._funcs, trans._func_count, trans) - if step_val is None: - # fail-fast: range 参数翻译失败 - HandlesType.fatal_error(args.get(2), "range 参数翻译失败", "TypeError") - # step 为负数字面量时循环条件反转(对齐 TPC HandlesFor.py L86-94): - # range(a, b, -1) → i > stop;range(a, b, +1) → i < stop。 - # TPC 仅识别负数字面量(UnaryOp USub 常量 / 负常量);变量 step 保守按正。 - # 修复 _find_provider 的 range(top-1, -1, -1) 循环体不执行(i < -1 恒假)。 - step_neg_const: int = 0 - if arg_count >= 3: - step_arg_node: ast.AST | t.CPtr = args.get(2) - if step_arg_node is not None: - skn: int = step_arg_node.kind() - if skn == ast.ASTKind.UnaryOp: - uop_r: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(step_arg_node) - if uop_r.op == ast.OpKind.USub and uop_r.operand is not None: - if uop_r.operand.kind() == ast.ASTKind.Constant: - uoc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_r.operand) - if uoc_r.int_val > 0: - step_neg_const = 1 - elif skn == ast.ASTKind.Constant: - skc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(step_arg_node) - if skc_r.int_val < 0: - step_neg_const = 1 - - # 4. 创建/查找循环变量 alloca - var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, var_name) - new_vars: int = 0 - if var_alloca is None: - var_alloca = HandlesVar._alloca_at_entry(builder, i32_ty) - if HandlesVar.define_var( - trans.SymTab, var_name, var_alloca) == 0: - new_vars = 1 - - # 获取循环变量的实际元素类型(alloca 是指针类型,需解引用 Pointee) - # 当循环变量已声明为 i64(如 t.CSizeT),使用 i64 而非硬编码 i32 - # 避免 load i32, i64* / store i32, i64* 类型不匹配 - loop_var_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if var_alloca is not None and var_alloca.Ty is not None: - match var_alloca.Ty: - case llvmlite.LLVMType.Ptr(pointee_ty): - if pointee_ty is not None: - loop_var_ty = pointee_ty - loop_var_bits: int = HandlesExpr.get_llvm_type_bits(loop_var_ty) - - # 5. 存储初始值 (类型对齐: start_val 可能是 i32/i64,需对齐到 loop_var_ty) - init_val: llvmlite.Value | t.CPtr = start_val - if start_val is not None and start_val.Ty is not None: - start_bits: int = HandlesExpr.get_llvm_type_bits(start_val.Ty) - if start_bits != 0 and start_bits != loop_var_bits: - if start_bits < loop_var_bits: - init_val = llvmlite.build_sext(builder, start_val, loop_var_ty) - else: - init_val = llvmlite.build_trunc(builder, start_val, loop_var_ty) - llvmlite.build_store(builder, init_val, var_alloca) - - # 6. 创建基本块: cond / body / incr / end(使用 trans._label_counter,不与 SSA 名共享) - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "for.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "for.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "for.incr.%d", cnt) - incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "for.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # 7. 跳转到 cond 块 - llvmlite.build_br(builder, cond_bb) - - # 8. cond 块: load i, icmp slt i, stop, cond_br body/end - llvmlite.position_at_end(builder, cond_bb) - cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca) - # 类型对齐: stop_val 可能是 i64 (如 range(strlen(s))),需将 cur_i 提升到 stop_val 类型 - cmp_lhs: llvmlite.Value | t.CPtr = cur_i - cmp_rhs: llvmlite.Value | t.CPtr = stop_val - if stop_val is not None and stop_val.Ty is not None: - stop_bits: int = HandlesExpr.get_llvm_type_bits(stop_val.Ty) - cur_bits: int = HandlesExpr.get_llvm_type_bits(cur_i.Ty) - if stop_bits != 0 and cur_bits != 0 and stop_bits != cur_bits: - if cur_bits < stop_bits: - cmp_lhs = llvmlite.build_sext(builder, cur_i, stop_val.Ty) - else: - # 循环变量位宽 > stop 位宽(如 t.CSizeT 循环变量 + range(i32)): - # 应把 cur_i 截断到 stop_val 类型(低向高才 sext/zext,高向低用 - # trunc)。原实现反了——把小的 stop_val trunc 到大的 loop_var_ty, - # 生成 `trunc i32 to i64` 扩宽非法 IR,llc 报 - # "invalid cast opcode for cast from 'i32' to 'i64'" - # (VpiReader.vp range(arg_count) 追加86 根因)。 - cmp_lhs = llvmlite.build_trunc(builder, cur_i, stop_val.Ty) - # step 为负时条件反转:i > stop(ICMP_SGT);正/缺省 step 保持 i < stop - range_cmp_op: int = llvmlite.ICMP_SLT - if step_neg_const != 0: - range_cmp_op = llvmlite.ICMP_SGT - cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, range_cmp_op, cmp_lhs, cmp_rhs) - llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb) - - # 9. body 块: 翻译循环体,跳到 incr - llvmlite.position_at_end(builder, body_bb) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = incr_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - # 恢复旧循环上下文 - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, incr_bb) - - # 10. incr 块: i = i + step, 跳回 cond - llvmlite.position_at_end(builder, incr_bb) - cur_i2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca) - # 类型对齐: step_val 可能是 i32/i64,需对齐到 loop_var_ty 与 cur_i2 类型一致 - incr_step: llvmlite.Value | t.CPtr = step_val - if step_val is not None and step_val.Ty is not None: - step_bits: int = HandlesExpr.get_llvm_type_bits(step_val.Ty) - cur2_bits: int = HandlesExpr.get_llvm_type_bits(cur_i2.Ty) - if step_bits != 0 and cur2_bits != 0 and step_bits != cur2_bits: - if step_bits > cur2_bits: - incr_step = llvmlite.build_trunc(builder, step_val, loop_var_ty) - else: - incr_step = llvmlite.build_sext(builder, step_val, loop_var_ty) - next_i: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_i2, incr_step) - llvmlite.build_store(builder, next_i, var_alloca) - llvmlite.build_br(builder, cond_bb) - - # 11. 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - return new_vars - - - - - # ============================================================ -# NewForHandle - 工厂函数(委托到 gen.NewForHandle) +# translate_for - for 循环语句翻译(委托到 gen.translate_for) # ============================================================ -def NewForHandle(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> ForHandle | t.CPtr: - """创建 ForHandle 实例(委托到 gen.NewForHandle)""" +def translate_for(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 for 循环语句(委托到 gen.translate_for)""" g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) if g is not None: - return g.NewForHandle(pool, trans) - return None + return g.translate_for(trans, node) + return 0 diff --git a/App/lib/core/Handles/HandlesIf.vp b/App/lib/core/Handles/HandlesIf.vp index 700d5bc..e6f3ed7 100644 --- a/App/lib/core/Handles/HandlesIf.vp +++ b/App/lib/core/Handles/HandlesIf.vp @@ -1,345 +1,42 @@ import t, c from stdint import * import ast -import llvmlite import memhub -import string -import stdio -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.HandlesType as HandlesType -import lib.core.Handles.HandlesImports as HandlesImports -import lib.Projectrans.Config as Config import lib.core.Gen.Generator as Generator # ============================================================ -# HandlesIf - if/elif/else 语句处理(P6 对象化后的委托层) +# HandlesIf - if/elif/else 语句处理(迁移完成,保留跨 Mixin 委托壳) # -# 编译期 CIf 求值的模块级函数(_is_cif_attr/_is_cif_call/ -# _get_platform_macro_value/_cif_name_value/_cif_attr_value/ -# _cif_eval_node/_evaluate_cif_test)已迁移为 lib.core.Gen. -# StmtGenMixin 的方法(_g_cif_eval_ok → gen 实例字段 CifEvalOk), -# 本模块保留同名模块级函数作为"一行委托";模块级 _g_cif_eval_ok -# 保留为镜像,委托后同步 gen.CifEvalOk(IfHandle.Handle 直接读它)。 -# -# IfHandle 类(trans.IfH 的类型)保留:由 HandlesTranslator. -# _init_state 通过 NewIfHandle 工厂创建,Handle 方法内部经模块级 -# 委托函数访问 gen。 +# P6 机械化迁移:IfHandle 类 → StmtGenCifMixin.translate_if。 +# CIf 编译期求值(_is_cif_attr/_is_cif_call/_get_platform_macro_value/ +# _cif_name_value/_cif_attr_value/_cif_eval_node/_evaluate_cif_test 及 +# 模块级 _g_cif_eval_ok)已迁移为 StmtGenCifMixin 的方法/字段 +# (CifEvalOk)。 +# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下 +# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。 +# 迁移收尾(编译器缺陷修复)后统一删除。 # ============================================================ -# 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...) -# -# 对齐 TPC HandlesIf.py:编译期求值命中分支并剪枝(不发射运行时 IR)。 -# c.CIf(expr) → 常量表达式求值(CDefine/平台宏/算术/比较/逻辑) -# c.CIfdef(NAME) → NAME 已定义?(本地 CDefine / 跨模块 CDefine / 平台宏) -# c.CIfndef(NAME) → NAME 未定义? ← 未定义名特判:返回"未定义"而非报错 -# -# 求值失败(如运行时变量 val == 1)→ 回退运行时翻译 -# (c.CIf 由 HandlesExprCall.translate_call 特判翻译成运行时真值, -# c.CIfdef/c.CIfndef 运行时恒真,对齐 TPC HandlesExprCall.py L2434-2446)。 - -_g_cif_eval_ok: int = 0 # ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式) +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) +# +# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 +# 委托函数用本地 _g_gen(cast 成 Generator 类型)调 +# StmtGenCifMixin 方法,避免函数体 import 包模块与类/模块名歧义。 # ============================================================ _g_gen: Generator.Generator | t.CPtr = None -def _is_cif_attr(attr: str) -> int: - """检查方法名是否为 CIf 系(CIf/CIfdef/CIfndef)(委托到 gen._is_cif_attr)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_cif_attr(attr) - return 0 - - -def _is_cif_call(node: ast.AST | t.CPtr) -> int: - """检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用(委托到 gen._is_cif_call)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g._is_cif_call(node) - return 0 - - -def _get_platform_macro_value(name: str) -> int: - """平台内置宏值(从目标三元组推导,对齐 TPC HandlesIf._get_platform_macros)。 - - 命中置 _g_cif_eval_ok=1;未命中置 0 返回 0(委托到 gen._get_platform_macro_value)。 - """ - global _g_cif_eval_ok - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - v: int = g._get_platform_macro_value(name) - _g_cif_eval_ok = g.CifEvalOk - return v - return 0 - - -def _cif_name_value(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - name: str) -> int: - """查宏名值: 本地 CDefine → 跨模块 CDefine → 平台宏。 - - 命中置 _g_cif_eval_ok=1(值 0 也算命中,如 DISABLED=0);未命中置 0(委托到 gen._cif_name_value)。 - """ - global _g_cif_eval_ok - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - v: int = g._cif_name_value(pool, trans, name) - _g_cif_eval_ok = g.CifEvalOk - return v - return 0 - - -def _cif_attr_value(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - at: ast.Attribute | t.CPtr) -> int: - """Attribute 宏值: platmacro.IS_WINDOWS → 本地 CDefine(attr) → 跨模块 CDefine。 - - 命中置 _g_cif_eval_ok=1;未命中置 0(委托到 gen._cif_attr_value)。 - """ - global _g_cif_eval_ok - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - v: int = g._cif_attr_value(pool, trans, at) - _g_cif_eval_ok = g.CifEvalOk - return v - return 0 - - -def _cif_eval_node(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - node: ast.AST | t.CPtr) -> int: - """递归常量求值 CIf 表达式。 - - 支持: Constant(int) / Name(CDefine/跨模块/平台宏) / Attribute(跨模块 CDefine) - / BinOp(+ - * // % & | ^ << >>) / Compare(== != < > <= >=) - / BoolOp(and/or) / UnaryOp(not - + ~)。 - 成功置 _g_cif_eval_ok=1;失败(含运行时变量)置 0 返回 0(委托到 gen._cif_eval_node)。 - """ - global _g_cif_eval_ok - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - v: int = g._cif_eval_node(pool, trans, node) - _g_cif_eval_ok = g.CifEvalOk - return v - return 0 - - -def _evaluate_cif_test(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - test: ast.AST | t.CPtr) -> int: - """求值 CIf 调用(test 必须是 c.CIf 系调用)。 - - 成功: 置 _g_cif_eval_ok=1,返回条件值(0/1) - 失败(运行时变量/未知结构): 置 _g_cif_eval_ok=0,返回 0(委托到 gen._evaluate_cif_test)。 - """ - global _g_cif_eval_ok - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - v: int = g._evaluate_cif_test(pool, trans, test) - _g_cif_eval_ok = g.CifEvalOk - return v - return 0 - - # ============================================================ -# HandlesIf - if/elif/else 语句处理(Mixin 继承模式) -# -# 翻译 if 语句为 LLVM IR 控制流: -# br i1 %cond, label %then, label %else -# then: -# ... body ... -# br label %end -# else: -# ... orelse ... -# br label %end -# end: +# translate_if - if/elif/else 语句翻译(委托到 gen.translate_if) # ============================================================ - - -@t.NoVTable -class IfHandle(HandlesBase.Mixin): - """if/elif/else 语句处理器:继承 Mixin 获得 Trans 回指针""" - - def __init__(self, trans: HT.Translator | t.CPtr): - self.Trans = trans - - # ============================================================ - # Handle - 处理 if 语句,返回新增变量数 - # ============================================================ - def Handle(self, node: ast.AST | t.CPtr) -> int: - """翻译 if/elif/else 语句""" - 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 - - if_node: ast.If | t.CPtr = (ast.If | t.CPtr)(node) - - # 0. 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...) - # 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归 - # 求值失败(运行时变量等)→ 回退运行时翻译 - if _is_cif_call(if_node.test) == 1: - cif_val: int = _evaluate_cif_test(pool, trans, if_node.test) - if _g_cif_eval_ok != 0: - if cif_val != 0: - body_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.children - if body_cif is not None: - bc_cif: t.CSizeT = len(body_cif) - bi_cif: t.CSizeT - for bi_cif in range(bc_cif): - stmt_cif: ast.AST | t.CPtr = body_cif.get(bi_cif) - if stmt_cif is not None: - HandlesBody.translate_stmt(trans, stmt_cif) - else: - orelse_cif: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse - if orelse_cif is not None and len(orelse_cif) == 1: - sub_cif: ast.AST | t.CPtr = orelse_cif.get(0) - if sub_cif is not None and sub_cif.kind() == ast.ASTKind.If: - # elif: 递归(子 If 的 test 仍会走 CIf 判定或运行时翻译) - self.Handle(sub_cif) - elif sub_cif is not None: - HandlesBody.translate_stmt(trans, sub_cif) - elif orelse_cif is not None: - oc_cif: t.CSizeT = len(orelse_cif) - oi_cif: t.CSizeT - for oi_cif in range(oc_cif): - stmt_cif2: ast.AST | t.CPtr = orelse_cif.get(oi_cif) - if stmt_cif2 is not None: - HandlesBody.translate_stmt(trans, stmt_cif2) - return 0 - - # 1. 求值条件表达式 - cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, if_node.test, - trans._funcs, trans._func_count, trans) - - # 2. 转换为 i1 条件 - # Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较 - if cond_val is None: - # fail-fast: if 条件表达式翻译失败 - HandlesType.fatal_error(if_node.test, "if 条件表达式翻译失败", "TypeError") - cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty) - if cond_bits == 1: - cond_i1: llvmlite.Value | t.CPtr = cond_val - elif HandlesExpr.is_ptr_type(cond_val.Ty) != 0: - # 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type") - null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null") - cond_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cond_val, null_cond) - else: - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - cond_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cond_val, zero) - - # 3. 创建基本块(使用 trans._label_counter 生成唯一标签名,不与 SSA 名共享) - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "if.then.%d", cnt) - then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "if.end.%d", cnt) - merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # 检查是否有 else 分支 - has_else: int = 0 - orelse_list: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse - if orelse_list is not None: - if len(orelse_list) > 0: - has_else = 1 - - else_bb: llvmlite.BasicBlock | t.CPtr = None - if has_else == 1: - viperlib.snprintf(name_buf, 32, "if.else.%d", cnt) - else_bb = llvmlite.create_block(pool, func, name_buf) - - # 4. 发射条件分支 - if has_else == 1: - llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb) - else: - llvmlite.build_cond_br(builder, cond_i1, then_bb, merge_bb) - - # 5. 翻译 then body - # 重置 merge 可达标志:分支内嵌套控制流会覆盖该标志,分支末尾判定依据 - # "分支最后语句的控制流状态",须防进入本 If 前的残留值污染(append90 - # 末句 If 全 return 被 fail-fast 误判"流程掉出末尾"的根因链一环) - trans._ctrl_merge_reachable = 1 - llvmlite.position_at_end(builder, then_bb) - body: list[ast.AST | t.CPtr] | t.CPtr = if_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - # then 块未终止则跳到 merge(记录 then 是否 br 到 merge) - then_branches_merge: int = 0 - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - if trans._ctrl_merge_reachable == 0: - # 分支末尾是嵌套控制流且 merge 结构性不可达(全分支 return): - # 当前块是嵌套的 merge(无 terminator),补 unreachable 收尾。 - # 不补 br merge——否则外层 If 的"分支是否 br merge"判定把不可达 - # 分支当可达,函数末句 If 全 return 被误判"流程掉出末尾" - # (vipermath.vp atan2 根因;对齐 FuncGenDef append90 unreachable) - llvmlite.build_unreachable(builder) - else: - llvmlite.build_br(builder, merge_bb) - then_branches_merge = 1 - - # 6. 翻译 else body(若有) - else_branches_merge: int = 0 - if has_else == 1: - # 同 then:重置标志防残留(else 是普通语句时不被 then 的嵌套控制流值污染) - trans._ctrl_merge_reachable = 1 - llvmlite.position_at_end(builder, else_bb) - else_count: t.CSizeT = len(orelse_list) - for ei in range(else_count): - stmt: ast.AST | t.CPtr = orelse_list.get(ei) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - if trans._ctrl_merge_reachable == 0: - # 嵌套控制流全分支 return:补 unreachable,不 br merge(同 then 分支) - llvmlite.build_unreachable(builder) - else: - llvmlite.build_br(builder, merge_bb) - else_branches_merge = 1 - - # 7. merge 块可达性(追加90,末句控制流收尾判定用): - # 无 else 时 cond_br 直接跳 merge(恒可达);有 else 时任一分支 - # br 到 merge 即可达;全分支 return(无 br)才结构性不可达。 - # 经 HandlesBase 模块级全局传递(避免依赖 Translator 字段表) - trans._ctrl_merge_reachable = 1 - if has_else == 1 and then_branches_merge == 0 and else_branches_merge == 0: - trans._ctrl_merge_reachable = 0 - - # 8. 定位到 merge 块继续后续代码 - llvmlite.position_at_end(builder, merge_bb) - return 0 - - -# ============================================================ -# NewIfHandle - 工厂函数(委托到 gen.NewIfHandle) -# ============================================================ -def NewIfHandle(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> IfHandle | t.CPtr: - """创建 IfHandle 实例(委托到 gen.NewIfHandle)""" +def translate_if(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 if/elif/else 语句(委托到 gen.translate_if)""" g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) if g is not None: - return g.NewIfHandle(pool, trans) - return None + return g.translate_if(trans, node) + return 0 diff --git a/App/lib/core/Handles/HandlesImports.vp b/App/lib/core/Handles/HandlesImports.vp index affb516..b00bd48 100644 --- a/App/lib/core/Handles/HandlesImports.vp +++ b/App/lib/core/Handles/HandlesImports.vp @@ -28,8 +28,10 @@ import lib.core.Gen.Generator as Generator # 保留同名模块级函数作为"一行委托":延迟 import Gen 取全局单例 # (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen 的 # 对应方法。签名与旧函数完全一致,调用方零改动。 -# ImportsHandle 类与 NewImportsHandle 工厂保留在本模块(对象工厂, -# 不依赖 gen 状态,与 HandlesExpr.NewExprHandle 模式一致)。 +# ImportsHandle 类与 NewImportsHandle 工厂已删除(P6 机械化迁移: +# HandleImport/HandleImportFromModule/HandleImportFromNames → 本模块 +# 新增的 translate_import/translate_import_from_module/ +# translate_import_from_names 模块级委托壳,路由到 gen 方法)。 # ============================================================ MAX_REEXPORT: t.CDefine = 512 @@ -287,137 +289,38 @@ def _check_import_sha1(node: ast.AST | t.CPtr, mod_name: str) -> int: # ============================================================ -# ImportsHandle - 导入语句处理器(Mixin 继承模式) -# -# 方法版本:直接更新 trans._imported_modules / trans._from_imports -# (内部调用的模块级工具函数经上方委托函数路由到 gen 方法) +# translate_import - 处理 import 语句(委托到 gen.translate_import) # ============================================================ -@t.NoVTable -class ImportsHandle(HandlesBase.Mixin): - """导入语句处理器:继承 Mixin 获得 Trans 回指针""" - - def __init__(self, trans: HT.Translator | t.CPtr): - self.Trans = trans - - # ============================================================ - # HandleImport - 处理 import 语句,更新 trans._imported_modules - # ============================================================ - def HandleImport(self, node: ast.AST | t.CPtr) -> int: - """处理 import 语句,返回 0""" - imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(node) - if imp is None: - return 0 - names: list[ast.AST | t.CPtr] | t.CPtr = imp.names - if names is None: - return 0 - nn: t.CSizeT = len(names) - for ni in range(nn): - alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) - if alias is not None and alias.name is not None: - # 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查) - # declare_only=1/2 是 struct 预注册/import 扫描阶段:此时 SHA1 表 - # 尚未包含后续才追加的模块(如 App 源文件),检查会造成误报 - if self.Trans._declare_only == 0: - _check_import_sha1(node, alias.name) - pool_val: memhub.MemBuddy | t.CPtr = self.Trans.Pool - im_val: str = self.Trans._imported_modules - self.Trans._imported_modules = add_imported_module( - pool_val, im_val, alias.name) - # 别名也加入导入模块列表(用于模块限定构造器检查 Module.Class()) - if alias.asname is not None: - self.Trans._imported_modules = add_imported_module( - pool_val, self.Trans._imported_modules, alias.asname) - # 别名也加入 from_imports(asname:fullname), - # 使 HT.func() 跨模块调用能通过 from_imports 查找别名→完整模块名→SHA1 - # 否则 _lookup_module_sha1("HT") 找不到(mod_arr 只存文件名 HandlesTranslator) - self.Trans._from_imports = add_from_import( - pool_val, self.Trans._from_imports, alias.asname, alias.name) - else: - # 无别名时(import a.b.c),将顶层包名 "a" 也加入 _imported_modules, - # 使 a.b.c 作为属性访问的 base 被翻译时能通过 is_module_imported("a") 检查 - dot_ptr: str = string.strstr(alias.name, '.') - if dot_ptr is not None: - pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_ptr) - t.CUInt64T(alias.name)) - if pkg_len > 0 and pkg_len < 256: - pkg_buf: bytes = pool_val.alloc(pkg_len + 1) - if pkg_buf is not None: - string.strncpy(pkg_buf, alias.name, pkg_len) - pkg_buf[pkg_len] = '\0' - self.Trans._imported_modules = add_imported_module( - pool_val, self.Trans._imported_modules, pkg_buf) - return 0 - - # ============================================================ - # HandleImportFromModule - 处理 from X import Y 的模块部分 - # - # 对相对导入(level > 0),使用 trans.CurrentPackage 解析为 - # 完整模块名(如 __types → llvmlite.__types),确保 .deps.txt - # 记录的模块名与 SHA1 映射表一致。 - # ============================================================ - def HandleImportFromModule(self, node: ast.AST | t.CPtr) -> int: - """处理 from X import Y 的模块部分,更新 trans._imported_modules""" - impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node) - if impf is None: - return 0 - # 解析模块名:相对导入需补充包前缀 - resolved: str = _resolve_relative_module( - self.Trans.Pool, self.Trans.CurrentPackage, - impf.level, impf.module) - if resolved is not None: - # 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查) - if self.Trans._declare_only == 0: - _check_import_sha1(node, resolved) - self.Trans._imported_modules = add_imported_module( - self.Trans.Pool, self.Trans._imported_modules, resolved) - return 0 - - # ============================================================ - # HandleImportFromNames - 处理 from X import Y 的名称部分 - # - # 同样使用解析后的完整模块名,确保 from-import 映射 - # (如 LLVMType:llvmlite.__types)能正确查到 SHA1。 - # ============================================================ - def HandleImportFromNames(self, node: ast.AST | t.CPtr) -> int: - """处理 from X import Y 的名称部分,更新 trans._from_imports""" - impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node) - if impf is None: - return 0 - # 解析模块名:相对导入需补充包前缀 - resolved: str = _resolve_relative_module( - self.Trans.Pool, self.Trans.CurrentPackage, - impf.level, impf.module) - if resolved is not None: - names: list[ast.AST | t.CPtr] | t.CPtr = impf.names - if names is not None: - nn: t.CSizeT = len(names) - for ni in range(nn): - alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni)) - if alias is not None and alias.name is not None: - local_name: str = alias.name - orig_name: str = None - if alias.asname is not None: - local_name = alias.asname - orig_name = alias.name - self.Trans._from_imports = add_from_import( - self.Trans.Pool, self.Trans._from_imports, - local_name, resolved, orig_name) - # 命名空间隔离:from-import 的名称标记为可见结构体 - HandlesStruct.add_visible_struct(self.Trans.Pool, local_name) - # 注册 re-export 映射:当前模块 re-export 了 local_name,源模块为 resolved - # 使跨模块调用 module.func() 能解析到正确的源模块 SHA1 - if self.Trans.ModuleSha1 is not None: - register_reexport(self.Trans.ModuleSha1, local_name, resolved) - return 0 +def translate_import(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """处理 import 语句,返回 0(委托到 gen.translate_import)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_import(trans, node) + return 0 # ============================================================ -# NewImportsHandle - 工厂函数 +# translate_import_from_module - 处理 from X import Y 的模块部分 +# (委托到 gen.translate_import_from_module) # ============================================================ -def NewImportsHandle(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> ImportsHandle | t.CPtr: - h: ImportsHandle | t.CPtr = pool.alloc(ImportsHandle.__sizeof__()) - if h is None: - return None - string.memset(h, 0, ImportsHandle.__sizeof__()) - h.Trans = trans - return h +def translate_import_from_module(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """处理 from X import Y 的模块部分(委托到 gen.translate_import_from_module)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_import_from_module(trans, node) + return 0 + + +# ============================================================ +# translate_import_from_names - 处理 from X import Y 的名称部分 +# (委托到 gen.translate_import_from_names) +# ============================================================ +def translate_import_from_names(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """处理 from X import Y 的名称部分(委托到 gen.translate_import_from_names)""" + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_import_from_names(trans, node) + return 0 diff --git a/App/lib/core/Handles/HandlesMatch.vp b/App/lib/core/Handles/HandlesMatch.vp index 74dbe0e..3103b1f 100644 --- a/App/lib/core/Handles/HandlesMatch.vp +++ b/App/lib/core/Handles/HandlesMatch.vp @@ -19,9 +19,15 @@ import lib.core.Gen.Generator as Generator # ============================================================ # HandlesMatch - match 语句处理(P6 对象化后的委托层) # -# NewMatchHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法 -# (MatchHandle 类保留:trans.MatchH 的类型,由 HandlesTranslator. -# _init_state 经 NewMatchHandle 委托创建)。 +# P6 机械化迁移:MatchHandle 类 → lib.core.Gen.MatchGenMixin +# (Handle → translate_match,方法体 self.Trans → trans 首参; +# 类内辅助方法 + 模块级 _case_tail_unreachable 一并搬入成方法)。 +# 本模块保留同名模块级函数作为"一行委托":延迟 import Gen 取全局单例 +# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen 的 +# 对应方法。签名与旧函数完全一致,调用方零改动。 +# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下 +# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。 +# 迁移收尾(编译器缺陷修复)后统一删除。 # # 逻辑移植自 TPC 的 HandlesMatch.py,用 Viper 语法重写。 # 两条路径: @@ -46,1290 +52,23 @@ SCOPE_MATCH: t.CDefine = 6 # ============================================================ -# _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, -# 避免残留值误判。 -# ============================================================ -def _case_tail_unreachable(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 - - -# ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式) +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) # # 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 -# 委托函数用本地 _g_gen(cast 成 Generator 类型)调 -# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。 +# P6 委托函数用本地 _g_gen(cast 成 Generator 类型)调 +# MatchGenMixin 方法,避免函数体 import 包模块与 Generator +# 类/模块名歧义。 # ============================================================ _g_gen: Generator.Generator | t.CPtr = None -@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 - - # 追加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(m_node, subject_node) - 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: - # fail-fast: match subject 翻译失败 - HandlesType.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: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if entry is not None and entry.AnnotClassName is not None \ - and HandlesClassDef._is_renum_class_name( - entry.AnnotClassName) != 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 = 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 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 类名 - # - # 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 HandlesClassDef._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, 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 - # 局部记录本 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 HandlesExpr.is_ptr_type(subj_ty) != 0 \ - and subj_ty.Pointee is not None \ - and HandlesExpr.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 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: - # fail-fast: REnum 结构体未注册,无法构造 - HandlesType.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 HandlesExpr.get_llvm_type_bits(subj_ty) != 64 \ - and 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: - # fail-fast: REnum tag 指针转换失败 - HandlesType.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 读取失败 - HandlesType.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: 标签缓冲区分配失败 - HandlesType.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 缺失 - HandlesType.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 分派数组分配失败 - HandlesType.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 = HandlesClassDef._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 = 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 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 = 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 \ - 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: - HandlesBody.translate_stmt(trans, stmt) - bi = bi + 1 - - # 退出 case 作用域 - HandlesVar.exit_scope(trans.SymTab) - - # 若未终止且无 NoBreak,跳到 end - # 末句控制流全 return(结构性不可达)时补 unreachable,不 br end_bb - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and nb == 0 \ - and _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) - HandlesVar.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: - HandlesBody.translate_stmt(trans, stmt) - dj = dj + 1 - HandlesVar.exit_scope(trans.SymTab) - break - di = di + 1 - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and _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: 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 = 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 = HandlesClassDef._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) - HandlesType.fatal_error( - sub_pat, - f"REnum 变体字段 '{bind_name}' 在结构体 '{renum_name}' 中越界且别名查找失败", - "TypeError") - # 获取字段类型 - 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: - # fail-fast: 变体字段类型缺失,禁止兜底 i8 - HandlesType.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: 变体字段地址计算失败 - HandlesType.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 = HandlesClassDef._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 - HandlesVar.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, 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 = self.Trans.Pool - if HandlesExpr.is_ptr_type(lhs.Ty) != 0 \ - or HandlesExpr.is_ptr_type(rhs.Ty) != 0: - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - if HandlesExpr.is_ptr_type(lhs.Ty) != 0: - lhs = llvmlite.build_ptrtoint(builder, lhs, i64_ty) - if HandlesExpr.is_ptr_type(rhs.Ty) != 0: - rhs = llvmlite.build_ptrtoint(builder, rhs, i64_ty) - lb: int = HandlesExpr.get_llvm_type_bits(lhs.Ty) - rb: int = HandlesExpr.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, node: ast.Match | t.CPtr, - subject_node: ast.AST | 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 - 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 = HandlesExpr.translate_value( - builder, pool, trans.Module, elt, - trans._funcs, trans._func_count, trans) - if sv is None: - HandlesType.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 / 顶层 _ 通配 - HandlesType.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 = HandlesExpr.translate_value( - builder, pool, trans.Module, mv.value, - trans._funcs, trans._func_count, trans) - if pv is None: - HandlesType.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( - builder, sv1, pv) - if c1 is None: - HandlesType.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:序列模式变量绑定暂不支持 - HandlesType.fatal_error( - pat1, "序列模式变量绑定暂不支持", "NotImplementedError") - elif pk1 == ast.ASTKind.MatchStar: - continue # 剩余元素通配:恒真 - else: - HandlesType.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 = HandlesExpr.translate_value( - builder, pool, trans.Module, gnode, - trans._funcs, trans._func_count, trans) - if gv is None: - HandlesType.fatal_error( - gnode, "match guard 翻译失败", "TypeError") - gbits: int = HandlesExpr.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) - HandlesVar.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: - HandlesBody.translate_stmt(trans, stmt) - bi = bi + 1 - HandlesVar.exit_scope(trans.SymTab) - # 末句控制流全 return → 补 unreachable(不 br end,无 fallthrough) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and _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) - HandlesVar.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: - HandlesBody.translate_stmt(trans, stmt) - dj = dj + 1 - HandlesVar.exit_scope(trans.SymTab) - break - di = di + 1 - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and _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, 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 - # 同主路径:局部记录本 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 = 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: - # fail-fast: subject 转 i32 失败 - HandlesType.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: 标签缓冲区分配失败 - HandlesType.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 缺失 - HandlesType.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 分派数组分配失败 - HandlesType.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 = 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 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 = 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 = len(body_list) - 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) - - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and nb == 0 \ - and _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) - HandlesVar.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: - HandlesBody.translate_stmt(trans, stmt) - dj = dj + 1 - HandlesVar.exit_scope(trans.SymTab) - break - di = di + 1 - # 末句控制流全 return → 补 unreachable(不 br end_bb) - if llvmlite.builder_cur_block_is_terminated(builder) == 0 \ - and _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 - - # ============================================================ -# NewMatchHandle - 工厂函数(委托到 gen.NewMatchHandle) +# translate_match - match 语句翻译(委托到 gen.translate_match) # ============================================================ -def NewMatchHandle(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> MatchHandle | t.CPtr: - """创建 MatchHandle 实例(委托到 gen.NewMatchHandle)""" +def translate_match(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 match 语句,返回 0(委托到 gen.translate_match)""" g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) if g is not None: - return g.NewMatchHandle(pool, trans) - return None + return g.translate_match(trans, node) + return 0 diff --git a/App/lib/core/Handles/HandlesReturn.vp b/App/lib/core/Handles/HandlesReturn.vp index 62a0043..fbd56dd 100644 --- a/App/lib/core/Handles/HandlesReturn.vp +++ b/App/lib/core/Handles/HandlesReturn.vp @@ -1,227 +1,18 @@ import t, c from stdint import * -import ast -import llvmlite -import memhub -import string -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.HandlesVar as HandlesVar -import lib.core.Handles.HandlesType as HandlesType import lib.core.Gen.Generator as Generator + # ============================================================ -# HandlesReturn - Return 语句处理(P6 对象化后的委托层) +# HandlesReturn - Return 语句处理(迁移完成) # -# NewReturnHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法 -# (ReturnHandle 类保留:trans.ReturnH 的类型,由 HandlesTranslator. -# _init_state 经 NewReturnHandle 委托创建)。 +# P6 机械化迁移:ReturnHandle 类 → StmtGenCifMixin.translate_return +# (lib.core.Gen.StmtGenCifMixin)。本文件保留模块级 _g_gen 单例 +# (main.vp / BuildPipeline.vp 注入),迁移收尾后统一删除。 # ============================================================ # ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式) +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) # ============================================================ _g_gen: Generator.Generator | t.CPtr = None - - -@t.NoVTable -class ReturnHandle(HandlesBase.Mixin): - """Return 语句处理器:继承 Mixin 获得 Trans 回指针""" - - def __init__(self, trans: HT.Translator | t.CPtr): - self.Trans = trans - - # ============================================================ - # Handle - 处理 Return 语句,返回 0 - # - # 翻译返回值(若有)并生成 ret 指令 - # ============================================================ - def Handle(self, node: ast.AST | t.CPtr) -> int: - """翻译 Return 语句""" - rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node) - if rt is None: - return 0 - - pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool - builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder - mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module - - val: llvmlite.Value | t.CPtr = None - if rt.value is not None: - # return a, b → 打包匿名 struct 值(多返回值,函数返回类型 tuple[T1,T2]) - if rt.value.kind() == ast.ASTKind.Tuple: - rtp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(rt.value) - rtp_elts: list[ast.AST | t.CPtr] | t.CPtr = rtp.elts - rt_n: t.CSizeT = 0 - if rtp_elts is not None: - rt_n = len(rtp_elts) - if rt_n > 0 and rt_n <= 16: - rt_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 16) - if rt_vals is not None: - rt_val_ok: int = 1 - rt_head: llvmlite.ParamNode | t.CPtr = None - rt_tail: llvmlite.ParamNode | t.CPtr = None - rvi: t.CSizeT - for rvi in range(rt_n): - ev_i: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, rtp_elts.get(rvi), - self.Trans._funcs, self.Trans._func_count, self.Trans) - if ev_i is None: - rt_val_ok = 0 - break - rt_vals[rvi] = t.CSizeT(ev_i) - if rt_val_ok != 0: - # 构建匿名 struct 类型(字段类型 = 元素值类型) - rvi2: t.CSizeT - for rvi2 in range(rt_n): - rv_i: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)( - t.CVoid(rt_vals[rvi2], t.CPtr)) - if rv_i is None or rv_i.Ty is None: - rt_val_ok = 0 - break - rn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, rv_i.Ty) - if rn is None: - rt_val_ok = 0 - break - if rt_head is None: - rt_head = rn - else: - llvmlite.paramnode_set_next(rt_tail, rn) - rt_tail = rn - rt_struct_ty: llvmlite.LLVMType | t.CPtr = None - if rt_val_ok != 0 and rt_head is not None: - rt_struct_ty = llvmlite.Struct(pool, rt_head, rt_n, None) - rt_tmp: llvmlite.Value | t.CPtr = None - if rt_struct_ty is not None: - rt_tmp = llvmlite.build_alloca(builder, rt_struct_ty) - if rt_tmp is not None: - rvi3: t.CSizeT - for rvi3 in range(rt_n): - rv3: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)( - t.CVoid(rt_vals[rvi3], t.CPtr)) - rfp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, rt_struct_ty, rv3.Ty, rt_tmp, rvi3) - if rfp is None: - rt_val_ok = 0 - break - llvmlite.build_store(builder, rv3, rfp) - if rt_val_ok != 0: - val = llvmlite.build_load(builder, rt_struct_ty, rt_tmp) - # return self: 返回 self 指针本身(Ptr(StructTy)),而非结构体值 - # translate_value 会 load 得到结构体值,但 return self 需要指针 - # 注意: lookup_var 返回的是存储 self 的 alloca (Ptr(Ptr(StructTy))) - # 需要 load 得到实际的 self 指针 (Ptr(StructTy)) - if rt.value.kind() == ast.ASTKind.Name: - ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rt.value) - if ret_nm is not None and ret_nm.id is not None \ - and string.strcmp(ret_nm.id, "self") == 0: - self_ptr: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - self.Trans.SymTab, "self") - if self_ptr is not None: - # 检查 self_ptr 是否是 Ptr(Ptr(...))(alloca 存储指针) - self_pointee_ty: llvmlite.LLVMType | t.CPtr = None - match self_ptr.Ty: - case llvmlite.LLVMType.Ptr(inner_ty): - self_pointee_ty = inner_ty - if self_pointee_ty is not None and HandlesExpr.is_ptr_type(self_pointee_ty) != 0: - # Ptr(Ptr(StructTy)) → load 得到 Ptr(StructTy) - val = llvmlite.build_load(builder, self_pointee_ty, self_ptr) - else: - val = self_ptr - if val is None: - val = HandlesExpr.translate_value( - builder, pool, mod, rt.value, - self.Trans._funcs, self.Trans._func_count, self.Trans) - - # val 为 None 时(裸 return):检查当前函数返回类型 - # void 函数(如 __init__/__before_init__)生成 ret void, - # ptr 函数生成 ret ptr null,浮点函数生成 ConstFloat(0.0), - # 否则 ret i32 0(浮点漏处理会报 llc: value doesn't match function result type) - if val is None: - cur_func: llvmlite.Function | t.CPtr = self.Trans._cur_func - is_void_ret: int = 0 - is_ptr_ret: int = 0 - is_float_ret: int = 0 - ret_ty: llvmlite.LLVMType | t.CPtr = None - if cur_func is not None: - ret_ty = llvmlite.function_get_ret_ty(cur_func) - if ret_ty is not None: - match ret_ty: - case llvmlite.LLVMType.Void(): - is_void_ret = 1 - case llvmlite.LLVMType.Ptr(_pe): - is_ptr_ret = 1 - case llvmlite.LLVMType.Float(_fb): - is_float_ret = 1 - if is_void_ret != 0: - llvmlite.build_ret_void(builder) - return 0 - if is_ptr_ret != 0: - null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null") - llvmlite.build_ret(builder, null_val) - return 0 - if is_float_ret != 0: - zero_f: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, ret_ty, 0.0) - llvmlite.build_ret(builder, zero_f) - return 0 - if ret_ty is None: - # fail-fast: 裸 return 无法确定函数返回类型,禁止硬编码 i32 零值兜底 - HandlesType.fatal_error(rt, "函数返回类型无法确定", "TypeError") - val = llvmlite.ConstZero(pool, ret_ty) - if val is None: - # fail-fast: 无法按返回类型构造零值 - HandlesType.fatal_error(rt, "函数返回类型无法确定", "TypeError") - - # 类型转换:确保 val 类型与函数返回类型匹配 - # 处理 i1(bool 比较结果)→ i8(t.CBool)等情况 - # i1 → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF) - # 注意:当 val 是整数而 ret_ty 是 ptr 时(即使 bits 相同,如 i64 vs ptr), - # 也必须 inttoptr 转换,否则 llc 报 "value doesn't match function result type" - cur_func_rt: llvmlite.Function | t.CPtr = self.Trans._cur_func - ret_ty_rt: llvmlite.LLVMType | t.CPtr = None - if cur_func_rt is not None and val is not None and val.Ty is not None: - ret_ty_rt = llvmlite.function_get_ret_ty(cur_func_rt) - if ret_ty_rt is not None: - val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty) - ret_bits: int = HandlesExpr.get_llvm_type_bits(ret_ty_rt) - val_is_ptr: int = HandlesExpr.is_ptr_type(val.Ty) - ret_is_ptr: int = HandlesExpr.is_ptr_type(ret_ty_rt) - # ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换 - if val_is_ptr != ret_is_ptr: - val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node) - elif val_is_ptr != 0 and ret_is_ptr != 0: - # 指针 → 指针且元素类型不同(如 t.CVoid(x, CPtr) 得到 i8*, - # 函数返回类型是类指针 Circle* 时)需 bitcast 回, - # 否则 llc 报 "value doesn't match function result type"。 - val_pointee: llvmlite.LLVMType | t.CPtr = None - ret_pointee: llvmlite.LLVMType | t.CPtr = None - match val.Ty: - case llvmlite.LLVMType.Ptr(v_inner): - val_pointee = v_inner - match ret_ty_rt: - case llvmlite.LLVMType.Ptr(r_inner): - ret_pointee = r_inner - if val_pointee is not None and ret_pointee is not None \ - and t.CUInt64T(val_pointee) != t.CUInt64T(ret_pointee): - val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node) - elif val_bits != 0 and ret_bits != 0 and val_bits != ret_bits: - if val_bits == 1 and val_bits < ret_bits: - val = llvmlite.build_zext(builder, val, ret_ty_rt) - else: - val = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node) - llvmlite.build_ret(builder, val) - return 0 - - -# ============================================================ -# NewReturnHandle - 工厂函数(委托到 gen.NewReturnHandle) -# ============================================================ -def NewReturnHandle(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> ReturnHandle | t.CPtr: - """创建 ReturnHandle 实例(委托到 gen.NewReturnHandle)""" - g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) - if g is not None: - return g.NewReturnHandle(pool, trans) - return None diff --git a/App/lib/core/Handles/HandlesTranslator.vp b/App/lib/core/Handles/HandlesTranslator.vp index 4d2ba58..81506a4 100644 --- a/App/lib/core/Handles/HandlesTranslator.vp +++ b/App/lib/core/Handles/HandlesTranslator.vp @@ -185,19 +185,6 @@ class Translator: # 跨模块函数返回类型无法精确解析。Phase A 多遍循环据此下遍重试。 _deps_pending: t.CInt - # 子 Handle 指针(每个 Handle 一个槽,通过 Mixin 回指针访问本结构体) - AssignH: HandlesAssign.AssignHandle | t.CPtr - ReturnH: HandlesReturn.ReturnHandle | t.CPtr - ImportsH: HandlesImports.ImportsHandle | t.CPtr - AnnAssignH: HandlesAnnAssign.AnnAssignHandle | t.CPtr - AugAssignH: HandlesAugAssign.AugAssignHandle | t.CPtr - IfH: HandlesIf.IfHandle | t.CPtr - WhileH: HandlesWhile.WhileHandle | t.CPtr - ForH: HandlesFor.ForHandle | t.CPtr - ExprH: HandlesExpr.ExprHandle | t.CPtr - ExprCallH: HandlesExprCall.ExprCallHandle | t.CPtr - MatchH: HandlesMatch.MatchHandle | t.CPtr - # 嵌套作用域符号表 SymTab: HandlesVar.SymbolTable | t.CPtr @@ -240,17 +227,6 @@ class Translator: self.GenericTypeArgs = None self._declare_only = 0 self._deps_pending = 0 - self.AssignH = None - self.ReturnH = None - self.ImportsH = None - self.AnnAssignH = None - self.AugAssignH = None - self.IfH = None - self.WhileH = None - self.ForH = None - self.ExprH = None - self.ExprCallH = None - self.MatchH = None self.SymTab = None # ============================================================ @@ -280,29 +256,6 @@ class Translator: self._nonlocal_types = stdlib.malloc(MAX_GLOBAL_NAMES * 8) if self._nonlocal_types is not None: string.memset(self._nonlocal_types, 0, MAX_GLOBAL_NAMES * 8) - # 创建子 Handle(传入 self 作为 Mixin 回指针) - if self.AssignH is None: - self.AssignH = HandlesAssign.NewAssignHandle(pool, self) - if self.ReturnH is None: - self.ReturnH = HandlesReturn.NewReturnHandle(pool, self) - if self.ImportsH is None: - self.ImportsH = HandlesImports.NewImportsHandle(pool, self) - if self.AnnAssignH is None: - self.AnnAssignH = HandlesAnnAssign.NewAnnAssignHandle(pool, self) - if self.AugAssignH is None: - self.AugAssignH = HandlesAugAssign.NewAugAssignHandle(pool, self) - if self.IfH is None: - self.IfH = HandlesIf.NewIfHandle(pool, self) - if self.WhileH is None: - self.WhileH = HandlesWhile.NewWhileHandle(pool, self) - if self.ForH is None: - self.ForH = HandlesFor.NewForHandle(pool, self) - if self.MatchH is None: - self.MatchH = HandlesMatch.NewMatchHandle(pool, self) - if self.ExprH is None: - self.ExprH = HandlesExpr.NewExprHandle(pool, self) - if self.ExprCallH is None: - self.ExprCallH = ExprCallHandle.NewExprCallHandle(pool, self) # ============================================================ # 主翻译入口 @@ -426,11 +379,11 @@ class Translator: kd: int = child.kind() if kd == ast.ASTKind.Import: cur_imp_lineno = child.lineno - self.ImportsH.HandleImport(child) + HandlesImports.translate_import(self, child) elif kd == ast.ASTKind.ImportFrom: cur_imp_lineno = child.lineno - self.ImportsH.HandleImportFromModule(child) - self.ImportsH.HandleImportFromNames(child) + HandlesImports.translate_import_from_module(self, child) + HandlesImports.translate_import_from_names(self, child) # 对齐 TPC _inject_auto_imports:检测源文件对 list/dict 容器的使用 # (裸名注解 d: dict / 构造 dict(...) / 下标 list[T]),自动把容器 # 类标记为可见结构体。背景:_list.vp/_dict.vp 定义内建容器类且已由 diff --git a/App/lib/core/Handles/HandlesWhile.vp b/App/lib/core/Handles/HandlesWhile.vp index ae7a0e1..a378cad 100644 --- a/App/lib/core/Handles/HandlesWhile.vp +++ b/App/lib/core/Handles/HandlesWhile.vp @@ -1,220 +1,40 @@ import t, c from stdint import * import ast -import llvmlite import memhub -import string -import stdio -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.HandlesType as HandlesType import lib.core.Gen.Generator as Generator # ============================================================ -# HandlesWhile - while 循环语句处理(P6 对象化后的委托层) +# HandlesWhile - while 循环语句处理(迁移完成,保留跨 Mixin 委托壳) # -# NewWhileHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法 -# (WhileHandle 类保留:trans.WhileH 的类型,由 HandlesTranslator. -# _init_state 经 NewWhileHandle 委托创建)。 -# -# 翻译 while 语句为 LLVM IR 控制流: -# br label %cond -# cond: -# %t = -# %c = icmp ne i32 %t, 0 -# br i1 %c, label %body, label %end -# body: -# ... body ... -# br label %cond -# end: +# P6 机械化迁移:WhileHandle 类 → StmtGenCifMixin.translate_while; +# 模块级辅助 _IsConstTrue/_NodeHasBreak/_StmtHasBreak → StmtGenCifMixin +# 方法(merge 可达性判定)。 +# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下 +# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。 +# 迁移收尾(编译器缺陷修复)后统一删除。 # ============================================================ # ============================================================ -# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式) +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) # # 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 # 委托函数用本地 _g_gen(cast 成 Generator 类型)调 -# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。 +# StmtGenCifMixin 方法,避免函数体 import 包模块与类/模块名歧义。 # ============================================================ _g_gen: Generator.Generator | t.CPtr = None -@t.NoVTable -class WhileHandle(HandlesBase.Mixin): - """while 循环语句处理器:继承 Mixin 获得 Trans 回指针""" - - def __init__(self, trans: HT.Translator | t.CPtr): - self.Trans = trans - - # ============================================================ - # Handle - 处理 while 语句,返回新增变量数 - # ============================================================ - def Handle(self, node: ast.AST | t.CPtr) -> int: - """翻译 while 循环语句""" - 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 - - while_node: ast.While | t.CPtr = (ast.While | t.CPtr)(node) - - # 1. 创建基本块: cond / body / end(使用 trans._label_counter,不与 SSA 名共享) - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - - name_buf: str = pool.alloc(32) - viperlib.snprintf(name_buf, 32, "while.cond.%d", cnt) - cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "while.body.%d", cnt) - body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - viperlib.snprintf(name_buf, 32, "while.end.%d", cnt) - end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # 2. 跳转到 cond 块 - llvmlite.build_br(builder, cond_bb) - - # 3. cond 块: 求值条件,条件分支 - llvmlite.position_at_end(builder, cond_bb) - cond_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, trans.Module, while_node.test, - trans._funcs, trans._func_count, trans) - if cond_val is None: - # fail-fast: while 条件表达式翻译失败 - HandlesType.fatal_error(while_node.test, "while 条件表达式翻译失败", "TypeError") - - # Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较 - cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty) - if cond_bits == 1: - cond_i1: llvmlite.Value | t.CPtr = cond_val - elif HandlesExpr.is_ptr_type(cond_val.Ty) != 0: - # 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type") - null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null") - cond_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cond_val, null_cond) - else: - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - cond_i1 = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cond_val, zero) - llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb) - - # 4. body 块: 翻译循环体,跳回 cond - llvmlite.position_at_end(builder, body_bb) - - # 保存旧循环上下文,设置 break/continue 目标 - old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb - old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb - trans._break_bb = end_bb - trans._continue_bb = cond_bb - - body: list[ast.AST | t.CPtr] | t.CPtr = while_node.children - if body is not None: - body_count: t.CSizeT = len(body) - for bi in range(body_count): - stmt: ast.AST | t.CPtr = body.get(bi) - if stmt is not None: - HandlesBody.translate_stmt(trans, stmt) - - # 恢复旧循环上下文 - trans._break_bb = old_break - trans._continue_bb = old_continue - - if llvmlite.builder_cur_block_is_terminated(builder) == 0: - llvmlite.build_br(builder, cond_bb) - - # 5. 定位到 end 块 - llvmlite.position_at_end(builder, end_bb) - # 追加90:while 的 cond_br 恒引用 end_bb → merge 恒可达(需正常收尾) - trans._ctrl_merge_reachable = 1 - # 无限循环(条件常量真 1/True)且循环体无本层 break → 运行时无任何边 - # 到达 end 块(merge 结构性不可达)→ 置 0,函数收尾对末句 While 生成 - # unreachable(追加90:无 br 到达 merge 时才安全;否则 llc O2 把 - # br-to-unreachable 优化为 fall-through → 双分支执行崩溃)。 - # 修复 vrandom.gammavariate 的 while 1 全 return 被误判"流程掉出末尾"。 - if _IsConstTrue(while_node.test) != 0 and _StmtHasBreak(body) == 0: - trans._ctrl_merge_reachable = 0 - return 0 - - # ============================================================ -# NewWhileHandle - 工厂函数(委托到 gen.NewWhileHandle) +# translate_while - while 循环语句翻译(委托到 gen.translate_while) # ============================================================ -def NewWhileHandle(pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr) -> WhileHandle | t.CPtr: - """创建 WhileHandle 实例(委托到 gen.NewWhileHandle)""" +def translate_while(trans: HT.Translator | t.CPtr, + node: ast.AST | t.CPtr) -> int: + """翻译 while 循环语句(委托到 gen.translate_while)""" g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) if g is not None: - return g.NewWhileHandle(pool, trans) - return None - - -# ============================================================ -# 无限循环判定辅助(merge 可达性) -# -# _IsConstTrue: while 条件为常量真(CONST_INT 非 0 / CONST_BOOL 真) -# _NodeHasBreak / _StmtHasBreak: 扫描本层 break(跳过嵌套 While/For -# 子树——嵌套循环的 break 归内层,不影响外层 merge 可达性) -# ============================================================ -def _IsConstTrue(test: ast.AST | t.CPtr) -> int: - """while 条件为常量真(1 / True)返回 1""" - if test is None: - return 0 - if test.kind() == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(test) - if cn.const_kind == ast.CONST_INT and cn.int_val != 0: - return 1 - if cn.const_kind == ast.CONST_BOOL and cn.int_val != 0: - return 1 - return 0 - - -def _NodeHasBreak(node: ast.AST | t.CPtr) -> int: - """递归扫描节点子树(跳过嵌套 While/For 子树),含 Break 返回 1""" - if node is None: - return 0 - ch: list[ast.AST | t.CPtr] | t.CPtr = node.children - if ch is not None: - n: t.CSizeT = len(ch) - for bi in range(n): - c: ast.AST | t.CPtr = ch.get(bi) - if c is None: - continue - k: int = c.kind() - if k == ast.ASTKind.Break: - return 1 - if k == ast.ASTKind.While or k == ast.ASTKind.For: - continue - if _NodeHasBreak(c) != 0: - return 1 - return 0 - - -def _StmtHasBreak(body: list[ast.AST | t.CPtr] | t.CPtr) -> int: - """语句列表是否含本层 break(嵌套循环的 break 归内层)""" - if body is None: - return 0 - n: t.CSizeT = len(body) - for bi in range(n): - s: ast.AST | t.CPtr = body.get(bi) - if s is None: - continue - k: int = s.kind() - if k == ast.ASTKind.Break: - return 1 - if k == ast.ASTKind.While or k == ast.ASTKind.For: - continue - if _NodeHasBreak(s) != 0: - return 1 + return g.translate_while(trans, node) return 0 diff --git a/App/main.vp b/App/main.vp index 0281552..fdf8e47 100644 --- a/App/main.vp +++ b/App/main.vp @@ -18,6 +18,7 @@ import lib.core.Handles.HandlesMatch as HandlesMatch import lib.core.Handles.HandlesEnum as HandlesEnum import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign import lib.core.Handles.HandlesAugAssign as HandlesAugAssign +import lib.core.Handles.HandlesAssign as HandlesAssign import lib.core.Handles.HandlesVar as HandlesVar import lib.core.Handles.HandlesMain as HandlesMain import lib.core.BuildPipeline as BuildPipeline @@ -149,6 +150,7 @@ def main() -> int: HandlesEnum._g_gen = gen HandlesAnnAssign._g_gen = gen HandlesAugAssign._g_gen = gen + HandlesAssign._g_gen = gen HandlesVar._g_gen = gen HandlesTranslator._g_gen = gen HandlesMain._g_gen = gen