- FuncGenDef: 有返回注解但解析失败 → fatal_error(不再静默回退 i32;无注解函数保留 i32 默认) - TypeGenResolve: 泛型类型实参污染(T→T 自映射 / 实参含类型参数名)→ fatal_error(不再 return None 静默退化) - ExprGenBase: coerce_to_type 窄→宽接入 _zext_or_sext_val(i1/i8 默认 zext、无符号类型名 zext、否则 sext),修正 t.CUInt32T 等无符号值被符号扩展的隐蔽数据损坏
2162 lines
123 KiB
Plaintext
2162 lines
123 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||
import lib.core.Gen.GenTypes as GenTypes
|
||
import lib.core.Gen.Generator as Generator
|
||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||
import lib.core.Gen.GenApi as GenApi
|
||
|
||
# ============================================================
|
||
# AssignGenMixin - 赋值翻译 Mixin(P6 方法化)
|
||
#
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
@t.NoVTable
|
||
class AssignGenMixin:
|
||
Gen: Generator.Generator | t.CPtr
|
||
"""赋值翻译 Mixin(P6 方法化)"""
|
||
|
||
RecoverFound: int
|
||
|
||
# ============================================================
|
||
# 检测注解是否为 t.CDefine(模块级函数)
|
||
#
|
||
# 支持两种形式:
|
||
# 1. Attribute(Name('t'), 'CDefine')
|
||
# 2. BinOp(... | Attribute(Name('t'), 'CDefine'))(联合注解)
|
||
# ============================================================
|
||
def is_cdefine_annotation(self, annot: ast.AST | t.CPtr) -> int:
|
||
"""检测注解是否为 t.CDefine,返回 1 表示是,0 表示否"""
|
||
if annot is None: return 0
|
||
k: int = annot.kind()
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
|
||
if at.attr is not None and string.strcmp(at.attr, "CDefine") == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||
if self.is_cdefine_annotation(bop.left) != 0:
|
||
return 1
|
||
if self.is_cdefine_annotation(bop.right) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数)
|
||
#
|
||
# 支持的表达式形式:
|
||
# 1. Constant(INT) — 如 0x0002, 42
|
||
# 2. BinOp(BitOr/BitAnd) — 如 FOREGROUND_RED | FOREGROUND_GREEN
|
||
# 3. Name — 引用已注册的 CDefine 常量
|
||
# 4. Call — 如 t.CUnsignedLong(-11) → 取第一个参数
|
||
# 5. UnaryOp(USub/UAdd/Invert) — 如 -11
|
||
# ============================================================
|
||
def extract_cdefine_int_value(self, val_node: ast.AST | t.CPtr) -> t.CInt64T:
|
||
"""从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp)
|
||
|
||
64 位返回:大整数 CDefine(如 sys.maxsize=9223372036854775807)
|
||
必须全精度提取,否则 int(32 位) 截断成 -1(SysLibTest maxsize FAIL 根因)。
|
||
"""
|
||
if val_node is None:
|
||
return 0
|
||
k: int = val_node.kind()
|
||
|
||
# Case 1: Constant(INT) — 如 0x0002
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
|
||
# True/False 布尔常量 → 1/0(对齐 TPC:bool 在 CDefine 语境按整数处理,
|
||
# 如 SHADOW_ENABLED: t.CDefine = False)
|
||
if cn.const_kind == ast.CONST_BOOL:
|
||
return 1 if cn.int_val != 0 else 0
|
||
if cn.const_kind != ast.CONST_INT:
|
||
# 非 INT 常量:直接报错终止(fail-fast)
|
||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
return cn.int_val
|
||
|
||
# Case 2: BinOp — 如 FOREGROUND_RED | FOREGROUND_GREEN、(1 << ZDEFLATE_WINDOW_BITS)
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(val_node)
|
||
left_val: t.CInt64T = self.extract_cdefine_int_value(bop.left)
|
||
right_val: t.CInt64T = self.extract_cdefine_int_value(bop.right)
|
||
if bop.op == ast.OpKind.BitOr: return left_val | right_val
|
||
if bop.op == ast.OpKind.BitAnd: return left_val & right_val
|
||
if bop.op == ast.OpKind.BitXor: return left_val ^ right_val
|
||
if bop.op == ast.OpKind.LShift: return left_val << right_val
|
||
if bop.op == ast.OpKind.RShift: return left_val >> right_val
|
||
if bop.op == ast.OpKind.Add: return left_val + right_val
|
||
if bop.op == ast.OpKind.Sub: return left_val - right_val
|
||
if bop.op == ast.OpKind.Mult: return left_val * right_val
|
||
if bop.op == ast.OpKind.Div: return left_val // right_val
|
||
if bop.op == ast.OpKind.FloorDiv: return left_val // right_val
|
||
if bop.op == ast.OpKind.Mod: return left_val % right_val
|
||
# 未知 BinOp 运算符:直接报错终止(fail-fast)
|
||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
|
||
# Case 3: Name — 引用已注册的 CDefine 常量,或 True/False 布尔字面量
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
|
||
if nm.id is not None:
|
||
# True/False 布尔字面量 → 1/0(bool 在 CDefine 语境按整数处理)
|
||
if string.strcmp(nm.id, "True") == 0:
|
||
return 1
|
||
if string.strcmp(nm.id, "False") == 0:
|
||
return 0
|
||
looked_up: t.CInt64T = self.Gen.TypeGenCDef.lookup_cdefine_constant(nm.id)
|
||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||
return looked_up
|
||
# 引用未注册:直接报错终止(fail-fast)
|
||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
|
||
# Case 4: Call — 如 t.CUnsignedLong(-11)
|
||
if k == ast.ASTKind.Call:
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node)
|
||
# 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
|
||
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
|
||
cl_args_list: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cl_args_list is not None and len(cl_args_list) > 0:
|
||
first_arg: ast.AST | t.CPtr = cl_args_list.get(0)
|
||
arg_val: t.CInt64T = self.extract_cdefine_int_value(first_arg)
|
||
return arg_val
|
||
# Call 无参数:直接报错终止(fail-fast)
|
||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
|
||
# Case 5: UnaryOp — 如 -11
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(val_node)
|
||
operand_val: t.CInt64T = self.extract_cdefine_int_value(uop.operand)
|
||
if uop.op == ast.OpKind.USub: return -operand_val
|
||
if uop.op == ast.OpKind.UAdd: return operand_val
|
||
if uop.op == ast.OpKind.Invert: return ~operand_val
|
||
# 未知 UnaryOp 运算符:直接报错终止(fail-fast)
|
||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
|
||
# 未知节点类型:直接报错终止(fail-fast)
|
||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
# 追加89 块设计:fatal_error 调用后补显式 return(运行时不可达,
|
||
# 保证函数末尾块被正确 terminated,不做 noreturn 函数名白名单)
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别)
|
||
#
|
||
# 浮点字面量(如 vipermath 的 U_M_PI: t.CDefine = 3.14159...)走
|
||
# register_cdefine_double,否则 translate_value 查表得 0 生成
|
||
# ret i32 0(llc 报错 "value doesn't match function result type")。
|
||
# ============================================================
|
||
def _register_cdefine_from_value(self, pool: memhub.MemBuddy | t.CPtr,
|
||
name: str, val_node: ast.AST | t.CPtr) -> None:
|
||
"""注册 CDefine 常量(浮点字面量 → register_cdefine_double,否则整数)"""
|
||
if pool is None or name is None:
|
||
return
|
||
# Call 包装的常量:如 PI: t.CDefine = float(3.14159...) /
|
||
# t.CFloat64T(2.5) / t.CDouble(1.0)。取第一个参数作为真实值节点,
|
||
# 再按 Constant 分支处理(浮点 → register_cdefine_double)。
|
||
if val_node is not None and val_node.kind() == ast.ASTKind.Call:
|
||
cl_cd: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node)
|
||
if cl_cd is not None and cl_cd.args is not None:
|
||
cl_args_cd: list[ast.AST | t.CPtr] | t.CPtr = cl_cd.args
|
||
if len(cl_args_cd) > 0:
|
||
first_arg_cd: ast.AST | t.CPtr = cl_args_cd.get(0)
|
||
if first_arg_cd is not None and first_arg_cd.kind() == ast.ASTKind.Constant:
|
||
val_node = first_arg_cd
|
||
if val_node is not None and val_node.kind() == ast.ASTKind.Constant:
|
||
cn_fp: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
|
||
if cn_fp.const_kind == ast.CONST_STR:
|
||
# 字符串 CDefine(如 ZLIB_VERSION: t.CDefine = "1.3.2"):
|
||
# 注册为字符串常量,读取端返回 global string(对齐 TPC)。
|
||
self.Gen.TypeGenCDef.register_cdefine_string(pool, name, cn_fp.str_val)
|
||
return
|
||
if cn_fp.const_kind == ast.CONST_FLOAT:
|
||
# 源文件重读恢复(最可靠:AST 节点 float_val 可能被 pool 操作覆写,
|
||
# 源文件文本不受影响;用输出参数绕开跨模块 double 返回值传递 bug)
|
||
use_val: double = cn_fp.float_val
|
||
rec_d: t.CDouble = 0.0
|
||
if self._recover_cdefine_float(name, t.CPtr(c.Addr(rec_d))) != 0:
|
||
use_val = rec_d
|
||
else:
|
||
# 源文件恢复失败:直接报错终止(fail-fast),避免注册被 pool 覆写的错误浮点值
|
||
self.Gen.TypeGenErr.fatal_error(val_node, "CDefine 浮点值源文件恢复失败", "InternalCompilerError")
|
||
return
|
||
self.Gen.TypeGenCDef.register_cdefine_double(pool, name, use_val)
|
||
return
|
||
if val_node is None:
|
||
# CDefine 声明缺少值节点:直接报错终止(fail-fast)
|
||
self.Gen.TypeGenErr.fatal_error(None, f"CDefine 值提取失败:'{name}' 缺少初始值", "TypeError")
|
||
return
|
||
val_fp: t.CInt64T = self.extract_cdefine_int_value(val_node)
|
||
self.Gen.TypeGenCDef.register_cdefine_constant(pool, name, val_fp)
|
||
|
||
# ============================================================
|
||
# 源文件重读恢复 CDefine 浮点值
|
||
#
|
||
# 背景:AST 节点的 float_val/str_val 字段可能被 pool 分配操作覆写
|
||
# (MemBuddy 内存冲突),导致注册的浮点 CDefine 值错误(llc ret i32 0)。
|
||
# 本函数直接读源文件找 "NAME: t.CDefine = value" 行,atof 解析 value——
|
||
# 源文件文本不受 pool 影响,是最可靠的恢复路径。
|
||
#
|
||
# 原模块级 _g_recover_found 全局已迁移为实例字段 self.RecoverFound。
|
||
# ============================================================
|
||
|
||
def _recover_found(self) -> int:
|
||
"""检查最近一次 _recover_cdefine_float 是否成功"""
|
||
return self.RecoverFound
|
||
|
||
def _recover_cdefine_float(self, name: str, out: t.CDouble | t.CPtr) -> int:
|
||
"""从当前模块源文件恢复浮点 CDefine 值,写入 out[0],成功返回 1
|
||
|
||
用输出参数传递 double,避免 TPV 跨模块 double 返回值传递 bug。
|
||
"""
|
||
self.RecoverFound = 0
|
||
fp: str = self.Gen.TypeGenResolve.get_current_file()
|
||
if fp is None or name is None or out is None:
|
||
return 0
|
||
f: fileio.File | t.CPtr = fileio.File(fp, fileio.MODE.R)
|
||
if f.closed:
|
||
return 0
|
||
BUF_SZ: t.CSizeT = 1048576
|
||
buf: bytes = stdlib.malloc(BUF_SZ)
|
||
if buf is None:
|
||
f.close()
|
||
return 0
|
||
nrd: LONG = f.read_all(buf, BUF_SZ)
|
||
f.close()
|
||
if nrd <= 0:
|
||
stdlib.free(buf)
|
||
return 0
|
||
if nrd < BUF_SZ:
|
||
buf[nrd] = 0
|
||
else:
|
||
buf[BUF_SZ - 1] = 0
|
||
|
||
name_len: t.CSizeT = string.strlen(name)
|
||
total_len: t.CSizeT = string.strlen(buf)
|
||
pos: t.CSizeT = 0
|
||
while pos < total_len:
|
||
line_start: t.CSizeT = pos
|
||
while pos < total_len and buf[pos] != '\n':
|
||
pos += 1
|
||
line_len: t.CSizeT = pos - line_start
|
||
if pos < total_len:
|
||
pos += 1
|
||
|
||
# 匹配 "name:"
|
||
if line_len < name_len + 1:
|
||
continue
|
||
match_ok: int = 1
|
||
ki: t.CSizeT
|
||
for ki in range(name_len):
|
||
if buf[line_start + ki] != name[ki]:
|
||
match_ok = 0
|
||
break
|
||
if match_ok == 0:
|
||
continue
|
||
if buf[line_start + name_len] != ':':
|
||
continue
|
||
|
||
# 行内包含 "t.CDefine"
|
||
has_cd: int = 0
|
||
ci: t.CSizeT = line_start + name_len + 1
|
||
while ci + 8 <= line_start + line_len:
|
||
if (buf[ci] == 't' and buf[ci + 1] == '.' and buf[ci + 2] == 'C' and
|
||
buf[ci + 3] == 'D' and buf[ci + 4] == 'e' and buf[ci + 5] == 'f' and
|
||
buf[ci + 6] == 'i' and buf[ci + 7] == 'n' and buf[ci + 8] == 'e'):
|
||
has_cd = 1
|
||
break
|
||
ci += 1
|
||
if has_cd == 0:
|
||
continue
|
||
|
||
# 找 '='
|
||
eq: t.CSizeT = line_start
|
||
while eq < line_start + line_len and buf[eq] != '=':
|
||
eq += 1
|
||
if eq >= line_start + line_len:
|
||
continue
|
||
eq += 1
|
||
while eq < line_start + line_len and buf[eq] == ' ':
|
||
eq += 1
|
||
val_start: t.CSizeT = eq
|
||
while eq < line_start + line_len and buf[eq] != ' ' and buf[eq] != '\t' \
|
||
and buf[eq] != '#' and buf[eq] != '\r' and buf[eq] != '\n':
|
||
eq += 1
|
||
if eq == val_start:
|
||
continue
|
||
|
||
val_txt: str = stdlib.malloc(eq - val_start + 1)
|
||
if val_txt is None:
|
||
stdlib.free(buf)
|
||
return 0
|
||
vi: t.CSizeT
|
||
for vi in range(eq - val_start):
|
||
val_txt[vi] = buf[val_start + vi]
|
||
val_txt[eq - val_start] = 0
|
||
stdlib.free(buf)
|
||
# 用 atof_out(输出参数)绕开跨模块 double 返回值传递 bug
|
||
if string.atof_out(val_txt, out) != 0:
|
||
self.RecoverFound = 1
|
||
return 1
|
||
return 0
|
||
|
||
stdlib.free(buf)
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _annotation_contains_name - 递归检查注解中是否包含指定名称
|
||
#
|
||
# 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。
|
||
# ============================================================
|
||
def _annotation_contains_name(self, annot: ast.AST | t.CPtr, name: str) -> int:
|
||
"""递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含"""
|
||
if annot is None or name is None:
|
||
return 0
|
||
k: int = annot.kind()
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
|
||
if at.attr is not None and string.strcmp(at.attr, name) == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot)
|
||
if nm.id is not None and string.strcmp(nm.id, name) == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||
if self._annotation_contains_name(bop.left, name) != 0:
|
||
return 1
|
||
if self._annotation_contains_name(bop.right, name) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr
|
||
#
|
||
# 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义)
|
||
#
|
||
# 规则:
|
||
# bytes|t.CPtr / str|t.CPtr → i8**(8 字节步长)→ 返回 1
|
||
# t.CChar|t.CPtr / t.CInt8T|t.CPtr → i8*(1 字节步长)→ 返回 0
|
||
# 纯 bytes / str → i8*(1 字节步长)→ 返回 0
|
||
#
|
||
# 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算
|
||
# ============================================================
|
||
def _is_ptr_element_annotation(self, annot: ast.AST | t.CPtr) -> int:
|
||
"""检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式"""
|
||
if annot is None:
|
||
return 0
|
||
k: int = annot.kind()
|
||
if k != ast.ASTKind.BinOp:
|
||
return 0
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||
if bop.op != ast.OpKind.BitOr:
|
||
return 0
|
||
if self._annotation_contains_name(annot, "str") != 0:
|
||
return 1
|
||
if self._annotation_contains_name(annot, "bytes") != 0:
|
||
return 1
|
||
# 泛型类型参数/嵌套联合 | t.CPtr(如 _list.vp 的 elem_ptr: T | t.CPtr):
|
||
# 先经泛型上下文解析 T 的具体类型——纯标量(int/float 等 sizeof≠8)时
|
||
# 元素按标量自身大小(list[int] elem_size=4 匹配 i32),不能按 8 字节
|
||
# 指针槽(否则 8 字节写 / 4 字节步长互相覆盖,pop 读到 0);
|
||
# 指针/嵌套联合/64 位标量/double(sizeof==8)才按 8 字节。
|
||
if self._is_generic_tp_or_nested(bop.left) != 0 or self._is_generic_tp_or_nested(bop.right) != 0:
|
||
gp_nm: str = None
|
||
if bop.left is not None and bop.left.kind() == ast.ASTKind.Name:
|
||
gp_left_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bop.left)
|
||
gp_nm = gp_left_nm.id
|
||
elif bop.right is not None and bop.right.kind() == ast.ASTKind.Name:
|
||
gp_right_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bop.right)
|
||
gp_nm = gp_right_nm.id
|
||
if gp_nm is not None:
|
||
# 经全局 gen 委托解析泛型参数(T → 具体类型名)。不能 self.GenericTpNames
|
||
# 直读(Mixin @t.NoVTable 静态绑定:字段声明在 TypeGenMixin,AssignGenMixin
|
||
# 访问会生成不存在的属性引用 → TPC fast-fail 编译崩溃)
|
||
gp_resolved: str = self.Gen.TypeGenBase.resolve_generic_type_name(gp_nm)
|
||
if gp_resolved is not None and string.strcmp(gp_resolved, gp_nm) != 0:
|
||
# 泛型参数解析为纯标量 → 元素按标量自身大小(非 8 字节指针槽)
|
||
if self._is_scalar_ty_name(gp_resolved) != 0:
|
||
return 0
|
||
return 1
|
||
# 64 位标量数值类型 | CPtr(如 CUInt64T | CPtr / CSizeT | CPtr):
|
||
# 联合解析后同样退化为指针表示,元素为 8 字节(i64 或指针)。
|
||
# 下标必须按 8 字节步长读写——否则 GEP 步长 1 + trunc i8 截断,
|
||
# 指针存进数组只剩低 1 字节(BuddyTest OOM/fill 的 ptrs 数组全错位:
|
||
# store i8 trunc i64、读回 inttoptr i8 丢高 56 位,free 全部无效)。
|
||
if self._is_64bit_scalar_ty(bop.left) != 0 or self._is_64bit_scalar_ty(bop.right) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
def _is_64bit_scalar_ty(self, node: ast.AST | t.CPtr) -> int:
|
||
"""判断类型节点是否为 64 位标量数值类型(CUInt64T/CInt64T/CSizeT),元素 8 字节"""
|
||
if node is None:
|
||
return 0
|
||
ty_nm: str = None
|
||
nk: int = node.kind()
|
||
if nk == ast.ASTKind.Name:
|
||
nm64: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
ty_nm = nm64.id
|
||
elif nk == ast.ASTKind.Attribute:
|
||
at64: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||
ty_nm = at64.attr
|
||
if ty_nm is None:
|
||
return 0
|
||
if string.strcmp(ty_nm, "CUInt64T") == 0:
|
||
return 1
|
||
if string.strcmp(ty_nm, "CInt64T") == 0:
|
||
return 1
|
||
if string.strcmp(ty_nm, "CSizeT") == 0:
|
||
return 1
|
||
return 0
|
||
|
||
def _is_scalar_ty_name(self, ty_name: str) -> int:
|
||
"""判断类型名是否为已知纯标量(整数/浮点/字符),白名单判定
|
||
|
||
泛型 T | t.CPtr(如 _list.vp 的 elem_ptr)经 Fix A(TypeGenMixin 联合
|
||
解析保留泛型标量)后 alloca 变 Ptr(标量):T 为纯标量(int/float/double/
|
||
i64 等)时下标按标量自身大小步长,不能再按 8 字节指针槽——否则
|
||
Ptr(标量) alloca + IsPtrElement 路径(load 标量当指针)产生非法 IR。
|
||
指针/联合/str/bytes 才保持 8 字节指针槽语义。
|
||
|
||
原实现"排除 Ptr/str/bytes/| 后默认返回 1"把**未知类名**(如泛型上下文
|
||
污染产生的 llvmlite.Value)误判为标量 → IsPtrElement=0 → elem_ptr[0]
|
||
走通用路径生成 Value* → list[str].get 声明 i8* 与 ret Value* 不匹配
|
||
(8fbba llc 报错根因)。改白名单:已知标量才 1,未知类名按 8 字节指针槽。
|
||
"""
|
||
if ty_name is None:
|
||
return 0
|
||
if string.strchr(ty_name, '|') is not None:
|
||
return 0
|
||
if string.strchr(ty_name, '*') is not None:
|
||
return 0
|
||
if string.strcmp(ty_name, "str") == 0:
|
||
return 0
|
||
if string.strcmp(ty_name, "bytes") == 0:
|
||
return 0
|
||
if string.strcmp(ty_name, "t.CPtr") == 0:
|
||
return 0
|
||
if string.strcmp(ty_name, "CPtr") == 0:
|
||
return 0
|
||
if string.strstr(ty_name, "Ptr") is not None:
|
||
return 0
|
||
# === 白名单:已知纯标量(基础名 + stdint 大写别名) ===
|
||
if string.strcmp(ty_name, "int") == 0: return 1
|
||
if string.strcmp(ty_name, "CInt") == 0: return 1
|
||
if string.strcmp(ty_name, "CChar") == 0: return 1
|
||
if string.strcmp(ty_name, "CUnsignedChar") == 0: return 1
|
||
if string.strcmp(ty_name, "CShort") == 0: return 1
|
||
if string.strcmp(ty_name, "CUnsignedShort") == 0: return 1
|
||
if string.strcmp(ty_name, "CLong") == 0: return 1
|
||
if string.strcmp(ty_name, "CUnsignedLong") == 0: return 1
|
||
if string.strcmp(ty_name, "CLongLong") == 0: return 1
|
||
if string.strcmp(ty_name, "CUnsignedLongLong") == 0: return 1
|
||
if string.strcmp(ty_name, "CSizeT") == 0: return 1
|
||
if string.strcmp(ty_name, "BOOL") == 0: return 1
|
||
if string.strcmp(ty_name, "BYTE") == 0: return 1
|
||
if string.strcmp(ty_name, "UCHAR") == 0: return 1
|
||
if string.strcmp(ty_name, "CHAR") == 0: return 1
|
||
if string.strcmp(ty_name, "SHORT") == 0: return 1
|
||
if string.strcmp(ty_name, "USHORT") == 0: return 1
|
||
if string.strcmp(ty_name, "LONG") == 0: return 1
|
||
if string.strcmp(ty_name, "ULONG") == 0: return 1
|
||
if string.strcmp(ty_name, "LONGLONG") == 0: return 1
|
||
if string.strcmp(ty_name, "ULONGLONG") == 0: return 1
|
||
if string.strcmp(ty_name, "INT") == 0: return 1
|
||
if string.strcmp(ty_name, "UINT") == 0: return 1
|
||
if string.strcmp(ty_name, "WORD") == 0: return 1
|
||
if string.strcmp(ty_name, "DWORD") == 0: return 1
|
||
if string.strcmp(ty_name, "QWORD") == 0: return 1
|
||
# 定长整数/浮点(C*T 形式与裸别名,strstr 前缀匹配)
|
||
if string.strstr(ty_name, "Int8") is not None: return 1
|
||
if string.strstr(ty_name, "Int16") is not None: return 1
|
||
if string.strstr(ty_name, "Int32") is not None: return 1
|
||
if string.strstr(ty_name, "Int64") is not None: return 1
|
||
if string.strstr(ty_name, "UInt8") is not None: return 1
|
||
if string.strstr(ty_name, "UInt16") is not None: return 1
|
||
if string.strstr(ty_name, "UInt32") is not None: return 1
|
||
if string.strstr(ty_name, "UInt64") is not None: return 1
|
||
if string.strstr(ty_name, "Float") is not None: return 1
|
||
if string.strstr(ty_name, "FLOAT") is not None: return 1
|
||
if string.strstr(ty_name, "Double") is not None: return 1
|
||
if string.strstr(ty_name, "DOUBLE") is not None: return 1
|
||
# 未知类名(结构体/类/污染类型)→ 非标量,按 8 字节指针槽
|
||
return 0
|
||
|
||
def _is_generic_tp_or_nested(self, node: ast.AST | t.CPtr) -> int:
|
||
"""判断注解节点是否为泛型类型参数名(单字母大写,如 T)或嵌套联合(BinOp)"""
|
||
if node is None:
|
||
return 0
|
||
nk: int = node.kind()
|
||
if nk == ast.ASTKind.BinOp:
|
||
return 1
|
||
if nk == ast.ASTKind.Name:
|
||
nm_tp: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
if nm_tp.id is None:
|
||
return 0
|
||
tp_len: t.CSizeT = string.strlen(nm_tp.id)
|
||
if tp_len == 1:
|
||
if nm_tp.id[0] >= 65 and nm_tp.id[0] <= 90:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _init_global_array_from_list — 从列表字面量初始化全局数组
|
||
#
|
||
# 为每个元素生成 GEP + store 指令,将值存入全局数组的对应位置。
|
||
# 适用于模块级 t.CArray[elem_ty, count] = [v0, v1, ...] 的初始化。
|
||
#
|
||
# Args:
|
||
# builder: IRBuilder
|
||
# pool: 编译器内存池
|
||
# mod: LLVMModule
|
||
# array_alloca: 全局数组变量的 Value 引用(类型为 [N x elem_ty]*)
|
||
# list_node: ast.List 节点
|
||
# trans: Translator 对象
|
||
#
|
||
# Returns:
|
||
# 0 成功,1 失败
|
||
# ============================================================
|
||
def _init_global_array_from_list(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
array_alloca: llvmlite.Value | t.CPtr,
|
||
list_node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> int:
|
||
"""从列表字面量初始化全局数组,为每个元素生成 GEP + store"""
|
||
if builder is None or array_alloca is None or list_node is None:
|
||
return 1
|
||
|
||
# 获取数组类型(Pointee of [N x elem_ty]*)
|
||
arr_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if array_alloca.Ty is not None:
|
||
arr_ty = array_alloca.Ty.Pointee
|
||
if arr_ty is None:
|
||
return 1
|
||
|
||
# 匹配数组类型获取元素类型
|
||
elem_ty: llvmlite.LLVMType | t.CPtr = None
|
||
match arr_ty:
|
||
case llvmlite.LLVMType.Array(et, _):
|
||
elem_ty = et
|
||
if elem_ty is None:
|
||
return 1
|
||
|
||
# 获取列表元素
|
||
lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
|
||
if lst is None or lst.elts is None:
|
||
return 1
|
||
elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts
|
||
elts_count: t.CSizeT = len(elts)
|
||
|
||
# 为每个元素生成 GEP + store
|
||
for i in range(elts_count):
|
||
elem_node: ast.AST | t.CPtr = elts.get(i)
|
||
elem_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, elem_node, None, 0, trans)
|
||
if elem_val is None:
|
||
# 元素翻译失败:直接报错终止(fail-fast),暴露上游根因
|
||
self.Gen.TypeGenErr.fatal_error(elem_node, "全局数组初始化元素翻译失败", "TypeError")
|
||
idx_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, i)
|
||
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||
builder, arr_ty, elem_ty, array_alloca, idx_val)
|
||
if elem_ptr is not None:
|
||
# 类型转换(如 i32 → i8 截断)
|
||
store_val: llvmlite.Value | t.CPtr = elem_val
|
||
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
|
||
store_val = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, elem_val, elem_ptr.Ty.Pointee, elem_node)
|
||
llvmlite.build_store(builder, store_val, elem_ptr)
|
||
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _apply_aug_op - 应用增强赋值的二元运算
|
||
#
|
||
# 支持浮点运算、指针算术: ptr += int / ptr -= int
|
||
# 整数运算自动类型提升
|
||
# ============================================================
|
||
def _apply_aug_op(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
op: int,
|
||
lhs: llvmlite.Value | t.CPtr,
|
||
rhs: llvmlite.Value | t.CPtr,
|
||
node: ast.AST | t.CPtr = None,
|
||
trans: HT.Translator | t.CPtr = None,
|
||
lhs_node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算)"""
|
||
lhs_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(lhs.Ty)
|
||
rhs_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(rhs.Ty)
|
||
lhs_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(lhs.Ty)
|
||
rhs_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(rhs.Ty)
|
||
|
||
# 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查,
|
||
# 因为 float 的 int bits 为 0,会被误认为指针)
|
||
if lhs_fbits != 0 or rhs_fbits != 0:
|
||
# 确定目标浮点类型(使用较大的位宽)
|
||
target_fbits: int = lhs_fbits
|
||
if rhs_fbits > target_fbits:
|
||
target_fbits = rhs_fbits
|
||
target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||
if target_fbits == 32:
|
||
target_float_ty = llvmlite.Float(pool)
|
||
# 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc)
|
||
lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, target_float_ty, node)
|
||
rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, target_float_ty, node)
|
||
if op == ast.OpKind.Add: return llvmlite.build_fadd(builder, lhs, rhs)
|
||
if op == ast.OpKind.Sub: return llvmlite.build_fsub(builder, lhs, rhs)
|
||
if op == ast.OpKind.Mult: return llvmlite.build_fmul(builder, lhs, rhs)
|
||
if op == ast.OpKind.Div: return llvmlite.build_fdiv(builder, lhs, rhs)
|
||
if op == ast.OpKind.Mod: return llvmlite.build_frem(builder, lhs, rhs)
|
||
return None
|
||
|
||
# 指针算术: ptr += int / ptr -= int → getelementptr(按元素大小缩放)
|
||
# 对齐 TPC HandlesAugAssign.py L140-149 / L170-180
|
||
if lhs_bits == 0 and rhs_bits != 0:
|
||
if op == ast.OpKind.Add or op == ast.OpKind.Sub:
|
||
return self.Gen.ExprGenBase.translate_ptr_arith(pool, builder, lhs, rhs, op)
|
||
return None
|
||
|
||
# 整数运算:类型提升
|
||
if lhs_bits > rhs_bits and rhs_bits > 0:
|
||
rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, lhs.Ty, node)
|
||
elif rhs_bits > lhs_bits and lhs_bits > 0:
|
||
lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, rhs.Ty, node)
|
||
|
||
if op == ast.OpKind.Add: return llvmlite.build_add(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Sub: return llvmlite.build_sub(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Mult: return llvmlite.build_mul(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Div: return llvmlite.build_sdiv(builder, lhs, rhs)
|
||
elif op == ast.OpKind.FloorDiv: return llvmlite.build_sdiv(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Mod: return llvmlite.build_srem(builder, lhs, rhs)
|
||
elif op == ast.OpKind.BitAnd: return llvmlite.build_and(builder, lhs, rhs)
|
||
elif op == ast.OpKind.BitOr: return llvmlite.build_or(builder, lhs, rhs)
|
||
elif op == ast.OpKind.BitXor: return llvmlite.build_xor(builder, lhs, rhs)
|
||
elif op == ast.OpKind.LShift: return llvmlite.build_shl(builder, lhs, rhs)
|
||
elif op == ast.OpKind.RShift:
|
||
# 无符号 >> → lshr(逻辑右移),有符号 >> → ashr(算术右移)
|
||
# 对齐 TPC ExprGen.emit_binary_op:i8/i16 默认无符号;其余查操作数无符号性
|
||
if lhs_bits == 8 or lhs_bits == 16:
|
||
return llvmlite.build_lshr(builder, lhs, rhs)
|
||
if lhs_node is not None and trans is not None:
|
||
if self.Gen.ExprGenOps._node_type_unsigned(pool, lhs_node, trans) != 0:
|
||
return llvmlite.build_lshr(builder, lhs, rhs)
|
||
return llvmlite.build_ashr(builder, lhs, rhs)
|
||
return None
|
||
|
||
# ============================================================
|
||
# translate_augassign - 增强赋值语句翻译(迁移自 HandlesAugAssign.AugAssignHandle.Handle)
|
||
#
|
||
# 支持 += -= *= /= %= &= |= ^= <<= >>=,local/global/nonlocal 三种作用域
|
||
# ============================================================
|
||
def translate_augassign(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译增强赋值语句 (x += 1, y -= 2, etc.)"""
|
||
if node is None:
|
||
return 0
|
||
|
||
aug: ast.AugAssign | t.CPtr = (ast.AugAssign | t.CPtr)(node)
|
||
if aug is None:
|
||
return 0
|
||
|
||
target: ast.AST | t.CPtr = aug.target
|
||
if target is None:
|
||
return 0
|
||
|
||
tk: int = target.kind()
|
||
|
||
# Attribute 目标: self.field += 1
|
||
# 流程: get_attribute_ptr → load → binop → store
|
||
if tk == ast.ASTKind.Attribute:
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
|
||
# 1. 获取字段指针
|
||
field_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr(
|
||
builder, pool, mod, target, trans)
|
||
if field_ptr is None:
|
||
# fail-fast: 属性指针解析失败
|
||
self.Gen.TypeGenErr.fatal_error(target, "attribute ptr is None", "TypeError")
|
||
|
||
# 2. 确定字段类型并加载当前值
|
||
target_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None:
|
||
target_ty = field_ptr.Ty.Pointee
|
||
if target_ty is None:
|
||
# fail-fast: 字段类型信息缺失,禁止兜底 i32
|
||
self.Gen.TypeGenErr.fatal_error(target, "字段类型信息缺失", "TypeError")
|
||
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, target_ty, field_ptr)
|
||
if cur_val is None:
|
||
# fail-fast: 属性当前值加载失败
|
||
self.Gen.TypeGenErr.fatal_error(target, "无法加载 attribute 当前值", "TypeError")
|
||
|
||
# 3. 翻译 RHS 值
|
||
rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, aug.value, None, 0, trans)
|
||
if rhs_val is None:
|
||
# fail-fast: RHS 翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(target, "rhs 翻译失败", "TypeError")
|
||
|
||
# 4. 应用二元运算
|
||
result: llvmlite.Value | t.CPtr = self._apply_aug_op(
|
||
pool, builder, aug.op, cur_val, rhs_val, node, trans, target)
|
||
if result is None:
|
||
# fail-fast: attribute 二元运算失败
|
||
self.Gen.TypeGenErr.fatal_error(target, f"attribute 二元运算失败 op={aug.op}", "TypeError")
|
||
|
||
# 5. 类型对齐并存储
|
||
result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node)
|
||
if result is None:
|
||
# fail-fast: 类型对齐失败
|
||
self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError")
|
||
llvmlite.build_store(builder, result, field_ptr)
|
||
return 0
|
||
|
||
# Subscript 目标: self.state[i] += x / arr[i] += x
|
||
# 流程: get_subscript_ptr → load → binop → store
|
||
if tk == ast.ASTKind.Subscript:
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
|
||
# 1. 获取元素指针
|
||
elem_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenName.get_subscript_ptr(
|
||
builder, pool, mod, target, trans)
|
||
if elem_ptr is None:
|
||
# fail-fast: 下标指针解析失败
|
||
self.Gen.TypeGenErr.fatal_error(target, "subscript ptr is None", "TypeError")
|
||
|
||
# 2. 确定元素类型并加载当前值
|
||
target_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
|
||
target_ty = elem_ptr.Ty.Pointee
|
||
if target_ty is None:
|
||
# fail-fast: 元素类型信息缺失,禁止兜底 i32
|
||
self.Gen.TypeGenErr.fatal_error(target, "元素类型信息缺失", "TypeError")
|
||
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, target_ty, elem_ptr)
|
||
if cur_val is None:
|
||
# fail-fast: 元素当前值加载失败
|
||
self.Gen.TypeGenErr.fatal_error(target, "无法加载 subscript 元素当前值", "TypeError")
|
||
|
||
# 3. 翻译 RHS 值
|
||
rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, aug.value, None, 0, trans)
|
||
if rhs_val is None:
|
||
# fail-fast: RHS 翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(target, "rhs 翻译失败", "TypeError")
|
||
|
||
# 4. 应用二元运算
|
||
result: llvmlite.Value | t.CPtr = self._apply_aug_op(
|
||
pool, builder, aug.op, cur_val, rhs_val, node, trans, target)
|
||
if result is None:
|
||
# fail-fast: subscript 二元运算失败
|
||
self.Gen.TypeGenErr.fatal_error(target, f"subscript 二元运算失败 op={aug.op}", "TypeError")
|
||
|
||
# 5. 类型对齐并存储
|
||
result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node)
|
||
if result is None:
|
||
# fail-fast: 类型对齐失败
|
||
self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError")
|
||
llvmlite.build_store(builder, result, elem_ptr)
|
||
return 0
|
||
|
||
if tk != ast.ASTKind.Name:
|
||
# fail-fast: 不支持的 AugAssign 目标类型
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
target, "AugAssign 目标类型不支持,仅支持 Name/Attribute/Subscript", "TypeError")
|
||
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
||
if nm is None or nm.id is None:
|
||
return 0
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
|
||
# 1. 确定变量作用域类型: 0=local, 1=global, 2=nonlocal
|
||
scope_type: int = 0
|
||
if GenApi.is_global_name(trans, nm.id) != 0:
|
||
scope_type = 1
|
||
elif GenApi.is_nonlocal_name(trans, nm.id) != 0:
|
||
scope_type = 2
|
||
|
||
# 2. 加载当前值
|
||
cur_val: llvmlite.Value | t.CPtr = None
|
||
target_alloca: llvmlite.Value | t.CPtr = None
|
||
target_ty: llvmlite.LLVMType | t.CPtr = None
|
||
|
||
if scope_type == 1:
|
||
# global 变量
|
||
target_alloca = self.Gen.VarGen.lookup_module_var(
|
||
trans.SymTab, nm.id)
|
||
if target_alloca is not None:
|
||
if target_alloca.Ty is None:
|
||
# fail-fast: 变量类型信息缺失,禁止兜底 i32
|
||
self.Gen.TypeGenErr.fatal_error(target, "变量类型信息缺失", "TypeError")
|
||
target_ty = target_alloca.Ty.Pointee
|
||
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
|
||
elif scope_type == 2:
|
||
# nonlocal 变量(通过闭包 env)
|
||
cur_val = self.Gen.StmtGenDecl.load_nonlocal_var(trans, nm.id)
|
||
if cur_val is not None:
|
||
target_ty = cur_val.Ty
|
||
else:
|
||
# 普通局部变量
|
||
target_alloca = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||
if target_alloca is not None:
|
||
if target_alloca.Ty is None:
|
||
# fail-fast: 变量类型信息缺失,禁止兜底 i32
|
||
self.Gen.TypeGenErr.fatal_error(target, "变量类型信息缺失", "TypeError")
|
||
target_ty = target_alloca.Ty.Pointee
|
||
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
|
||
|
||
if cur_val is None:
|
||
# fail-fast: 目标变量当前值加载失败
|
||
self.Gen.TypeGenErr.fatal_error(target, f"无法加载目标变量 '{nm.id}' 的当前值", "TypeError")
|
||
|
||
# 3. 翻译 RHS 值
|
||
rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, aug.value, None, 0, trans)
|
||
if rhs_val is None:
|
||
# fail-fast: RHS 翻译失败
|
||
self.Gen.TypeGenErr.fatal_error(target, "rhs 翻译失败", "TypeError")
|
||
|
||
# 4. 类型对齐 + 应用二元运算
|
||
# 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__)
|
||
result: llvmlite.Value | t.CPtr = self._apply_aug_op(
|
||
pool, builder, aug.op, cur_val, rhs_val, node, trans, target)
|
||
if result is None:
|
||
# fail-fast: 二元运算失败
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
target,
|
||
f"对变量 '{nm.id}' 应用二元运算失败 op={aug.op}",
|
||
"TypeError")
|
||
|
||
# 5. 存储结果
|
||
result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node)
|
||
if result is None:
|
||
# fail-fast: 类型对齐失败
|
||
self.Gen.TypeGenErr.fatal_error(target, "类型对齐失败", "TypeError")
|
||
|
||
if scope_type == 1:
|
||
# global 变量
|
||
if target_alloca is not None:
|
||
llvmlite.build_store(builder, result, target_alloca)
|
||
elif scope_type == 2:
|
||
# nonlocal 变量
|
||
nl_ptr: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.get_nonlocal_var_ptr(
|
||
trans, nm.id)
|
||
if nl_ptr is not None:
|
||
llvmlite.build_store(builder, result, nl_ptr)
|
||
else:
|
||
# 普通局部变量
|
||
if target_alloca is not None:
|
||
llvmlite.build_store(builder, result, target_alloca)
|
||
|
||
return 0
|
||
|
||
# ============================================================
|
||
# is_ctypedef_annotation - 检测注解是否为 t.CTypedef
|
||
#
|
||
# 迁移自 HandlesAnnAssign.is_ctypedef_annotation(模块级委托壳);
|
||
# 真实实现 TypeGenCType._is_ctypedef_annotation 在另一 Mixin,经
|
||
# gen 单例(HandlesExpr._g_gen 镜像)跨链调用。
|
||
# ============================================================
|
||
def is_ctypedef_annotation(self, annot: ast.AST | t.CPtr) -> int:
|
||
"""检测注解是否为 t.CTypedef,返回 1 表示是,0 表示否"""
|
||
return self.Gen.TypeGenCType._is_ctypedef_annotation(annot)
|
||
|
||
# ============================================================
|
||
# _is_single_param_carray_annot - 检查注解是否为单参 t.CArray[elem_ty]
|
||
#
|
||
# 单参形式(t.CArray[elem_ty])与 count=None 形式(t.CArray[elem_ty, None])
|
||
# 都解析为 Ptr(elem_ty)。当 RHS 是列表字面量时,按 TPC 语义应推断为
|
||
# 静态数组 [len x elem_ty](对齐 TPC ParseListAnnotation 的 is_pointer 分支:
|
||
# "单参数 list[type] → 指针,但如果有列表字面量初始化值则按数组 list[type, N] 处理")。
|
||
# ============================================================
|
||
def _is_single_param_carray_annot(self, annot: ast.AST | t.CPtr) -> int:
|
||
"""检查注解是否为单参/None 长度 t.CArray[...],返回 1=是 0=否
|
||
|
||
支持两种书写形式:
|
||
1. 模块限定 t.CArray[...](Attribute value)
|
||
2. 裸名 CArray[...](from t import * 后使用) # 存疑
|
||
"""
|
||
if annot is None or annot.kind() != ast.ASTKind.Subscript:
|
||
return 0
|
||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot)
|
||
if sub.value is None or sub.slice is None:
|
||
return 0
|
||
if sub.value.kind() == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value)
|
||
if at.attr is None or string.strcmp(at.attr, "CArray") != 0:
|
||
return 0
|
||
if at.value is None or at.value.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
mv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||
if mv.id is None or string.strcmp(mv.id, "t") != 0:
|
||
return 0
|
||
elif sub.value.kind() == ast.ASTKind.Name:
|
||
# 裸名 CArray(from t import *):与 t.CArray 等价
|
||
bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
|
||
if bn.id is None or string.strcmp(bn.id, "CArray") != 0:
|
||
return 0
|
||
else:
|
||
return 0
|
||
# 单参形式:slice 非 Tuple(如 t.CArray[u64] / CArray[str])
|
||
if sub.slice.kind() != ast.ASTKind.Tuple:
|
||
return 1
|
||
# 双参形式:count=None(t.CArray[u64, None])→ 等价单参
|
||
tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice)
|
||
if tup.elts is None or len(tup.elts) < 2:
|
||
return 0
|
||
cnt_node: ast.AST | t.CPtr = tup.elts.get(1)
|
||
if cnt_node is not None and cnt_node.kind() == ast.ASTKind.Constant:
|
||
cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(cnt_node)
|
||
if cn0.const_kind == ast.CONST_NONE:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _infer_static_array_ty_from_literal - 单参 CArray + 列表字面量 → 静态数组
|
||
#
|
||
# 单参 t.CArray[elem_ty] 解析为 Ptr(elem_ty),但当 RHS 是列表字面量时,
|
||
# 按 TPC 语义应推断为 [len x elem_ty](对齐 TPC ParseListAnnotation):
|
||
# 避免误走动态 list 构造(_find_pool_var 兜底引用外部 @_mbuddy → 链接期
|
||
# undefined)。PreScan 与 Handle 都调用(PreScan 预创建 alloca 的类型必须
|
||
# 与 Handle 一致,否则 get_or_create_sym 复用旧 alloca 使推断失效)。
|
||
# ============================================================
|
||
def _infer_static_array_ty_from_literal(self, pool: memhub.MemBuddy | t.CPtr,
|
||
annot: ast.AST | t.CPtr,
|
||
value: ast.AST | t.CPtr,
|
||
resolved_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||
"""单参 CArray + 列表字面量 → Array(elem_ty, len);否则返回原类型"""
|
||
if value is not None and value.kind() == ast.ASTKind.List and resolved_ty is not None:
|
||
if self._is_single_param_carray_annot(annot) != 0:
|
||
elem_ty_arr: llvmlite.LLVMType | t.CPtr = resolved_ty.Pointee
|
||
lst_arr: ast.List | t.CPtr = (ast.List | t.CPtr)(value)
|
||
cnt_arr: int = 0
|
||
if lst_arr.elts is not None:
|
||
cnt_arr = len(lst_arr.elts)
|
||
if elem_ty_arr is not None and cnt_arr > 0:
|
||
return llvmlite.Array(pool, elem_ty_arr, cnt_arr)
|
||
return resolved_ty
|
||
|
||
# ============================================================
|
||
# translate_annassign_prescan - 预扫描 AnnAssign(迁移自
|
||
# HandlesAnnAssign.AnnAssignHandle.PreScan)
|
||
#
|
||
# 为有类型注解的变量提前创建 alloca 到 entry block 顶部;返回新增的变量数
|
||
# ============================================================
|
||
def translate_annassign_prescan(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""预扫描 AnnAssign,提前创建 alloca 到 entry block 顶部"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k != ast.ASTKind.AnnAssign:
|
||
return 0
|
||
|
||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||
if aa is None or aa.target is None:
|
||
return 0
|
||
target: ast.AST | t.CPtr = aa.target
|
||
if target.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
||
if nm.id is None:
|
||
return 0
|
||
|
||
# CDefine 注解: 不创建 alloca,但注册常量到全局表
|
||
# 供后续 t.CArray[elem_ty, NAME] 编译期解析使用
|
||
# 浮点/整数自动识别(与 Handle/handle_module_level_var 路径一致)
|
||
if self.is_cdefine_annotation(aa.annotation) != 0:
|
||
pool_ps: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
self._register_cdefine_from_value(pool_ps, nm.id, aa.value)
|
||
return 0
|
||
|
||
# CTypedef 注解: 类型别名(ScanCTypedefDeclarations 已注册到 CTypedef 表),
|
||
# 不创建全局/局部存储——否则 stdint.vp 的 float64_t: t.CTypedef = t.CFloat64T
|
||
# 等生成 @float64_t 符号,链接 duplicate symbol warning
|
||
if self.is_ctypedef_annotation(aa.annotation) != 0:
|
||
return 0
|
||
|
||
# global/nonlocal 变量不需要局部 alloca
|
||
if GenApi.is_global_name(trans, nm.id) != 0:
|
||
return 0
|
||
if GenApi.is_nonlocal_name(trans, nm.id) != 0:
|
||
return 0
|
||
|
||
# 模块级全局变量已由 handle_module_level_var 注册到模块作用域。
|
||
# Python 语义:仅模块级代码(Current == Root)时跳过局部 alloca;
|
||
# 函数内无 global 声明时应创建局部变量(不遮蔽全局)。
|
||
if self.Gen.VarGen.is_module_scope(trans.SymTab) != 0:
|
||
if self.Gen.VarGen.lookup_module_var(trans.SymTab, nm.id) is not None:
|
||
return 0
|
||
|
||
# 检查是否已存在
|
||
existing: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current(
|
||
trans.SymTab, nm.id)
|
||
if existing is not None:
|
||
return 0
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
|
||
# 从 annotation 推断类型(修复:原硬编码 i32 导致 str 等类型错误)
|
||
var_ty: llvmlite.LLVMType | t.CPtr = None
|
||
annot: ast.AST | t.CPtr = aa.annotation
|
||
if annot is not None:
|
||
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||
pool, annot, trans._imported_modules, trans._from_imports, trans, 0)
|
||
if resolved is None:
|
||
# 尝试特化泛型类注解(如 list[str])
|
||
# resolve_annotation_type 返回 None 可能是因为泛型类未特化
|
||
if annot.kind() == ast.ASTKind.Subscript:
|
||
sub_annot: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot)
|
||
if sub_annot.value is not None and sub_annot.value.kind() == ast.ASTKind.Name:
|
||
sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_annot.value)
|
||
if sub_nm.id is not None:
|
||
template_cd: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(sub_nm.id)
|
||
spec_name_ps: str = None
|
||
if template_cd is not None:
|
||
type_args_ps: list[str] | t.CPtr = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_annot.slice, trans._from_imports)
|
||
if type_args_ps is not None and len(type_args_ps) > 0:
|
||
spec_name_ps = self.Gen.ClassGenGeneric._specialize_generic_class(
|
||
trans, sub_nm.id, type_args_ps)
|
||
if spec_name_ps is not None:
|
||
resolved = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||
pool, annot, trans._imported_modules, trans._from_imports, trans, 0)
|
||
if resolved is not None:
|
||
var_ty = resolved
|
||
# 单参 t.CArray[elem_ty] + 列表字面量 → 静态数组(与 Handle 推断一致)。
|
||
# PreScan 预创建的 alloca 类型必须与 Handle 期望一致,否则 Handle 的
|
||
# get_or_create_sym 复用旧 alloca,数组推断失效仍走动态 list → _mbuddy。
|
||
var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty)
|
||
else:
|
||
# fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32)
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
aa,
|
||
f"变量类型注解解析失败,变量名: {nm.id}",
|
||
"TypeError")
|
||
else:
|
||
# fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32)
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
aa,
|
||
f"AnnAssign 缺少类型注解,变量名: {nm.id}",
|
||
"SyntaxError")
|
||
|
||
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
|
||
self.Gen.StructGen.ensure_struct_def_in_module(pool, trans.Module, var_ty)
|
||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, var_ty)
|
||
if alloca is not None:
|
||
if self.Gen.VarGen.define_var(
|
||
trans.SymTab, nm.id, alloca) == 0:
|
||
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
|
||
# 传 pool:泛型 Subscript 返回 mangled name(GSList[BasicBlock] → 特化
|
||
# struct 名),否则 pool=None 只返回裸类名(GSList → 泛型模板未注册
|
||
# → 属性访问 lookup_field_by_class("GSList") 报"类未注册",LLVMLiteTest
|
||
# __function.vp blocks.Tail 根因;对齐 ClassGenMixin L3159 BUG 1 方案3)
|
||
if annot is not None:
|
||
cls_nm_ps: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(
|
||
annot, trans._imported_modules, pool, trans._from_imports)
|
||
if cls_nm_ps is not None:
|
||
self.Gen.VarGen.set_var_annot_class_name(
|
||
trans.SymTab, nm.id, cls_nm_ps)
|
||
# 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长)
|
||
if self._is_ptr_element_annotation(annot) != 0:
|
||
self.Gen.VarGen.set_var_ptr_element(
|
||
trans.SymTab, nm.id)
|
||
return 0
|
||
return 0
|
||
|
||
# ============================================================
|
||
# translate_annassign - 翻译 AnnAssign 语句(迁移自
|
||
# HandlesAnnAssign.AnnAssignHandle.Handle)
|
||
#
|
||
# 返回新增的变量数
|
||
# ============================================================
|
||
def translate_annassign(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译 AnnAssign(target=Name, annotation=..., value=expr)"""
|
||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||
if aa is None:
|
||
return 0
|
||
|
||
target: ast.AST | t.CPtr = aa.target
|
||
if target is None or target.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
||
if nm.id is None:
|
||
return 0
|
||
|
||
# CDefine 注解: 编译期常量,不生成运行时代码
|
||
# 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析
|
||
# 注: PreScan 已注册过,此处保证即使跳过 PreScan 也能正确注册
|
||
if self.is_cdefine_annotation(aa.annotation) != 0:
|
||
pool_cd: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
self._register_cdefine_from_value(pool_cd, nm.id, aa.value)
|
||
return 0
|
||
|
||
# CTypedef 注解: 类型别名(mode_t: t.CTypedef = t.CUInt32T 等)。
|
||
# 翻译期 CTypedef 表已被 clear_ctypedefs 清空(每文件隔离;表字符串
|
||
# pool 分配,reset_to(mark1) 回收后悬空,不能跨文件累积),必须在此
|
||
# 按需注册,否则 posix.vp S_ISREG(mode: mode_t) 等普通函数参数注解
|
||
# 解析查表失败 → NameError: mode_t。仅登记类型表达式,不创建全局/
|
||
# 局部存储——否则生成 @mode_t 符号,链接 duplicate symbol warning。
|
||
if self.is_ctypedef_annotation(aa.annotation) != 0:
|
||
pool_ct: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
ctd_str: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool_ct, aa.value)
|
||
if ctd_str is not None:
|
||
self.Gen.TypeGenCType.register_ctypedef(pool_ct, nm.id, ctd_str)
|
||
return 0
|
||
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
|
||
# 确定类型(从 annotation 推断)
|
||
var_ty: llvmlite.LLVMType | t.CPtr = None
|
||
annot: ast.AST | t.CPtr = aa.annotation
|
||
if annot is not None:
|
||
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||
pool, annot, trans._imported_modules, trans._from_imports, trans, 0)
|
||
if resolved is not None:
|
||
var_ty = resolved
|
||
else:
|
||
# fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32)
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
aa,
|
||
f"变量类型注解解析失败,变量名: {nm.id}",
|
||
"TypeError")
|
||
else:
|
||
# fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32)
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
aa,
|
||
f"AnnAssign 缺少类型注解,变量名: {nm.id}",
|
||
"SyntaxError")
|
||
|
||
# t.Callable 函数指针:注册返回类型签名(供函数指针间接调用精确返回类型)
|
||
callable_ret: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenErr.try_extract_callable_ret(
|
||
pool, annot, trans._imported_modules, trans._from_imports, trans, 0)
|
||
if callable_ret is not None:
|
||
self.Gen.CallGenLeafKit.register_func_ptr_sig(nm.id, callable_ret)
|
||
|
||
# global 变量:写入模块作用域中的全局变量
|
||
if GenApi.is_global_name(trans, nm.id) != 0:
|
||
mod_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var(
|
||
trans.SymTab, nm.id)
|
||
if mod_alloca is not None and aa.value is not None:
|
||
rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, aa.value,
|
||
None, 0, trans)
|
||
if rhs_val is not None:
|
||
target_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if mod_alloca.Ty is not None:
|
||
target_ty = mod_alloca.Ty.Pointee
|
||
if target_ty is not None:
|
||
rhs_val = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, target_ty, node)
|
||
llvmlite.build_store(builder, rhs_val, mod_alloca)
|
||
return 0
|
||
|
||
# nonlocal 变量:通过闭包 env 写入
|
||
if GenApi.is_nonlocal_name(trans, nm.id) != 0:
|
||
if aa.value is not None:
|
||
rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, aa.value,
|
||
None, 0, trans)
|
||
if rhs_val is not None:
|
||
nl_ptr: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.get_nonlocal_var_ptr(
|
||
trans, nm.id)
|
||
if nl_ptr is not None:
|
||
# 从 nl_ptr 的类型推断 nonlocal 变量实际类型,
|
||
# 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏)
|
||
nl_target_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if nl_ptr.Ty is not None:
|
||
nl_target_ty = nl_ptr.Ty.Pointee
|
||
if nl_target_ty is None:
|
||
# fast-fail: nl_ptr 类型信息丢失,无法安全 store
|
||
VLogger.error(
|
||
f"nonlocal 变量类型信息丢失,无法写入: {nm.id}",
|
||
"HandlesAnnAssign")
|
||
return 0
|
||
rhs_coerced: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, rhs_val, nl_target_ty, node)
|
||
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
|
||
return 0
|
||
|
||
# 模块级全局变量(由 handle_module_level_var 注册到模块作用域)
|
||
# Python 语义:仅模块级代码(Current == Root)时修改全局变量;
|
||
# 函数内无 global 声明时应创建局部变量(走后面的 get_or_create_sym 路径)。
|
||
if self.Gen.VarGen.is_module_scope(trans.SymTab) != 0:
|
||
mod_glob: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var(
|
||
trans.SymTab, nm.id)
|
||
else:
|
||
mod_glob = None
|
||
if mod_glob is not None:
|
||
if aa.value is not None:
|
||
# 列表字面量 → 逐元素 GEP + store 初始化数组
|
||
if aa.value.kind() == ast.ASTKind.List:
|
||
self._init_global_array_from_list(
|
||
builder, pool, mod, mod_glob, aa.value, trans)
|
||
else:
|
||
rhs_val_mg: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, aa.value,
|
||
None, 0, trans)
|
||
if rhs_val_mg is not None:
|
||
target_ty_mg: llvmlite.LLVMType | t.CPtr = None
|
||
if mod_glob.Ty is not None:
|
||
target_ty_mg = mod_glob.Ty.Pointee
|
||
if target_ty_mg is not None:
|
||
rhs_val_mg = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node)
|
||
llvmlite.build_store(builder, rhs_val_mg, mod_glob)
|
||
return 0
|
||
|
||
# 单参 t.CArray[elem_ty] + 列表字面量 → 按静态数组处理(count 从字面量长度推断)
|
||
# 与 PreScan 推断一致:get_or_create_sym 复用 PreScan 创建的 alloca,
|
||
# 类型一致才能命中局部数组快路径,避免 _find_pool_var 兜底引用 @_mbuddy。
|
||
var_ty = self._infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty)
|
||
|
||
# 普通局部变量
|
||
# 创建 alloca
|
||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.get_or_create_sym(
|
||
trans.SymTab, pool, builder, nm.id, var_ty)
|
||
if alloca is None:
|
||
# fail-fast: 存储创建失败,立即终止(禁止静默跳过)
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
aa,
|
||
f"无法为变量 {nm.id} 创建存储",
|
||
"TypeError")
|
||
# FakeDuck: str 变量创建影子结构体 {var}__meta__(per-instance 字段存储)
|
||
# 仅裸 str 注解(Name("str"))且 _str 已注册时创建;bytes / t.CChar|t.CPtr 不创建。
|
||
# a 保持为 i8*(可 printf/len),a__meta__ 存 __data__/__mbuddy__ 等字段,
|
||
# 属性读写(fd3)与方法调用(fd5)均通过该影子解析。
|
||
fd_str_ty: llvmlite.LLVMType | t.CPtr = None
|
||
fd_meta_alloca: llvmlite.Value | t.CPtr = None
|
||
fd_meta_name: str = None
|
||
if annot is not None and annot.kind() == ast.ASTKind.Name:
|
||
fd_annot: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot)
|
||
if fd_annot is not None and fd_annot.id is not None:
|
||
if string.strcmp(fd_annot.id, "str") == 0:
|
||
fd_str_ty = self.Gen.StructGen.get_struct_type("_str")
|
||
if fd_str_ty is not None:
|
||
# 确保 _str 完整类型定义在当前模块可用:跨模块结构体默认 opaque,
|
||
# 直接 alloca opaque 类型 → llc "Cannot allocate unsized type"
|
||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, fd_str_ty)
|
||
# 影子变量名必须用 pool 持久缓冲:f-string 生成栈缓冲,在 AnnAssign
|
||
# 返回后被覆盖,符号表注册的名字内容损坏 → 后续 lookup 找不到。
|
||
fd_meta_name = pool.alloc(256)
|
||
if fd_meta_name is not None:
|
||
viperlib.snprintf(fd_meta_name, 256, "%s__meta__", nm.id)
|
||
fd_meta_alloca = self.Gen.VarGen.get_or_create_sym(
|
||
trans.SymTab, pool, builder, fd_meta_name, fd_str_ty)
|
||
if fd_meta_alloca is None:
|
||
# fail-fast: 影子存储创建失败,立即终止
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
aa,
|
||
f"无法为 str 影子变量 {fd_meta_name} 创建存储",
|
||
"TypeError")
|
||
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
|
||
# 传 pool:泛型 Subscript 返回 mangled name(对齐 L401 同根因修复)
|
||
if annot is not None:
|
||
cls_nm_hd: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(
|
||
annot, trans._imported_modules, pool, trans._from_imports)
|
||
if cls_nm_hd is not None:
|
||
self.Gen.VarGen.set_var_annot_class_name(
|
||
trans.SymTab, nm.id, cls_nm_hd)
|
||
# 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长)
|
||
if self._is_ptr_element_annotation(annot) != 0:
|
||
self.Gen.VarGen.set_var_ptr_element(
|
||
trans.SymTab, nm.id)
|
||
|
||
new_vars: int = 0
|
||
existing: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current(
|
||
trans.SymTab, nm.id)
|
||
if existing is None:
|
||
new_vars = 1
|
||
|
||
# 如果有初始值,store
|
||
if aa.value is not None:
|
||
# 协程(TPV-M1):记录 async 函数调用赋值的变量名(coro.coro_run
|
||
# 内联翻译反查帧类型用)。对齐 TPC HandlesAnnAssign.py L319-326:
|
||
# value 是 Call 且 func 是 Name 且该名字是 async 函数时,
|
||
# 登记 _coro_var_async[target] = callee。
|
||
if aa.value.kind() == ast.ASTKind.Call:
|
||
val_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(aa.value)
|
||
if val_cl.func is not None and val_cl.func.kind() == ast.ASTKind.Name:
|
||
val_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_cl.func)
|
||
if val_nm.id is not None:
|
||
if self.Gen.AsyncGen.is_async_func(trans, val_nm.id) != 0:
|
||
self.Gen.AsyncGen.register_coro_var(trans, nm.id, val_nm.id)
|
||
# c.Addr(async_call):tt: Coroutine = c.Addr(task()) 就地解读
|
||
elif val_cl.func is not None and val_cl.func.kind() == ast.ASTKind.Attribute:
|
||
val_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(val_cl.func)
|
||
if val_at.attr is not None and string.strcmp(val_at.attr, "Addr") == 0 \
|
||
and val_cl.args is not None and len(val_cl.args) >= 1:
|
||
icall: ast.AST | t.CPtr = val_cl.args.get(0)
|
||
if icall is not None and icall.kind() == ast.ASTKind.Call:
|
||
icl2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(icall)
|
||
if icl2.func is not None and icl2.func.kind() == ast.ASTKind.Name:
|
||
inm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(icl2.func)
|
||
if inm2.id is not None:
|
||
if self.Gen.AsyncGen.is_async_func(trans, inm2.id) != 0:
|
||
self.Gen.AsyncGen.register_coro_var(trans, nm.id, inm2.id)
|
||
# 局部数组:列表字面量 → 逐元素 GEP + store 初始化
|
||
# 修复:此前局部 CArray[...] = [x, y] 会走 translate_list_literal,
|
||
# 错误触发 list[T] 泛型特化(堆对象)导致崩溃(如 this.vp 的
|
||
# t.CArray[t.CChar, 256] = [0])。局部 alloca 未零初始化,
|
||
# 先整体置零再写列表元素(与全局数组默认零初始化语义一致)。
|
||
local_arr_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if aa.value.kind() == ast.ASTKind.List and alloca.Ty is not None:
|
||
pt_l: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||
if self.Gen.ExprGenBase.is_array_type(pt_l) != 0:
|
||
local_arr_ty = pt_l
|
||
if local_arr_ty is not None:
|
||
zero_arr: llvmlite.Value | t.CPtr = llvmlite.ConstZero(
|
||
pool, local_arr_ty)
|
||
if zero_arr is not None:
|
||
llvmlite.build_store(builder, zero_arr, alloca)
|
||
self._init_global_array_from_list(
|
||
builder, pool, mod, alloca, aa.value, trans)
|
||
else:
|
||
# 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → 读 i32
|
||
# CurAssignNode 记录 RHS 节点:translate_c_deref 据此判定 Deref
|
||
# 是否为赋值直接 RHS(对齐 TPC _infer_deref_target_type)。
|
||
trans.CurAssignAnnot = aa.annotation
|
||
trans.CurAssignNode = aa.value
|
||
rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, aa.value,
|
||
None, 0, trans)
|
||
if rhs_val is not None:
|
||
# 注解退化修复(对齐 TPC 从构造结果推断类型):
|
||
# 无实参泛型模板类注解(如 vi: vector.Vector | CPtr,模板
|
||
# 未注册 struct → resolve 退化)会让 alloca 类型退化为
|
||
# Ptr(i8),但 rhs 构造返回精确结构体指针(如 Ptr(Vector[int]
|
||
# 结构))。此时按退化 alloca store 会丢失特化类型,后续
|
||
# vi.push 方法调用按 Ptr(i8) 查不到类名 → AnnotClassName
|
||
# 回退到模板名(无实参)→ vpi 查不到返回类型 fail-fast。
|
||
# 用 rhs 精确类型重建 alloca 并更新符号表注册,使方法调用
|
||
# 按精确特化类名解析。旧退化 alloca 行残留为 entry block
|
||
# 死代码(文本 IR 即时生成,无法删除,无害)。
|
||
precise_rhs_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if rhs_val.Ty is not None:
|
||
match rhs_val.Ty:
|
||
case llvmlite.LLVMType.Ptr(inner_struct):
|
||
match inner_struct:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
precise_rhs_ty = rhs_val.Ty
|
||
case _:
|
||
pass
|
||
case _:
|
||
pass
|
||
if precise_rhs_ty is not None and alloca.Ty is not None:
|
||
alloca_pt: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||
if alloca_pt is not None and \
|
||
t.CUInt64T(alloca_pt) != t.CUInt64T(precise_rhs_ty):
|
||
new_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(
|
||
builder, precise_rhs_ty)
|
||
if new_alloca is not None:
|
||
v_entry_rb: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||
trans.SymTab, nm.id)
|
||
if v_entry_rb is not None:
|
||
v_entry_rb.Alloca = new_alloca
|
||
alloca = new_alloca
|
||
# 类型转换:将 rhs_val 转换为 alloca 的 pointee 类型
|
||
# 修复:整数字面量是 i32,但变量可能是 i8/i16/i64,需 trunc/sext
|
||
target_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if alloca.Ty is not None:
|
||
target_ty = alloca.Ty.Pointee
|
||
if target_ty is not None:
|
||
rhs_val = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, target_ty, node)
|
||
llvmlite.build_store(builder, rhs_val, alloca)
|
||
# FakeDuck: 初始化影子结构体 __data__ 字段 = 初始字符串指针
|
||
# (对齐 TPC HandlesAnnAssign.py: 仅当有初值时写入 __data__)
|
||
if fd_str_ty is not None and fd_meta_alloca is not None:
|
||
fd_data_fe: GenTypes.FieldEntry | t.CPtr = \
|
||
self.Gen.StructGen.lookup_field(fd_str_ty, "__data__")
|
||
if fd_data_fe is not None:
|
||
fd_data_ptr: llvmlite.Value | t.CPtr = \
|
||
llvmlite.build_gep_struct(
|
||
builder, fd_str_ty, fd_data_fe.Ty,
|
||
fd_meta_alloca, fd_data_fe.Index)
|
||
if fd_data_ptr is not None:
|
||
llvmlite.build_store(builder, rhs_val, fd_data_ptr)
|
||
# 清除赋值上下文(防残留):CurAssignAnnot/CurAssignNode 只在该
|
||
# AnnAssign 的 RHS 翻译期间有效,否则后续 while 条件/比较等处的
|
||
# c.Deref 会被残留注解误判读取宽度(i8* 被 bitcast i32* 读 4 字节)。
|
||
trans.CurAssignAnnot = None
|
||
trans.CurAssignNode = None
|
||
|
||
# FakeDuck: __mbuddy__ 字段初始化为 NULL。
|
||
# with 上下文提供的 __mbuddy__ 注入由 _inject_requires_fields(fd4)完成,
|
||
# 此处仅确保影子结构体初始为空指针(对齐 TPC HandlesAnnAssign.py L667-670)。
|
||
if fd_str_ty is not None and fd_meta_alloca is not None:
|
||
fd_buddy_fe: GenTypes.FieldEntry | t.CPtr = \
|
||
self.Gen.StructGen.lookup_field(fd_str_ty, "__mbuddy__")
|
||
if fd_buddy_fe is not None and fd_buddy_fe.Ty is not None:
|
||
fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(
|
||
pool, fd_buddy_fe.Ty, "null")
|
||
fd_buddy_ptr: llvmlite.Value | t.CPtr = \
|
||
llvmlite.build_gep_struct(
|
||
builder, fd_str_ty, fd_buddy_fe.Ty,
|
||
fd_meta_alloca, fd_buddy_fe.Index)
|
||
if fd_buddy_ptr is not None and fd_null is not None:
|
||
llvmlite.build_store(builder, fd_null, fd_buddy_ptr)
|
||
# FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__)。
|
||
# 跨 Mixin 经 self.Gen 调用 CallGenFd._inject_requires_fields。
|
||
self.Gen.CallGenFd._inject_requires_fields(
|
||
trans, pool, builder, mod, fd_meta_alloca, "_str")
|
||
|
||
return 0
|
||
|
||
# ============================================================
|
||
# translate_assign - 处理 Assign 语句,返回新增变量数(0 或 1)
|
||
#
|
||
# 迁移自 HandlesAssign.AssignHandle.Handle(对应 TransPyC
|
||
# AssignHandle._HandleAssignLlvm)。共享状态从 trans 获取。
|
||
# ============================================================
|
||
def translate_assign(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""翻译 Assign 语句,返回新增变量数(0 或 1)"""
|
||
|
||
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||
if asgn is None:
|
||
VLogger.error("cast failed", "ASGN")
|
||
return 0
|
||
|
||
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
|
||
if targets is None:
|
||
VLogger.error("targets is None", "ASGN")
|
||
return 0
|
||
|
||
# 从 trans 取共享状态(替代 11 个参数)
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
|
||
# 翻译 RHS 值
|
||
# 无注解赋值无目标类型可推断,清空 CurAssignAnnot/CurAssignNode
|
||
# (防残留误判 c.Deref 宽度)
|
||
trans.CurAssignAnnot = None
|
||
trans.CurAssignNode = None
|
||
rhs_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, asgn.value, None, 0, trans)
|
||
if rhs_val is None:
|
||
# Phase A 依赖未就绪(_deps_pending=1):跨模块函数/方法因 text.ll
|
||
# 未生成返回类型退化为 void/None(CallGenMixin L4493
|
||
# g_vta._resolve_attr_field_class 根因)。此时整文件不写盘、下遍重译
|
||
# (Phase2.vp L590-599),跳过本语句不报错——否则 fatal 使多遍
|
||
# 重试机制永远无法收敛(本语句只是"本遍保持默认类型"的退化结果,
|
||
# 下遍依赖已生成即可精确解析)。依赖就绪时 _deps_pending=0,
|
||
# 此处仍 fail-fast,不掩盖真实错误。
|
||
if trans is not None and trans._deps_pending != 0:
|
||
return 0
|
||
# 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位
|
||
if asgn.value is not None:
|
||
sha1: str = trans.ModuleSha1
|
||
val_kind: int = asgn.value.kind()
|
||
val_line: t.CInt = asgn.value.lineno
|
||
# 通过 sha1 查找文件名(人类可读)
|
||
rel_path: str = None
|
||
if sha1 is not None:
|
||
rel_path = StubMergerStore.LookupSha1RelPath(sha1)
|
||
# 根据 AST 节点类型提取详情
|
||
if val_kind == ast.ASTKind.Attribute:
|
||
at_nv: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(asgn.value)
|
||
attr_nm: str = at_nv.attr
|
||
target_nm: str = "?"
|
||
if at_nv.value is not None:
|
||
if at_nv.value.kind() == ast.ASTKind.Name:
|
||
tn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_nv.value)
|
||
target_nm = tn_nm.id
|
||
if rel_path is not None:
|
||
VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} '{target_nm}.{attr_nm}' 属性访问失败", "ASGN")
|
||
else:
|
||
VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} '{target_nm}.{attr_nm}' 属性访问失败", "ASGN")
|
||
elif val_kind == ast.ASTKind.Name:
|
||
nm_nv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(asgn.value)
|
||
if rel_path is not None:
|
||
VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} 变量 '{nm_nv.id}' 未找到", "ASGN")
|
||
else:
|
||
VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} 变量 '{nm_nv.id}' 未找到", "ASGN")
|
||
elif val_kind == ast.ASTKind.Call:
|
||
cl_nv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(asgn.value)
|
||
func_nm: str = "?"
|
||
if cl_nv.func is not None:
|
||
if cl_nv.func.kind() == ast.ASTKind.Name:
|
||
fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_nv.func)
|
||
func_nm = fn_nm.id
|
||
if rel_path is not None:
|
||
VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} 调用 '{func_nm}(...)' 返回 None", "ASGN")
|
||
else:
|
||
VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} 调用 '{func_nm}(...)' 返回 None", "ASGN")
|
||
else:
|
||
if rel_path is not None:
|
||
VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} [kind={val_kind}]")
|
||
else:
|
||
VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} [kind={val_kind}]")
|
||
else:
|
||
VLogger.error("赋值右侧为 None (asgn.value 为空)", "ASGN")
|
||
return 0
|
||
|
||
new_vars: int = 0
|
||
tn: t.CSizeT = len(targets)
|
||
for ti in range(tn):
|
||
target: ast.AST | t.CPtr = targets.get(ti)
|
||
if target is None:
|
||
continue
|
||
|
||
tk: int = target.kind()
|
||
|
||
# Tuple 赋值: a, b = f() 多返回值解包
|
||
# rhs_val 是匿名 struct 值(函数返回 tuple[T1,T2] 打包)→ alloca +
|
||
# store + GEP 逐字段 load → store 到各 Name 目标。
|
||
if tk == ast.ASTKind.Tuple:
|
||
tgt_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target)
|
||
tgt_elts: list[ast.AST | t.CPtr] | t.CPtr = tgt_tup.elts
|
||
# 守卫:rhs 不是 struct(tuple 打包)时跳过本 target
|
||
if tgt_elts is None or rhs_val is None or rhs_val.Ty is None:
|
||
continue
|
||
match rhs_val.Ty:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
tgt_n: t.CSizeT = len(tgt_elts)
|
||
tmp_s: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, rhs_val.Ty)
|
||
if tmp_s is not None:
|
||
llvmlite.build_store(builder, rhs_val, tmp_s)
|
||
fchain: llvmlite.ParamNode | t.CPtr = llvmlite.get_struct_fields(rhs_val.Ty)
|
||
fcur: llvmlite.ParamNode | t.CPtr = fchain
|
||
fti: t.CSizeT
|
||
for fti in range(tgt_n):
|
||
tgt_elt: ast.AST | t.CPtr = tgt_elts.get(fti)
|
||
if tgt_elt is None or fcur is None:
|
||
break
|
||
fty: llvmlite.LLVMType | t.CPtr = llvmlite.paramnode_get_ty(fcur)
|
||
fcur = llvmlite.paramnode_get_next(fcur)
|
||
if fty is None:
|
||
# fail-fast: 字段类型缺失,立即终止
|
||
self.Gen.TypeGenErr.fatal_error(target, "元组解包字段类型缺失", "TypeError")
|
||
# 守卫:非 Name 元素无法解包,跳过
|
||
if tgt_elt.kind() != ast.ASTKind.Name:
|
||
continue
|
||
tgt_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_elt)
|
||
if tgt_nm2.id is None:
|
||
continue
|
||
fp2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, rhs_val.Ty, fty, tmp_s, fti)
|
||
if fp2 is None:
|
||
continue
|
||
fv2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, fty, fp2)
|
||
tgt_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||
trans.SymTab, tgt_nm2.id)
|
||
if tgt_alloca is None:
|
||
tgt_alloca = self.Gen.VarGen.get_or_create_sym(
|
||
trans.SymTab, pool, builder, tgt_nm2.id, fty)
|
||
if tgt_alloca is None:
|
||
continue
|
||
sval: llvmlite.Value | t.CPtr = fv2
|
||
if tgt_alloca.Ty is not None and tgt_alloca.Ty.Pointee is not None:
|
||
sval = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, fv2, tgt_alloca.Ty.Pointee, node)
|
||
llvmlite.build_store(builder, sval, tgt_alloca)
|
||
case _:
|
||
pass
|
||
continue
|
||
|
||
# Subscript 赋值: arr[i] = val / ptr[i] = val / list[i] = val
|
||
if tk == ast.ASTKind.Subscript:
|
||
# 检查是否是 list[T] 类型的 Subscript(泛型类不注册 struct)
|
||
# list 的 subscript 赋值走 __setitem__ 内联路径
|
||
list_obj: llvmlite.Value | t.CPtr = self.Gen.ExprGenName.is_list_subscript(
|
||
target, trans)
|
||
if list_obj is not None:
|
||
# list[T] 类型: 内联生成 __setitem__ 逻辑
|
||
sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target)
|
||
if sub_node is not None and sub_node.slice is not None:
|
||
list_idx_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, sub_node.slice, None, 0, trans)
|
||
if list_idx_val is None:
|
||
# fail-fast: list 下标翻译失败,立即终止
|
||
self.Gen.TypeGenErr.fatal_error(target, "list 下标翻译失败", "TypeError")
|
||
self.Gen.ExprGenName.list_setitem_inline(
|
||
builder, pool, list_obj, list_idx_val, rhs_val, target)
|
||
continue
|
||
# 普通 Subscript 赋值
|
||
elem_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenName.get_subscript_ptr(
|
||
builder, pool, mod, target, trans)
|
||
if elem_ptr is not None:
|
||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||
# 守卫短路:elem 类型完整才做类型转换
|
||
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
|
||
store_val = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, rhs_val, elem_ptr.Ty.Pointee, node)
|
||
llvmlite.build_store(builder, store_val, elem_ptr)
|
||
continue
|
||
# get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载
|
||
# 适用于自定义类(如 hashtable[key]=val → hashtable.__setitem__(key, val))
|
||
sub_asgn: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target)
|
||
setitem_done: int = 0
|
||
if sub_asgn is not None and sub_asgn.value is not None:
|
||
if sub_asgn.value.kind() == ast.ASTKind.Name:
|
||
sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_asgn.value)
|
||
if sub_nm.id is not None:
|
||
sub_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(
|
||
trans.SymTab, sub_nm.id)
|
||
if sub_alloca is not None and sub_alloca.Ty is not None \
|
||
and sub_alloca.Ty.Pointee is not None \
|
||
and self.Gen.ExprGenBase.is_ptr_type(sub_alloca.Ty) != 0:
|
||
sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee
|
||
cls_nm_set: str = self.Gen.StructGen.get_class_name_by_type(pool, sub_pointee)
|
||
obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, sub_pointee, sub_alloca)
|
||
# 指针类型变量 (X|t.CPtr): sub_pointee 是 Ptr(Struct),
|
||
# 需 load 获取 Ptr(Struct) 再检查 inner struct
|
||
if cls_nm_set is None and obj_val_set is not None \
|
||
and self.Gen.ExprGenBase.is_ptr_type(sub_pointee) != 0 \
|
||
and sub_pointee.Pointee is not None:
|
||
cls_nm_set = self.Gen.StructGen.get_class_name_by_type(
|
||
pool, sub_pointee.Pointee)
|
||
if cls_nm_set is not None and obj_val_set is not None:
|
||
key_val_set: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, sub_asgn.slice, None, 0, trans)
|
||
if key_val_set is not None:
|
||
arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16)
|
||
if arg_vals_set is not None:
|
||
arg_vals_set[0] = t.CSizeT(key_val_set)
|
||
arg_vals_set[1] = t.CSizeT(rhs_val)
|
||
self.Gen.CallGenCall._call_method_on_ptr(
|
||
pool, builder, mod, cls_nm_set, "__setitem__",
|
||
obj_val_set, arg_vals_set, 2, trans)
|
||
setitem_done = 1
|
||
elif sub_asgn.value.kind() == ast.ASTKind.Attribute:
|
||
# self._ht[key] = val → self._ht.__setitem__(key, val)
|
||
# 通过 get_attribute_ptr 获取字段指针,再调用 __setitem__
|
||
field_ptr_set: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr(
|
||
builder, pool, mod, sub_asgn.value, trans)
|
||
if field_ptr_set is not None and field_ptr_set.Ty is not None \
|
||
and field_ptr_set.Ty.Pointee is not None \
|
||
and self.Gen.ExprGenBase.is_ptr_type(field_ptr_set.Ty) != 0:
|
||
field_pointee_set: llvmlite.LLVMType | t.CPtr = field_ptr_set.Ty.Pointee
|
||
cls_nm_attr: str = self.Gen.StructGen.get_class_name_by_type(pool, field_pointee_set)
|
||
obj_val_attr: llvmlite.Value | t.CPtr = field_ptr_set
|
||
# field_ptr 是 Ptr(Ptr(Struct)) (X|t.CPtr 字段):
|
||
# load 解引用获取 Ptr(Struct)
|
||
if cls_nm_attr is None \
|
||
and self.Gen.ExprGenBase.is_ptr_type(field_pointee_set) != 0 \
|
||
and field_pointee_set.Pointee is not None:
|
||
cls_nm_attr = self.Gen.StructGen.get_class_name_by_type(
|
||
pool, field_pointee_set.Pointee)
|
||
if cls_nm_attr is not None:
|
||
obj_val_attr = llvmlite.build_load(
|
||
builder, field_pointee_set, field_ptr_set)
|
||
if cls_nm_attr is not None and obj_val_attr is not None:
|
||
key_val_attr: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, sub_asgn.slice, None, 0, trans)
|
||
if key_val_attr is not None:
|
||
arg_vals_attr: t.CSizeT | t.CPtr = pool.alloc(16)
|
||
if arg_vals_attr is not None:
|
||
arg_vals_attr[0] = t.CSizeT(key_val_attr)
|
||
arg_vals_attr[1] = t.CSizeT(rhs_val)
|
||
self.Gen.CallGenCall._call_method_on_ptr(
|
||
pool, builder, mod, cls_nm_attr, "__setitem__",
|
||
obj_val_attr, arg_vals_attr, 2, trans)
|
||
setitem_done = 1
|
||
if setitem_done == 0:
|
||
# 通用 fallback: 翻译 sub.value 并尝试 __setitem__ 或直接 GEP+store
|
||
# 处理 Name/Attribute 之外的节点以及 SymTab 查找失败的情况
|
||
if sub_asgn is not None and sub_asgn.value is not None:
|
||
obj_val_gen: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, sub_asgn.value, None, 0, trans)
|
||
key_val_gen: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, sub_asgn.slice, None, 0, trans)
|
||
if obj_val_gen is not None and key_val_gen is not None \
|
||
and obj_val_gen.Ty is not None:
|
||
# 内联 _get_custom_struct_cls_nm 逻辑(避免依赖新函数)
|
||
cls_nm_gen: str = self.Gen.StructGen.get_class_name_by_type(
|
||
pool, obj_val_gen.Ty)
|
||
if cls_nm_gen is None and self.Gen.ExprGenBase.is_ptr_type(obj_val_gen.Ty) != 0 \
|
||
and obj_val_gen.Ty.Pointee is not None:
|
||
cls_nm_gen = self.Gen.StructGen.get_class_name_by_type(
|
||
pool, obj_val_gen.Ty.Pointee)
|
||
if cls_nm_gen is not None:
|
||
# 自定义结构体: 调用 __setitem__
|
||
arg_vals_gen: t.CSizeT | t.CPtr = pool.alloc(16)
|
||
if arg_vals_gen is not None:
|
||
arg_vals_gen[0] = t.CSizeT(key_val_gen)
|
||
arg_vals_gen[1] = t.CSizeT(rhs_val)
|
||
self.Gen.CallGenCall._call_method_on_ptr(
|
||
pool, builder, mod, cls_nm_gen, "__setitem__",
|
||
obj_val_gen, arg_vals_gen, 2, trans)
|
||
setitem_done = 1
|
||
elif self.Gen.ExprGenBase.is_ptr_type(obj_val_gen.Ty) != 0 \
|
||
and obj_val_gen.Ty.Pointee is not None:
|
||
# 非自定义结构体: 直接 GEP + store
|
||
# 处理 get_subscript_ptr 因边界情况返回 None 的指针下标
|
||
elem_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee
|
||
store_val_gen: llvmlite.Value | t.CPtr = rhs_val
|
||
elem_ptr_gen: llvmlite.Value | t.CPtr = None
|
||
match elem_gen:
|
||
case llvmlite.LLVMType.Array(arr_elem_gen, _):
|
||
elem_ptr_gen = llvmlite.build_gep_array(
|
||
builder, elem_gen, arr_elem_gen,
|
||
obj_val_gen, key_val_gen)
|
||
case _:
|
||
elem_ptr_gen = llvmlite.build_gep(
|
||
builder, elem_gen, obj_val_gen, key_val_gen)
|
||
if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None:
|
||
if elem_ptr_gen.Ty.Pointee is not None:
|
||
store_val_gen = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, rhs_val, elem_ptr_gen.Ty.Pointee, node)
|
||
llvmlite.build_store(builder, store_val_gen, elem_ptr_gen)
|
||
setitem_done = 1
|
||
if setitem_done == 0:
|
||
self.Gen.TypeGenErr.fatal_error(target, "subscript ptr is None")
|
||
continue
|
||
|
||
# Attribute 赋值: obj.field = val
|
||
if tk == ast.ASTKind.Attribute:
|
||
# property setter 拦截: obj.attr = v 且 attr 是 @x.setter 方法时,
|
||
# 生成 call Class.attr$set(obj, v),跳过字段存储
|
||
# 注意参数顺序:_try_property_setter(pool, builder, mod, ...)——
|
||
# 旧代码传 (builder, pool, ...) 导致 pool/builder 错位,pool 参数
|
||
# 实际是 IRBuilder 对象,pool.alloc 虚调用读 IRBuilder[0] 当 vtable
|
||
# 跳到垃圾地址崩溃(BuiltinDecoratorTest Phase A 崩溃根因)。
|
||
if self.Gen.CallGenProp._try_property_setter(
|
||
pool, builder, mod, target, rhs_val, trans) == 1:
|
||
continue
|
||
# FakeDuck: 影子结构体属性写入 (str 变量的 per-instance 字段)
|
||
# a.__data__ = v → GEP {a}__meta__[field] 并 store
|
||
# 对齐 TPC HandlesAssign.py L67-76:对象是 Name 变量且存在
|
||
# {var}__meta__ 影子(fd2 创建)时,属性写入改走影子结构体。
|
||
fd_an: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target)
|
||
if fd_an is not None and fd_an.value is not None and fd_an.attr is not None:
|
||
if fd_an.value.kind() == ast.ASTKind.Name:
|
||
fd_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_an.value)
|
||
if fd_obj_nm.id is not None:
|
||
# pool 持久缓冲(f-string 栈缓冲在函数返回后失效)
|
||
fd_meta_w: str = pool.alloc(256)
|
||
if fd_meta_w is not None:
|
||
viperlib.snprintf(fd_meta_w, 256, "%s__meta__", fd_obj_nm.id)
|
||
fd_meta_vw: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current(
|
||
trans.SymTab, fd_meta_w)
|
||
if fd_meta_vw is not None:
|
||
fd_sty_w: llvmlite.LLVMType | t.CPtr = \
|
||
self.Gen.StructGen.get_struct_type("_str")
|
||
if fd_sty_w is not None:
|
||
fd_fe_w: GenTypes.FieldEntry | t.CPtr = \
|
||
self.Gen.StructGen.lookup_field(fd_sty_w, fd_an.attr)
|
||
if fd_fe_w is not None and fd_fe_w.Ty is not None:
|
||
fd_fp_w: llvmlite.Value | t.CPtr = \
|
||
llvmlite.build_gep_struct(
|
||
builder, fd_sty_w, fd_fe_w.Ty,
|
||
fd_meta_vw, fd_fe_w.Index)
|
||
if fd_fp_w is not None:
|
||
sv_fd: llvmlite.Value | t.CPtr = \
|
||
self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, rhs_val, fd_fe_w.Ty, node)
|
||
llvmlite.build_store(builder, sv_fd, fd_fp_w)
|
||
continue
|
||
# VTABLE 直接写入:obj.method = func(serial0_file.open = serial0_open)
|
||
# vtable 方法不是数据字段(FieldEntry),get_attribute_ptr 查不到会
|
||
# fatal_error;此处对齐 TPC HandlesAssign.py L905-949 的写时复制,
|
||
# 检测到 vtable 方法时直接生成槽位写入并跳过字段路径。
|
||
if self.Gen.CallGenVt._write_vtable_attr(
|
||
builder, pool, mod, target, rhs_val, trans) == 1:
|
||
continue
|
||
field_ptr: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.get_attribute_ptr(
|
||
builder, pool, mod, target, trans)
|
||
if field_ptr is not None:
|
||
# 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64)
|
||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||
if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None:
|
||
store_val = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, rhs_val, field_ptr.Ty.Pointee, node)
|
||
llvmlite.build_store(builder, store_val, field_ptr)
|
||
continue
|
||
# 守卫:field_ptr 为 None → 构造详细错误信息
|
||
# Phase A 依赖未就绪(_deps_pending):get_attribute_ptr 已因
|
||
# 父类/依赖类未注册跳过字段,此处同样跳过不报错,整文件下遍重译
|
||
# (对齐 HandlesAssign L69-78 与 get_attribute_ptr 的 pending 容忍)
|
||
if trans is not None and trans._deps_pending != 0:
|
||
continue
|
||
attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target)
|
||
attr_name: str = "(unknown)"
|
||
obj_name: str = "(unknown)"
|
||
if attr_node is not None:
|
||
attr_name = attr_node.attr
|
||
if attr_node.value is not None and attr_node.value.kind() == ast.ASTKind.Name:
|
||
obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(attr_node.value)
|
||
obj_name = obj_nm.id
|
||
err_buf: str = pool.alloc(256)
|
||
if err_buf is not None:
|
||
viperlib.snprintf(err_buf, 256,
|
||
"attribute ptr is None: %s.%s",
|
||
obj_name, attr_name)
|
||
self.Gen.TypeGenErr.fatal_error(target, err_buf)
|
||
else:
|
||
self.Gen.TypeGenErr.fatal_error(target, "attribute ptr is None")
|
||
continue
|
||
|
||
# Name 赋值: var = val
|
||
if tk == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
|
||
# 守卫:target 名缺失时跳过
|
||
if nm.id is None:
|
||
continue
|
||
# global 变量:写入模块作用域中的全局变量
|
||
if GenApi.is_global_name(trans, nm.id) != 0:
|
||
mod_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var(
|
||
trans.SymTab, nm.id)
|
||
if mod_alloca is None:
|
||
# fail-fast: global 变量未注册,无法赋值
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
target,
|
||
f"global 变量 '{nm.id}' 未注册,无法赋值",
|
||
"NameError")
|
||
target_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if mod_alloca.Ty is not None:
|
||
target_ty = mod_alloca.Ty.Pointee
|
||
if target_ty is not None:
|
||
rhs_val = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, target_ty, node)
|
||
llvmlite.build_store(builder, rhs_val, mod_alloca)
|
||
continue
|
||
|
||
# nonlocal 变量:通过闭包 env 写入
|
||
if GenApi.is_nonlocal_name(trans, nm.id) != 0:
|
||
nl_ptr: llvmlite.Value | t.CPtr = self.Gen.StmtGenDecl.get_nonlocal_var_ptr(
|
||
trans, nm.id)
|
||
if nl_ptr is None:
|
||
# fail-fast: nonlocal 变量指针解析失败
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
target,
|
||
f"nonlocal 变量 '{nm.id}' 指针解析失败",
|
||
"NameError")
|
||
# 从 nl_ptr 的类型推断 nonlocal 变量实际类型,
|
||
# 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏)
|
||
nl_target_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if nl_ptr.Ty is not None:
|
||
nl_target_ty = nl_ptr.Ty.Pointee
|
||
if nl_target_ty is None:
|
||
# fail-fast: nl_ptr 类型信息丢失,无法安全 store
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
target,
|
||
f"nonlocal 变量 '{nm.id}' 类型信息丢失,无法写入",
|
||
"TypeError")
|
||
rhs_coerced: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, rhs_val, nl_target_ty, node)
|
||
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
|
||
continue
|
||
|
||
# 拦截:函数内对模块级全局变量赋值但没 global 声明
|
||
# 否则静默创建局部变量遮蔽全局,全局保持 null 导致运行时崩溃
|
||
# (_mbuddy = mb 缺 global 声明即此类 bug:Int32 解引用 null 崩溃)
|
||
if self.Gen.VarGen.is_module_scope(trans.SymTab) == 0:
|
||
mod_gv: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var(
|
||
trans.SymTab, nm.id)
|
||
if mod_gv is not None:
|
||
self.Gen.TypeGenErr.fatal_error(target, f"变量 '{nm.id}' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", "SyntaxError")
|
||
|
||
# 普通局部变量
|
||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.get_or_create_sym(
|
||
trans.SymTab, pool, builder, nm.id, rhs_val.Ty)
|
||
if alloca is not None:
|
||
# 无注解赋值:从 RHS 表达式推断类名设置变量注解
|
||
# (联合类型 X|t.CPtr 简化为 Ptr(i8),属性访问按需过滤需要
|
||
# AnnotClassName 才能定位结构体字段)
|
||
cls_inf: str = self._infer_rhs_annot(pool, mod, asgn.value, trans, rhs_val)
|
||
if cls_inf is not None:
|
||
self.Gen.VarGen.set_var_annot_class_name(
|
||
trans.SymTab, nm.id, cls_inf)
|
||
# 按 alloca 类型对值进行转换(如 double → float)
|
||
store_val: llvmlite.Value | t.CPtr = rhs_val
|
||
if alloca.Ty is not None and alloca.Ty.Pointee is not None:
|
||
store_val = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, rhs_val, alloca.Ty.Pointee, node)
|
||
llvmlite.build_store(builder, store_val, alloca)
|
||
# lambda 表达式赋给变量:注册为闭包变量名,
|
||
# 调用分派(is_closure_name)才走闭包间接调用路径;
|
||
# 否则 i8** alloca 被 _is_func_ptr_alloca 误判为
|
||
# 函数指针,无参 call 直接跳闭包数据崩溃
|
||
if asgn.value is not None \
|
||
and asgn.value.kind() == ast.ASTKind.Lambda:
|
||
self.Gen.CallGenLeafKit.register_closure_name(nm.id)
|
||
existing: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_current(
|
||
trans.SymTab, nm.id)
|
||
if existing is None:
|
||
new_vars += 1
|
||
else:
|
||
# fail-fast: 变量存储创建失败,立即终止
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
target,
|
||
f"变量 '{nm.id}' 存储创建失败",
|
||
"TypeError")
|
||
|
||
return new_vars
|
||
|
||
# ============================================================
|
||
# _infer_rhs_annot - 从 RHS 表达式推断变量注解类名
|
||
#
|
||
# 无注解赋值(如 v = Vec2(...) / v3 = v1 + v2)时,变量 AnnotClassName
|
||
# 缺失会导致后续属性访问(.x)无法"按需过滤":联合类型 X|t.CPtr 在 LLVM
|
||
# 中简化为 Ptr(i8),不携带类名,无法定位结构体字段(字段未找到 → fast-fail)。
|
||
# 此函数按 RHS 结构推断类名:
|
||
# Call → 类实例化(func 为已注册结构体名才采用,避免普通函数误标);
|
||
# func 为 Attribute 时是方法调用(a.cross()),obj 类名 +
|
||
# 方法存在 + rhs_val 为指针类型(联合对象)三条件判定
|
||
# Name → 源变量的 AnnotClassName
|
||
# BinOp/UnaryOp → lhs 类名 + 该类存在对应 dunder 方法(运算符重载返回同类对象)
|
||
# Attribute → 字段注解类名(委托 Generator 单例 _resolve_attr_field_class)
|
||
# 仅当目标为已注册结构体时采用,与"按需过滤,找不到 fast-fail"原则一致。
|
||
# ============================================================
|
||
def _infer_rhs_annot(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
rhs_val: llvmlite.Value | t.CPtr = None) -> str:
|
||
"""从 RHS 表达式推断类名,无法推断返回 None"""
|
||
if node is None or trans is None:
|
||
return None
|
||
k: int = node.kind()
|
||
# Call: 类实例化 / 方法调用
|
||
if k == ast.ASTKind.Call:
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||
if cl is None or cl.func is None:
|
||
return None
|
||
if cl.func.kind() == ast.ASTKind.Name:
|
||
# 类实例化:func 为已注册结构体名才采用
|
||
cand: str = ((ast.Name | t.CPtr)(cl.func)).id
|
||
if cand is None:
|
||
return None
|
||
se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(cand)
|
||
if se is not None:
|
||
return cand
|
||
return None
|
||
if cl.func.kind() == ast.ASTKind.Attribute:
|
||
# 方法调用 a.cross(b):从 vpi 返回注解缓存精确解析返回类名
|
||
# (方法可返回非同类对象,如 Transform.world_position → 'Vec3',
|
||
# 启发式取 obj 类名会 GEP 错字段)。vpi 未命中时返回 None,
|
||
# 由后续属性访问 fast-fail 暴露 vpi 缺失根因(不静默回退)。
|
||
ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if ca is None or ca.attr is None or ca.value is None:
|
||
return None
|
||
obj_cls: str = self._infer_rhs_annot(pool, mod, ca.value, trans)
|
||
if obj_cls is None:
|
||
# 模块级函数调用(requests.get):ca.value 是已导入模块名
|
||
# 而非对象变量(模块名 lookup_var_entry 返回 None → 上面
|
||
# 对象类名推断失败)。从该模块 vpi 的返回注解缓存解析返回
|
||
# 类名(键 {sha1}.{func},cls_name=None 即模块级函数,与
|
||
# CallGenMixin 跨模块返回类型解析一致)。
|
||
# WebTest resp = requests.get(...) 根因:无注解赋值变量
|
||
# AnnotClassName 推断失败(annot=None)→ 属性访问按需过滤
|
||
# (依赖 AnnotClassName)失效 → "属性访问失败: .status_code"。
|
||
if ca.value.kind() == ast.ASTKind.Name:
|
||
mod_nm_rhs: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value)
|
||
if mod_nm_rhs.id is not None:
|
||
mod_sha1_rhs: str = self.Gen.CallGenBase._lookup_module_sha1(
|
||
mod_nm_rhs.id)
|
||
if mod_sha1_rhs is not None:
|
||
temp_dir_rhs: str = None
|
||
if self.Gen.CallGenBase.TempDir is not None:
|
||
temp_dir_rhs = self.Gen.CallGenBase.TempDir
|
||
if temp_dir_rhs is not None:
|
||
VpiReader._ensure_vpi_ret_annot_loaded(
|
||
mod_sha1_rhs, temp_dir_rhs)
|
||
annot_rhs: str = VpiReader._lookup_vpi_ret_annot(
|
||
mod_sha1_rhs, None, ca.attr)
|
||
if annot_rhs is not None:
|
||
ret_cls_rhs: str = self._extract_annot_class_name(
|
||
pool, annot_rhs)
|
||
if ret_cls_rhs is not None:
|
||
return ret_cls_rhs
|
||
return None
|
||
if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0:
|
||
return None
|
||
# 方法定义所在模块 SHA1(优先 struct entry,回退当前模块 sha1)
|
||
cls_sha1: str = self.Gen.StructGen.get_struct_sha1(obj_cls)
|
||
if cls_sha1 is None and trans.ModuleSha1 is not None:
|
||
cls_sha1 = trans.ModuleSha1
|
||
ret_cls: str = None
|
||
if cls_sha1 is not None:
|
||
temp_dir: str = None
|
||
if self.Gen.CallGenBase.TempDir is not None:
|
||
temp_dir = self.Gen.CallGenBase.TempDir
|
||
if temp_dir is not None:
|
||
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir)
|
||
annot_ret: str = VpiReader._lookup_vpi_ret_annot(
|
||
cls_sha1, obj_cls, ca.attr)
|
||
if annot_ret is not None:
|
||
ret_cls = self._extract_annot_class_name(pool, annot_ret)
|
||
return ret_cls
|
||
return None
|
||
# Name: 源变量注解
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
if nm is None or nm.id is None:
|
||
return None
|
||
ve: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||
trans.SymTab, nm.id)
|
||
if ve is None:
|
||
return None
|
||
return ve.AnnotClassName
|
||
# BinOp/UnaryOp: 运算符重载返回同类对象
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||
if bop is None or bop.left is None:
|
||
return None
|
||
dunder: str = self._op_to_dunder(bop.op)
|
||
if dunder is None:
|
||
return None
|
||
lhs_cls: str = self._infer_rhs_annot(pool, mod, bop.left, trans)
|
||
if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0:
|
||
return None
|
||
return lhs_cls
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
|
||
if uop is None or uop.operand is None:
|
||
return None
|
||
dunder: str = self._op_to_dunder(uop.op)
|
||
if dunder is None:
|
||
return None
|
||
opr_cls: str = self._infer_rhs_annot(pool, mod, uop.operand, trans)
|
||
if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0:
|
||
return None
|
||
return opr_cls
|
||
# Attribute: 字段注解类名(属性链递归,如 p = r.origin)
|
||
if k == ast.ASTKind.Attribute:
|
||
return self.Gen.ExprGenAttr._resolve_attr_field_class(pool, trans, node)
|
||
return None
|
||
|
||
# ============================================================
|
||
# _extract_annot_class_name - 从返回注解文本提取结构体类名
|
||
#
|
||
# vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除
|
||
# 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/
|
||
# CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合
|
||
# 多候选时取首个命中段。
|
||
# ============================================================
|
||
def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||
annot: str) -> str:
|
||
"""从返回注解文本提取已注册结构体类名,无命中返回 None"""
|
||
if pool is None or annot is None:
|
||
return None
|
||
alen: t.CSizeT = string.strlen(annot)
|
||
if alen == 0:
|
||
return None
|
||
seg: str = pool.alloc(256)
|
||
if seg is None:
|
||
return None
|
||
start: t.CSizeT = 0
|
||
i: t.CSizeT
|
||
for i in range(alen):
|
||
if annot[i] == '|':
|
||
seglen: t.CSizeT = i - start
|
||
# 段 [start, i):去除首尾空格与引号后查注册表
|
||
s: t.CSizeT = start
|
||
e: t.CSizeT = i
|
||
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
|
||
s += 1
|
||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
|
||
e -= 1
|
||
seglen = e - s
|
||
if seglen > 0 and seglen < 256:
|
||
string.strncpy(seg, annot + s, seglen)
|
||
seg[seglen] = '\0'
|
||
se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(seg)
|
||
if se is not None:
|
||
return seg
|
||
start = i + 1
|
||
# 最后一段(无 '|' 后缀)
|
||
s: t.CSizeT = start
|
||
e: t.CSizeT = alen
|
||
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
|
||
s += 1
|
||
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
|
||
e -= 1
|
||
seglen: t.CSizeT = e - s
|
||
if seglen > 0 and seglen < 256:
|
||
string.strncpy(seg, annot + s, seglen)
|
||
seg[seglen] = '\0'
|
||
se: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(seg)
|
||
if se is not None:
|
||
return seg
|
||
return None
|
||
|
||
# ============================================================
|
||
# _op_to_dunder - 运算符 → dunder 方法名(本地副本,避免跨 Mixin 调用)
|
||
# ============================================================
|
||
def _op_to_dunder(self, op: int) -> str:
|
||
"""BinOp/UnaryOp 运算符 → dunder 方法名,无映射返回 None"""
|
||
if op == ast.OpKind.Add: return "__add__"
|
||
if op == ast.OpKind.Sub: return "__sub__"
|
||
if op == ast.OpKind.Mult: return "__mul__"
|
||
if op == ast.OpKind.Div: return "__truediv__"
|
||
if op == ast.OpKind.FloorDiv: return "__floordiv__"
|
||
if op == ast.OpKind.Mod: return "__mod__"
|
||
if op == ast.OpKind.Pow: return "__pow__"
|
||
if op == ast.OpKind.BitAnd: return "__and__"
|
||
if op == ast.OpKind.BitOr: return "__or__"
|
||
if op == ast.OpKind.BitXor: return "__xor__"
|
||
if op == ast.OpKind.LShift: return "__lshift__"
|
||
if op == ast.OpKind.RShift: return "__rshift__"
|
||
if op == ast.OpKind.USub: return "__neg__"
|
||
if op == ast.OpKind.UAdd: return "__pos__"
|
||
if op == ast.OpKind.Invert: return "__invert__"
|
||
return None
|
||
|
||
# ============================================================
|
||
# _cls_has_dunder - 检查类(含继承链)是否存在 dunder 方法
|
||
#
|
||
# 与 ExprGenMixin.try_operator_overload 的查找一致:当前模块内定义
|
||
# 或跨模块类有 SHA1(stub 中声明)即视为存在。仅在确实存在时
|
||
# 才采用运算符重载推断的类名,避免把原生运算误标为类类型。
|
||
# ============================================================
|
||
def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str, dunder: str) -> int:
|
||
"""类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1"""
|
||
if class_name is None or dunder is None or mod is None:
|
||
return 0
|
||
lookup_name: str = pool.alloc(128)
|
||
if lookup_name is None:
|
||
return 0
|
||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder)
|
||
if self.Gen.CallGenBase.find_func_in_module(mod, lookup_name) is not None:
|
||
return 1
|
||
# 继承链祖先查找
|
||
mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||
mi: int = 1
|
||
while mro_ptr is not None and mro_ptr[mi] != 0:
|
||
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
|
||
if anc is not None:
|
||
anc_lookup: str = pool.alloc(128)
|
||
if anc_lookup is not None:
|
||
viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder)
|
||
if self.Gen.CallGenBase.find_func_in_module(mod, anc_lookup) is not None:
|
||
return 1
|
||
mi += 1
|
||
# 跨模块:类有 SHA1(stub 中声明该方法)视为存在
|
||
if self.Gen.StructGen.get_struct_sha1(class_name) is not None:
|
||
return 1
|
||
return 0
|
||
|
||
def InitAssignGen(self) -> int:
|
||
"""初始化 AssignGen 字段(构造时由 Generator 调用)"""
|
||
if self is None:
|
||
return 1
|
||
self.RecoverFound = 0
|
||
return 0
|