2922 lines
141 KiB
Python
2922 lines
141 KiB
Python
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
|
||
|
||
|
||
# ============================================================
|
||
# HandlesExpr - 表达式处理(Mixin 继承模式)
|
||
#
|
||
# 工具函数保留为模块级(供外部调用),ExprHandle.HandleValue 提供 trans 接口
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 从 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
|
||
return None
|
||
|
||
|
||
# ============================================================
|
||
# 转义 LLVM IR 字符串字面量
|
||
# ============================================================
|
||
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
|
||
if hi < 10:
|
||
buf[pos] = '0' + hi
|
||
else:
|
||
buf[pos] = 'A' + (hi - 10)
|
||
pos += 1
|
||
if lo < 10:
|
||
buf[pos] = '0' + lo
|
||
else:
|
||
buf[pos] = 'A' + (lo - 10)
|
||
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(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(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
|
||
|
||
|
||
# ============================================================
|
||
# 检查类型是否为 Ptr(独立函数,避免嵌套 match 的编译器 BUG)
|
||
#
|
||
# 嵌套 match 的 REnum 检测在宿主编译器中有 BUG:当 match 嵌套在
|
||
# 另一个 match 的 case 块中时,内层 match 走非 REnum 路径,
|
||
# 导致 case 列表为空。提取为独立函数可规避此问题。
|
||
# ============================================================
|
||
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
|
||
|
||
|
||
# ============================================================
|
||
# 检查类型是否为 Array(独立函数,避免嵌套 match 的编译器 BUG)
|
||
# ============================================================
|
||
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
|
||
|
||
|
||
# ============================================================
|
||
# _get_custom_struct_cls_nm - 检查类型是否为已注册的自定义结构体
|
||
#
|
||
# 处理两种情况:
|
||
# - 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)
|
||
return None
|
||
|
||
|
||
# ============================================================
|
||
# _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 解引用
|
||
#
|
||
# 用 is_ptr_type 避免嵌套 match 的编译器 BUG
|
||
# ============================================================
|
||
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
|
||
|
||
|
||
# ============================================================
|
||
# 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si
|
||
# ============================================================
|
||
def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr,
|
||
val: llvmlite.Value | t.CPtr,
|
||
target_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""将 val 强制转换为 target_ty
|
||
|
||
整数: sext(扩展)/ trunc(截断)
|
||
浮点: fpext(扩展)/ fptrunc(截断)
|
||
int→float: sitofp
|
||
float→int: fptosi
|
||
"""
|
||
if val is None or target_ty is None:
|
||
return val
|
||
# 整数转换
|
||
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(当目标明确是整数而非指针时)
|
||
if is_ptr_type(val.Ty) != 0 and target_bits != 0 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:
|
||
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)
|
||
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
|
||
# 注意:使用独立函数 is_ptr_type 检查,避免嵌套 match 的编译器 BUG
|
||
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
|
||
|
||
|
||
# ============================================================
|
||
# 创建全局字符串常量
|
||
# ============================================================
|
||
def create_global_string(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 = escape_llvm_string(pool, str_val)
|
||
if escaped is None:
|
||
stdio.printf("[CGS] escape_llvm_string None\n")
|
||
stdio.fflush(0)
|
||
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:
|
||
stdio.printf("[CGS] gv_name alloc None\n")
|
||
stdio.fflush(0)
|
||
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:
|
||
stdio.printf("[CGS] new_global_variable None name=%s\n", gv_name)
|
||
stdio.fflush(0)
|
||
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)
|
||
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:
|
||
stdio.printf("[CGS] gv_ref_name alloc None\n")
|
||
stdio.fflush(0)
|
||
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)
|
||
if bc is None:
|
||
stdio.printf("[CGS] build_bitcast None\n")
|
||
stdio.fflush(0)
|
||
return bc
|
||
|
||
|
||
# ============================================================
|
||
# 翻译常量表达式
|
||
# ============================================================
|
||
def translate_constant(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:
|
||
stdio.printf("[TC] cn is None\n")
|
||
stdio.fflush(0)
|
||
return None
|
||
ck: int = cn.const_kind
|
||
stdio.printf("[TC] const_kind=%d\n", ck)
|
||
stdio.fflush(0)
|
||
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_STR:
|
||
sv: str = cn.str_val
|
||
if sv is None:
|
||
stdio.printf("[TC] CONST_STR but str_val is None\n")
|
||
stdio.fflush(0)
|
||
return None
|
||
stdio.printf("[TC] CONST_STR sv[0]=%d\n", sv[0])
|
||
stdio.fflush(0)
|
||
r: llvmlite.Value | t.CPtr = create_global_string(builder, pool, mod, sv, trans)
|
||
if r is None:
|
||
stdio.printf("[TC] create_global_string returned None\n")
|
||
stdio.fflush(0)
|
||
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` 比较
|
||
stdio.printf("[TC] NONE step1 Int8\n")
|
||
stdio.fflush(0)
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
if i8_ty is None:
|
||
stdio.printf("[TC] NONE Int8 alloc None\n")
|
||
stdio.fflush(0)
|
||
return None
|
||
stdio.printf("[TC] NONE step2 Ptr\n")
|
||
stdio.fflush(0)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
if i8_ptr_ty is None:
|
||
stdio.printf("[TC] NONE Ptr alloc None\n")
|
||
stdio.fflush(0)
|
||
return None
|
||
stdio.printf("[TC] NONE step3 ConstNull\n")
|
||
stdio.fflush(0)
|
||
rv_none: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
|
||
if rv_none is None:
|
||
stdio.printf("[TC] NONE ConstNull None\n")
|
||
stdio.fflush(0)
|
||
else:
|
||
stdio.printf("[TC] NONE ok\n")
|
||
stdio.fflush(0)
|
||
return rv_none
|
||
stdio.printf("[TC] unknown const_kind=%d\n", ck)
|
||
stdio.fflush(0)
|
||
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"
|
||
|
||
|
||
# ============================================================
|
||
# _find_pool_var — 查找上下文中的 pool 变量
|
||
#
|
||
# 依次尝试 "pool", "_mbuddy", "mbuddy", "mb"
|
||
# ============================================================
|
||
def _find_pool_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""查找上下文中的 pool 变量,返回 alloca 或 None"""
|
||
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
|
||
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,
|
||
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 = 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] 类
|
||
type_args: list[str] | t.CPtr = list[str](pool, 4)
|
||
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
|
||
|
||
|
||
# ============================================================
|
||
# 翻译值表达式(RHS 分派)— 模块级版本
|
||
# ============================================================
|
||
def translate_value(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 = translate_constant(builder, pool, mod, node, trans)
|
||
if rv is None:
|
||
stdio.printf("[TV] Constant returned None\n")
|
||
stdio.fflush(0)
|
||
else:
|
||
stdio.printf("[TV] Constant ok\n")
|
||
stdio.fflush(0)
|
||
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)
|
||
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:
|
||
stdio.printf("[IFEXP] func=None\n")
|
||
stdio.fflush(0)
|
||
return None
|
||
|
||
# 1. 求值条件
|
||
cond_val: llvmlite.Value | t.CPtr = translate_value(
|
||
builder, pool, mod, ie.test, None, 0, trans)
|
||
if cond_val is None:
|
||
stdio.printf("[IFEXP] cond_val=None\n")
|
||
stdio.fflush(0)
|
||
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:
|
||
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)
|
||
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)
|
||
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)
|
||
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)
|
||
|
||
# 现在分别在 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 translate_compare(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:
|
||
stdio.printf("[CMP] comparators empty\n")
|
||
stdio.fflush(0)
|
||
return None
|
||
rhs: llvmlite.Value | t.CPtr = translate_value(
|
||
builder, pool, mod, comparators.get(0), None, 0, trans)
|
||
if rhs is None:
|
||
stdio.printf("[CMP] rhs=None\n")
|
||
stdio.fflush(0)
|
||
return None
|
||
|
||
# === 比较运算符重载路径 1: lhs 是 Name 且对应结构体变量 ===
|
||
# 对于值类型变量(如 cnt: Counter),用 alloca 指针尝试重载
|
||
lhs_node: ast.AST | t.CPtr = cmp.left
|
||
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 = 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:
|
||
stdio.printf("[CMP] lhs=None\n")
|
||
stdio.fflush(0)
|
||
return None
|
||
|
||
# === 比较运算符重载路径 2: lhs 是 Ptr(Struct) ===
|
||
# Is/IsNot 不在 _cmpop_to_dunder 映射中,会自动返回 None 回退原生比较
|
||
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
|
||
|
||
# 隐式类型转换:当一侧是指针(i8*),另一侧是整数时,
|
||
# 从指针加载第一个字节,使两侧类型一致
|
||
lhs_is_ptr: int = is_ptr_type(lhs.Ty)
|
||
rhs_is_ptr: int = is_ptr_type(rhs.Ty)
|
||
if lhs_is_ptr != 0 and rhs_is_ptr == 0:
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
lhs = llvmlite.build_load(builder, i8_ty, lhs)
|
||
elif rhs_is_ptr != 0 and lhs_is_ptr == 0:
|
||
i8_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
rhs = llvmlite.build_load(builder, i8_ty2, rhs)
|
||
|
||
# 类型对齐:icmp 要求两边类型相同,将较窄的整数 sext 到较宽的类型
|
||
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:
|
||
lhs = llvmlite.build_sext(builder, lhs, rhs.Ty)
|
||
else:
|
||
rhs = llvmlite.build_sext(builder, rhs, lhs.Ty)
|
||
|
||
return llvmlite.build_icmp(builder, predicate, lhs, rhs)
|
||
|
||
|
||
# ============================================================
|
||
# 翻译一元运算表达式 UnaryOp(op, operand)
|
||
# ============================================================
|
||
def translate_unaryop(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 = translate_value(
|
||
builder, pool, mod, uo.operand, None, 0, trans)
|
||
if operand is None:
|
||
return None
|
||
|
||
if uo.op == ast.OpKind.USub:
|
||
# -x = 0 - x
|
||
# 根据 operand 类型选择零值常量(避免 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),返回 i1
|
||
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
|
||
|
||
|
||
# ============================================================
|
||
# 翻译布尔运算 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,
|
||
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 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 比较)
|
||
val_bits: int = get_llvm_type_bits(val.Ty)
|
||
val_i1: llvmlite.Value | t.CPtr = val
|
||
if val_bits != 1:
|
||
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:
|
||
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 从存储器构建源 .py 文件路径
|
||
#
|
||
# .pyi 文件可能未生成(Phase1 未输出 pyi),此时回退读取源 .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
|
||
|
||
|
||
# ============================================================
|
||
# _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) -> int:
|
||
"""跨模块查找 CDefine 常量,返回值或 -1(未找到)"""
|
||
# [XMOD-CD] 诊断:记录跨模块 CDefine 查找入口
|
||
_xmod_log_buf: str = pool.alloc(512)
|
||
if _xmod_log_buf is not None:
|
||
viperlib.snprintf(_xmod_log_buf, 512, "[XMOD-CD] enter name=%s from_imports=%s\n", name, from_imports)
|
||
_xmod_lf: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf.closed:
|
||
_xmod_lf.write_str(_xmod_log_buf)
|
||
_xmod_lf.close()
|
||
|
||
if name is None or from_imports is None:
|
||
return -1
|
||
|
||
# 1. 从 from_imports 查找名称对应的模块名
|
||
# allow_star_fallback=1: CDefine 常量(如 INVALID_HANDLE_VALUE)通过
|
||
# from w32.win32base import * 导入,不会作为精确条目出现在 from_imports 中,
|
||
# 而是作为 *:w32.win32base 条目。必须启用 star import 回退才能找到源模块。
|
||
mod_name_raw: str = HandlesImports.lookup_from_import(from_imports, name, 1)
|
||
if mod_name_raw is None:
|
||
if _xmod_log_buf is not None:
|
||
viperlib.snprintf(_xmod_log_buf, 512, "[XMOD-CD] FAIL step1 mod=None name=%s\n", name)
|
||
_xmod_lf2: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf2.closed:
|
||
_xmod_lf2.write_str(_xmod_log_buf)
|
||
_xmod_lf2.close()
|
||
return -1
|
||
|
||
# 2. 复制模块名到新缓冲区(lookup_from_import 返回的是内部指针)
|
||
# 截断于空格、null、或 ':'(别名格式的分隔符)
|
||
mod_len: t.CSizeT = 0
|
||
while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0' and mod_name_raw[mod_len] != ':':
|
||
mod_len += 1
|
||
mod_name_buf: str = pool.alloc(mod_len + 1)
|
||
if mod_name_buf is None:
|
||
return -1
|
||
for mi in range(mod_len):
|
||
mod_name_buf[mi] = mod_name_raw[mi]
|
||
mod_name_buf[mod_len] = '\0'
|
||
|
||
# 3. 去掉相对导入的前导点
|
||
base_mod: str = mod_name_buf
|
||
while base_mod[0] == '.':
|
||
base_mod = base_mod + 1
|
||
|
||
# 4. 查找模块的 SHA1
|
||
sha1: str = HandlesExprCall._lookup_module_sha1(base_mod)
|
||
if sha1 is None:
|
||
sha1 = HandlesExprCall._lookup_module_sha1_suffix(base_mod)
|
||
if sha1 is None:
|
||
if _xmod_log_buf is not None:
|
||
viperlib.snprintf(_xmod_log_buf, 512, "[XMOD-CD] FAIL step4 sha1=None base_mod=%s\n", base_mod)
|
||
_xmod_lf3: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf3.closed:
|
||
_xmod_lf3.write_str(_xmod_log_buf)
|
||
_xmod_lf3.close()
|
||
return -1
|
||
|
||
# [XMOD-CD] 诊断:记录 SHA1 查找成功
|
||
if _xmod_log_buf is not None:
|
||
viperlib.snprintf(_xmod_log_buf, 512, "[XMOD-CD] ok step4 base_mod=%s sha1=%s\n", base_mod, sha1)
|
||
_xmod_lf4: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf4.closed:
|
||
_xmod_lf4.write_str(_xmod_log_buf)
|
||
_xmod_lf4.close()
|
||
|
||
# 4.5 优先查全局跨模块 CDefine 表(编译期注册,无需文件 I/O)
|
||
gcdef_val: int = HandlesType.lookup_global_cdefine(sha1, name)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
return gcdef_val
|
||
|
||
# 5. 获取 temp_dir
|
||
temp_dir: str = HandlesType.get_temp_dir()
|
||
if temp_dir is None:
|
||
return -1
|
||
|
||
# 6. 构建 pyi 文件路径
|
||
td_len: t.CSizeT = string.strlen(temp_dir)
|
||
pyi_path: str = StubMerger._sliced_path(temp_dir, td_len, sha1, "pyi")
|
||
if pyi_path is None:
|
||
return -1
|
||
|
||
# 7. 读取 pyi 文件;若不存在或内容过短(空 stub)则回退读取源 .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:
|
||
# .pyi 文件不存在:回退读取源 .py 文件
|
||
need_py_fallback = 1
|
||
else:
|
||
bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE)
|
||
pf.close()
|
||
# pyi 内容过短(< 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
|
||
# [XMOD-CD] 诊断:记录 src_path
|
||
_xmod_dbg_sp2: str = pool.alloc(512)
|
||
if _xmod_dbg_sp2 is not None:
|
||
viperlib.snprintf(_xmod_dbg_sp2, 512,
|
||
"[XMOD-CD] py-fallback src_path=%s sha1=%s\n", src_path, sha1)
|
||
_xmod_lf_sp2: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf_sp2.closed:
|
||
_xmod_lf_sp2.write_str(_xmod_dbg_sp2)
|
||
_xmod_lf_sp2.close()
|
||
pf = fileio.File(src_path, fileio.MODE.R)
|
||
stdlib.free(src_path)
|
||
if pf.closed:
|
||
# [XMOD-CD] 诊断:文件打开失败
|
||
_xmod_dbg_fc: str = pool.alloc(512)
|
||
if _xmod_dbg_fc is not None:
|
||
viperlib.snprintf(_xmod_dbg_fc, 512,
|
||
"[XMOD-CD] FAIL file-closed sha1=%s\n", sha1)
|
||
_xmod_lf_fc: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf_fc.closed:
|
||
_xmod_lf_fc.write_str(_xmod_dbg_fc)
|
||
_xmod_lf_fc.close()
|
||
stdlib.free(pyi_buf)
|
||
return -1
|
||
bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE)
|
||
pf.close()
|
||
if bytes_read <= 0:
|
||
# [XMOD-CD] 诊断:文件读取失败
|
||
_xmod_dbg_br: str = pool.alloc(512)
|
||
if _xmod_dbg_br is not None:
|
||
viperlib.snprintf(_xmod_dbg_br, 512,
|
||
"[XMOD-CD] FAIL bytes_read=%d sha1=%s\n", bytes_read, sha1)
|
||
_xmod_lf_br: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf_br.closed:
|
||
_xmod_lf_br.write_str(_xmod_dbg_br)
|
||
_xmod_lf_br.close()
|
||
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)
|
||
# [XMOD-CD] 诊断:记录文件读取结果和 total_len
|
||
_xmod_dbg1: str = pool.alloc(512)
|
||
if _xmod_dbg1 is not None:
|
||
_dbg_first80: str = pool.alloc(81)
|
||
if _dbg_first80 is not None:
|
||
_dbg_n: int = 0
|
||
while _dbg_n < 80 and _dbg_n < total_len:
|
||
_dbg_first80[_dbg_n] = pyi_buf[_dbg_n]
|
||
_dbg_n += 1
|
||
_dbg_first80[_dbg_n] = '\0'
|
||
else:
|
||
_dbg_first80 = "<alloc-fail>"
|
||
viperlib.snprintf(_xmod_dbg1, 512, "[XMOD-CD] file-read name=%s bytes_read=%d total_len=%d first80=%.80s\n",
|
||
name, bytes_read, total_len, _dbg_first80)
|
||
_xmod_lf_d1: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf_d1.closed:
|
||
_xmod_lf_d1.write_str(_xmod_dbg1)
|
||
_xmod_lf_d1.close()
|
||
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
|
||
|
||
# 解析整数值(支持十六进制 0x 前缀)
|
||
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
|
||
result_found = 1
|
||
else:
|
||
result_val = string.atoi(val_buf)
|
||
result_found = 1
|
||
break
|
||
|
||
# 9.5 如果当前模块文件中没找到,递归查找子模块
|
||
# 处理 from .X import NAME 和 from .X import * 的情况
|
||
# 例如 ast.__init__.py 中 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
|
||
|
||
# [XMOD-CD] 诊断:记录找到的 from . 行和子模块名
|
||
_xmod_dbg_rc: str = pool.alloc(512)
|
||
if _xmod_dbg_rc is not None:
|
||
_rc_sub_buf_dbg: str = pool.alloc(rc_sub_len + 1)
|
||
if _rc_sub_buf_dbg is not None:
|
||
_rc_si2: t.CSizeT
|
||
for _rc_si2 in range(rc_sub_len):
|
||
_rc_sub_buf_dbg[_rc_si2] = pyi_buf[rc_sub_start + _rc_si2]
|
||
_rc_sub_buf_dbg[rc_sub_len] = '\0'
|
||
else:
|
||
_rc_sub_buf_dbg = "<alloc-fail>"
|
||
viperlib.snprintf(_xmod_dbg_rc, 512,
|
||
"[XMOD-CD] rc-from-line name=%s sub=%s rc_line_start=%d rc_line_len=%d\n",
|
||
name, _rc_sub_buf_dbg, rc_line_start, rc_line_len)
|
||
_xmod_lf_rc: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf_rc.closed:
|
||
_xmod_lf_rc.write_str(_xmod_dbg_rc)
|
||
_xmod_lf_rc.close()
|
||
|
||
# 检查行是否包含 "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
|
||
|
||
# [XMOD-CD] 诊断:记录 NAME 匹配结果
|
||
_xmod_dbg_match: str = pool.alloc(512)
|
||
if _xmod_dbg_match is not None:
|
||
viperlib.snprintf(_xmod_dbg_match, 512,
|
||
"[XMOD-CD] rc-match name=%s star=%d name_match=%d has_paren=%d rc_scan_end=%d rc_imp_start=%d\n",
|
||
name, rc_star, rc_name_match, rc_has_paren, rc_scan_end, rc_imp_start)
|
||
_xmod_lf_m: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf_m.closed:
|
||
_xmod_lf_m.write_str(_xmod_dbg_match)
|
||
_xmod_lf_m.close()
|
||
|
||
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)
|
||
|
||
# [XMOD-CD] 诊断:记录递归调用前的状态
|
||
_xmod_dbg_recurse: str = pool.alloc(512)
|
||
if _xmod_dbg_recurse is not None:
|
||
viperlib.snprintf(_xmod_dbg_recurse, 512,
|
||
"[XMOD-CD] rc-recurse name=%s full_mod=%s fi=%s star=%d name_match=%d has_paren=%d scan_end=%d\n",
|
||
name, rc_full_mod, rc_fi, rc_star, rc_name_match, rc_has_paren, rc_scan_end)
|
||
_xmod_lf_rec: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf_rec.closed:
|
||
_xmod_lf_rec.write_str(_xmod_dbg_recurse)
|
||
_xmod_lf_rec.close()
|
||
|
||
# 递归调用查找子模块
|
||
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)
|
||
|
||
# 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)
|
||
|
||
# [XMOD-CD] 诊断:记录查找结果
|
||
if _xmod_log_buf is not None:
|
||
if result_found != 0:
|
||
viperlib.snprintf(_xmod_log_buf, 512, "[XMOD-CD] FOUND name=%s val=%d base_mod=%s\n", name, result_val, base_mod)
|
||
else:
|
||
viperlib.snprintf(_xmod_log_buf, 512, "[XMOD-CD] NOTFOUND name=%s base_mod=%s sha1=%s\n", name, base_mod, sha1)
|
||
_xmod_lf5: fileio.File | t.CPtr = fileio.File(
|
||
"d:/Users/TermiNexus/Desktop/TransPyC/_xmod_cdefine.log", fileio.MODE.A)
|
||
if not _xmod_lf5.closed:
|
||
_xmod_lf5.write_str(_xmod_log_buf)
|
||
_xmod_lf5.close()
|
||
|
||
return result_val
|
||
|
||
|
||
# ============================================================
|
||
# 翻译变量引用(Name 节点)→ load
|
||
# ============================================================
|
||
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 编译期常量: 直接返回整数常量值(不生成运行时代码)
|
||
# NAME: t.CDefine = value 形式定义的常量在编译期已注册到全局表
|
||
cdef_val: int = HandlesType.lookup_cdefine_constant(nm_id)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
return llvmlite.const_int32(pool, cdef_val)
|
||
|
||
# 本地 CDefine 表未找到:尝试跨模块查找
|
||
# 对于 from w32.win32base import * 导入的 INVALID_HANDLE_VALUE 等常量,
|
||
# CDefine 表在模块切换时被清空,需要从 from_imports 查找来源模块并读取 .pyi
|
||
if trans is not None:
|
||
if trans._from_imports is not None:
|
||
cdef_val = _lookup_cross_module_cdefine(pool, nm_id, trans._from_imports)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
return llvmlite.const_int32(pool, cdef_val)
|
||
|
||
# 模块别名检查:如果 nm_id 是已导入模块名(如 win32file, fileio),
|
||
# 不应被当作普通变量或全局变量,返回 None 让上层处理
|
||
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
|
||
|
||
# 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)
|
||
|
||
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm_id)
|
||
if alloca is None:
|
||
# 跨模块 CDefine 查找(仅当 Name 不是任何变量时才尝试):
|
||
# 从 from_imports 解析源模块,再从该模块的 pyi 文件中解析 CDefine 常量值
|
||
# (如 FLAG_IS_ASYNC 从 base.py 导入)
|
||
if trans is not None and trans._from_imports is not None:
|
||
cross_val: int = _lookup_cross_module_cdefine(pool, nm_id, trans._from_imports)
|
||
if cross_val >= 0:
|
||
return llvmlite.const_int32(pool, cross_val)
|
||
return 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)
|
||
return llvmlite.build_load(builder, load_ty, alloca)
|
||
|
||
|
||
# ============================================================
|
||
# ExprHandle - 表达式处理器(Mixin 继承模式)
|
||
#
|
||
# HandleValue 提供 trans 接口,委托到模块级 translate_value
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class ExprHandle(HandlesBase.Mixin):
|
||
"""表达式处理器:继承 Mixin 获得 Trans 回指针"""
|
||
|
||
def __init__(self, trans: HT.Translator | t.CPtr):
|
||
self.Trans = trans
|
||
|
||
# ============================================================
|
||
# HandleValue - 翻译值表达式为 LLVM Value
|
||
# ============================================================
|
||
def HandleValue(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""翻译值表达式,从 self.Trans 获取共享状态"""
|
||
return translate_value(
|
||
self.Trans._cur_builder, self.Trans.Pool, self.Trans.Module,
|
||
node,
|
||
self.Trans._funcs, self.Trans._func_count, self.Trans)
|
||
|
||
|
||
# ============================================================
|
||
# NewExprHandle - 工厂函数
|
||
# ============================================================
|
||
def NewExprHandle(pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> ExprHandle | t.CPtr:
|
||
h: ExprHandle | t.CPtr = pool.alloc(ExprHandle.__sizeof__())
|
||
if h is None:
|
||
return None
|
||
string.memset(h, 0, ExprHandle.__sizeof__())
|
||
h.Trans = trans
|
||
return h
|
||
|
||
|
||
# ============================================================
|
||
# 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(builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
lm_obj: llvmlite.Value | t.CPtr,
|
||
idx_val: llvmlite.Value | t.CPtr) -> 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)
|
||
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 类型
|
||
#
|
||
# 类型名格式: <sha1>.list[<elem_type>]
|
||
# 用 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_setitem_inline — 内联生成 list[T] __setitem__ 逻辑
|
||
#
|
||
# 直接存储 rhs_val 到元素地址 (coerce 为 i8* 后 store)
|
||
# ============================================================
|
||
def list_setitem_inline(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) -> 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)
|
||
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)
|
||
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(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(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 None:
|
||
stdio.printf("[TS] alloca=None var=%s\n", nm.id)
|
||
stdio.fflush(0)
|
||
elif alloca.Ty is None:
|
||
stdio.printf("[TS] alloca.Ty=None var=%s\n", nm.id)
|
||
stdio.fflush(0)
|
||
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 None:
|
||
stdio.printf("[TS] pointee=None var=%s\n", nm.id)
|
||
stdio.fflush(0)
|
||
if pointee is not None:
|
||
# 不调用 pointee.kind() 避免跨模块引用 LLVMType.kind 符号
|
||
stdio.printf("[TS] var=%s pointee_not_null\n", nm.id)
|
||
stdio.fflush(0)
|
||
# 单层 match(避免嵌套 match 的编译器 bug)
|
||
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, 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):
|
||
stdio.printf("[TS] matched Ptr var=%s\n", nm.id)
|
||
stdio.fflush(0)
|
||
# 检查 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)
|
||
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__,避免 IsPtrElement 误判为指针遍历
|
||
cls_nm_rd_ptr: str = _get_custom_struct_cls_nm(pool, inner_ty)
|
||
if cls_nm_rd_ptr is None:
|
||
stdio.printf("[TS] cls_nm=None var=%s\n", nm.id)
|
||
stdio.fflush(0)
|
||
if not (cls_nm_rd_ptr is None):
|
||
stdio.printf("[TS] cls_nm=%s var=%s\n", cls_nm_rd_ptr, nm.id)
|
||
stdio.fflush(0)
|
||
stdio.printf("[TS] pre_getitem cls=%s\n", cls_nm_rd_ptr)
|
||
stdio.fflush(0)
|
||
obj_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if obj_ptr_rd is None:
|
||
stdio.printf("[TS] __getitem__ build_load=None\n")
|
||
stdio.fflush(0)
|
||
if not (obj_ptr_rd is None):
|
||
arg_vals_rd_p: t.CSizeT | t.CPtr = pool.alloc(8)
|
||
if arg_vals_rd_p is None:
|
||
stdio.printf("[TS] __getitem__ alloc=None\n")
|
||
stdio.fflush(0)
|
||
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)
|
||
if ret_rd_p is None:
|
||
stdio.printf("[TS] __getitem__ call=None cls=%s\n", cls_nm_rd_ptr)
|
||
stdio.fflush(0)
|
||
if not (ret_rd_p is None):
|
||
return ret_rd_p
|
||
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__ 方法调用
|
||
# 如 hashtable[key] → hashtable.__getitem__(key)
|
||
cls_nm_sub: str = HandlesStruct.get_class_name_by_type(pool, pointee)
|
||
if cls_nm_sub is None:
|
||
pass
|
||
if not (cls_nm_sub is 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)
|
||
if not (ret_sub is None):
|
||
return ret_sub
|
||
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, 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__ 方法调用
|
||
cls_nm_rd_gen: str = _get_custom_struct_cls_nm(pool, elem_ty2)
|
||
if cls_nm_rd_gen is None:
|
||
pass
|
||
if not (cls_nm_rd_gen is 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)
|
||
if not (ret_rd_g is None):
|
||
return ret_rd_g
|
||
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(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(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 _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)
|
||
ext_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, at.attr, use_ty)
|
||
if ext_gv is not None:
|
||
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 结构体)
|
||
# ============================================================
|
||
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:
|
||
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)
|
||
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)
|
||
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 常量需要跨模块查找源 .py / .pyi 文件
|
||
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 # 是子模块,交给嵌套属性访问路径
|
||
# 非 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 等嵌套模块属性访问,
|
||
# 先从限定模块的 .pyi 文件中查找 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 未找到: 创建前向引用 (CDefine 通常是 i32)
|
||
i32_ty_fwd: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
gv_ref_fwd: llvmlite.Value | t.CPtr = make_global_ref(
|
||
pool, at.attr, i32_ty_fwd)
|
||
if gv_ref_fwd is not None and gv_ref_fwd.Ty is not None:
|
||
load_ty_fwd: llvmlite.LLVMType | t.CPtr = gv_ref_fwd.Ty.Pointee
|
||
if load_ty_fwd is not None:
|
||
return llvmlite.build_load(builder, load_ty_fwd, gv_ref_fwd)
|
||
|
||
# 对于 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:
|
||
obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans)
|
||
|
||
if obj_ptr is None or obj_ptr.Ty is None:
|
||
if at.value.kind() == ast.ASTKind.Name:
|
||
nm_d: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if nm_d.id is not None:
|
||
stdio.printf("[TA-DIAG] obj_ptr=None attr=%s name=%s\n",
|
||
at.attr, nm_d.id)
|
||
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)
|
||
# 回退: 类型指针比较失败时,通过 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:
|
||
stdio.printf("[TA-DIAG] fallback annot=%s attr=%s\n",
|
||
var_entry.AnnotClassName, at.attr)
|
||
cur_sha1: str = trans.ModuleSha1
|
||
field_info = HandlesStruct.lookup_field_by_class(
|
||
var_entry.AnnotClassName, at.attr, cur_sha1)
|
||
if field_info is None:
|
||
stdio.printf("[TA-DIAG] lfbc_failed annot=%s attr=%s\n",
|
||
var_entry.AnnotClassName, at.attr)
|
||
stdio.fflush(0)
|
||
else:
|
||
stdio.printf("[TA-DIAG] lfbc_ok annot=%s attr=%s idx=%d\n",
|
||
var_entry.AnnotClassName, at.attr, field_info.Index)
|
||
stdio.fflush(0)
|
||
# 回退 1 成功: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 None:
|
||
stdio.printf("[TA-DIAG] fb1 find_struct None annot=%s\n",
|
||
var_entry.AnnotClassName)
|
||
stdio.fflush(0)
|
||
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
|
||
# 回退 1 更新 struct_ty 后,需重新确保
|
||
# 注解类型结构体定义在当前模块可用
|
||
# (原始 struct_ty 可能是 i8,ensure 无效)
|
||
HandlesStruct.ensure_struct_def_in_module(
|
||
pool, mod, annot_se.Ty)
|
||
stdio.printf("[TA-DIAG] fb1 struct_ty updated\n")
|
||
stdio.fflush(0)
|
||
else:
|
||
stdio.printf("[TA-DIAG] fb1 bitcast None\n")
|
||
stdio.fflush(0)
|
||
# 回退 2: 子类搜索 — 注解类型是基类但实际值是派生类
|
||
# 如 node: AST | t.CPtr = If(...),访问 node.orelse
|
||
if field_info is None:
|
||
sub_entry: HandlesStruct.StructEntry | t.CPtr = \
|
||
HandlesStruct.find_subclass_with_field(
|
||
var_entry.AnnotClassName, at.attr)
|
||
if sub_entry is not None and sub_entry.Ty is not None:
|
||
sub_field: HandlesStruct.FieldEntry | t.CPtr = \
|
||
HandlesStruct.lookup_field(sub_entry.Ty, at.attr)
|
||
if sub_field is not None:
|
||
sub_ptr_ty: llvmlite.LLVMType | t.CPtr = \
|
||
llvmlite.Ptr(pool, sub_entry.Ty)
|
||
casted_ptr: llvmlite.Value | t.CPtr = \
|
||
llvmlite.build_bitcast(builder, obj_ptr, sub_ptr_ty)
|
||
if casted_ptr is not None:
|
||
sub_field_ptr: llvmlite.Value | t.CPtr = \
|
||
llvmlite.build_gep_struct(
|
||
builder, sub_entry.Ty, sub_field.Ty,
|
||
casted_ptr, sub_field.Index)
|
||
if sub_field_ptr is not None:
|
||
return llvmlite.build_load(
|
||
builder, sub_field.Ty, sub_field_ptr)
|
||
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
|
||
stdio.printf("[TA-DIAG] gep_try idx=%d struct_is_ptr=%d\n",
|
||
field_idx, is_ptr_type(struct_ty))
|
||
stdio.fflush(0)
|
||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, struct_ty, field_ty, obj_ptr, field_idx)
|
||
if field_ptr is None:
|
||
stdio.printf("[TA-DIAG] gep_failed idx=%d\n", field_idx)
|
||
stdio.fflush(0)
|
||
if field_ptr is not None:
|
||
stdio.printf("[TA-DIAG] gep_ok idx=%d is_array=%d\n",
|
||
field_idx, is_array_type(field_ty))
|
||
stdio.fflush(0)
|
||
# 数组类型字段不能 load 为 SSA value,直接返回字段指针
|
||
# 用于后续下标访问: self.state[0] → GEP state 字段 → GEP 数组元素
|
||
if is_array_type(field_ty) != 0:
|
||
return field_ptr
|
||
stdio.printf("[TA-DIAG] pre_load idx=%d field_ty_not_null=%d\n",
|
||
field_idx, 1 if field_ty is not None else 0)
|
||
stdio.fflush(0)
|
||
loaded_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, field_ty, field_ptr)
|
||
stdio.printf("[TA-DIAG] post_load idx=%d loaded=%d\n",
|
||
field_idx, 1 if loaded_val is not None else 0)
|
||
stdio.fflush(0)
|
||
# 联合类型字段(如 Token | t.CPtr)被编译为 i8*,
|
||
# 若 AnnotClassName 指示了具体结构体类型,bitcast 为正确的结构体指针
|
||
if loaded_val is not None and field_info.AnnotClassName is not None:
|
||
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
|
||
# 诊断:所有字段查找路径失败
|
||
sn_diag: str = HandlesStruct._extract_struct_name(struct_ty)
|
||
if sn_diag is not None:
|
||
stdio.printf("[TA-DIAG] field=None attr=%s sname=%s\n",
|
||
at.attr, sn_diag)
|
||
else:
|
||
stdio.printf("[TA-DIAG] field=None attr=%s sname=(null)\n",
|
||
at.attr)
|
||
return None
|
||
case _:
|
||
stdio.printf("[TA-DIAG] type_mismatch attr=%s\n", at.attr)
|
||
return None
|
||
|
||
# ============================================================
|
||
# 获取下标表达式的元素指针(不加载值,用于赋值)
|
||
# ============================================================
|
||
def get_subscript_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
|
||
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 None:
|
||
stdio.printf("[GSP] alloca=None var=%s\n", nm.id)
|
||
stdio.fflush(0)
|
||
elif alloca.Ty is None:
|
||
stdio.printf("[GSP] alloca.Ty=None var=%s\n", nm.id)
|
||
stdio.fflush(0)
|
||
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 None:
|
||
stdio.printf("[GSP] pointee=None var=%s\n", nm.id)
|
||
stdio.fflush(0)
|
||
if pointee is not None:
|
||
pe_arr: int = is_array_type(pointee)
|
||
pe_ptr: int = is_ptr_type(pointee)
|
||
stdio.printf("[GSP] var=%s pe_arr=%d pe_ptr=%d\n", nm.id, pe_arr, pe_ptr)
|
||
stdio.fflush(0)
|
||
# 单层 match(避免嵌套 match 的编译器 bug)
|
||
match pointee:
|
||
case llvmlite.LLVMType.Array(elem_ty, count):
|
||
stdio.printf("[GSP] matched Array\n")
|
||
stdio.fflush(0)
|
||
# 数组遍历
|
||
return llvmlite.build_gep_array(
|
||
builder, pointee, elem_ty, alloca, idx_val)
|
||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||
stdio.printf("[GSP] matched Ptr\n")
|
||
stdio.fflush(0)
|
||
# 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):
|
||
# 优先返回 None 触发 __setitem__ 重载,
|
||
# 避免 IsPtrElement 误判为指针遍历
|
||
cls_nm_ptr_chk: str = _get_custom_struct_cls_nm(pool, inner_ty)
|
||
if cls_nm_ptr_chk is None:
|
||
pass
|
||
if not (cls_nm_ptr_chk is None):
|
||
stdio.printf("[GSP] custom struct %s, defer to __setitem__\n",
|
||
cls_nm_ptr_chk)
|
||
stdio.fflush(0)
|
||
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:
|
||
stdio.printf("[GSP] IsPtrElement=1, gep direct\n")
|
||
stdio.fflush(0)
|
||
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:
|
||
stdio.printf("[GSP] build_load=None\n")
|
||
stdio.fflush(0)
|
||
return None
|
||
gep_r: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, inner_ty, ptr_val, idx_val)
|
||
if gep_r is None:
|
||
stdio.printf("[GSP] build_gep=None\n")
|
||
stdio.fflush(0)
|
||
return gep_r
|
||
case _:
|
||
# pointee 是普通标量类型 (如 i64, i32, i8):
|
||
# alloca 是 Ptr(标量), 直接 GEP 获取第 idx 个元素指针
|
||
# 支持 arg_vals[i] = val 这类参数数组下标赋值
|
||
stdio.printf("[GSP] matched scalar, gep direct\n")
|
||
stdio.fflush(0)
|
||
return llvmlite.build_gep(builder, pointee, alloca, idx_val)
|
||
|
||
# 通用路径
|
||
stdio.printf("[GSP] fallback to generic path\n")
|
||
stdio.fflush(0)
|
||
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:
|
||
stdio.printf("[GSP] generic: ptr_val=None\n")
|
||
stdio.fflush(0)
|
||
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, idx_val)
|
||
case _:
|
||
pass
|
||
# 自定义结构体 (如 self._ht[key]): 返回 None,
|
||
# 触发 HandlesAssign 的 __setitem__ 重载
|
||
cls_nm_gen: str = _get_custom_struct_cls_nm(pool, elem_ty2)
|
||
if cls_nm_gen is None:
|
||
pass
|
||
if not (cls_nm_gen is None):
|
||
stdio.printf("[GSP] generic custom struct %s, defer to __setitem__\n",
|
||
cls_nm_gen)
|
||
stdio.fflush(0)
|
||
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(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:
|
||
# 使用 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:
|
||
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)
|
||
# 回退 1: 类型指针比较失败时,通过 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)
|
||
# 回退 1 成功: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
|
||
# 回退 1 更新 struct_ty 后,需重新确保
|
||
# 注解类型结构体定义在当前模块可用
|
||
HandlesStruct.ensure_struct_def_in_module(
|
||
pool, mod, annot_se.Ty)
|
||
# 回退 2: 子类搜索 — 注解类型是基类但实际值是派生类
|
||
# 如 node: AST | t.CPtr = If(...),访问 node.orelse
|
||
# orelse 在 If 上不在 AST 上,需搜索 AST 的子类
|
||
if field_info is None:
|
||
sub_entry: HandlesStruct.StructEntry | t.CPtr = \
|
||
HandlesStruct.find_subclass_with_field(
|
||
var_entry.AnnotClassName, at.attr)
|
||
if sub_entry is not None and sub_entry.Ty is not None:
|
||
sub_field: HandlesStruct.FieldEntry | t.CPtr = \
|
||
HandlesStruct.lookup_field(sub_entry.Ty, at.attr)
|
||
if sub_field is not None:
|
||
sub_ptr_ty: llvmlite.LLVMType | t.CPtr = \
|
||
llvmlite.Ptr(pool, sub_entry.Ty)
|
||
casted_ptr: llvmlite.Value | t.CPtr = \
|
||
llvmlite.build_bitcast(builder, obj_ptr, sub_ptr_ty)
|
||
if casted_ptr is not None:
|
||
# 确保子类结构体定义在当前模块可用
|
||
HandlesStruct.ensure_struct_def_in_module(
|
||
pool, mod, sub_entry.Ty)
|
||
return llvmlite.build_gep_struct(
|
||
builder, sub_entry.Ty, sub_field.Ty,
|
||
casted_ptr, sub_field.Index)
|
||
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)
|
||
return None
|
||
case _:
|
||
return None
|