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