fix(gen): lambda 捕获 str 指针偏移 + 表达式接收者等五组回归修复
- lambda 捕获 cap_slot 改 cap_names + ci*64:TPV 将 (str)(整数) 编译为 itoa,define_var 键名变数字串,lambda body lookup 穿透父函数作用域产生跨函数误读 - StructGenMixin 递归解 Ptr 到 Struct / CallGenMixin self coerce + 表达式接收者方法调用:修 sub Vec3**、ld.lld undefined dot/cross - TranslatorGenMixin/HandlesAnnAssign 跳过 CTypedef 全局符号:修 duplicate float64_t - ClassGenMixin 枚举/联合/REnum 基类别名经 lookup_from_import_original 解析:修 Color.Green NameError - 重载路径 1 对 Ptr(Ptr(Struct)) 先 load 对象指针:修 MultiInheritTest self 误读 - TypeGenMixin 泛型 T 先 resolve_generic_type_name:修 NoVTableTest T 未注册
This commit is contained in:
1 parent
a0edc3d961
commit
c27a1ba347
8 files changed
+362
-52
No files matched your search
@@ -2746,19 +2746,18 @@ class CallGenMixin:
|
||||
total_count += 1
|
||||
param_node = llvmlite.param_get_next(param_node)
|
||||
|
||||
# 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(跳过 self/cls 参数 0)
|
||||
# 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(含 self)。
|
||||
# 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT),
|
||||
# 但 4096 字面量按 i32 传递,未提升导致运行时 size 高 32 位垃圾,
|
||||
# 破坏伙伴分配器的池大小元数据(如 total=2048)引发 calloc 失败/OOM。
|
||||
# self 在运算符重载路径 2(lhs 为 X|t.CPtr 联合简化的 Vec3** 对象指针)时
|
||||
# 与形参 Vec3* 不匹配,需 bitcast(coerce 指针→指针生成 bitcast),
|
||||
# 否则 call 参数类型与声明不一致 llc 报错。
|
||||
if found_func is not None and head is not None:
|
||||
pc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||||
# 跳过 self 参数(索引 0)
|
||||
if pc_param is not None:
|
||||
pc_param = llvmlite.param_get_next(pc_param)
|
||||
pc_node: llvmlite.Value | t.CPtr = head.Next
|
||||
new_tail: llvmlite.Value | t.CPtr = head
|
||||
if head is not None:
|
||||
head.Next = None
|
||||
pc_node: llvmlite.Value | t.CPtr = head
|
||||
new_head_pc: llvmlite.Value | t.CPtr = head
|
||||
prev_pc: llvmlite.Value | t.CPtr = None
|
||||
while pc_node is not None:
|
||||
pc_next_save: llvmlite.Value | t.CPtr = pc_node.Next
|
||||
coerced_pc: llvmlite.Value | t.CPtr = pc_node
|
||||
@@ -2771,9 +2770,13 @@ class CallGenMixin:
|
||||
coerced_pc = c_pc
|
||||
pc_param = llvmlite.param_get_next(pc_param)
|
||||
coerced_pc.Next = None
|
||||
new_tail.Next = coerced_pc
|
||||
new_tail = coerced_pc
|
||||
if prev_pc is None:
|
||||
new_head_pc = coerced_pc
|
||||
else:
|
||||
prev_pc.Next = coerced_pc
|
||||
prev_pc = coerced_pc
|
||||
pc_node = pc_next_save
|
||||
head = new_head_pc
|
||||
|
||||
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
|
||||
# 复用前面已获取的 cmop_entry(find_struct_by_type 规避跨模块同名找错)
|
||||
@@ -5749,10 +5752,25 @@ class CallGenMixin:
|
||||
builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans)
|
||||
if expr_obj is not None and expr_obj.Ty is not None:
|
||||
expr_cls_nm: str = None
|
||||
match expr_obj.Ty:
|
||||
case llvmlite.LLVMType.Ptr(expr_struct_ty):
|
||||
expr_cls_nm = HandlesStruct.get_class_name_by_type(
|
||||
pool, expr_struct_ty)
|
||||
# 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct))
|
||||
# (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法
|
||||
# 调用被当裸函数 @dot 解析 → 链接 undefined symbol
|
||||
expr_struct_ty: llvmlite.LLVMType | t.CPtr = \
|
||||
HandlesStruct.get_struct_type_from_value(expr_obj)
|
||||
if expr_struct_ty is not None:
|
||||
expr_cls_nm = HandlesStruct.get_class_name_by_type(
|
||||
pool, expr_struct_ty)
|
||||
# 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时,
|
||||
# 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...)
|
||||
# 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解)
|
||||
# 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例
|
||||
if expr_cls_nm is None:
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g3: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
|
||||
t.CVoid(HandlesExpr._g_gen, t.CPtr))
|
||||
if g3 is not None:
|
||||
expr_cls_nm = g3.infer_expr_class(
|
||||
pool, mod, expr_method_at.value, trans)
|
||||
if expr_cls_nm is not None:
|
||||
return self._translate_method_call(
|
||||
pool, builder, mod, expr_cls_nm, func_name,
|
||||
|
||||
@@ -14,6 +14,7 @@ import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.Handles.HandlesVar as HandlesVar
|
||||
import lib.core.Handles.HandlesEnum as HandlesEnum
|
||||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||||
import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.core.StubMerger as StubMerger
|
||||
|
||||
|
||||
@@ -136,7 +137,8 @@ class ClassGenMixin:
|
||||
# 本模块函数调用改 self.,外部模块调用保留模块前缀)
|
||||
# ============================================================
|
||||
|
||||
def _is_cenum_base(self, base_node: ast.AST | t.CPtr) -> int:
|
||||
def _is_cenum_base(self, base_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""检查 base 节点是否为 t.CEnum,返回 1=是 / 0=否"""
|
||||
if base_node is None:
|
||||
return 0
|
||||
@@ -144,8 +146,21 @@ class ClassGenMixin:
|
||||
# Name('CEnum') 形式(from t import CEnum)
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node)
|
||||
if nm.id is not None and string.strcmp(nm.id, "CEnum") == 0:
|
||||
if nm.id is None:
|
||||
return 0
|
||||
if string.strcmp(nm.id, "CEnum") == 0:
|
||||
return 1
|
||||
# 别名形式: from t import CEnum as en; class Color(en)
|
||||
# 解析别名原始名(en → CEnum)再比较
|
||||
if trans is not None and trans._from_imports is not None:
|
||||
alias_orig: str = HandlesImports.lookup_from_import_original(
|
||||
trans._from_imports, nm.id)
|
||||
if alias_orig is not None:
|
||||
og_len_ce: t.CSizeT = 0
|
||||
while alias_orig[og_len_ce] != ' ' and alias_orig[og_len_ce] != '\0':
|
||||
og_len_ce += 1
|
||||
if og_len_ce == 5 and string.strncmp(alias_orig, "CEnum", 5) == 0:
|
||||
return 1
|
||||
return 0
|
||||
# Attribute(t.CEnum) 形式
|
||||
if k == ast.ASTKind.Attribute:
|
||||
@@ -155,7 +170,8 @@ class ClassGenMixin:
|
||||
return 0
|
||||
return 0
|
||||
|
||||
def _is_enum_class(self, cd: ast.ClassDef | t.CPtr) -> int:
|
||||
def _is_enum_class(self, cd: ast.ClassDef | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""检查 ClassDef 是否为 CEnum:继承自 t.CEnum 或 @t.CEnum 装饰器形式"""
|
||||
if cd is None:
|
||||
return 0
|
||||
@@ -173,11 +189,12 @@ class ClassGenMixin:
|
||||
base_node: ast.AST | t.CPtr = bases.get(bi)
|
||||
if base_node is None:
|
||||
continue
|
||||
if self._is_cenum_base(base_node) == 1:
|
||||
if self._is_cenum_base(base_node, trans) == 1:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _is_cunion_base(self, base_node: ast.AST | t.CPtr) -> int:
|
||||
def _is_cunion_base(self, base_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""检查 base 节点是否为 t.CUnion,返回 1=是 / 0=否"""
|
||||
if base_node is None:
|
||||
return 0
|
||||
@@ -185,8 +202,20 @@ class ClassGenMixin:
|
||||
# Name('CUnion') 形式(from t import CUnion)
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node)
|
||||
if nm.id is not None and string.strcmp(nm.id, "CUnion") == 0:
|
||||
if nm.id is None:
|
||||
return 0
|
||||
if string.strcmp(nm.id, "CUnion") == 0:
|
||||
return 1
|
||||
# 别名形式: from t import CUnion as un; class Data(un)
|
||||
if trans is not None and trans._from_imports is not None:
|
||||
alias_orig: str = HandlesImports.lookup_from_import_original(
|
||||
trans._from_imports, nm.id)
|
||||
if alias_orig is not None:
|
||||
og_len_cu: t.CSizeT = 0
|
||||
while alias_orig[og_len_cu] != ' ' and alias_orig[og_len_cu] != '\0':
|
||||
og_len_cu += 1
|
||||
if og_len_cu == 6 and string.strncmp(alias_orig, "CUnion", 6) == 0:
|
||||
return 1
|
||||
return 0
|
||||
# Attribute(t.CUnion) 形式
|
||||
if k == ast.ASTKind.Attribute:
|
||||
@@ -196,7 +225,8 @@ class ClassGenMixin:
|
||||
return 0
|
||||
return 0
|
||||
|
||||
def _is_union_class(self, cd: ast.ClassDef | t.CPtr) -> int:
|
||||
def _is_union_class(self, cd: ast.ClassDef | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""检查 ClassDef 是否为 CUnion:继承自 t.CUnion 或 @t.CUnion 装饰器形式"""
|
||||
if cd is None:
|
||||
return 0
|
||||
@@ -214,11 +244,12 @@ class ClassGenMixin:
|
||||
base_node: ast.AST | t.CPtr = bases.get(bi)
|
||||
if base_node is None:
|
||||
continue
|
||||
if self._is_cunion_base(base_node) == 1:
|
||||
if self._is_cunion_base(base_node, trans) == 1:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _is_crenum_base(self, base_node: ast.AST | t.CPtr) -> int:
|
||||
def _is_crenum_base(self, base_node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""检查 base 节点是否为 t.REnum,返回 1=是 / 0=否"""
|
||||
if base_node is None:
|
||||
return 0
|
||||
@@ -226,8 +257,20 @@ class ClassGenMixin:
|
||||
# Name('REnum') 形式(from t import REnum)
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(base_node)
|
||||
if nm.id is not None and string.strcmp(nm.id, "REnum") == 0:
|
||||
if nm.id is None:
|
||||
return 0
|
||||
if string.strcmp(nm.id, "REnum") == 0:
|
||||
return 1
|
||||
# 别名形式: from t import REnum as ren; class Opt(ren)
|
||||
if trans is not None and trans._from_imports is not None:
|
||||
alias_orig: str = HandlesImports.lookup_from_import_original(
|
||||
trans._from_imports, nm.id)
|
||||
if alias_orig is not None:
|
||||
og_len_cr: t.CSizeT = 0
|
||||
while alias_orig[og_len_cr] != ' ' and alias_orig[og_len_cr] != '\0':
|
||||
og_len_cr += 1
|
||||
if og_len_cr == 5 and string.strncmp(alias_orig, "REnum", 5) == 0:
|
||||
return 1
|
||||
return 0
|
||||
# Attribute(t.REnum) 形式
|
||||
if k == ast.ASTKind.Attribute:
|
||||
@@ -237,7 +280,8 @@ class ClassGenMixin:
|
||||
return 0
|
||||
return 0
|
||||
|
||||
def _is_renum_class(self, cd: ast.ClassDef | t.CPtr) -> int:
|
||||
def _is_renum_class(self, cd: ast.ClassDef | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> int:
|
||||
"""检查 ClassDef 是否为 REnum:继承自 t.REnum 或 @t.REnum 装饰器形式"""
|
||||
if cd is None:
|
||||
return 0
|
||||
@@ -255,7 +299,7 @@ class ClassGenMixin:
|
||||
base_node: ast.AST | t.CPtr = bases.get(bi)
|
||||
if base_node is None:
|
||||
continue
|
||||
if self._is_crenum_base(base_node) == 1:
|
||||
if self._is_crenum_base(base_node, trans) == 1:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -2392,15 +2436,15 @@ class ClassGenMixin:
|
||||
HandlesStruct.add_visible_struct(pool, class_name)
|
||||
|
||||
# 枚举类:交给 HandlesEnum 处理
|
||||
if self._is_enum_class(cd) == 1:
|
||||
if self._is_enum_class(cd, trans) == 1:
|
||||
return self._translate_enum_def(trans, cd)
|
||||
|
||||
# 联合体类:交给联合体处理
|
||||
if self._is_union_class(cd) == 1:
|
||||
if self._is_union_class(cd, trans) == 1:
|
||||
return self._translate_union_def(trans, cd)
|
||||
|
||||
# REnum 类:交给 REnum 处理({i32 tag, max_payload} 布局)
|
||||
if self._is_renum_class(cd) == 1:
|
||||
if self._is_renum_class(cd, trans) == 1:
|
||||
return self._translate_renum_def(trans, cd)
|
||||
|
||||
# 泛型类:存储为模板,不发射 IR(等实例化时特化)
|
||||
|
||||
@@ -1776,8 +1776,17 @@ class ExprGenMixin:
|
||||
trans.SymTab, nm.id)
|
||||
if lhs_alloca is not None:
|
||||
if cmp_zero == 0 or self.get_ptr_level(lhs_alloca.Ty) == 0:
|
||||
ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca
|
||||
# Ptr(Ptr(Struct)) 对象存储槽:load 出对象指针作 self
|
||||
# (与 translate_binop 路径 1 一致,避免槽地址当对象地址)
|
||||
if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \
|
||||
and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0:
|
||||
load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, lhs_alloca.Ty.Pointee, lhs_alloca)
|
||||
if load_self1 is not None:
|
||||
ovl_self1 = load_self1
|
||||
ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload(
|
||||
pool, builder, mod, lhs_alloca, rhs, op, trans, 1)
|
||||
pool, builder, mod, ovl_self1, rhs, op, trans, 1)
|
||||
if ovl_result is not None:
|
||||
return ovl_result
|
||||
|
||||
@@ -4947,6 +4956,196 @@ class ExprGenMixin:
|
||||
# P3 迁移方法(来自 HandlesExprOps.vp:运算符重载 + 二元运算)
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# infer_expr_class - 从表达式推断结构体类名(共享推断)
|
||||
#
|
||||
# 无注解赋值(HandlesAssign)与方法调用分派(CallGenMixin)共用:
|
||||
# 联合类型 X|t.CPtr 简化为 Ptr(i8),不含类名,需按表达式结构推断:
|
||||
# Call → 类实例化(func 为已注册结构体名);func 为 Attribute
|
||||
# 时是方法调用,经 vpi 返回注解缓存解析返回类名
|
||||
# Name → 源变量的 AnnotClassName
|
||||
# BinOp/UnaryOp → lhs 类名 + 存在对应 dunder 方法(返回同类对象)
|
||||
# Attribute → 字段注解类名(_resolve_attr_field_class)
|
||||
# 仅采用已注册结构体;无法精确推断返回 None(fail-fast 由调用方暴露)。
|
||||
# ============================================================
|
||||
def infer_expr_class(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
node: ast.AST | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr) -> str:
|
||||
"""从表达式推断结构体类名,无法推断返回 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:
|
||||
cand: str = ((ast.Name | t.CPtr)(cl.func)).id
|
||||
if cand is None:
|
||||
return None
|
||||
if HandlesStruct.find_struct(cand) is not None:
|
||||
return cand
|
||||
return None
|
||||
if cl.func.kind() == ast.ASTKind.Attribute:
|
||||
# 方法调用 a.cross(b):vpi 返回注解缓存精确解析返回类名
|
||||
# (方法可返回非同类对象,如 Transform.world_position → 'Vec3')。
|
||||
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_expr_class(pool, mod, ca.value, trans)
|
||||
if obj_cls is None:
|
||||
return None
|
||||
if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0:
|
||||
return None
|
||||
cls_sha1: str = HandlesStruct.get_struct_sha1(obj_cls)
|
||||
if cls_sha1 is None and trans.ModuleSha1 is not None:
|
||||
cls_sha1 = trans.ModuleSha1
|
||||
ret_cls: str = None
|
||||
if cls_sha1 is not None:
|
||||
import lib.StubGen.VpiReader as VpiReader
|
||||
temp_dir: str = None
|
||||
# 跨 Mixin 不能 self 访问 Generator 的 TempDir 字段(字段按
|
||||
# 声明类隔离),经全局单例获取(同 HandlesAssign 模式)
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g2: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
|
||||
t.CVoid(HandlesExpr._g_gen, t.CPtr))
|
||||
if g2 is not None and g2.TempDir is not None:
|
||||
temp_dir = g2.TempDir
|
||||
if temp_dir is not None:
|
||||
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir)
|
||||
annot_ret: str = VpiReader._lookup_vpi_ret_annot(
|
||||
cls_sha1, obj_cls, ca.attr)
|
||||
if annot_ret is not None:
|
||||
ret_cls = self._extract_annot_class_name(pool, annot_ret)
|
||||
return ret_cls
|
||||
return None
|
||||
# Name: 源变量注解
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm is None or nm.id is None:
|
||||
return None
|
||||
ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||||
trans.SymTab, nm.id)
|
||||
if ve is None:
|
||||
return None
|
||||
return ve.AnnotClassName
|
||||
# BinOp/UnaryOp: 运算符重载返回同类对象
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
|
||||
if bop is None or bop.left is None:
|
||||
return None
|
||||
dunder: str = self._binop_to_dunder(bop.op)
|
||||
if dunder is None:
|
||||
return None
|
||||
lhs_cls: str = self.infer_expr_class(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._unaryop_to_dunder(uop.op)
|
||||
if dunder is None:
|
||||
return None
|
||||
opr_cls: str = self.infer_expr_class(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._resolve_attr_field_class(pool, trans, node)
|
||||
return None
|
||||
|
||||
# ============================================================
|
||||
# _cls_has_dunder - 检查类(含继承链)是否存在 dunder/方法
|
||||
#
|
||||
# 与 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 HandlesExprCall.find_func_in_module(mod, lookup_name) is not None:
|
||||
return 1
|
||||
# 继承链祖先查找
|
||||
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
|
||||
mi: int = 1
|
||||
while mro_ptr is not None and mro_ptr[mi] != 0:
|
||||
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
|
||||
if anc is not None:
|
||||
anc_lookup: str = pool.alloc(128)
|
||||
if anc_lookup is not None:
|
||||
viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder)
|
||||
if HandlesExprCall.find_func_in_module(mod, anc_lookup) is not None:
|
||||
return 1
|
||||
mi += 1
|
||||
# 跨模块:类有 SHA1(stub 中声明该方法)视为存在
|
||||
if HandlesStruct.get_struct_sha1(class_name) is not None:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
# ============================================================
|
||||
# _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] == '|':
|
||||
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: t.CSizeT = e - s
|
||||
if seglen > 0 and seglen < 256:
|
||||
string.strncpy(seg, annot + s, seglen)
|
||||
seg[seglen] = '\0'
|
||||
if HandlesStruct.find_struct(seg) 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'
|
||||
if HandlesStruct.find_struct(seg) is not None:
|
||||
return seg
|
||||
return None
|
||||
|
||||
# ============================================================
|
||||
# BinOp 运算符 → dunder 方法名
|
||||
# ============================================================
|
||||
@@ -5221,8 +5420,20 @@ class ExprGenMixin:
|
||||
lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
trans.SymTab, nm.id)
|
||||
if lhs_alloca is not None:
|
||||
ovl_self1: llvmlite.Value | t.CPtr = lhs_alloca
|
||||
# alloca 是 Ptr(Ptr(Struct))(X|t.CPtr 对象存储槽)时,
|
||||
# load 出对象指针作为 self——若把槽地址当 self,dunder 内
|
||||
# load 槽内容(对象指针值)当字段读 → 垃圾(MultiInheritTest
|
||||
# Vec2Both __add__ 输出 (1.0,2.0) 根因;get_struct_type_from_value
|
||||
# 递归解指针后路径 1 能识别 alloca,需同步修正 self 语义)
|
||||
if lhs_alloca.Ty is not None and lhs_alloca.Ty.Pointee is not None \
|
||||
and HandlesExpr.is_ptr_type(lhs_alloca.Ty.Pointee) != 0:
|
||||
load_self1: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||||
builder, lhs_alloca.Ty.Pointee, lhs_alloca)
|
||||
if load_self1 is not None:
|
||||
ovl_self1 = load_self1
|
||||
ovl_result: llvmlite.Value | t.CPtr = self.try_operator_overload(
|
||||
pool, builder, mod, lhs_alloca, rhs, op, trans, 0)
|
||||
pool, builder, mod, ovl_self1, rhs, op, trans, 0)
|
||||
if ovl_result is not None:
|
||||
return ovl_result
|
||||
|
||||
|
||||
@@ -1709,8 +1709,10 @@ class FuncGenMixin:
|
||||
|
||||
# 9. 捕获变量:从 env 堆槽加载值到局部 alloca
|
||||
for ci in range(cap_count):
|
||||
cap_addr: t.CUInt64T = t.CUInt64T(cap_names) + ci * 64
|
||||
cap_slot: str = (str)(cap_addr)
|
||||
# 直接 str 指针偏移取捕获名(与 param_names + pi*32 一致)。
|
||||
# 注意:不能用 (str)(cap_addr) 整数转换——TPV 将其编译为 itoa(整数转字符串),
|
||||
# 会把 cap_slot 变成数字串,define_var 键名错乱,lambda body lookup 无法命中。
|
||||
cap_slot: str = cap_names + ci * 64
|
||||
if cap_slot[0] == '\0':
|
||||
continue
|
||||
ty_addr3: t.CUInt64T = t.CUInt64T(cap_tys) + ci * 8
|
||||
@@ -1798,8 +1800,8 @@ class FuncGenMixin:
|
||||
builder, "malloc", env_size_val, 1, i8_ptr_ty, 0)
|
||||
if env_ptr is not None:
|
||||
for ci3 in range(cap_count):
|
||||
cap_addr3: t.CUInt64T = t.CUInt64T(cap_names) + ci3 * 64
|
||||
cap_slot3: str = (str)(cap_addr3)
|
||||
# 与步骤 9 一致:str 指针偏移判空,避免整数转换 itoa 语义
|
||||
cap_slot3: str = cap_names + ci3 * 64
|
||||
if cap_slot3[0] == '\0':
|
||||
continue
|
||||
al_addr: t.CUInt64T = t.CUInt64T(cap_allocas) + ci3 * 8
|
||||
|
||||
@@ -660,19 +660,25 @@ class StructGenMixin:
|
||||
return 0
|
||||
|
||||
def get_struct_type_from_value(self, val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""从 Value 的类型推断结构体类型"""
|
||||
"""从 Value 的类型推断结构体类型
|
||||
|
||||
递归解 Ptr:支持 X|t.CPtr 联合简化产生的 Ptr(Ptr(Struct)) 对象指针
|
||||
(如运算符重载中间结果 a*2.0 的 Vec3**),否则 try_operator_overload
|
||||
重载识别失败回退原生运算,对指针生成非法 sub 指令(llc: invalid
|
||||
operand type for instruction)。
|
||||
"""
|
||||
if val is None or val.Ty is None:
|
||||
return None
|
||||
# 嵌套 match:先匹配 Ptr,再在 case 块内匹配 pointee 是否为 Struct
|
||||
match val.Ty:
|
||||
case llvmlite.LLVMType.Ptr(pointee):
|
||||
match pointee:
|
||||
case llvmlite.LLVMType.Struct(fields, fcount, name):
|
||||
return pointee
|
||||
case _:
|
||||
return None
|
||||
case _:
|
||||
return None
|
||||
ty: llvmlite.LLVMType | t.CPtr = val.Ty
|
||||
while ty is not None:
|
||||
match ty:
|
||||
case llvmlite.LLVMType.Ptr(pointee):
|
||||
ty = pointee
|
||||
case llvmlite.LLVMType.Struct(fields, fcount, name):
|
||||
return ty
|
||||
case _:
|
||||
return None
|
||||
return None
|
||||
|
||||
def mark_as_union(self, name: str) -> int:
|
||||
"""标记已注册的结构体为联合体,返回 1=成功 / 0=失败"""
|
||||
|
||||
@@ -346,6 +346,13 @@ class TranslatorGenMixin:
|
||||
HandlesAnnAssign._register_cdefine_from_value(
|
||||
pool, nm_cd.id, aa_cd.value)
|
||||
return 0
|
||||
# CTypedef 注解(如 stdint.vp float64_t: t.CTypedef = t.CFloat64T):
|
||||
# 类型别名已由 ScanCTypedefDeclarations 注册到 CTypedef 表,
|
||||
# 不创建全局变量——否则每个包含 stdint 的模块生成
|
||||
# @float64_t 全局 → 链接 duplicate symbol warning
|
||||
# (跨 Mixin 经 HandlesAnnAssign 模块委托调用)
|
||||
if HandlesAnnAssign.is_ctypedef_annotation(aa_cd.annotation) != 0:
|
||||
return 0
|
||||
|
||||
# _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量
|
||||
# CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过
|
||||
|
||||
@@ -1505,18 +1505,25 @@ class TypeGenMixin:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||||
if nm.id is None:
|
||||
return None
|
||||
# 泛型特化上下文:T → 具体类型(特化方法体内局部变量注解
|
||||
# 如 `cur: T | t.CPtr` 未被 _clone_classdef_for_spec 克隆替换,
|
||||
# 依赖此处在翻译时经上下文解析;否则 cur.annot="T",
|
||||
# 属性访问 cur.Next → lookup_field_by_class("T") 未注册报错)
|
||||
resolved_id: str = self.resolve_generic_type_name(nm.id)
|
||||
if resolved_id is None:
|
||||
return None
|
||||
# 跳过内置类型名
|
||||
if string.strcmp(nm.id, "str") == 0:
|
||||
if string.strcmp(resolved_id, "str") == 0:
|
||||
return None
|
||||
if string.strcmp(nm.id, "bytes") == 0:
|
||||
if string.strcmp(resolved_id, "bytes") == 0:
|
||||
return None
|
||||
if string.strcmp(nm.id, "bool") == 0:
|
||||
if string.strcmp(resolved_id, "bool") == 0:
|
||||
return None
|
||||
if string.strcmp(nm.id, "float") == 0:
|
||||
if string.strcmp(resolved_id, "float") == 0:
|
||||
return None
|
||||
if string.strcmp(nm.id, "double") == 0:
|
||||
if string.strcmp(resolved_id, "double") == 0:
|
||||
return None
|
||||
return nm.id
|
||||
return resolved_id
|
||||
|
||||
# Attribute 节点: memhub.MemBuddy → "memhub.MemBuddy"(模块限定名)
|
||||
if k == ast.ASTKind.Attribute:
|
||||
|
||||
@@ -59,6 +59,15 @@ def is_cdefine_annotation(annot: ast.AST | t.CPtr) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def is_ctypedef_annotation(annot: ast.AST | t.CPtr) -> int:
|
||||
"""检测注解是否为 t.CTypedef,返回 1 表示是,0 表示否(委托到 gen._is_ctypedef_annotation)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g._is_ctypedef_annotation(annot)
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数)
|
||||
#
|
||||
@@ -310,6 +319,12 @@ class AnnAssignHandle(HandlesBase.Mixin):
|
||||
_register_cdefine_from_value(pool_ps, nm.id, aa.value)
|
||||
return 0
|
||||
|
||||
# CTypedef 注解: 类型别名(ScanCTypedefDeclarations 已注册到 CTypedef 表),
|
||||
# 不创建全局/局部存储——否则 stdint.vp 的 float64_t: t.CTypedef = t.CFloat64T
|
||||
# 等生成 @float64_t 符号,链接 duplicate symbol warning
|
||||
if is_ctypedef_annotation(aa.annotation) != 0:
|
||||
return 0
|
||||
|
||||
# global/nonlocal 变量不需要局部 alloca
|
||||
if HT.is_global_name(self.Trans, nm.id) != 0:
|
||||
return 0
|
||||
|
||||
Reference in new issue
Block a user