From 24c1aada308175cb59d77310e7ff938a61e8d5f3 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 10 Aug 2026 02:11:26 +0800 Subject: [PATCH] =?UTF-8?q?refactor(gen):=20P3=20ExprGenMixin=20-=20Handle?= =?UTF-8?q?sExpr/ExprOps=2051=20=E5=87=BD=E6=95=B0=E8=BF=81=E7=A7=BB=20+?= =?UTF-8?q?=20=E5=A7=94=E6=89=98=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HandlesExpr 45 个表达式函数(translate_value/subscript/attribute 等) 与 HandlesExprOps 6 个运算符函数(try_operator_overload/translate_binop 等)迁移为 ExprGenMixin 方法;本模块调用 self 化、外部模块调用保留 前缀,_lookup_cross_module_cdefine(490 行)完整迁移。旧函数保留为 _g_gen 单例委托。Generator 多继承追加 ExprGenMixin(4 Mixin 组合)。 --- App/lib/core/BuildPipeline.vp | 8 +- App/lib/core/Gen/ExprGenMixin.vp | 4029 ++++++++++++++++++++++++ App/lib/core/Gen/Generator.vp | 3 +- App/lib/core/Handles/HandlesExpr.vp | 3536 ++------------------- App/lib/core/Handles/HandlesExprOps.vp | 386 +-- App/main.vp | 7 +- 6 files changed, 4396 insertions(+), 3573 deletions(-) create mode 100644 App/lib/core/Gen/ExprGenMixin.vp diff --git a/App/lib/core/BuildPipeline.vp b/App/lib/core/BuildPipeline.vp index 0b29186..fb0b097 100644 --- a/App/lib/core/BuildPipeline.vp +++ b/App/lib/core/BuildPipeline.vp @@ -14,6 +14,8 @@ import lib.core.VLogger as VLogger import lib.core.Handles.HandlesTranslator as HandlesTranslator import lib.core.Handles.HandlesStruct as HandlesStruct import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprOps as HandlesExprOps import lib.core.Handles.HandlesImports as HandlesImports import lib.core.StubMerger as StubMerger import lib.StubGen.Converter as StubConverter @@ -142,10 +144,12 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str, gen.__before_init__() gen.__init__(mb) GenGenerator.set_global_gen(gen) - # P2: 注入 HandlesType/HandlesStruct 模块级单例(委托函数经本地 _g_gen 访问, - # 避免函数体 import 包模块与 Generator 类/模块名歧义) + # P2/P3: 注入 HandlesType/HandlesStruct/HandlesExpr/HandlesExprOps 模块级单例 + # (委托函数经本地 _g_gen 访问,避免函数体 import 包模块与类/模块名歧义) HandlesType.set_global_gen(gen) HandlesStruct.set_global_gen(gen) + HandlesExpr.set_global_gen(gen) + HandlesExprOps.set_global_gen(gen) # 设置当前文件名(供报错使用) HandlesType.set_current_file(file_path) # 同步到 HandlesImports(import 时 SHA1 检查报错需要当前文件名,循环依赖无法直接读 HandlesType) diff --git a/App/lib/core/Gen/ExprGenMixin.vp b/App/lib/core/Gen/ExprGenMixin.vp new file mode 100644 index 0000000..3747a62 --- /dev/null +++ b/App/lib/core/Gen/ExprGenMixin.vp @@ -0,0 +1,4029 @@ +import t, c +from stdint import * +import ast +import memhub +import string +import llvmlite +import stdlib +import stdio +import viperlib +import w32.fileio as fileio +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.HandlesExprOps as HandlesExprOps +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesEnum as HandlesEnum +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.StubMerger as StubMerger +import lib.core.VLogger as VLogger +import lib.Projectrans.Config as Config +import lib.Projectrans.Utils as Utils + + +# ============================================================ +# ExprGenMixin - 表达式处理 Mixin(对象化 P3,wiki/14-oo-refactor.md) +# +# 从 HandlesExpr.vp(48 函数,无全局状态)与 HandlesExprOps.vp +# 迁移:模块级纯函数 → 类方法(self 替代,参数保留含 builder/pool)。 +# +# 迁移原则(与 P2 一致,行为零变化): +# 1. 方法保留原函数签名(含 builder/pool 首参),仅函数体内 +# 本模块函数调用改为 self.xxx(...) +# 2. 外部模块调用(HandlesExprCall.xxx / HandlesType.xxx 等)保留模块前缀 +# 3. HandlesExpr.vp / HandlesExprOps.vp 原函数保留为"委托":本地 +# 模块级单例 _g_gen(BuildPipeline/main 注入)cast 成 Generator 类型 +# 4. ExprHandle 类保留在 HandlesExpr.vp(translator handler 模式) +# +# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 +# ============================================================ + + +# ============================================================ +# ExprGenMixin - 表达式/常量/下标/属性访问/运算符 +# ============================================================ +@t.NoVTable +class ExprGenMixin: + """表达式处理 Mixin(纯方法化迁移,无状态字段)""" + + # ============================================================ + # P3 迁移方法(函数体来自 HandlesExpr.vp 模块级函数, + # 本模块函数调用改 self.,外部模块调用保留模块前缀) + # ============================================================ + + # ============================================================ + # 从 AST 节点提取函数名 + # ============================================================ + def get_func_name(self, func_node: ast.AST | t.CPtr) -> str: + """从函数节点提取函数名""" + if func_node is None: + return None + k: int = func_node.kind() + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_node) + return nm.id + elif k == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(func_node) + return at.attr + return None + + # ============================================================ + # 转义 LLVM IR 字符串字面量 + # ============================================================ + def escape_llvm_string(self, pool: memhub.MemBuddy | t.CPtr, + src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: + """将字符串转换为 LLVM IR 字符串字面量 c"...\\00" """ + if src is None: + return None + slen: t.CSizeT = string.strlen(src) + alloc_size: t.CSizeT = 4 * slen + 8 + buf: t.CChar | t.CPtr = pool.alloc(alloc_size) + if buf is None: + return None + pos: t.CSizeT = 0 + buf[pos] = 'c' + pos += 1 + buf[pos] = '"' + pos += 1 + for i in range(slen): + ch: t.CChar = src[i] + if ch == '\0': + break + if ch == '\"' or ch == '\\' or ch < 0x20: + buf[pos] = '\\' + pos += 1 + hi: int = (ch >> 4) & 0xF + lo: int = ch & 0xF + buf[pos] = Utils.nibble_to_hex_char(hi, 1) + pos += 1 + buf[pos] = Utils.nibble_to_hex_char(lo, 1) + pos += 1 + else: + buf[pos] = ch + pos += 1 + buf[pos] = '\\' + pos += 1 + buf[pos] = '0' + pos += 1 + buf[pos] = '0' + pos += 1 + buf[pos] = '"' + pos += 1 + buf[pos] = '\0' + return buf + + # ============================================================ + # 获取 LLVM 整数类型的位宽 + # ============================================================ + def get_llvm_type_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """获取 LLVM 整数类型的位宽,非整数类型返回 0""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Int(bits): + return bits + case _: + return 0 + + # ============================================================ + # 获取 LLVM 浮点类型的位宽 + # ============================================================ + def get_llvm_float_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """获取 LLVM 浮点类型的位宽,非浮点类型返回 0""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Float(bits): + return bits + case _: + return 0 + + # ============================================================ + # is_ptr_type - 检查类型是否为 Ptr + # + # 返回 1=是, 0=否。作为类型检查工具函数被广泛使用(50+ 处调用)。 + # ============================================================ + def is_ptr_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """检查 ty 是否是 Ptr 类型,返回 1=是, 0=否""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Ptr(pointee): + return 1 + case _: + return 0 + + # ============================================================ + # get_ptr_level - 计算指针层级 + # + # 返回值: + # 0 = 非指针(数值/结构体等) + # 1 = 一级指针(如 i8*, Struct*) + # 2 = 二级指针(如 i8**, Struct**) + # 3+ = 更高级指针 + # + # 用于比较运算的类型安全检查: + # - 数值(0) vs 数值(0) → 允许 + # - 一级指针(1) vs 一级指针(1) → 允许 + # - 数值(0) vs 指针(1+) → 禁止(fast-fail) + # - 不同级指针(1 vs 2) → 禁止(fast-fail) + # ============================================================ + def get_ptr_level(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """计算指针层级,0=非指针, 1=一级指针, 2=二级指针...""" + if ty is None: + return 0 + level: int = 0 + cur: llvmlite.LLVMType | t.CPtr = ty + while cur is not None: + match cur: + case llvmlite.LLVMType.Ptr(pointee): + level += 1 + cur = pointee + case _: + break + return level + + # ============================================================ + # is_array_type - 检查类型是否为 Array + # + # 返回 1=是, 0=否。类型检查工具函数。 + # ============================================================ + def is_array_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int: + """检查 ty 是否是 Array 类型,返回 1=是, 0=否""" + if ty is None: + return 0 + match ty: + case llvmlite.LLVMType.Array(_, _): + return 1 + case _: + return 0 + + # ============================================================ + # _zext_index_to_i32 - 数组下标索引零扩展 + # + # LLVM GEP 对窄整数索引默认符号扩展:i8 0xE2(226) 会被当成 -30, + # 导致数组下标越界读(字节 >= 128 的乱码根因)。 + # 数组下标语义为非负,<32 位整数索引一律 zext 到 i32。 + # 仅用于数组 GEP;指针负偏移(p[-1])不经过此路径,不受影响。 + # ============================================================ + def _zext_index_to_i32(self, builder: llvmlite.IRBuilder | t.CPtr, + idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """将 <32 位整数下标零扩展到 i32(数组下标非负语义)""" + if idx_val is None or idx_val.Ty is None or builder is None: + return idx_val + idx_bits: int = self.get_llvm_type_bits(idx_val.Ty) + if idx_bits != 0 and idx_bits < 32: + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(builder.Pool) + return llvmlite.build_zext(builder, idx_val, i32_ty) + return idx_val + + # ============================================================ + # _get_custom_struct_cls_nm - 检查类型是否为已注册的自定义结构体 + # + # 处理两种情况: + # - ty 直接是 Struct → 检查是否注册 + # - ty 是 Ptr(Struct) → 检查 pointee 是否注册 + # + # 返回类名字符串或 None。用于 subscript 操作中判断是否需要 + # 转发到 __getitem__/__setitem__ 而非生成 GEP。 + # ============================================================ + def _get_custom_struct_cls_nm(self, pool: memhub.MemBuddy | t.CPtr, + ty: llvmlite.LLVMType | t.CPtr) -> str: + """检查 ty 或 ty 的 pointee 是否是已注册的自定义结构体,返回类名或 None""" + if ty is None: + return None + # 直接检查 ty 是否是注册的结构体 + cls_nm_direct: str = HandlesStruct.get_class_name_by_type(pool, ty) + if cls_nm_direct is not None: + return cls_nm_direct + # 如果 ty 是 Ptr,检查 pointee + if self.is_ptr_type(ty) != 0: + pointee_cs: llvmlite.LLVMType | t.CPtr = ty.Pointee + if pointee_cs is not None: + return HandlesStruct.get_class_name_by_type(pool, pointee_cs) + return None + + # ============================================================ + # _is_list_subscript_base - 判断下标基座是否为 list[T] 变量 + # + # 属性访问的 Subscript 基座(如 lst[i].x)需要区分: + # - list[T] 变量:translate_subscript 走 __getitem__ 内联返回元素地址 + # - 普通结构体指针数组(如 pts: Point | t.CPtr):get_subscript_ptr 返回元素地址 + # 路由错误会让 list[T] 被当作结构体数组 GEP,访问错位崩溃。 + # ============================================================ + def _is_list_subscript_base(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + sub_node: ast.AST | t.CPtr) -> int: + """判断下标基座是否为 list[T] 变量(1=是)""" + if sub_node is None or trans is None: + return 0 + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node) + if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name: + return 0 + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm.id is None: + return 0 + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is None or alloca.Ty is None: + return 0 + if self.is_ptr_type(alloca.Ty) == 0: + return 0 + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is None: + return 0 + match pointee: + case llvmlite.LLVMType.Ptr(inner_ty): + lsn_ls: str = None + match inner_ty: + case llvmlite.LLVMType.Struct(_, _, lsn3): + lsn_ls = lsn3 + case _: + pass + if lsn_ls is not None and string.strstr(lsn_ls, "list[") is not None: + return 1 + case _: + pass + return 0 + + # ============================================================ + # _sub_base_class_name - 解析下标基座变量的结构体类名 + # ============================================================ + def _sub_base_class_name(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + sub_node: ast.AST | t.CPtr) -> str: + """解析下标基座变量的结构体类名(无则 None)""" + if sub_node is None or trans is None: + return None + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node) + if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name: + return None + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm.id is None: + return None + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is None or alloca.Ty is None: + return None + if self.is_ptr_type(alloca.Ty) == 0: + return None + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is None: + return None + if self.is_ptr_type(pointee) != 0: + inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee + if inner is not None: + return HandlesStruct.get_class_name_by_type(pool, inner) + return HandlesStruct.get_class_name_by_type(pool, pointee) + + # ============================================================ + # _sub_base_uses_getitem - 下标基座是否应走 __getitem__ 语义 + # + # 属性访问的 Subscript 基座路由依据: + # - list[T] / OOP 定义 __getitem__ 的类(如 dict[key])→ translate_value + # (translate_subscript 走 __getitem__ 内联/方法调用返回元素值或地址) + # - 普通结构体指针数组(如 pts: Point | t.CPtr)→ get_subscript_ptr + # (GEP 元素地址,避免结构体值 base=非指针 报错) + # ============================================================ + def _sub_base_uses_getitem(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + sub_node: ast.AST | t.CPtr) -> int: + """下标基座应走 __getitem__ 语义时返回 1,否则 0(应走 GEP 地址语义)""" + if self._is_list_subscript_base(pool, trans, sub_node) != 0: + return 1 + cls_ugi: str = self._sub_base_class_name(pool, trans, sub_node) + if cls_ugi is None: + return 0 + lookup_ugi: t.CChar | t.CPtr = pool.alloc(128) + if lookup_ugi is None: + return 0 + viperlib.snprintf(lookup_ugi, 128, "%s.__getitem__", cls_ugi) + if HandlesExprCall.find_func_in_module(mod, lookup_ugi) is not None: + return 1 + return 0 + + # ============================================================ + # _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用 + # + # 用于支持 X|t.CPtr 类型变量的属性访问: + # - 值类型变量 (cnt: Counter): alloca 类型是 Ptr(Struct) → 不解引用 + # - 指针类型变量 (r: Vec2|t.CPtr): alloca 类型是 Ptr(Ptr(Struct)) → load 解引用 + # ============================================================ + def _deref_if_ptr_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, + obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针""" + if obj_ptr is None or obj_ptr.Ty is None: + return obj_ptr + if self.is_ptr_type(obj_ptr.Ty) == 0: + return obj_ptr + pointee: llvmlite.LLVMType | t.CPtr = obj_ptr.Ty.Pointee + if pointee is None: + return obj_ptr + if self.is_ptr_type(pointee) == 0: + return obj_ptr + # obj_ptr 是 Ptr(Ptr(...)),load 解引用 + loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, obj_ptr) + if loaded is None: + return obj_ptr + return loaded + + # ============================================================ + # 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si + # ============================================================ + def coerce_to_type(self, builder: llvmlite.IRBuilder | t.CPtr, + val: llvmlite.Value | t.CPtr, + target_ty: llvmlite.LLVMType | t.CPtr, + node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """将 val 强制转换为 target_ty + + 整数: sext(扩展)/ trunc(截断) + 浮点: fpext(扩展)/ fptrunc(截断) + int→float: sitofp + float→int: fptosi + + node: AST 节点(用于错误定位),可为 None + """ + if val is None or target_ty is None: + return val + # 函数 → 指针: bitcast(如 CreateThread(..., _thread_alloc_free, ...) 传函数指针) + # 函数 Value 的 Ty 是 Func,既不是整数也不是指针,需在整数/浮点转换之前处理 + match val.Ty: + case llvmlite.LLVMType.Func(_, _, _): + if self.is_ptr_type(target_ty) != 0: + return llvmlite.build_bitcast(builder, val, target_ty) + return val + case _: + pass + # 整数转换 + val_bits: int = self.get_llvm_type_bits(val.Ty) + target_bits: int = self.get_llvm_type_bits(target_ty) + # 整数 → 指针: inttoptr(必须在纯整数转换之前检查,因为 ptr 的 bits 非零会误入 sext/trunc 路径) + # 适用于: 跨模块方法返回 i64/i32(默认推断),目标变量是指针类型 + if val_bits != 0 and self.is_ptr_type(target_ty) != 0: + return llvmlite.build_inttoptr(builder, val, target_ty) + # 指针 → 整数: ptrtoint(当目标明确是整数而非指针时) + # 注意: target_bits == 8 时跳过 ptrtoint,走后面的 build_load 解引用首字符 + # 修复: buf[idx] = '\0' 中 '\0' 是 CONST_STR → i8* 指针, + # ptrtoint 会截断地址低 8 位(非 0),应 load 解引用取首字符 0 + if self.is_ptr_type(val.Ty) != 0 and target_bits != 0 and target_bits != 8 and self.is_ptr_type(target_ty) == 0: + return llvmlite.build_ptrtoint(builder, val, target_ty) + if val_bits != 0 and target_bits != 0: + if val_bits == target_bits: + return val + if val_bits < target_bits: + # i1 (bool) → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF...) + # 与 HandlesReturn 中 return 语句的 i1 扩展规则保持一致 + if val_bits == 1: + return llvmlite.build_zext(builder, val, target_ty) + return llvmlite.build_sext(builder, val, target_ty) + return llvmlite.build_trunc(builder, val, target_ty) + # 浮点转换 + val_fbits: int = self.get_llvm_float_bits(val.Ty) + target_fbits: int = self.get_llvm_float_bits(target_ty) + # float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径) + if (val_fbits != 0 and self.is_ptr_type(target_ty) != 0) or \ + (self.is_ptr_type(val.Ty) != 0 and target_fbits != 0): + HandlesType.fatal_error(node, "unsupported type conversion: float <-> ptr", "CastError") + return val + if val_fbits != 0 and target_fbits != 0: + if val_fbits == target_fbits: + return val + if val_fbits < target_fbits: + return llvmlite.build_fpext(builder, val, target_ty) + return llvmlite.build_fptrunc(builder, val, target_ty) + # int → float + if val_bits != 0 and target_fbits != 0: + return llvmlite.build_si2fp(builder, val, target_ty) + # float → int + if val_fbits != 0 and target_bits != 0: + return llvmlite.build_fp2si(builder, val, target_ty) + # 指针 → 非指针值: build_load 解引用 + # 适用于: 指针 → 整数 (如 i8* → i8), 指针 → 结构体值 + # 当构造器返回 Ptr(Struct) 但目标变量是 Struct 值类型时,需要 load + if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) == 0: + return llvmlite.build_load(builder, target_ty, val) + # 指针 → 指针: bitcast (如 i8* → i8** 当目标是全局变量存储指针) + if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) != 0: + return llvmlite.build_bitcast(builder, val, target_ty) + return val + + # ============================================================ + # translate_ptr_arith - 指针算术: ptr + int / ptr - int + # + # 用 getelementptr(按 pointee 元素大小缩放索引),对齐 TPC + # ExprGen.emit_binary_op / HandlesAugAssign.py。 + # 旧实现用 ptrtoint + add + inttoptr(按字节加):i8* 元素大小 1 + # 恰好正确,但 i32*/struct* 等指针 `p + 3` 只前进 3 字节(应 12), + # 导致 StringIterTest Test 4/8 失败(指针偏移/指针算术)。 + # + # 数组 pointee([N x ty]*)先 decay 为元素指针(GEP 0,0), + # 避免以整个数组为步长(对齐 TPC ExprGen L53-55)。 + # ============================================================ + def translate_ptr_arith(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + ptr_val: llvmlite.Value | t.CPtr, + int_val: llvmlite.Value | t.CPtr, + op: int) -> llvmlite.Value | t.CPtr: + """指针算术: ptr + int / ptr - int → GEP(按元素大小缩放索引)""" + if ptr_val is None or int_val is None or ptr_val.Ty is None: + return None + # 提取 pointee 类型(非指针 → 不处理返回 None) + elem_ty: llvmlite.LLVMType | t.CPtr = None + match ptr_val.Ty: + case llvmlite.LLVMType.Ptr(pointee): + elem_ty = pointee + case _: + return None + if elem_ty is None: + return None + # 索引统一到 i64(对齐 TPC zext 到 i64) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + idx: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, int_val, i64_ty, None) + if idx is None: + return None + # ptr - int → 负索引(LLVM GEP 索引为加法语义) + if op == ast.OpKind.Sub: + neg_idx: llvmlite.Value | t.CPtr = llvmlite.build_sub( + builder, llvmlite.const_int64(pool, 0), idx) + if neg_idx is None: + return None + idx = neg_idx + # 数组 pointee → 先 decay 为元素指针(getelementptr [N x ty], [N x ty]* %p, i32 0, i32 0) + if self.is_array_type(elem_ty) != 0: + inner_ty: llvmlite.LLVMType | t.CPtr = None + match elem_ty: + case llvmlite.LLVMType.Array(inner, _): + inner_ty = inner + case _: + return None + if inner_ty is None: + return None + decayed: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, elem_ty, inner_ty, ptr_val, llvmlite.const_int64(pool, 0)) + if decayed is None: + return None + return llvmlite.build_gep(builder, inner_ty, decayed, idx) + return llvmlite.build_gep(builder, elem_ty, ptr_val, idx) + + # ============================================================ + # 创建全局字符串常量 + # ============================================================ + def create_global_string(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + str_val: str, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """创建全局字符串常量并返回 i8* bitcast""" + escaped: t.CChar | t.CPtr = self.escape_llvm_string(pool, str_val) + if escaped is None: + return None + + slen: t.CSizeT = string.strlen(str_val) + count: int = slen + 1 + + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, count) + + # 使用模块级计数器(trans._label_counter)避免跨函数命名冲突 + str_idx: int = trans._label_counter + trans._label_counter += 1 + + # 字符串名加 SHA1 前缀,和函数导出规则一致,避免跨模块重名 + gv_name: t.CChar | t.CPtr = pool.alloc(48) + if gv_name is None: + return None + if trans.ModuleSha1 is not None: + viperlib.snprintf(gv_name, 48, ".str.%s.%d", trans.ModuleSha1, str_idx) + else: + viperlib.snprintf(gv_name, 48, ".str.%d", str_idx) + + gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name, arr_ty) + if gv is None: + return None + llvmlite.module_add_global(mod, gv) + + # 去掉 private 链接,和函数一致:stub 中 declare,text 中 define + llvmlite.global_set_unnamed_addr(gv, 1) + llvmlite.global_set_constant(gv, 1) + # LLVM 22+ 不允许 external linkage 全局变量带初始值,设为 internal + gv.Linkage = "internal" + gv.Initializer = escaped + + arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty) + gv_ref_name: t.CChar | t.CPtr = pool.alloc(64) + if gv_ref_name is None: + return None + viperlib.snprintf(gv_ref_name, 64, "@%s", gv.Name) + gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, arr_ptr_ty, gv_ref_name) + + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, gv_ref, i8_ptr_ty) + return bc + + # ============================================================ + # 翻译常量表达式 + # ============================================================ + def translate_constant(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译常量(int/str/bool)""" + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) + if cn is None: + return None + ck: int = cn.const_kind + if cn.const_kind == ast.CONST_INT: + # 超出 i32 范围则用 i64(避免常量创建时被截断) + iv: t.CInt64T = cn.int_val + if iv > 2147483647 or iv < -2147483648: + return llvmlite.const_int64(pool, iv) + return llvmlite.const_int32(pool, iv) + elif cn.const_kind == ast.CONST_FLOAT: + # 浮点常量默认创建为 double(64 位),赋值时由 coerce_to_type 自动 fptrunc + double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + return llvmlite.ConstFloat(pool, double_ty, cn.float_val) + elif cn.const_kind == ast.CONST_CHAR: + # 单引号单字符 → i32 值(字符 ASCII 码),coerce_to_type 会 trunc 为 i8 + cv: t.CInt64T = cn.int_val + return llvmlite.const_int32(pool, cv) + elif cn.const_kind == ast.CONST_STR: + sv: str = cn.str_val + if sv is None: + return None + r: llvmlite.Value | t.CPtr = self.create_global_string(builder, pool, mod, sv, trans) + return r + elif cn.const_kind == ast.CONST_BOOL: + if cn.int_val != 0: + return llvmlite.const_int32(pool, 1) + return llvmlite.const_int32(pool, 0) + elif cn.const_kind == ast.CONST_NONE: + # None → i8* null(空指针常量),用于 `p is None` / `p is not None` 比较 + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + if i8_ty is None: + return None + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + if i8_ptr_ty is None: + return None + rv_none: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") + return rv_none + return None + + # ============================================================ + # _infer_elem_type_from_value — 从 LLVM Value 推断 list 元素类型名 + # + # 用于 list 字面量 [a, b, c] 的元素类型推断 + # ============================================================ + def _infer_elem_type_from_value(self, pool: memhub.MemBuddy | t.CPtr, + value: llvmlite.Value | t.CPtr) -> str: + """从 LLVM Value 的类型推断 list 元素类型名""" + if value is None or value.Ty is None: + return "str" + ty: llvmlite.LLVMType | t.CPtr = value.Ty + bits: int = self.get_llvm_type_bits(ty) + if bits != 0: + if bits == 32: + return "int" + if bits == 64: + return "CSizeT" + if bits == 8: + return "CInt8T" + if bits == 16: + return "CInt16T" + return "int" + if self.is_ptr_type(ty) != 0: + return "str" + fbits: int = self.get_llvm_float_bits(ty) + if fbits != 0: + if fbits == 64: + return "CDouble" + if fbits == 32: + return "CFloat" + return "str" + + # ============================================================ + # _find_pool_var — 查找上下文中的 pool 变量 + # + # 依次尝试 "pool", "_mbuddy", "mbuddy", "mb" + # ============================================================ + def _find_pool_var(self, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """查找上下文中的 pool 变量,返回 alloca 或 None + + 查找顺序: pool → _mbuddy → mbuddy → mb + 兜底: 若都未找到,注册外部全局 @_mbuddy (i8*) 供函数内动态 list 创建使用。 + 注意: 模块级 t.CArray 初始化不走此路径(由 _init_global_array_from_list 处理), + 此兜底仅用于函数内的动态 list 字面量(如 op=[...])。 + @_mbuddy 由入口模块(如 Phase2.py)定义并初始化,其他模块以 external 引用。 + """ + if trans is None: + return None + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, "pool") + if alloca is not None: + return alloca + alloca = HandlesVar.lookup_var(trans.SymTab, "_mbuddy") + if alloca is not None: + return alloca + alloca = HandlesVar.lookup_var(trans.SymTab, "mbuddy") + if alloca is not None: + return alloca + alloca = HandlesVar.lookup_var(trans.SymTab, "mb") + if alloca is not None: + return alloca + # 兜底: 创建外部全局 @_mbuddy 引用(i8** 类型) + # 仅用于函数内动态 list 字面量,@_mbuddy 由入口模块定义并初始化 + pool: memhub.MemBuddy | t.CPtr = trans.Pool + if pool is None or trans.Module is None or trans.SymTab is None: + return None + # 先检查是否已注册到模块作用域(避免重复创建全局变量) + existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(trans.SymTab, "_mbuddy") + if existing is not None: + return existing + # 创建 i8* 类型(t.CVoid | t.CPtr = i8*) + i8_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_fb) + # 创建外部全局 @_mbuddy(external linkage,无初始值) + gv_ext: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, "_mbuddy", i8_ptr_ty_fb) + if gv_ext is not None: + gv_ext.Linkage = "external" + llvmlite.module_add_global(trans.Module, gv_ext) + # 创建 Value 引用(@_mbuddy, 类型为 i8**) + i8_ptr_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_fb) + ref_name_fb: t.CChar | t.CPtr = pool.alloc(16) + if ref_name_fb is not None: + string.strcpy(ref_name_fb, "@_mbuddy") + gv_ref_fb: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb) + # 注册到模块作用域,避免重复创建 + HandlesVar.define_module_var(trans.SymTab, "_mbuddy", gv_ref_fb) + return gv_ref_fb + + # ============================================================ + # translate_list_literal — 翻译 list 字面量 [a, b, c] + # + # 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列 + # + # Args: + # builder: IRBuilder + # pool: 编译器内存池(MemBuddy) + # mod: LLVMModule + # node: ast.List 节点 + # elem_type_name: 元素类型名(如 "str", "int"),None 表示从元素推断 + # trans: Translator 对象 + # + # Returns: + # list 对象指针(Ptr(list[T] struct)),None 失败 + # ============================================================ + def translate_list_literal(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + elem_type_name: str, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列""" + if node is None or trans is None: + return None + + list_node: ast.List | t.CPtr = (ast.List | t.CPtr)(node) + if list_node is None: + return None + + elts: list[ast.AST | t.CPtr] | t.CPtr = list_node.elts + elts_count: t.CSizeT = 0 + if elts is not None: + elts_count = elts.__len__() + + # 推断元素类型 + inferred_type_name: str = elem_type_name + first_elem_val: llvmlite.Value | t.CPtr = None + if inferred_type_name is None: + inferred_type_name = "str" + if elts_count > 0: + first_elem_node: ast.AST | t.CPtr = elts.get(0) + first_elem_val = self.translate_value(builder, pool, mod, first_elem_node, None, 0, trans) + if first_elem_val is not None: + inferred_type_name = self._infer_elem_type_from_value(pool, first_elem_val) + + # 查找 pool 变量 + pool_alloca: llvmlite.Value | t.CPtr = self._find_pool_var(trans) + if pool_alloca is None: + HandlesType.fatal_error(node, "list literal requires pool variable in context") + return None + + # load pool 变量值(i8*) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + pool_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, pool_alloca) + if pool_val is None: + return None + + # 特化 list[T] 类(elem_size=8:str 是指针,4 会导致双元素重叠损坏) + type_args: list[str] | t.CPtr = list[str](pool, 8) + type_args.append(inferred_type_name) + spec_name: str = HandlesClassDef._specialize_generic_class(trans, "list", type_args) + if spec_name is None: + HandlesType.fatal_error(node, "list literal generic specialization failed") + return None + + # 查找 struct entry + struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) + if struct_entry is None: + HandlesType.fatal_error(node, "list literal specialized class not registered") + return None + struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty + if struct_ty is None: + return None + + # alloca 临时 list 空间 + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return None + + # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 + # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 + # (与 _translate_struct_ctor/_translate_generic_ctor_call 保持一致, + # 避免为无 __new__ 的类生成过度声明) + storage_ptr: llvmlite.Value | t.CPtr = tmp + has_new_flag: int = 0 + if struct_entry is not None: + has_new_flag = struct_entry.HasNew + if has_new_flag != 0: + new_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if new_args is None: + return None + string.memset(new_args, 0, 8 * 32) + new_args[0] = t.CSizeT(pool_val) + new_ptr: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__new__", tmp, new_args, 1, trans) + if new_ptr is not None: + storage_ptr = new_ptr + + # 调用 __before_init__(storage_ptr) + HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) + + # 调用 __init__(storage_ptr, pool_val, elem_size=0) + init_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if init_args is None: + return None + string.memset(init_args, 0, 8 * 32) + init_args[0] = t.CSizeT(pool_val) + elem_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + init_args[1] = t.CSizeT(elem_size_val) + HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__init__", storage_ptr, init_args, 2, trans) + + # 对每个元素调用 append(storage_ptr, elem_val) + if elts_count > 0: + # 第一个元素可能已经翻译过 + if first_elem_val is not None: + append_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if append_args is not None: + string.memset(append_args, 0, 8 * 32) + append_args[0] = t.CSizeT(first_elem_val) + HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "append", storage_ptr, append_args, 1, trans) + + # 翻译剩余元素 + i: t.CSizeT = 1 + while i < elts_count: + elem_node_i: ast.AST | t.CPtr = elts.get(i) + elem_val_i: llvmlite.Value | t.CPtr = self.translate_value(builder, pool, mod, elem_node_i, None, 0, trans) + if elem_val_i is not None: + ap_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if ap_args is not None: + string.memset(ap_args, 0, 8 * 32) + ap_args[0] = t.CSizeT(elem_val_i) + HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "append", storage_ptr, ap_args, 1, trans) + i += 1 + + return storage_ptr + + # ============================================================ + # 翻译值表达式(RHS 分派)— 模块级版本 + # ============================================================ + def translate_value(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr = None, + func_count: int = 0, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译值表达式为 LLVM Value""" + if node is None: + return None + k: int = node.kind() + if k == ast.ASTKind.Constant: + rv: llvmlite.Value | t.CPtr = self.translate_constant(builder, pool, mod, node, trans) + return rv + elif k == ast.ASTKind.Name: + return self.translate_name_value(builder, pool, node, trans) + elif k == ast.ASTKind.BinOp: + return self.translate_binop(pool, builder, mod, node, trans) + elif k == ast.ASTKind.Call: + return HandlesExprCall.translate_call(pool, builder, mod, node, + funcs_ptr, func_count, trans) + elif k == ast.ASTKind.Compare: + return self.translate_compare(builder, pool, mod, node, trans) + elif k == ast.ASTKind.UnaryOp: + return self.translate_unaryop(builder, pool, mod, node, trans) + elif k == ast.ASTKind.BoolOp: + return self.translate_boolop(builder, pool, mod, node, + funcs_ptr, func_count, trans) + elif k == ast.ASTKind.Subscript: + return self.translate_subscript(builder, pool, mod, node, trans) + elif k == ast.ASTKind.Attribute: + return self.translate_attribute(builder, pool, mod, node, trans) + elif k == ast.ASTKind.List: + return self.translate_list_literal(builder, pool, mod, node, None, trans) + elif k == ast.ASTKind.IfExp: + return self.translate_ifexp(builder, pool, mod, node, trans) + return None + + # ============================================================ + # 翻译三元表达式 IfExp(test, body, orelse) + # + # 生成: cond ? body : orelse + # then_blk: 翻译 body → br merge + # else_blk: 翻译 orelse → br merge + # merge_blk: phi [body_val, then_blk], [orelse_val, else_blk] + # ============================================================ + def translate_ifexp(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译三元表达式 (body if test else orelse),返回 phi 结果 Value""" + if node is None or builder is None or trans is None: + return None + ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) + if ie is None: + return None + + func: llvmlite.Function | t.CPtr = trans._cur_func + if func is None: + return None + + # 1. 求值条件 + cond_val: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, ie.test, None, 0, trans) + if cond_val is None: + return None + # 转换为 i1 + cond_bits: int = self.get_llvm_type_bits(cond_val.Ty) + if cond_bits == 1: + cond_i1: llvmlite.Value | t.CPtr = cond_val + else: + if self.is_ptr_type(cond_val.Ty) != 0: + # 指针类型:与 null 比较 + 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) + + # 2. 创建三个基本块 + cnt: int = trans._label_counter + trans._label_counter = cnt + 1 + name_buf: t.CChar | t.CPtr = pool.alloc(32) + if name_buf is None: + return None + viperlib.snprintf(name_buf, 32, "ifexp.then.%d", cnt) + then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "ifexp.else.%d", cnt) + else_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + viperlib.snprintf(name_buf, 32, "ifexp.merge.%d", cnt) + merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + if then_bb is None or else_bb is None or merge_bb is None: + return None + + # 3. 条件跳转 + llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb) + + # 4. then 分支 + llvmlite.position_at_end(builder, then_bb) + body_val: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, ie.body, None, 0, trans) + then_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock + if body_val is None: + body_val = llvmlite.const_int32(pool, 0) + # 暂不 br,等类型对齐后再 br + + # 5. else 分支 + llvmlite.position_at_end(builder, else_bb) + orelse_val: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, ie.orelse, None, 0, trans) + else_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock + if orelse_val is None: + orelse_val = llvmlite.const_int32(pool, 0) + # 暂不 br,等类型对齐后再 br + + # 类型对齐 (两分支类型可能不同) + # 必须在各自分支中执行 coerce_to_type,确保 merge 块中 PHI 是第一条指令 + # (否则 coerce_to_type 生成的 sext/zext/ptrtoint/inttoptr 指令在 PHI 之前,违反 LLVM 规则) + body_bits: int = self.get_llvm_type_bits(body_val.Ty) + orelse_bits: int = self.get_llvm_type_bits(orelse_val.Ty) + body_is_ptr: int = self.is_ptr_type(body_val.Ty) + orelse_is_ptr: int = self.is_ptr_type(orelse_val.Ty) + # 情况0: 一侧是指针,另一侧是整数(如 i64 vs i8* null) + # 必须优先处理,因为 Ptr 的 bits=0 会导致下面三个分支全部跳过 + # 选择 body_val.Ty 作为 phi_ty(then 分支优先),orelse_val 对齐到它 + # coerce_to_type 内部会调用 ptrtoint(指针→整数)或 inttoptr(整数→指针) + if body_is_ptr != orelse_is_ptr: + llvmlite.position_at_end(builder, else_blk_for_phi) + orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) + elif body_bits > orelse_bits and orelse_bits > 0: + # 在 else 块中转换 orelse_val + llvmlite.position_at_end(builder, else_blk_for_phi) + orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) + elif orelse_bits > body_bits and body_bits > 0: + # 回到 then 块转换 body_val + llvmlite.position_at_end(builder, then_blk_for_phi) + body_val = self.coerce_to_type(builder, body_val, orelse_val.Ty, node) + elif body_bits == orelse_bits and body_bits > 0: + # bits 相同但类型不同(如 i64 vs Ptr):null 不能用于 i64 PHI + # 此分支理论上不会触发(已被情况0覆盖),保留作为防御 + if self.is_ptr_type(body_val.Ty) != self.is_ptr_type(orelse_val.Ty): + llvmlite.position_at_end(builder, else_blk_for_phi) + orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) + + # 现在分别在 then/else 块中 br 到 merge(在类型转换之后) + llvmlite.position_at_end(builder, then_blk_for_phi) + llvmlite.build_br(builder, merge_bb) + llvmlite.position_at_end(builder, else_blk_for_phi) + llvmlite.build_br(builder, merge_bb) + + # 6. merge 块: phi(PHI 是 merge 块的第一条指令) + llvmlite.position_at_end(builder, merge_bb) + + phi_ty: llvmlite.LLVMType | t.CPtr = body_val.Ty + if phi_ty is None: + phi_ty = llvmlite.Int32(pool) + + inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( + pool, body_val, then_blk_for_phi) + inc2: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( + pool, orelse_val, else_blk_for_phi) + if inc1 is None or inc2 is None: + return None + # 链表顺序: inc1 (head) -> inc2 (tail) + # 之前错误写成 inc2.Next = inc1,导致 build_phi 从 inc1 遍历时 + # inc1.Next 为 None,只输出一个 phi 条目,引发 LLVM 验证错误: + # "PHINode should have one entry for each predecessor" + inc1.Next = inc2 + return llvmlite.build_phi(builder, phi_ty, inc1, 2) + + # ============================================================ + # 翻译比较表达式 Compare(left, ops, comparators) + # ============================================================ + def should_zext_widen(self, pool: memhub.MemBuddy | t.CPtr, + narrow_val: llvmlite.Value | t.CPtr, + wide_val: llvmlite.Value | t.CPtr, + narrow_node: ast.AST | t.CPtr = None) -> int: + """判断整数拓宽方向:1=zext(无符号语义),0=sext + + 对齐 TPC 的 _check_node_unsigned / HandlesExprOps 拓宽规则: + 1. i1 (bool) → zext(1 保持 1,而非 sext 的 0xFF...) + 2. i8 → zext(系统编程中 i8 几乎总是无符号字节) + 3. 宽侧是常量且其值超出窄侧位宽的有符号范围 → zext + (常量"想要"无符号解释,如 0xAABBCCDD > INT32_MAX 与 + t.CUInt32T 值比较,sext 会把 0xAABBCCDD 变成 + 0xFFFFFFFFAABBCCDD 导致恒不等) + """ + if narrow_val is None or narrow_val.Ty is None: + return 0 + narrow_bits: int = self.get_llvm_type_bits(narrow_val.Ty) + if narrow_bits == 1: + return 1 + if narrow_bits == 8: + return 1 + # 宽侧常量启发式 + if wide_val is not None and wide_val.IsConst == 1: + wide_bits: int = self.get_llvm_type_bits(wide_val.Ty) + if wide_bits > narrow_bits and narrow_bits < 64: + signed_max: t.CInt64T = (t.CInt64T(1) << (narrow_bits - 1)) - 1 + if wide_val.IntVal > signed_max: + return 1 + # 窄侧 AST 节点解析为无符号类型(如 t.CUIntXXT 字面量/强转) + if narrow_node is not None: + if self._node_type_unsigned(pool, narrow_node) != 0: + return 1 + return 0 + + def _node_type_unsigned(self, pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> int: + """轻量判断 AST 节点是否解析为无符号整数类型(1=是,0=否/未知) + + 覆盖常见形态(对齐 TPC _check_node_unsigned 的 Call/Subscript 分支): + - t.CUInt8T/CUInt16T/CUInt32T/CUInt64T/CUnsigned* 等显式无符号类型强转调用 + - 无符号类型名的 Name 引用(如 UInt32T 别名) + - 变量名(trans 可用时):查询 SymTab 中变量的 AnnotClassName(如 v: t.CUInt32T) + """ + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0 \ + and at.attr is not None: + if self._type_name_unsigned(at.attr) != 0: + return 1 + return 0 + if k == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm.id is not None: + # 1) 名字本身是无符号类型名(如 UInt32T 别名) + if self._type_name_unsigned(nm.id) != 0: + return 1 + # 2) 变量注解类型为无符号类型(trans 可用时查 SymTab) + if trans is not None: + ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm.id) + if ve is not None and ve.AnnotClassName is not None: + if self._type_name_unsigned(ve.AnnotClassName) != 0: + return 1 + return 0 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if self._node_type_unsigned(pool, bop.left, trans) != 0: + return 1 + if self._node_type_unsigned(pool, bop.right, trans) != 0: + return 1 + return 0 + if k == ast.ASTKind.UnaryOp: + uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if self._node_type_unsigned(pool, uop.operand, trans) != 0: + return 1 + return 0 + return 0 + + def _type_name_unsigned(self, type_name: str) -> int: + """类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)""" + if type_name is None: + return 0 + # t.CUIntXXT 形式 + if string.strcmp(type_name, "CUInt8T") == 0: return 1 + if string.strcmp(type_name, "CUInt16T") == 0: return 1 + if string.strcmp(type_name, "CUInt32T") == 0: return 1 + if string.strcmp(type_name, "CUInt64T") == 0: return 1 + # stdint 裸别名(from stdint import *) + if string.strcmp(type_name, "UInt8T") == 0: return 1 + if string.strcmp(type_name, "UInt16T") == 0: return 1 + if string.strcmp(type_name, "UInt32T") == 0: return 1 + if string.strcmp(type_name, "UInt64T") == 0: return 1 + # CUnsigned* 形式 + if string.strcmp(type_name, "CUnsignedChar") == 0: return 1 + if string.strcmp(type_name, "CUnsignedShort") == 0: return 1 + if string.strcmp(type_name, "CUnsignedInt") == 0: return 1 + if string.strcmp(type_name, "CUnsignedLong") == 0: return 1 + if string.strcmp(type_name, "CUnsignedLongLong") == 0: return 1 + # 常见无符号别名 + if string.strcmp(type_name, "BYTE") == 0: return 1 + if string.strcmp(type_name, "UCHAR") == 0: return 1 + if string.strcmp(type_name, "USHORT") == 0: return 1 + if string.strcmp(type_name, "UINT") == 0: return 1 + if string.strcmp(type_name, "ULONG") == 0: return 1 + return 0 + + def translate_compare(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译比较表达式,返回 i1 结果""" + cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) + if cmp is None: + return None + + ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops) + if ops_list is None or ops_list.__len__() == 0: + return None + op: int = ops_list.get(0) + + comparators: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators + if comparators is None or comparators.__len__() == 0: + return None + rhs_node: ast.AST | t.CPtr = comparators.get(0) + rhs: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, rhs_node, None, 0, trans) + if rhs is None: + return None + + # === None 比较优化: x == None / x != None 走身份比较(icmp eq/ne null)=== + # 避免对结构体指针生成无效的 __eq__/__ne__ 调用(方法未定义但类有 SHA1 时 + # try_operator_overload 会误生成 call void @...__eq__(...) 导致链接错误) + # 语义依据: Python 中 == None / != None 默认走身份比较,不调用 __eq__/__ne__ + lhs_node: ast.AST | t.CPtr = cmp.left + cmp_with_none: int = 0 + if op == ast.OpKind.Eq or op == ast.OpKind.Ne or op == ast.OpKind.Is or op == ast.OpKind.IsNot: + if rhs_node is not None and rhs_node.kind() == ast.ASTKind.Constant: + rhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rhs_node) + if rhs_cn is not None and rhs_cn.const_kind == ast.CONST_NONE: + cmp_with_none = 1 + if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Constant: + lhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(lhs_node) + if lhs_cn is not None and lhs_cn.const_kind == ast.CONST_NONE: + cmp_with_none = 1 + + # === 比较运算符重载路径 1: lhs 是 Name 且对应结构体变量 === + # 对于值类型变量(如 cnt: Counter),用 alloca 指针尝试重载 + # None 比较跳过重载(走身份比较) + if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) + if nm is not None and nm.id is not None: + lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, nm.id) + if lhs_alloca is not None: + ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload( + pool, builder, mod, lhs_alloca, rhs, op, trans, 1) + if ovl_result is not None: + return ovl_result + + # 正常翻译 lhs + lhs: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, cmp.left, None, 0, trans) + if lhs is None: + return None + + # === 比较运算符重载路径 2: lhs 是 Ptr(Struct) === + # Is/IsNot 不在 _cmpop_to_dunder 映射中,会自动返回 None 回退原生比较 + # None 比较跳过重载(走身份比较) + if cmp_with_none == 0: + ovl_result2: llvmlite.Value | t.CPtr = self.try_operator_overload( + pool, builder, mod, lhs, rhs, op, trans, 1) + if ovl_result2 is not None: + return ovl_result2 + + predicate: int = llvmlite.ICMP_SLT + if op == ast.OpKind.Lt: + predicate = llvmlite.ICMP_SLT + elif op == ast.OpKind.Le: + predicate = llvmlite.ICMP_SLE + elif op == ast.OpKind.Gt: + predicate = llvmlite.ICMP_SGT + elif op == ast.OpKind.Ge: + predicate = llvmlite.ICMP_SGE + elif op == ast.OpKind.Eq: + predicate = llvmlite.ICMP_EQ + elif op == ast.OpKind.Ne: + predicate = llvmlite.ICMP_NE + elif op == ast.OpKind.Is: + # `x is y` → 指针/值相等比较 + predicate = llvmlite.ICMP_EQ + elif op == ast.OpKind.IsNot: + # `x is not y` → 指针/值不等比较 + predicate = llvmlite.ICMP_NE + + # === 类型安全检查(BUG2 修复)=== + # 规则: + # - 数值(0) vs 数值(0) → 允许(无关类型,按位宽 sext 对齐) + # - 一级指针(1) vs 一级指针(1) → 允许(无关 pointee 类型,地址比较) + # - 数值(0) vs 指针(1+) → 禁止(fast-fail,除 None 比较外) + # - 不同级指针(1 vs 2 等) → 禁止(fast-fail) + # + # None 比较跳过此检查(None 被翻译为 null 指针或 0,与任意指针/数值比较合法) + if cmp_with_none == 0: + lhs_ptr_level: int = self.get_ptr_level(lhs.Ty) + rhs_ptr_level: int = self.get_ptr_level(rhs.Ty) + if lhs_ptr_level != rhs_ptr_level: + # 类型不匹配:数值vs指针 或 不同级指针 + # 用 fmt_buf 构造可读消息(Viper % 格式化在部分路径生成 null) + fmt_msg: t.CChar | t.CPtr = VLogger.fmt_buf() + if fmt_msg is not None: + viperlib.snprintf( + fmt_msg, 1024, + "比较类型不匹配(行 %d): lhs 层级=%d (ty=%p), rhs 层级=%d (ty=%p)", + cmp.lineno, lhs_ptr_level, lhs.Ty, rhs_ptr_level, rhs.Ty) + VLogger.error(fmt_msg, "Compare") + else: + VLogger.error("比较类型不匹配: 数值与指针/不同级指针比较", "Compare") + return None + else: + # None 比较: None 被翻译为 i8* null(一级指针) + # 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型 + # 如果 lhs 是数值,将 rhs 转为数值 0(走正常整数比较) + # 如果 lhs 是结构体值类型,结构体永远不等于 None,返回常量 i1 + lhs_ptr_level_none: int = self.get_ptr_level(lhs.Ty) + rhs_ptr_level_none: int = self.get_ptr_level(rhs.Ty) + if lhs_ptr_level_none != 0 and rhs_ptr_level_none != 0: + # 两边都是指针,类型可能不同(如 lhs=Struct*, rhs=i8* null) + # 由下方 bitcast 对齐处理,此处不处理 + pass + elif lhs_ptr_level_none != 0 and rhs_ptr_level_none == 0: + # lhs 是指针, rhs 是数值 → 将 rhs 转为同层级 null 指针 + rhs = llvmlite.ConstNull(pool, lhs.Ty, None) + elif rhs_ptr_level_none != 0 and lhs_ptr_level_none == 0: + # 检查 lhs 是否是结构体值类型(非指针的 Struct) + lhs_is_struct_none: int = 0 + match lhs.Ty: + case llvmlite.LLVMType.Struct(_, _, _): + lhs_is_struct_none = 1 + case _: + lhs_is_struct_none = 0 + if lhs_is_struct_none != 0: + # 结构体值永远不等于 None:==/is 返回 false,!=/is not 返回 true + if op == ast.OpKind.Eq or op == ast.OpKind.Is: + return llvmlite.const_int(pool, 1, 0) + else: # Ne, IsNot + return llvmlite.const_int(pool, 1, 1) + # lhs 是数值, rhs 是 i8* null → 将 rhs 转为数值 0(保持 lhs 不变) + rhs = llvmlite.const_int32(pool, 0) + + # 类型对齐:icmp 要求两边类型相同 + # 仅对数值类型做对齐(指针类型无需对齐,LLVM 允许同层级指针直接 icmp) + # i1 (bool) 侧用 zext 对齐(1 保持 1,而非 sext 的 0xFF...) + lhs_bits: int = self.get_llvm_type_bits(lhs.Ty) + rhs_bits: int = self.get_llvm_type_bits(rhs.Ty) + if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits: + if lhs_bits < rhs_bits: + if self.should_zext_widen(pool, lhs, rhs, cmp.left) != 0: + lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) + else: + lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) + else: + if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0: + rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) + else: + rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) + + # 指针类型对齐:同层级但不同 pointee 类型的指针需要 bitcast 统一类型 + # 例如 i8* vs Struct* → 将 rhs bitcast 为 lhs 的类型 + if lhs_bits == 0 and rhs_bits == 0: + lhs_is_ptr_now: int = self.is_ptr_type(lhs.Ty) + rhs_is_ptr_now: int = self.is_ptr_type(rhs.Ty) + if lhs_is_ptr_now != 0 and rhs_is_ptr_now != 0: + # 两边都是指针,用 TypePrint 比较类型字符串 + lhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128) + rhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128) + if lhs_ty_buf is not None and rhs_ty_buf is not None: + llvmlite.TypePrint(lhs_ty_buf, 128, lhs.Ty, pool) + llvmlite.TypePrint(rhs_ty_buf, 128, rhs.Ty, pool) + if string.strcmp(lhs_ty_buf, rhs_ty_buf) != 0: + rhs = llvmlite.build_bitcast(builder, rhs, lhs.Ty) + + # 浮点比较:任一操作数为浮点类型时使用 fcmp 而非 icmp + lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty) + rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty) + if lhs_fbits != 0 or rhs_fbits != 0: + # 浮点类型对齐(fpext/fptrunc) + if lhs_fbits != 0 and rhs_fbits != 0 and lhs_fbits != rhs_fbits: + if lhs_fbits < rhs_fbits: + lhs = llvmlite.build_fpext(builder, lhs, rhs.Ty) + else: + rhs = llvmlite.build_fptrunc(builder, rhs, lhs.Ty) + elif lhs_fbits != 0 and rhs_fbits == 0: + # int → float + rhs = llvmlite.build_si2fp(builder, rhs, lhs.Ty) + elif rhs_fbits != 0 and lhs_fbits == 0: + lhs = llvmlite.build_si2fp(builder, lhs, rhs.Ty) + # 映射比较谓词到 fcmp + fpredicate: int = llvmlite.FCMP_OEQ + if op == ast.OpKind.Eq or op == ast.OpKind.Is: + fpredicate = llvmlite.FCMP_OEQ + elif op == ast.OpKind.Ne or op == ast.OpKind.IsNot: + fpredicate = llvmlite.FCMP_ONE + elif op == ast.OpKind.Lt: + fpredicate = llvmlite.FCMP_OLT + elif op == ast.OpKind.Le: + fpredicate = llvmlite.FCMP_OLE + elif op == ast.OpKind.Gt: + fpredicate = llvmlite.FCMP_OGT + elif op == ast.OpKind.Ge: + fpredicate = llvmlite.FCMP_OGE + return llvmlite.build_fcmp(builder, fpredicate, lhs, rhs) + + return llvmlite.build_icmp(builder, predicate, lhs, rhs) + + # ============================================================ + # 翻译一元运算表达式 UnaryOp(op, operand) + # ============================================================ + def translate_unaryop(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译一元运算(-x, +x, not x, ~x)""" + uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) + if uo is None: + return None + + operand: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, uo.operand, None, 0, trans) + if operand is None: + return None + + # === 一元运算符重载: -obj/+obj/~obj 调用 __neg__/__pos__/__invert__ === + # 仅 USub/UAdd/Invert 有重载语义(not 无 dunder 方法) + if uo.op == ast.OpKind.USub or uo.op == ast.OpKind.UAdd or uo.op == ast.OpKind.Invert: + ovl_u: llvmlite.Value | t.CPtr = self.try_unary_operator_overload( + pool, builder, mod, operand, uo.op, trans) + if ovl_u is not None: + return ovl_u + + if uo.op == ast.OpKind.USub: + # -x + # 浮点类型用 fneg(直接生成 fneg 指令,避免 0.0 - x 的类型不匹配) + operand_fbits: int = self.get_llvm_float_bits(operand.Ty) + if operand_fbits > 0: + return llvmlite.build_fneg(builder, operand) + # 整数类型:-x = 0 - x,根据位宽选择零值常量(避免 i32 与 i64 类型不匹配) + operand_bits: int = self.get_llvm_type_bits(operand.Ty) + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + if operand_bits == 64: + zero = llvmlite.const_int64(pool, 0) + elif operand_bits > 0 and operand_bits != 32: + # 其他位宽(i8/i16 等):用 i32 零值,operand 会被 coerce + zero = llvmlite.const_int32(pool, 0) + return llvmlite.build_sub(builder, zero, operand) + elif uo.op == ast.OpKind.UAdd: + # +x = x + return operand + elif uo.op == ast.OpKind.Not: + # not x = (x == 0/null),返回 i1 + if self.is_ptr_type(operand.Ty) != 0: + # 指针类型:与 null 比较 + null_op: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, operand.Ty, "null") + return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, null_op) + # 结构体值类型:永远为真(非空),not 返回 false + operand_is_struct_not: int = 0 + match operand.Ty: + case llvmlite.LLVMType.Struct(_, _, _): + operand_is_struct_not = 1 + case _: + operand_is_struct_not = 0 + if operand_is_struct_not != 0: + return llvmlite.const_int(pool, 1, 0) + operand_bits_not: int = self.get_llvm_type_bits(operand.Ty) + zero = llvmlite.const_int32(pool, 0) + if operand_bits_not == 64: + zero = llvmlite.const_int64(pool, 0) + return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, zero) + elif uo.op == ast.OpKind.Invert: + # ~x = x ^ -1 + operand_bits_inv: int = self.get_llvm_type_bits(operand.Ty) + neg1: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, -1) + if operand_bits_inv == 64: + neg1 = llvmlite.const_int64(pool, -1) + return llvmlite.build_xor(builder, operand, neg1) + return operand + + # ============================================================ + # 翻译布尔运算 BoolOp(op, values) — 短路求值,返回 i1 + # + # and: a and b and c → 若 a 为假短路到 merge(返回 a 的 i1),否则求 b, + # 最后一个值直接求值并跳 merge + # or: a or b or c → 若 a 为真短路到 merge(返回 a 的 i1),否则求 b, + # 最后一个值直接求值并跳 merge + # merge 块用 phi 合并所有入边的 i1 + # ============================================================ + def translate_boolop(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr = None, + func_count: int = 0, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译布尔运算(and/or)的短路求值,返回 i1""" + bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) + if bo is None: + return None + + op: int = bo.op + values: list[ast.AST | t.CPtr] | t.CPtr = bo.values + if values is None: + return None + count: t.CSizeT = values.__len__() + if count == 0: + return None + if count == 1: + return self.translate_value(builder, pool, mod, values.get(0), + funcs_ptr, func_count, trans) + + func: llvmlite.Function | t.CPtr = builder.Func + if func is None: + return None + + # 创建 merge BB(用 builder.Counter 生成唯一标签名,position_at_end 的 + # move_to_end 保证 BB 文本顺序与控制流顺序一致,标签名用 counter 安全) + cnt: int = builder.Counter + builder.Counter = cnt + 1 + name_buf: t.CChar | t.CPtr = pool.alloc(32) + if name_buf is None: + return None + viperlib.snprintf(name_buf, 32, "bool.merge.%d", cnt) + merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # phi 入边链表头/尾 + phi_head: llvmlite.PhiIncoming | t.CPtr = None + phi_tail: llvmlite.PhiIncoming | t.CPtr = None + phi_count: int = count - 1 # 循环次数 + + # 对每个值(除最后一个)求值并短路 + for i in range(count - 1): + val_node: ast.AST | t.CPtr = values.get(i) + val: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, val_node, + funcs_ptr, func_count, trans) + if val is None: + return None + + # 转为 i1(已经是 i1 的直接用,否则与 0/null 比较) + val_bits: int = self.get_llvm_type_bits(val.Ty) + val_i1: llvmlite.Value | t.CPtr = val + if val_bits != 1: + if self.is_ptr_type(val.Ty) != 0: + # 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配) + null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, val.Ty, "null") + val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, null_val) + else: + zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero) + + # 创建 next BB(求值下一个值) + cnt = builder.Counter + builder.Counter = cnt + 1 + viperlib.snprintf(name_buf, 32, "bool.next.%d", cnt) + next_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) + + # and: 短路假→merge,真→next;or: 短路真→merge,假→next + if op == ast.OpKind.And: + llvmlite.build_cond_br(builder, val_i1, next_bb, merge_bb) + else: + llvmlite.build_cond_br(builder, val_i1, merge_bb, next_bb) + + # 添加 phi 入边:(val_i1, cond_br 所在 BB) + cur_bb: llvmlite.BasicBlock | t.CPtr = builder.CurBlock + inc: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, val_i1, cur_bb) + if phi_head is None: + phi_head = inc + phi_tail = inc + else: + phi_tail.Next = inc + phi_tail = inc + + # 定位到 next BB,求值下一个值 + llvmlite.position_at_end(builder, next_bb) + + # 最后一个值:求值后直接跳 merge + last_node: ast.AST | t.CPtr = values.get(count - 1) + last_val: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, last_node, + funcs_ptr, func_count, trans) + if last_val is None: + return None + last_bits: int = self.get_llvm_type_bits(last_val.Ty) + last_i1: llvmlite.Value | t.CPtr = last_val + if last_bits != 1: + if self.is_ptr_type(last_val.Ty) != 0: + # 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配) + null_val2: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, last_val.Ty, "null") + last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, null_val2) + else: + zero = llvmlite.const_int32(pool, 0) + last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, zero) + + llvmlite.build_br(builder, merge_bb) + + cur_bb = builder.CurBlock + inc = llvmlite.new_phi_incoming(pool, last_i1, cur_bb) + if phi_head is None: + phi_head = inc + else: + phi_tail.Next = inc + phi_count += 1 + + # 定位到 merge,创建 phi 合并所有入边 + llvmlite.position_at_end(builder, merge_bb) + i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + return llvmlite.build_phi(builder, i1_ty, phi_head, phi_count) + + # ============================================================ + # _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径 + # + # .vpi 文件可能未生成(Phase1 未输出 vpi),此时回退读取源 .py 文件。 + # 从 StubMerger 全局存储器查找 SHA1 对应的相对路径, + # 根据 rel_path 前缀选择基础目录: + # - rel_path 以 "lib/" 开头 → App 源文件,用 {Config.SourceDir}/{rel_path} + # - 其他 → includes 文件,用 {Config.IncludesDir}/{rel_path} + # + # Returns: + # stdlib.malloc 分配的路径字符串(调用者负责 free),None 失败 + # ============================================================ + def _build_source_path_from_sha1(self, sha1: str) -> str: + """通过 SHA1 从全局存储器构建源 .py 文件路径""" + if sha1 is None: + return None + if Config.IncludesDir is None: + return None + # 从 StubMerger 全局存储器获取相对路径数组 + rel_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr() + count: int = StubMerger.GetSha1StoreCount() + if rel_arr_ptr is None or count <= 0: + return None + sha1_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr() + if sha1_arr_ptr is None: + return None + # 遍历查找匹配的 SHA1 + idx_s: int = -1 + for i in range(count): + sidx: t.CSizeT = t.CSizeT(i) * 17 + cur_sha1: str = sha1_arr_ptr + sidx + if cur_sha1[0] == '\0': + continue + if string.strcmp(cur_sha1, sha1) == 0: + idx_s = i + break + if idx_s < 0: + return None + # 获取相对路径(MAX_REL_PATH_LEN=256,避免跨模块 CDefine 解析问题) + MAX_RPL: t.CSizeT = 256 + ridx: t.CSizeT = t.CSizeT(idx_s) * MAX_RPL + rel_path: str = rel_arr_ptr + ridx + if rel_path[0] == '\0': + return None + # 选择基础目录:rel_path 以 "lib/" 开头 → App 源文件(SourceDir),否则 includes 文件 + base_dir: str = Config.IncludesDir + is_app: int = 0 + if string.strlen(rel_path) >= 4: + if (rel_path[0] == 'l' and rel_path[1] == 'i' and + rel_path[2] == 'b' and rel_path[3] == '/'): + is_app = 1 + if is_app != 0 and Config.SourceDir is not None: + base_dir = Config.SourceDir + # 构建完整路径: {base_dir}/{rel_path} + base_len: t.CSizeT = string.strlen(base_dir) + rel_len: t.CSizeT = string.strlen(rel_path) + path_len: t.CSizeT = base_len + rel_len + 2 + buf: str = stdlib.malloc(path_len) + if buf is None: + return None + viperlib.snprintf(buf, path_len, "%s/%s", base_dir, rel_path) + return buf + + # ============================================================ + # _lookup_cross_module_cdefine - 跨模块查找 CDefine 常量 + # + # 当当前模块的 CDefine 表中找不到某个 Name 时,从 from_imports + # 解析出源模块,再从该模块的 pyi 文件中解析 CDefine 常量值。 + # 找到后缓存到当前模块的 CDefine 表中,避免重复查找。 + # + # pyi 文件格式: "NAME: t.CDefine = value" + # ============================================================ + def _lookup_cross_module_cdefine(self, pool: memhub.MemBuddy | t.CPtr, + name: str, + from_imports: str, + imported_modules: str = None) -> int: + """跨模块查找 CDefine 常量,返回值或 -1(未找到) + + 查找顺序: + 1. from_imports 精确匹配(from X import NAME) + 2. from_imports star 回退(from X import *) + 3. imported_modules 遍历(import X):当通过 import X 导入模块时, + 模块中定义的 CDefine 常量可通过此路径找到(如方法签名默认参数引用) + """ + # 入口处清零标志,确保所有早退路径(return -1)都返回"未找到"状态 + # 避免递归调用时前一次成功的标志残留导致误判 + HandlesType.set_cdefine_found(0) + if name is None: + return -1 + if from_imports is None: + from_imports = "" + + # 1. 从 from_imports 查找名称对应的模块名 + # 先尝试精确匹配(allow_star_fallback=0),避免 CDefine 常量被 star import 误导 + mod_name_raw: str = HandlesImports.lookup_from_import(from_imports, name, 0) + if mod_name_raw is None: + # 精确匹配失败:尝试 star import 回退 + mod_name_raw = HandlesImports.lookup_from_import(from_imports, name, 1) + + # 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6) + # 注意:star fallback 可能返回错误模块(如 stdint),常量实际不在其中, + # 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules + if mod_name_raw is None: + # from_imports 完全没有匹配(精确和 star 都失败) + # 直接进入 imported_modules 遍历(步骤 9.6) + if imported_modules is None: + return -1 + # 跳过 from_imports 模块读取,直接走步骤 9.6 的 imported_modules 遍历 + # 设置 result_found=0 跳过步骤 3-9,直接到 9.6 + HandlesType.set_cdefine_found(0) + # 直接遍历 imported_modules + im_len: t.CSizeT = string.strlen(imported_modules) + im_ci: t.CSizeT = 0 + while im_ci < im_len: + while im_ci < im_len and imported_modules[im_ci] == ' ': + im_ci += 1 + if im_ci >= im_len: + break + im_start: t.CSizeT = im_ci + while im_ci < im_len and imported_modules[im_ci] != ' ': + im_ci += 1 + im_end: t.CSizeT = im_ci + im_nlen: t.CSizeT = im_end - im_start + if im_nlen > 0 and im_nlen < 256: + im_buf: str = pool.alloc(im_nlen + 1) + if im_buf is not None: + mk: t.CSizeT = 0 + while mk < im_nlen: + im_buf[mk] = imported_modules[im_start + mk] + mk += 1 + im_buf[im_nlen] = '\0' + sub_fi: str = pool.alloc(im_nlen + 3) + if sub_fi is not None: + sub_fi[0] = '*' + sub_fi[1] = ':' + mk2: t.CSizeT = 0 + while mk2 < im_nlen: + sub_fi[2 + mk2] = im_buf[mk2] + mk2 += 1 + sub_fi[2 + im_nlen] = '\0' + sub_val: int = self._lookup_cross_module_cdefine(pool, name, sub_fi, None) + if HandlesType.is_cdefine_found() != 0: + return sub_val + return -1 + + # 2. 截断模块名 → 去前导点 → 精确+后缀查找 SHA1(复用 HandlesExprCall 公共逻辑) + sha1: str = HandlesExprCall._lookup_sha1_from_modname_raw(pool, mod_name_raw) + if sha1 is None: + return -1 + + # 5. 获取 temp_dir + temp_dir: str = HandlesType.get_temp_dir() + if temp_dir is None: + return -1 + + # 6. 构建 vpi 文件路径 + td_len: t.CSizeT = string.strlen(temp_dir) + pyi_path: str = StubMerger._sliced_path(temp_dir, td_len, sha1, "vpi") + if pyi_path is None: + return -1 + + # 7. 读取 vpi 文件;若不存在或内容过短(空 stub)则回退读取源 .vp/.py 文件 + PYI_READ_BUF_SIZE: t.CSizeT = 65536 + pyi_buf: bytes = stdlib.malloc(PYI_READ_BUF_SIZE) + if pyi_buf is None: + stdlib.free(pyi_path) + return -1 + pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.R) + need_py_fallback: int = 0 + bytes_read: LONG = 0 + if pf.closed: + # .vpi 文件不存在:回退读取源 .vp/.py 文件 + need_py_fallback = 1 + else: + bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE) + pf.close() + # vpi 内容过短(< 10 字节)视为空 stub,回退 .py + if bytes_read < 10: + need_py_fallback = 1 + else: + if bytes_read < PYI_READ_BUF_SIZE: + pyi_buf[bytes_read] = 0 + else: + pyi_buf[PYI_READ_BUF_SIZE - 1] = 0 + stdlib.free(pyi_path) + + if need_py_fallback != 0: + # 从 SHA1 存储器查找相对路径,构建 {base_dir}/{rel_path} + src_path: str = self._build_source_path_from_sha1(sha1) + if src_path is None: + # 存储器中找不到 SHA1 = 编译器 bug(Phase1/Phase2 未填充存储器) + # 报错终止,不静默返回 -1(避免后续生成错误的 @UNDEFINED 全局变量引用) + err_buf: str = pool.alloc(512) + if err_buf is not None: + viperlib.snprintf(err_buf, 512, + "跨模块 CDefine 查找失败:SHA1 %s 不在存储器中(base_mod=%s name=%s)。" + "Phase1/Phase2 未正确填充 PopulateSha1MapStore/AppendToSha1MapStore", + sha1, base_mod, name) + VLogger.error(err_buf, "XMOD-CD") + stdlib.free(pyi_buf) + return -1 + pf = fileio.File(src_path, fileio.MODE.R) + stdlib.free(src_path) + if pf.closed: + stdlib.free(pyi_buf) + return -1 + bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE) + pf.close() + if bytes_read <= 0: + stdlib.free(pyi_buf) + return -1 + if bytes_read < PYI_READ_BUF_SIZE: + pyi_buf[bytes_read] = 0 + else: + pyi_buf[PYI_READ_BUF_SIZE - 1] = 0 + + # 8. 在 pyi_buf 中查找 "name: t.CDefine = value" 行 + # 格式: NAME: t.CDefine = value + name_len: t.CSizeT = string.strlen(name) + total_len: t.CSizeT = string.strlen(pyi_buf) + pos: t.CSizeT = 0 + result_val: int = 0 + result_found: int = 0 + while pos < total_len: + # 找到行首 + line_start: t.CSizeT = pos + # 找到行尾 + while pos < total_len and pyi_buf[pos] != '\n': + pos += 1 + line_len: t.CSizeT = pos - line_start + if pos < total_len: + pos += 1 # 跳过 '\n' + + # 检查行是否以 "name:" 开头 + if line_len < name_len + 1: + continue + match_ok: int = 1 + for ki in range(name_len): + if pyi_buf[line_start + ki] != name[ki]: + match_ok = 0 + break + if match_ok == 0: + continue + if pyi_buf[line_start + name_len] != ':': + continue + + # 检查行是否包含 "t.CDefine" + # 在行中查找 "t.CDefine" + has_cdefine: int = 0 + ci: t.CSizeT = line_start + name_len + 1 + while ci + 8 <= line_start + line_len: + if (pyi_buf[ci] == 't' and pyi_buf[ci + 1] == '.' and + pyi_buf[ci + 2] == 'C' and pyi_buf[ci + 3] == 'D' and + pyi_buf[ci + 4] == 'e' and pyi_buf[ci + 5] == 'f' and + pyi_buf[ci + 6] == 'i' and pyi_buf[ci + 7] == 'n' and + pyi_buf[ci + 8] == 'e'): + has_cdefine = 1 + break + ci += 1 + if has_cdefine == 0: + continue + + # 找到 "=" 后面的值 + eq_pos: t.CSizeT = line_start + name_len + 1 + while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '=': + eq_pos += 1 + if eq_pos >= line_start + line_len: + continue + eq_pos += 1 # 跳过 '=' + + # 跳过空格 + while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': + eq_pos += 1 + + # 检查是否是 t.CUnsignedLong(...) / t.CLong(...) / t.CInt(...) 等类型构造函数 + # 格式: t.CUnsignedLong(-11) / t.CUnsignedLong(0xFFFFFFFF) + # 如果是,跳过 "t.CXxx(" 前缀,解析括号内的值,忽略结尾 ')' + is_type_ctor: int = 0 + if eq_pos + 2 < line_start + line_len: + if pyi_buf[eq_pos] == 't' and pyi_buf[eq_pos + 1] == '.': + # 找到 '(' 的位置 + paren_pos: t.CSizeT = eq_pos + 2 + while paren_pos < line_start + line_len and pyi_buf[paren_pos] != '(': + paren_pos += 1 + if paren_pos < line_start + line_len and pyi_buf[paren_pos] == '(': + is_type_ctor = 1 + eq_pos = paren_pos + 1 # 跳过 '(' + # 跳过括号内可能的前导空格 + while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': + eq_pos += 1 + + # 解析整数值(支持十六进制 0x 前缀和负号) + # 负号标记 + is_neg: int = 0 + if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-': + is_neg = 1 + eq_pos += 1 + val_str_start: t.CSizeT = eq_pos + val_str_len: t.CSizeT = 0 + is_hex: int = 0 + if eq_pos + 1 < line_start + line_len: + if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'): + is_hex = 1 + val_str_len = 2 + eq_pos += 2 + while eq_pos < line_start + line_len: + ch: t.CChar = pyi_buf[eq_pos] + if is_hex == 1: + if ((ch >= '0' and ch <= '9') or + (ch >= 'a' and ch <= 'f') or + (ch >= 'A' and ch <= 'F')): + val_str_len += 1 + eq_pos += 1 + else: + break + else: + if ch >= '0' and ch <= '9': + val_str_len += 1 + eq_pos += 1 + else: + break + + if val_str_len == 0: + continue + + # 复制值字符串到新缓冲区并解析 + val_buf: str = pool.alloc(val_str_len + 1) + if val_buf is None: + continue + for vi in range(val_str_len): + val_buf[vi] = pyi_buf[val_str_start + vi] + val_buf[val_str_len] = '\0' + + if is_hex == 1: + # 手动解析十六进制(跳过 0x 前缀) + hex_result: int = 0 + hex_buf: str = val_buf + 2 # 跳过 "0x" + for hi in range(val_str_len - 2): + hc: t.CChar = hex_buf[hi] + hd: int = 0 + if hc >= '0' and hc <= '9': + hd = hc - '0' + elif hc >= 'a' and hc <= 'f': + hd = hc - 'a' + 10 + elif hc >= 'A' and hc <= 'F': + hd = hc - 'A' + 10 + else: + break + hex_result = hex_result * 16 + hd + result_val = hex_result + # 十六进制负值(如 0xFFFFFFFF)保持原样,由 32 位截断处理 + result_found = 1 + else: + result_val = string.atoi(val_buf) + # 应用负号(如 t.CUnsignedLong(-11) → -11) + if is_neg != 0: + result_val = -result_val + result_found = 1 + break + + # 9.5 如果当前模块文件中没找到,递归查找子模块 + # 处理 from .X import NAME 和 from .X import * 的情况 + # 例如 ast.__init__.vp 中 from .base import CONST_INT, ... + # 需要递归查找 ast.base 子模块中的 CONST_INT: t.CDefine = 1 + if result_found == 0: + name_len_rc: t.CSizeT = string.strlen(name) + rc_pos: t.CSizeT = 0 + while rc_pos < total_len and result_found == 0: + # 找到行首 + rc_line_start: t.CSizeT = rc_pos + # 找到行尾 + while rc_pos < total_len and pyi_buf[rc_pos] != '\n': + rc_pos += 1 + rc_line_len: t.CSizeT = rc_pos - rc_line_start + if rc_pos < total_len: + rc_pos += 1 + + # 检查行是否以 "from ." 开头(相对导入子模块) + if rc_line_len < 12: + continue + if pyi_buf[rc_line_start] != 'f' or pyi_buf[rc_line_start+1] != 'r' or \ + pyi_buf[rc_line_start+2] != 'o' or pyi_buf[rc_line_start+3] != 'm' or \ + pyi_buf[rc_line_start+4] != ' ' or pyi_buf[rc_line_start+5] != '.': + continue + + # 提取子模块名(从 rc_line_start+6 开始,到空格/tab 为止) + rc_sub_start: t.CSizeT = rc_line_start + 6 + rc_sub_end: t.CSizeT = rc_sub_start + while rc_sub_end < rc_line_start + rc_line_len and \ + pyi_buf[rc_sub_end] != ' ' and pyi_buf[rc_sub_end] != '\t': + rc_sub_end += 1 + rc_sub_len: t.CSizeT = rc_sub_end - rc_sub_start + if rc_sub_len == 0: + continue + + # 检查行是否包含 "import" + rc_has_import: int = 0 + rc_ipos: t.CSizeT = rc_sub_end + while rc_ipos + 6 <= rc_line_start + rc_line_len: + if pyi_buf[rc_ipos] == 'i' and pyi_buf[rc_ipos+1] == 'm' and \ + pyi_buf[rc_ipos+2] == 'p' and pyi_buf[rc_ipos+3] == 'o' and \ + pyi_buf[rc_ipos+4] == 'r' and pyi_buf[rc_ipos+5] == 't': + rc_has_import = 1 + break + rc_ipos += 1 + if rc_has_import == 0: + continue + + # 检查 NAME 是否在导入列表中,或导入是 * + # 处理多行导入:from .X import (... NAME, ...) + # 从 "import" 之后扫描,如果有 "(" 则扫描到 ")" 为止 + rc_imp_start: t.CSizeT = rc_ipos + 6 + rc_star: int = 0 + rc_name_match: int = 0 + + # 确定扫描范围:单行或跨行(括号内) + rc_scan_end: t.CSizeT = rc_line_start + rc_line_len + rc_has_paren: int = 0 + rc_pp: t.CSizeT = rc_imp_start + while rc_pp < rc_line_start + rc_line_len: + if pyi_buf[rc_pp] == '(': + rc_has_paren = 1 + break + if pyi_buf[rc_pp] == '*': + rc_star = 1 + rc_pp += 1 + if rc_has_paren != 0: + # 多行导入:从 "(" 之后扫描到 ")" 为止 + rc_scan_end = rc_pp + 1 + rc_paren_closed: int = 0 + rc_sp: t.CSizeT = rc_pp + 1 + while rc_sp < total_len and rc_paren_closed == 0: + if pyi_buf[rc_sp] == ')': + rc_paren_closed = 1 + rc_scan_end = rc_sp + break + rc_sp += 1 + if rc_paren_closed == 0: + rc_scan_end = total_len + + # 在 rc_imp_start 到 rc_scan_end 范围内查找 NAME 和 * + rc_cpos: t.CSizeT = rc_imp_start + while rc_cpos < rc_scan_end: + rc_ch: t.CChar = pyi_buf[rc_cpos] + if rc_ch == '*': + rc_star = 1 + # 检查 NAME 是否匹配(作为完整单词) + if rc_cpos + name_len_rc <= rc_scan_end: + rc_match: int = 1 + rc_ki: t.CSizeT + for rc_ki in range(name_len_rc): + if pyi_buf[rc_cpos + rc_ki] != name[rc_ki]: + rc_match = 0 + break + if rc_match == 1: + # 检查前字符是否是非标识符字符 + rc_before_ok: int = 0 + if rc_cpos == rc_imp_start: + rc_before_ok = 1 + else: + rc_before_ch: t.CChar = pyi_buf[rc_cpos - 1] + if rc_before_ch == ' ' or rc_before_ch == '\t' or \ + rc_before_ch == '(' or rc_before_ch == ',' or \ + rc_before_ch == '\n' or rc_before_ch == '\r': + rc_before_ok = 1 + # 检查后字符是否是非标识符字符 + rc_after_ok: int = 0 + rc_after_pos: t.CSizeT = rc_cpos + name_len_rc + if rc_after_pos >= rc_scan_end: + rc_after_ok = 1 + else: + rc_after_ch: t.CChar = pyi_buf[rc_after_pos] + if rc_after_ch == ' ' or rc_after_ch == '\t' or \ + rc_after_ch == ')' or rc_after_ch == ',' or \ + rc_after_ch == '\r' or rc_after_ch == '\n': + rc_after_ok = 1 + if rc_before_ok == 1 and rc_after_ok == 1: + rc_name_match = 1 + rc_cpos += 1 + + if rc_star == 0 and rc_name_match == 0: + continue + + # 复制子模块名到新缓冲区(pyi_buf + rc_sub_start 不是 NUL 结尾) + rc_sub_buf: str = pool.alloc(rc_sub_len + 1) + if rc_sub_buf is None: + continue + rc_si: t.CSizeT + for rc_si in range(rc_sub_len): + rc_sub_buf[rc_si] = pyi_buf[rc_sub_start + rc_si] + rc_sub_buf[rc_sub_len] = '\0' + + # 构建完整子模块名 base_mod.X + rc_full_len: t.CSizeT = string.strlen(base_mod) + 1 + rc_sub_len + 1 + rc_full_mod: str = pool.alloc(rc_full_len) + if rc_full_mod is None: + continue + viperlib.snprintf(rc_full_mod, rc_full_len, "%s.%s", base_mod, rc_sub_buf) + + # 构建临时 from_imports "name:full_mod" + rc_fi_len: t.CSizeT = name_len_rc + 1 + string.strlen(rc_full_mod) + 1 + rc_fi: str = pool.alloc(rc_fi_len) + if rc_fi is None: + continue + viperlib.snprintf(rc_fi, rc_fi_len, "%s:%s", name, rc_full_mod) + + # 递归调用查找子模块 + rc_sub_val: int = self._lookup_cross_module_cdefine(pool, name, rc_fi) + if HandlesType.is_cdefine_found() != 0: + result_val = rc_sub_val + result_found = 1 + + stdlib.free(pyi_buf) + + # 9.6 from_imports star fallback 模块中未找到:回退到 imported_modules 遍历 + # 当 `from stdint import *` 导致 star fallback 返回 stdint,但目标常量 + # (如 SHARE_READ)实际在 `import w32.fileio` 导入的模块中时, + # 需要遍历 imported_modules 逐个查找 + if result_found == 0 and imported_modules is not None: + im2_len: t.CSizeT = string.strlen(imported_modules) + im2_ci: t.CSizeT = 0 + while im2_ci < im2_len and result_found == 0: + while im2_ci < im2_len and imported_modules[im2_ci] == ' ': + im2_ci += 1 + if im2_ci >= im2_len: + break + im2_start: t.CSizeT = im2_ci + while im2_ci < im2_len and imported_modules[im2_ci] != ' ': + im2_ci += 1 + im2_end: t.CSizeT = im2_ci + im2_nlen: t.CSizeT = im2_end - im2_start + if im2_nlen > 0 and im2_nlen < 256: + im2_buf: str = pool.alloc(im2_nlen + 1) + if im2_buf is not None: + mk3: t.CSizeT = 0 + while mk3 < im2_nlen: + im2_buf[mk3] = imported_modules[im2_start + mk3] + mk3 += 1 + im2_buf[im2_nlen] = '\0' + sub_fi2: str = pool.alloc(im2_nlen + 3) + if sub_fi2 is not None: + sub_fi2[0] = '*' + sub_fi2[1] = ':' + mk4: t.CSizeT = 0 + while mk4 < im2_nlen: + sub_fi2[2 + mk4] = im2_buf[mk4] + mk4 += 1 + sub_fi2[2 + im2_nlen] = '\0' + sub_val2: int = self._lookup_cross_module_cdefine(pool, name, sub_fi2, None) + if HandlesType.is_cdefine_found() != 0: + result_val = sub_val2 + result_found = 1 + + # 10. 缓存到当前模块的 CDefine 表中 + if result_found != 0: + HandlesType.register_cdefine_constant(pool, name, result_val) + HandlesType.set_cdefine_found(1) + else: + HandlesType.set_cdefine_found(0) + + return result_val + + # ============================================================ + # _is_cdefine_name_pattern - 检查名字是否符合 CDefine 命名约定 + # + # CDefine 常量(如 FOREGROUND_GREEN, STD_OUTPUT_HANDLE, SCOPE_MODULE) + # 都遵循 ALL_CAPS 约定:仅含大写字母 A-Z、数字 0-9、下划线 _, + # 且至少含一个大写字母。 + # + # Python 关键字(match, if, for)和变量名(self, pool, builder) + # 都含小写字母,不会匹配,从而避免 fail-fast 误报。 + # + # 返回: 1=符合 CDefine 命名约定, 0=不符合 + # ============================================================ + def _is_cdefine_name_pattern(self, name: str) -> int: + """检查名字是否符合 CDefine 命名约定(全大写+下划线+数字)""" + if name is None: + return 0 + has_upper: int = 0 + i: t.CSizeT = 0 + while name[i] != '\0': + c: t.CChar = name[i] + if c >= 'a' and c <= 'z': + return 0 + if c >= 'A' and c <= 'Z': + has_upper = 1 + i += 1 + return has_upper + + # ============================================================ + # 翻译变量引用(Name 节点)→ load + # ============================================================ + def translate_name_value(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译变量引用(Name 节点)→ load""" + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) + if nm is None: + return None + nm_id: str = nm.id + if nm_id is None: + return None + + # CDefine 编译期常量: 返回常量值(浮点 CDefine → double 常量,整数 → i32) + # NAME: t.CDefine = value 形式定义的常量在编译期已注册到本地表 + # 浮点 CDefine(如 vipermath 的 U_M_PI=3.14...)必须返回浮点常量, + # 否则在 double 函数里 return 生成 ret i32 0(llc 报错)。 + cdef_val_d: double = HandlesType.lookup_cdefine_double(nm_id) + if HandlesType.is_cdefine_found() != 0: + if HandlesType.is_cdefine_double() != 0: + # CDEF-DBG: 打印浮点 CDefine 使用(返回 ConstFloat) + fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_cd is not None: + stdio.snprintf(fb_cd, 1024, "USE-D: %s -> %.17g (float)", nm_id, cdef_val_d) + VLogger.info(fb_cd, "CDEF-DBG") + return llvmlite.ConstFloat(pool, llvmlite.Double(pool), cdef_val_d) + cdef_val_i: int = t.CInt(cdef_val_d) + # CDEF-DBG: 打印整数 CDefine 使用(返回 const_int32) + fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_cd is not None: + viperlib.snprintf(fb_cd, 1024, "USE-I: %s -> %d (int)", nm_id, cdef_val_i) + VLogger.info(fb_cd, "CDEF-DBG") + return llvmlite.const_int32(pool, cdef_val_i) + + # 本地表未找到:尝试跨模块 .vpi 查找(保证多模块查表存表一致) + # 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找, + # 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗 + if self._is_cdefine_name_pattern(nm_id) != 0: + if trans is not None: + cdef_val = self._lookup_cross_module_cdefine( + pool, nm_id, trans._from_imports, trans._imported_modules) + if HandlesType.is_cdefine_found() != 0: + return llvmlite.const_int32(pool, cdef_val) + + # global 变量:从模块作用域查找(global 声明优先级最高) + if trans is not None: + 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: + load_ty: llvmlite.LLVMType | t.CPtr = None + if mod_alloca.Ty is not None: + load_ty = mod_alloca.Ty.Pointee + if load_ty is None: + load_ty = llvmlite.Int32(pool) + return llvmlite.build_load(builder, load_ty, mod_alloca) + + # nonlocal 变量:通过闭包 env 访问 + if HT.is_nonlocal_name(trans, nm_id) != 0: + return HandlesNonlocal.load_nonlocal_var(trans, nm_id) + + # *args va_list:变量名直接解析为指向 24 字节 va_list 缓冲区的 i8* 地址 + # (对齐 TPC _direct_values[vararg_name] = va_list_ptr;不 load 缓冲区内容, + # 转发时按值传该地址即可,如 sprintf → vsnprintf(..., args)) + if trans is not None and trans._vararg_name is not None: + if nm_id is not None and string.strcmp(nm_id, trans._vararg_name) == 0: + if trans._va_list_ptr is not None: + return trans._va_list_ptr + + # 局部变量查找(必须先于模块别名检查) + # 否则与模块同名的局部变量(如 `import t, c` 后的局部变量 c)会被误判为模块别名, + # 导致 SymTab 已注册的局部变量查找不到(rhs_val is None bug 根因) + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm_id) + if alloca is not None: + load_ty: llvmlite.LLVMType | t.CPtr = None + if alloca.Ty is not None: + load_ty = alloca.Ty.Pointee + if load_ty is None: + load_ty = llvmlite.Int32(pool) + # 结构体值变量(alloca 类型为 Struct,如 `x: Cls | t.CPtr`): + # 按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值。 + # 结构体值无法参与 ptrtoint/方法调用等地址相关操作,加载值会导致 + # `ptrtoint %Struct ... to i64` 无效指令(llc invalid cast opcode)。 + match load_ty: + case llvmlite.LLVMType.Struct(_, _, _): + return alloca + return llvmlite.build_load(builder, load_ty, alloca) + + # 模块别名检查:SymTab 查找失败后才检查 + # 如果 nm_id 是已导入模块名(如 win32file, fileio)且未被声明为局部变量, + # 返回 None 让上层处理(用于属性访问 win32file.CreateFileA) + if trans is not None and trans._imported_modules is not None: + if HandlesImports.is_module_imported(trans._imported_modules, nm_id) != 0: + return None + + # 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。 + # 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移 + # (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。 + # 注意:不能直接返回 Function 对象,也不能直接 build_bitcast(Function)—— + # Function 布局是 {Next, Name, RetTy, Params, ...},value_get_ty 会错位读到 + # Name 字段,TypePrint 输出 "void",生成 `bitcast void ... to i8*` 非法 IR; + # 且 Function.Next 是模块函数链表指针,参数链表构建对其赋值会截断函数链表, + # 最终打印出 `declare void @()` 空名函数。正确做法:按 Function 的 + # RetTy/Params 构造真实函数类型,用 new_value 包装成普通 Value 再 bitcast。 + if trans is not None and trans.Module is not None: + fn_ref: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module( + trans.Module, nm_id) + if fn_ref is not None: + fn_name: t.CChar | t.CPtr = llvmlite.function_get_name(fn_ref) + if fn_name is None: + return None + # 构造函数类型:ret_ty + 参数 ParamNode 链表 + fn_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fn_ref) + if fn_ret_ty is None: + fn_ret_ty = llvmlite.Int32(pool) + fn_pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(fn_ref) + fn_first_node: llvmlite.ParamNode | t.CPtr = None + fn_prev_node: llvmlite.ParamNode | t.CPtr = None + fn_pcount: int = 0 + while fn_pp is not None: + fn_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fn_pp) + fn_pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, fn_pty) + if fn_pn is not None: + if fn_first_node is None: + fn_first_node = fn_pn + if fn_prev_node is not None: + llvmlite.paramnode_set_next(fn_prev_node, fn_pn) + fn_prev_node = fn_pn + fn_pcount += 1 + fn_pp = llvmlite.param_get_next(fn_pp) + fn_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func( + pool, fn_ret_ty, fn_first_node, fn_pcount) + if fn_ty is None: + return None + # 构造函数指针 Value(new_value 包装,避免触碰 Function.Next) + fn_ref_v: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) + if fn_ref_v is None: + return None + llvmlite.value_set_ty(fn_ref_v, llvmlite.Ptr(pool, fn_ty)) + llvmlite.value_set_isconst(fn_ref_v, 1) + fn_ref_name: t.CChar | t.CPtr = pool.alloc(256) + if fn_ref_name is not None: + fn_ref_name[0] = '\0' + if HandlesClassDef._vtable_name_needs_quote(fn_name) != 0: + viperlib.snprintf(fn_ref_name, 256, "@\"%s\"", fn_name) + else: + viperlib.snprintf(fn_ref_name, 256, "@%s", fn_name) + llvmlite.value_set_name(fn_ref_v, fn_ref_name) + fn_i8ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + return llvmlite.build_bitcast(builder, fn_ref_v, fn_i8ptr_ty) + + # 所有查找路径均失败 + # fail-fast: 仅对符合 CDefine 命名约定(ALL_CAPS)的名字报错 + # 避免对 match/self/pool 等关键字和变量名误报 + # 跨模块 CDefine 查找已在上方完成,此处不重复 + if self._is_cdefine_name_pattern(nm_id) != 0: + err_buf2: str = pool.alloc(256) + if err_buf2 is not None: + cur_sha1: str = "(unknown)" + if trans is not None and trans.ModuleSha1 is not None: + cur_sha1 = trans.ModuleSha1 + viperlib.snprintf(err_buf2, 256, + "[CD] FATAL: Name '%s' NOT found (CDefine local+cross + global + nonlocal + alloca + module alias) in module sha1=%s\n", + nm_id, cur_sha1) + VLogger.error(err_buf2, "CD") + return None + + # ============================================================ + # list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑 + # + # list 结构布局 (6 字段 × 8 字节): + # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) + # 返回元素地址 (i8*),调用方根据元素类型 load 正确的值 + # ============================================================ + def list_getitem_inline(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + lm_obj: llvmlite.Value | t.CPtr, + idx_val: llvmlite.Value | t.CPtr, + node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)""" + if builder is None or pool is None or lm_obj is None or idx_val is None: + return None + 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) + # 加载 __data__ (偏移 0, index 0) + g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) + if g_dpp is None: + return None + g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) + # 加载 __elem_size__ (偏移 32, index 4) + g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) + if g_epp is None: + return None + g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) + if g_data is None or g_esize is None: + return None + g_idx_i64: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, idx_val, i64_ty, node) + if g_idx_i64 is None: + return None + g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) + if g_offset is None: + return None + # 返回元素地址 (i8*),不 load + return llvmlite.build_gep(builder, i8_ty, g_data, g_offset) + + # ============================================================ + # _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型 + # + # 类型名格式: .list[] + # 用 strstr 检查完整模式,避免子串提取 + # 支持: list[int]→i32, list[str]/list[bytes]→i8*, list[CInt]→i32 等 + # 默认: i32 + # ============================================================ + def _list_elem_type_from_name(self, pool: memhub.MemBuddy | t.CPtr, + struct_name: str) -> llvmlite.LLVMType | t.CPtr: + """从 list 类型名提取元素 LLVM 类型""" + if pool is None or struct_name is None: + return None + # 用 strstr 检查完整模式 + if string.strstr(struct_name, "list[int]") is not None: + return llvmlite.Int32(pool) + if string.strstr(struct_name, "list[CInt]") is not None: + return llvmlite.Int32(pool) + if string.strstr(struct_name, "list[CInt8T]") is not None: + return llvmlite.Int8(pool) + if string.strstr(struct_name, "list[CInt16T]") is not None: + return llvmlite.Int16(pool) + if string.strstr(struct_name, "list[CInt32T]") is not None: + return llvmlite.Int32(pool) + if string.strstr(struct_name, "list[CInt64T]") is not None: + return llvmlite.Int64(pool) + if string.strstr(struct_name, "list[CSizeT]") is not None: + return llvmlite.Int64(pool) + if string.strstr(struct_name, "list[CDouble]") is not None: + return llvmlite.Double(pool) + if string.strstr(struct_name, "list[CFloat]") is not None: + return llvmlite.Float(pool) + if string.strstr(struct_name, "list[CChar]") is not None: + return llvmlite.Int8(pool) + # str/bytes/CPtr/其他指针类型 → i8* + i8_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + return llvmlite.Ptr(pool, i8_ty_d) + + # ============================================================ + # list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑 + # + # 直接存储 rhs_val 到元素地址 (coerce 为 i8* 后 store) + # ============================================================ + def list_setitem_inline(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + lm_obj: llvmlite.Value | t.CPtr, + idx_val: llvmlite.Value | t.CPtr, + rhs_val: llvmlite.Value | t.CPtr, + node: ast.AST | t.CPtr = None) -> int: + """内联生成 list __setitem__ 逻辑,返回 0""" + if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None: + return 0 + 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) + # 加载 __data__ (偏移 0, index 0) + s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) + if s_dpp is None: + return 0 + s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) + # 加载 __elem_size__ (偏移 32, index 4) + s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) + if s_epp is None: + return 0 + s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) + if s_data is None or s_esize is None: + return 0 + s_idx_i64: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, idx_val, i64_ty, node) + if s_idx_i64 is None: + return 0 + s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) + if s_offset is None: + return 0 + s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) + if s_addr is None: + return 0 + s_val_ptr: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, rhs_val, i8_ptr_ty, node) + if s_val_ptr is None: + return 0 + llvmlite.build_store(builder, s_val_ptr, s_addr) + return 0 + + # ============================================================ + # is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型 + # + # 返回 list 对象指针 (Ptr(list[T])) 或 None + # ============================================================ + def is_list_subscript(self, node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None""" + if node is None or trans is None: + return None + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub is None or sub.value is None: + return None + if sub.value.kind() != ast.ASTKind.Name: + return None + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm is None or nm.id is None: + return None + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is None or alloca.Ty is None: + return None + if self.is_ptr_type(alloca.Ty) == 0: + return None + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is None: + return None + # 检查 pointee 是否是 Ptr(Struct) + inner_ty: llvmlite.LLVMType | t.CPtr = None + match pointee: + case llvmlite.LLVMType.Ptr(it): + inner_ty = it + case _: + return None + if inner_ty is None: + return None + # 检查 inner_ty 是否是 Struct 且名称包含 "list[" + struct_name: str = None + match inner_ty: + case llvmlite.LLVMType.Struct(_, _, sname): + struct_name = sname + case _: + return None + if struct_name is None: + return None + if string.strstr(struct_name, "list[") is None: + return None + # 是 list 类型: load 出 list 对象指针 + builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder + return llvmlite.build_load(builder, pointee, alloca) + + # ============================================================ + # 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i] + # + # 指针遍历: ptr 是指针变量,load 出指针值后 GEP + load + # 数组遍历: arr 是数组变量,用 alloca 指针做双索引 GEP [0, i] + load + # list[T]: 泛型类不注册 struct,subscript 走 __getitem__ 内联路径 + # ============================================================ + def translate_subscript(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译下标表达式,返回加载的元素值""" + if node is None or builder is None: + return None + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub is None: + return None + + # 翻译索引 + idx_val: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, sub.slice, None, 0, trans) + if idx_val is None: + return None + + # 如果 value 是 Name,尝试从 alloca 类型推断 + if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm.id is not None and trans is not None: + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is not None and alloca.Ty is not None: + if self.is_ptr_type(alloca.Ty) != 0: + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is not None: + # 不调用 pointee.kind() 避免跨模块引用 LLVMType.kind 符号 + # 用 match 检查 pointee 类型 + match pointee: + case llvmlite.LLVMType.Array(elem_ty, count): + # 数组遍历: getelementptr [N x elem_ty], ... , i32 0, i32 %idx + elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, pointee, elem_ty, alloca, + self._zext_index_to_i32(builder, idx_val)) + if elem_ptr is not None: + return llvmlite.build_load(builder, elem_ty, elem_ptr) + return None + case llvmlite.LLVMType.Ptr(inner_ty): + # 检查 inner_ty 是否是 list[T] 类型(泛型类不注册 struct) + # list 的 subscript 应该走 __getitem__ 内联路径,而非指针遍历 + list_struct_name: str = None + match inner_ty: + case llvmlite.LLVMType.Struct(_, _, lsn): + list_struct_name = lsn + case _: + pass + if list_struct_name is not None: + if string.strstr(list_struct_name, "list[") is not None: + # list[T] 类型: 内联生成 __getitem__ 逻辑 + ptr_val_list: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_list is not None: + elem_addr_list: llvmlite.Value | t.CPtr = self.list_getitem_inline( + builder, pool, ptr_val_list, idx_val, node) + if elem_addr_list is not None: + # 根据类型名提取元素类型,bitcast 后 load + elem_ty_list: llvmlite.LLVMType | t.CPtr = self._list_elem_type_from_name( + pool, list_struct_name) + if elem_ty_list is not None: + elem_ptr_ty_list: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, elem_ty_list) + casted_addr_list: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, elem_addr_list, elem_ptr_ty_list) + if casted_addr_list is not None: + return llvmlite.build_load( + builder, elem_ty_list, casted_addr_list) + return None + # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针 Ptr(Ptr(Ptr(...))), + # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 + # 此时 [i] 应该是指针解引用 (步长 sizeof(ptr)=8), 而非调用 + # 结构体的 __getitem__ 方法 (会错误生成 AST.__getitem__ 调用)。 + # 对比 HashTable|t.CPtr: alloca.Ty=HashTable**, inner_ty=Struct(HashTable) + # (非 Ptr), 仍走下面的方法调用转发路径。 + if self.is_ptr_type(inner_ty) != 0: + ptr_val_pp: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_pp is not None: + elem_ptr_pp: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, inner_ty, ptr_val_pp, idx_val) + if elem_ptr_pp is not None: + return llvmlite.build_load(builder, inner_ty, elem_ptr_pp) + return None + # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): + # 仅当类定义了 __getitem__(当前模块定义或跨模块 stub declare 注入) + # 才转发方法调用;否则普通结构体指针按下标做 GEP 数组访问 + # (对齐 TPC _HandleSubscriptLlvm: if ClassName and has_function(__getitem__)) + cls_nm_rd_ptr: str = self._get_custom_struct_cls_nm(pool, inner_ty) + if not (cls_nm_rd_ptr is None): + gi_lookup_rd: t.CChar | t.CPtr = pool.alloc(128) + if gi_lookup_rd is not None: + viperlib.snprintf(gi_lookup_rd, 128, "%s.__getitem__", cls_nm_rd_ptr) + if HandlesExprCall.find_func_in_module(mod, gi_lookup_rd) is not None: + obj_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if not (obj_ptr_rd is None): + arg_vals_rd_p: t.CSizeT | t.CPtr = pool.alloc(8) + if not (arg_vals_rd_p is None): + arg_vals_rd_p[0] = t.CSizeT(idx_val) + ret_rd_p: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( + pool, builder, mod, cls_nm_rd_ptr, "__getitem__", + obj_ptr_rd, arg_vals_rd_p, 1, trans, sub) + if not (ret_rd_p is None): + return ret_rd_p + # 无 __getitem__:结构体指针数组访问(GEP + load) + ptr_val_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_rd_g is not None: + elem_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, inner_ty, ptr_val_rd_g, idx_val) + if elem_rd_g is not None: + return llvmlite.build_load(builder, inner_ty, elem_rd_g) + return None + # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, + # 直接 GEP 按 i8* 步长(8 字节),load i8* + # 仅当 inner_ty 不是自定义结构体时才走指针遍历 + if trans is not None: + ve_pe_ts: HandlesVar.VarEntry | t.CPtr = \ + HandlesVar.lookup_var_entry(trans.SymTab, nm.id) + if ve_pe_ts is not None and ve_pe_ts.IsPtrElement == 1: + elem_ptr_ts: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, pointee, alloca, idx_val) + if elem_ptr_ts is not None: + return llvmlite.build_load(builder, pointee, elem_ptr_ts) + return None + # 普通指针遍历: 先 load 指针值,再 GEP + ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val is not None: + elem_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, inner_ty, ptr_val, idx_val) + if elem_ptr2 is not None: + return llvmlite.build_load(builder, inner_ty, elem_ptr2) + return None + case _: + # 自定义类(结构体类型): 仅当类定义了 __getitem__ + # (当前模块定义或跨模块 stub declare 注入)才转发方法调用; + # 否则普通结构体指针按下标做 GEP 数组访问 + cls_nm_sub: str = HandlesStruct.get_class_name_by_type(pool, pointee) + if not (cls_nm_sub is None): + gi_lookup_sub: t.CChar | t.CPtr = pool.alloc(128) + if gi_lookup_sub is not None: + viperlib.snprintf(gi_lookup_sub, 128, "%s.__getitem__", cls_nm_sub) + if HandlesExprCall.find_func_in_module(mod, gi_lookup_sub) is not None: + obj_val_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if not (obj_val_sub is None): + arg_vals_sub: t.CSizeT | t.CPtr = pool.alloc(8) + if not (arg_vals_sub is None): + arg_vals_sub[0] = t.CSizeT(idx_val) + ret_sub: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( + pool, builder, mod, cls_nm_sub, "__getitem__", + obj_val_sub, arg_vals_sub, 1, trans, sub) + if not (ret_sub is None): + return ret_sub + # 无 __getitem__:结构体指针数组访问(GEP + load) + ptr_val_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_sub_g is not None: + elem_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, pointee, ptr_val_sub_g, idx_val) + if elem_sub_g is not None: + return llvmlite.build_load(builder, pointee, elem_sub_g) + return None + pass + + # 通用路径:翻译 value 获取指针 + ptr_val: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, sub.value, None, 0, trans) + if ptr_val is None or ptr_val.Ty is None: + return None + + # 检查是否是指针类型 + if self.is_ptr_type(ptr_val.Ty) != 0: + elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if elem_ty2 is not None: + # 数组类型: 双索引 GEP + load 元素 + match elem_ty2: + case llvmlite.LLVMType.Array(arr_elem_ty2, arr_count2): + elem_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, elem_ty2, arr_elem_ty2, ptr_val, + self._zext_index_to_i32(builder, idx_val)) + if elem_ptr3 is not None: + return llvmlite.build_load(builder, arr_elem_ty2, elem_ptr3) + return None + case _: + pass + # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __getitem__ 才转发方法调用; + # 否则普通结构体指针按下标做 GEP 数组访问 + cls_nm_rd_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2) + if not (cls_nm_rd_gen is None): + gi_lookup_gen: t.CChar | t.CPtr = pool.alloc(128) + if gi_lookup_gen is not None: + viperlib.snprintf(gi_lookup_gen, 128, "%s.__getitem__", cls_nm_rd_gen) + if HandlesExprCall.find_func_in_module(mod, gi_lookup_gen) is not None: + arg_vals_rd_g: t.CSizeT | t.CPtr = pool.alloc(8) + if not (arg_vals_rd_g is None): + arg_vals_rd_g[0] = t.CSizeT(idx_val) + ret_rd_g: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( + pool, builder, mod, cls_nm_rd_gen, "__getitem__", + ptr_val, arg_vals_rd_g, 1, trans, sub) + if not (ret_rd_g is None): + return ret_rd_g + # 无 __getitem__:结构体指针数组访问(GEP + load) + elem_ptr_gen: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, elem_ty2, ptr_val, idx_val) + if elem_ptr_gen is not None: + return llvmlite.build_load(builder, elem_ty2, elem_ptr_gen) + return None + # 指针类型: 单索引 GEP + load + elem_ptr4: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, elem_ty2, ptr_val, idx_val) + if elem_ptr4 is not None: + return llvmlite.build_load(builder, elem_ty2, elem_ptr4) + return None + + # ============================================================ + # find_global_in_module - 在模块全局变量链表中按名称查找 + # + # 查找策略: + # 1. 精确匹配 (如 "_mbuddy" 匹配 @_mbuddy) + # 2. 后缀匹配 (如 "_mbuddy" 匹配 @"sha1._mbuddy") + # ============================================================ + def find_global_in_module(self, mod: llvmlite.LLVMModule | t.CPtr, + name: str) -> llvmlite.GlobalVariable | t.CPtr: + """在模块全局变量链表中按名称查找全局变量""" + if mod is None or name is None: + return None + name_len: t.CSizeT = string.strlen(name) + cur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead + # 第一遍: 精确匹配 + while cur is not None: + if cur.Name is not None: + if string.strcmp(cur.Name, name) == 0: + return cur + cur = cur.Next + # 第二遍: 后缀匹配 (.name) + cur = mod.GlobalHead + while cur is not None: + if cur.Name is not None: + cur_len: t.CSizeT = string.strlen(cur.Name) + if cur_len > name_len + 1: + suffix_start: t.CSizeT = cur_len - name_len + if cur.Name[suffix_start - 1] == '.': + match: int = 1 + for i in range(name_len): + if cur.Name[suffix_start + i] != name[i]: + match = 0 + break + if match == 1: + return cur + cur = cur.Next + return None + + # ============================================================ + # make_global_ref - 创建全局变量引用 (@name,类型为 ty*) + # + # 用于跨模块全局变量访问: stub 未注入时,翻译阶段生成 @name 引用, + # 链接时由 stub 提供 external global 声明。 + # ============================================================ + def make_global_ref(self, pool: memhub.MemBuddy | t.CPtr, + name: str, + ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """创建全局变量引用 (类型为 ty*,名称为 @name)""" + if name is None or ty is None: + return None + ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, ty) + ref_name: t.CChar | t.CPtr = pool.alloc(64) + if ref_name is None: + return None + viperlib.snprintf(ref_name, 64, "@%s", name) + return llvmlite.SSAValue(pool, ptr_ty, ref_name) + + # ============================================================ + # _resolve_module_attribute_global - 解析模块属性访问的全局变量引用 + # + # 当 obj 是已导入模块名 (如 sys._mbuddy) 时: + # 1. 在当前模块全局变量链表中查找 (stub 已注入的情况) + # 2. 未找到则创建前向引用 (@attr_name, 类型为 ty 参数) + # + # 参数: + # ty_hint: 类型提示 (写路径用 rhs 类型, 读路径用 i8* 回退) + # 返回: Value 指针 (类型为 ty*),未识别为模块属性返回 None + # ============================================================ + def _is_t_type_object_name(self, name: str) -> int: + """检查 name 是否是 t.py 中的类型对象名(CPtr/CInt/CDouble 等) + + 这些类型对象在运行时作为全局变量 @CPtr/@CInt 等被引用, + 但 t.py 不被编译,需要在使用处生成带 null 初值的定义。 + """ + if name is None: + return 0 + # t.py 中的类型对象名(PascalCase,首字母大写) + if string.strcmp(name, "CPtr") == 0: + return 1 + if string.strcmp(name, "CInt") == 0: + return 1 + if string.strcmp(name, "CChar") == 0: + return 1 + if string.strcmp(name, "CShort") == 0: + return 1 + if string.strcmp(name, "CLong") == 0: + return 1 + if string.strcmp(name, "CLongLong") == 0: + return 1 + if string.strcmp(name, "CDouble") == 0: + return 1 + if string.strcmp(name, "CFloat") == 0: + return 1 + if string.strcmp(name, "CBool") == 0: + return 1 + if string.strcmp(name, "CVoid") == 0: + return 1 + if string.strcmp(name, "CInt8T") == 0: + return 1 + if string.strcmp(name, "CInt16T") == 0: + return 1 + if string.strcmp(name, "CInt32T") == 0: + return 1 + if string.strcmp(name, "CInt64T") == 0: + return 1 + if string.strcmp(name, "CUInt8T") == 0: + return 1 + if string.strcmp(name, "CUInt16T") == 0: + return 1 + if string.strcmp(name, "CUInt32T") == 0: + return 1 + if string.strcmp(name, "CUInt64T") == 0: + return 1 + if string.strcmp(name, "CUnsigned") == 0: + return 1 + if string.strcmp(name, "CUnsignedInt") == 0: + return 1 + if string.strcmp(name, "CUnsignedChar") == 0: + return 1 + if string.strcmp(name, "CUnsignedShort") == 0: + return 1 + if string.strcmp(name, "CUnsignedLong") == 0: + return 1 + if string.strcmp(name, "CUnsignedLongLong") == 0: + return 1 + if string.strcmp(name, "CSizeT") == 0: + return 1 + if string.strcmp(name, "CIntPtrT") == 0: + return 1 + if string.strcmp(name, "CUIntPtrT") == 0: + return 1 + if string.strcmp(name, "CPtrDiffT") == 0: + return 1 + if string.strcmp(name, "CType") == 0: + return 1 + if string.strcmp(name, "CDefine") == 0: + return 1 + if string.strcmp(name, "CStatic") == 0: + return 1 + if string.strcmp(name, "CExport") == 0: + return 1 + if string.strcmp(name, "CArray") == 0: + return 1 + if string.strcmp(name, "CTypedef") == 0: + return 1 + if string.strcmp(name, "CNoVTable") == 0: + return 1 + if string.strcmp(name, "CNeedPtr") == 0: + return 1 + if string.strcmp(name, "CAutoPtr") == 0: + return 1 + return 0 + + def _resolve_module_attribute_global(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + trans: HT.Translator | t.CPtr, + at: ast.Attribute | t.CPtr, + ty_hint: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """解析模块属性访问,返回全局变量引用 (用于跨模块 global 访问)""" + if at is None or at.value is None or at.attr is None: + return None + if at.value.kind() != ast.ASTKind.Name: + return None + if trans is None or trans._imported_modules is None: + return None + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if mod_nm.id is None: + return None + # 检查是否是已导入模块 + if HandlesImports.is_module_imported(trans._imported_modules, mod_nm.id) == 0: + return None + # 在当前模块查找全局变量 (stub 可能已注入) + gv: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, at.attr) + if gv is not None and gv.Ty is not None: + return self.make_global_ref(pool, at.attr, gv.Ty) + # 未找到: 创建 external global 声明并添加到模块 + # 否则只生成 @_argc 引用而无声明,LLVM 报 "use of undefined value '@_argc'" + use_ty: llvmlite.LLVMType | t.CPtr = ty_hint + if use_ty is None: + use_ty = llvmlite.Int8(pool) + # 确保 use_ty 中的跨模块结构体类型有 opaque 声明 + llvmlite.module_ensure_opaque_for_type(mod, pool, use_ty) + # 特殊处理: t.py 中的类型对象(CPtr/CInt/CDouble 等) + # t.py 不被编译,但这些类型对象在运行时被引用(如 va_arg(ap, t.CPtr))。 + # 创建带 null 初值的 linkonce_odr 全局变量定义,避免链接时 undefined reference。 + # LLVM 22+ 不允许 external linkage 全局变量带初值,使用 linkonce_odr 替代。 + is_t_type_obj: int = 0 + if string.strcmp(mod_nm.id, "t") == 0: + is_t_type_obj = self._is_t_type_object_name(at.attr) + ext_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, at.attr, use_ty) + if ext_gv is not None: + if is_t_type_obj != 0: + # t.CPtr 等类型对象: 创建带 null 初值的定义(linkonce_odr) + ext_gv.Linkage = "linkonce_odr" + # i8* null 的初值文本 + null_init: bytes = pool.alloc(8) + if null_init is not None: + null_init[0] = 'n' + null_init[1] = 'u' + null_init[2] = 'l' + null_init[3] = 'l' + null_init[4] = '\0' + ext_gv.Initializer = null_init + else: + ext_gv.Initializer = None + else: + # 普通模块属性: external 声明(由其他模块提供定义) + ext_gv.Linkage = "external" + ext_gv.Initializer = None + llvmlite.module_add_global(mod, ext_gv) + return self.make_global_ref(pool, at.attr, use_ty) + + # ============================================================ + # 翻译属性访问 Attribute(value, attr, ctx) — obj.field + # + # 优先级: + # 1. 枚举成员访问 (State.Idle → 常量值) + # 2. 模块属性访问 (sys._mbuddy → 加载全局变量) + # 3. 结构体字段访问 (obj.field → GEP + load) + # + # 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) + # ============================================================ + + + # ============================================================ + # _get_cderef_attr_base - c.Deref(ptr).attr 属性访问的 base 指针 + # + # c.Deref(ptr) 作为属性访问 base 时(如 c.Deref(p).a),需要 ptr + # 指针本身而非 load 后的结构体值(*p.a → p->a),与 TPC + # _handle_attr_call_result 语义一致。否则 c.Deref 返回结构体值, + # 后续 GEP 在非指针上做属性访问会误报"base=非指针类型"。 + # + # 返回: + # ptr 指针值(Ptr(Struct) 或 Ptr(Ptr(Struct)),交由 _deref_if_ptr_ptr 解层级) + # 非 c.Deref 模式返回 None + # ============================================================ + def _get_cderef_attr_base(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + at_value: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """检测 at.value 是否为 c.Deref(ptr) 调用,返回 ptr 指针(不做 load)""" + if at_value is None or at_value.kind() != ast.ASTKind.Call: + return None + cl_cd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(at_value) + if cl_cd.func is None or cl_cd.func.kind() != ast.ASTKind.Attribute: + return None + f_cd: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_cd.func) + if f_cd.attr is None or string.strcmp(f_cd.attr, "Deref") != 0: + return None + if f_cd.value is None or f_cd.value.kind() != ast.ASTKind.Name: + return None + nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(f_cd.value) + if nm_cd.id is None or string.strcmp(nm_cd.id, "c") != 0: + return None + if cl_cd.args is None or cl_cd.args.__len__() < 1: + return None + inner_cd: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, cl_cd.args.get(0), None, 0, trans) + if inner_cd is not None and self.is_ptr_type(inner_cd.Ty) != 0: + return inner_cd + return None + + def translate_attribute(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译属性访问,返回加载的字段值""" + if node is None or builder is None: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at is None or at.value is None or at.attr is None: + # fast-fail: AST 节点字段缺失属解析器 bug,应报告具体缺失字段 + diag_buf_an: bytes = stdlib.malloc(256) + if diag_buf_an is not None: + missing_an: str = "?" + if at is not None: + if at.value is None: + missing_an = "value" + elif at.attr is None: + missing_an = "attr" + viperlib.snprintf(diag_buf_an, 256, + "属性访问失败: AST 节点字段缺失 (%s sha1=%s:%d)", + missing_an, + trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?", + at.lineno if at is not None and at.lineno is not None else 0) + VLogger.error(diag_buf_an, "ATTR") + return None + + # 枚举成员访问: EnumName.MemberName → 常量值 + # 当 value 是 Name 且 Name.id 是已注册枚举时,查找成员并返回常量 + if at.value.kind() == ast.ASTKind.Name: + enum_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if enum_nm.id is not None: + if HandlesEnum.is_enum_class(enum_nm.id) == 1: + member: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member( + enum_nm.id, at.attr) + if member is not None: + base_ty: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type( + enum_nm.id) + if base_ty is not None: + # 生成数字字符串作为常量名(LLVM IR 要求常量输出数字值) + name_buf: t.CChar | t.CPtr = pool.alloc(32) + if name_buf is not None: + viperlib.snprintf(name_buf, 32, "%lld", member.Value) + return llvmlite.ConstInt(pool, base_ty, member.Value, name_buf) + return llvmlite.const_int32(pool, member.Value) + # fast-fail: 枚举成员未找到 + VLogger.error( + f"枚举成员未找到: {enum_nm.id}.{at.attr}", + "ATTR") + return None + + # 嵌套枚举成员访问: Module.EnumName.MemberName → 常量值 + # 当 value 是 Attribute(如 fileio.MODE)且 attr 部分是已注册枚举时 + if at.value.kind() == ast.ASTKind.Attribute: + inner_at_e: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) + if inner_at_e.value is not None and inner_at_e.value.kind() == ast.ASTKind.Name: + inner_nm_e: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_at_e.value) + if inner_nm_e.id is not None and inner_at_e.attr is not None: + if HandlesEnum.is_enum_class(inner_at_e.attr) == 1: + member_e: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member( + inner_at_e.attr, at.attr) + if member_e is not None: + base_ty_e: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type( + inner_at_e.attr) + if base_ty_e is not None: + name_buf_e: t.CChar | t.CPtr = pool.alloc(32) + if name_buf_e is not None: + viperlib.snprintf(name_buf_e, 32, "%lld", member_e.Value) + return llvmlite.ConstInt(pool, base_ty_e, member_e.Value, name_buf_e) + return llvmlite.const_int32(pool, member_e.Value) + # fast-fail: 嵌套枚举成员未找到 + VLogger.error( + f"嵌套枚举成员未找到: {inner_at_e.attr}.{at.attr}", + "ATTR") + return None + + # 模块属性访问 (读路径): sys._mbuddy → 加载全局变量 @_mbuddy + # 当 obj 是已导入模块名且不是普通变量时,查找/创建全局变量引用并加载 + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm_ma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_ma.id is not None: + # 先检查是否是普通变量 (优先级高于模块属性) + ma_is_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, nm_ma.id) + if ma_is_var is None: + # 先检查是否是 CDefine 编译期常量 (如 ast.CONST_INT / win32base.INVALID_HANDLE_VALUE) + # 模块属性访问的 CDefine 常量需要跨模块查找源 .vp / .vpi 文件 + cdef_ma_val: int = HandlesType.lookup_cdefine_constant(at.attr) + cd_local: int = HandlesType.is_cdefine_found() + if cd_local == 0: + # 确定真实模块名:优先从 _from_imports 解析别名 + # from_imports 中条目格式 "local_name:real_module" + # 如 win32base:w32.win32base → 别名 win32base 真实模块 w32.win32base + real_mod_name: str = nm_ma.id + if trans._from_imports is not None: + resolved_mod: str = HandlesImports.lookup_from_import( + trans._from_imports, nm_ma.id, 0) + if resolved_mod is not None: + # 复制模块名到新缓冲区(截断于空格、null、或 ':') + rm_len: t.CSizeT = 0 + while resolved_mod[rm_len] != ' ' and resolved_mod[rm_len] != '\0' and resolved_mod[rm_len] != ':': + rm_len += 1 + rm_buf: str = pool.alloc(rm_len + 1) + if rm_buf is not None: + for rm_i in range(rm_len): + rm_buf[rm_i] = resolved_mod[rm_i] + rm_buf[rm_len] = '\0' + real_mod_name = rm_buf + # 即使 _from_imports 为 None(如纯 `import ast` 无 from-import), + # 也必须尝试跨模块 CDefine 查找,否则 ast.CONST_INT 会被 + # 误解析为全局变量引用 @CONST_INT(未定义符号)。 + # 构建临时 from_imports "{attr}:{real_module}" 用于跨模块查找 + if real_mod_name is not None: + ma_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod_name) + 2 + ma_fi: str = pool.alloc(ma_fi_len) + if ma_fi is not None: + viperlib.snprintf(ma_fi, ma_fi_len, "%s:%s", at.attr, real_mod_name) + cdef_ma_val = self._lookup_cross_module_cdefine(pool, at.attr, ma_fi) + if HandlesType.is_cdefine_found() != 0: + return llvmlite.const_int32(pool, cdef_ma_val) + # 检查 nm_ma.id.at.attr 是否是已导入子模块 (如 w32.win32file) + # 如果是子模块,不应创建全局变量,让嵌套属性访问路径处理 + is_submod: int = 0 + if trans._imported_modules is not None: + submod_len: t.CSizeT = string.strlen(nm_ma.id) + string.strlen(at.attr) + 2 + submod_buf: t.CChar | t.CPtr = pool.alloc(submod_len) + if submod_buf is not None: + viperlib.snprintf(submod_buf, submod_len, "%s.%s", nm_ma.id, at.attr) + if HandlesImports.is_module_imported(trans._imported_modules, submod_buf) == 1: + is_submod = 1 + # also check from_imports: at.attr 别名对应真实模块 w32.win32file + if is_submod == 0 and trans._from_imports is not None: + fi_mod_raw: str = HandlesImports.lookup_from_import( + trans._from_imports, at.attr, 0) + if fi_mod_raw is not None: + # 复制模块名到新缓冲区(截断于空格、null、或 ':') + fm_len: t.CSizeT = 0 + while fi_mod_raw[fm_len] != ' ' and fi_mod_raw[fm_len] != '\0' and fi_mod_raw[fm_len] != ':': + fm_len += 1 + fi_mod: str = pool.alloc(fm_len + 1) + if fi_mod is not None: + for fm_i in range(fm_len): + fi_mod[fm_i] = fi_mod_raw[fm_i] + fi_mod[fm_len] = '\0' + # 检查 fi_mod 是否以 "nm_ma.id." 开头 (如 w32.win32file 以 w32. 开头) + prefix_len: t.CSizeT = string.strlen(nm_ma.id) + fi_mod_len: t.CSizeT = string.strlen(fi_mod) + if fi_mod_len > prefix_len + 1: + match_prefix: int = 1 + for pi in range(prefix_len): + if fi_mod[pi] != nm_ma.id[pi]: + match_prefix = 0 + break + if match_prefix == 1 and fi_mod[prefix_len] == '.': + is_submod = 1 + if is_submod != 0: + return None # 是子模块,交给嵌套属性访问路径 + # 特殊处理: t.ASM_DESCR 不是 CDefine,是内联汇编约束命名空间 + # t.ASM_DESCR.XXX 由 HandlesExprCall 的 _asm_resolve_constraint 处理 + # 此处返回 None,让上层嵌套属性访问路径处理 + if string.strcmp(nm_ma.id, "t") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0: + return None + # CDefine 未找到且属性名符合 ALL_CAPS 约定: 报 FATAL 错误 + # 不再创建未定义的外部全局变量引用(否则 llc 报 "use of undefined value") + if self._is_cdefine_name_pattern(at.attr) != 0: + err_buf_sma: str = pool.alloc(256) + if err_buf_sma is not None: + cur_sha1_sma: str = "(unknown)" + if trans is not None and trans.ModuleSha1 is not None: + cur_sha1_sma = trans.ModuleSha1 + viperlib.snprintf(err_buf_sma, 256, + "[CD] FATAL: Module attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n", + nm_ma.id, at.attr, cur_sha1_sma) + VLogger.error(err_buf_sma, "CD") + return None + # 非 CDefine: 使用 i8* 作为类型提示 (模块级变量通常存储指针) + i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + mod_gv_ref: llvmlite.Value | t.CPtr = self._resolve_module_attribute_global( + pool, mod, trans, at, i8_ptr_hint) + if mod_gv_ref is not None and mod_gv_ref.Ty is not None: + load_ty_mod: llvmlite.LLVMType | t.CPtr = mod_gv_ref.Ty.Pointee + if load_ty_mod is not None: + return llvmlite.build_load(builder, load_ty_mod, mod_gv_ref) + + # 嵌套模块属性访问 (w32.win32file.GENERIC_READ → 查找全局 @GENERIC_READ) + # 当 at.value 是 Attribute 且解析为已导入子模块时,查找 at.attr 作为全局常量 + if at.value.kind() == ast.ASTKind.Attribute and trans is not None: + inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) + if inner_at.value is not None and inner_at.value.kind() == ast.ASTKind.Name: + inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_at.value) + if inner_nm.id is not None and inner_at.attr is not None: + if HandlesVar.lookup_var(trans.SymTab, inner_nm.id) is None: + # 构建限定模块名: "w32.win32file" + qual_len: t.CSizeT = string.strlen(inner_nm.id) + string.strlen(inner_at.attr) + 2 + qual_buf: t.CChar | t.CPtr = pool.alloc(qual_len) + if qual_buf is not None: + viperlib.snprintf(qual_buf, qual_len, "%s.%s", inner_nm.id, inner_at.attr) + if HandlesImports.is_module_imported(trans._imported_modules, qual_buf) == 1: + # 查找全局变量 at.attr (stub 已注入的情况) + gv_nested: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, at.attr) + if gv_nested is not None and gv_nested.Ty is not None: + gv_ref_nested: llvmlite.Value | t.CPtr = self.make_global_ref( + pool, at.attr, gv_nested.Ty) + if gv_ref_nested is not None and gv_ref_nested.Ty is not None: + load_ty_nested: llvmlite.LLVMType | t.CPtr = gv_ref_nested.Ty.Pointee + if load_ty_nested is not None: + return llvmlite.build_load(builder, load_ty_nested, gv_ref_nested) + # 未找到全局: 尝试 CDefine 常量查找 + # 对于 w32.win32base.INVALID_HANDLE_VALUE 等嵌套模块属性访问, + # 先从限定模块的 .vpi 文件中查找 CDefine 常量值并内联 + cdef_val_nested: int = HandlesType.lookup_cdefine_constant(at.attr) + if HandlesType.is_cdefine_found() == 0: + # 构建临时 from_imports "attr:module" 用于跨模块查找 + tmp_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(qual_buf) + 2 + tmp_fi: str = pool.alloc(tmp_fi_len) + if tmp_fi is not None: + viperlib.snprintf(tmp_fi, tmp_fi_len, "%s:%s", at.attr, qual_buf) + cdef_val_nested = self._lookup_cross_module_cdefine(pool, at.attr, tmp_fi) + if HandlesType.is_cdefine_found() != 0: + return llvmlite.const_int32(pool, cdef_val_nested) + # CDefine 未找到: 报 FATAL 错误(不再创建未定义的全局变量引用) + # 之前此处创建 @INVALID_HANDLE_VALUE 等前向引用,但全局未定义, + # 导致 llc 报 "use of undefined value" 错误。 + # 正确做法是报错终止,让开发者修复跨模块 CDefine 查找失败的根本原因。 + if self._is_cdefine_name_pattern(at.attr) != 0: + err_buf_ma: str = pool.alloc(256) + if err_buf_ma is not None: + cur_sha1_ma: str = "(unknown)" + if trans is not None and trans.ModuleSha1 is not None: + cur_sha1_ma = trans.ModuleSha1 + viperlib.snprintf(err_buf_ma, 256, + "[CD] FATAL: Nested attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n", + qual_buf, at.attr, cur_sha1_ma) + VLogger.error(err_buf_ma, "CD") + return None + + # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体) + obj_ptr: llvmlite.Value | t.CPtr = None + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm.id is not None: + obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) + + # 非 Name 路径:翻译对象值(会 load) + if obj_ptr is None: + # c.Deref(ptr).attr: 属性访问 base 取指针本身而非 load 后的结构体值 + # (如 c.Deref(p).a 语义是 (*p).a,直接对 p 做 GEP) + cd_base_rd: llvmlite.Value | t.CPtr = self._get_cderef_attr_base( + builder, pool, mod, at.value, trans) + if cd_base_rd is not None: + obj_ptr = cd_base_rd + elif at.value.kind() == ast.ASTKind.Subscript: + # 下标基座属性访问(如 pts[0].x):list[T]/OOP __getitem__ 类走 + # translate_value(返回元素值/地址);普通结构体指针数组走 + # get_subscript_ptr(GEP 元素地址,避免结构体值 base=非指针 报错) + if self._sub_base_uses_getitem(pool, mod, trans, at.value) != 0: + obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) + else: + obj_ptr = self.get_subscript_ptr(builder, pool, mod, at.value, trans) + elif at.value.kind() == ast.ASTKind.Attribute: + # 嵌套属性基座(如 r.origin.x):取内层字段地址(get_attribute_ptr 递归, + # 地址语义),指针字段(X|t.CPtr)由 _deref_if_ptr_ptr load 解引用 + obj_ptr = self.get_attribute_ptr(builder, pool, mod, at.value, trans) + if obj_ptr is None: + obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) + else: + obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) + + if obj_ptr is None or obj_ptr.Ty is None: + return None + + # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), + # load 解引用获取 Ptr(Struct) + obj_ptr = self._deref_if_ptr_ptr(builder, obj_ptr) + + # 查找结构体类型信息 + # obj_ptr 类型应该是 Ptr(Struct(...)) + match obj_ptr.Ty: + case llvmlite.LLVMType.Ptr(struct_ty): + # 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段) + HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) + # 查找字段索引和类型 + field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + struct_ty, at.attr) + # REnum 变体字段查找: lookup_field 失败时,尝试 REnum 别名 + # REnum 结构体字段名是 _p1/_p2/...,但源码用变体字段名访问(如 ty.Pointee) + if field_info is None: + renum_se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type( + struct_ty) + if renum_se is not None and renum_se.Name is not None: + is_rn: int = HandlesClassDef._is_renum_class_name(renum_se.Name) + if is_rn == 1: + alias_idx: int = HandlesClassDef._lookup_renum_field_alias( + renum_se.Name, at.attr) + if alias_idx >= 1: + alias_fe: HandlesStruct.FieldEntry | t.CPtr = \ + HandlesStruct._get_field_entry(renum_se, alias_idx) + if alias_fe is not None and alias_fe.Ty is not None: + alias_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, alias_fe.Ty, obj_ptr, alias_idx) + if alias_ptr is not None: + return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr) + # property getter 回退: obj.attr 是 @property/@x.getter 方法时生成调用 + # (字段未找到时先尝试,避免报误导性的"字段未找到"错误) + if field_info is None and at.value is not None and trans is not None: + prop_cls_fb: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) + prop_val: llvmlite.Value | t.CPtr = HandlesExprCall._try_property_getter_attr( + pool, builder, mod, at, obj_ptr, trans, prop_cls_fb) + if prop_val is not None: + return prop_val + # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找 + # 传递 SHA1 以区分跨模块同名类 + if field_info is None: + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_fb.id is not None: + var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm_fb.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + cur_sha1: str = trans.ModuleSha1 + field_info = HandlesStruct.lookup_field_by_class( + var_entry.AnnotClassName, at.attr, cur_sha1) + # 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型 + # 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)), + # 需用实际结构体类型做 GEP,否则 GEP i8 失败 + if field_info is not None: + annot_se: HandlesStruct.StructEntry | t.CPtr = \ + HandlesStruct.find_struct(var_entry.AnnotClassName) + if annot_se is not None and annot_se.Ty is not None: + annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \ + llvmlite.Ptr(pool, annot_se.Ty) + casted_ptr: llvmlite.Value | t.CPtr = \ + llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty) + if casted_ptr is not None: + obj_ptr = casted_ptr + struct_ty = annot_se.Ty + # 按需过滤更新 struct_ty 后,需重新确保 + # 注解类型结构体定义在当前模块可用 + # (原始 struct_ty 可能是 i8,ensure 无效) + HandlesStruct.ensure_struct_def_in_module( + pool, mod, annot_se.Ty) + if field_info is not None: + field_ty: llvmlite.LLVMType | t.CPtr = field_info.Ty + # 联合体:bitcast obj_ptr 到 field_ty* 后 load + if HandlesStruct.is_union_by_type(struct_ty) == 1: + field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_ty) + casted: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, obj_ptr, field_ptr_ty) + if casted is not None: + return llvmlite.build_load(builder, field_ty, casted) + return None + # 普通结构体:GEP + load + field_idx: int = field_info.Index + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, field_ty, obj_ptr, field_idx) + if field_ptr is not None: + # 数组类型字段不能 load 为 SSA value,直接返回字段指针 + # 用于后续下标访问: self.state[0] → GEP state 字段 → GEP 数组元素 + if self.is_array_type(field_ty) != 0: + return field_ptr + loaded_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, field_ty, field_ptr) + # 联合类型字段(如 Token | t.CPtr)被编译为 i8*, + # 若 AnnotClassName 指示了具体结构体类型,bitcast 为正确的结构体指针。 + # 注意:仅当字段类型本身是指针时才 bitcast(指针→指针); + # 内嵌结构体字段(field_ty=Struct)load 出的是结构体值, + # bitcast 值→指针是非法 IR(llc: invalid cast opcode)。 + if loaded_val is not None and field_info.AnnotClassName is not None \ + and self.is_ptr_type(field_ty) != 0: + annot_struct: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( + field_info.AnnotClassName) + if annot_struct is not None and annot_struct.Ty is not None: + annot_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, annot_struct.Ty) + return llvmlite.build_bitcast(builder, loaded_val, annot_ptr_ty) + return loaded_val + # fast-fail: 字段未找到,打印诊断信息 + if trans is not None: + diag_annot: str = None + diag_var_nm: str = None + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + diag_var_nm = dnm.id + if dnm.id is not None: + dve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, dnm.id) + if dve is not None: + diag_annot = dve.AnnotClassName + fb_attr: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_attr is not None: + viperlib.snprintf(fb_attr, 1024, + "属性访问失败: .%s (var=%s annot=%s sha1=%s:%d)", + at.attr, + diag_var_nm if diag_var_nm is not None else "?", + diag_annot if diag_annot is not None else "None", + trans.ModuleSha1 if trans.ModuleSha1 is not None else "?", + at.lineno if at.lineno is not None else 0) + VLogger.error(fb_attr, "ATTR") + return None + case _: + # fast-fail: 对非指针类型做属性访问(如 i32.x), + # Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃,丢失错误现场) + attr_nm_ap: str = "?" + if at is not None and at.attr is not None: + attr_nm_ap = at.attr + sha1_ap: str = "?" + if trans is not None and trans.ModuleSha1 is not None: + sha1_ap = trans.ModuleSha1 + ln_ap: int = 0 + if at is not None and at.lineno is not None: + ln_ap = at.lineno + HandlesType.fatal_error( + at, + f"属性访问失败: .{attr_nm_ap} (base=非指针类型,无法做属性访问 sha1={sha1_ap}:{ln_ap})", + "TypeError") + + # ============================================================ + # 获取下标表达式的元素指针(不加载值,用于赋值) + # ============================================================ + def get_subscript_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """获取下标表达式的元素指针(用于赋值 lhs)""" + if node is None or builder is None: + return None + sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) + if sub is None: + return None + + # 翻译索引 + idx_val: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, sub.slice, None, 0, trans) + if idx_val is None: + return None + + # 如果 value 是 Name,尝试从 alloca 类型推断 + if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) + if nm.id is not None and trans is not None: + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is not None and alloca.Ty is not None: + if self.is_ptr_type(alloca.Ty) != 0: + pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee + if pointee is not None: + # 用 match 检查 pointee 类型 + match pointee: + case llvmlite.LLVMType.Array(elem_ty, count): + # 数组遍历 + return llvmlite.build_gep_array( + builder, pointee, elem_ty, alloca, + self._zext_index_to_i32(builder, idx_val)) + case llvmlite.LLVMType.Ptr(inner_ty): + # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针, + # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 + # 此时 [i]=val 应该是指针解引用赋值, 而非调用 __setitem__。 + if self.is_ptr_type(inner_ty) != 0: + ptr_val_gsp: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val_gsp is not None: + return llvmlite.build_gep( + builder, inner_ty, ptr_val_gsp, idx_val) + return None + # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): + # 仅当类定义了 __setitem__(当前模块定义或跨模块 stub declare 注入) + # 才返回 None 触发 __setitem__ 重载;否则普通结构体指针按下标 + # 做 GEP 数组访问(走下方指针遍历路径) + cls_nm_ptr_chk: str = self._get_custom_struct_cls_nm(pool, inner_ty) + if not (cls_nm_ptr_chk is None): + si_lookup_gsp: t.CChar | t.CPtr = pool.alloc(128) + if si_lookup_gsp is not None: + viperlib.snprintf(si_lookup_gsp, 128, "%s.__setitem__", cls_nm_ptr_chk) + if HandlesExprCall.find_func_in_module(mod, si_lookup_gsp) is not None: + return None + # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, + # 直接 GEP 按 i8* 步长(8 字节),不 load + # 仅当 inner_ty 不是自定义结构体时才走指针遍历 + if trans is not None: + ve_pe: HandlesVar.VarEntry | t.CPtr = \ + HandlesVar.lookup_var_entry(trans.SymTab, nm.id) + if ve_pe is not None and ve_pe.IsPtrElement == 1: + return llvmlite.build_gep( + builder, pointee, alloca, idx_val) + # 普通指针遍历: 先 load 指针值,再 GEP + ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, pointee, alloca) + if ptr_val is None: + return None + gep_r: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, inner_ty, ptr_val, idx_val) + return gep_r + case _: + # pointee 是普通标量类型 (如 i64, i32, i8): + # alloca 是 Ptr(标量), 直接 GEP 获取第 idx 个元素指针 + # 支持 arg_vals[i] = val 这类参数数组下标赋值 + return llvmlite.build_gep(builder, pointee, alloca, idx_val) + + # 通用路径 + ptr_val: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, sub.value, None, 0, trans) + if ptr_val is None or ptr_val.Ty is None: + return None + if self.is_ptr_type(ptr_val.Ty) != 0: + elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee + if elem_ty2 is not None: + # 数组类型: 双索引 GEP (getelementptr [N x ty], ptr, i32 0, i32 idx) + match elem_ty2: + case llvmlite.LLVMType.Array(arr_elem_ty, arr_count): + return llvmlite.build_gep_array( + builder, elem_ty2, arr_elem_ty, ptr_val, + self._zext_index_to_i32(builder, idx_val)) + case _: + pass + # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __setitem__ + # 才返回 None 触发 HandlesAssign 的 __setitem__ 重载; + # 否则普通结构体指针按下标做 GEP 数组访问 + cls_nm_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2) + if not (cls_nm_gen is None): + si_lookup_gen: t.CChar | t.CPtr = pool.alloc(128) + if si_lookup_gen is not None: + viperlib.snprintf(si_lookup_gen, 128, "%s.__setitem__", cls_nm_gen) + if find_func_in_module(mod, si_lookup_gen) is not None: + return None + # 指针类型: 单索引 GEP (getelementptr ty, ptr, idx) + return llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val) + return None + + # ============================================================ + # 获取属性访问的字段指针(不加载值,用于赋值) + # 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) + # ============================================================ + def get_attribute_ptr(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """获取属性访问的字段指针(用于赋值 lhs)""" + if node is None or builder is None: + return None + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at is None or at.value is None or at.attr is None: + return None + + # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体) + obj_ptr: llvmlite.Value | t.CPtr = None + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm.id is not None: + obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) + + # 模块属性访问 (写路径): sys._mbuddy = mb → store 到全局变量 @_mbuddy + # 当 obj 是已导入模块名且不是普通变量时,查找/创建全局变量引用 + if obj_ptr is None and at.value.kind() == ast.ASTKind.Name and trans is not None: + nm_wma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_wma.id is not None: + # CDefine 常量不可写: 报 FATAL 错误,不创建未定义全局 + if self._is_cdefine_name_pattern(at.attr) != 0: + err_buf_wma: str = pool.alloc(256) + if err_buf_wma is not None: + viperlib.snprintf(err_buf_wma, 256, + "[CD] FATAL: Cannot assign to CDefine constant '%s.%s'\n", + nm_wma.id, at.attr) + VLogger.error(err_buf_wma, "CD") + return None + # 使用 i8* 作为类型提示 (模块级变量通常存储指针) + i8_ptr_w: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + wma_ref: llvmlite.Value | t.CPtr = self._resolve_module_attribute_global( + pool, mod, trans, at, i8_ptr_w) + if wma_ref is not None: + return wma_ref + + # 非 Name 路径:翻译对象值(会 load) + if obj_ptr is None: + # c.Deref(ptr).attr: 属性写入 base 取指针本身而非 load 后的结构体值 + # (如 c.Deref(p).a = val 语义是 (*p).a = val,直接对 p 做 GEP) + cd_base_wr: llvmlite.Value | t.CPtr = self._get_cderef_attr_base( + builder, pool, mod, at.value, trans) + if cd_base_wr is not None: + obj_ptr = cd_base_wr + elif at.value.kind() == ast.ASTKind.Subscript: + # 下标基座属性写入(如 pts[0].x = val):list[T]/OOP __getitem__ 类走 + # translate_value(返回元素值/地址);普通结构体指针数组走 + # get_subscript_ptr(GEP 元素地址,避免结构体值 base=非指针 报错) + if self._sub_base_uses_getitem(pool, mod, trans, at.value) != 0: + obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) + else: + obj_ptr = self.get_subscript_ptr(builder, pool, mod, at.value, trans) + elif at.value.kind() == ast.ASTKind.Attribute: + # 嵌套属性基座写入(如 r.origin.x = val):取内层字段地址 + # (get_attribute_ptr 递归,地址语义),指针字段由 _deref_if_ptr_ptr 解引用 + obj_ptr = self.get_attribute_ptr(builder, pool, mod, at.value, trans) + if obj_ptr is None: + obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) + else: + obj_ptr = self.translate_value(builder, pool, mod, at.value, None, 0, trans) + + if obj_ptr is None or obj_ptr.Ty is None: + return None + + # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), + # load 解引用获取 Ptr(Struct) + obj_ptr = self._deref_if_ptr_ptr(builder, obj_ptr) + + match obj_ptr.Ty: + case llvmlite.LLVMType.Ptr(struct_ty): + # 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段) + # 与 translate_attribute 一致,避免 opaque 类型导致 GEP 报错 + HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) + field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + struct_ty, at.attr) + # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找 + # 传递 SHA1 以区分跨模块同名类 + if field_info is None: + if at.value.kind() == ast.ASTKind.Name and trans is not None: + nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_fb.id is not None: + var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm_fb.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + cur_sha1: str = None + if trans is not None: + cur_sha1 = trans.ModuleSha1 + field_info = HandlesStruct.lookup_field_by_class( + var_entry.AnnotClassName, at.attr, cur_sha1) + # 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型 + # 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)), + # 需用实际结构体类型做 GEP,否则 GEP i8 失败 + if field_info is not None: + annot_se: HandlesStruct.StructEntry | t.CPtr = \ + HandlesStruct.find_struct(var_entry.AnnotClassName) + if annot_se is not None and annot_se.Ty is not None: + annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \ + llvmlite.Ptr(pool, annot_se.Ty) + casted_ptr: llvmlite.Value | t.CPtr = \ + llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty) + if casted_ptr is not None: + obj_ptr = casted_ptr + struct_ty = annot_se.Ty + # 按需过滤更新 struct_ty 后,需重新确保 + # 注解类型结构体定义在当前模块可用 + HandlesStruct.ensure_struct_def_in_module( + pool, mod, annot_se.Ty) + if field_info is not None: + # 联合体:bitcast obj_ptr 到 field_ty*(字段指针用于 store) + if HandlesStruct.is_union_by_type(struct_ty) == 1: + field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_info.Ty) + return llvmlite.build_bitcast(builder, obj_ptr, field_ptr_ty) + # 普通结构体:GEP 获取字段指针 + return llvmlite.build_gep_struct( + builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index) + # fast-fail: 字段未找到,打印诊断信息 + if trans is not None: + diag_annot_g: str = None + diag_var_nm_g: str = None + if at.value is not None and at.value.kind() == ast.ASTKind.Name: + dnm_g: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + diag_var_nm_g = dnm_g.id + if dnm_g.id is not None: + dve_g: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, dnm_g.id) + if dve_g is not None: + diag_annot_g = dve_g.AnnotClassName + fb_attr_g: t.CChar | t.CPtr = VLogger.fmt_buf() + if fb_attr_g is not None: + viperlib.snprintf(fb_attr_g, 1024, + "属性写入失败: .%s (var=%s annot=%s sha1=%s:%d)", + at.attr, + diag_var_nm_g if diag_var_nm_g is not None else "?", + diag_annot_g if diag_annot_g is not None else "None", + trans.ModuleSha1 if trans.ModuleSha1 is not None else "?", + at.lineno if at.lineno is not None else 0) + VLogger.error(fb_attr_g, "ATTR") + return None + case _: + # fast-fail: 对非指针类型做属性写入(如 i32.x = ...), + # Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃) + attr_nm_gp: str = "?" + if at is not None and at.attr is not None: + attr_nm_gp = at.attr + sha1_gp: str = "?" + if trans is not None and trans.ModuleSha1 is not None: + sha1_gp = trans.ModuleSha1 + ln_gp: int = 0 + if at is not None and at.lineno is not None: + ln_gp = at.lineno + HandlesType.fatal_error( + at, + f"属性写入失败: .{attr_nm_gp} (base=非指针类型,无法做属性写入 sha1={sha1_gp}:{ln_gp})", + "TypeError") + + # ============================================================ + # P3 迁移方法(来自 HandlesExprOps.vp:运算符重载 + 二元运算) + # ============================================================ + + # ============================================================ + # BinOp 运算符 → dunder 方法名 + # ============================================================ + def _binop_to_dunder(self, op: int) -> str: + """将 BinOp 运算符映射到 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 "__div__" + if op == ast.OpKind.Mod: return "__mod__" + 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.FloorDiv: return "__floordiv__" + return None + + # ============================================================ + # Compare 运算符 → dunder 方法名 + # ============================================================ + def _cmpop_to_dunder(self, op: int) -> str: + """将 Compare 运算符映射到 dunder 方法名,无映射时返回 None""" + if op == ast.OpKind.Eq: return "__eq__" + if op == ast.OpKind.Ne: return "__ne__" + if op == ast.OpKind.Lt: return "__lt__" + if op == ast.OpKind.Le: return "__le__" + if op == ast.OpKind.Gt: return "__gt__" + if op == ast.OpKind.Ge: return "__ge__" + return None + + # ============================================================ + # UnaryOp 运算符 → dunder 方法名 + # ============================================================ + def _unaryop_to_dunder(self, op: int) -> str: + """将 UnaryOp 运算符映射到 dunder 方法名,无映射时返回 None""" + if op == ast.OpKind.USub: return "__neg__" + if op == ast.OpKind.UAdd: return "__pos__" + if op == ast.OpKind.Invert: return "__invert__" + return None + + # ============================================================ + # try_operator_overload - 尝试运算符重载 + # + # 检查 lhs 是否为结构体指针,并在该类(含继承链)中查找对应的 + # dunder 方法。找到则生成方法调用 lhs.__dunder__(rhs),返回 + # 调用结果;未找到返回 None,调用方回退到原生运算。 + # ============================================================ + def try_operator_overload(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + lhs: llvmlite.Value | t.CPtr, + rhs: llvmlite.Value | t.CPtr, + op: int, + trans: HT.Translator | t.CPtr, + is_compare: int) -> llvmlite.Value | t.CPtr: + """尝试运算符重载:lhs 是结构体指针时调用 dunder 方法,否则返回 None""" + if lhs is None or rhs is None: + return None + + # 延迟导入避免循环依赖 + import lib.core.Handles.HandlesStruct as HandlesStruct + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + # 映射运算符到 dunder 方法名 + dunder: str = None + if is_compare != 0: + dunder = self._cmpop_to_dunder(op) + else: + dunder = self._binop_to_dunder(op) + if dunder is None: + return None + + # 检查 lhs 是否为结构体指针 + struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(lhs) + if struct_ty is None: + return None + + # 获取类名 + class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) + if class_name is None: + return None + + # 在继承链中查找 dunder 方法 + lookup_name: t.CChar | t.CPtr = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) + found_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, lookup_name) + + search_class: str = class_name + if found_func is None: + # 多继承:沿 MRO 祖先链查找(先声明父类优先) + 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: + parent_lookup: t.CChar | t.CPtr = pool.alloc(128) + if parent_lookup is not None: + viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) + parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup) + if parent_func is not None: + found_func = parent_func + search_class = anc + break + mi += 1 + + # 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入) + # 优先用类型指针定位 entry 获取 SHA1(规避跨模块同名 find_struct 找错) + cls_sha1: str = None + op_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + if op_entry is not None: + cls_sha1 = op_entry.ModuleSha1 + if cls_sha1 is None: + cls_sha1 = HandlesStruct.get_struct_sha1(search_class) + if cls_sha1 is None: + mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class) + mj: int = 1 + while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None: + anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr)) + if anc_p is not None: + cls_sha1 = HandlesStruct.get_struct_sha1(anc_p) + mj += 1 + + # 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算 + if found_func is None and cls_sha1 is None: + return None + + # 构建 extra_args 数组(仅含 rhs 一个参数) + extra_args: t.CSizeT | t.CPtr = pool.alloc(8) + if extra_args is None: + return None + extra_args[0] = t.CSizeT(rhs) + + # 调用方法: lhs.__dunder__(rhs) + return HandlesExprCall._call_method_on_ptr( + pool, builder, mod, search_class, dunder, + lhs, extra_args, 1, trans) + + # ============================================================ + # try_unary_operator_overload - 尝试一元运算符重载 + # + # 检查 operand 是否为结构体指针,并在该类(含继承链)中查找对应的 + # dunder 方法(__neg__/__pos__/__invert__)。找到则生成方法调用 + # operand.__dunder__(),返回调用结果;未找到返回 None,调用方回退到原生运算。 + # ============================================================ + def try_unary_operator_overload(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + operand: llvmlite.Value | t.CPtr, + op: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """尝试一元运算符重载:operand 是结构体指针时调用 dunder 方法,否则返回 None""" + if operand is None: + return None + + # 延迟导入避免循环依赖 + import lib.core.Handles.HandlesStruct as HandlesStruct + import lib.core.Handles.HandlesExprCall as HandlesExprCall + + dunder: str = self._unaryop_to_dunder(op) + if dunder is None: + return None + + # 检查 operand 是否为结构体指针 + struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(operand) + if struct_ty is None: + return None + + # 获取类名 + class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) + if class_name is None: + return None + + # 在继承链中查找 dunder 方法 + lookup_name: t.CChar | t.CPtr = pool.alloc(128) + if lookup_name is None: + return None + viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) + found_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, lookup_name) + + search_class: str = class_name + if found_func is None: + # 多继承:沿 MRO 祖先链查找(先声明父类优先) + 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: + parent_lookup: t.CChar | t.CPtr = pool.alloc(128) + if parent_lookup is not None: + viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) + parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup) + if parent_func is not None: + found_func = parent_func + search_class = anc + break + mi += 1 + + # 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入) + cls_sha1: str = None + uop_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + if uop_entry is not None: + cls_sha1 = uop_entry.ModuleSha1 + if cls_sha1 is None: + cls_sha1 = HandlesStruct.get_struct_sha1(search_class) + if cls_sha1 is None: + mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class) + mj: int = 1 + while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None: + anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr)) + if anc_p is not None: + cls_sha1 = HandlesStruct.get_struct_sha1(anc_p) + mj += 1 + + # 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算 + if found_func is None and cls_sha1 is None: + return None + + # 一元方法无额外参数(extra_args 为空) + return HandlesExprCall._call_method_on_ptr( + pool, builder, mod, search_class, dunder, + operand, None, 0, trans) + + # ============================================================ + # 翻译二元运算(自动类型提升) + # ============================================================ + def translate_binop(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """翻译二元运算(自动类型提升)""" + binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if binop is None: + return None + + lhs_node: ast.AST | t.CPtr = binop.left + rhs_node: ast.AST | t.CPtr = binop.right + op: int = binop.op + + # 先翻译 rhs(只翻译一次,避免副作用重复) + rhs: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, rhs_node, None, 0, trans) + if rhs is None: + return None + + # === 运算符重载路径 1: lhs 是 Name 且对应结构体变量 === + # 对于值类型变量(如 cnt: Counter),translate_value 会 load 返回 Struct 值, + # 但 dunder 方法需要 Ptr(Struct) 作为 self。直接用 alloca 指针尝试重载。 + if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) + if nm is not None and nm.id is not None: + lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, nm.id) + if lhs_alloca is not None: + ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload( + pool, builder, mod, lhs_alloca, rhs, op, trans, 0) + if ovl_result is not None: + return ovl_result + + # 正常翻译 lhs + lhs: llvmlite.Value | t.CPtr = self.translate_value( + builder, pool, mod, lhs_node, None, 0, trans) + if lhs is None: + return None + + # === 运算符重载路径 2: lhs 是 Ptr(Struct)(如 Counter|t.CPtr 变量 load 后)=== + ovl_result2: llvmlite.Value | t.CPtr = self.try_operator_overload( + pool, builder, mod, lhs, rhs, op, trans, 0) + if ovl_result2 is not None: + return ovl_result2 + + # 获取操作数类型信息 + lhs_bits: int = self.get_llvm_type_bits(lhs.Ty) + rhs_bits: int = self.get_llvm_type_bits(rhs.Ty) + lhs_fbits: int = self.get_llvm_float_bits(lhs.Ty) + rhs_fbits: int = self.get_llvm_float_bits(rhs.Ty) + + # 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查, + # 因为 float 的 int bits 为 0,会被误认为指针) + if lhs_fbits != 0 or rhs_fbits != 0: + # 确定目标浮点类型(使用较大的位宽) + target_fbits: int = lhs_fbits + if rhs_fbits > target_fbits: + target_fbits = rhs_fbits + target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + if target_fbits == 32: + target_float_ty = llvmlite.Float(pool) + # 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc) + lhs = self.coerce_to_type(builder, lhs, target_float_ty, node) + rhs = self.coerce_to_type(builder, rhs, target_float_ty, node) + if op == ast.OpKind.Add: + return llvmlite.build_fadd(builder, lhs, rhs) + if op == ast.OpKind.Sub: + return llvmlite.build_fsub(builder, lhs, rhs) + if op == ast.OpKind.Mult: + return llvmlite.build_fmul(builder, lhs, rhs) + if op == ast.OpKind.Div: + return llvmlite.build_fdiv(builder, lhs, rhs) + if op == ast.OpKind.Mod: + return llvmlite.build_frem(builder, lhs, rhs) + return None + + # 指针算术: ptr + int / ptr - int / int + ptr → getelementptr(按元素大小缩放) + # 对齐 TPC ExprGen.emit_binary_op L50-67;int - ptr 无 GEP 形式(C 语义非法) + if (lhs_bits == 0 and rhs_bits != 0) or (lhs_bits != 0 and rhs_bits == 0): + if op == ast.OpKind.Add: + if lhs_bits == 0: + return self.translate_ptr_arith(pool, builder, lhs, rhs, op) + # int + ptr(交换) + return self.translate_ptr_arith(pool, builder, rhs, lhs, op) + if op == ast.OpKind.Sub and lhs_bits == 0: + return self.translate_ptr_arith(pool, builder, lhs, rhs, op) + + if lhs_bits > rhs_bits: + if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0: + rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) + else: + rhs = self.coerce_to_type(builder, rhs, lhs.Ty, node) + elif rhs_bits > lhs_bits: + if self.should_zext_widen(pool, lhs, rhs, lhs_node) != 0: + lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) + else: + lhs = self.coerce_to_type(builder, lhs, rhs.Ty, node) + + # 位运算类型安全检查:两边都是指针(lhs_bits==0 and rhs_bits==0)时, + # 位运算(BitOr/BitAnd/BitXor/LShift/RShift)非法,LLVM 要求整数操作数。 + # 常见触发场景:CDefine 常量查找失败返回指针 null,与另一指针做 `|`。 + if lhs_bits == 0 and rhs_bits == 0: + if op == ast.OpKind.BitOr or op == ast.OpKind.BitAnd or op == ast.OpKind.BitXor or op == ast.OpKind.LShift or op == ast.OpKind.RShift: + VLogger.error( + "位运算操作数类型非法: lhs/rhs 均为非整数类型(指针或结构体),无法执行位运算", + "BinOp") + return None + + if op == ast.OpKind.Add: + return llvmlite.build_add(builder, lhs, rhs) + elif op == ast.OpKind.Sub: + return llvmlite.build_sub(builder, lhs, rhs) + elif op == ast.OpKind.Mult: + return llvmlite.build_mul(builder, lhs, rhs) + elif op == ast.OpKind.Div: + return llvmlite.build_sdiv(builder, lhs, rhs) + elif op == ast.OpKind.FloorDiv: + return llvmlite.build_sdiv(builder, lhs, rhs) + elif op == ast.OpKind.Mod: + return llvmlite.build_srem(builder, lhs, rhs) + elif op == ast.OpKind.BitAnd: + return llvmlite.build_and(builder, lhs, rhs) + elif op == ast.OpKind.BitOr: + return llvmlite.build_or(builder, lhs, rhs) + elif op == ast.OpKind.BitXor: + return llvmlite.build_xor(builder, lhs, rhs) + elif op == ast.OpKind.LShift: + return llvmlite.build_shl(builder, lhs, rhs) + elif op == ast.OpKind.RShift: + # 无符号 >> → lshr(逻辑右移),有符号 >> → ashr(算术右移) + # 对齐 TPC ExprGen.emit_binary_op:i8/i16 默认无符号;其余查操作数无符号性 + if lhs_bits == 8 or lhs_bits == 16: + return llvmlite.build_lshr(builder, lhs, rhs) + if self._node_type_unsigned(pool, lhs_node, trans) != 0: + return llvmlite.build_lshr(builder, lhs, rhs) + return llvmlite.build_ashr(builder, lhs, rhs) + return None diff --git a/App/lib/core/Gen/Generator.vp b/App/lib/core/Gen/Generator.vp index eca5d87..63e3b12 100644 --- a/App/lib/core/Gen/Generator.vp +++ b/App/lib/core/Gen/Generator.vp @@ -5,6 +5,7 @@ import llvmlite import lib.core.Gen.BaseGenMixin as BaseGenMixin import lib.core.Gen.TypeGenMixin as TypeGenMixin import lib.core.Gen.StructGenMixin as StructGenMixin +import lib.core.Gen.ExprGenMixin as ExprGenMixin import lib.core.Handles.HandlesVar as HandlesVar import lib.core.Handles.HandlesExprCall as HandlesExprCall @@ -23,7 +24,7 @@ import lib.core.Handles.HandlesExprCall as HandlesExprCall # ============================================================ @t.NoVTable class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin, - StructGenMixin.StructGenMixin): + StructGenMixin.StructGenMixin, ExprGenMixin.ExprGenMixin): """生成器:多继承 Mixin 组合(对象化迁移宿主)""" def __init__(self, pool: memhub.MemBuddy | t.CPtr): diff --git a/App/lib/core/Handles/HandlesExpr.vp b/App/lib/core/Handles/HandlesExpr.vp index ad5f884..4819840 100644 --- a/App/lib/core/Handles/HandlesExpr.vp +++ b/App/lib/core/Handles/HandlesExpr.vp @@ -26,9 +26,37 @@ import lib.Projectrans.Utils as Utils # ============================================================ -# HandlesExpr - 表达式处理(Mixin 继承模式) +# HandlesExpr - 表达式处理(P3 对象化后的委托层) # -# 工具函数保留为模块级(供外部调用),ExprHandle.HandleValue 提供 trans 接口 +# 全部模块级函数已迁移为 lib.core.Gen.ExprGenMixin 的方法 +# (全局状态迁入 gen 字段),本模块保留同名模块级函数作为 +# "一行委托":延迟 import Gen 取全局单例(BuildPipeline/main +# 创建后 set_global_gen 注册),再调用 gen 的对应方法。签名与 +# 旧函数完全一致,调用方零改动。 +# +# ExprHandle 类及其 NewExprHandle 工厂保留(translator handler 模式)。 +# ============================================================ + + +# ============================================================ +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) +# +# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 +# P3 委托函数用本地 _g_gen(cast 成 Generator 类型)调 +# ExprGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。 +# ============================================================ +_g_gen: t.CVoid | t.CPtr = None + + +def set_global_gen(gen: t.CVoid | t.CPtr) -> None: + """注入全局 gen 单例(BuildPipeline/main 调用)""" + global _g_gen + _g_gen = gen + + +# ============================================================ +# 委托函数:延迟 import Gen 取全局单例 → 调 gen 方法 +# (gen 未注册时正常流程不会发生;有返回值函数返回默认值) # ============================================================ @@ -36,16 +64,11 @@ import lib.Projectrans.Utils as Utils # 从 AST 节点提取函数名 # ============================================================ def get_func_name(func_node: ast.AST | t.CPtr) -> str: - """从函数节点提取函数名""" - if func_node is None: - return None - k: int = func_node.kind() - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_node) - return nm.id - elif k == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(func_node) - return at.attr + """从函数节点提取函数名(委托到 gen.get_func_name)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.get_func_name(func_node) return None @@ -54,73 +77,36 @@ def get_func_name(func_node: ast.AST | t.CPtr) -> str: # ============================================================ def escape_llvm_string(pool: memhub.MemBuddy | t.CPtr, src: t.CChar | t.CPtr) -> t.CChar | t.CPtr: - """将字符串转换为 LLVM IR 字符串字面量 c"...\\00" """ - if src is None: - return None - slen: t.CSizeT = string.strlen(src) - alloc_size: t.CSizeT = 4 * slen + 8 - buf: t.CChar | t.CPtr = pool.alloc(alloc_size) - if buf is None: - return None - pos: t.CSizeT = 0 - buf[pos] = 'c' - pos += 1 - buf[pos] = '"' - pos += 1 - for i in range(slen): - ch: t.CChar = src[i] - if ch == '\0': - break - if ch == '\"' or ch == '\\' or ch < 0x20: - buf[pos] = '\\' - pos += 1 - hi: int = (ch >> 4) & 0xF - lo: int = ch & 0xF - buf[pos] = Utils.nibble_to_hex_char(hi, 1) - pos += 1 - buf[pos] = Utils.nibble_to_hex_char(lo, 1) - pos += 1 - else: - buf[pos] = ch - pos += 1 - buf[pos] = '\\' - pos += 1 - buf[pos] = '0' - pos += 1 - buf[pos] = '0' - pos += 1 - buf[pos] = '"' - pos += 1 - buf[pos] = '\0' - return buf + """将字符串转换为 LLVM IR 字符串字面量 c"...\\00"(委托到 gen.escape_llvm_string)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.escape_llvm_string(pool, src) + return None # ============================================================ # 获取 LLVM 整数类型的位宽 # ============================================================ def get_llvm_type_bits(ty: llvmlite.LLVMType | t.CPtr) -> int: - """获取 LLVM 整数类型的位宽,非整数类型返回 0""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Int(bits): - return bits - case _: - return 0 + """获取 LLVM 整数类型的位宽,非整数类型返回 0(委托到 gen.get_llvm_type_bits)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.get_llvm_type_bits(ty) + return 0 # ============================================================ # 获取 LLVM 浮点类型的位宽 # ============================================================ def get_llvm_float_bits(ty: llvmlite.LLVMType | t.CPtr) -> int: - """获取 LLVM 浮点类型的位宽,非浮点类型返回 0""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Float(bits): - return bits - case _: - return 0 + """获取 LLVM 浮点类型的位宽,非浮点类型返回 0(委托到 gen.get_llvm_float_bits)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.get_llvm_float_bits(ty) + return 0 # ============================================================ @@ -129,14 +115,12 @@ def get_llvm_float_bits(ty: llvmlite.LLVMType | t.CPtr) -> int: # 返回 1=是, 0=否。作为类型检查工具函数被广泛使用(50+ 处调用)。 # ============================================================ def is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int: - """检查 ty 是否是 Ptr 类型,返回 1=是, 0=否""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Ptr(pointee): - return 1 - case _: - return 0 + """检查 ty 是否是 Ptr 类型,返回 1=是, 0=否(委托到 gen.is_ptr_type)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.is_ptr_type(ty) + return 0 # ============================================================ @@ -147,27 +131,14 @@ def is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int: # 1 = 一级指针(如 i8*, Struct*) # 2 = 二级指针(如 i8**, Struct**) # 3+ = 更高级指针 -# -# 用于比较运算的类型安全检查: -# - 数值(0) vs 数值(0) → 允许 -# - 一级指针(1) vs 一级指针(1) → 允许 -# - 数值(0) vs 指针(1+) → 禁止(fast-fail) -# - 不同级指针(1 vs 2) → 禁止(fast-fail) # ============================================================ def get_ptr_level(ty: llvmlite.LLVMType | t.CPtr) -> int: - """计算指针层级,0=非指针, 1=一级指针, 2=二级指针...""" - if ty is None: - return 0 - level: int = 0 - cur: llvmlite.LLVMType | t.CPtr = ty - while cur is not None: - match cur: - case llvmlite.LLVMType.Ptr(pointee): - level += 1 - cur = pointee - case _: - break - return level + """计算指针层级,0=非指针, 1=一级指针, 2=二级指针...(委托到 gen.get_ptr_level)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.get_ptr_level(ty) + return 0 # ============================================================ @@ -176,14 +147,12 @@ def get_ptr_level(ty: llvmlite.LLVMType | t.CPtr) -> int: # 返回 1=是, 0=否。类型检查工具函数。 # ============================================================ def is_array_type(ty: llvmlite.LLVMType | t.CPtr) -> int: - """检查 ty 是否是 Array 类型,返回 1=是, 0=否""" - if ty is None: - return 0 - match ty: - case llvmlite.LLVMType.Array(_, _): - return 1 - case _: - return 0 + """检查 ty 是否是 Array 类型,返回 1=是, 0=否(委托到 gen.is_array_type)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.is_array_type(ty) + return 0 # ============================================================ @@ -192,18 +161,15 @@ def is_array_type(ty: llvmlite.LLVMType | t.CPtr) -> int: # LLVM GEP 对窄整数索引默认符号扩展:i8 0xE2(226) 会被当成 -30, # 导致数组下标越界读(字节 >= 128 的乱码根因)。 # 数组下标语义为非负,<32 位整数索引一律 zext 到 i32。 -# 仅用于数组 GEP;指针负偏移(p[-1])不经过此路径,不受影响。 # ============================================================ def _zext_index_to_i32(builder: llvmlite.IRBuilder | t.CPtr, idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """将 <32 位整数下标零扩展到 i32(数组下标非负语义)""" - if idx_val is None or idx_val.Ty is None or builder is None: - return idx_val - idx_bits: int = get_llvm_type_bits(idx_val.Ty) - if idx_bits != 0 and idx_bits < 32: - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(builder.Pool) - return llvmlite.build_zext(builder, idx_val, i32_ty) - return idx_val + """将 <32 位整数下标零扩展到 i32(数组下标非负语义)(委托到 gen._zext_index_to_i32)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._zext_index_to_i32(builder, idx_val) + return None # ============================================================ @@ -212,67 +178,28 @@ def _zext_index_to_i32(builder: llvmlite.IRBuilder | t.CPtr, # 处理两种情况: # - ty 直接是 Struct → 检查是否注册 # - ty 是 Ptr(Struct) → 检查 pointee 是否注册 -# -# 返回类名字符串或 None。用于 subscript 操作中判断是否需要 -# 转发到 __getitem__/__setitem__ 而非生成 GEP。 # ============================================================ def _get_custom_struct_cls_nm(pool: memhub.MemBuddy | t.CPtr, ty: llvmlite.LLVMType | t.CPtr) -> str: - """检查 ty 或 ty 的 pointee 是否是已注册的自定义结构体,返回类名或 None""" - if ty is None: - return None - # 直接检查 ty 是否是注册的结构体 - cls_nm_direct: str = HandlesStruct.get_class_name_by_type(pool, ty) - if cls_nm_direct is not None: - return cls_nm_direct - # 如果 ty 是 Ptr,检查 pointee - if is_ptr_type(ty) != 0: - pointee_cs: llvmlite.LLVMType | t.CPtr = ty.Pointee - if pointee_cs is not None: - return HandlesStruct.get_class_name_by_type(pool, pointee_cs) + """检查 ty 或 ty 的 pointee 是否是已注册的自定义结构体,返回类名或 None(委托到 gen._get_custom_struct_cls_nm)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._get_custom_struct_cls_nm(pool, ty) return None # ============================================================ # _is_list_subscript_base - 判断下标基座是否为 list[T] 变量 -# -# 属性访问的 Subscript 基座(如 lst[i].x)需要区分: -# - list[T] 变量:translate_subscript 走 __getitem__ 内联返回元素地址 -# - 普通结构体指针数组(如 pts: Point | t.CPtr):get_subscript_ptr 返回元素地址 -# 路由错误会让 list[T] 被当作结构体数组 GEP,访问错位崩溃。 # ============================================================ def _is_list_subscript_base(pool: memhub.MemBuddy | t.CPtr, trans: HT.Translator | t.CPtr, sub_node: ast.AST | t.CPtr) -> int: - """判断下标基座是否为 list[T] 变量(1=是)""" - if sub_node is None or trans is None: - return 0 - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node) - if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name: - return 0 - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is None: - return 0 - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None or alloca.Ty is None: - return 0 - if is_ptr_type(alloca.Ty) == 0: - return 0 - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None: - return 0 - match pointee: - case llvmlite.LLVMType.Ptr(inner_ty): - lsn_ls: str = None - match inner_ty: - case llvmlite.LLVMType.Struct(_, _, lsn3): - lsn_ls = lsn3 - case _: - pass - if lsn_ls is not None and string.strstr(lsn_ls, "list[") is not None: - return 1 - case _: - pass + """判断下标基座是否为 list[T] 变量(1=是)(委托到 gen._is_list_subscript_base)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._is_list_subscript_base(pool, trans, sub_node) return 0 @@ -282,82 +209,40 @@ def _is_list_subscript_base(pool: memhub.MemBuddy | t.CPtr, def _sub_base_class_name(pool: memhub.MemBuddy | t.CPtr, trans: HT.Translator | t.CPtr, sub_node: ast.AST | t.CPtr) -> str: - """解析下标基座变量的结构体类名(无则 None)""" - if sub_node is None or trans is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node) - if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name: - return None - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is None: - return None - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None or alloca.Ty is None: - return None - if is_ptr_type(alloca.Ty) == 0: - return None - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None: - return None - if is_ptr_type(pointee) != 0: - inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee - if inner is not None: - return HandlesStruct.get_class_name_by_type(pool, inner) - return HandlesStruct.get_class_name_by_type(pool, pointee) + """解析下标基座变量的结构体类名(无则 None)(委托到 gen._sub_base_class_name)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._sub_base_class_name(pool, trans, sub_node) + return None # ============================================================ # _sub_base_uses_getitem - 下标基座是否应走 __getitem__ 语义 -# -# 属性访问的 Subscript 基座路由依据: -# - list[T] / OOP 定义 __getitem__ 的类(如 dict[key])→ translate_value -# (translate_subscript 走 __getitem__ 内联/方法调用返回元素值或地址) -# - 普通结构体指针数组(如 pts: Point | t.CPtr)→ get_subscript_ptr -# (GEP 元素地址,避免结构体值 base=非指针 报错) # ============================================================ def _sub_base_uses_getitem(pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, trans: HT.Translator | t.CPtr, sub_node: ast.AST | t.CPtr) -> int: - """下标基座应走 __getitem__ 语义时返回 1,否则 0(应走 GEP 地址语义)""" - if _is_list_subscript_base(pool, trans, sub_node) != 0: - return 1 - cls_ugi: str = _sub_base_class_name(pool, trans, sub_node) - if cls_ugi is None: - return 0 - lookup_ugi: t.CChar | t.CPtr = pool.alloc(128) - if lookup_ugi is None: - return 0 - viperlib.snprintf(lookup_ugi, 128, "%s.__getitem__", cls_ugi) - if HandlesExprCall.find_func_in_module(mod, lookup_ugi) is not None: - return 1 + """下标基座应走 __getitem__ 语义时返回 1,否则 0(应走 GEP 地址语义)(委托到 gen._sub_base_uses_getitem)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._sub_base_uses_getitem(pool, mod, trans, sub_node) return 0 # ============================================================ # _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用 -# -# 用于支持 X|t.CPtr 类型变量的属性访问: -# - 值类型变量 (cnt: Counter): alloca 类型是 Ptr(Struct) → 不解引用 -# - 指针类型变量 (r: Vec2|t.CPtr): alloca 类型是 Ptr(Ptr(Struct)) → load 解引用 # ============================================================ def _deref_if_ptr_ptr(builder: llvmlite.IRBuilder | t.CPtr, obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针""" - if obj_ptr is None or obj_ptr.Ty is None: - return obj_ptr - if is_ptr_type(obj_ptr.Ty) == 0: - return obj_ptr - pointee: llvmlite.LLVMType | t.CPtr = obj_ptr.Ty.Pointee - if pointee is None: - return obj_ptr - if is_ptr_type(pointee) == 0: - return obj_ptr - # obj_ptr 是 Ptr(Ptr(...)),load 解引用 - loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, obj_ptr) - if loaded is None: - return obj_ptr - return loaded + """如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针(委托到 gen._deref_if_ptr_ptr)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._deref_if_ptr_ptr(builder, obj_ptr) + return None # ============================================================ @@ -367,78 +252,12 @@ def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr, val: llvmlite.Value | t.CPtr, target_ty: llvmlite.LLVMType | t.CPtr, node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """将 val 强制转换为 target_ty - - 整数: sext(扩展)/ trunc(截断) - 浮点: fpext(扩展)/ fptrunc(截断) - int→float: sitofp - float→int: fptosi - - node: AST 节点(用于错误定位),可为 None - """ - if val is None or target_ty is None: - return val - # 函数 → 指针: bitcast(如 CreateThread(..., _thread_alloc_free, ...) 传函数指针) - # 函数 Value 的 Ty 是 Func,既不是整数也不是指针,需在整数/浮点转换之前处理 - match val.Ty: - case llvmlite.LLVMType.Func(_, _, _): - if is_ptr_type(target_ty) != 0: - return llvmlite.build_bitcast(builder, val, target_ty) - return val - case _: - pass - # 整数转换 - val_bits: int = get_llvm_type_bits(val.Ty) - target_bits: int = get_llvm_type_bits(target_ty) - # 整数 → 指针: inttoptr(必须在纯整数转换之前检查,因为 ptr 的 bits 非零会误入 sext/trunc 路径) - # 适用于: 跨模块方法返回 i64/i32(默认推断),目标变量是指针类型 - if val_bits != 0 and is_ptr_type(target_ty) != 0: - return llvmlite.build_inttoptr(builder, val, target_ty) - # 指针 → 整数: ptrtoint(当目标明确是整数而非指针时) - # 注意: target_bits == 8 时跳过 ptrtoint,走后面的 build_load 解引用首字符 - # 修复: buf[idx] = '\0' 中 '\0' 是 CONST_STR → i8* 指针, - # ptrtoint 会截断地址低 8 位(非 0),应 load 解引用取首字符 0 - if is_ptr_type(val.Ty) != 0 and target_bits != 0 and target_bits != 8 and is_ptr_type(target_ty) == 0: - return llvmlite.build_ptrtoint(builder, val, target_ty) - if val_bits != 0 and target_bits != 0: - if val_bits == target_bits: - return val - if val_bits < target_bits: - # i1 (bool) → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF...) - # 与 HandlesReturn 中 return 语句的 i1 扩展规则保持一致 - if val_bits == 1: - return llvmlite.build_zext(builder, val, target_ty) - return llvmlite.build_sext(builder, val, target_ty) - return llvmlite.build_trunc(builder, val, target_ty) - # 浮点转换 - val_fbits: int = get_llvm_float_bits(val.Ty) - target_fbits: int = get_llvm_float_bits(target_ty) - # float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径) - if (val_fbits != 0 and is_ptr_type(target_ty) != 0) or \ - (is_ptr_type(val.Ty) != 0 and target_fbits != 0): - HandlesType.fatal_error(node, "unsupported type conversion: float <-> ptr", "CastError") - return val - if val_fbits != 0 and target_fbits != 0: - if val_fbits == target_fbits: - return val - if val_fbits < target_fbits: - return llvmlite.build_fpext(builder, val, target_ty) - return llvmlite.build_fptrunc(builder, val, target_ty) - # int → float - if val_bits != 0 and target_fbits != 0: - return llvmlite.build_si2fp(builder, val, target_ty) - # float → int - if val_fbits != 0 and target_bits != 0: - return llvmlite.build_fp2si(builder, val, target_ty) - # 指针 → 非指针值: build_load 解引用 - # 适用于: 指针 → 整数 (如 i8* → i8), 指针 → 结构体值 - # 当构造器返回 Ptr(Struct) 但目标变量是 Struct 值类型时,需要 load - if is_ptr_type(val.Ty) != 0 and is_ptr_type(target_ty) == 0: - return llvmlite.build_load(builder, target_ty, val) - # 指针 → 指针: bitcast (如 i8* → i8** 当目标是全局变量存储指针) - if is_ptr_type(val.Ty) != 0 and is_ptr_type(target_ty) != 0: - return llvmlite.build_bitcast(builder, val, target_ty) - return val + """将 val 强制转换为 target_ty(委托到 gen.coerce_to_type)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.coerce_to_type(builder, val, target_ty, node) + return None # ============================================================ @@ -446,58 +265,18 @@ def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr, # # 用 getelementptr(按 pointee 元素大小缩放索引),对齐 TPC # ExprGen.emit_binary_op / HandlesAugAssign.py。 -# 旧实现用 ptrtoint + add + inttoptr(按字节加):i8* 元素大小 1 -# 恰好正确,但 i32*/struct* 等指针 `p + 3` 只前进 3 字节(应 12), -# 导致 StringIterTest Test 4/8 失败(指针偏移/指针算术)。 -# -# 数组 pointee([N x ty]*)先 decay 为元素指针(GEP 0,0), -# 避免以整个数组为步长(对齐 TPC ExprGen L53-55)。 # ============================================================ def translate_ptr_arith(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, ptr_val: llvmlite.Value | t.CPtr, int_val: llvmlite.Value | t.CPtr, op: int) -> llvmlite.Value | t.CPtr: - """指针算术: ptr + int / ptr - int → GEP(按元素大小缩放索引)""" - if ptr_val is None or int_val is None or ptr_val.Ty is None: - return None - # 提取 pointee 类型(非指针 → 不处理返回 None) - elem_ty: llvmlite.LLVMType | t.CPtr = None - match ptr_val.Ty: - case llvmlite.LLVMType.Ptr(pointee): - elem_ty = pointee - case _: - return None - if elem_ty is None: - return None - # 索引统一到 i64(对齐 TPC zext 到 i64) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - idx: llvmlite.Value | t.CPtr = coerce_to_type(builder, int_val, i64_ty, None) - if idx is None: - return None - # ptr - int → 负索引(LLVM GEP 索引为加法语义) - if op == ast.OpKind.Sub: - neg_idx: llvmlite.Value | t.CPtr = llvmlite.build_sub( - builder, llvmlite.const_int64(pool, 0), idx) - if neg_idx is None: - return None - idx = neg_idx - # 数组 pointee → 先 decay 为元素指针(getelementptr [N x ty], [N x ty]* %p, i32 0, i32 0) - if is_array_type(elem_ty) != 0: - inner_ty: llvmlite.LLVMType | t.CPtr = None - match elem_ty: - case llvmlite.LLVMType.Array(inner, _): - inner_ty = inner - case _: - return None - if inner_ty is None: - return None - decayed: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, elem_ty, inner_ty, ptr_val, llvmlite.const_int64(pool, 0)) - if decayed is None: - return None - return llvmlite.build_gep(builder, inner_ty, decayed, idx) - return llvmlite.build_gep(builder, elem_ty, ptr_val, idx) + """指针算术: ptr + int / ptr - int → GEP(按元素大小缩放索引)(委托到 gen.translate_ptr_arith)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_ptr_arith(pool, builder, ptr_val, int_val, op) + return None # ============================================================ @@ -508,53 +287,12 @@ def create_global_string(builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, str_val: str, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """创建全局字符串常量并返回 i8* bitcast""" - escaped: t.CChar | t.CPtr = escape_llvm_string(pool, str_val) - if escaped is None: - return None - - slen: t.CSizeT = string.strlen(str_val) - count: int = slen + 1 - - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, count) - - # 使用模块级计数器(trans._label_counter)避免跨函数命名冲突 - str_idx: int = trans._label_counter - trans._label_counter += 1 - - # 字符串名加 SHA1 前缀,和函数导出规则一致,避免跨模块重名 - gv_name: t.CChar | t.CPtr = pool.alloc(48) - if gv_name is None: - return None - if trans.ModuleSha1 is not None: - viperlib.snprintf(gv_name, 48, ".str.%s.%d", trans.ModuleSha1, str_idx) - else: - viperlib.snprintf(gv_name, 48, ".str.%d", str_idx) - - gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name, arr_ty) - if gv is None: - return None - llvmlite.module_add_global(mod, gv) - - # 去掉 private 链接,和函数一致:stub 中 declare,text 中 define - llvmlite.global_set_unnamed_addr(gv, 1) - llvmlite.global_set_constant(gv, 1) - # LLVM 22+ 不允许 external linkage 全局变量带初始值,设为 internal - gv.Linkage = "internal" - gv.Initializer = escaped - - arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty) - gv_ref_name: t.CChar | t.CPtr = pool.alloc(64) - if gv_ref_name is None: - return None - viperlib.snprintf(gv_ref_name, 64, "@%s", gv.Name) - gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, arr_ptr_ty, gv_ref_name) - - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, gv_ref, i8_ptr_ty) - return bc + """创建全局字符串常量并返回 i8* bitcast(委托到 gen.create_global_string)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.create_global_string(builder, pool, mod, str_val, trans) + return None # ============================================================ @@ -565,79 +303,25 @@ def translate_constant(builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译常量(int/str/bool)""" - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node) - if cn is None: - return None - ck: int = cn.const_kind - if cn.const_kind == ast.CONST_INT: - # 超出 i32 范围则用 i64(避免常量创建时被截断) - iv: t.CInt64T = cn.int_val - if iv > 2147483647 or iv < -2147483648: - return llvmlite.const_int64(pool, iv) - return llvmlite.const_int32(pool, iv) - elif cn.const_kind == ast.CONST_FLOAT: - # 浮点常量默认创建为 double(64 位),赋值时由 coerce_to_type 自动 fptrunc - double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - return llvmlite.ConstFloat(pool, double_ty, cn.float_val) - elif cn.const_kind == ast.CONST_CHAR: - # 单引号单字符 → i32 值(字符 ASCII 码),coerce_to_type 会 trunc 为 i8 - cv: t.CInt64T = cn.int_val - return llvmlite.const_int32(pool, cv) - elif cn.const_kind == ast.CONST_STR: - sv: str = cn.str_val - if sv is None: - return None - r: llvmlite.Value | t.CPtr = create_global_string(builder, pool, mod, sv, trans) - return r - elif cn.const_kind == ast.CONST_BOOL: - if cn.int_val != 0: - return llvmlite.const_int32(pool, 1) - return llvmlite.const_int32(pool, 0) - elif cn.const_kind == ast.CONST_NONE: - # None → i8* null(空指针常量),用于 `p is None` / `p is not None` 比较 - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if i8_ty is None: - return None - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - if i8_ptr_ty is None: - return None - rv_none: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null") - return rv_none + """翻译常量(int/str/bool)(委托到 gen.translate_constant)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_constant(builder, pool, mod, node, trans) return None # ============================================================ # _infer_elem_type_from_value — 从 LLVM Value 推断 list 元素类型名 -# -# 用于 list 字面量 [a, b, c] 的元素类型推断 # ============================================================ def _infer_elem_type_from_value(pool: memhub.MemBuddy | t.CPtr, value: llvmlite.Value | t.CPtr) -> str: - """从 LLVM Value 的类型推断 list 元素类型名""" - if value is None or value.Ty is None: - return "str" - ty: llvmlite.LLVMType | t.CPtr = value.Ty - bits: int = get_llvm_type_bits(ty) - if bits != 0: - if bits == 32: - return "int" - if bits == 64: - return "CSizeT" - if bits == 8: - return "CInt8T" - if bits == 16: - return "CInt16T" - return "int" - if is_ptr_type(ty) != 0: - return "str" - fbits: int = get_llvm_float_bits(ty) - if fbits != 0: - if fbits == 64: - return "CDouble" - if fbits == 32: - return "CFloat" - return "str" + """从 LLVM Value 的类型推断 list 元素类型名(委托到 gen._infer_elem_type_from_value)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._infer_elem_type_from_value(pool, value) + return None # ============================================================ @@ -646,71 +330,18 @@ def _infer_elem_type_from_value(pool: memhub.MemBuddy | t.CPtr, # 依次尝试 "pool", "_mbuddy", "mbuddy", "mb" # ============================================================ def _find_pool_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """查找上下文中的 pool 变量,返回 alloca 或 None - - 查找顺序: pool → _mbuddy → mbuddy → mb - 兜底: 若都未找到,注册外部全局 @_mbuddy (i8*) 供函数内动态 list 创建使用。 - 注意: 模块级 t.CArray 初始化不走此路径(由 _init_global_array_from_list 处理), - 此兜底仅用于函数内的动态 list 字面量(如 op=[...])。 - @_mbuddy 由入口模块(如 Phase2.py)定义并初始化,其他模块以 external 引用。 - """ - if trans is None: - return None - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, "pool") - if alloca is not None: - return alloca - alloca = HandlesVar.lookup_var(trans.SymTab, "_mbuddy") - if alloca is not None: - return alloca - alloca = HandlesVar.lookup_var(trans.SymTab, "mbuddy") - if alloca is not None: - return alloca - alloca = HandlesVar.lookup_var(trans.SymTab, "mb") - if alloca is not None: - return alloca - # 兜底: 创建外部全局 @_mbuddy 引用(i8** 类型) - # 仅用于函数内动态 list 字面量,@_mbuddy 由入口模块定义并初始化 - pool: memhub.MemBuddy | t.CPtr = trans.Pool - if pool is None or trans.Module is None or trans.SymTab is None: - return None - # 先检查是否已注册到模块作用域(避免重复创建全局变量) - existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(trans.SymTab, "_mbuddy") - if existing is not None: - return existing - # 创建 i8* 类型(t.CVoid | t.CPtr = i8*) - i8_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_fb) - # 创建外部全局 @_mbuddy(external linkage,无初始值) - gv_ext: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, "_mbuddy", i8_ptr_ty_fb) - if gv_ext is not None: - gv_ext.Linkage = "external" - llvmlite.module_add_global(trans.Module, gv_ext) - # 创建 Value 引用(@_mbuddy, 类型为 i8**) - i8_ptr_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_fb) - ref_name_fb: t.CChar | t.CPtr = pool.alloc(16) - if ref_name_fb is not None: - string.strcpy(ref_name_fb, "@_mbuddy") - gv_ref_fb: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb) - # 注册到模块作用域,避免重复创建 - HandlesVar.define_module_var(trans.SymTab, "_mbuddy", gv_ref_fb) - return gv_ref_fb + """查找上下文中的 pool 变量,返回 alloca 或 None(委托到 gen._find_pool_var)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._find_pool_var(trans) + return None # ============================================================ # translate_list_literal — 翻译 list 字面量 [a, b, c] # # 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列 -# -# Args: -# builder: IRBuilder -# pool: 编译器内存池(MemBuddy) -# mod: LLVMModule -# node: ast.List 节点 -# elem_type_name: 元素类型名(如 "str", "int"),None 表示从元素推断 -# trans: Translator 对象 -# -# Returns: -# list 对象指针(Ptr(list[T] struct)),None 失败 # ============================================================ def translate_list_literal(builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, @@ -718,127 +349,12 @@ def translate_list_literal(builder: llvmlite.IRBuilder | t.CPtr, node: ast.AST | t.CPtr, elem_type_name: str, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列""" - if node is None or trans is None: - return None - - list_node: ast.List | t.CPtr = (ast.List | t.CPtr)(node) - if list_node is None: - return None - - elts: list[ast.AST | t.CPtr] | t.CPtr = list_node.elts - elts_count: t.CSizeT = 0 - if elts is not None: - elts_count = elts.__len__() - - # 推断元素类型 - inferred_type_name: str = elem_type_name - first_elem_val: llvmlite.Value | t.CPtr = None - if inferred_type_name is None: - inferred_type_name = "str" - if elts_count > 0: - first_elem_node: ast.AST | t.CPtr = elts.get(0) - first_elem_val = translate_value(builder, pool, mod, first_elem_node, None, 0, trans) - if first_elem_val is not None: - inferred_type_name = _infer_elem_type_from_value(pool, first_elem_val) - - # 查找 pool 变量 - pool_alloca: llvmlite.Value | t.CPtr = _find_pool_var(trans) - if pool_alloca is None: - HandlesType.fatal_error(node, "list literal requires pool variable in context") - return None - - # load pool 变量值(i8*) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - pool_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, pool_alloca) - if pool_val is None: - return None - - # 特化 list[T] 类(elem_size=8:str 是指针,4 会导致双元素重叠损坏) - type_args: list[str] | t.CPtr = list[str](pool, 8) - type_args.append(inferred_type_name) - spec_name: str = HandlesClassDef._specialize_generic_class(trans, "list", type_args) - if spec_name is None: - HandlesType.fatal_error(node, "list literal generic specialization failed") - return None - - # 查找 struct entry - struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if struct_entry is None: - HandlesType.fatal_error(node, "list literal specialized class not registered") - return None - struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty - if struct_ty is None: - return None - - # alloca 临时 list 空间 - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) - if tmp is None: - return None - - # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 - # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 - # (与 _translate_struct_ctor/_translate_generic_ctor_call 保持一致, - # 避免为无 __new__ 的类生成过度声明) - storage_ptr: llvmlite.Value | t.CPtr = tmp - has_new_flag: int = 0 - if struct_entry is not None: - has_new_flag = struct_entry.HasNew - if has_new_flag != 0: - new_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if new_args is None: - return None - string.memset(new_args, 0, 8 * 32) - new_args[0] = t.CSizeT(pool_val) - new_ptr: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( - pool, builder, mod, spec_name, "__new__", tmp, new_args, 1, trans) - if new_ptr is not None: - storage_ptr = new_ptr - - # 调用 __before_init__(storage_ptr) - HandlesExprCall._call_method_on_ptr( - pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) - - # 调用 __init__(storage_ptr, pool_val, elem_size=0) - init_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if init_args is None: - return None - string.memset(init_args, 0, 8 * 32) - init_args[0] = t.CSizeT(pool_val) - elem_size_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - init_args[1] = t.CSizeT(elem_size_val) - HandlesExprCall._call_method_on_ptr( - pool, builder, mod, spec_name, "__init__", storage_ptr, init_args, 2, trans) - - # 对每个元素调用 append(storage_ptr, elem_val) - if elts_count > 0: - # 第一个元素可能已经翻译过 - if first_elem_val is not None: - append_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if append_args is not None: - string.memset(append_args, 0, 8 * 32) - append_args[0] = t.CSizeT(first_elem_val) - HandlesExprCall._call_method_on_ptr( - pool, builder, mod, spec_name, "append", storage_ptr, append_args, 1, trans) - - # 翻译剩余元素 - i: t.CSizeT = 1 - while i < elts_count: - elem_node_i: ast.AST | t.CPtr = elts.get(i) - elem_val_i: llvmlite.Value | t.CPtr = translate_value(builder, pool, mod, elem_node_i, None, 0, trans) - if elem_val_i is not None: - ap_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if ap_args is not None: - string.memset(ap_args, 0, 8 * 32) - ap_args[0] = t.CSizeT(elem_val_i) - HandlesExprCall._call_method_on_ptr( - pool, builder, mod, spec_name, "append", storage_ptr, ap_args, 1, trans) - i += 1 - - return storage_ptr + """翻译 list 字面量 [a, b, c] → list[T](pool) + append 序列(委托到 gen.translate_list_literal)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_list_literal(builder, pool, mod, node, elem_type_name, trans) + return None # ============================================================ @@ -851,171 +367,28 @@ def translate_value(builder: llvmlite.IRBuilder | t.CPtr, funcs_ptr: t.CPtr = None, func_count: int = 0, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译值表达式为 LLVM Value""" - if node is None: - return None - k: int = node.kind() - if k == ast.ASTKind.Constant: - rv: llvmlite.Value | t.CPtr = translate_constant(builder, pool, mod, node, trans) - return rv - elif k == ast.ASTKind.Name: - return translate_name_value(builder, pool, node, trans) - elif k == ast.ASTKind.BinOp: - return HandlesExprOps.translate_binop(pool, builder, mod, node, trans) - elif k == ast.ASTKind.Call: - return HandlesExprCall.translate_call(pool, builder, mod, node, - funcs_ptr, func_count, trans) - elif k == ast.ASTKind.Compare: - return translate_compare(builder, pool, mod, node, trans) - elif k == ast.ASTKind.UnaryOp: - return translate_unaryop(builder, pool, mod, node, trans) - elif k == ast.ASTKind.BoolOp: - return translate_boolop(builder, pool, mod, node, - funcs_ptr, func_count, trans) - elif k == ast.ASTKind.Subscript: - return translate_subscript(builder, pool, mod, node, trans) - elif k == ast.ASTKind.Attribute: - return translate_attribute(builder, pool, mod, node, trans) - elif k == ast.ASTKind.List: - return translate_list_literal(builder, pool, mod, node, None, trans) - elif k == ast.ASTKind.IfExp: - return translate_ifexp(builder, pool, mod, node, trans) + """翻译值表达式为 LLVM Value(委托到 gen.translate_value)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_value(builder, pool, mod, node, funcs_ptr, func_count, trans) return None # ============================================================ # 翻译三元表达式 IfExp(test, body, orelse) -# -# 生成: cond ? body : orelse -# then_blk: 翻译 body → br merge -# else_blk: 翻译 orelse → br merge -# merge_blk: phi [body_val, then_blk], [orelse_val, else_blk] # ============================================================ def translate_ifexp(builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译三元表达式 (body if test else orelse),返回 phi 结果 Value""" - if node is None or builder is None or trans is None: - return None - ie: ast.IfExp | t.CPtr = (ast.IfExp | t.CPtr)(node) - if ie is None: - return None - - func: llvmlite.Function | t.CPtr = trans._cur_func - if func is None: - return None - - # 1. 求值条件 - cond_val: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, ie.test, None, 0, trans) - if cond_val is None: - return None - # 转换为 i1 - cond_bits: int = get_llvm_type_bits(cond_val.Ty) - if cond_bits == 1: - cond_i1: llvmlite.Value | t.CPtr = cond_val - else: - if is_ptr_type(cond_val.Ty) != 0: - # 指针类型:与 null 比较 - 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) - - # 2. 创建三个基本块 - cnt: int = trans._label_counter - trans._label_counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) - if name_buf is None: - return None - viperlib.snprintf(name_buf, 32, "ifexp.then.%d", cnt) - then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "ifexp.else.%d", cnt) - else_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - viperlib.snprintf(name_buf, 32, "ifexp.merge.%d", cnt) - merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - if then_bb is None or else_bb is None or merge_bb is None: - return None - - # 3. 条件跳转 - llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb) - - # 4. then 分支 - llvmlite.position_at_end(builder, then_bb) - body_val: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, ie.body, None, 0, trans) - then_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock - if body_val is None: - body_val = llvmlite.const_int32(pool, 0) - # 暂不 br,等类型对齐后再 br - - # 5. else 分支 - llvmlite.position_at_end(builder, else_bb) - orelse_val: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, ie.orelse, None, 0, trans) - else_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock - if orelse_val is None: - orelse_val = llvmlite.const_int32(pool, 0) - # 暂不 br,等类型对齐后再 br - - # 类型对齐 (两分支类型可能不同) - # 必须在各自分支中执行 coerce_to_type,确保 merge 块中 PHI 是第一条指令 - # (否则 coerce_to_type 生成的 sext/zext/ptrtoint/inttoptr 指令在 PHI 之前,违反 LLVM 规则) - body_bits: int = get_llvm_type_bits(body_val.Ty) - orelse_bits: int = get_llvm_type_bits(orelse_val.Ty) - body_is_ptr: int = is_ptr_type(body_val.Ty) - orelse_is_ptr: int = is_ptr_type(orelse_val.Ty) - # 情况0: 一侧是指针,另一侧是整数(如 i64 vs i8* null) - # 必须优先处理,因为 Ptr 的 bits=0 会导致下面三个分支全部跳过 - # 选择 body_val.Ty 作为 phi_ty(then 分支优先),orelse_val 对齐到它 - # coerce_to_type 内部会调用 ptrtoint(指针→整数)或 inttoptr(整数→指针) - if body_is_ptr != orelse_is_ptr: - llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node) - elif body_bits > orelse_bits and orelse_bits > 0: - # 在 else 块中转换 orelse_val - llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node) - elif orelse_bits > body_bits and body_bits > 0: - # 回到 then 块转换 body_val - llvmlite.position_at_end(builder, then_blk_for_phi) - body_val = coerce_to_type(builder, body_val, orelse_val.Ty, node) - elif body_bits == orelse_bits and body_bits > 0: - # bits 相同但类型不同(如 i64 vs Ptr):null 不能用于 i64 PHI - # 此分支理论上不会触发(已被情况0覆盖),保留作为防御 - if is_ptr_type(body_val.Ty) != is_ptr_type(orelse_val.Ty): - llvmlite.position_at_end(builder, else_blk_for_phi) - orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node) - - # 现在分别在 then/else 块中 br 到 merge(在类型转换之后) - llvmlite.position_at_end(builder, then_blk_for_phi) - llvmlite.build_br(builder, merge_bb) - llvmlite.position_at_end(builder, else_blk_for_phi) - llvmlite.build_br(builder, merge_bb) - - # 6. merge 块: phi(PHI 是 merge 块的第一条指令) - llvmlite.position_at_end(builder, merge_bb) - - phi_ty: llvmlite.LLVMType | t.CPtr = body_val.Ty - if phi_ty is None: - phi_ty = llvmlite.Int32(pool) - - inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( - pool, body_val, then_blk_for_phi) - inc2: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming( - pool, orelse_val, else_blk_for_phi) - if inc1 is None or inc2 is None: - return None - # 链表顺序: inc1 (head) -> inc2 (tail) - # 之前错误写成 inc2.Next = inc1,导致 build_phi 从 inc1 遍历时 - # inc1.Next 为 None,只输出一个 phi 条目,引发 LLVM 验证错误: - # "PHINode should have one entry for each predecessor" - inc1.Next = inc2 - return llvmlite.build_phi(builder, phi_ty, inc1, 2) + """翻译三元表达式 (body if test else orelse),返回 phi 结果 Value(委托到 gen.translate_ifexp)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_ifexp(builder, pool, mod, node, trans) + return None # ============================================================ @@ -1025,116 +398,31 @@ def should_zext_widen(pool: memhub.MemBuddy | t.CPtr, narrow_val: llvmlite.Value | t.CPtr, wide_val: llvmlite.Value | t.CPtr, narrow_node: ast.AST | t.CPtr = None) -> int: - """判断整数拓宽方向:1=zext(无符号语义),0=sext - - 对齐 TPC 的 _check_node_unsigned / HandlesExprOps 拓宽规则: - 1. i1 (bool) → zext(1 保持 1,而非 sext 的 0xFF...) - 2. i8 → zext(系统编程中 i8 几乎总是无符号字节) - 3. 宽侧是常量且其值超出窄侧位宽的有符号范围 → zext - (常量"想要"无符号解释,如 0xAABBCCDD > INT32_MAX 与 - t.CUInt32T 值比较,sext 会把 0xAABBCCDD 变成 - 0xFFFFFFFFAABBCCDD 导致恒不等) - """ - if narrow_val is None or narrow_val.Ty is None: - return 0 - narrow_bits: int = get_llvm_type_bits(narrow_val.Ty) - if narrow_bits == 1: - return 1 - if narrow_bits == 8: - return 1 - # 宽侧常量启发式 - if wide_val is not None and wide_val.IsConst == 1: - wide_bits: int = get_llvm_type_bits(wide_val.Ty) - if wide_bits > narrow_bits and narrow_bits < 64: - signed_max: t.CInt64T = (t.CInt64T(1) << (narrow_bits - 1)) - 1 - if wide_val.IntVal > signed_max: - return 1 - # 窄侧 AST 节点解析为无符号类型(如 t.CUIntXXT 字面量/强转) - if narrow_node is not None: - if _node_type_unsigned(pool, narrow_node) != 0: - return 1 + """判断整数拓宽方向:1=zext(无符号语义),0=sext(委托到 gen.should_zext_widen)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.should_zext_widen(pool, narrow_val, wide_val, narrow_node) return 0 def _node_type_unsigned(pool: memhub.MemBuddy | t.CPtr, node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> int: - """轻量判断 AST 节点是否解析为无符号整数类型(1=是,0=否/未知) - - 覆盖常见形态(对齐 TPC _check_node_unsigned 的 Call/Subscript 分支): - - t.CUInt8T/CUInt16T/CUInt32T/CUInt64T/CUnsigned* 等显式无符号类型强转调用 - - 无符号类型名的 Name 引用(如 UInt32T 别名) - - 变量名(trans 可用时):查询 SymTab 中变量的 AnnotClassName(如 v: t.CUInt32T) - """ - if node is None: - return 0 - k: int = node.kind() - if k == ast.ASTKind.Call: - cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0 \ - and at.attr is not None: - if _type_name_unsigned(at.attr) != 0: - return 1 - return 0 - if k == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm.id is not None: - # 1) 名字本身是无符号类型名(如 UInt32T 别名) - if _type_name_unsigned(nm.id) != 0: - return 1 - # 2) 变量注解类型为无符号类型(trans 可用时查 SymTab) - if trans is not None: - ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm.id) - if ve is not None and ve.AnnotClassName is not None: - if _type_name_unsigned(ve.AnnotClassName) != 0: - return 1 - return 0 - if k == ast.ASTKind.BinOp: - bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if _node_type_unsigned(pool, bop.left, trans) != 0: - return 1 - if _node_type_unsigned(pool, bop.right, trans) != 0: - return 1 - return 0 - if k == ast.ASTKind.UnaryOp: - uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if _node_type_unsigned(pool, uop.operand, trans) != 0: - return 1 - return 0 + """轻量判断 AST 节点是否解析为无符号整数类型(1=是,0=否/未知)(委托到 gen._node_type_unsigned)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._node_type_unsigned(pool, node, trans) return 0 def _type_name_unsigned(type_name: str) -> int: - """类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)""" - if type_name is None: - return 0 - # t.CUIntXXT 形式 - if string.strcmp(type_name, "CUInt8T") == 0: return 1 - if string.strcmp(type_name, "CUInt16T") == 0: return 1 - if string.strcmp(type_name, "CUInt32T") == 0: return 1 - if string.strcmp(type_name, "CUInt64T") == 0: return 1 - # stdint 裸别名(from stdint import *) - if string.strcmp(type_name, "UInt8T") == 0: return 1 - if string.strcmp(type_name, "UInt16T") == 0: return 1 - if string.strcmp(type_name, "UInt32T") == 0: return 1 - if string.strcmp(type_name, "UInt64T") == 0: return 1 - # CUnsigned* 形式 - if string.strcmp(type_name, "CUnsignedChar") == 0: return 1 - if string.strcmp(type_name, "CUnsignedShort") == 0: return 1 - if string.strcmp(type_name, "CUnsignedInt") == 0: return 1 - if string.strcmp(type_name, "CUnsignedLong") == 0: return 1 - if string.strcmp(type_name, "CUnsignedLongLong") == 0: return 1 - # 常见无符号别名 - if string.strcmp(type_name, "BYTE") == 0: return 1 - if string.strcmp(type_name, "UCHAR") == 0: return 1 - if string.strcmp(type_name, "USHORT") == 0: return 1 - if string.strcmp(type_name, "UINT") == 0: return 1 - if string.strcmp(type_name, "ULONG") == 0: return 1 + """类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)(委托到 gen._type_name_unsigned)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._type_name_unsigned(type_name) return 0 @@ -1143,209 +431,12 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译比较表达式,返回 i1 结果""" - cmp: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node) - if cmp is None: - return None - - ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops) - if ops_list is None or ops_list.__len__() == 0: - return None - op: int = ops_list.get(0) - - comparators: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators - if comparators is None or comparators.__len__() == 0: - return None - rhs_node: ast.AST | t.CPtr = comparators.get(0) - rhs: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, rhs_node, None, 0, trans) - if rhs is None: - return None - - # === None 比较优化: x == None / x != None 走身份比较(icmp eq/ne null)=== - # 避免对结构体指针生成无效的 __eq__/__ne__ 调用(方法未定义但类有 SHA1 时 - # try_operator_overload 会误生成 call void @...__eq__(...) 导致链接错误) - # 语义依据: Python 中 == None / != None 默认走身份比较,不调用 __eq__/__ne__ - lhs_node: ast.AST | t.CPtr = cmp.left - cmp_with_none: int = 0 - if op == ast.OpKind.Eq or op == ast.OpKind.Ne or op == ast.OpKind.Is or op == ast.OpKind.IsNot: - if rhs_node is not None and rhs_node.kind() == ast.ASTKind.Constant: - rhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rhs_node) - if rhs_cn is not None and rhs_cn.const_kind == ast.CONST_NONE: - cmp_with_none = 1 - if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Constant: - lhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(lhs_node) - if lhs_cn is not None and lhs_cn.const_kind == ast.CONST_NONE: - cmp_with_none = 1 - - # === 比较运算符重载路径 1: lhs 是 Name 且对应结构体变量 === - # 对于值类型变量(如 cnt: Counter),用 alloca 指针尝试重载 - # None 比较跳过重载(走身份比较) - if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) - if nm is not None and nm.id is not None: - lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm.id) - if lhs_alloca is not None: - ovl_result: llvmlite.Value | t.CPtr = HandlesExprOps.try_operator_overload( - pool, builder, mod, lhs_alloca, rhs, op, trans, 1) - if ovl_result is not None: - return ovl_result - - # 正常翻译 lhs - lhs: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, cmp.left, None, 0, trans) - if lhs is None: - return None - - # === 比较运算符重载路径 2: lhs 是 Ptr(Struct) === - # Is/IsNot 不在 _cmpop_to_dunder 映射中,会自动返回 None 回退原生比较 - # None 比较跳过重载(走身份比较) - if cmp_with_none == 0: - ovl_result2: llvmlite.Value | t.CPtr = HandlesExprOps.try_operator_overload( - pool, builder, mod, lhs, rhs, op, trans, 1) - if ovl_result2 is not None: - return ovl_result2 - - predicate: int = llvmlite.ICMP_SLT - if op == ast.OpKind.Lt: - predicate = llvmlite.ICMP_SLT - elif op == ast.OpKind.Le: - predicate = llvmlite.ICMP_SLE - elif op == ast.OpKind.Gt: - predicate = llvmlite.ICMP_SGT - elif op == ast.OpKind.Ge: - predicate = llvmlite.ICMP_SGE - elif op == ast.OpKind.Eq: - predicate = llvmlite.ICMP_EQ - elif op == ast.OpKind.Ne: - predicate = llvmlite.ICMP_NE - elif op == ast.OpKind.Is: - # `x is y` → 指针/值相等比较 - predicate = llvmlite.ICMP_EQ - elif op == ast.OpKind.IsNot: - # `x is not y` → 指针/值不等比较 - predicate = llvmlite.ICMP_NE - - # === 类型安全检查(BUG2 修复)=== - # 规则: - # - 数值(0) vs 数值(0) → 允许(无关类型,按位宽 sext 对齐) - # - 一级指针(1) vs 一级指针(1) → 允许(无关 pointee 类型,地址比较) - # - 数值(0) vs 指针(1+) → 禁止(fast-fail,除 None 比较外) - # - 不同级指针(1 vs 2 等) → 禁止(fast-fail) - # - # None 比较跳过此检查(None 被翻译为 null 指针或 0,与任意指针/数值比较合法) - if cmp_with_none == 0: - lhs_ptr_level: int = get_ptr_level(lhs.Ty) - rhs_ptr_level: int = get_ptr_level(rhs.Ty) - if lhs_ptr_level != rhs_ptr_level: - # 类型不匹配:数值vs指针 或 不同级指针 - # 用 fmt_buf 构造可读消息(Viper % 格式化在部分路径生成 null) - fmt_msg: t.CChar | t.CPtr = VLogger.fmt_buf() - if fmt_msg is not None: - viperlib.snprintf( - fmt_msg, 1024, - "比较类型不匹配(行 %d): lhs 层级=%d (ty=%p), rhs 层级=%d (ty=%p)", - cmp.lineno, lhs_ptr_level, lhs.Ty, rhs_ptr_level, rhs.Ty) - VLogger.error(fmt_msg, "Compare") - else: - VLogger.error("比较类型不匹配: 数值与指针/不同级指针比较", "Compare") - return None - else: - # None 比较: None 被翻译为 i8* null(一级指针) - # 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型 - # 如果 lhs 是数值,将 rhs 转为数值 0(走正常整数比较) - # 如果 lhs 是结构体值类型,结构体永远不等于 None,返回常量 i1 - lhs_ptr_level_none: int = get_ptr_level(lhs.Ty) - rhs_ptr_level_none: int = get_ptr_level(rhs.Ty) - if lhs_ptr_level_none != 0 and rhs_ptr_level_none != 0: - # 两边都是指针,类型可能不同(如 lhs=Struct*, rhs=i8* null) - # 由下方 bitcast 对齐处理,此处不处理 - pass - elif lhs_ptr_level_none != 0 and rhs_ptr_level_none == 0: - # lhs 是指针, rhs 是数值 → 将 rhs 转为同层级 null 指针 - rhs = llvmlite.ConstNull(pool, lhs.Ty, None) - elif rhs_ptr_level_none != 0 and lhs_ptr_level_none == 0: - # 检查 lhs 是否是结构体值类型(非指针的 Struct) - lhs_is_struct_none: int = 0 - match lhs.Ty: - case llvmlite.LLVMType.Struct(_, _, _): - lhs_is_struct_none = 1 - case _: - lhs_is_struct_none = 0 - if lhs_is_struct_none != 0: - # 结构体值永远不等于 None:==/is 返回 false,!=/is not 返回 true - if op == ast.OpKind.Eq or op == ast.OpKind.Is: - return llvmlite.const_int(pool, 1, 0) - else: # Ne, IsNot - return llvmlite.const_int(pool, 1, 1) - # lhs 是数值, rhs 是 i8* null → 将 rhs 转为数值 0(保持 lhs 不变) - rhs = llvmlite.const_int32(pool, 0) - - # 类型对齐:icmp 要求两边类型相同 - # 仅对数值类型做对齐(指针类型无需对齐,LLVM 允许同层级指针直接 icmp) - # i1 (bool) 侧用 zext 对齐(1 保持 1,而非 sext 的 0xFF...) - lhs_bits: int = get_llvm_type_bits(lhs.Ty) - rhs_bits: int = get_llvm_type_bits(rhs.Ty) - if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits: - if lhs_bits < rhs_bits: - if should_zext_widen(pool, lhs, rhs, cmp.left) != 0: - lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) - else: - lhs = llvmlite.build_sext(builder, lhs, rhs.Ty) - else: - if should_zext_widen(pool, rhs, lhs, rhs_node) != 0: - rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) - else: - rhs = llvmlite.build_sext(builder, rhs, lhs.Ty) - - # 指针类型对齐:同层级但不同 pointee 类型的指针需要 bitcast 统一类型 - # 例如 i8* vs Struct* → 将 rhs bitcast 为 lhs 的类型 - if lhs_bits == 0 and rhs_bits == 0: - lhs_is_ptr_now: int = is_ptr_type(lhs.Ty) - rhs_is_ptr_now: int = is_ptr_type(rhs.Ty) - if lhs_is_ptr_now != 0 and rhs_is_ptr_now != 0: - # 两边都是指针,用 TypePrint 比较类型字符串 - lhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128) - rhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128) - if lhs_ty_buf is not None and rhs_ty_buf is not None: - llvmlite.TypePrint(lhs_ty_buf, 128, lhs.Ty, pool) - llvmlite.TypePrint(rhs_ty_buf, 128, rhs.Ty, pool) - if string.strcmp(lhs_ty_buf, rhs_ty_buf) != 0: - rhs = llvmlite.build_bitcast(builder, rhs, lhs.Ty) - - # 浮点比较:任一操作数为浮点类型时使用 fcmp 而非 icmp - lhs_fbits: int = get_llvm_float_bits(lhs.Ty) - rhs_fbits: int = get_llvm_float_bits(rhs.Ty) - if lhs_fbits != 0 or rhs_fbits != 0: - # 浮点类型对齐(fpext/fptrunc) - if lhs_fbits != 0 and rhs_fbits != 0 and lhs_fbits != rhs_fbits: - if lhs_fbits < rhs_fbits: - lhs = llvmlite.build_fpext(builder, lhs, rhs.Ty) - else: - rhs = llvmlite.build_fptrunc(builder, rhs, lhs.Ty) - elif lhs_fbits != 0 and rhs_fbits == 0: - # int → float - rhs = llvmlite.build_si2fp(builder, rhs, lhs.Ty) - elif rhs_fbits != 0 and lhs_fbits == 0: - lhs = llvmlite.build_si2fp(builder, lhs, rhs.Ty) - # 映射比较谓词到 fcmp - fpredicate: int = llvmlite.FCMP_OEQ - if op == ast.OpKind.Eq or op == ast.OpKind.Is: - fpredicate = llvmlite.FCMP_OEQ - elif op == ast.OpKind.Ne or op == ast.OpKind.IsNot: - fpredicate = llvmlite.FCMP_ONE - elif op == ast.OpKind.Lt: - fpredicate = llvmlite.FCMP_OLT - elif op == ast.OpKind.Le: - fpredicate = llvmlite.FCMP_OLE - elif op == ast.OpKind.Gt: - fpredicate = llvmlite.FCMP_OGT - elif op == ast.OpKind.Ge: - fpredicate = llvmlite.FCMP_OGE - return llvmlite.build_fcmp(builder, fpredicate, lhs, rhs) - - return llvmlite.build_icmp(builder, predicate, lhs, rhs) + """翻译比较表达式,返回 i1 结果(委托到 gen.translate_compare)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_compare(builder, pool, mod, node, trans) + return None # ============================================================ @@ -1356,80 +447,16 @@ def translate_unaryop(builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译一元运算(-x, +x, not x, ~x)""" - uo: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node) - if uo is None: - return None - - operand: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, uo.operand, None, 0, trans) - if operand is None: - return None - - # === 一元运算符重载: -obj/+obj/~obj 调用 __neg__/__pos__/__invert__ === - # 仅 USub/UAdd/Invert 有重载语义(not 无 dunder 方法) - if uo.op == ast.OpKind.USub or uo.op == ast.OpKind.UAdd or uo.op == ast.OpKind.Invert: - ovl_u: llvmlite.Value | t.CPtr = HandlesExprOps.try_unary_operator_overload( - pool, builder, mod, operand, uo.op, trans) - if ovl_u is not None: - return ovl_u - - if uo.op == ast.OpKind.USub: - # -x - # 浮点类型用 fneg(直接生成 fneg 指令,避免 0.0 - x 的类型不匹配) - operand_fbits: int = get_llvm_float_bits(operand.Ty) - if operand_fbits > 0: - return llvmlite.build_fneg(builder, operand) - # 整数类型:-x = 0 - x,根据位宽选择零值常量(避免 i32 与 i64 类型不匹配) - operand_bits: int = get_llvm_type_bits(operand.Ty) - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - if operand_bits == 64: - zero = llvmlite.const_int64(pool, 0) - elif operand_bits > 0 and operand_bits != 32: - # 其他位宽(i8/i16 等):用 i32 零值,operand 会被 coerce - zero = llvmlite.const_int32(pool, 0) - return llvmlite.build_sub(builder, zero, operand) - elif uo.op == ast.OpKind.UAdd: - # +x = x - return operand - elif uo.op == ast.OpKind.Not: - # not x = (x == 0/null),返回 i1 - if is_ptr_type(operand.Ty) != 0: - # 指针类型:与 null 比较 - null_op: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, operand.Ty, "null") - return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, null_op) - # 结构体值类型:永远为真(非空),not 返回 false - operand_is_struct_not: int = 0 - match operand.Ty: - case llvmlite.LLVMType.Struct(_, _, _): - operand_is_struct_not = 1 - case _: - operand_is_struct_not = 0 - if operand_is_struct_not != 0: - return llvmlite.const_int(pool, 1, 0) - operand_bits_not: int = get_llvm_type_bits(operand.Ty) - zero = llvmlite.const_int32(pool, 0) - if operand_bits_not == 64: - zero = llvmlite.const_int64(pool, 0) - return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, zero) - elif uo.op == ast.OpKind.Invert: - # ~x = x ^ -1 - operand_bits_inv: int = get_llvm_type_bits(operand.Ty) - neg1: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, -1) - if operand_bits_inv == 64: - neg1 = llvmlite.const_int64(pool, -1) - return llvmlite.build_xor(builder, operand, neg1) - return operand + """翻译一元运算(-x, +x, not x, ~x)(委托到 gen.translate_unaryop)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_unaryop(builder, pool, mod, node, trans) + return None # ============================================================ # 翻译布尔运算 BoolOp(op, values) — 短路求值,返回 i1 -# -# and: a and b and c → 若 a 为假短路到 merge(返回 a 的 i1),否则求 b, -# 最后一个值直接求值并跳 merge -# or: a or b or c → 若 a 为真短路到 merge(返回 a 的 i1),否则求 b, -# 最后一个值直接求值并跳 merge -# merge 块用 phi 合并所有入边的 i1 # ============================================================ def translate_boolop(builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, @@ -1438,712 +465,51 @@ def translate_boolop(builder: llvmlite.IRBuilder | t.CPtr, funcs_ptr: t.CPtr = None, func_count: int = 0, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译布尔运算(and/or)的短路求值,返回 i1""" - bo: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node) - if bo is None: - return None - - op: int = bo.op - values: list[ast.AST | t.CPtr] | t.CPtr = bo.values - if values is None: - return None - count: t.CSizeT = values.__len__() - if count == 0: - return None - if count == 1: - return translate_value(builder, pool, mod, values.get(0), - funcs_ptr, func_count, trans) - - func: llvmlite.Function | t.CPtr = builder.Func - if func is None: - return None - - # 创建 merge BB(用 builder.Counter 生成唯一标签名,position_at_end 的 - # move_to_end 保证 BB 文本顺序与控制流顺序一致,标签名用 counter 安全) - cnt: int = builder.Counter - builder.Counter = cnt + 1 - name_buf: t.CChar | t.CPtr = pool.alloc(32) - if name_buf is None: - return None - viperlib.snprintf(name_buf, 32, "bool.merge.%d", cnt) - merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # phi 入边链表头/尾 - phi_head: llvmlite.PhiIncoming | t.CPtr = None - phi_tail: llvmlite.PhiIncoming | t.CPtr = None - phi_count: int = count - 1 # 循环次数 - - # 对每个值(除最后一个)求值并短路 - for i in range(count - 1): - val_node: ast.AST | t.CPtr = values.get(i) - val: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, val_node, - funcs_ptr, func_count, trans) - if val is None: - return None - - # 转为 i1(已经是 i1 的直接用,否则与 0/null 比较) - val_bits: int = get_llvm_type_bits(val.Ty) - val_i1: llvmlite.Value | t.CPtr = val - if val_bits != 1: - if is_ptr_type(val.Ty) != 0: - # 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配) - null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, val.Ty, "null") - val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, null_val) - else: - zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero) - - # 创建 next BB(求值下一个值) - cnt = builder.Counter - builder.Counter = cnt + 1 - viperlib.snprintf(name_buf, 32, "bool.next.%d", cnt) - next_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf) - - # and: 短路假→merge,真→next;or: 短路真→merge,假→next - if op == ast.OpKind.And: - llvmlite.build_cond_br(builder, val_i1, next_bb, merge_bb) - else: - llvmlite.build_cond_br(builder, val_i1, merge_bb, next_bb) - - # 添加 phi 入边:(val_i1, cond_br 所在 BB) - cur_bb: llvmlite.BasicBlock | t.CPtr = builder.CurBlock - inc: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, val_i1, cur_bb) - if phi_head is None: - phi_head = inc - phi_tail = inc - else: - phi_tail.Next = inc - phi_tail = inc - - # 定位到 next BB,求值下一个值 - llvmlite.position_at_end(builder, next_bb) - - # 最后一个值:求值后直接跳 merge - last_node: ast.AST | t.CPtr = values.get(count - 1) - last_val: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, last_node, - funcs_ptr, func_count, trans) - if last_val is None: - return None - last_bits: int = get_llvm_type_bits(last_val.Ty) - last_i1: llvmlite.Value | t.CPtr = last_val - if last_bits != 1: - if is_ptr_type(last_val.Ty) != 0: - # 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配) - null_val2: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, last_val.Ty, "null") - last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, null_val2) - else: - zero = llvmlite.const_int32(pool, 0) - last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, zero) - - llvmlite.build_br(builder, merge_bb) - - cur_bb = builder.CurBlock - inc = llvmlite.new_phi_incoming(pool, last_i1, cur_bb) - if phi_head is None: - phi_head = inc - else: - phi_tail.Next = inc - phi_count += 1 - - # 定位到 merge,创建 phi 合并所有入边 - llvmlite.position_at_end(builder, merge_bb) - i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - return llvmlite.build_phi(builder, i1_ty, phi_head, phi_count) + """翻译布尔运算(and/or)的短路求值,返回 i1(委托到 gen.translate_boolop)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_boolop(builder, pool, mod, node, funcs_ptr, func_count, trans) + return None # ============================================================ # _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径 -# -# .vpi 文件可能未生成(Phase1 未输出 vpi),此时回退读取源 .py 文件。 -# 从 StubMerger 全局存储器查找 SHA1 对应的相对路径, -# 根据 rel_path 前缀选择基础目录: -# - rel_path 以 "lib/" 开头 → App 源文件,用 {Config.SourceDir}/{rel_path} -# - 其他 → includes 文件,用 {Config.IncludesDir}/{rel_path} -# -# Returns: -# stdlib.malloc 分配的路径字符串(调用者负责 free),None 失败 # ============================================================ def _build_source_path_from_sha1(sha1: str) -> str: - """通过 SHA1 从全局存储器构建源 .py 文件路径""" - if sha1 is None: - return None - if Config.IncludesDir is None: - return None - # 从 StubMerger 全局存储器获取相对路径数组 - rel_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr() - count: int = StubMerger.GetSha1StoreCount() - if rel_arr_ptr is None or count <= 0: - return None - sha1_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr() - if sha1_arr_ptr is None: - return None - # 遍历查找匹配的 SHA1 - idx_s: int = -1 - for i in range(count): - sidx: t.CSizeT = t.CSizeT(i) * 17 - cur_sha1: str = sha1_arr_ptr + sidx - if cur_sha1[0] == '\0': - continue - if string.strcmp(cur_sha1, sha1) == 0: - idx_s = i - break - if idx_s < 0: - return None - # 获取相对路径(MAX_REL_PATH_LEN=256,避免跨模块 CDefine 解析问题) - MAX_RPL: t.CSizeT = 256 - ridx: t.CSizeT = t.CSizeT(idx_s) * MAX_RPL - rel_path: str = rel_arr_ptr + ridx - if rel_path[0] == '\0': - return None - # 选择基础目录:rel_path 以 "lib/" 开头 → App 源文件(SourceDir),否则 includes 文件 - base_dir: str = Config.IncludesDir - is_app: int = 0 - if string.strlen(rel_path) >= 4: - if (rel_path[0] == 'l' and rel_path[1] == 'i' and - rel_path[2] == 'b' and rel_path[3] == '/'): - is_app = 1 - if is_app != 0 and Config.SourceDir is not None: - base_dir = Config.SourceDir - # 构建完整路径: {base_dir}/{rel_path} - base_len: t.CSizeT = string.strlen(base_dir) - rel_len: t.CSizeT = string.strlen(rel_path) - path_len: t.CSizeT = base_len + rel_len + 2 - buf: str = stdlib.malloc(path_len) - if buf is None: - return None - viperlib.snprintf(buf, path_len, "%s/%s", base_dir, rel_path) - return buf + """通过 SHA1 从全局存储器构建源 .py 文件路径(委托到 gen._build_source_path_from_sha1)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._build_source_path_from_sha1(sha1) + return None # ============================================================ # _lookup_cross_module_cdefine - 跨模块查找 CDefine 常量 -# -# 当当前模块的 CDefine 表中找不到某个 Name 时,从 from_imports -# 解析出源模块,再从该模块的 pyi 文件中解析 CDefine 常量值。 -# 找到后缓存到当前模块的 CDefine 表中,避免重复查找。 -# -# pyi 文件格式: "NAME: t.CDefine = value" # ============================================================ def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr, name: str, from_imports: str, imported_modules: str = None) -> int: - """跨模块查找 CDefine 常量,返回值或 -1(未找到) - - 查找顺序: - 1. from_imports 精确匹配(from X import NAME) - 2. from_imports star 回退(from X import *) - 3. imported_modules 遍历(import X):当通过 import X 导入模块时, - 模块中定义的 CDefine 常量可通过此路径找到(如方法签名默认参数引用) - """ - # 入口处清零标志,确保所有早退路径(return -1)都返回"未找到"状态 - # 避免递归调用时前一次成功的标志残留导致误判 - HandlesType.set_cdefine_found(0) - if name is None: - return -1 - if from_imports is None: - from_imports = "" - - # 1. 从 from_imports 查找名称对应的模块名 - # 先尝试精确匹配(allow_star_fallback=0),避免 CDefine 常量被 star import 误导 - mod_name_raw: str = HandlesImports.lookup_from_import(from_imports, name, 0) - if mod_name_raw is None: - # 精确匹配失败:尝试 star import 回退 - mod_name_raw = HandlesImports.lookup_from_import(from_imports, name, 1) - - # 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6) - # 注意:star fallback 可能返回错误模块(如 stdint),常量实际不在其中, - # 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules - if mod_name_raw is None: - # from_imports 完全没有匹配(精确和 star 都失败) - # 直接进入 imported_modules 遍历(步骤 9.6) - if imported_modules is None: - return -1 - # 跳过 from_imports 模块读取,直接走步骤 9.6 的 imported_modules 遍历 - # 设置 result_found=0 跳过步骤 3-9,直接到 9.6 - HandlesType.set_cdefine_found(0) - # 直接遍历 imported_modules - im_len: t.CSizeT = string.strlen(imported_modules) - im_ci: t.CSizeT = 0 - while im_ci < im_len: - while im_ci < im_len and imported_modules[im_ci] == ' ': - im_ci += 1 - if im_ci >= im_len: - break - im_start: t.CSizeT = im_ci - while im_ci < im_len and imported_modules[im_ci] != ' ': - im_ci += 1 - im_end: t.CSizeT = im_ci - im_nlen: t.CSizeT = im_end - im_start - if im_nlen > 0 and im_nlen < 256: - im_buf: str = pool.alloc(im_nlen + 1) - if im_buf is not None: - mk: t.CSizeT = 0 - while mk < im_nlen: - im_buf[mk] = imported_modules[im_start + mk] - mk += 1 - im_buf[im_nlen] = '\0' - sub_fi: str = pool.alloc(im_nlen + 3) - if sub_fi is not None: - sub_fi[0] = '*' - sub_fi[1] = ':' - mk2: t.CSizeT = 0 - while mk2 < im_nlen: - sub_fi[2 + mk2] = im_buf[mk2] - mk2 += 1 - sub_fi[2 + im_nlen] = '\0' - sub_val: int = _lookup_cross_module_cdefine(pool, name, sub_fi, None) - if HandlesType.is_cdefine_found() != 0: - return sub_val - return -1 - - # 2. 截断模块名 → 去前导点 → 精确+后缀查找 SHA1(复用 HandlesExprCall 公共逻辑) - sha1: str = HandlesExprCall._lookup_sha1_from_modname_raw(pool, mod_name_raw) - if sha1 is None: - return -1 - - # 5. 获取 temp_dir - temp_dir: str = HandlesType.get_temp_dir() - if temp_dir is None: - return -1 - - # 6. 构建 vpi 文件路径 - td_len: t.CSizeT = string.strlen(temp_dir) - pyi_path: str = StubMerger._sliced_path(temp_dir, td_len, sha1, "vpi") - if pyi_path is None: - return -1 - - # 7. 读取 vpi 文件;若不存在或内容过短(空 stub)则回退读取源 .vp/.py 文件 - PYI_READ_BUF_SIZE: t.CSizeT = 65536 - pyi_buf: bytes = stdlib.malloc(PYI_READ_BUF_SIZE) - if pyi_buf is None: - stdlib.free(pyi_path) - return -1 - pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.R) - need_py_fallback: int = 0 - bytes_read: LONG = 0 - if pf.closed: - # .vpi 文件不存在:回退读取源 .vp/.py 文件 - need_py_fallback = 1 - else: - bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE) - pf.close() - # vpi 内容过短(< 10 字节)视为空 stub,回退 .py - if bytes_read < 10: - need_py_fallback = 1 - else: - if bytes_read < PYI_READ_BUF_SIZE: - pyi_buf[bytes_read] = 0 - else: - pyi_buf[PYI_READ_BUF_SIZE - 1] = 0 - stdlib.free(pyi_path) - - if need_py_fallback != 0: - # 从 SHA1 存储器查找相对路径,构建 {base_dir}/{rel_path} - src_path: str = _build_source_path_from_sha1(sha1) - if src_path is None: - # 存储器中找不到 SHA1 = 编译器 bug(Phase1/Phase2 未填充存储器) - # 报错终止,不静默返回 -1(避免后续生成错误的 @UNDEFINED 全局变量引用) - err_buf: str = pool.alloc(512) - if err_buf is not None: - viperlib.snprintf(err_buf, 512, - "跨模块 CDefine 查找失败:SHA1 %s 不在存储器中(base_mod=%s name=%s)。" - "Phase1/Phase2 未正确填充 PopulateSha1MapStore/AppendToSha1MapStore", - sha1, base_mod, name) - VLogger.error(err_buf, "XMOD-CD") - stdlib.free(pyi_buf) - return -1 - pf = fileio.File(src_path, fileio.MODE.R) - stdlib.free(src_path) - if pf.closed: - stdlib.free(pyi_buf) - return -1 - bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE) - pf.close() - if bytes_read <= 0: - stdlib.free(pyi_buf) - return -1 - if bytes_read < PYI_READ_BUF_SIZE: - pyi_buf[bytes_read] = 0 - else: - pyi_buf[PYI_READ_BUF_SIZE - 1] = 0 - - # 8. 在 pyi_buf 中查找 "name: t.CDefine = value" 行 - # 格式: NAME: t.CDefine = value - name_len: t.CSizeT = string.strlen(name) - total_len: t.CSizeT = string.strlen(pyi_buf) - pos: t.CSizeT = 0 - result_val: int = 0 - result_found: int = 0 - while pos < total_len: - # 找到行首 - line_start: t.CSizeT = pos - # 找到行尾 - while pos < total_len and pyi_buf[pos] != '\n': - pos += 1 - line_len: t.CSizeT = pos - line_start - if pos < total_len: - pos += 1 # 跳过 '\n' - - # 检查行是否以 "name:" 开头 - if line_len < name_len + 1: - continue - match_ok: int = 1 - for ki in range(name_len): - if pyi_buf[line_start + ki] != name[ki]: - match_ok = 0 - break - if match_ok == 0: - continue - if pyi_buf[line_start + name_len] != ':': - continue - - # 检查行是否包含 "t.CDefine" - # 在行中查找 "t.CDefine" - has_cdefine: int = 0 - ci: t.CSizeT = line_start + name_len + 1 - while ci + 8 <= line_start + line_len: - if (pyi_buf[ci] == 't' and pyi_buf[ci + 1] == '.' and - pyi_buf[ci + 2] == 'C' and pyi_buf[ci + 3] == 'D' and - pyi_buf[ci + 4] == 'e' and pyi_buf[ci + 5] == 'f' and - pyi_buf[ci + 6] == 'i' and pyi_buf[ci + 7] == 'n' and - pyi_buf[ci + 8] == 'e'): - has_cdefine = 1 - break - ci += 1 - if has_cdefine == 0: - continue - - # 找到 "=" 后面的值 - eq_pos: t.CSizeT = line_start + name_len + 1 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '=': - eq_pos += 1 - if eq_pos >= line_start + line_len: - continue - eq_pos += 1 # 跳过 '=' - - # 跳过空格 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - - # 检查是否是 t.CUnsignedLong(...) / t.CLong(...) / t.CInt(...) 等类型构造函数 - # 格式: t.CUnsignedLong(-11) / t.CUnsignedLong(0xFFFFFFFF) - # 如果是,跳过 "t.CXxx(" 前缀,解析括号内的值,忽略结尾 ')' - is_type_ctor: int = 0 - if eq_pos + 2 < line_start + line_len: - if pyi_buf[eq_pos] == 't' and pyi_buf[eq_pos + 1] == '.': - # 找到 '(' 的位置 - paren_pos: t.CSizeT = eq_pos + 2 - while paren_pos < line_start + line_len and pyi_buf[paren_pos] != '(': - paren_pos += 1 - if paren_pos < line_start + line_len and pyi_buf[paren_pos] == '(': - is_type_ctor = 1 - eq_pos = paren_pos + 1 # 跳过 '(' - # 跳过括号内可能的前导空格 - while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ': - eq_pos += 1 - - # 解析整数值(支持十六进制 0x 前缀和负号) - # 负号标记 - is_neg: int = 0 - if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-': - is_neg = 1 - eq_pos += 1 - val_str_start: t.CSizeT = eq_pos - val_str_len: t.CSizeT = 0 - is_hex: int = 0 - if eq_pos + 1 < line_start + line_len: - if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'): - is_hex = 1 - val_str_len = 2 - eq_pos += 2 - while eq_pos < line_start + line_len: - ch: t.CChar = pyi_buf[eq_pos] - if is_hex == 1: - if ((ch >= '0' and ch <= '9') or - (ch >= 'a' and ch <= 'f') or - (ch >= 'A' and ch <= 'F')): - val_str_len += 1 - eq_pos += 1 - else: - break - else: - if ch >= '0' and ch <= '9': - val_str_len += 1 - eq_pos += 1 - else: - break - - if val_str_len == 0: - continue - - # 复制值字符串到新缓冲区并解析 - val_buf: str = pool.alloc(val_str_len + 1) - if val_buf is None: - continue - for vi in range(val_str_len): - val_buf[vi] = pyi_buf[val_str_start + vi] - val_buf[val_str_len] = '\0' - - if is_hex == 1: - # 手动解析十六进制(跳过 0x 前缀) - hex_result: int = 0 - hex_buf: str = val_buf + 2 # 跳过 "0x" - for hi in range(val_str_len - 2): - hc: t.CChar = hex_buf[hi] - hd: int = 0 - if hc >= '0' and hc <= '9': - hd = hc - '0' - elif hc >= 'a' and hc <= 'f': - hd = hc - 'a' + 10 - elif hc >= 'A' and hc <= 'F': - hd = hc - 'A' + 10 - else: - break - hex_result = hex_result * 16 + hd - result_val = hex_result - # 十六进制负值(如 0xFFFFFFFF)保持原样,由 32 位截断处理 - result_found = 1 - else: - result_val = string.atoi(val_buf) - # 应用负号(如 t.CUnsignedLong(-11) → -11) - if is_neg != 0: - result_val = -result_val - result_found = 1 - break - - # 9.5 如果当前模块文件中没找到,递归查找子模块 - # 处理 from .X import NAME 和 from .X import * 的情况 - # 例如 ast.__init__.vp 中 from .base import CONST_INT, ... - # 需要递归查找 ast.base 子模块中的 CONST_INT: t.CDefine = 1 - if result_found == 0: - name_len_rc: t.CSizeT = string.strlen(name) - rc_pos: t.CSizeT = 0 - while rc_pos < total_len and result_found == 0: - # 找到行首 - rc_line_start: t.CSizeT = rc_pos - # 找到行尾 - while rc_pos < total_len and pyi_buf[rc_pos] != '\n': - rc_pos += 1 - rc_line_len: t.CSizeT = rc_pos - rc_line_start - if rc_pos < total_len: - rc_pos += 1 - - # 检查行是否以 "from ." 开头(相对导入子模块) - if rc_line_len < 12: - continue - if pyi_buf[rc_line_start] != 'f' or pyi_buf[rc_line_start+1] != 'r' or \ - pyi_buf[rc_line_start+2] != 'o' or pyi_buf[rc_line_start+3] != 'm' or \ - pyi_buf[rc_line_start+4] != ' ' or pyi_buf[rc_line_start+5] != '.': - continue - - # 提取子模块名(从 rc_line_start+6 开始,到空格/tab 为止) - rc_sub_start: t.CSizeT = rc_line_start + 6 - rc_sub_end: t.CSizeT = rc_sub_start - while rc_sub_end < rc_line_start + rc_line_len and \ - pyi_buf[rc_sub_end] != ' ' and pyi_buf[rc_sub_end] != '\t': - rc_sub_end += 1 - rc_sub_len: t.CSizeT = rc_sub_end - rc_sub_start - if rc_sub_len == 0: - continue - - # 检查行是否包含 "import" - rc_has_import: int = 0 - rc_ipos: t.CSizeT = rc_sub_end - while rc_ipos + 6 <= rc_line_start + rc_line_len: - if pyi_buf[rc_ipos] == 'i' and pyi_buf[rc_ipos+1] == 'm' and \ - pyi_buf[rc_ipos+2] == 'p' and pyi_buf[rc_ipos+3] == 'o' and \ - pyi_buf[rc_ipos+4] == 'r' and pyi_buf[rc_ipos+5] == 't': - rc_has_import = 1 - break - rc_ipos += 1 - if rc_has_import == 0: - continue - - # 检查 NAME 是否在导入列表中,或导入是 * - # 处理多行导入:from .X import (... NAME, ...) - # 从 "import" 之后扫描,如果有 "(" 则扫描到 ")" 为止 - rc_imp_start: t.CSizeT = rc_ipos + 6 - rc_star: int = 0 - rc_name_match: int = 0 - - # 确定扫描范围:单行或跨行(括号内) - rc_scan_end: t.CSizeT = rc_line_start + rc_line_len - rc_has_paren: int = 0 - rc_pp: t.CSizeT = rc_imp_start - while rc_pp < rc_line_start + rc_line_len: - if pyi_buf[rc_pp] == '(': - rc_has_paren = 1 - break - if pyi_buf[rc_pp] == '*': - rc_star = 1 - rc_pp += 1 - - if rc_has_paren != 0: - # 多行导入:从 "(" 之后扫描到 ")" 为止 - rc_scan_end = rc_pp + 1 - rc_paren_closed: int = 0 - rc_sp: t.CSizeT = rc_pp + 1 - while rc_sp < total_len and rc_paren_closed == 0: - if pyi_buf[rc_sp] == ')': - rc_paren_closed = 1 - rc_scan_end = rc_sp - break - rc_sp += 1 - if rc_paren_closed == 0: - rc_scan_end = total_len - - # 在 rc_imp_start 到 rc_scan_end 范围内查找 NAME 和 * - rc_cpos: t.CSizeT = rc_imp_start - while rc_cpos < rc_scan_end: - rc_ch: t.CChar = pyi_buf[rc_cpos] - if rc_ch == '*': - rc_star = 1 - # 检查 NAME 是否匹配(作为完整单词) - if rc_cpos + name_len_rc <= rc_scan_end: - rc_match: int = 1 - rc_ki: t.CSizeT - for rc_ki in range(name_len_rc): - if pyi_buf[rc_cpos + rc_ki] != name[rc_ki]: - rc_match = 0 - break - if rc_match == 1: - # 检查前字符是否是非标识符字符 - rc_before_ok: int = 0 - if rc_cpos == rc_imp_start: - rc_before_ok = 1 - else: - rc_before_ch: t.CChar = pyi_buf[rc_cpos - 1] - if rc_before_ch == ' ' or rc_before_ch == '\t' or \ - rc_before_ch == '(' or rc_before_ch == ',' or \ - rc_before_ch == '\n' or rc_before_ch == '\r': - rc_before_ok = 1 - # 检查后字符是否是非标识符字符 - rc_after_ok: int = 0 - rc_after_pos: t.CSizeT = rc_cpos + name_len_rc - if rc_after_pos >= rc_scan_end: - rc_after_ok = 1 - else: - rc_after_ch: t.CChar = pyi_buf[rc_after_pos] - if rc_after_ch == ' ' or rc_after_ch == '\t' or \ - rc_after_ch == ')' or rc_after_ch == ',' or \ - rc_after_ch == '\r' or rc_after_ch == '\n': - rc_after_ok = 1 - if rc_before_ok == 1 and rc_after_ok == 1: - rc_name_match = 1 - rc_cpos += 1 - - if rc_star == 0 and rc_name_match == 0: - continue - - # 复制子模块名到新缓冲区(pyi_buf + rc_sub_start 不是 NUL 结尾) - rc_sub_buf: str = pool.alloc(rc_sub_len + 1) - if rc_sub_buf is None: - continue - rc_si: t.CSizeT - for rc_si in range(rc_sub_len): - rc_sub_buf[rc_si] = pyi_buf[rc_sub_start + rc_si] - rc_sub_buf[rc_sub_len] = '\0' - - # 构建完整子模块名 base_mod.X - rc_full_len: t.CSizeT = string.strlen(base_mod) + 1 + rc_sub_len + 1 - rc_full_mod: str = pool.alloc(rc_full_len) - if rc_full_mod is None: - continue - viperlib.snprintf(rc_full_mod, rc_full_len, "%s.%s", base_mod, rc_sub_buf) - - # 构建临时 from_imports "name:full_mod" - rc_fi_len: t.CSizeT = name_len_rc + 1 + string.strlen(rc_full_mod) + 1 - rc_fi: str = pool.alloc(rc_fi_len) - if rc_fi is None: - continue - viperlib.snprintf(rc_fi, rc_fi_len, "%s:%s", name, rc_full_mod) - - # 递归调用查找子模块 - rc_sub_val: int = _lookup_cross_module_cdefine(pool, name, rc_fi) - if HandlesType.is_cdefine_found() != 0: - result_val = rc_sub_val - result_found = 1 - - stdlib.free(pyi_buf) - - # 9.6 from_imports star fallback 模块中未找到:回退到 imported_modules 遍历 - # 当 `from stdint import *` 导致 star fallback 返回 stdint,但目标常量 - # (如 SHARE_READ)实际在 `import w32.fileio` 导入的模块中时, - # 需要遍历 imported_modules 逐个查找 - if result_found == 0 and imported_modules is not None: - im2_len: t.CSizeT = string.strlen(imported_modules) - im2_ci: t.CSizeT = 0 - while im2_ci < im2_len and result_found == 0: - while im2_ci < im2_len and imported_modules[im2_ci] == ' ': - im2_ci += 1 - if im2_ci >= im2_len: - break - im2_start: t.CSizeT = im2_ci - while im2_ci < im2_len and imported_modules[im2_ci] != ' ': - im2_ci += 1 - im2_end: t.CSizeT = im2_ci - im2_nlen: t.CSizeT = im2_end - im2_start - if im2_nlen > 0 and im2_nlen < 256: - im2_buf: str = pool.alloc(im2_nlen + 1) - if im2_buf is not None: - mk3: t.CSizeT = 0 - while mk3 < im2_nlen: - im2_buf[mk3] = imported_modules[im2_start + mk3] - mk3 += 1 - im2_buf[im2_nlen] = '\0' - sub_fi2: str = pool.alloc(im2_nlen + 3) - if sub_fi2 is not None: - sub_fi2[0] = '*' - sub_fi2[1] = ':' - mk4: t.CSizeT = 0 - while mk4 < im2_nlen: - sub_fi2[2 + mk4] = im2_buf[mk4] - mk4 += 1 - sub_fi2[2 + im2_nlen] = '\0' - sub_val2: int = _lookup_cross_module_cdefine(pool, name, sub_fi2, None) - if HandlesType.is_cdefine_found() != 0: - result_val = sub_val2 - result_found = 1 - - # 10. 缓存到当前模块的 CDefine 表中 - if result_found != 0: - HandlesType.register_cdefine_constant(pool, name, result_val) - HandlesType.set_cdefine_found(1) - else: - HandlesType.set_cdefine_found(0) - - return result_val + """跨模块查找 CDefine 常量,返回值或 -1(未找到)(委托到 gen._lookup_cross_module_cdefine)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._lookup_cross_module_cdefine(pool, name, from_imports, imported_modules) + return 0 # ============================================================ # _is_cdefine_name_pattern - 检查名字是否符合 CDefine 命名约定 -# -# CDefine 常量(如 FOREGROUND_GREEN, STD_OUTPUT_HANDLE, SCOPE_MODULE) -# 都遵循 ALL_CAPS 约定:仅含大写字母 A-Z、数字 0-9、下划线 _, -# 且至少含一个大写字母。 -# -# Python 关键字(match, if, for)和变量名(self, pool, builder) -# 都含小写字母,不会匹配,从而避免 fail-fast 误报。 -# -# 返回: 1=符合 CDefine 命名约定, 0=不符合 # ============================================================ def _is_cdefine_name_pattern(name: str) -> int: - """检查名字是否符合 CDefine 命名约定(全大写+下划线+数字)""" - if name is None: - return 0 - has_upper: int = 0 - i: t.CSizeT = 0 - while name[i] != '\0': - c: t.CChar = name[i] - if c >= 'a' and c <= 'z': - return 0 - if c >= 'A' and c <= 'Z': - has_upper = 1 - i += 1 - return has_upper + """检查名字是否符合 CDefine 命名约定(全大写+下划线+数字)(委托到 gen._is_cdefine_name_pattern)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._is_cdefine_name_pattern(name) + return 0 # ============================================================ @@ -2153,167 +519,11 @@ def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译变量引用(Name 节点)→ load""" - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node) - if nm is None: - return None - nm_id: str = nm.id - if nm_id is None: - return None - - # CDefine 编译期常量: 返回常量值(浮点 CDefine → double 常量,整数 → i32) - # NAME: t.CDefine = value 形式定义的常量在编译期已注册到本地表 - # 浮点 CDefine(如 vipermath 的 U_M_PI=3.14...)必须返回浮点常量, - # 否则在 double 函数里 return 生成 ret i32 0(llc 报错)。 - cdef_val_d: double = HandlesType.lookup_cdefine_double(nm_id) - if HandlesType.is_cdefine_found() != 0: - if HandlesType.is_cdefine_double() != 0: - # CDEF-DBG: 打印浮点 CDefine 使用(返回 ConstFloat) - fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb_cd is not None: - stdio.snprintf(fb_cd, 1024, "USE-D: %s -> %.17g (float)", nm_id, cdef_val_d) - VLogger.info(fb_cd, "CDEF-DBG") - return llvmlite.ConstFloat(pool, llvmlite.Double(pool), cdef_val_d) - cdef_val_i: int = t.CInt(cdef_val_d) - # CDEF-DBG: 打印整数 CDefine 使用(返回 const_int32) - fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb_cd is not None: - viperlib.snprintf(fb_cd, 1024, "USE-I: %s -> %d (int)", nm_id, cdef_val_i) - VLogger.info(fb_cd, "CDEF-DBG") - return llvmlite.const_int32(pool, cdef_val_i) - - # 本地表未找到:尝试跨模块 .vpi 查找(保证多模块查表存表一致) - # 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找, - # 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗 - if _is_cdefine_name_pattern(nm_id) != 0: - if trans is not None: - cdef_val = _lookup_cross_module_cdefine( - pool, nm_id, trans._from_imports, trans._imported_modules) - if HandlesType.is_cdefine_found() != 0: - return llvmlite.const_int32(pool, cdef_val) - - # global 变量:从模块作用域查找(global 声明优先级最高) - if trans is not None: - 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: - load_ty: llvmlite.LLVMType | t.CPtr = None - if mod_alloca.Ty is not None: - load_ty = mod_alloca.Ty.Pointee - if load_ty is None: - load_ty = llvmlite.Int32(pool) - return llvmlite.build_load(builder, load_ty, mod_alloca) - - # nonlocal 变量:通过闭包 env 访问 - if HT.is_nonlocal_name(trans, nm_id) != 0: - return HandlesNonlocal.load_nonlocal_var(trans, nm_id) - - # *args va_list:变量名直接解析为指向 24 字节 va_list 缓冲区的 i8* 地址 - # (对齐 TPC _direct_values[vararg_name] = va_list_ptr;不 load 缓冲区内容, - # 转发时按值传该地址即可,如 sprintf → vsnprintf(..., args)) - if trans is not None and trans._vararg_name is not None: - if nm_id is not None and string.strcmp(nm_id, trans._vararg_name) == 0: - if trans._va_list_ptr is not None: - return trans._va_list_ptr - - # 局部变量查找(必须先于模块别名检查) - # 否则与模块同名的局部变量(如 `import t, c` 后的局部变量 c)会被误判为模块别名, - # 导致 SymTab 已注册的局部变量查找不到(rhs_val is None bug 根因) - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm_id) - if alloca is not None: - load_ty: llvmlite.LLVMType | t.CPtr = None - if alloca.Ty is not None: - load_ty = alloca.Ty.Pointee - if load_ty is None: - load_ty = llvmlite.Int32(pool) - # 结构体值变量(alloca 类型为 Struct,如 `x: Cls | t.CPtr`): - # 按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值。 - # 结构体值无法参与 ptrtoint/方法调用等地址相关操作,加载值会导致 - # `ptrtoint %Struct ... to i64` 无效指令(llc invalid cast opcode)。 - match load_ty: - case llvmlite.LLVMType.Struct(_, _, _): - return alloca - return llvmlite.build_load(builder, load_ty, alloca) - - # 模块别名检查:SymTab 查找失败后才检查 - # 如果 nm_id 是已导入模块名(如 win32file, fileio)且未被声明为局部变量, - # 返回 None 让上层处理(用于属性访问 win32file.CreateFileA) - if trans is not None and trans._imported_modules is not None: - if HandlesImports.is_module_imported(trans._imported_modules, nm_id) != 0: - return None - - # 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。 - # 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移 - # (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。 - # 注意:不能直接返回 Function 对象,也不能直接 build_bitcast(Function)—— - # Function 布局是 {Next, Name, RetTy, Params, ...},value_get_ty 会错位读到 - # Name 字段,TypePrint 输出 "void",生成 `bitcast void ... to i8*` 非法 IR; - # 且 Function.Next 是模块函数链表指针,参数链表构建对其赋值会截断函数链表, - # 最终打印出 `declare void @()` 空名函数。正确做法:按 Function 的 - # RetTy/Params 构造真实函数类型,用 new_value 包装成普通 Value 再 bitcast。 - if trans is not None and trans.Module is not None: - fn_ref: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module( - trans.Module, nm_id) - if fn_ref is not None: - fn_name: t.CChar | t.CPtr = llvmlite.function_get_name(fn_ref) - if fn_name is None: - return None - # 构造函数类型:ret_ty + 参数 ParamNode 链表 - fn_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fn_ref) - if fn_ret_ty is None: - fn_ret_ty = llvmlite.Int32(pool) - fn_pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(fn_ref) - fn_first_node: llvmlite.ParamNode | t.CPtr = None - fn_prev_node: llvmlite.ParamNode | t.CPtr = None - fn_pcount: int = 0 - while fn_pp is not None: - fn_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fn_pp) - fn_pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, fn_pty) - if fn_pn is not None: - if fn_first_node is None: - fn_first_node = fn_pn - if fn_prev_node is not None: - llvmlite.paramnode_set_next(fn_prev_node, fn_pn) - fn_prev_node = fn_pn - fn_pcount += 1 - fn_pp = llvmlite.param_get_next(fn_pp) - fn_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func( - pool, fn_ret_ty, fn_first_node, fn_pcount) - if fn_ty is None: - return None - # 构造函数指针 Value(new_value 包装,避免触碰 Function.Next) - fn_ref_v: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) - if fn_ref_v is None: - return None - llvmlite.value_set_ty(fn_ref_v, llvmlite.Ptr(pool, fn_ty)) - llvmlite.value_set_isconst(fn_ref_v, 1) - fn_ref_name: t.CChar | t.CPtr = pool.alloc(256) - if fn_ref_name is not None: - fn_ref_name[0] = '\0' - if HandlesClassDef._vtable_name_needs_quote(fn_name) != 0: - viperlib.snprintf(fn_ref_name, 256, "@\"%s\"", fn_name) - else: - viperlib.snprintf(fn_ref_name, 256, "@%s", fn_name) - llvmlite.value_set_name(fn_ref_v, fn_ref_name) - fn_i8ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - return llvmlite.build_bitcast(builder, fn_ref_v, fn_i8ptr_ty) - - # 所有查找路径均失败 - # fail-fast: 仅对符合 CDefine 命名约定(ALL_CAPS)的名字报错 - # 避免对 match/self/pool 等关键字和变量名误报 - # 跨模块 CDefine 查找已在上方完成,此处不重复 - if _is_cdefine_name_pattern(nm_id) != 0: - err_buf2: str = pool.alloc(256) - if err_buf2 is not None: - cur_sha1: str = "(unknown)" - if trans is not None and trans.ModuleSha1 is not None: - cur_sha1 = trans.ModuleSha1 - viperlib.snprintf(err_buf2, 256, - "[CD] FATAL: Name '%s' NOT found (CDefine local+cross + global + nonlocal + alloca + module alias) in module sha1=%s\n", - nm_id, cur_sha1) - VLogger.error(err_buf2, "CD") + """翻译变量引用(Name 节点)→ load(委托到 gen.translate_name_value)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_name_value(builder, pool, node, trans) return None @@ -2365,79 +575,29 @@ def list_getitem_inline(builder: llvmlite.IRBuilder | t.CPtr, lm_obj: llvmlite.Value | t.CPtr, idx_val: llvmlite.Value | t.CPtr, node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)""" - if builder is None or pool is None or lm_obj is None or idx_val is None: - return None - 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) - # 加载 __data__ (偏移 0, index 0) - g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) - if g_dpp is None: - return None - g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) - # 加载 __elem_size__ (偏移 32, index 4) - g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) - if g_epp is None: - return None - g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) - if g_data is None or g_esize is None: - return None - g_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty, node) - if g_idx_i64 is None: - return None - g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) - if g_offset is None: - return None - # 返回元素地址 (i8*),不 load - return llvmlite.build_gep(builder, i8_ty, g_data, g_offset) + """内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)(委托到 gen.list_getitem_inline)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.list_getitem_inline(builder, pool, lm_obj, idx_val, node) + return None # ============================================================ # _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型 -# -# 类型名格式: .list[] -# 用 strstr 检查完整模式,避免子串提取 -# 支持: list[int]→i32, list[str]/list[bytes]→i8*, list[CInt]→i32 等 -# 默认: i32 # ============================================================ def _list_elem_type_from_name(pool: memhub.MemBuddy | t.CPtr, struct_name: str) -> llvmlite.LLVMType | t.CPtr: - """从 list 类型名提取元素 LLVM 类型""" - if pool is None or struct_name is None: - return None - # 用 strstr 检查完整模式 - if string.strstr(struct_name, "list[int]") is not None: - return llvmlite.Int32(pool) - if string.strstr(struct_name, "list[CInt]") is not None: - return llvmlite.Int32(pool) - if string.strstr(struct_name, "list[CInt8T]") is not None: - return llvmlite.Int8(pool) - if string.strstr(struct_name, "list[CInt16T]") is not None: - return llvmlite.Int16(pool) - if string.strstr(struct_name, "list[CInt32T]") is not None: - return llvmlite.Int32(pool) - if string.strstr(struct_name, "list[CInt64T]") is not None: - return llvmlite.Int64(pool) - if string.strstr(struct_name, "list[CSizeT]") is not None: - return llvmlite.Int64(pool) - if string.strstr(struct_name, "list[CDouble]") is not None: - return llvmlite.Double(pool) - if string.strstr(struct_name, "list[CFloat]") is not None: - return llvmlite.Float(pool) - if string.strstr(struct_name, "list[CChar]") is not None: - return llvmlite.Int8(pool) - # str/bytes/CPtr/其他指针类型 → i8* - i8_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - return llvmlite.Ptr(pool, i8_ty_d) + """从 list 类型名提取元素 LLVM 类型(委托到 gen._list_elem_type_from_name)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._list_elem_type_from_name(pool, struct_name) + return None # ============================================================ # list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑 -# -# 直接存储 rhs_val 到元素地址 (coerce 为 i8* 后 store) # ============================================================ def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, @@ -2445,39 +605,11 @@ def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr, idx_val: llvmlite.Value | t.CPtr, rhs_val: llvmlite.Value | t.CPtr, node: ast.AST | t.CPtr = None) -> int: - """内联生成 list __setitem__ 逻辑,返回 0""" - if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None: - return 0 - 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) - # 加载 __data__ (偏移 0, index 0) - s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) - if s_dpp is None: - return 0 - s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) - # 加载 __elem_size__ (偏移 32, index 4) - s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) - if s_epp is None: - return 0 - s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) - if s_data is None or s_esize is None: - return 0 - s_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty, node) - if s_idx_i64 is None: - return 0 - s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) - if s_offset is None: - return 0 - s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) - if s_addr is None: - return 0 - s_val_ptr: llvmlite.Value | t.CPtr = coerce_to_type(builder, rhs_val, i8_ptr_ty, node) - if s_val_ptr is None: - return 0 - llvmlite.build_store(builder, s_val_ptr, s_addr) + """内联生成 list __setitem__ 逻辑,返回 0(委托到 gen.list_setitem_inline)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.list_setitem_inline(builder, pool, lm_obj, idx_val, rhs_val, node) return 0 @@ -2488,271 +620,27 @@ def list_setitem_inline(builder: llvmlite.IRBuilder | t.CPtr, # ============================================================ def is_list_subscript(node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None""" - if node is None or trans is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub is None or sub.value is None: - return None - if sub.value.kind() != ast.ASTKind.Name: - return None - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm is None or nm.id is None: - return None - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is None or alloca.Ty is None: - return None - if is_ptr_type(alloca.Ty) == 0: - return None - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is None: - return None - # 检查 pointee 是否是 Ptr(Struct) - inner_ty: llvmlite.LLVMType | t.CPtr = None - match pointee: - case llvmlite.LLVMType.Ptr(it): - inner_ty = it - case _: - return None - if inner_ty is None: - return None - # 检查 inner_ty 是否是 Struct 且名称包含 "list[" - struct_name: str = None - match inner_ty: - case llvmlite.LLVMType.Struct(_, _, sname): - struct_name = sname - case _: - return None - if struct_name is None: - return None - if string.strstr(struct_name, "list[") is None: - return None - # 是 list 类型: load 出 list 对象指针 - builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder - return llvmlite.build_load(builder, pointee, alloca) + """检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None(委托到 gen.is_list_subscript)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.is_list_subscript(node, trans) + return None # ============================================================ # 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i] -# -# 指针遍历: ptr 是指针变量,load 出指针值后 GEP + load -# 数组遍历: arr 是数组变量,用 alloca 指针做双索引 GEP [0, i] + load -# list[T]: 泛型类不注册 struct,subscript 走 __getitem__ 内联路径 # ============================================================ def translate_subscript(builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译下标表达式,返回加载的元素值""" - if node is None or builder is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub is None: - return None - - # 翻译索引 - idx_val: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, sub.slice, None, 0, trans) - if idx_val is None: - return None - - # 如果 value 是 Name,尝试从 alloca 类型推断 - if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is not None and trans is not None: - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is not None and alloca.Ty is not None: - if is_ptr_type(alloca.Ty) != 0: - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is not None: - # 不调用 pointee.kind() 避免跨模块引用 LLVMType.kind 符号 - # 用 match 检查 pointee 类型 - match pointee: - case llvmlite.LLVMType.Array(elem_ty, count): - # 数组遍历: getelementptr [N x elem_ty], ... , i32 0, i32 %idx - elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, pointee, elem_ty, alloca, - _zext_index_to_i32(builder, idx_val)) - if elem_ptr is not None: - return llvmlite.build_load(builder, elem_ty, elem_ptr) - return None - case llvmlite.LLVMType.Ptr(inner_ty): - # 检查 inner_ty 是否是 list[T] 类型(泛型类不注册 struct) - # list 的 subscript 应该走 __getitem__ 内联路径,而非指针遍历 - list_struct_name: str = None - match inner_ty: - case llvmlite.LLVMType.Struct(_, _, lsn): - list_struct_name = lsn - case _: - pass - if list_struct_name is not None: - if string.strstr(list_struct_name, "list[") is not None: - # list[T] 类型: 内联生成 __getitem__ 逻辑 - ptr_val_list: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_list is not None: - elem_addr_list: llvmlite.Value | t.CPtr = list_getitem_inline( - builder, pool, ptr_val_list, idx_val, node) - if elem_addr_list is not None: - # 根据类型名提取元素类型,bitcast 后 load - elem_ty_list: llvmlite.LLVMType | t.CPtr = _list_elem_type_from_name( - pool, list_struct_name) - if elem_ty_list is not None: - elem_ptr_ty_list: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, elem_ty_list) - casted_addr_list: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, elem_addr_list, elem_ptr_ty_list) - if casted_addr_list is not None: - return llvmlite.build_load( - builder, elem_ty_list, casted_addr_list) - return None - # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针 Ptr(Ptr(Ptr(...))), - # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 - # 此时 [i] 应该是指针解引用 (步长 sizeof(ptr)=8), 而非调用 - # 结构体的 __getitem__ 方法 (会错误生成 AST.__getitem__ 调用)。 - # 对比 HashTable|t.CPtr: alloca.Ty=HashTable**, inner_ty=Struct(HashTable) - # (非 Ptr), 仍走下面的方法调用转发路径。 - if is_ptr_type(inner_ty) != 0: - ptr_val_pp: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_pp is not None: - elem_ptr_pp: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val_pp, idx_val) - if elem_ptr_pp is not None: - return llvmlite.build_load(builder, inner_ty, elem_ptr_pp) - return None - # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): - # 仅当类定义了 __getitem__(当前模块定义或跨模块 stub declare 注入) - # 才转发方法调用;否则普通结构体指针按下标做 GEP 数组访问 - # (对齐 TPC _HandleSubscriptLlvm: if ClassName and has_function(__getitem__)) - cls_nm_rd_ptr: str = _get_custom_struct_cls_nm(pool, inner_ty) - if not (cls_nm_rd_ptr is None): - gi_lookup_rd: t.CChar | t.CPtr = pool.alloc(128) - if gi_lookup_rd is not None: - viperlib.snprintf(gi_lookup_rd, 128, "%s.__getitem__", cls_nm_rd_ptr) - if HandlesExprCall.find_func_in_module(mod, gi_lookup_rd) is not None: - obj_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if not (obj_ptr_rd is None): - arg_vals_rd_p: t.CSizeT | t.CPtr = pool.alloc(8) - if not (arg_vals_rd_p is None): - arg_vals_rd_p[0] = t.CSizeT(idx_val) - ret_rd_p: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( - pool, builder, mod, cls_nm_rd_ptr, "__getitem__", - obj_ptr_rd, arg_vals_rd_p, 1, trans, sub) - if not (ret_rd_p is None): - return ret_rd_p - # 无 __getitem__:结构体指针数组访问(GEP + load) - ptr_val_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_rd_g is not None: - elem_rd_g: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val_rd_g, idx_val) - if elem_rd_g is not None: - return llvmlite.build_load(builder, inner_ty, elem_rd_g) - return None - # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, - # 直接 GEP 按 i8* 步长(8 字节),load i8* - # 仅当 inner_ty 不是自定义结构体时才走指针遍历 - if trans is not None: - ve_pe_ts: HandlesVar.VarEntry | t.CPtr = \ - HandlesVar.lookup_var_entry(trans.SymTab, nm.id) - if ve_pe_ts is not None and ve_pe_ts.IsPtrElement == 1: - elem_ptr_ts: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, pointee, alloca, idx_val) - if elem_ptr_ts is not None: - return llvmlite.build_load(builder, pointee, elem_ptr_ts) - return None - # 普通指针遍历: 先 load 指针值,再 GEP - ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val is not None: - elem_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val, idx_val) - if elem_ptr2 is not None: - return llvmlite.build_load(builder, inner_ty, elem_ptr2) - return None - case _: - # 自定义类(结构体类型): 仅当类定义了 __getitem__ - # (当前模块定义或跨模块 stub declare 注入)才转发方法调用; - # 否则普通结构体指针按下标做 GEP 数组访问 - cls_nm_sub: str = HandlesStruct.get_class_name_by_type(pool, pointee) - if not (cls_nm_sub is None): - gi_lookup_sub: t.CChar | t.CPtr = pool.alloc(128) - if gi_lookup_sub is not None: - viperlib.snprintf(gi_lookup_sub, 128, "%s.__getitem__", cls_nm_sub) - if HandlesExprCall.find_func_in_module(mod, gi_lookup_sub) is not None: - obj_val_sub: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if not (obj_val_sub is None): - arg_vals_sub: t.CSizeT | t.CPtr = pool.alloc(8) - if not (arg_vals_sub is None): - arg_vals_sub[0] = t.CSizeT(idx_val) - ret_sub: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( - pool, builder, mod, cls_nm_sub, "__getitem__", - obj_val_sub, arg_vals_sub, 1, trans, sub) - if not (ret_sub is None): - return ret_sub - # 无 __getitem__:结构体指针数组访问(GEP + load) - ptr_val_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_sub_g is not None: - elem_sub_g: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, pointee, ptr_val_sub_g, idx_val) - if elem_sub_g is not None: - return llvmlite.build_load(builder, pointee, elem_sub_g) - return None - pass - - # 通用路径:翻译 value 获取指针 - ptr_val: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, sub.value, None, 0, trans) - if ptr_val is None or ptr_val.Ty is None: - return None - - # 检查是否是指针类型 - if is_ptr_type(ptr_val.Ty) != 0: - elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - if elem_ty2 is not None: - # 数组类型: 双索引 GEP + load 元素 - match elem_ty2: - case llvmlite.LLVMType.Array(arr_elem_ty2, arr_count2): - elem_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( - builder, elem_ty2, arr_elem_ty2, ptr_val, - _zext_index_to_i32(builder, idx_val)) - if elem_ptr3 is not None: - return llvmlite.build_load(builder, arr_elem_ty2, elem_ptr3) - return None - case _: - pass - # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __getitem__ 才转发方法调用; - # 否则普通结构体指针按下标做 GEP 数组访问 - cls_nm_rd_gen: str = _get_custom_struct_cls_nm(pool, elem_ty2) - if not (cls_nm_rd_gen is None): - gi_lookup_gen: t.CChar | t.CPtr = pool.alloc(128) - if gi_lookup_gen is not None: - viperlib.snprintf(gi_lookup_gen, 128, "%s.__getitem__", cls_nm_rd_gen) - if HandlesExprCall.find_func_in_module(mod, gi_lookup_gen) is not None: - arg_vals_rd_g: t.CSizeT | t.CPtr = pool.alloc(8) - if not (arg_vals_rd_g is None): - arg_vals_rd_g[0] = t.CSizeT(idx_val) - ret_rd_g: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( - pool, builder, mod, cls_nm_rd_gen, "__getitem__", - ptr_val, arg_vals_rd_g, 1, trans, sub) - if not (ret_rd_g is None): - return ret_rd_g - # 无 __getitem__:结构体指针数组访问(GEP + load) - elem_ptr_gen: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, elem_ty2, ptr_val, idx_val) - if elem_ptr_gen is not None: - return llvmlite.build_load(builder, elem_ty2, elem_ptr_gen) - return None - # 指针类型: 单索引 GEP + load - elem_ptr4: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, elem_ty2, ptr_val, idx_val) - if elem_ptr4 is not None: - return llvmlite.build_load(builder, elem_ty2, elem_ptr4) + """翻译下标表达式,返回加载的元素值(委托到 gen.translate_subscript)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_subscript(builder, pool, mod, node, trans) return None @@ -2765,678 +653,87 @@ def translate_subscript(builder: llvmlite.IRBuilder | t.CPtr, # ============================================================ def find_global_in_module(mod: llvmlite.LLVMModule | t.CPtr, name: str) -> llvmlite.GlobalVariable | t.CPtr: - """在模块全局变量链表中按名称查找全局变量""" - if mod is None or name is None: - return None - name_len: t.CSizeT = string.strlen(name) - cur: llvmlite.GlobalVariable | t.CPtr = mod.GlobalHead - # 第一遍: 精确匹配 - while cur is not None: - if cur.Name is not None: - if string.strcmp(cur.Name, name) == 0: - return cur - cur = cur.Next - # 第二遍: 后缀匹配 (.name) - cur = mod.GlobalHead - while cur is not None: - if cur.Name is not None: - cur_len: t.CSizeT = string.strlen(cur.Name) - if cur_len > name_len + 1: - suffix_start: t.CSizeT = cur_len - name_len - if cur.Name[suffix_start - 1] == '.': - match: int = 1 - for i in range(name_len): - if cur.Name[suffix_start + i] != name[i]: - match = 0 - break - if match == 1: - return cur - cur = cur.Next + """在模块全局变量链表中按名称查找全局变量(委托到 gen.find_global_in_module)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.find_global_in_module(mod, name) return None # ============================================================ # make_global_ref - 创建全局变量引用 (@name,类型为 ty*) -# -# 用于跨模块全局变量访问: stub 未注入时,翻译阶段生成 @name 引用, -# 链接时由 stub 提供 external global 声明。 # ============================================================ def make_global_ref(pool: memhub.MemBuddy | t.CPtr, name: str, ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """创建全局变量引用 (类型为 ty*,名称为 @name)""" - if name is None or ty is None: - return None - ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, ty) - ref_name: t.CChar | t.CPtr = pool.alloc(64) - if ref_name is None: - return None - viperlib.snprintf(ref_name, 64, "@%s", name) - return llvmlite.SSAValue(pool, ptr_ty, ref_name) + """创建全局变量引用 (类型为 ty*,名称为 @name)(委托到 gen.make_global_ref)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.make_global_ref(pool, name, ty) + return None + + +# ============================================================ +# _is_t_type_object_name - 检查 name 是否是 t.py 中的类型对象名 +# ============================================================ +def _is_t_type_object_name(name: str) -> int: + """检查 name 是否是 t.py 中的类型对象名(CPtr/CInt/CDouble 等)(委托到 gen._is_t_type_object_name)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._is_t_type_object_name(name) + return 0 # ============================================================ # _resolve_module_attribute_global - 解析模块属性访问的全局变量引用 -# -# 当 obj 是已导入模块名 (如 sys._mbuddy) 时: -# 1. 在当前模块全局变量链表中查找 (stub 已注入的情况) -# 2. 未找到则创建前向引用 (@attr_name, 类型为 ty 参数) -# -# 参数: -# ty_hint: 类型提示 (写路径用 rhs 类型, 读路径用 i8* 回退) -# 返回: Value 指针 (类型为 ty*),未识别为模块属性返回 None # ============================================================ -def _is_t_type_object_name(name: str) -> int: - """检查 name 是否是 t.py 中的类型对象名(CPtr/CInt/CDouble 等) - - 这些类型对象在运行时作为全局变量 @CPtr/@CInt 等被引用, - 但 t.py 不被编译,需要在使用处生成带 null 初值的定义。 - """ - if name is None: - return 0 - # t.py 中的类型对象名(PascalCase,首字母大写) - if string.strcmp(name, "CPtr") == 0: - return 1 - if string.strcmp(name, "CInt") == 0: - return 1 - if string.strcmp(name, "CChar") == 0: - return 1 - if string.strcmp(name, "CShort") == 0: - return 1 - if string.strcmp(name, "CLong") == 0: - return 1 - if string.strcmp(name, "CLongLong") == 0: - return 1 - if string.strcmp(name, "CDouble") == 0: - return 1 - if string.strcmp(name, "CFloat") == 0: - return 1 - if string.strcmp(name, "CBool") == 0: - return 1 - if string.strcmp(name, "CVoid") == 0: - return 1 - if string.strcmp(name, "CInt8T") == 0: - return 1 - if string.strcmp(name, "CInt16T") == 0: - return 1 - if string.strcmp(name, "CInt32T") == 0: - return 1 - if string.strcmp(name, "CInt64T") == 0: - return 1 - if string.strcmp(name, "CUInt8T") == 0: - return 1 - if string.strcmp(name, "CUInt16T") == 0: - return 1 - if string.strcmp(name, "CUInt32T") == 0: - return 1 - if string.strcmp(name, "CUInt64T") == 0: - return 1 - if string.strcmp(name, "CUnsigned") == 0: - return 1 - if string.strcmp(name, "CUnsignedInt") == 0: - return 1 - if string.strcmp(name, "CUnsignedChar") == 0: - return 1 - if string.strcmp(name, "CUnsignedShort") == 0: - return 1 - if string.strcmp(name, "CUnsignedLong") == 0: - return 1 - if string.strcmp(name, "CUnsignedLongLong") == 0: - return 1 - if string.strcmp(name, "CSizeT") == 0: - return 1 - if string.strcmp(name, "CIntPtrT") == 0: - return 1 - if string.strcmp(name, "CUIntPtrT") == 0: - return 1 - if string.strcmp(name, "CPtrDiffT") == 0: - return 1 - if string.strcmp(name, "CType") == 0: - return 1 - if string.strcmp(name, "CDefine") == 0: - return 1 - if string.strcmp(name, "CStatic") == 0: - return 1 - if string.strcmp(name, "CExport") == 0: - return 1 - if string.strcmp(name, "CArray") == 0: - return 1 - if string.strcmp(name, "CTypedef") == 0: - return 1 - if string.strcmp(name, "CNoVTable") == 0: - return 1 - if string.strcmp(name, "CNeedPtr") == 0: - return 1 - if string.strcmp(name, "CAutoPtr") == 0: - return 1 - return 0 - - def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, trans: HT.Translator | t.CPtr, at: ast.Attribute | t.CPtr, ty_hint: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: - """解析模块属性访问,返回全局变量引用 (用于跨模块 global 访问)""" - if at is None or at.value is None or at.attr is None: - return None - if at.value.kind() != ast.ASTKind.Name: - return None - if trans is None or trans._imported_modules is None: - return None - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if mod_nm.id is None: - return None - # 检查是否是已导入模块 - if HandlesImports.is_module_imported(trans._imported_modules, mod_nm.id) == 0: - return None - # 在当前模块查找全局变量 (stub 可能已注入) - gv: llvmlite.GlobalVariable | t.CPtr = find_global_in_module(mod, at.attr) - if gv is not None and gv.Ty is not None: - return make_global_ref(pool, at.attr, gv.Ty) - # 未找到: 创建 external global 声明并添加到模块 - # 否则只生成 @_argc 引用而无声明,LLVM 报 "use of undefined value '@_argc'" - use_ty: llvmlite.LLVMType | t.CPtr = ty_hint - if use_ty is None: - use_ty = llvmlite.Int8(pool) - # 确保 use_ty 中的跨模块结构体类型有 opaque 声明 - llvmlite.module_ensure_opaque_for_type(mod, pool, use_ty) - # 特殊处理: t.py 中的类型对象(CPtr/CInt/CDouble 等) - # t.py 不被编译,但这些类型对象在运行时被引用(如 va_arg(ap, t.CPtr))。 - # 创建带 null 初值的 linkonce_odr 全局变量定义,避免链接时 undefined reference。 - # LLVM 22+ 不允许 external linkage 全局变量带初值,使用 linkonce_odr 替代。 - is_t_type_obj: int = 0 - if string.strcmp(mod_nm.id, "t") == 0: - is_t_type_obj = _is_t_type_object_name(at.attr) - ext_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, at.attr, use_ty) - if ext_gv is not None: - if is_t_type_obj != 0: - # t.CPtr 等类型对象: 创建带 null 初值的定义(linkonce_odr) - ext_gv.Linkage = "linkonce_odr" - # i8* null 的初值文本 - null_init: bytes = pool.alloc(8) - if null_init is not None: - null_init[0] = 'n' - null_init[1] = 'u' - null_init[2] = 'l' - null_init[3] = 'l' - null_init[4] = '\0' - ext_gv.Initializer = null_init - else: - ext_gv.Initializer = None - else: - # 普通模块属性: external 声明(由其他模块提供定义) - ext_gv.Linkage = "external" - ext_gv.Initializer = None - llvmlite.module_add_global(mod, ext_gv) - return make_global_ref(pool, at.attr, use_ty) - - -# ============================================================ -# 翻译属性访问 Attribute(value, attr, ctx) — obj.field -# -# 优先级: -# 1. 枚举成员访问 (State.Idle → 常量值) -# 2. 模块属性访问 (sys._mbuddy → 加载全局变量) -# 3. 结构体字段访问 (obj.field → GEP + load) -# -# 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) -# ============================================================ + """解析模块属性访问,返回全局变量引用 (用于跨模块 global 访问)(委托到 gen._resolve_module_attribute_global)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._resolve_module_attribute_global(pool, mod, trans, at, ty_hint) + return None # ============================================================ # _get_cderef_attr_base - c.Deref(ptr).attr 属性访问的 base 指针 -# -# c.Deref(ptr) 作为属性访问 base 时(如 c.Deref(p).a),需要 ptr -# 指针本身而非 load 后的结构体值(*p.a → p->a),与 TPC -# _handle_attr_call_result 语义一致。否则 c.Deref 返回结构体值, -# 后续 GEP 在非指针上做属性访问会误报"base=非指针类型"。 -# -# 返回: -# ptr 指针值(Ptr(Struct) 或 Ptr(Ptr(Struct)),交由 _deref_if_ptr_ptr 解层级) -# 非 c.Deref 模式返回 None # ============================================================ def _get_cderef_attr_base(builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, at_value: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """检测 at.value 是否为 c.Deref(ptr) 调用,返回 ptr 指针(不做 load)""" - if at_value is None or at_value.kind() != ast.ASTKind.Call: - return None - cl_cd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(at_value) - if cl_cd.func is None or cl_cd.func.kind() != ast.ASTKind.Attribute: - return None - f_cd: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_cd.func) - if f_cd.attr is None or string.strcmp(f_cd.attr, "Deref") != 0: - return None - if f_cd.value is None or f_cd.value.kind() != ast.ASTKind.Name: - return None - nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(f_cd.value) - if nm_cd.id is None or string.strcmp(nm_cd.id, "c") != 0: - return None - if cl_cd.args is None or cl_cd.args.__len__() < 1: - return None - inner_cd: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, cl_cd.args.get(0), None, 0, trans) - if inner_cd is not None and is_ptr_type(inner_cd.Ty) != 0: - return inner_cd + """检测 at.value 是否为 c.Deref(ptr) 调用,返回 ptr 指针(不做 load)(委托到 gen._get_cderef_attr_base)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._get_cderef_attr_base(builder, pool, mod, at_value, trans) return None +# ============================================================ +# 翻译属性访问 Attribute(value, attr, ctx) — obj.field +# ============================================================ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译属性访问,返回加载的字段值""" - if node is None or builder is None: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at is None or at.value is None or at.attr is None: - # fast-fail: AST 节点字段缺失属解析器 bug,应报告具体缺失字段 - diag_buf_an: bytes = stdlib.malloc(256) - if diag_buf_an is not None: - missing_an: str = "?" - if at is not None: - if at.value is None: - missing_an = "value" - elif at.attr is None: - missing_an = "attr" - viperlib.snprintf(diag_buf_an, 256, - "属性访问失败: AST 节点字段缺失 (%s sha1=%s:%d)", - missing_an, - trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?", - at.lineno if at is not None and at.lineno is not None else 0) - VLogger.error(diag_buf_an, "ATTR") - return None + """翻译属性访问,返回加载的字段值(委托到 gen.translate_attribute)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_attribute(builder, pool, mod, node, trans) + return None - # 枚举成员访问: EnumName.MemberName → 常量值 - # 当 value 是 Name 且 Name.id 是已注册枚举时,查找成员并返回常量 - if at.value.kind() == ast.ASTKind.Name: - enum_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if enum_nm.id is not None: - if HandlesEnum.is_enum_class(enum_nm.id) == 1: - member: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member( - enum_nm.id, at.attr) - if member is not None: - base_ty: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type( - enum_nm.id) - if base_ty is not None: - # 生成数字字符串作为常量名(LLVM IR 要求常量输出数字值) - name_buf: t.CChar | t.CPtr = pool.alloc(32) - if name_buf is not None: - viperlib.snprintf(name_buf, 32, "%lld", member.Value) - return llvmlite.ConstInt(pool, base_ty, member.Value, name_buf) - return llvmlite.const_int32(pool, member.Value) - # fast-fail: 枚举成员未找到 - VLogger.error( - f"枚举成员未找到: {enum_nm.id}.{at.attr}", - "ATTR") - return None - - # 嵌套枚举成员访问: Module.EnumName.MemberName → 常量值 - # 当 value 是 Attribute(如 fileio.MODE)且 attr 部分是已注册枚举时 - if at.value.kind() == ast.ASTKind.Attribute: - inner_at_e: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) - if inner_at_e.value is not None and inner_at_e.value.kind() == ast.ASTKind.Name: - inner_nm_e: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_at_e.value) - if inner_nm_e.id is not None and inner_at_e.attr is not None: - if HandlesEnum.is_enum_class(inner_at_e.attr) == 1: - member_e: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member( - inner_at_e.attr, at.attr) - if member_e is not None: - base_ty_e: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type( - inner_at_e.attr) - if base_ty_e is not None: - name_buf_e: t.CChar | t.CPtr = pool.alloc(32) - if name_buf_e is not None: - viperlib.snprintf(name_buf_e, 32, "%lld", member_e.Value) - return llvmlite.ConstInt(pool, base_ty_e, member_e.Value, name_buf_e) - return llvmlite.const_int32(pool, member_e.Value) - # fast-fail: 嵌套枚举成员未找到 - VLogger.error( - f"嵌套枚举成员未找到: {inner_at_e.attr}.{at.attr}", - "ATTR") - return None - - # 模块属性访问 (读路径): sys._mbuddy → 加载全局变量 @_mbuddy - # 当 obj 是已导入模块名且不是普通变量时,查找/创建全局变量引用并加载 - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm_ma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_ma.id is not None: - # 先检查是否是普通变量 (优先级高于模块属性) - ma_is_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm_ma.id) - if ma_is_var is None: - # 先检查是否是 CDefine 编译期常量 (如 ast.CONST_INT / win32base.INVALID_HANDLE_VALUE) - # 模块属性访问的 CDefine 常量需要跨模块查找源 .vp / .vpi 文件 - cdef_ma_val: int = HandlesType.lookup_cdefine_constant(at.attr) - cd_local: int = HandlesType.is_cdefine_found() - if cd_local == 0: - # 确定真实模块名:优先从 _from_imports 解析别名 - # from_imports 中条目格式 "local_name:real_module" - # 如 win32base:w32.win32base → 别名 win32base 真实模块 w32.win32base - real_mod_name: str = nm_ma.id - if trans._from_imports is not None: - resolved_mod: str = HandlesImports.lookup_from_import( - trans._from_imports, nm_ma.id, 0) - if resolved_mod is not None: - # 复制模块名到新缓冲区(截断于空格、null、或 ':') - rm_len: t.CSizeT = 0 - while resolved_mod[rm_len] != ' ' and resolved_mod[rm_len] != '\0' and resolved_mod[rm_len] != ':': - rm_len += 1 - rm_buf: str = pool.alloc(rm_len + 1) - if rm_buf is not None: - for rm_i in range(rm_len): - rm_buf[rm_i] = resolved_mod[rm_i] - rm_buf[rm_len] = '\0' - real_mod_name = rm_buf - # 即使 _from_imports 为 None(如纯 `import ast` 无 from-import), - # 也必须尝试跨模块 CDefine 查找,否则 ast.CONST_INT 会被 - # 误解析为全局变量引用 @CONST_INT(未定义符号)。 - # 构建临时 from_imports "{attr}:{real_module}" 用于跨模块查找 - if real_mod_name is not None: - ma_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod_name) + 2 - ma_fi: str = pool.alloc(ma_fi_len) - if ma_fi is not None: - viperlib.snprintf(ma_fi, ma_fi_len, "%s:%s", at.attr, real_mod_name) - cdef_ma_val = _lookup_cross_module_cdefine(pool, at.attr, ma_fi) - if HandlesType.is_cdefine_found() != 0: - return llvmlite.const_int32(pool, cdef_ma_val) - # 检查 nm_ma.id.at.attr 是否是已导入子模块 (如 w32.win32file) - # 如果是子模块,不应创建全局变量,让嵌套属性访问路径处理 - is_submod: int = 0 - if trans._imported_modules is not None: - submod_len: t.CSizeT = string.strlen(nm_ma.id) + string.strlen(at.attr) + 2 - submod_buf: t.CChar | t.CPtr = pool.alloc(submod_len) - if submod_buf is not None: - viperlib.snprintf(submod_buf, submod_len, "%s.%s", nm_ma.id, at.attr) - if HandlesImports.is_module_imported(trans._imported_modules, submod_buf) == 1: - is_submod = 1 - # also check from_imports: at.attr 别名对应真实模块 w32.win32file - if is_submod == 0 and trans._from_imports is not None: - fi_mod_raw: str = HandlesImports.lookup_from_import( - trans._from_imports, at.attr, 0) - if fi_mod_raw is not None: - # 复制模块名到新缓冲区(截断于空格、null、或 ':') - fm_len: t.CSizeT = 0 - while fi_mod_raw[fm_len] != ' ' and fi_mod_raw[fm_len] != '\0' and fi_mod_raw[fm_len] != ':': - fm_len += 1 - fi_mod: str = pool.alloc(fm_len + 1) - if fi_mod is not None: - for fm_i in range(fm_len): - fi_mod[fm_i] = fi_mod_raw[fm_i] - fi_mod[fm_len] = '\0' - # 检查 fi_mod 是否以 "nm_ma.id." 开头 (如 w32.win32file 以 w32. 开头) - prefix_len: t.CSizeT = string.strlen(nm_ma.id) - fi_mod_len: t.CSizeT = string.strlen(fi_mod) - if fi_mod_len > prefix_len + 1: - match_prefix: int = 1 - for pi in range(prefix_len): - if fi_mod[pi] != nm_ma.id[pi]: - match_prefix = 0 - break - if match_prefix == 1 and fi_mod[prefix_len] == '.': - is_submod = 1 - if is_submod != 0: - return None # 是子模块,交给嵌套属性访问路径 - # 特殊处理: t.ASM_DESCR 不是 CDefine,是内联汇编约束命名空间 - # t.ASM_DESCR.XXX 由 HandlesExprCall 的 _asm_resolve_constraint 处理 - # 此处返回 None,让上层嵌套属性访问路径处理 - if string.strcmp(nm_ma.id, "t") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0: - return None - # CDefine 未找到且属性名符合 ALL_CAPS 约定: 报 FATAL 错误 - # 不再创建未定义的外部全局变量引用(否则 llc 报 "use of undefined value") - if _is_cdefine_name_pattern(at.attr) != 0: - err_buf_sma: str = pool.alloc(256) - if err_buf_sma is not None: - cur_sha1_sma: str = "(unknown)" - if trans is not None and trans.ModuleSha1 is not None: - cur_sha1_sma = trans.ModuleSha1 - viperlib.snprintf(err_buf_sma, 256, - "[CD] FATAL: Module attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n", - nm_ma.id, at.attr, cur_sha1_sma) - VLogger.error(err_buf_sma, "CD") - return None - # 非 CDefine: 使用 i8* 作为类型提示 (模块级变量通常存储指针) - i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - mod_gv_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global( - pool, mod, trans, at, i8_ptr_hint) - if mod_gv_ref is not None and mod_gv_ref.Ty is not None: - load_ty_mod: llvmlite.LLVMType | t.CPtr = mod_gv_ref.Ty.Pointee - if load_ty_mod is not None: - return llvmlite.build_load(builder, load_ty_mod, mod_gv_ref) - - # 嵌套模块属性访问 (w32.win32file.GENERIC_READ → 查找全局 @GENERIC_READ) - # 当 at.value 是 Attribute 且解析为已导入子模块时,查找 at.attr 作为全局常量 - if at.value.kind() == ast.ASTKind.Attribute and trans is not None: - inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value) - if inner_at.value is not None and inner_at.value.kind() == ast.ASTKind.Name: - inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_at.value) - if inner_nm.id is not None and inner_at.attr is not None: - if HandlesVar.lookup_var(trans.SymTab, inner_nm.id) is None: - # 构建限定模块名: "w32.win32file" - qual_len: t.CSizeT = string.strlen(inner_nm.id) + string.strlen(inner_at.attr) + 2 - qual_buf: t.CChar | t.CPtr = pool.alloc(qual_len) - if qual_buf is not None: - viperlib.snprintf(qual_buf, qual_len, "%s.%s", inner_nm.id, inner_at.attr) - if HandlesImports.is_module_imported(trans._imported_modules, qual_buf) == 1: - # 查找全局变量 at.attr (stub 已注入的情况) - gv_nested: llvmlite.GlobalVariable | t.CPtr = find_global_in_module(mod, at.attr) - if gv_nested is not None and gv_nested.Ty is not None: - gv_ref_nested: llvmlite.Value | t.CPtr = make_global_ref( - pool, at.attr, gv_nested.Ty) - if gv_ref_nested is not None and gv_ref_nested.Ty is not None: - load_ty_nested: llvmlite.LLVMType | t.CPtr = gv_ref_nested.Ty.Pointee - if load_ty_nested is not None: - return llvmlite.build_load(builder, load_ty_nested, gv_ref_nested) - # 未找到全局: 尝试 CDefine 常量查找 - # 对于 w32.win32base.INVALID_HANDLE_VALUE 等嵌套模块属性访问, - # 先从限定模块的 .vpi 文件中查找 CDefine 常量值并内联 - cdef_val_nested: int = HandlesType.lookup_cdefine_constant(at.attr) - if HandlesType.is_cdefine_found() == 0: - # 构建临时 from_imports "attr:module" 用于跨模块查找 - tmp_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(qual_buf) + 2 - tmp_fi: str = pool.alloc(tmp_fi_len) - if tmp_fi is not None: - viperlib.snprintf(tmp_fi, tmp_fi_len, "%s:%s", at.attr, qual_buf) - cdef_val_nested = _lookup_cross_module_cdefine(pool, at.attr, tmp_fi) - if HandlesType.is_cdefine_found() != 0: - return llvmlite.const_int32(pool, cdef_val_nested) - # CDefine 未找到: 报 FATAL 错误(不再创建未定义的全局变量引用) - # 之前此处创建 @INVALID_HANDLE_VALUE 等前向引用,但全局未定义, - # 导致 llc 报 "use of undefined value" 错误。 - # 正确做法是报错终止,让开发者修复跨模块 CDefine 查找失败的根本原因。 - if _is_cdefine_name_pattern(at.attr) != 0: - err_buf_ma: str = pool.alloc(256) - if err_buf_ma is not None: - cur_sha1_ma: str = "(unknown)" - if trans is not None and trans.ModuleSha1 is not None: - cur_sha1_ma = trans.ModuleSha1 - viperlib.snprintf(err_buf_ma, 256, - "[CD] FATAL: Nested attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n", - qual_buf, at.attr, cur_sha1_ma) - VLogger.error(err_buf_ma, "CD") - return None - - # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体) - obj_ptr: llvmlite.Value | t.CPtr = None - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm.id is not None: - obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) - - # 非 Name 路径:翻译对象值(会 load) - if obj_ptr is None: - # c.Deref(ptr).attr: 属性访问 base 取指针本身而非 load 后的结构体值 - # (如 c.Deref(p).a 语义是 (*p).a,直接对 p 做 GEP) - cd_base_rd: llvmlite.Value | t.CPtr = _get_cderef_attr_base( - builder, pool, mod, at.value, trans) - if cd_base_rd is not None: - obj_ptr = cd_base_rd - elif at.value.kind() == ast.ASTKind.Subscript: - # 下标基座属性访问(如 pts[0].x):list[T]/OOP __getitem__ 类走 - # translate_value(返回元素值/地址);普通结构体指针数组走 - # get_subscript_ptr(GEP 元素地址,避免结构体值 base=非指针 报错) - if _sub_base_uses_getitem(pool, mod, trans, at.value) != 0: - obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = get_subscript_ptr(builder, pool, mod, at.value, trans) - elif at.value.kind() == ast.ASTKind.Attribute: - # 嵌套属性基座(如 r.origin.x):取内层字段地址(get_attribute_ptr 递归, - # 地址语义),指针字段(X|t.CPtr)由 _deref_if_ptr_ptr load 解引用 - obj_ptr = get_attribute_ptr(builder, pool, mod, at.value, trans) - if obj_ptr is None: - obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans) - - if obj_ptr is None or obj_ptr.Ty is None: - return None - - # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), - # load 解引用获取 Ptr(Struct) - obj_ptr = _deref_if_ptr_ptr(builder, obj_ptr) - - # 查找结构体类型信息 - # obj_ptr 类型应该是 Ptr(Struct(...)) - match obj_ptr.Ty: - case llvmlite.LLVMType.Ptr(struct_ty): - # 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - # 查找字段索引和类型 - field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - struct_ty, at.attr) - # REnum 变体字段查找: lookup_field 失败时,尝试 REnum 别名 - # REnum 结构体字段名是 _p1/_p2/...,但源码用变体字段名访问(如 ty.Pointee) - if field_info is None: - renum_se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type( - struct_ty) - if renum_se is not None and renum_se.Name is not None: - is_rn: int = HandlesClassDef._is_renum_class_name(renum_se.Name) - if is_rn == 1: - alias_idx: int = HandlesClassDef._lookup_renum_field_alias( - renum_se.Name, at.attr) - if alias_idx >= 1: - alias_fe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct._get_field_entry(renum_se, alias_idx) - if alias_fe is not None and alias_fe.Ty is not None: - alias_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, alias_fe.Ty, obj_ptr, alias_idx) - if alias_ptr is not None: - return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr) - # property getter 回退: obj.attr 是 @property/@x.getter 方法时生成调用 - # (字段未找到时先尝试,避免报误导性的"字段未找到"错误) - if field_info is None and at.value is not None and trans is not None: - prop_cls_fb: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) - prop_val: llvmlite.Value | t.CPtr = HandlesExprCall._try_property_getter_attr( - pool, builder, mod, at, obj_ptr, trans, prop_cls_fb) - if prop_val is not None: - return prop_val - # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找 - # 传递 SHA1 以区分跨模块同名类 - if field_info is None: - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_fb.id is not None: - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm_fb.id) - if var_entry is not None and var_entry.AnnotClassName is not None: - cur_sha1: str = trans.ModuleSha1 - field_info = HandlesStruct.lookup_field_by_class( - var_entry.AnnotClassName, at.attr, cur_sha1) - # 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型 - # 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)), - # 需用实际结构体类型做 GEP,否则 GEP i8 失败 - if field_info is not None: - annot_se: HandlesStruct.StructEntry | t.CPtr = \ - HandlesStruct.find_struct(var_entry.AnnotClassName) - if annot_se is not None and annot_se.Ty is not None: - annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \ - llvmlite.Ptr(pool, annot_se.Ty) - casted_ptr: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty) - if casted_ptr is not None: - obj_ptr = casted_ptr - struct_ty = annot_se.Ty - # 按需过滤更新 struct_ty 后,需重新确保 - # 注解类型结构体定义在当前模块可用 - # (原始 struct_ty 可能是 i8,ensure 无效) - HandlesStruct.ensure_struct_def_in_module( - pool, mod, annot_se.Ty) - if field_info is not None: - field_ty: llvmlite.LLVMType | t.CPtr = field_info.Ty - # 联合体:bitcast obj_ptr 到 field_ty* 后 load - if HandlesStruct.is_union_by_type(struct_ty) == 1: - field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_ty) - casted: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, obj_ptr, field_ptr_ty) - if casted is not None: - return llvmlite.build_load(builder, field_ty, casted) - return None - # 普通结构体:GEP + load - field_idx: int = field_info.Index - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, field_ty, obj_ptr, field_idx) - if field_ptr is not None: - # 数组类型字段不能 load 为 SSA value,直接返回字段指针 - # 用于后续下标访问: self.state[0] → GEP state 字段 → GEP 数组元素 - if is_array_type(field_ty) != 0: - return field_ptr - loaded_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, field_ty, field_ptr) - # 联合类型字段(如 Token | t.CPtr)被编译为 i8*, - # 若 AnnotClassName 指示了具体结构体类型,bitcast 为正确的结构体指针。 - # 注意:仅当字段类型本身是指针时才 bitcast(指针→指针); - # 内嵌结构体字段(field_ty=Struct)load 出的是结构体值, - # bitcast 值→指针是非法 IR(llc: invalid cast opcode)。 - if loaded_val is not None and field_info.AnnotClassName is not None \ - and is_ptr_type(field_ty) != 0: - annot_struct: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( - field_info.AnnotClassName) - if annot_struct is not None and annot_struct.Ty is not None: - annot_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, annot_struct.Ty) - return llvmlite.build_bitcast(builder, loaded_val, annot_ptr_ty) - return loaded_val - # fast-fail: 字段未找到,打印诊断信息 - if trans is not None: - diag_annot: str = None - diag_var_nm: str = None - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - diag_var_nm = dnm.id - if dnm.id is not None: - dve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, dnm.id) - if dve is not None: - diag_annot = dve.AnnotClassName - fb_attr: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb_attr is not None: - viperlib.snprintf(fb_attr, 1024, - "属性访问失败: .%s (var=%s annot=%s sha1=%s:%d)", - at.attr, - diag_var_nm if diag_var_nm is not None else "?", - diag_annot if diag_annot is not None else "None", - trans.ModuleSha1 if trans.ModuleSha1 is not None else "?", - at.lineno if at.lineno is not None else 0) - VLogger.error(fb_attr, "ATTR") - return None - case _: - # fast-fail: 对非指针类型做属性访问(如 i32.x), - # Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃,丢失错误现场) - attr_nm_ap: str = "?" - if at is not None and at.attr is not None: - attr_nm_ap = at.attr - sha1_ap: str = "?" - if trans is not None and trans.ModuleSha1 is not None: - sha1_ap = trans.ModuleSha1 - ln_ap: int = 0 - if at is not None and at.lineno is not None: - ln_ap = at.lineno - HandlesType.fatal_error( - at, - f"属性访问失败: .{attr_nm_ap} (base=非指针类型,无法做属性访问 sha1={sha1_ap}:{ln_ap})", - "TypeError") # ============================================================ # 获取下标表达式的元素指针(不加载值,用于赋值) @@ -3446,270 +743,25 @@ def get_subscript_ptr(builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """获取下标表达式的元素指针(用于赋值 lhs)""" - if node is None or builder is None: - return None - sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node) - if sub is None: - return None - - # 翻译索引 - idx_val: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, sub.slice, None, 0, trans) - if idx_val is None: - return None - - # 如果 value 是 Name,尝试从 alloca 类型推断 - if sub.value is not None and sub.value.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value) - if nm.id is not None and trans is not None: - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is not None and alloca.Ty is not None: - if is_ptr_type(alloca.Ty) != 0: - pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee - if pointee is not None: - # 用 match 检查 pointee 类型 - match pointee: - case llvmlite.LLVMType.Array(elem_ty, count): - # 数组遍历 - return llvmlite.build_gep_array( - builder, pointee, elem_ty, alloca, - _zext_index_to_i32(builder, idx_val)) - case llvmlite.LLVMType.Ptr(inner_ty): - # inner_ty 是 Ptr 说明 alloca.Ty 是三重指针, - # 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。 - # 此时 [i]=val 应该是指针解引用赋值, 而非调用 __setitem__。 - if is_ptr_type(inner_ty) != 0: - ptr_val_gsp: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val_gsp is not None: - return llvmlite.build_gep( - builder, inner_ty, ptr_val_gsp, idx_val) - return None - # 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr): - # 仅当类定义了 __setitem__(当前模块定义或跨模块 stub declare 注入) - # 才返回 None 触发 __setitem__ 重载;否则普通结构体指针按下标 - # 做 GEP 数组访问(走下方指针遍历路径) - cls_nm_ptr_chk: str = _get_custom_struct_cls_nm(pool, inner_ty) - if not (cls_nm_ptr_chk is None): - si_lookup_gsp: t.CChar | t.CPtr = pool.alloc(128) - if si_lookup_gsp is not None: - viperlib.snprintf(si_lookup_gsp, 128, "%s.__setitem__", cls_nm_ptr_chk) - if HandlesExprCall.find_func_in_module(mod, si_lookup_gsp) is not None: - return None - # bytes|t.CPtr / str|t.CPtr: alloca 是 i8**, - # 直接 GEP 按 i8* 步长(8 字节),不 load - # 仅当 inner_ty 不是自定义结构体时才走指针遍历 - if trans is not None: - ve_pe: HandlesVar.VarEntry | t.CPtr = \ - HandlesVar.lookup_var_entry(trans.SymTab, nm.id) - if ve_pe is not None and ve_pe.IsPtrElement == 1: - return llvmlite.build_gep( - builder, pointee, alloca, idx_val) - # 普通指针遍历: 先 load 指针值,再 GEP - ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, pointee, alloca) - if ptr_val is None: - return None - gep_r: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, inner_ty, ptr_val, idx_val) - return gep_r - case _: - # pointee 是普通标量类型 (如 i64, i32, i8): - # alloca 是 Ptr(标量), 直接 GEP 获取第 idx 个元素指针 - # 支持 arg_vals[i] = val 这类参数数组下标赋值 - return llvmlite.build_gep(builder, pointee, alloca, idx_val) - - # 通用路径 - ptr_val: llvmlite.Value | t.CPtr = translate_value( - builder, pool, mod, sub.value, None, 0, trans) - if ptr_val is None or ptr_val.Ty is None: - return None - if is_ptr_type(ptr_val.Ty) != 0: - elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee - if elem_ty2 is not None: - # 数组类型: 双索引 GEP (getelementptr [N x ty], ptr, i32 0, i32 idx) - match elem_ty2: - case llvmlite.LLVMType.Array(arr_elem_ty, arr_count): - return llvmlite.build_gep_array( - builder, elem_ty2, arr_elem_ty, ptr_val, - _zext_index_to_i32(builder, idx_val)) - case _: - pass - # 自定义结构体 (如 self._ht[key]): 仅当类定义了 __setitem__ - # 才返回 None 触发 HandlesAssign 的 __setitem__ 重载; - # 否则普通结构体指针按下标做 GEP 数组访问 - cls_nm_gen: str = _get_custom_struct_cls_nm(pool, elem_ty2) - if not (cls_nm_gen is None): - si_lookup_gen: t.CChar | t.CPtr = pool.alloc(128) - if si_lookup_gen is not None: - viperlib.snprintf(si_lookup_gen, 128, "%s.__setitem__", cls_nm_gen) - if find_func_in_module(mod, si_lookup_gen) is not None: - return None - # 指针类型: 单索引 GEP (getelementptr ty, ptr, idx) - return llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val) + """获取下标表达式的元素指针(用于赋值 lhs)(委托到 gen.get_subscript_ptr)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.get_subscript_ptr(builder, pool, mod, node, trans) return None # ============================================================ # 获取属性访问的字段指针(不加载值,用于赋值) -# 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体) # ============================================================ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """获取属性访问的字段指针(用于赋值 lhs)""" - if node is None or builder is None: - return None - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at is None or at.value is None or at.attr is None: - return None - - # 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体) - obj_ptr: llvmlite.Value | t.CPtr = None - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm.id is not None: - obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id) - - # 模块属性访问 (写路径): sys._mbuddy = mb → store 到全局变量 @_mbuddy - # 当 obj 是已导入模块名且不是普通变量时,查找/创建全局变量引用 - if obj_ptr is None and at.value.kind() == ast.ASTKind.Name and trans is not None: - nm_wma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_wma.id is not None: - # CDefine 常量不可写: 报 FATAL 错误,不创建未定义全局 - if _is_cdefine_name_pattern(at.attr) != 0: - err_buf_wma: str = pool.alloc(256) - if err_buf_wma is not None: - viperlib.snprintf(err_buf_wma, 256, - "[CD] FATAL: Cannot assign to CDefine constant '%s.%s'\n", - nm_wma.id, at.attr) - VLogger.error(err_buf_wma, "CD") - return None - # 使用 i8* 作为类型提示 (模块级变量通常存储指针) - i8_ptr_w: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - wma_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global( - pool, mod, trans, at, i8_ptr_w) - if wma_ref is not None: - return wma_ref - - # 非 Name 路径:翻译对象值(会 load) - if obj_ptr is None: - # c.Deref(ptr).attr: 属性写入 base 取指针本身而非 load 后的结构体值 - # (如 c.Deref(p).a = val 语义是 (*p).a = val,直接对 p 做 GEP) - cd_base_wr: llvmlite.Value | t.CPtr = _get_cderef_attr_base( - builder, pool, mod, at.value, trans) - if cd_base_wr is not None: - obj_ptr = cd_base_wr - elif at.value.kind() == ast.ASTKind.Subscript: - # 下标基座属性写入(如 pts[0].x = val):list[T]/OOP __getitem__ 类走 - # translate_value(返回元素值/地址);普通结构体指针数组走 - # get_subscript_ptr(GEP 元素地址,避免结构体值 base=非指针 报错) - if _sub_base_uses_getitem(pool, mod, trans, at.value) != 0: - obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = get_subscript_ptr(builder, pool, mod, at.value, trans) - elif at.value.kind() == ast.ASTKind.Attribute: - # 嵌套属性基座写入(如 r.origin.x = val):取内层字段地址 - # (get_attribute_ptr 递归,地址语义),指针字段由 _deref_if_ptr_ptr 解引用 - obj_ptr = get_attribute_ptr(builder, pool, mod, at.value, trans) - if obj_ptr is None: - obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans) - else: - obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans) - - if obj_ptr is None or obj_ptr.Ty is None: - return None - - # 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca), - # load 解引用获取 Ptr(Struct) - obj_ptr = _deref_if_ptr_ptr(builder, obj_ptr) - - match obj_ptr.Ty: - case llvmlite.LLVMType.Ptr(struct_ty): - # 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段) - # 与 translate_attribute 一致,避免 opaque 类型导致 GEP 报错 - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - struct_ty, at.attr) - # 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找 - # 传递 SHA1 以区分跨模块同名类 - if field_info is None: - if at.value.kind() == ast.ASTKind.Name and trans is not None: - nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_fb.id is not None: - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm_fb.id) - if var_entry is not None and var_entry.AnnotClassName is not None: - cur_sha1: str = None - if trans is not None: - cur_sha1 = trans.ModuleSha1 - field_info = HandlesStruct.lookup_field_by_class( - var_entry.AnnotClassName, at.attr, cur_sha1) - # 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型 - # 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)), - # 需用实际结构体类型做 GEP,否则 GEP i8 失败 - if field_info is not None: - annot_se: HandlesStruct.StructEntry | t.CPtr = \ - HandlesStruct.find_struct(var_entry.AnnotClassName) - if annot_se is not None and annot_se.Ty is not None: - annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \ - llvmlite.Ptr(pool, annot_se.Ty) - casted_ptr: llvmlite.Value | t.CPtr = \ - llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty) - if casted_ptr is not None: - obj_ptr = casted_ptr - struct_ty = annot_se.Ty - # 按需过滤更新 struct_ty 后,需重新确保 - # 注解类型结构体定义在当前模块可用 - HandlesStruct.ensure_struct_def_in_module( - pool, mod, annot_se.Ty) - if field_info is not None: - # 联合体:bitcast obj_ptr 到 field_ty*(字段指针用于 store) - if HandlesStruct.is_union_by_type(struct_ty) == 1: - field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_info.Ty) - return llvmlite.build_bitcast(builder, obj_ptr, field_ptr_ty) - # 普通结构体:GEP 获取字段指针 - return llvmlite.build_gep_struct( - builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index) - # fast-fail: 字段未找到,打印诊断信息 - if trans is not None: - diag_annot_g: str = None - diag_var_nm_g: str = None - if at.value is not None and at.value.kind() == ast.ASTKind.Name: - dnm_g: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - diag_var_nm_g = dnm_g.id - if dnm_g.id is not None: - dve_g: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, dnm_g.id) - if dve_g is not None: - diag_annot_g = dve_g.AnnotClassName - fb_attr_g: t.CChar | t.CPtr = VLogger.fmt_buf() - if fb_attr_g is not None: - viperlib.snprintf(fb_attr_g, 1024, - "属性写入失败: .%s (var=%s annot=%s sha1=%s:%d)", - at.attr, - diag_var_nm_g if diag_var_nm_g is not None else "?", - diag_annot_g if diag_annot_g is not None else "None", - trans.ModuleSha1 if trans.ModuleSha1 is not None else "?", - at.lineno if at.lineno is not None else 0) - VLogger.error(fb_attr_g, "ATTR") - return None - case _: - # fast-fail: 对非指针类型做属性写入(如 i32.x = ...), - # Python traceback 立即终止,不静默返回 None(否则下游 "store to None" 崩溃) - attr_nm_gp: str = "?" - if at is not None and at.attr is not None: - attr_nm_gp = at.attr - sha1_gp: str = "?" - if trans is not None and trans.ModuleSha1 is not None: - sha1_gp = trans.ModuleSha1 - ln_gp: int = 0 - if at is not None and at.lineno is not None: - ln_gp = at.lineno - HandlesType.fatal_error( - at, - f"属性写入失败: .{attr_nm_gp} (base=非指针类型,无法做属性写入 sha1={sha1_gp}:{ln_gp})", - "TypeError") + """获取属性访问的字段指针(用于赋值 lhs)(委托到 gen.get_attribute_ptr)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.get_attribute_ptr(builder, pool, mod, node, trans) + return None diff --git a/App/lib/core/Handles/HandlesExprOps.vp b/App/lib/core/Handles/HandlesExprOps.vp index 12e9c20..7b21364 100644 --- a/App/lib/core/Handles/HandlesExprOps.vp +++ b/App/lib/core/Handles/HandlesExprOps.vp @@ -11,50 +11,64 @@ import lib.core.Handles.HandlesTranslator as HT # ============================================================ -# HandlesExprOps - 二元运算处理(模块级纯函数) +# HandlesExprOps - 二元运算处理(P3 对象化后的委托层) +# +# 全部函数已迁移为 lib.core.Gen.ExprGenMixin 的方法,本模块保留 +# 同名模块级函数作为"一行委托":延迟 import Gen 取全局单例 +# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen +# 的对应方法。签名与旧函数完全一致,调用方零改动。 # ============================================================ + # ============================================================ -# 运算符重载支持 +# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式) # -# 当二元/比较运算的 lhs 是结构体指针时,检查该类是否定义了 -# 对应的 dunder 方法(如 __add__、__eq__),若有则生成方法调用 -# 而非原生算术/比较指令。 +# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。 +# P3 委托函数用本地 _g_gen(cast 成 Generator 类型)调 +# ExprGenMixin 方法。 # ============================================================ +_g_gen: t.CVoid | t.CPtr = None + + +def set_global_gen(gen: t.CVoid | t.CPtr) -> None: + """注入全局 gen 单例(BuildPipeline/main 调用)""" + global _g_gen + _g_gen = gen + + +# ============================================================ +# 委托函数:延迟 import Gen 取全局单例 → 调 gen 方法 +# (gen 未注册时正常流程不会发生;有返回值函数返回默认值) +# ============================================================ + # BinOp 运算符 → dunder 方法名 def _binop_to_dunder(op: int) -> str: - """将 BinOp 运算符映射到 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 "__div__" - if op == ast.OpKind.Mod: return "__mod__" - 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.FloorDiv: return "__floordiv__" + """将 BinOp 运算符映射到 dunder 方法名,无映射时返回 None(委托到 gen._binop_to_dunder)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._binop_to_dunder(op) return None + # Compare 运算符 → dunder 方法名 def _cmpop_to_dunder(op: int) -> str: - """将 Compare 运算符映射到 dunder 方法名,无映射时返回 None""" - if op == ast.OpKind.Eq: return "__eq__" - if op == ast.OpKind.Ne: return "__ne__" - if op == ast.OpKind.Lt: return "__lt__" - if op == ast.OpKind.Le: return "__le__" - if op == ast.OpKind.Gt: return "__gt__" - if op == ast.OpKind.Ge: return "__ge__" + """将 Compare 运算符映射到 dunder 方法名,无映射时返回 None(委托到 gen._cmpop_to_dunder)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._cmpop_to_dunder(op) return None + # UnaryOp 运算符 → dunder 方法名 def _unaryop_to_dunder(op: int) -> str: - """将 UnaryOp 运算符映射到 dunder 方法名,无映射时返回 None""" - if op == ast.OpKind.USub: return "__neg__" - if op == ast.OpKind.UAdd: return "__pos__" - if op == ast.OpKind.Invert: return "__invert__" + """将 UnaryOp 运算符映射到 dunder 方法名,无映射时返回 None(委托到 gen._unaryop_to_dunder)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._unaryop_to_dunder(op) return None @@ -64,19 +78,6 @@ def _unaryop_to_dunder(op: int) -> str: # 检查 lhs 是否为结构体指针,并在该类(含继承链)中查找对应的 # dunder 方法。找到则生成方法调用 lhs.__dunder__(rhs),返回 # 调用结果;未找到返回 None,调用方回退到原生运算。 -# -# Args: -# pool: 内存池 -# builder: IRBuilder -# mod: LLVM 模块 -# lhs: 左操作数 Value(已求值) -# rhs: 右操作数 Value(已求值) -# op: OpKind 运算符 -# trans: Translator 对象 -# is_compare: 0=BinOp, 1=Compare(决定 dunder 映射表) -# -# Returns: -# 方法调用的 Value(成功),None(未重载) # ============================================================ def try_operator_overload(pool: memhub.MemBuddy | t.CPtr, builder: llvmlite.IRBuilder | t.CPtr, @@ -86,89 +87,12 @@ def try_operator_overload(pool: memhub.MemBuddy | t.CPtr, op: int, trans: HT.Translator | t.CPtr, is_compare: int) -> llvmlite.Value | t.CPtr: - """尝试运算符重载:lhs 是结构体指针时调用 dunder 方法,否则返回 None""" - if lhs is None or rhs is None: - return None - - # 延迟导入避免循环依赖 - import lib.core.Handles.HandlesStruct as HandlesStruct - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - # 映射运算符到 dunder 方法名 - dunder: str = None - if is_compare != 0: - dunder = _cmpop_to_dunder(op) - else: - dunder = _binop_to_dunder(op) - if dunder is None: - return None - - # 检查 lhs 是否为结构体指针 - struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(lhs) - if struct_ty is None: - return None - - # 获取类名 - class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) - if class_name is None: - return None - - # 在继承链中查找 dunder 方法 - lookup_name: t.CChar | t.CPtr = pool.alloc(128) - if lookup_name is None: - return None - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) - found_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, lookup_name) - - search_class: str = class_name - if found_func is None: - # 多继承:沿 MRO 祖先链查找(先声明父类优先) - 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: - parent_lookup: t.CChar | t.CPtr = pool.alloc(128) - if parent_lookup is not None: - viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) - parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup) - if parent_func is not None: - found_func = parent_func - search_class = anc - break - mi += 1 - - # 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入) - # 优先用类型指针定位 entry 获取 SHA1(规避跨模块同名 find_struct 找错) - cls_sha1: str = None - op_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - if op_entry is not None: - cls_sha1 = op_entry.ModuleSha1 - if cls_sha1 is None: - cls_sha1 = HandlesStruct.get_struct_sha1(search_class) - if cls_sha1 is None: - mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class) - mj: int = 1 - while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None: - anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr)) - if anc_p is not None: - cls_sha1 = HandlesStruct.get_struct_sha1(anc_p) - mj += 1 - - # 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算 - if found_func is None and cls_sha1 is None: - return None - - # 构建 extra_args 数组(仅含 rhs 一个参数) - extra_args: t.CSizeT | t.CPtr = pool.alloc(8) - if extra_args is None: - return None - extra_args[0] = t.CSizeT(rhs) - - # 调用方法: lhs.__dunder__(rhs) - return HandlesExprCall._call_method_on_ptr( - pool, builder, mod, search_class, dunder, - lhs, extra_args, 1, trans) + """尝试运算符重载:lhs 是结构体指针时调用 dunder 方法,否则返回 None(委托到 gen.try_operator_overload)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.try_operator_overload(pool, builder, mod, lhs, rhs, op, trans, is_compare) + return None # ============================================================ @@ -184,77 +108,12 @@ def try_unary_operator_overload(pool: memhub.MemBuddy | t.CPtr, operand: llvmlite.Value | t.CPtr, op: int, trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """尝试一元运算符重载:operand 是结构体指针时调用 dunder 方法,否则返回 None""" - if operand is None: - return None - - # 延迟导入避免循环依赖 - import lib.core.Handles.HandlesStruct as HandlesStruct - import lib.core.Handles.HandlesExprCall as HandlesExprCall - - dunder: str = _unaryop_to_dunder(op) - if dunder is None: - return None - - # 检查 operand 是否为结构体指针 - struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(operand) - if struct_ty is None: - return None - - # 获取类名 - class_name: str = HandlesStruct.get_class_name_by_type(pool, struct_ty) - if class_name is None: - return None - - # 在继承链中查找 dunder 方法 - lookup_name: t.CChar | t.CPtr = pool.alloc(128) - if lookup_name is None: - return None - viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder) - found_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, lookup_name) - - search_class: str = class_name - if found_func is None: - # 多继承:沿 MRO 祖先链查找(先声明父类优先) - 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: - parent_lookup: t.CChar | t.CPtr = pool.alloc(128) - if parent_lookup is not None: - viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, dunder) - parent_func: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, parent_lookup) - if parent_func is not None: - found_func = parent_func - search_class = anc - break - mi += 1 - - # 方法不在当前模块中时,检查类(含父类)是否有 SHA1(stub 可能未注入) - cls_sha1: str = None - uop_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - if uop_entry is not None: - cls_sha1 = uop_entry.ModuleSha1 - if cls_sha1 is None: - cls_sha1 = HandlesStruct.get_struct_sha1(search_class) - if cls_sha1 is None: - mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, search_class) - mj: int = 1 - while mro_p is not None and mro_p[mj] != 0 and cls_sha1 is None: - anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr)) - if anc_p is not None: - cls_sha1 = HandlesStruct.get_struct_sha1(anc_p) - mj += 1 - - # 既无函数定义也无 SHA1 → 该类没有此 dunder 方法,返回 None 回退原生运算 - if found_func is None and cls_sha1 is None: - return None - - # 一元方法无额外参数(extra_args 为空) - return HandlesExprCall._call_method_on_ptr( - pool, builder, mod, search_class, dunder, - operand, None, 0, trans) + """尝试一元运算符重载:operand 是结构体指针时调用 dunder 方法,否则返回 None(委托到 gen.try_unary_operator_overload)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.try_unary_operator_overload(pool, builder, mod, operand, op, trans) + return None # ============================================================ @@ -265,136 +124,9 @@ def translate_binop(pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, node: ast.AST | t.CPtr, trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """翻译二元运算(自动类型提升)""" - binop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) - if binop is None: - return None - - lhs_node: ast.AST | t.CPtr = binop.left - rhs_node: ast.AST | t.CPtr = binop.right - op: int = binop.op - - # 先翻译 rhs(只翻译一次,避免副作用重复) - rhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, rhs_node, None, 0, trans) - if rhs is None: - return None - - # === 运算符重载路径 1: lhs 是 Name 且对应结构体变量 === - # 对于值类型变量(如 cnt: Counter),translate_value 会 load 返回 Struct 值, - # 但 dunder 方法需要 Ptr(Struct) 作为 self。直接用 alloca 指针尝试重载。 - if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node) - if nm is not None and nm.id is not None: - lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, nm.id) - if lhs_alloca is not None: - ovl_result: llvmlite.Value | t.CPtr = try_operator_overload( - pool, builder, mod, lhs_alloca, rhs, op, trans, 0) - if ovl_result is not None: - return ovl_result - - # 正常翻译 lhs - lhs: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, lhs_node, None, 0, trans) - if lhs is None: - return None - - # === 运算符重载路径 2: lhs 是 Ptr(Struct)(如 Counter|t.CPtr 变量 load 后)=== - ovl_result2: llvmlite.Value | t.CPtr = try_operator_overload( - pool, builder, mod, lhs, rhs, op, trans, 0) - if ovl_result2 is not None: - return ovl_result2 - - # 获取操作数类型信息 - lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty) - rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty) - lhs_fbits: int = HandlesExpr.get_llvm_float_bits(lhs.Ty) - rhs_fbits: int = HandlesExpr.get_llvm_float_bits(rhs.Ty) - - # 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查, - # 因为 float 的 int bits 为 0,会被误认为指针) - if lhs_fbits != 0 or rhs_fbits != 0: - # 确定目标浮点类型(使用较大的位宽) - target_fbits: int = lhs_fbits - if rhs_fbits > target_fbits: - target_fbits = rhs_fbits - target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - if target_fbits == 32: - target_float_ty = llvmlite.Float(pool) - # 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc) - lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty, node) - rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty, node) - if op == ast.OpKind.Add: - return llvmlite.build_fadd(builder, lhs, rhs) - if op == ast.OpKind.Sub: - return llvmlite.build_fsub(builder, lhs, rhs) - if op == ast.OpKind.Mult: - return llvmlite.build_fmul(builder, lhs, rhs) - if op == ast.OpKind.Div: - return llvmlite.build_fdiv(builder, lhs, rhs) - if op == ast.OpKind.Mod: - return llvmlite.build_frem(builder, lhs, rhs) - return None - - # 指针算术: ptr + int / ptr - int / int + ptr → getelementptr(按元素大小缩放) - # 对齐 TPC ExprGen.emit_binary_op L50-67;int - ptr 无 GEP 形式(C 语义非法) - if (lhs_bits == 0 and rhs_bits != 0) or (lhs_bits != 0 and rhs_bits == 0): - if op == ast.OpKind.Add: - if lhs_bits == 0: - return HandlesExpr.translate_ptr_arith(pool, builder, lhs, rhs, op) - # int + ptr(交换) - return HandlesExpr.translate_ptr_arith(pool, builder, rhs, lhs, op) - if op == ast.OpKind.Sub and lhs_bits == 0: - return HandlesExpr.translate_ptr_arith(pool, builder, lhs, rhs, op) - - if lhs_bits > rhs_bits: - if HandlesExpr.should_zext_widen(pool, rhs, lhs, rhs_node) != 0: - rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) - else: - rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty, node) - elif rhs_bits > lhs_bits: - if HandlesExpr.should_zext_widen(pool, lhs, rhs, lhs_node) != 0: - lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) - else: - lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty, node) - - # 位运算类型安全检查:两边都是指针(lhs_bits==0 and rhs_bits==0)时, - # 位运算(BitOr/BitAnd/BitXor/LShift/RShift)非法,LLVM 要求整数操作数。 - # 常见触发场景:CDefine 常量查找失败返回指针 null,与另一指针做 `|`。 - if lhs_bits == 0 and rhs_bits == 0: - if op == ast.OpKind.BitOr or op == ast.OpKind.BitAnd or op == ast.OpKind.BitXor or op == ast.OpKind.LShift or op == ast.OpKind.RShift: - VLogger.error( - "位运算操作数类型非法: lhs/rhs 均为非整数类型(指针或结构体),无法执行位运算", - "BinOp") - return None - - if op == ast.OpKind.Add: - return llvmlite.build_add(builder, lhs, rhs) - elif op == ast.OpKind.Sub: - return llvmlite.build_sub(builder, lhs, rhs) - elif op == ast.OpKind.Mult: - return llvmlite.build_mul(builder, lhs, rhs) - elif op == ast.OpKind.Div: - return llvmlite.build_sdiv(builder, lhs, rhs) - elif op == ast.OpKind.FloorDiv: - return llvmlite.build_sdiv(builder, lhs, rhs) - elif op == ast.OpKind.Mod: - return llvmlite.build_srem(builder, lhs, rhs) - elif op == ast.OpKind.BitAnd: - return llvmlite.build_and(builder, lhs, rhs) - elif op == ast.OpKind.BitOr: - return llvmlite.build_or(builder, lhs, rhs) - elif op == ast.OpKind.BitXor: - return llvmlite.build_xor(builder, lhs, rhs) - elif op == ast.OpKind.LShift: - return llvmlite.build_shl(builder, lhs, rhs) - elif op == ast.OpKind.RShift: - # 无符号 >> → lshr(逻辑右移),有符号 >> → ashr(算术右移) - # 对齐 TPC ExprGen.emit_binary_op:i8/i16 默认无符号;其余查操作数无符号性 - if lhs_bits == 8 or lhs_bits == 16: - return llvmlite.build_lshr(builder, lhs, rhs) - if HandlesExpr._node_type_unsigned(pool, lhs_node, trans) != 0: - return llvmlite.build_lshr(builder, lhs, rhs) - return llvmlite.build_ashr(builder, lhs, rhs) + """翻译二元运算(自动类型提升)(委托到 gen.translate_binop)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g.translate_binop(pool, builder, mod, node, trans) return None diff --git a/App/main.vp b/App/main.vp index b581a34..b107fb0 100644 --- a/App/main.vp +++ b/App/main.vp @@ -15,6 +15,8 @@ import lib import lib.core.VLogger as VLogger import lib.core.Handles.HandlesTranslator as HandlesTranslator import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesExpr as HandlesExpr +import lib.core.Handles.HandlesExprOps as HandlesExprOps import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.core.Handles.HandlesType as HandlesType import lib.core.BuildPipeline as BuildPipeline @@ -87,9 +89,12 @@ def main() -> int: gen.__before_init__() gen.__init__(mb) GenGenerator.set_global_gen(gen) - # P2: 注入 HandlesType/HandlesStruct 模块级单例(Phase1 阶段即调用其状态函数) + # P2/P3: 注入 HandlesType/HandlesStruct/HandlesExpr/HandlesExprOps 模块级单例 + # (Phase1 阶段即调用其状态函数) HandlesType.set_global_gen(gen) HandlesStruct.set_global_gen(gen) + HandlesExpr.set_global_gen(gen) + HandlesExprOps.set_global_gen(gen) # 初始化 VLogger 并打印启动日志 log: VLogger.Logger | t.CPtr = VLogger.get_logger()