_translate_method_call ignored cl.keywords, so keyword-style calls
like add_argument("--count", short="-c", arg_type=INT) lost all
keyword values (short_name/arg_type stayed default), breaking
Test 4. Match keywords against function params by name, fill
missing params with zero values to keep call arity consistent.'
3278 lines
157 KiB
Plaintext
3278 lines
157 KiB
Plaintext
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
|
||
|
||
|
||
# ============================================================
|
||
# is_ptr_type - 检查类型是否为 Ptr
|
||
#
|
||
# 返回 1=是, 0=否。作为类型检查工具函数被广泛使用(50+ 处调用)。
|
||
# ============================================================
|
||
def is_ptr_type(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""检查 ty 是否是 Ptr 类型,返回 1=是, 0=否"""
|
||
if ty is None:
|
||
return 0
|
||
match ty:
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
return 1
|
||
case _:
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# get_ptr_level - 计算指针层级
|
||
#
|
||
# 返回值:
|
||
# 0 = 非指针(数值/结构体等)
|
||
# 1 = 一级指针(如 i8*, Struct*)
|
||
# 2 = 二级指针(如 i8**, Struct**)
|
||
# 3+ = 更高级指针
|
||
#
|
||
# 用于比较运算的类型安全检查:
|
||
# - 数值(0) vs 数值(0) → 允许
|
||
# - 一级指针(1) vs 一级指针(1) → 允许
|
||
# - 数值(0) vs 指针(1+) → 禁止(fast-fail)
|
||
# - 不同级指针(1 vs 2) → 禁止(fast-fail)
|
||
# ============================================================
|
||
def get_ptr_level(ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""计算指针层级,0=非指针, 1=一级指针, 2=二级指针..."""
|
||
if ty is None:
|
||
return 0
|
||
level: int = 0
|
||
cur: llvmlite.LLVMType | t.CPtr = ty
|
||
while cur is not None:
|
||
match cur:
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
level += 1
|
||
cur = pointee
|
||
case _:
|
||
break
|
||
return level
|
||
|
||
|
||
# ============================================================
|
||
# is_array_type - 检查类型是否为 Array
|
||
#
|
||
# 返回 1=是, 0=否。类型检查工具函数。
|
||
# ============================================================
|
||
def is_array_type(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 解引用
|
||
# ============================================================
|
||
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,
|
||
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""将 val 强制转换为 target_ty
|
||
|
||
整数: sext(扩展)/ trunc(截断)
|
||
浮点: fpext(扩展)/ fptrunc(截断)
|
||
int→float: sitofp
|
||
float→int: fptosi
|
||
|
||
node: AST 节点(用于错误定位),可为 None
|
||
"""
|
||
if val is None or target_ty is None:
|
||
return val
|
||
# 函数 → 指针: bitcast(如 CreateThread(..., _thread_alloc_free, ...) 传函数指针)
|
||
# 函数 Value 的 Ty 是 Func,既不是整数也不是指针,需在整数/浮点转换之前处理
|
||
match val.Ty:
|
||
case llvmlite.LLVMType.Func(_, _, _):
|
||
if is_ptr_type(target_ty) != 0:
|
||
return llvmlite.build_bitcast(builder, val, target_ty)
|
||
return val
|
||
case _:
|
||
pass
|
||
# 整数转换
|
||
val_bits: int = get_llvm_type_bits(val.Ty)
|
||
target_bits: int = get_llvm_type_bits(target_ty)
|
||
# 整数 → 指针: inttoptr(必须在纯整数转换之前检查,因为 ptr 的 bits 非零会误入 sext/trunc 路径)
|
||
# 适用于: 跨模块方法返回 i64/i32(默认推断),目标变量是指针类型
|
||
if val_bits != 0 and is_ptr_type(target_ty) != 0:
|
||
return llvmlite.build_inttoptr(builder, val, target_ty)
|
||
# 指针 → 整数: ptrtoint(当目标明确是整数而非指针时)
|
||
# 注意: target_bits == 8 时跳过 ptrtoint,走后面的 build_load 解引用首字符
|
||
# 修复: buf[idx] = '\0' 中 '\0' 是 CONST_STR → i8* 指针,
|
||
# ptrtoint 会截断地址低 8 位(非 0),应 load 解引用取首字符 0
|
||
if is_ptr_type(val.Ty) != 0 and target_bits != 0 and target_bits != 8 and is_ptr_type(target_ty) == 0:
|
||
return llvmlite.build_ptrtoint(builder, val, target_ty)
|
||
if val_bits != 0 and target_bits != 0:
|
||
if val_bits == target_bits:
|
||
return val
|
||
if val_bits < target_bits:
|
||
# i1 (bool) → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF...)
|
||
# 与 HandlesReturn 中 return 语句的 i1 扩展规则保持一致
|
||
if val_bits == 1:
|
||
return llvmlite.build_zext(builder, val, target_ty)
|
||
return llvmlite.build_sext(builder, val, target_ty)
|
||
return llvmlite.build_trunc(builder, val, target_ty)
|
||
# 浮点转换
|
||
val_fbits: int = get_llvm_float_bits(val.Ty)
|
||
target_fbits: int = get_llvm_float_bits(target_ty)
|
||
# float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径)
|
||
if (val_fbits != 0 and is_ptr_type(target_ty) != 0) or \
|
||
(is_ptr_type(val.Ty) != 0 and target_fbits != 0):
|
||
HandlesType.fatal_error(node, "unsupported type conversion: float <-> ptr", "CastError")
|
||
return val
|
||
if val_fbits != 0 and target_fbits != 0:
|
||
if val_fbits == target_fbits:
|
||
return val
|
||
if val_fbits < target_fbits:
|
||
return llvmlite.build_fpext(builder, val, target_ty)
|
||
return llvmlite.build_fptrunc(builder, val, target_ty)
|
||
# int → float
|
||
if val_bits != 0 and target_fbits != 0:
|
||
return llvmlite.build_si2fp(builder, val, target_ty)
|
||
# float → int
|
||
if val_fbits != 0 and target_bits != 0:
|
||
return llvmlite.build_fp2si(builder, val, target_ty)
|
||
# 指针 → 非指针值: build_load 解引用
|
||
# 适用于: 指针 → 整数 (如 i8* → i8), 指针 → 结构体值
|
||
# 当构造器返回 Ptr(Struct) 但目标变量是 Struct 值类型时,需要 load
|
||
if is_ptr_type(val.Ty) != 0 and is_ptr_type(target_ty) == 0:
|
||
return llvmlite.build_load(builder, target_ty, val)
|
||
# 指针 → 指针: bitcast (如 i8* → i8** 当目标是全局变量存储指针)
|
||
if is_ptr_type(val.Ty) != 0 and is_ptr_type(target_ty) != 0:
|
||
return llvmlite.build_bitcast(builder, val, target_ty)
|
||
return val
|
||
|
||
|
||
# ============================================================
|
||
# 创建全局字符串常量
|
||
# ============================================================
|
||
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:
|
||
return None
|
||
|
||
slen: t.CSizeT = string.strlen(str_val)
|
||
count: int = slen + 1
|
||
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, count)
|
||
|
||
# 使用模块级计数器(trans._label_counter)避免跨函数命名冲突
|
||
str_idx: int = trans._label_counter
|
||
trans._label_counter += 1
|
||
|
||
# 字符串名加 SHA1 前缀,和函数导出规则一致,避免跨模块重名
|
||
gv_name: t.CChar | t.CPtr = pool.alloc(48)
|
||
if gv_name is None:
|
||
return None
|
||
if trans.ModuleSha1 is not None:
|
||
viperlib.snprintf(gv_name, 48, ".str.%s.%d", trans.ModuleSha1, str_idx)
|
||
else:
|
||
viperlib.snprintf(gv_name, 48, ".str.%d", str_idx)
|
||
|
||
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, gv_name, arr_ty)
|
||
if gv is None:
|
||
return None
|
||
llvmlite.module_add_global(mod, gv)
|
||
|
||
# 去掉 private 链接,和函数一致:stub 中 declare,text 中 define
|
||
llvmlite.global_set_unnamed_addr(gv, 1)
|
||
llvmlite.global_set_constant(gv, 1)
|
||
# LLVM 22+ 不允许 external linkage 全局变量带初始值,设为 internal
|
||
gv.Linkage = "internal"
|
||
gv.Initializer = escaped
|
||
|
||
arr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, arr_ty)
|
||
gv_ref_name: t.CChar | t.CPtr = pool.alloc(64)
|
||
if gv_ref_name is None:
|
||
return None
|
||
viperlib.snprintf(gv_ref_name, 64, "@%s", gv.Name)
|
||
gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, arr_ptr_ty, gv_ref_name)
|
||
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
|
||
bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, gv_ref, i8_ptr_ty)
|
||
return bc
|
||
|
||
|
||
# ============================================================
|
||
# 翻译常量表达式
|
||
# ============================================================
|
||
def translate_constant(builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""翻译常量(int/str/bool)"""
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||
if cn is None:
|
||
return None
|
||
ck: int = cn.const_kind
|
||
if cn.const_kind == ast.CONST_INT:
|
||
# 超出 i32 范围则用 i64(避免常量创建时被截断)
|
||
iv: t.CInt64T = cn.int_val
|
||
if iv > 2147483647 or iv < -2147483648:
|
||
return llvmlite.const_int64(pool, iv)
|
||
return llvmlite.const_int32(pool, iv)
|
||
elif cn.const_kind == ast.CONST_FLOAT:
|
||
# 浮点常量默认创建为 double(64 位),赋值时由 coerce_to_type 自动 fptrunc
|
||
double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||
return llvmlite.ConstFloat(pool, double_ty, cn.float_val)
|
||
elif cn.const_kind == ast.CONST_CHAR:
|
||
# 单引号单字符 → i32 值(字符 ASCII 码),coerce_to_type 会 trunc 为 i8
|
||
cv: t.CInt64T = cn.int_val
|
||
return llvmlite.const_int32(pool, cv)
|
||
elif cn.const_kind == ast.CONST_STR:
|
||
sv: str = cn.str_val
|
||
if sv is None:
|
||
return None
|
||
r: llvmlite.Value | t.CPtr = create_global_string(builder, pool, mod, sv, trans)
|
||
return r
|
||
elif cn.const_kind == ast.CONST_BOOL:
|
||
if cn.int_val != 0:
|
||
return llvmlite.const_int32(pool, 1)
|
||
return llvmlite.const_int32(pool, 0)
|
||
elif cn.const_kind == ast.CONST_NONE:
|
||
# None → i8* null(空指针常量),用于 `p is None` / `p is not None` 比较
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
if i8_ty is None:
|
||
return None
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
if i8_ptr_ty is None:
|
||
return None
|
||
rv_none: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty, "null")
|
||
return rv_none
|
||
return None
|
||
|
||
|
||
# ============================================================
|
||
# _infer_elem_type_from_value — 从 LLVM Value 推断 list 元素类型名
|
||
#
|
||
# 用于 list 字面量 [a, b, c] 的元素类型推断
|
||
# ============================================================
|
||
def _infer_elem_type_from_value(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
|
||
|
||
查找顺序: pool → _mbuddy → mbuddy → mb
|
||
兜底: 若都未找到,注册外部全局 @_mbuddy (i8*) 供函数内动态 list 创建使用。
|
||
注意: 模块级 t.CArray 初始化不走此路径(由 _init_global_array_from_list 处理),
|
||
此兜底仅用于函数内的动态 list 字面量(如 op=[...])。
|
||
@_mbuddy 由入口模块(如 Phase2.py)定义并初始化,其他模块以 external 引用。
|
||
"""
|
||
if trans is None:
|
||
return None
|
||
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, "pool")
|
||
if alloca is not None:
|
||
return alloca
|
||
alloca = HandlesVar.lookup_var(trans.SymTab, "_mbuddy")
|
||
if alloca is not None:
|
||
return alloca
|
||
alloca = HandlesVar.lookup_var(trans.SymTab, "mbuddy")
|
||
if alloca is not None:
|
||
return alloca
|
||
alloca = HandlesVar.lookup_var(trans.SymTab, "mb")
|
||
if alloca is not None:
|
||
return alloca
|
||
# 兜底: 创建外部全局 @_mbuddy 引用(i8** 类型)
|
||
# 仅用于函数内动态 list 字面量,@_mbuddy 由入口模块定义并初始化
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
if pool is None or trans.Module is None or trans.SymTab is None:
|
||
return None
|
||
# 先检查是否已注册到模块作用域(避免重复创建全局变量)
|
||
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(trans.SymTab, "_mbuddy")
|
||
if existing is not None:
|
||
return existing
|
||
# 创建 i8* 类型(t.CVoid | t.CPtr = i8*)
|
||
i8_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_fb)
|
||
# 创建外部全局 @_mbuddy(external linkage,无初始值)
|
||
gv_ext: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, "_mbuddy", i8_ptr_ty_fb)
|
||
if gv_ext is not None:
|
||
gv_ext.Linkage = "external"
|
||
llvmlite.module_add_global(trans.Module, gv_ext)
|
||
# 创建 Value 引用(@_mbuddy, 类型为 i8**)
|
||
i8_ptr_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_fb)
|
||
ref_name_fb: t.CChar | t.CPtr = pool.alloc(16)
|
||
if ref_name_fb is not None:
|
||
string.strcpy(ref_name_fb, "@_mbuddy")
|
||
gv_ref_fb: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb)
|
||
# 注册到模块作用域,避免重复创建
|
||
HandlesVar.define_module_var(trans.SymTab, "_mbuddy", gv_ref_fb)
|
||
return gv_ref_fb
|
||
|
||
|
||
# ============================================================
|
||
# translate_list_literal — 翻译 list 字面量 [a, b, c]
|
||
#
|
||
# 将 list 字面量翻译为 list[T](pool) 构造 + append 调用序列
|
||
#
|
||
# Args:
|
||
# builder: IRBuilder
|
||
# pool: 编译器内存池(MemBuddy)
|
||
# mod: LLVMModule
|
||
# node: ast.List 节点
|
||
# elem_type_name: 元素类型名(如 "str", "int"),None 表示从元素推断
|
||
# trans: Translator 对象
|
||
#
|
||
# Returns:
|
||
# list 对象指针(Ptr(list[T] struct)),None 失败
|
||
# ============================================================
|
||
def translate_list_literal(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)
|
||
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:
|
||
return None
|
||
|
||
# 1. 求值条件
|
||
cond_val: llvmlite.Value | t.CPtr = translate_value(
|
||
builder, pool, mod, ie.test, None, 0, trans)
|
||
if cond_val is None:
|
||
return None
|
||
# 转换为 i1
|
||
cond_bits: int = get_llvm_type_bits(cond_val.Ty)
|
||
if cond_bits == 1:
|
||
cond_i1: llvmlite.Value | t.CPtr = cond_val
|
||
else:
|
||
if is_ptr_type(cond_val.Ty) != 0:
|
||
# 指针类型:与 null 比较
|
||
null_cond: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null")
|
||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond)
|
||
else:
|
||
zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero)
|
||
|
||
# 2. 创建三个基本块
|
||
cnt: int = trans._label_counter
|
||
trans._label_counter = cnt + 1
|
||
name_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||
if name_buf is None:
|
||
return None
|
||
viperlib.snprintf(name_buf, 32, "ifexp.then.%d", cnt)
|
||
then_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "ifexp.else.%d", cnt)
|
||
else_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
viperlib.snprintf(name_buf, 32, "ifexp.merge.%d", cnt)
|
||
merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
if then_bb is None or else_bb is None or merge_bb is None:
|
||
return None
|
||
|
||
# 3. 条件跳转
|
||
llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb)
|
||
|
||
# 4. then 分支
|
||
llvmlite.position_at_end(builder, then_bb)
|
||
body_val: llvmlite.Value | t.CPtr = translate_value(
|
||
builder, pool, mod, ie.body, None, 0, trans)
|
||
then_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock
|
||
if body_val is None:
|
||
body_val = llvmlite.const_int32(pool, 0)
|
||
# 暂不 br,等类型对齐后再 br
|
||
|
||
# 5. else 分支
|
||
llvmlite.position_at_end(builder, else_bb)
|
||
orelse_val: llvmlite.Value | t.CPtr = translate_value(
|
||
builder, pool, mod, ie.orelse, None, 0, trans)
|
||
else_blk_for_phi: llvmlite.BasicBlock | t.CPtr = trans._cur_builder.CurBlock
|
||
if orelse_val is None:
|
||
orelse_val = llvmlite.const_int32(pool, 0)
|
||
# 暂不 br,等类型对齐后再 br
|
||
|
||
# 类型对齐 (两分支类型可能不同)
|
||
# 必须在各自分支中执行 coerce_to_type,确保 merge 块中 PHI 是第一条指令
|
||
# (否则 coerce_to_type 生成的 sext/zext/ptrtoint/inttoptr 指令在 PHI 之前,违反 LLVM 规则)
|
||
body_bits: int = get_llvm_type_bits(body_val.Ty)
|
||
orelse_bits: int = get_llvm_type_bits(orelse_val.Ty)
|
||
body_is_ptr: int = is_ptr_type(body_val.Ty)
|
||
orelse_is_ptr: int = is_ptr_type(orelse_val.Ty)
|
||
# 情况0: 一侧是指针,另一侧是整数(如 i64 vs i8* null)
|
||
# 必须优先处理,因为 Ptr 的 bits=0 会导致下面三个分支全部跳过
|
||
# 选择 body_val.Ty 作为 phi_ty(then 分支优先),orelse_val 对齐到它
|
||
# coerce_to_type 内部会调用 ptrtoint(指针→整数)或 inttoptr(整数→指针)
|
||
if body_is_ptr != orelse_is_ptr:
|
||
llvmlite.position_at_end(builder, else_blk_for_phi)
|
||
orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node)
|
||
elif body_bits > orelse_bits and orelse_bits > 0:
|
||
# 在 else 块中转换 orelse_val
|
||
llvmlite.position_at_end(builder, else_blk_for_phi)
|
||
orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node)
|
||
elif orelse_bits > body_bits and body_bits > 0:
|
||
# 回到 then 块转换 body_val
|
||
llvmlite.position_at_end(builder, then_blk_for_phi)
|
||
body_val = coerce_to_type(builder, body_val, orelse_val.Ty, node)
|
||
elif body_bits == orelse_bits and body_bits > 0:
|
||
# bits 相同但类型不同(如 i64 vs Ptr):null 不能用于 i64 PHI
|
||
# 此分支理论上不会触发(已被情况0覆盖),保留作为防御
|
||
if is_ptr_type(body_val.Ty) != is_ptr_type(orelse_val.Ty):
|
||
llvmlite.position_at_end(builder, else_blk_for_phi)
|
||
orelse_val = coerce_to_type(builder, orelse_val, body_val.Ty, node)
|
||
|
||
# 现在分别在 then/else 块中 br 到 merge(在类型转换之后)
|
||
llvmlite.position_at_end(builder, then_blk_for_phi)
|
||
llvmlite.build_br(builder, merge_bb)
|
||
llvmlite.position_at_end(builder, else_blk_for_phi)
|
||
llvmlite.build_br(builder, merge_bb)
|
||
|
||
# 6. merge 块: phi(PHI 是 merge 块的第一条指令)
|
||
llvmlite.position_at_end(builder, merge_bb)
|
||
|
||
phi_ty: llvmlite.LLVMType | t.CPtr = body_val.Ty
|
||
if phi_ty is None:
|
||
phi_ty = llvmlite.Int32(pool)
|
||
|
||
inc1: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(
|
||
pool, body_val, then_blk_for_phi)
|
||
inc2: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(
|
||
pool, orelse_val, else_blk_for_phi)
|
||
if inc1 is None or inc2 is None:
|
||
return None
|
||
# 链表顺序: inc1 (head) -> inc2 (tail)
|
||
# 之前错误写成 inc2.Next = inc1,导致 build_phi 从 inc1 遍历时
|
||
# inc1.Next 为 None,只输出一个 phi 条目,引发 LLVM 验证错误:
|
||
# "PHINode should have one entry for each predecessor"
|
||
inc1.Next = inc2
|
||
return llvmlite.build_phi(builder, phi_ty, inc1, 2)
|
||
|
||
|
||
# ============================================================
|
||
# 翻译比较表达式 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:
|
||
return None
|
||
rhs_node: ast.AST | t.CPtr = comparators.get(0)
|
||
rhs: llvmlite.Value | t.CPtr = translate_value(
|
||
builder, pool, mod, rhs_node, None, 0, trans)
|
||
if rhs is None:
|
||
return None
|
||
|
||
# === None 比较优化: x == None / x != None 走身份比较(icmp eq/ne null)===
|
||
# 避免对结构体指针生成无效的 __eq__/__ne__ 调用(方法未定义但类有 SHA1 时
|
||
# try_operator_overload 会误生成 call void @...__eq__(...) 导致链接错误)
|
||
# 语义依据: Python 中 == None / != None 默认走身份比较,不调用 __eq__/__ne__
|
||
lhs_node: ast.AST | t.CPtr = cmp.left
|
||
cmp_with_none: int = 0
|
||
if op == ast.OpKind.Eq or op == ast.OpKind.Ne or op == ast.OpKind.Is or op == ast.OpKind.IsNot:
|
||
if rhs_node is not None and rhs_node.kind() == ast.ASTKind.Constant:
|
||
rhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rhs_node)
|
||
if rhs_cn is not None and rhs_cn.const_kind == ast.CONST_NONE:
|
||
cmp_with_none = 1
|
||
if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Constant:
|
||
lhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(lhs_node)
|
||
if lhs_cn is not None and lhs_cn.const_kind == ast.CONST_NONE:
|
||
cmp_with_none = 1
|
||
|
||
# === 比较运算符重载路径 1: lhs 是 Name 且对应结构体变量 ===
|
||
# 对于值类型变量(如 cnt: Counter),用 alloca 指针尝试重载
|
||
# None 比较跳过重载(走身份比较)
|
||
if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node)
|
||
if nm is not None and nm.id is not None:
|
||
lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
trans.SymTab, nm.id)
|
||
if lhs_alloca is not None:
|
||
ovl_result: llvmlite.Value | t.CPtr = HandlesExprOps.try_operator_overload(
|
||
pool, builder, mod, lhs_alloca, rhs, op, trans, 1)
|
||
if ovl_result is not None:
|
||
return ovl_result
|
||
|
||
# 正常翻译 lhs
|
||
lhs: llvmlite.Value | t.CPtr = translate_value(
|
||
builder, pool, mod, cmp.left, None, 0, trans)
|
||
if lhs is None:
|
||
return None
|
||
|
||
# === 比较运算符重载路径 2: lhs 是 Ptr(Struct) ===
|
||
# Is/IsNot 不在 _cmpop_to_dunder 映射中,会自动返回 None 回退原生比较
|
||
# None 比较跳过重载(走身份比较)
|
||
if cmp_with_none == 0:
|
||
ovl_result2: llvmlite.Value | t.CPtr = HandlesExprOps.try_operator_overload(
|
||
pool, builder, mod, lhs, rhs, op, trans, 1)
|
||
if ovl_result2 is not None:
|
||
return ovl_result2
|
||
|
||
predicate: int = llvmlite.ICMP_SLT
|
||
if op == ast.OpKind.Lt:
|
||
predicate = llvmlite.ICMP_SLT
|
||
elif op == ast.OpKind.Le:
|
||
predicate = llvmlite.ICMP_SLE
|
||
elif op == ast.OpKind.Gt:
|
||
predicate = llvmlite.ICMP_SGT
|
||
elif op == ast.OpKind.Ge:
|
||
predicate = llvmlite.ICMP_SGE
|
||
elif op == ast.OpKind.Eq:
|
||
predicate = llvmlite.ICMP_EQ
|
||
elif op == ast.OpKind.Ne:
|
||
predicate = llvmlite.ICMP_NE
|
||
elif op == ast.OpKind.Is:
|
||
# `x is y` → 指针/值相等比较
|
||
predicate = llvmlite.ICMP_EQ
|
||
elif op == ast.OpKind.IsNot:
|
||
# `x is not y` → 指针/值不等比较
|
||
predicate = llvmlite.ICMP_NE
|
||
|
||
# === 类型安全检查(BUG2 修复)===
|
||
# 规则:
|
||
# - 数值(0) vs 数值(0) → 允许(无关类型,按位宽 sext 对齐)
|
||
# - 一级指针(1) vs 一级指针(1) → 允许(无关 pointee 类型,地址比较)
|
||
# - 数值(0) vs 指针(1+) → 禁止(fast-fail,除 None 比较外)
|
||
# - 不同级指针(1 vs 2 等) → 禁止(fast-fail)
|
||
#
|
||
# None 比较跳过此检查(None 被翻译为 null 指针或 0,与任意指针/数值比较合法)
|
||
if cmp_with_none == 0:
|
||
lhs_ptr_level: int = get_ptr_level(lhs.Ty)
|
||
rhs_ptr_level: int = get_ptr_level(rhs.Ty)
|
||
if lhs_ptr_level != rhs_ptr_level:
|
||
# 类型不匹配:数值vs指针 或 不同级指针
|
||
# 用 fmt_buf 构造可读消息(Viper % 格式化在部分路径生成 null)
|
||
fmt_msg: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||
if fmt_msg is not None:
|
||
viperlib.snprintf(
|
||
fmt_msg, 1024,
|
||
"比较类型不匹配(行 %d): lhs 层级=%d (ty=%p), rhs 层级=%d (ty=%p)",
|
||
cmp.lineno, lhs_ptr_level, lhs.Ty, rhs_ptr_level, rhs.Ty)
|
||
VLogger.error(fmt_msg, "Compare")
|
||
else:
|
||
VLogger.error("比较类型不匹配: 数值与指针/不同级指针比较", "Compare")
|
||
return None
|
||
else:
|
||
# None 比较: None 被翻译为 i8* null(一级指针)
|
||
# 如果 lhs 是指针,将 rhs (i8* null) bitcast 为 lhs 的指针类型
|
||
# 如果 lhs 是数值,将 rhs 转为数值 0(走正常整数比较)
|
||
# 如果 lhs 是结构体值类型,结构体永远不等于 None,返回常量 i1
|
||
lhs_ptr_level_none: int = get_ptr_level(lhs.Ty)
|
||
rhs_ptr_level_none: int = get_ptr_level(rhs.Ty)
|
||
if lhs_ptr_level_none != 0 and rhs_ptr_level_none != 0:
|
||
# 两边都是指针,类型可能不同(如 lhs=Struct*, rhs=i8* null)
|
||
# 由下方 bitcast 对齐处理,此处不处理
|
||
pass
|
||
elif lhs_ptr_level_none != 0 and rhs_ptr_level_none == 0:
|
||
# lhs 是指针, rhs 是数值 → 将 rhs 转为同层级 null 指针
|
||
rhs = llvmlite.ConstNull(pool, lhs.Ty, None)
|
||
elif rhs_ptr_level_none != 0 and lhs_ptr_level_none == 0:
|
||
# 检查 lhs 是否是结构体值类型(非指针的 Struct)
|
||
lhs_is_struct_none: int = 0
|
||
match lhs.Ty:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
lhs_is_struct_none = 1
|
||
case _:
|
||
lhs_is_struct_none = 0
|
||
if lhs_is_struct_none != 0:
|
||
# 结构体值永远不等于 None:==/is 返回 false,!=/is not 返回 true
|
||
if op == ast.OpKind.Eq or op == ast.OpKind.Is:
|
||
return llvmlite.const_int(pool, 1, 0)
|
||
else: # Ne, IsNot
|
||
return llvmlite.const_int(pool, 1, 1)
|
||
# lhs 是数值, rhs 是 i8* null → 将 rhs 转为数值 0(保持 lhs 不变)
|
||
rhs = llvmlite.const_int32(pool, 0)
|
||
|
||
# 类型对齐:icmp 要求两边类型相同
|
||
# 仅对数值类型做对齐(指针类型无需对齐,LLVM 允许同层级指针直接 icmp)
|
||
# i1 (bool) 侧用 zext 对齐(1 保持 1,而非 sext 的 0xFF...)
|
||
lhs_bits: int = get_llvm_type_bits(lhs.Ty)
|
||
rhs_bits: int = get_llvm_type_bits(rhs.Ty)
|
||
if lhs_bits != 0 and rhs_bits != 0 and lhs_bits != rhs_bits:
|
||
if lhs_bits < rhs_bits:
|
||
if lhs_bits == 1:
|
||
lhs = llvmlite.build_zext(builder, lhs, rhs.Ty)
|
||
else:
|
||
lhs = llvmlite.build_sext(builder, lhs, rhs.Ty)
|
||
else:
|
||
if rhs_bits == 1:
|
||
rhs = llvmlite.build_zext(builder, rhs, lhs.Ty)
|
||
else:
|
||
rhs = llvmlite.build_sext(builder, rhs, lhs.Ty)
|
||
|
||
# 指针类型对齐:同层级但不同 pointee 类型的指针需要 bitcast 统一类型
|
||
# 例如 i8* vs Struct* → 将 rhs bitcast 为 lhs 的类型
|
||
if lhs_bits == 0 and rhs_bits == 0:
|
||
lhs_is_ptr_now: int = is_ptr_type(lhs.Ty)
|
||
rhs_is_ptr_now: int = is_ptr_type(rhs.Ty)
|
||
if lhs_is_ptr_now != 0 and rhs_is_ptr_now != 0:
|
||
# 两边都是指针,用 TypePrint 比较类型字符串
|
||
lhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||
rhs_ty_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||
if lhs_ty_buf is not None and rhs_ty_buf is not None:
|
||
llvmlite.TypePrint(lhs_ty_buf, 128, lhs.Ty, pool)
|
||
llvmlite.TypePrint(rhs_ty_buf, 128, rhs.Ty, pool)
|
||
if string.strcmp(lhs_ty_buf, rhs_ty_buf) != 0:
|
||
rhs = llvmlite.build_bitcast(builder, rhs, lhs.Ty)
|
||
|
||
# 浮点比较:任一操作数为浮点类型时使用 fcmp 而非 icmp
|
||
lhs_fbits: int = get_llvm_float_bits(lhs.Ty)
|
||
rhs_fbits: int = get_llvm_float_bits(rhs.Ty)
|
||
if lhs_fbits != 0 or rhs_fbits != 0:
|
||
# 浮点类型对齐(fpext/fptrunc)
|
||
if lhs_fbits != 0 and rhs_fbits != 0 and lhs_fbits != rhs_fbits:
|
||
if lhs_fbits < rhs_fbits:
|
||
lhs = llvmlite.build_fpext(builder, lhs, rhs.Ty)
|
||
else:
|
||
rhs = llvmlite.build_fptrunc(builder, rhs, lhs.Ty)
|
||
elif lhs_fbits != 0 and rhs_fbits == 0:
|
||
# int → float
|
||
rhs = llvmlite.build_si2fp(builder, rhs, lhs.Ty)
|
||
elif rhs_fbits != 0 and lhs_fbits == 0:
|
||
lhs = llvmlite.build_si2fp(builder, lhs, rhs.Ty)
|
||
# 映射比较谓词到 fcmp
|
||
fpredicate: int = llvmlite.FCMP_OEQ
|
||
if op == ast.OpKind.Eq or op == ast.OpKind.Is:
|
||
fpredicate = llvmlite.FCMP_OEQ
|
||
elif op == ast.OpKind.Ne or op == ast.OpKind.IsNot:
|
||
fpredicate = llvmlite.FCMP_ONE
|
||
elif op == ast.OpKind.Lt:
|
||
fpredicate = llvmlite.FCMP_OLT
|
||
elif op == ast.OpKind.Le:
|
||
fpredicate = llvmlite.FCMP_OLE
|
||
elif op == ast.OpKind.Gt:
|
||
fpredicate = llvmlite.FCMP_OGT
|
||
elif op == ast.OpKind.Ge:
|
||
fpredicate = llvmlite.FCMP_OGE
|
||
return llvmlite.build_fcmp(builder, fpredicate, lhs, rhs)
|
||
|
||
return llvmlite.build_icmp(builder, predicate, lhs, rhs)
|
||
|
||
|
||
# ============================================================
|
||
# 翻译一元运算表达式 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
|
||
# 浮点类型用 fneg(直接生成 fneg 指令,避免 0.0 - x 的类型不匹配)
|
||
operand_fbits: int = get_llvm_float_bits(operand.Ty)
|
||
if operand_fbits > 0:
|
||
return llvmlite.build_fneg(builder, operand)
|
||
# 整数类型:-x = 0 - x,根据位宽选择零值常量(避免 i32 与 i64 类型不匹配)
|
||
operand_bits: int = get_llvm_type_bits(operand.Ty)
|
||
zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||
if operand_bits == 64:
|
||
zero = llvmlite.const_int64(pool, 0)
|
||
elif operand_bits > 0 and operand_bits != 32:
|
||
# 其他位宽(i8/i16 等):用 i32 零值,operand 会被 coerce
|
||
zero = llvmlite.const_int32(pool, 0)
|
||
return llvmlite.build_sub(builder, zero, operand)
|
||
elif uo.op == ast.OpKind.UAdd:
|
||
# +x = x
|
||
return operand
|
||
elif uo.op == ast.OpKind.Not:
|
||
# not x = (x == 0/null),返回 i1
|
||
if is_ptr_type(operand.Ty) != 0:
|
||
# 指针类型:与 null 比较
|
||
null_op: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, operand.Ty, "null")
|
||
return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, null_op)
|
||
# 结构体值类型:永远为真(非空),not 返回 false
|
||
operand_is_struct_not: int = 0
|
||
match operand.Ty:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
operand_is_struct_not = 1
|
||
case _:
|
||
operand_is_struct_not = 0
|
||
if operand_is_struct_not != 0:
|
||
return llvmlite.const_int(pool, 1, 0)
|
||
operand_bits_not: int = get_llvm_type_bits(operand.Ty)
|
||
zero = llvmlite.const_int32(pool, 0)
|
||
if operand_bits_not == 64:
|
||
zero = llvmlite.const_int64(pool, 0)
|
||
return llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, operand, zero)
|
||
elif uo.op == ast.OpKind.Invert:
|
||
# ~x = x ^ -1
|
||
operand_bits_inv: int = get_llvm_type_bits(operand.Ty)
|
||
neg1: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, -1)
|
||
if operand_bits_inv == 64:
|
||
neg1 = llvmlite.const_int64(pool, -1)
|
||
return llvmlite.build_xor(builder, operand, neg1)
|
||
return operand
|
||
|
||
|
||
# ============================================================
|
||
# 翻译布尔运算 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/null 比较)
|
||
val_bits: int = get_llvm_type_bits(val.Ty)
|
||
val_i1: llvmlite.Value | t.CPtr = val
|
||
if val_bits != 1:
|
||
if is_ptr_type(val.Ty) != 0:
|
||
# 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配)
|
||
null_val: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, val.Ty, "null")
|
||
val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, null_val)
|
||
else:
|
||
zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||
val_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, val, zero)
|
||
|
||
# 创建 next BB(求值下一个值)
|
||
cnt = builder.Counter
|
||
builder.Counter = cnt + 1
|
||
viperlib.snprintf(name_buf, 32, "bool.next.%d", cnt)
|
||
next_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
|
||
|
||
# and: 短路假→merge,真→next;or: 短路真→merge,假→next
|
||
if op == ast.OpKind.And:
|
||
llvmlite.build_cond_br(builder, val_i1, next_bb, merge_bb)
|
||
else:
|
||
llvmlite.build_cond_br(builder, val_i1, merge_bb, next_bb)
|
||
|
||
# 添加 phi 入边:(val_i1, cond_br 所在 BB)
|
||
cur_bb: llvmlite.BasicBlock | t.CPtr = builder.CurBlock
|
||
inc: llvmlite.PhiIncoming | t.CPtr = llvmlite.new_phi_incoming(pool, val_i1, cur_bb)
|
||
if phi_head is None:
|
||
phi_head = inc
|
||
phi_tail = inc
|
||
else:
|
||
phi_tail.Next = inc
|
||
phi_tail = inc
|
||
|
||
# 定位到 next BB,求值下一个值
|
||
llvmlite.position_at_end(builder, next_bb)
|
||
|
||
# 最后一个值:求值后直接跳 merge
|
||
last_node: ast.AST | t.CPtr = values.get(count - 1)
|
||
last_val: llvmlite.Value | t.CPtr = translate_value(
|
||
builder, pool, mod, last_node,
|
||
funcs_ptr, func_count, trans)
|
||
if last_val is None:
|
||
return None
|
||
last_bits: int = get_llvm_type_bits(last_val.Ty)
|
||
last_i1: llvmlite.Value | t.CPtr = last_val
|
||
if last_bits != 1:
|
||
if is_ptr_type(last_val.Ty) != 0:
|
||
# 指针类型:与 null 比较(避免 i8* 与 i32 类型不匹配)
|
||
null_val2: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, last_val.Ty, "null")
|
||
last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, null_val2)
|
||
else:
|
||
zero = llvmlite.const_int32(pool, 0)
|
||
last_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, last_val, zero)
|
||
|
||
llvmlite.build_br(builder, merge_bb)
|
||
|
||
cur_bb = builder.CurBlock
|
||
inc = llvmlite.new_phi_incoming(pool, last_i1, cur_bb)
|
||
if phi_head is None:
|
||
phi_head = inc
|
||
else:
|
||
phi_tail.Next = inc
|
||
phi_count += 1
|
||
|
||
# 定位到 merge,创建 phi 合并所有入边
|
||
llvmlite.position_at_end(builder, merge_bb)
|
||
i1_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
|
||
return llvmlite.build_phi(builder, i1_ty, phi_head, phi_count)
|
||
|
||
|
||
# ============================================================
|
||
# _build_source_path_from_sha1 - 通过 SHA1 从存储器构建源 .vp/.py 文件路径
|
||
#
|
||
# .vpi 文件可能未生成(Phase1 未输出 vpi),此时回退读取源 .py 文件。
|
||
# 从 StubMerger 全局存储器查找 SHA1 对应的相对路径,
|
||
# 根据 rel_path 前缀选择基础目录:
|
||
# - rel_path 以 "lib/" 开头 → App 源文件,用 {Config.SourceDir}/{rel_path}
|
||
# - 其他 → includes 文件,用 {Config.IncludesDir}/{rel_path}
|
||
#
|
||
# Returns:
|
||
# stdlib.malloc 分配的路径字符串(调用者负责 free),None 失败
|
||
# ============================================================
|
||
def _build_source_path_from_sha1(sha1: str) -> str:
|
||
"""通过 SHA1 从全局存储器构建源 .py 文件路径"""
|
||
if sha1 is None:
|
||
return None
|
||
if Config.IncludesDir is None:
|
||
return None
|
||
# 从 StubMerger 全局存储器获取相对路径数组
|
||
rel_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
|
||
count: int = StubMerger.GetSha1StoreCount()
|
||
if rel_arr_ptr is None or count <= 0:
|
||
return None
|
||
sha1_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
|
||
if sha1_arr_ptr is None:
|
||
return None
|
||
# 遍历查找匹配的 SHA1
|
||
idx_s: int = -1
|
||
for i in range(count):
|
||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||
cur_sha1: str = sha1_arr_ptr + sidx
|
||
if cur_sha1[0] == '\0':
|
||
continue
|
||
if string.strcmp(cur_sha1, sha1) == 0:
|
||
idx_s = i
|
||
break
|
||
if idx_s < 0:
|
||
return None
|
||
# 获取相对路径(MAX_REL_PATH_LEN=256,避免跨模块 CDefine 解析问题)
|
||
MAX_RPL: t.CSizeT = 256
|
||
ridx: t.CSizeT = t.CSizeT(idx_s) * MAX_RPL
|
||
rel_path: str = rel_arr_ptr + ridx
|
||
if rel_path[0] == '\0':
|
||
return None
|
||
# 选择基础目录:rel_path 以 "lib/" 开头 → App 源文件(SourceDir),否则 includes 文件
|
||
base_dir: str = Config.IncludesDir
|
||
is_app: int = 0
|
||
if string.strlen(rel_path) >= 4:
|
||
if (rel_path[0] == 'l' and rel_path[1] == 'i' and
|
||
rel_path[2] == 'b' and rel_path[3] == '/'):
|
||
is_app = 1
|
||
if is_app != 0 and Config.SourceDir is not None:
|
||
base_dir = Config.SourceDir
|
||
# 构建完整路径: {base_dir}/{rel_path}
|
||
base_len: t.CSizeT = string.strlen(base_dir)
|
||
rel_len: t.CSizeT = string.strlen(rel_path)
|
||
path_len: t.CSizeT = base_len + rel_len + 2
|
||
buf: str = stdlib.malloc(path_len)
|
||
if buf is None:
|
||
return None
|
||
viperlib.snprintf(buf, path_len, "%s/%s", base_dir, rel_path)
|
||
return buf
|
||
|
||
|
||
# ============================================================
|
||
# _lookup_cross_module_cdefine - 跨模块查找 CDefine 常量
|
||
#
|
||
# 当当前模块的 CDefine 表中找不到某个 Name 时,从 from_imports
|
||
# 解析出源模块,再从该模块的 pyi 文件中解析 CDefine 常量值。
|
||
# 找到后缓存到当前模块的 CDefine 表中,避免重复查找。
|
||
#
|
||
# pyi 文件格式: "NAME: t.CDefine = value"
|
||
# ============================================================
|
||
def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
|
||
name: str,
|
||
from_imports: str,
|
||
imported_modules: str = None) -> int:
|
||
"""跨模块查找 CDefine 常量,返回值或 -1(未找到)
|
||
|
||
查找顺序:
|
||
1. from_imports 精确匹配(from X import NAME)
|
||
2. from_imports star 回退(from X import *)
|
||
3. imported_modules 遍历(import X):当通过 import X 导入模块时,
|
||
模块中定义的 CDefine 常量可通过此路径找到(如方法签名默认参数引用)
|
||
"""
|
||
# 入口处清零标志,确保所有早退路径(return -1)都返回"未找到"状态
|
||
# 避免递归调用时前一次成功的标志残留导致误判
|
||
HandlesType.set_cdefine_found(0)
|
||
if name is None:
|
||
return -1
|
||
if from_imports is None:
|
||
from_imports = ""
|
||
|
||
# 1. 从 from_imports 查找名称对应的模块名
|
||
# 先尝试精确匹配(allow_star_fallback=0),避免 CDefine 常量被 star import 误导
|
||
mod_name_raw: str = HandlesImports.lookup_from_import(from_imports, name, 0)
|
||
if mod_name_raw is None:
|
||
# 精确匹配失败:尝试 star import 回退
|
||
mod_name_raw = HandlesImports.lookup_from_import(from_imports, name, 1)
|
||
|
||
# 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6)
|
||
# 注意:star fallback 可能返回错误模块(如 stdint),常量实际不在其中,
|
||
# 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules
|
||
if mod_name_raw is None:
|
||
# from_imports 完全没有匹配(精确和 star 都失败)
|
||
# 直接进入 imported_modules 遍历(步骤 9.6)
|
||
if imported_modules is None:
|
||
return -1
|
||
# 跳过 from_imports 模块读取,直接走步骤 9.6 的 imported_modules 遍历
|
||
# 设置 result_found=0 跳过步骤 3-9,直接到 9.6
|
||
HandlesType.set_cdefine_found(0)
|
||
# 直接遍历 imported_modules
|
||
im_len: t.CSizeT = string.strlen(imported_modules)
|
||
im_ci: t.CSizeT = 0
|
||
while im_ci < im_len:
|
||
while im_ci < im_len and imported_modules[im_ci] == ' ':
|
||
im_ci += 1
|
||
if im_ci >= im_len:
|
||
break
|
||
im_start: t.CSizeT = im_ci
|
||
while im_ci < im_len and imported_modules[im_ci] != ' ':
|
||
im_ci += 1
|
||
im_end: t.CSizeT = im_ci
|
||
im_nlen: t.CSizeT = im_end - im_start
|
||
if im_nlen > 0 and im_nlen < 256:
|
||
im_buf: str = pool.alloc(im_nlen + 1)
|
||
if im_buf is not None:
|
||
mk: t.CSizeT = 0
|
||
while mk < im_nlen:
|
||
im_buf[mk] = imported_modules[im_start + mk]
|
||
mk += 1
|
||
im_buf[im_nlen] = '\0'
|
||
sub_fi: str = pool.alloc(im_nlen + 3)
|
||
if sub_fi is not None:
|
||
sub_fi[0] = '*'
|
||
sub_fi[1] = ':'
|
||
mk2: t.CSizeT = 0
|
||
while mk2 < im_nlen:
|
||
sub_fi[2 + mk2] = im_buf[mk2]
|
||
mk2 += 1
|
||
sub_fi[2 + im_nlen] = '\0'
|
||
sub_val: int = _lookup_cross_module_cdefine(pool, name, sub_fi, None)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
return sub_val
|
||
return -1
|
||
|
||
# 2. 复制模块名到新缓冲区(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:
|
||
return -1
|
||
|
||
# 5. 获取 temp_dir
|
||
temp_dir: str = HandlesType.get_temp_dir()
|
||
if temp_dir is None:
|
||
return -1
|
||
|
||
# 6. 构建 vpi 文件路径
|
||
td_len: t.CSizeT = string.strlen(temp_dir)
|
||
pyi_path: str = StubMerger._sliced_path(temp_dir, td_len, sha1, "vpi")
|
||
if pyi_path is None:
|
||
return -1
|
||
|
||
# 7. 读取 vpi 文件;若不存在或内容过短(空 stub)则回退读取源 .vp/.py 文件
|
||
PYI_READ_BUF_SIZE: t.CSizeT = 65536
|
||
pyi_buf: bytes = stdlib.malloc(PYI_READ_BUF_SIZE)
|
||
if pyi_buf is None:
|
||
stdlib.free(pyi_path)
|
||
return -1
|
||
pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.R)
|
||
need_py_fallback: int = 0
|
||
bytes_read: LONG = 0
|
||
if pf.closed:
|
||
# .vpi 文件不存在:回退读取源 .vp/.py 文件
|
||
need_py_fallback = 1
|
||
else:
|
||
bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE)
|
||
pf.close()
|
||
# vpi 内容过短(< 10 字节)视为空 stub,回退 .py
|
||
if bytes_read < 10:
|
||
need_py_fallback = 1
|
||
else:
|
||
if bytes_read < PYI_READ_BUF_SIZE:
|
||
pyi_buf[bytes_read] = 0
|
||
else:
|
||
pyi_buf[PYI_READ_BUF_SIZE - 1] = 0
|
||
stdlib.free(pyi_path)
|
||
|
||
if need_py_fallback != 0:
|
||
# 从 SHA1 存储器查找相对路径,构建 {base_dir}/{rel_path}
|
||
src_path: str = _build_source_path_from_sha1(sha1)
|
||
if src_path is None:
|
||
# 存储器中找不到 SHA1 = 编译器 bug(Phase1/Phase2 未填充存储器)
|
||
# 报错终止,不静默返回 -1(避免后续生成错误的 @UNDEFINED 全局变量引用)
|
||
err_buf: str = pool.alloc(512)
|
||
if err_buf is not None:
|
||
viperlib.snprintf(err_buf, 512,
|
||
"跨模块 CDefine 查找失败:SHA1 %s 不在存储器中(base_mod=%s name=%s)。"
|
||
"Phase1/Phase2 未正确填充 PopulateSha1MapStore/AppendToSha1MapStore",
|
||
sha1, base_mod, name)
|
||
VLogger.error(err_buf, "XMOD-CD")
|
||
stdlib.free(pyi_buf)
|
||
return -1
|
||
pf = fileio.File(src_path, fileio.MODE.R)
|
||
stdlib.free(src_path)
|
||
if pf.closed:
|
||
stdlib.free(pyi_buf)
|
||
return -1
|
||
bytes_read = pf.read_all(pyi_buf, PYI_READ_BUF_SIZE)
|
||
pf.close()
|
||
if bytes_read <= 0:
|
||
stdlib.free(pyi_buf)
|
||
return -1
|
||
if bytes_read < PYI_READ_BUF_SIZE:
|
||
pyi_buf[bytes_read] = 0
|
||
else:
|
||
pyi_buf[PYI_READ_BUF_SIZE - 1] = 0
|
||
|
||
# 8. 在 pyi_buf 中查找 "name: t.CDefine = value" 行
|
||
# 格式: NAME: t.CDefine = value
|
||
name_len: t.CSizeT = string.strlen(name)
|
||
total_len: t.CSizeT = string.strlen(pyi_buf)
|
||
pos: t.CSizeT = 0
|
||
result_val: int = 0
|
||
result_found: int = 0
|
||
while pos < total_len:
|
||
# 找到行首
|
||
line_start: t.CSizeT = pos
|
||
# 找到行尾
|
||
while pos < total_len and pyi_buf[pos] != '\n':
|
||
pos += 1
|
||
line_len: t.CSizeT = pos - line_start
|
||
if pos < total_len:
|
||
pos += 1 # 跳过 '\n'
|
||
|
||
# 检查行是否以 "name:" 开头
|
||
if line_len < name_len + 1:
|
||
continue
|
||
match_ok: int = 1
|
||
for ki in range(name_len):
|
||
if pyi_buf[line_start + ki] != name[ki]:
|
||
match_ok = 0
|
||
break
|
||
if match_ok == 0:
|
||
continue
|
||
if pyi_buf[line_start + name_len] != ':':
|
||
continue
|
||
|
||
# 检查行是否包含 "t.CDefine"
|
||
# 在行中查找 "t.CDefine"
|
||
has_cdefine: int = 0
|
||
ci: t.CSizeT = line_start + name_len + 1
|
||
while ci + 8 <= line_start + line_len:
|
||
if (pyi_buf[ci] == 't' and pyi_buf[ci + 1] == '.' and
|
||
pyi_buf[ci + 2] == 'C' and pyi_buf[ci + 3] == 'D' and
|
||
pyi_buf[ci + 4] == 'e' and pyi_buf[ci + 5] == 'f' and
|
||
pyi_buf[ci + 6] == 'i' and pyi_buf[ci + 7] == 'n' and
|
||
pyi_buf[ci + 8] == 'e'):
|
||
has_cdefine = 1
|
||
break
|
||
ci += 1
|
||
if has_cdefine == 0:
|
||
continue
|
||
|
||
# 找到 "=" 后面的值
|
||
eq_pos: t.CSizeT = line_start + name_len + 1
|
||
while eq_pos < line_start + line_len and pyi_buf[eq_pos] != '=':
|
||
eq_pos += 1
|
||
if eq_pos >= line_start + line_len:
|
||
continue
|
||
eq_pos += 1 # 跳过 '='
|
||
|
||
# 跳过空格
|
||
while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ':
|
||
eq_pos += 1
|
||
|
||
# 检查是否是 t.CUnsignedLong(...) / t.CLong(...) / t.CInt(...) 等类型构造函数
|
||
# 格式: t.CUnsignedLong(-11) / t.CUnsignedLong(0xFFFFFFFF)
|
||
# 如果是,跳过 "t.CXxx(" 前缀,解析括号内的值,忽略结尾 ')'
|
||
is_type_ctor: int = 0
|
||
if eq_pos + 2 < line_start + line_len:
|
||
if pyi_buf[eq_pos] == 't' and pyi_buf[eq_pos + 1] == '.':
|
||
# 找到 '(' 的位置
|
||
paren_pos: t.CSizeT = eq_pos + 2
|
||
while paren_pos < line_start + line_len and pyi_buf[paren_pos] != '(':
|
||
paren_pos += 1
|
||
if paren_pos < line_start + line_len and pyi_buf[paren_pos] == '(':
|
||
is_type_ctor = 1
|
||
eq_pos = paren_pos + 1 # 跳过 '('
|
||
# 跳过括号内可能的前导空格
|
||
while eq_pos < line_start + line_len and pyi_buf[eq_pos] == ' ':
|
||
eq_pos += 1
|
||
|
||
# 解析整数值(支持十六进制 0x 前缀和负号)
|
||
# 负号标记
|
||
is_neg: int = 0
|
||
if eq_pos < line_start + line_len and pyi_buf[eq_pos] == '-':
|
||
is_neg = 1
|
||
eq_pos += 1
|
||
val_str_start: t.CSizeT = eq_pos
|
||
val_str_len: t.CSizeT = 0
|
||
is_hex: int = 0
|
||
if eq_pos + 1 < line_start + line_len:
|
||
if pyi_buf[eq_pos] == '0' and (pyi_buf[eq_pos + 1] == 'x' or pyi_buf[eq_pos + 1] == 'X'):
|
||
is_hex = 1
|
||
val_str_len = 2
|
||
eq_pos += 2
|
||
while eq_pos < line_start + line_len:
|
||
ch: t.CChar = pyi_buf[eq_pos]
|
||
if is_hex == 1:
|
||
if ((ch >= '0' and ch <= '9') or
|
||
(ch >= 'a' and ch <= 'f') or
|
||
(ch >= 'A' and ch <= 'F')):
|
||
val_str_len += 1
|
||
eq_pos += 1
|
||
else:
|
||
break
|
||
else:
|
||
if ch >= '0' and ch <= '9':
|
||
val_str_len += 1
|
||
eq_pos += 1
|
||
else:
|
||
break
|
||
|
||
if val_str_len == 0:
|
||
continue
|
||
|
||
# 复制值字符串到新缓冲区并解析
|
||
val_buf: str = pool.alloc(val_str_len + 1)
|
||
if val_buf is None:
|
||
continue
|
||
for vi in range(val_str_len):
|
||
val_buf[vi] = pyi_buf[val_str_start + vi]
|
||
val_buf[val_str_len] = '\0'
|
||
|
||
if is_hex == 1:
|
||
# 手动解析十六进制(跳过 0x 前缀)
|
||
hex_result: int = 0
|
||
hex_buf: str = val_buf + 2 # 跳过 "0x"
|
||
for hi in range(val_str_len - 2):
|
||
hc: t.CChar = hex_buf[hi]
|
||
hd: int = 0
|
||
if hc >= '0' and hc <= '9':
|
||
hd = hc - '0'
|
||
elif hc >= 'a' and hc <= 'f':
|
||
hd = hc - 'a' + 10
|
||
elif hc >= 'A' and hc <= 'F':
|
||
hd = hc - 'A' + 10
|
||
else:
|
||
break
|
||
hex_result = hex_result * 16 + hd
|
||
result_val = hex_result
|
||
# 十六进制负值(如 0xFFFFFFFF)保持原样,由 32 位截断处理
|
||
result_found = 1
|
||
else:
|
||
result_val = string.atoi(val_buf)
|
||
# 应用负号(如 t.CUnsignedLong(-11) → -11)
|
||
if is_neg != 0:
|
||
result_val = -result_val
|
||
result_found = 1
|
||
break
|
||
|
||
# 9.5 如果当前模块文件中没找到,递归查找子模块
|
||
# 处理 from .X import NAME 和 from .X import * 的情况
|
||
# 例如 ast.__init__.vp 中 from .base import CONST_INT, ...
|
||
# 需要递归查找 ast.base 子模块中的 CONST_INT: t.CDefine = 1
|
||
if result_found == 0:
|
||
name_len_rc: t.CSizeT = string.strlen(name)
|
||
rc_pos: t.CSizeT = 0
|
||
while rc_pos < total_len and result_found == 0:
|
||
# 找到行首
|
||
rc_line_start: t.CSizeT = rc_pos
|
||
# 找到行尾
|
||
while rc_pos < total_len and pyi_buf[rc_pos] != '\n':
|
||
rc_pos += 1
|
||
rc_line_len: t.CSizeT = rc_pos - rc_line_start
|
||
if rc_pos < total_len:
|
||
rc_pos += 1
|
||
|
||
# 检查行是否以 "from ." 开头(相对导入子模块)
|
||
if rc_line_len < 12:
|
||
continue
|
||
if pyi_buf[rc_line_start] != 'f' or pyi_buf[rc_line_start+1] != 'r' or \
|
||
pyi_buf[rc_line_start+2] != 'o' or pyi_buf[rc_line_start+3] != 'm' or \
|
||
pyi_buf[rc_line_start+4] != ' ' or pyi_buf[rc_line_start+5] != '.':
|
||
continue
|
||
|
||
# 提取子模块名(从 rc_line_start+6 开始,到空格/tab 为止)
|
||
rc_sub_start: t.CSizeT = rc_line_start + 6
|
||
rc_sub_end: t.CSizeT = rc_sub_start
|
||
while rc_sub_end < rc_line_start + rc_line_len and \
|
||
pyi_buf[rc_sub_end] != ' ' and pyi_buf[rc_sub_end] != '\t':
|
||
rc_sub_end += 1
|
||
rc_sub_len: t.CSizeT = rc_sub_end - rc_sub_start
|
||
if rc_sub_len == 0:
|
||
continue
|
||
|
||
# 检查行是否包含 "import"
|
||
rc_has_import: int = 0
|
||
rc_ipos: t.CSizeT = rc_sub_end
|
||
while rc_ipos + 6 <= rc_line_start + rc_line_len:
|
||
if pyi_buf[rc_ipos] == 'i' and pyi_buf[rc_ipos+1] == 'm' and \
|
||
pyi_buf[rc_ipos+2] == 'p' and pyi_buf[rc_ipos+3] == 'o' and \
|
||
pyi_buf[rc_ipos+4] == 'r' and pyi_buf[rc_ipos+5] == 't':
|
||
rc_has_import = 1
|
||
break
|
||
rc_ipos += 1
|
||
if rc_has_import == 0:
|
||
continue
|
||
|
||
# 检查 NAME 是否在导入列表中,或导入是 *
|
||
# 处理多行导入:from .X import (... NAME, ...)
|
||
# 从 "import" 之后扫描,如果有 "(" 则扫描到 ")" 为止
|
||
rc_imp_start: t.CSizeT = rc_ipos + 6
|
||
rc_star: int = 0
|
||
rc_name_match: int = 0
|
||
|
||
# 确定扫描范围:单行或跨行(括号内)
|
||
rc_scan_end: t.CSizeT = rc_line_start + rc_line_len
|
||
rc_has_paren: int = 0
|
||
rc_pp: t.CSizeT = rc_imp_start
|
||
while rc_pp < rc_line_start + rc_line_len:
|
||
if pyi_buf[rc_pp] == '(':
|
||
rc_has_paren = 1
|
||
break
|
||
if pyi_buf[rc_pp] == '*':
|
||
rc_star = 1
|
||
rc_pp += 1
|
||
|
||
if rc_has_paren != 0:
|
||
# 多行导入:从 "(" 之后扫描到 ")" 为止
|
||
rc_scan_end = rc_pp + 1
|
||
rc_paren_closed: int = 0
|
||
rc_sp: t.CSizeT = rc_pp + 1
|
||
while rc_sp < total_len and rc_paren_closed == 0:
|
||
if pyi_buf[rc_sp] == ')':
|
||
rc_paren_closed = 1
|
||
rc_scan_end = rc_sp
|
||
break
|
||
rc_sp += 1
|
||
if rc_paren_closed == 0:
|
||
rc_scan_end = total_len
|
||
|
||
# 在 rc_imp_start 到 rc_scan_end 范围内查找 NAME 和 *
|
||
rc_cpos: t.CSizeT = rc_imp_start
|
||
while rc_cpos < rc_scan_end:
|
||
rc_ch: t.CChar = pyi_buf[rc_cpos]
|
||
if rc_ch == '*':
|
||
rc_star = 1
|
||
# 检查 NAME 是否匹配(作为完整单词)
|
||
if rc_cpos + name_len_rc <= rc_scan_end:
|
||
rc_match: int = 1
|
||
rc_ki: t.CSizeT
|
||
for rc_ki in range(name_len_rc):
|
||
if pyi_buf[rc_cpos + rc_ki] != name[rc_ki]:
|
||
rc_match = 0
|
||
break
|
||
if rc_match == 1:
|
||
# 检查前字符是否是非标识符字符
|
||
rc_before_ok: int = 0
|
||
if rc_cpos == rc_imp_start:
|
||
rc_before_ok = 1
|
||
else:
|
||
rc_before_ch: t.CChar = pyi_buf[rc_cpos - 1]
|
||
if rc_before_ch == ' ' or rc_before_ch == '\t' or \
|
||
rc_before_ch == '(' or rc_before_ch == ',' or \
|
||
rc_before_ch == '\n' or rc_before_ch == '\r':
|
||
rc_before_ok = 1
|
||
# 检查后字符是否是非标识符字符
|
||
rc_after_ok: int = 0
|
||
rc_after_pos: t.CSizeT = rc_cpos + name_len_rc
|
||
if rc_after_pos >= rc_scan_end:
|
||
rc_after_ok = 1
|
||
else:
|
||
rc_after_ch: t.CChar = pyi_buf[rc_after_pos]
|
||
if rc_after_ch == ' ' or rc_after_ch == '\t' or \
|
||
rc_after_ch == ')' or rc_after_ch == ',' or \
|
||
rc_after_ch == '\r' or rc_after_ch == '\n':
|
||
rc_after_ok = 1
|
||
if rc_before_ok == 1 and rc_after_ok == 1:
|
||
rc_name_match = 1
|
||
rc_cpos += 1
|
||
|
||
if rc_star == 0 and rc_name_match == 0:
|
||
continue
|
||
|
||
# 复制子模块名到新缓冲区(pyi_buf + rc_sub_start 不是 NUL 结尾)
|
||
rc_sub_buf: str = pool.alloc(rc_sub_len + 1)
|
||
if rc_sub_buf is None:
|
||
continue
|
||
rc_si: t.CSizeT
|
||
for rc_si in range(rc_sub_len):
|
||
rc_sub_buf[rc_si] = pyi_buf[rc_sub_start + rc_si]
|
||
rc_sub_buf[rc_sub_len] = '\0'
|
||
|
||
# 构建完整子模块名 base_mod.X
|
||
rc_full_len: t.CSizeT = string.strlen(base_mod) + 1 + rc_sub_len + 1
|
||
rc_full_mod: str = pool.alloc(rc_full_len)
|
||
if rc_full_mod is None:
|
||
continue
|
||
viperlib.snprintf(rc_full_mod, rc_full_len, "%s.%s", base_mod, rc_sub_buf)
|
||
|
||
# 构建临时 from_imports "name:full_mod"
|
||
rc_fi_len: t.CSizeT = name_len_rc + 1 + string.strlen(rc_full_mod) + 1
|
||
rc_fi: str = pool.alloc(rc_fi_len)
|
||
if rc_fi is None:
|
||
continue
|
||
viperlib.snprintf(rc_fi, rc_fi_len, "%s:%s", name, rc_full_mod)
|
||
|
||
# 递归调用查找子模块
|
||
rc_sub_val: int = _lookup_cross_module_cdefine(pool, name, rc_fi)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
result_val = rc_sub_val
|
||
result_found = 1
|
||
|
||
stdlib.free(pyi_buf)
|
||
|
||
# 9.6 from_imports star fallback 模块中未找到:回退到 imported_modules 遍历
|
||
# 当 `from stdint import *` 导致 star fallback 返回 stdint,但目标常量
|
||
# (如 SHARE_READ)实际在 `import w32.fileio` 导入的模块中时,
|
||
# 需要遍历 imported_modules 逐个查找
|
||
if result_found == 0 and imported_modules is not None:
|
||
im2_len: t.CSizeT = string.strlen(imported_modules)
|
||
im2_ci: t.CSizeT = 0
|
||
while im2_ci < im2_len and result_found == 0:
|
||
while im2_ci < im2_len and imported_modules[im2_ci] == ' ':
|
||
im2_ci += 1
|
||
if im2_ci >= im2_len:
|
||
break
|
||
im2_start: t.CSizeT = im2_ci
|
||
while im2_ci < im2_len and imported_modules[im2_ci] != ' ':
|
||
im2_ci += 1
|
||
im2_end: t.CSizeT = im2_ci
|
||
im2_nlen: t.CSizeT = im2_end - im2_start
|
||
if im2_nlen > 0 and im2_nlen < 256:
|
||
im2_buf: str = pool.alloc(im2_nlen + 1)
|
||
if im2_buf is not None:
|
||
mk3: t.CSizeT = 0
|
||
while mk3 < im2_nlen:
|
||
im2_buf[mk3] = imported_modules[im2_start + mk3]
|
||
mk3 += 1
|
||
im2_buf[im2_nlen] = '\0'
|
||
sub_fi2: str = pool.alloc(im2_nlen + 3)
|
||
if sub_fi2 is not None:
|
||
sub_fi2[0] = '*'
|
||
sub_fi2[1] = ':'
|
||
mk4: t.CSizeT = 0
|
||
while mk4 < im2_nlen:
|
||
sub_fi2[2 + mk4] = im2_buf[mk4]
|
||
mk4 += 1
|
||
sub_fi2[2 + im2_nlen] = '\0'
|
||
sub_val2: int = _lookup_cross_module_cdefine(pool, name, sub_fi2, None)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
result_val = sub_val2
|
||
result_found = 1
|
||
|
||
# 10. 缓存到当前模块的 CDefine 表中
|
||
if result_found != 0:
|
||
HandlesType.register_cdefine_constant(pool, name, result_val)
|
||
HandlesType.set_cdefine_found(1)
|
||
else:
|
||
HandlesType.set_cdefine_found(0)
|
||
|
||
return result_val
|
||
|
||
|
||
# ============================================================
|
||
# _is_cdefine_name_pattern - 检查名字是否符合 CDefine 命名约定
|
||
#
|
||
# CDefine 常量(如 FOREGROUND_GREEN, STD_OUTPUT_HANDLE, SCOPE_MODULE)
|
||
# 都遵循 ALL_CAPS 约定:仅含大写字母 A-Z、数字 0-9、下划线 _,
|
||
# 且至少含一个大写字母。
|
||
#
|
||
# Python 关键字(match, if, for)和变量名(self, pool, builder)
|
||
# 都含小写字母,不会匹配,从而避免 fail-fast 误报。
|
||
#
|
||
# 返回: 1=符合 CDefine 命名约定, 0=不符合
|
||
# ============================================================
|
||
def _is_cdefine_name_pattern(name: str) -> int:
|
||
"""检查名字是否符合 CDefine 命名约定(全大写+下划线+数字)"""
|
||
if name is None:
|
||
return 0
|
||
has_upper: int = 0
|
||
i: t.CSizeT = 0
|
||
while name[i] != '\0':
|
||
c: t.CChar = name[i]
|
||
if c >= 'a' and c <= 'z':
|
||
return 0
|
||
if c >= 'A' and c <= 'Z':
|
||
has_upper = 1
|
||
i += 1
|
||
return has_upper
|
||
|
||
|
||
# ============================================================
|
||
# 翻译变量引用(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)
|
||
|
||
# 本地表未找到:尝试跨模块 .vpi 查找(保证多模块查表存表一致)
|
||
# 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找,
|
||
# 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗
|
||
if _is_cdefine_name_pattern(nm_id) != 0:
|
||
if trans is not None:
|
||
cdef_val = _lookup_cross_module_cdefine(
|
||
pool, nm_id, trans._from_imports, trans._imported_modules)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
return llvmlite.const_int32(pool, cdef_val)
|
||
|
||
# global 变量:从模块作用域查找(global 声明优先级最高)
|
||
if trans is not None:
|
||
if HT.is_global_name(trans, nm_id) != 0:
|
||
mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
|
||
trans.SymTab, nm_id)
|
||
if mod_alloca is not None:
|
||
load_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if mod_alloca.Ty is not None:
|
||
load_ty = mod_alloca.Ty.Pointee
|
||
if load_ty is None:
|
||
load_ty = llvmlite.Int32(pool)
|
||
return llvmlite.build_load(builder, load_ty, mod_alloca)
|
||
|
||
# nonlocal 变量:通过闭包 env 访问
|
||
if HT.is_nonlocal_name(trans, nm_id) != 0:
|
||
return HandlesNonlocal.load_nonlocal_var(trans, nm_id)
|
||
|
||
# 局部变量查找(必须先于模块别名检查)
|
||
# 否则与模块同名的局部变量(如 `import t, c` 后的局部变量 c)会被误判为模块别名,
|
||
# 导致 SymTab 已注册的局部变量查找不到(rhs_val is None bug 根因)
|
||
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm_id)
|
||
if alloca is not None:
|
||
load_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if alloca.Ty is not None:
|
||
load_ty = alloca.Ty.Pointee
|
||
if load_ty is None:
|
||
load_ty = llvmlite.Int32(pool)
|
||
# 结构体值变量(alloca 类型为 Struct,如 `x: Cls | t.CPtr`):
|
||
# 按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值。
|
||
# 结构体值无法参与 ptrtoint/方法调用等地址相关操作,加载值会导致
|
||
# `ptrtoint %Struct ... to i64` 无效指令(llc invalid cast opcode)。
|
||
match load_ty:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
return alloca
|
||
return llvmlite.build_load(builder, load_ty, alloca)
|
||
|
||
# 模块别名检查:SymTab 查找失败后才检查
|
||
# 如果 nm_id 是已导入模块名(如 win32file, fileio)且未被声明为局部变量,
|
||
# 返回 None 让上层处理(用于属性访问 win32file.CreateFileA)
|
||
if trans is not None and trans._imported_modules is not None:
|
||
if HandlesImports.is_module_imported(trans._imported_modules, nm_id) != 0:
|
||
return None
|
||
|
||
# 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。
|
||
# 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移
|
||
# (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。
|
||
# 注意:不能直接返回 Function 对象,也不能直接 build_bitcast(Function)——
|
||
# Function 布局是 {Next, Name, RetTy, Params, ...},value_get_ty 会错位读到
|
||
# Name 字段,TypePrint 输出 "void",生成 `bitcast void ... to i8*` 非法 IR;
|
||
# 且 Function.Next 是模块函数链表指针,参数链表构建对其赋值会截断函数链表,
|
||
# 最终打印出 `declare void @()` 空名函数。正确做法:按 Function 的
|
||
# RetTy/Params 构造真实函数类型,用 new_value 包装成普通 Value 再 bitcast。
|
||
if trans is not None and trans.Module is not None:
|
||
fn_ref: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(
|
||
trans.Module, nm_id)
|
||
if fn_ref is not None:
|
||
fn_name: t.CChar | t.CPtr = llvmlite.function_get_name(fn_ref)
|
||
if fn_name is None:
|
||
return None
|
||
# 构造函数类型:ret_ty + 参数 ParamNode 链表
|
||
fn_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fn_ref)
|
||
if fn_ret_ty is None:
|
||
fn_ret_ty = llvmlite.Int32(pool)
|
||
fn_pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(fn_ref)
|
||
fn_first_node: llvmlite.ParamNode | t.CPtr = None
|
||
fn_prev_node: llvmlite.ParamNode | t.CPtr = None
|
||
fn_pcount: int = 0
|
||
while fn_pp is not None:
|
||
fn_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fn_pp)
|
||
fn_pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, fn_pty)
|
||
if fn_pn is not None:
|
||
if fn_first_node is None:
|
||
fn_first_node = fn_pn
|
||
if fn_prev_node is not None:
|
||
llvmlite.paramnode_set_next(fn_prev_node, fn_pn)
|
||
fn_prev_node = fn_pn
|
||
fn_pcount += 1
|
||
fn_pp = llvmlite.param_get_next(fn_pp)
|
||
fn_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(
|
||
pool, fn_ret_ty, fn_first_node, fn_pcount)
|
||
if fn_ty is None:
|
||
return None
|
||
# 构造函数指针 Value(new_value 包装,避免触碰 Function.Next)
|
||
fn_ref_v: llvmlite.Value | t.CPtr = llvmlite.new_value(pool)
|
||
if fn_ref_v is None:
|
||
return None
|
||
llvmlite.value_set_ty(fn_ref_v, llvmlite.Ptr(pool, fn_ty))
|
||
llvmlite.value_set_isconst(fn_ref_v, 1)
|
||
fn_ref_name: t.CChar | t.CPtr = pool.alloc(256)
|
||
if fn_ref_name is not None:
|
||
fn_ref_name[0] = '\0'
|
||
if HandlesClassDef._vtable_name_needs_quote(fn_name) != 0:
|
||
viperlib.snprintf(fn_ref_name, 256, "@\"%s\"", fn_name)
|
||
else:
|
||
viperlib.snprintf(fn_ref_name, 256, "@%s", fn_name)
|
||
llvmlite.value_set_name(fn_ref_v, fn_ref_name)
|
||
fn_i8ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, llvmlite.Int8(pool))
|
||
return llvmlite.build_bitcast(builder, fn_ref_v, fn_i8ptr_ty)
|
||
|
||
# 所有查找路径均失败
|
||
# fail-fast: 仅对符合 CDefine 命名约定(ALL_CAPS)的名字报错
|
||
# 避免对 match/self/pool 等关键字和变量名误报
|
||
# 跨模块 CDefine 查找已在上方完成,此处不重复
|
||
if _is_cdefine_name_pattern(nm_id) != 0:
|
||
err_buf2: str = pool.alloc(256)
|
||
if err_buf2 is not None:
|
||
cur_sha1: str = "(unknown)"
|
||
if trans is not None and trans.ModuleSha1 is not None:
|
||
cur_sha1 = trans.ModuleSha1
|
||
viperlib.snprintf(err_buf2, 256,
|
||
"[CD] FATAL: Name '%s' NOT found (CDefine local+cross + global + nonlocal + alloca + module alias) in module sha1=%s\n",
|
||
nm_id, cur_sha1)
|
||
VLogger.error(err_buf2, "CD")
|
||
return None
|
||
|
||
|
||
# ============================================================
|
||
# 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,
|
||
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)"""
|
||
if builder is None or pool is None or lm_obj is None or idx_val is None:
|
||
return None
|
||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
# 加载 __data__ (偏移 0, index 0)
|
||
g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
|
||
g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0)
|
||
if g_dpp is None:
|
||
return None
|
||
g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp)
|
||
# 加载 __elem_size__ (偏移 32, index 4)
|
||
g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4)
|
||
g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4)
|
||
if g_epp is None:
|
||
return None
|
||
g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp)
|
||
if g_data is None or g_esize is None:
|
||
return None
|
||
g_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty, node)
|
||
if g_idx_i64 is None:
|
||
return None
|
||
g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize)
|
||
if g_offset is None:
|
||
return None
|
||
# 返回元素地址 (i8*),不 load
|
||
return llvmlite.build_gep(builder, i8_ty, g_data, g_offset)
|
||
|
||
|
||
# ============================================================
|
||
# _list_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,
|
||
node: ast.AST | t.CPtr = None) -> int:
|
||
"""内联生成 list __setitem__ 逻辑,返回 0"""
|
||
if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None:
|
||
return 0
|
||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
# 加载 __data__ (偏移 0, index 0)
|
||
s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0)
|
||
s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0)
|
||
if s_dpp is None:
|
||
return 0
|
||
s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp)
|
||
# 加载 __elem_size__ (偏移 32, index 4)
|
||
s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4)
|
||
s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4)
|
||
if s_epp is None:
|
||
return 0
|
||
s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp)
|
||
if s_data is None or s_esize is None:
|
||
return 0
|
||
s_idx_i64: llvmlite.Value | t.CPtr = coerce_to_type(builder, idx_val, i64_ty, node)
|
||
if s_idx_i64 is None:
|
||
return 0
|
||
s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize)
|
||
if s_offset is None:
|
||
return 0
|
||
s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset)
|
||
if s_addr is None:
|
||
return 0
|
||
s_val_ptr: llvmlite.Value | t.CPtr = coerce_to_type(builder, rhs_val, i8_ptr_ty, node)
|
||
if s_val_ptr is None:
|
||
return 0
|
||
llvmlite.build_store(builder, s_val_ptr, s_addr)
|
||
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 not None and alloca.Ty is not None:
|
||
if is_ptr_type(alloca.Ty) != 0:
|
||
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||
if pointee is not None:
|
||
# 不调用 pointee.kind() 避免跨模块引用 LLVMType.kind 符号
|
||
# 用 match 检查 pointee 类型
|
||
match pointee:
|
||
case llvmlite.LLVMType.Array(elem_ty, count):
|
||
# 数组遍历: getelementptr [N x elem_ty], ... , i32 0, i32 %idx
|
||
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||
builder, pointee, elem_ty, alloca, idx_val)
|
||
if elem_ptr is not None:
|
||
return llvmlite.build_load(builder, elem_ty, elem_ptr)
|
||
return None
|
||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||
# 检查 inner_ty 是否是 list[T] 类型(泛型类不注册 struct)
|
||
# list 的 subscript 应该走 __getitem__ 内联路径,而非指针遍历
|
||
list_struct_name: str = None
|
||
match inner_ty:
|
||
case llvmlite.LLVMType.Struct(_, _, lsn):
|
||
list_struct_name = lsn
|
||
case _:
|
||
pass
|
||
if list_struct_name is not None:
|
||
if string.strstr(list_struct_name, "list[") is not None:
|
||
# list[T] 类型: 内联生成 __getitem__ 逻辑
|
||
ptr_val_list: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val_list is not None:
|
||
elem_addr_list: llvmlite.Value | t.CPtr = list_getitem_inline(
|
||
builder, pool, ptr_val_list, idx_val, node)
|
||
if elem_addr_list is not None:
|
||
# 根据类型名提取元素类型,bitcast 后 load
|
||
elem_ty_list: llvmlite.LLVMType | t.CPtr = _list_elem_type_from_name(
|
||
pool, list_struct_name)
|
||
if elem_ty_list is not None:
|
||
elem_ptr_ty_list: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, elem_ty_list)
|
||
casted_addr_list: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, elem_addr_list, elem_ptr_ty_list)
|
||
if casted_addr_list is not None:
|
||
return llvmlite.build_load(
|
||
builder, elem_ty_list, casted_addr_list)
|
||
return None
|
||
# inner_ty 是 Ptr 说明 alloca.Ty 是三重指针 Ptr(Ptr(Ptr(...))),
|
||
# 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。
|
||
# 此时 [i] 应该是指针解引用 (步长 sizeof(ptr)=8), 而非调用
|
||
# 结构体的 __getitem__ 方法 (会错误生成 AST.__getitem__ 调用)。
|
||
# 对比 HashTable|t.CPtr: alloca.Ty=HashTable**, inner_ty=Struct(HashTable)
|
||
# (非 Ptr), 仍走下面的方法调用转发路径。
|
||
if is_ptr_type(inner_ty) != 0:
|
||
ptr_val_pp: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val_pp is not None:
|
||
elem_ptr_pp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, inner_ty, ptr_val_pp, idx_val)
|
||
if elem_ptr_pp is not None:
|
||
return llvmlite.build_load(builder, inner_ty, elem_ptr_pp)
|
||
return None
|
||
# 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr):
|
||
# 优先转发到 __getitem__,避免 IsPtrElement 误判为指针遍历
|
||
cls_nm_rd_ptr: str = _get_custom_struct_cls_nm(pool, inner_ty)
|
||
if not (cls_nm_rd_ptr is None):
|
||
obj_ptr_rd: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if not (obj_ptr_rd is None):
|
||
arg_vals_rd_p: t.CSizeT | t.CPtr = pool.alloc(8)
|
||
if not (arg_vals_rd_p is None):
|
||
arg_vals_rd_p[0] = t.CSizeT(idx_val)
|
||
ret_rd_p: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr(
|
||
pool, builder, mod, cls_nm_rd_ptr, "__getitem__",
|
||
obj_ptr_rd, arg_vals_rd_p, 1, trans)
|
||
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 _is_t_type_object_name(name: str) -> int:
|
||
"""检查 name 是否是 t.py 中的类型对象名(CPtr/CInt/CDouble 等)
|
||
|
||
这些类型对象在运行时作为全局变量 @CPtr/@CInt 等被引用,
|
||
但 t.py 不被编译,需要在使用处生成带 null 初值的定义。
|
||
"""
|
||
if name is None:
|
||
return 0
|
||
# t.py 中的类型对象名(PascalCase,首字母大写)
|
||
if string.strcmp(name, "CPtr") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CInt") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CChar") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CShort") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CLong") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CLongLong") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CDouble") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CFloat") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CBool") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CVoid") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CInt8T") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CInt16T") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CInt32T") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CInt64T") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CUInt8T") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CUInt16T") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CUInt32T") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CUInt64T") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CUnsigned") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CUnsignedInt") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CUnsignedChar") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CUnsignedShort") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CUnsignedLong") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CUnsignedLongLong") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CSizeT") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CIntPtrT") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CUIntPtrT") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CPtrDiffT") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CType") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CDefine") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CStatic") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CExport") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CArray") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CTypedef") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CNoVTable") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CNeedPtr") == 0:
|
||
return 1
|
||
if string.strcmp(name, "CAutoPtr") == 0:
|
||
return 1
|
||
return 0
|
||
|
||
|
||
def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
at: ast.Attribute | t.CPtr,
|
||
ty_hint: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""解析模块属性访问,返回全局变量引用 (用于跨模块 global 访问)"""
|
||
if at is None or at.value is None or at.attr is None:
|
||
return None
|
||
if at.value.kind() != ast.ASTKind.Name:
|
||
return None
|
||
if trans is None or trans._imported_modules is None:
|
||
return None
|
||
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if mod_nm.id is None:
|
||
return None
|
||
# 检查是否是已导入模块
|
||
if HandlesImports.is_module_imported(trans._imported_modules, mod_nm.id) == 0:
|
||
return None
|
||
# 在当前模块查找全局变量 (stub 可能已注入)
|
||
gv: llvmlite.GlobalVariable | t.CPtr = find_global_in_module(mod, at.attr)
|
||
if gv is not None and gv.Ty is not None:
|
||
return make_global_ref(pool, at.attr, gv.Ty)
|
||
# 未找到: 创建 external global 声明并添加到模块
|
||
# 否则只生成 @_argc 引用而无声明,LLVM 报 "use of undefined value '@_argc'"
|
||
use_ty: llvmlite.LLVMType | t.CPtr = ty_hint
|
||
if use_ty is None:
|
||
use_ty = llvmlite.Int8(pool)
|
||
# 确保 use_ty 中的跨模块结构体类型有 opaque 声明
|
||
llvmlite.module_ensure_opaque_for_type(mod, pool, use_ty)
|
||
# 特殊处理: t.py 中的类型对象(CPtr/CInt/CDouble 等)
|
||
# t.py 不被编译,但这些类型对象在运行时被引用(如 va_arg(ap, t.CPtr))。
|
||
# 创建带 null 初值的 linkonce_odr 全局变量定义,避免链接时 undefined reference。
|
||
# LLVM 22+ 不允许 external linkage 全局变量带初值,使用 linkonce_odr 替代。
|
||
is_t_type_obj: int = 0
|
||
if string.strcmp(mod_nm.id, "t") == 0:
|
||
is_t_type_obj = _is_t_type_object_name(at.attr)
|
||
ext_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, at.attr, use_ty)
|
||
if ext_gv is not None:
|
||
if is_t_type_obj != 0:
|
||
# t.CPtr 等类型对象: 创建带 null 初值的定义(linkonce_odr)
|
||
ext_gv.Linkage = "linkonce_odr"
|
||
# i8* null 的初值文本
|
||
null_init: bytes = pool.alloc(8)
|
||
if null_init is not None:
|
||
null_init[0] = 'n'
|
||
null_init[1] = 'u'
|
||
null_init[2] = 'l'
|
||
null_init[3] = 'l'
|
||
null_init[4] = '\0'
|
||
ext_gv.Initializer = null_init
|
||
else:
|
||
ext_gv.Initializer = None
|
||
else:
|
||
# 普通模块属性: external 声明(由其他模块提供定义)
|
||
ext_gv.Linkage = "external"
|
||
ext_gv.Initializer = None
|
||
llvmlite.module_add_global(mod, ext_gv)
|
||
return make_global_ref(pool, at.attr, use_ty)
|
||
|
||
|
||
# ============================================================
|
||
# 翻译属性访问 Attribute(value, attr, ctx) — obj.field
|
||
#
|
||
# 优先级:
|
||
# 1. 枚举成员访问 (State.Idle → 常量值)
|
||
# 2. 模块属性访问 (sys._mbuddy → 加载全局变量)
|
||
# 3. 结构体字段访问 (obj.field → GEP + load)
|
||
#
|
||
# 对于 Name 类型的 obj,直接使用 alloca 指针(不 load 结构体)
|
||
# ============================================================
|
||
def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""翻译属性访问,返回加载的字段值"""
|
||
if node is None or builder is None:
|
||
return None
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||
if at is None or at.value is None or at.attr is None:
|
||
# fast-fail: AST 节点字段缺失属解析器 bug,应报告具体缺失字段
|
||
diag_buf_an: bytes = stdlib.malloc(256)
|
||
if diag_buf_an is not None:
|
||
missing_an: str = "?"
|
||
if at is not None:
|
||
if at.value is None:
|
||
missing_an = "value"
|
||
elif at.attr is None:
|
||
missing_an = "attr"
|
||
viperlib.snprintf(diag_buf_an, 256,
|
||
"属性访问失败: AST 节点字段缺失 (%s sha1=%s:%d)",
|
||
missing_an,
|
||
trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?",
|
||
at.lineno if at is not None and at.lineno is not None else 0)
|
||
VLogger.error(diag_buf_an, "ATTR")
|
||
return None
|
||
|
||
# 枚举成员访问: EnumName.MemberName → 常量值
|
||
# 当 value 是 Name 且 Name.id 是已注册枚举时,查找成员并返回常量
|
||
if at.value.kind() == ast.ASTKind.Name:
|
||
enum_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if enum_nm.id is not None:
|
||
if HandlesEnum.is_enum_class(enum_nm.id) == 1:
|
||
member: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member(
|
||
enum_nm.id, at.attr)
|
||
if member is not None:
|
||
base_ty: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type(
|
||
enum_nm.id)
|
||
if base_ty is not None:
|
||
# 生成数字字符串作为常量名(LLVM IR 要求常量输出数字值)
|
||
name_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||
if name_buf is not None:
|
||
viperlib.snprintf(name_buf, 32, "%lld", member.Value)
|
||
return llvmlite.ConstInt(pool, base_ty, member.Value, name_buf)
|
||
return llvmlite.const_int32(pool, member.Value)
|
||
# fast-fail: 枚举成员未找到
|
||
VLogger.error(
|
||
f"枚举成员未找到: {enum_nm.id}.{at.attr}",
|
||
"ATTR")
|
||
return None
|
||
|
||
# 嵌套枚举成员访问: Module.EnumName.MemberName → 常量值
|
||
# 当 value 是 Attribute(如 fileio.MODE)且 attr 部分是已注册枚举时
|
||
if at.value.kind() == ast.ASTKind.Attribute:
|
||
inner_at_e: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value)
|
||
if inner_at_e.value is not None and inner_at_e.value.kind() == ast.ASTKind.Name:
|
||
inner_nm_e: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_at_e.value)
|
||
if inner_nm_e.id is not None and inner_at_e.attr is not None:
|
||
if HandlesEnum.is_enum_class(inner_at_e.attr) == 1:
|
||
member_e: HandlesEnum.EnumMember | t.CPtr = HandlesEnum.lookup_enum_member(
|
||
inner_at_e.attr, at.attr)
|
||
if member_e is not None:
|
||
base_ty_e: llvmlite.LLVMType | t.CPtr = HandlesEnum.get_enum_base_type(
|
||
inner_at_e.attr)
|
||
if base_ty_e is not None:
|
||
name_buf_e: t.CChar | t.CPtr = pool.alloc(32)
|
||
if name_buf_e is not None:
|
||
viperlib.snprintf(name_buf_e, 32, "%lld", member_e.Value)
|
||
return llvmlite.ConstInt(pool, base_ty_e, member_e.Value, name_buf_e)
|
||
return llvmlite.const_int32(pool, member_e.Value)
|
||
# fast-fail: 嵌套枚举成员未找到
|
||
VLogger.error(
|
||
f"嵌套枚举成员未找到: {inner_at_e.attr}.{at.attr}",
|
||
"ATTR")
|
||
return None
|
||
|
||
# 模块属性访问 (读路径): sys._mbuddy → 加载全局变量 @_mbuddy
|
||
# 当 obj 是已导入模块名且不是普通变量时,查找/创建全局变量引用并加载
|
||
if at.value.kind() == ast.ASTKind.Name and trans is not None:
|
||
nm_ma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if nm_ma.id is not None:
|
||
# 先检查是否是普通变量 (优先级高于模块属性)
|
||
ma_is_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
trans.SymTab, nm_ma.id)
|
||
if ma_is_var is None:
|
||
# 先检查是否是 CDefine 编译期常量 (如 ast.CONST_INT / win32base.INVALID_HANDLE_VALUE)
|
||
# 模块属性访问的 CDefine 常量需要跨模块查找源 .vp / .vpi 文件
|
||
cdef_ma_val: int = HandlesType.lookup_cdefine_constant(at.attr)
|
||
cd_local: int = HandlesType.is_cdefine_found()
|
||
if cd_local == 0:
|
||
# 确定真实模块名:优先从 _from_imports 解析别名
|
||
# from_imports 中条目格式 "local_name:real_module"
|
||
# 如 win32base:w32.win32base → 别名 win32base 真实模块 w32.win32base
|
||
real_mod_name: str = nm_ma.id
|
||
if trans._from_imports is not None:
|
||
resolved_mod: str = HandlesImports.lookup_from_import(
|
||
trans._from_imports, nm_ma.id, 0)
|
||
if resolved_mod is not None:
|
||
# 复制模块名到新缓冲区(截断于空格、null、或 ':')
|
||
rm_len: t.CSizeT = 0
|
||
while resolved_mod[rm_len] != ' ' and resolved_mod[rm_len] != '\0' and resolved_mod[rm_len] != ':':
|
||
rm_len += 1
|
||
rm_buf: str = pool.alloc(rm_len + 1)
|
||
if rm_buf is not None:
|
||
for rm_i in range(rm_len):
|
||
rm_buf[rm_i] = resolved_mod[rm_i]
|
||
rm_buf[rm_len] = '\0'
|
||
real_mod_name = rm_buf
|
||
# 即使 _from_imports 为 None(如纯 `import ast` 无 from-import),
|
||
# 也必须尝试跨模块 CDefine 查找,否则 ast.CONST_INT 会被
|
||
# 误解析为全局变量引用 @CONST_INT(未定义符号)。
|
||
# 构建临时 from_imports "{attr}:{real_module}" 用于跨模块查找
|
||
if real_mod_name is not None:
|
||
ma_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(real_mod_name) + 2
|
||
ma_fi: str = pool.alloc(ma_fi_len)
|
||
if ma_fi is not None:
|
||
viperlib.snprintf(ma_fi, ma_fi_len, "%s:%s", at.attr, real_mod_name)
|
||
cdef_ma_val = _lookup_cross_module_cdefine(pool, at.attr, ma_fi)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
return llvmlite.const_int32(pool, cdef_ma_val)
|
||
# 检查 nm_ma.id.at.attr 是否是已导入子模块 (如 w32.win32file)
|
||
# 如果是子模块,不应创建全局变量,让嵌套属性访问路径处理
|
||
is_submod: int = 0
|
||
if trans._imported_modules is not None:
|
||
submod_len: t.CSizeT = string.strlen(nm_ma.id) + string.strlen(at.attr) + 2
|
||
submod_buf: t.CChar | t.CPtr = pool.alloc(submod_len)
|
||
if submod_buf is not None:
|
||
viperlib.snprintf(submod_buf, submod_len, "%s.%s", nm_ma.id, at.attr)
|
||
if HandlesImports.is_module_imported(trans._imported_modules, submod_buf) == 1:
|
||
is_submod = 1
|
||
# also check from_imports: at.attr 别名对应真实模块 w32.win32file
|
||
if is_submod == 0 and trans._from_imports is not None:
|
||
fi_mod_raw: str = HandlesImports.lookup_from_import(
|
||
trans._from_imports, at.attr, 0)
|
||
if fi_mod_raw is not None:
|
||
# 复制模块名到新缓冲区(截断于空格、null、或 ':')
|
||
fm_len: t.CSizeT = 0
|
||
while fi_mod_raw[fm_len] != ' ' and fi_mod_raw[fm_len] != '\0' and fi_mod_raw[fm_len] != ':':
|
||
fm_len += 1
|
||
fi_mod: str = pool.alloc(fm_len + 1)
|
||
if fi_mod is not None:
|
||
for fm_i in range(fm_len):
|
||
fi_mod[fm_i] = fi_mod_raw[fm_i]
|
||
fi_mod[fm_len] = '\0'
|
||
# 检查 fi_mod 是否以 "nm_ma.id." 开头 (如 w32.win32file 以 w32. 开头)
|
||
prefix_len: t.CSizeT = string.strlen(nm_ma.id)
|
||
fi_mod_len: t.CSizeT = string.strlen(fi_mod)
|
||
if fi_mod_len > prefix_len + 1:
|
||
match_prefix: int = 1
|
||
for pi in range(prefix_len):
|
||
if fi_mod[pi] != nm_ma.id[pi]:
|
||
match_prefix = 0
|
||
break
|
||
if match_prefix == 1 and fi_mod[prefix_len] == '.':
|
||
is_submod = 1
|
||
if is_submod != 0:
|
||
return None # 是子模块,交给嵌套属性访问路径
|
||
# 特殊处理: t.ASM_DESCR 不是 CDefine,是内联汇编约束命名空间
|
||
# t.ASM_DESCR.XXX 由 HandlesExprCall 的 _asm_resolve_constraint 处理
|
||
# 此处返回 None,让上层嵌套属性访问路径处理
|
||
if string.strcmp(nm_ma.id, "t") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0:
|
||
return None
|
||
# CDefine 未找到且属性名符合 ALL_CAPS 约定: 报 FATAL 错误
|
||
# 不再创建未定义的外部全局变量引用(否则 llc 报 "use of undefined value")
|
||
if _is_cdefine_name_pattern(at.attr) != 0:
|
||
err_buf_sma: str = pool.alloc(256)
|
||
if err_buf_sma is not None:
|
||
cur_sha1_sma: str = "(unknown)"
|
||
if trans is not None and trans.ModuleSha1 is not None:
|
||
cur_sha1_sma = trans.ModuleSha1
|
||
viperlib.snprintf(err_buf_sma, 256,
|
||
"[CD] FATAL: Module attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n",
|
||
nm_ma.id, at.attr, cur_sha1_sma)
|
||
VLogger.error(err_buf_sma, "CD")
|
||
return None
|
||
# 非 CDefine: 使用 i8* 作为类型提示 (模块级变量通常存储指针)
|
||
i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
mod_gv_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global(
|
||
pool, mod, trans, at, i8_ptr_hint)
|
||
if mod_gv_ref is not None and mod_gv_ref.Ty is not None:
|
||
load_ty_mod: llvmlite.LLVMType | t.CPtr = mod_gv_ref.Ty.Pointee
|
||
if load_ty_mod is not None:
|
||
return llvmlite.build_load(builder, load_ty_mod, mod_gv_ref)
|
||
|
||
# 嵌套模块属性访问 (w32.win32file.GENERIC_READ → 查找全局 @GENERIC_READ)
|
||
# 当 at.value 是 Attribute 且解析为已导入子模块时,查找 at.attr 作为全局常量
|
||
if at.value.kind() == ast.ASTKind.Attribute and trans is not None:
|
||
inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value)
|
||
if inner_at.value is not None and inner_at.value.kind() == ast.ASTKind.Name:
|
||
inner_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_at.value)
|
||
if inner_nm.id is not None and inner_at.attr is not None:
|
||
if HandlesVar.lookup_var(trans.SymTab, inner_nm.id) is None:
|
||
# 构建限定模块名: "w32.win32file"
|
||
qual_len: t.CSizeT = string.strlen(inner_nm.id) + string.strlen(inner_at.attr) + 2
|
||
qual_buf: t.CChar | t.CPtr = pool.alloc(qual_len)
|
||
if qual_buf is not None:
|
||
viperlib.snprintf(qual_buf, qual_len, "%s.%s", inner_nm.id, inner_at.attr)
|
||
if HandlesImports.is_module_imported(trans._imported_modules, qual_buf) == 1:
|
||
# 查找全局变量 at.attr (stub 已注入的情况)
|
||
gv_nested: llvmlite.GlobalVariable | t.CPtr = find_global_in_module(mod, at.attr)
|
||
if gv_nested is not None and gv_nested.Ty is not None:
|
||
gv_ref_nested: llvmlite.Value | t.CPtr = make_global_ref(
|
||
pool, at.attr, gv_nested.Ty)
|
||
if gv_ref_nested is not None and gv_ref_nested.Ty is not None:
|
||
load_ty_nested: llvmlite.LLVMType | t.CPtr = gv_ref_nested.Ty.Pointee
|
||
if load_ty_nested is not None:
|
||
return llvmlite.build_load(builder, load_ty_nested, gv_ref_nested)
|
||
# 未找到全局: 尝试 CDefine 常量查找
|
||
# 对于 w32.win32base.INVALID_HANDLE_VALUE 等嵌套模块属性访问,
|
||
# 先从限定模块的 .vpi 文件中查找 CDefine 常量值并内联
|
||
cdef_val_nested: int = HandlesType.lookup_cdefine_constant(at.attr)
|
||
if HandlesType.is_cdefine_found() == 0:
|
||
# 构建临时 from_imports "attr:module" 用于跨模块查找
|
||
tmp_fi_len: t.CSizeT = string.strlen(at.attr) + string.strlen(qual_buf) + 2
|
||
tmp_fi: str = pool.alloc(tmp_fi_len)
|
||
if tmp_fi is not None:
|
||
viperlib.snprintf(tmp_fi, tmp_fi_len, "%s:%s", at.attr, qual_buf)
|
||
cdef_val_nested = _lookup_cross_module_cdefine(pool, at.attr, tmp_fi)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
return llvmlite.const_int32(pool, cdef_val_nested)
|
||
# CDefine 未找到: 报 FATAL 错误(不再创建未定义的全局变量引用)
|
||
# 之前此处创建 @INVALID_HANDLE_VALUE 等前向引用,但全局未定义,
|
||
# 导致 llc 报 "use of undefined value" 错误。
|
||
# 正确做法是报错终止,让开发者修复跨模块 CDefine 查找失败的根本原因。
|
||
if _is_cdefine_name_pattern(at.attr) != 0:
|
||
err_buf_ma: str = pool.alloc(256)
|
||
if err_buf_ma is not None:
|
||
cur_sha1_ma: str = "(unknown)"
|
||
if trans is not None and trans.ModuleSha1 is not None:
|
||
cur_sha1_ma = trans.ModuleSha1
|
||
viperlib.snprintf(err_buf_ma, 256,
|
||
"[CD] FATAL: Nested attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n",
|
||
qual_buf, at.attr, cur_sha1_ma)
|
||
VLogger.error(err_buf_ma, "CD")
|
||
return None
|
||
|
||
# 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体)
|
||
obj_ptr: llvmlite.Value | t.CPtr = None
|
||
if at.value.kind() == ast.ASTKind.Name and trans is not None:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if nm.id is not None:
|
||
obj_ptr = HandlesVar.lookup_var(trans.SymTab, nm.id)
|
||
|
||
# 非 Name 路径:翻译对象值(会 load)
|
||
if obj_ptr is None:
|
||
obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans)
|
||
|
||
if obj_ptr is None or obj_ptr.Ty is None:
|
||
return None
|
||
|
||
# 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca),
|
||
# load 解引用获取 Ptr(Struct)
|
||
obj_ptr = _deref_if_ptr_ptr(builder, obj_ptr)
|
||
|
||
# 查找结构体类型信息
|
||
# obj_ptr 类型应该是 Ptr(Struct(...))
|
||
match obj_ptr.Ty:
|
||
case llvmlite.LLVMType.Ptr(struct_ty):
|
||
# 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段)
|
||
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||
# 查找字段索引和类型
|
||
field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
|
||
struct_ty, at.attr)
|
||
# REnum 变体字段查找: lookup_field 失败时,尝试 REnum 别名
|
||
# REnum 结构体字段名是 _p1/_p2/...,但源码用变体字段名访问(如 ty.Pointee)
|
||
if field_info is None:
|
||
renum_se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(
|
||
struct_ty)
|
||
if renum_se is not None and renum_se.Name is not None:
|
||
is_rn: int = HandlesClassDef._is_renum_class_name(renum_se.Name)
|
||
if is_rn == 1:
|
||
alias_idx: int = HandlesClassDef._lookup_renum_field_alias(
|
||
renum_se.Name, at.attr)
|
||
if alias_idx >= 1:
|
||
alias_fe: HandlesStruct.FieldEntry | t.CPtr = \
|
||
HandlesStruct._get_field_entry(renum_se, alias_idx)
|
||
if alias_fe is not None and alias_fe.Ty is not None:
|
||
alias_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, struct_ty, alias_fe.Ty, obj_ptr, alias_idx)
|
||
if alias_ptr is not None:
|
||
return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr)
|
||
# property getter 回退: obj.attr 是 @property/@x.getter 方法时生成调用
|
||
# (字段未找到时先尝试,避免报误导性的"字段未找到"错误)
|
||
if field_info is None and at.value is not None and trans is not None:
|
||
prop_cls_fb: str = HandlesStruct.get_class_name_by_type(pool, struct_ty)
|
||
prop_val: llvmlite.Value | t.CPtr = HandlesExprCall._try_property_getter_attr(
|
||
pool, builder, mod, at, obj_ptr, trans, prop_cls_fb)
|
||
if prop_val is not None:
|
||
return prop_val
|
||
# 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找
|
||
# 传递 SHA1 以区分跨模块同名类
|
||
if field_info is None:
|
||
if at.value.kind() == ast.ASTKind.Name and trans is not None:
|
||
nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if nm_fb.id is not None:
|
||
var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||
trans.SymTab, nm_fb.id)
|
||
if var_entry is not None and var_entry.AnnotClassName is not None:
|
||
cur_sha1: str = trans.ModuleSha1
|
||
field_info = HandlesStruct.lookup_field_by_class(
|
||
var_entry.AnnotClassName, at.attr, cur_sha1)
|
||
# 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
|
||
# 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)),
|
||
# 需用实际结构体类型做 GEP,否则 GEP i8 失败
|
||
if field_info is not None:
|
||
annot_se: HandlesStruct.StructEntry | t.CPtr = \
|
||
HandlesStruct.find_struct(var_entry.AnnotClassName)
|
||
if annot_se is not None and annot_se.Ty is not None:
|
||
annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \
|
||
llvmlite.Ptr(pool, annot_se.Ty)
|
||
casted_ptr: llvmlite.Value | t.CPtr = \
|
||
llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty)
|
||
if casted_ptr is not None:
|
||
obj_ptr = casted_ptr
|
||
struct_ty = annot_se.Ty
|
||
# 按需过滤更新 struct_ty 后,需重新确保
|
||
# 注解类型结构体定义在当前模块可用
|
||
# (原始 struct_ty 可能是 i8,ensure 无效)
|
||
HandlesStruct.ensure_struct_def_in_module(
|
||
pool, mod, annot_se.Ty)
|
||
if field_info is not None:
|
||
field_ty: llvmlite.LLVMType | t.CPtr = field_info.Ty
|
||
# 联合体:bitcast obj_ptr 到 field_ty* 后 load
|
||
if HandlesStruct.is_union_by_type(struct_ty) == 1:
|
||
field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_ty)
|
||
casted: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, obj_ptr, field_ptr_ty)
|
||
if casted is not None:
|
||
return llvmlite.build_load(builder, field_ty, casted)
|
||
return None
|
||
# 普通结构体:GEP + load
|
||
field_idx: int = field_info.Index
|
||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, struct_ty, field_ty, obj_ptr, field_idx)
|
||
if field_ptr is not None:
|
||
# 数组类型字段不能 load 为 SSA value,直接返回字段指针
|
||
# 用于后续下标访问: self.state[0] → GEP state 字段 → GEP 数组元素
|
||
if is_array_type(field_ty) != 0:
|
||
return field_ptr
|
||
loaded_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, field_ty, field_ptr)
|
||
# 联合类型字段(如 Token | t.CPtr)被编译为 i8*,
|
||
# 若 AnnotClassName 指示了具体结构体类型,bitcast 为正确的结构体指针
|
||
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
|
||
# fast-fail: 字段未找到,打印诊断信息
|
||
if trans is not None:
|
||
diag_annot: str = None
|
||
diag_var_nm: str = None
|
||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||
dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
diag_var_nm = dnm.id
|
||
if dnm.id is not None:
|
||
dve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||
trans.SymTab, dnm.id)
|
||
if dve is not None:
|
||
diag_annot = dve.AnnotClassName
|
||
fb_attr: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||
if fb_attr is not None:
|
||
viperlib.snprintf(fb_attr, 1024,
|
||
"属性访问失败: .%s (var=%s annot=%s sha1=%s:%d)",
|
||
at.attr,
|
||
diag_var_nm if diag_var_nm is not None else "?",
|
||
diag_annot if diag_annot is not None else "None",
|
||
trans.ModuleSha1 if trans.ModuleSha1 is not None else "?",
|
||
at.lineno if at.lineno is not None else 0)
|
||
VLogger.error(fb_attr, "ATTR")
|
||
return None
|
||
case _:
|
||
# fast-fail: 对非指针类型做属性访问(如 i32.x),
|
||
# 静默返回 None 会导致下游 "store to None" 崩溃,丢失错误现场
|
||
diag_buf_ap: bytes = stdlib.malloc(256)
|
||
if diag_buf_ap is not None:
|
||
attr_nm_ap: str = "?"
|
||
if at is not None and at.attr is not None:
|
||
attr_nm_ap = at.attr
|
||
viperlib.snprintf(diag_buf_ap, 256,
|
||
"属性访问失败: .%s (base=非指针类型,无法做属性访问 sha1=%s:%d)",
|
||
attr_nm_ap,
|
||
trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?",
|
||
at.lineno if at is not None and at.lineno is not None else 0)
|
||
VLogger.error(diag_buf_ap, "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 not None and alloca.Ty is not None:
|
||
if is_ptr_type(alloca.Ty) != 0:
|
||
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||
if pointee is not None:
|
||
# 用 match 检查 pointee 类型
|
||
match pointee:
|
||
case llvmlite.LLVMType.Array(elem_ty, count):
|
||
# 数组遍历
|
||
return llvmlite.build_gep_array(
|
||
builder, pointee, elem_ty, alloca, idx_val)
|
||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||
# inner_ty 是 Ptr 说明 alloca.Ty 是三重指针,
|
||
# 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。
|
||
# 此时 [i]=val 应该是指针解引用赋值, 而非调用 __setitem__。
|
||
if is_ptr_type(inner_ty) != 0:
|
||
ptr_val_gsp: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val_gsp is not None:
|
||
return llvmlite.build_gep(
|
||
builder, inner_ty, ptr_val_gsp, idx_val)
|
||
return None
|
||
# 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr):
|
||
# 优先返回 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):
|
||
return None
|
||
# bytes|t.CPtr / str|t.CPtr: alloca 是 i8**,
|
||
# 直接 GEP 按 i8* 步长(8 字节),不 load
|
||
# 仅当 inner_ty 不是自定义结构体时才走指针遍历
|
||
if trans is not None:
|
||
ve_pe: HandlesVar.VarEntry | t.CPtr = \
|
||
HandlesVar.lookup_var_entry(trans.SymTab, nm.id)
|
||
if ve_pe is not None and ve_pe.IsPtrElement == 1:
|
||
return llvmlite.build_gep(
|
||
builder, pointee, alloca, idx_val)
|
||
# 普通指针遍历: 先 load 指针值,再 GEP
|
||
ptr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, pointee, alloca)
|
||
if ptr_val is None:
|
||
return None
|
||
gep_r: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, inner_ty, ptr_val, idx_val)
|
||
return gep_r
|
||
case _:
|
||
# pointee 是普通标量类型 (如 i64, i32, i8):
|
||
# alloca 是 Ptr(标量), 直接 GEP 获取第 idx 个元素指针
|
||
# 支持 arg_vals[i] = val 这类参数数组下标赋值
|
||
return llvmlite.build_gep(builder, pointee, alloca, idx_val)
|
||
|
||
# 通用路径
|
||
ptr_val: llvmlite.Value | t.CPtr = translate_value(
|
||
builder, pool, mod, sub.value, None, 0, trans)
|
||
if ptr_val is None or ptr_val.Ty is None:
|
||
return None
|
||
if is_ptr_type(ptr_val.Ty) != 0:
|
||
elem_ty2: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
|
||
if elem_ty2 is not None:
|
||
# 数组类型: 双索引 GEP (getelementptr [N x ty], ptr, i32 0, i32 idx)
|
||
match elem_ty2:
|
||
case llvmlite.LLVMType.Array(arr_elem_ty, arr_count):
|
||
return llvmlite.build_gep_array(
|
||
builder, elem_ty2, arr_elem_ty, ptr_val, 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):
|
||
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:
|
||
# CDefine 常量不可写: 报 FATAL 错误,不创建未定义全局
|
||
if _is_cdefine_name_pattern(at.attr) != 0:
|
||
err_buf_wma: str = pool.alloc(256)
|
||
if err_buf_wma is not None:
|
||
viperlib.snprintf(err_buf_wma, 256,
|
||
"[CD] FATAL: Cannot assign to CDefine constant '%s.%s'\n",
|
||
nm_wma.id, at.attr)
|
||
VLogger.error(err_buf_wma, "CD")
|
||
return None
|
||
# 使用 i8* 作为类型提示 (模块级变量通常存储指针)
|
||
i8_ptr_w: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
wma_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global(
|
||
pool, mod, trans, at, i8_ptr_w)
|
||
if wma_ref is not None:
|
||
return wma_ref
|
||
|
||
# 非 Name 路径:翻译对象值(会 load)
|
||
if obj_ptr is None:
|
||
obj_ptr = translate_value(builder, pool, mod, at.value, None, 0, trans)
|
||
|
||
if obj_ptr is None or obj_ptr.Ty is None:
|
||
return None
|
||
|
||
# 如果 obj_ptr 是 Ptr(Ptr(Struct))(X|t.CPtr 变量的 alloca),
|
||
# load 解引用获取 Ptr(Struct)
|
||
obj_ptr = _deref_if_ptr_ptr(builder, obj_ptr)
|
||
|
||
match obj_ptr.Ty:
|
||
case llvmlite.LLVMType.Ptr(struct_ty):
|
||
# 确保跨模块结构体的完整定义在当前模块中可用(供 getelementptr 访问字段)
|
||
# 与 translate_attribute 一致,避免 opaque 类型导致 GEP 报错
|
||
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||
field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
|
||
struct_ty, at.attr)
|
||
# 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找
|
||
# 传递 SHA1 以区分跨模块同名类
|
||
if field_info is None:
|
||
if at.value.kind() == ast.ASTKind.Name and trans is not None:
|
||
nm_fb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if nm_fb.id is not None:
|
||
var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||
trans.SymTab, nm_fb.id)
|
||
if var_entry is not None and var_entry.AnnotClassName is not None:
|
||
cur_sha1: str = None
|
||
if trans is not None:
|
||
cur_sha1 = trans.ModuleSha1
|
||
field_info = HandlesStruct.lookup_field_by_class(
|
||
var_entry.AnnotClassName, at.attr, cur_sha1)
|
||
# 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
|
||
# 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)),
|
||
# 需用实际结构体类型做 GEP,否则 GEP i8 失败
|
||
if field_info is not None:
|
||
annot_se: HandlesStruct.StructEntry | t.CPtr = \
|
||
HandlesStruct.find_struct(var_entry.AnnotClassName)
|
||
if annot_se is not None and annot_se.Ty is not None:
|
||
annot_ptr_ty: llvmlite.LLVMType | t.CPtr = \
|
||
llvmlite.Ptr(pool, annot_se.Ty)
|
||
casted_ptr: llvmlite.Value | t.CPtr = \
|
||
llvmlite.build_bitcast(builder, obj_ptr, annot_ptr_ty)
|
||
if casted_ptr is not None:
|
||
obj_ptr = casted_ptr
|
||
struct_ty = annot_se.Ty
|
||
# 按需过滤更新 struct_ty 后,需重新确保
|
||
# 注解类型结构体定义在当前模块可用
|
||
HandlesStruct.ensure_struct_def_in_module(
|
||
pool, mod, annot_se.Ty)
|
||
if field_info is not None:
|
||
# 联合体:bitcast obj_ptr 到 field_ty*(字段指针用于 store)
|
||
if HandlesStruct.is_union_by_type(struct_ty) == 1:
|
||
field_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, field_info.Ty)
|
||
return llvmlite.build_bitcast(builder, obj_ptr, field_ptr_ty)
|
||
# 普通结构体:GEP 获取字段指针
|
||
return llvmlite.build_gep_struct(
|
||
builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index)
|
||
# fast-fail: 字段未找到,打印诊断信息
|
||
if trans is not None:
|
||
diag_annot_g: str = None
|
||
diag_var_nm_g: str = None
|
||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||
dnm_g: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
diag_var_nm_g = dnm_g.id
|
||
if dnm_g.id is not None:
|
||
dve_g: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||
trans.SymTab, dnm_g.id)
|
||
if dve_g is not None:
|
||
diag_annot_g = dve_g.AnnotClassName
|
||
fb_attr_g: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||
if fb_attr_g is not None:
|
||
viperlib.snprintf(fb_attr_g, 1024,
|
||
"属性写入失败: .%s (var=%s annot=%s sha1=%s:%d)",
|
||
at.attr,
|
||
diag_var_nm_g if diag_var_nm_g is not None else "?",
|
||
diag_annot_g if diag_annot_g is not None else "None",
|
||
trans.ModuleSha1 if trans.ModuleSha1 is not None else "?",
|
||
at.lineno if at.lineno is not None else 0)
|
||
VLogger.error(fb_attr_g, "ATTR")
|
||
return None
|
||
case _:
|
||
# fast-fail: 对非指针类型做属性写入(如 i32.x = ...),
|
||
# 静默返回 None 会导致下游 "store to None" 崩溃
|
||
diag_buf_gp: bytes = stdlib.malloc(256)
|
||
if diag_buf_gp is not None:
|
||
attr_nm_gp: str = "?"
|
||
if at is not None and at.attr is not None:
|
||
attr_nm_gp = at.attr
|
||
viperlib.snprintf(diag_buf_gp, 256,
|
||
"属性写入失败: .%s (base=非指针类型,无法做属性写入 sha1=%s:%d)",
|
||
attr_nm_gp,
|
||
trans.ModuleSha1 if trans is not None and trans.ModuleSha1 is not None else "?",
|
||
at.lineno if at is not None and at.lineno is not None else 0)
|
||
VLogger.error(diag_buf_gp, "ATTR")
|
||
return None
|