重置上传,新增了多个标准库,开始 TransPyV 自举实验
This commit is contained in:
@@ -1872,69 +1872,180 @@ class ExprCallHandle(BaseHandle):
|
||||
self._check_eh_return(result, FuncName, Gen, called_func=func)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _has_cvtable_decorator(node: ast.ClassDef) -> bool:
|
||||
"""检查 ClassDef 是否有 @t.CVTable 装饰器(或 @CVTable)"""
|
||||
for decorator in node.decorator_list:
|
||||
if isinstance(decorator, ast.Attribute) and getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'CVTable':
|
||||
return True
|
||||
if isinstance(decorator, ast.Call):
|
||||
inner = decorator.func
|
||||
if isinstance(inner, ast.Attribute) and getattr(inner.value, 'id', None) == 't' and inner.attr == 'CVTable':
|
||||
return True
|
||||
if isinstance(inner, ast.Name) and inner.id == 'CVTable':
|
||||
return True
|
||||
if isinstance(decorator, ast.Name) and decorator.id == 'CVTable':
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _has_novtable_decorator(node: ast.ClassDef) -> bool:
|
||||
"""检查 ClassDef 是否有 @t.NoVTable 装饰器"""
|
||||
for decorator in node.decorator_list:
|
||||
if isinstance(decorator, ast.Attribute) and getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'NoVTable':
|
||||
return True
|
||||
if isinstance(decorator, ast.Name) and decorator.id == 'NoVTable':
|
||||
return True
|
||||
return False
|
||||
|
||||
def _try_register_vtable_ondemand(self, ClassName: str, class_sha1: str, Gen: "LlvmGeneratorMixin") -> None:
|
||||
"""按需 vtable 注册:从 .pyi stub 检查 @t.CVTable 并注册到 vtable 集合。
|
||||
|
||||
当 vcall 决策点发现 ClassName 不在 vtable 集合中时调用。
|
||||
读取 temp/{sha1}.pyi 文件,查找 ClassName 的 ClassDef,
|
||||
检查 @t.CVTable 装饰器,注册 vtable 和方法列表。
|
||||
沿继承链递归收集方法,保证 vtable 布局与 prescan 的 _EmitClassLlvm 一致:
|
||||
- 基类方法在前(固定索引,保证多态分派正确)
|
||||
- 子类新增方法在后
|
||||
- 子类覆盖的方法放在父类的位置(用子类实现)
|
||||
|
||||
与 prescan 的 _resolve_class_flags 逻辑一致:
|
||||
- 类自身有 @t.CVTable → 注册
|
||||
- 类自身有 @t.NoVTable → 不注册
|
||||
- 类继承 @t.CVTable 基类(且无 @t.NoVTable)→ 注册(自动启用 CVTable)
|
||||
"""
|
||||
try:
|
||||
import_handler = self.Trans.ImportHandler
|
||||
project_root = import_handler._find_project_root()
|
||||
pyi_path = os.path.join(project_root, 'temp', f'{class_sha1}.pyi')
|
||||
if not os.path.isfile(pyi_path):
|
||||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||||
|
||||
# 缓存已读取的 .pyi 文件(sha1 -> class_map)
|
||||
pyi_cache: dict[str, dict[str, ast.ClassDef]] = {}
|
||||
|
||||
def load_pyi(sha1: str) -> dict[str, ast.ClassDef] | None:
|
||||
if sha1 in pyi_cache:
|
||||
return pyi_cache[sha1]
|
||||
pyi_path = os.path.join(project_root, 'temp', f'{sha1}.pyi')
|
||||
if not os.path.isfile(pyi_path):
|
||||
return None
|
||||
with open(pyi_path, 'r', encoding='utf-8') as f:
|
||||
pyi_code = f.read()
|
||||
tree = ast.parse(pyi_code)
|
||||
cmap: dict[str, ast.ClassDef] = {}
|
||||
for node in ast.iter_child_nodes(tree):
|
||||
if isinstance(node, ast.ClassDef):
|
||||
cmap[node.name] = node
|
||||
pyi_cache[sha1] = cmap
|
||||
return cmap
|
||||
|
||||
def collect_class_methods(class_name: str, sha1: str, visited: set[str]) -> tuple[list[str], bool, bool, str | None]:
|
||||
"""递归收集类的方法列表(基类方法在前,子类方法在后)。
|
||||
|
||||
Returns:
|
||||
(methods, is_cvtable, is_novtable, parent_name)
|
||||
"""
|
||||
if class_name in visited:
|
||||
return ([], False, False, None)
|
||||
visited.add(class_name)
|
||||
|
||||
class_map = load_pyi(sha1)
|
||||
if class_map is None:
|
||||
return ([], False, False, None)
|
||||
|
||||
target_node = class_map.get(class_name)
|
||||
if target_node is None:
|
||||
return ([], False, False, None)
|
||||
|
||||
is_cvtable = self._has_cvtable_decorator(target_node)
|
||||
is_novtable = self._has_novtable_decorator(target_node)
|
||||
|
||||
# 收集自身方法
|
||||
self_methods: list[str] = []
|
||||
for item in target_node.body:
|
||||
if isinstance(item, ast.FunctionDef):
|
||||
method_name = item.name
|
||||
if method_name in ('__new__', '__init__', '__before_init__'):
|
||||
continue
|
||||
if method_name == '__call__':
|
||||
self_methods.append(f"{class_name}.__call__")
|
||||
else:
|
||||
self_methods.append(f"{class_name}.{method_name}")
|
||||
|
||||
# 收集基类方法
|
||||
parent_methods: list[str] = []
|
||||
parent_name: str | None = None
|
||||
for base in target_node.bases:
|
||||
base_name: str | None = None
|
||||
if hasattr(base, 'id'):
|
||||
base_name = base.id
|
||||
elif hasattr(base, 'attr'):
|
||||
base_name = base.attr
|
||||
if not base_name or base_name in ('Object', 'CVTable', 'NoVTable', 'CStruct', 'CUnion', 'CEnum', 'REnum', 'Exception', 'Enum'):
|
||||
continue
|
||||
if parent_name is None:
|
||||
parent_name = base_name
|
||||
|
||||
# 检查同文件内的基类
|
||||
base_node = class_map.get(base_name)
|
||||
if base_node is not None:
|
||||
base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, sha1, visited)
|
||||
if base_novtable:
|
||||
pass # 父类是 NoVTable,不继承 vtable
|
||||
elif base_cvtable:
|
||||
is_cvtable = True
|
||||
parent_methods.extend(base_methods)
|
||||
else:
|
||||
# 跨模块基类 — 查找基类的 sha1
|
||||
base_sha1 = struct_sha1_map.get(base_name)
|
||||
if base_sha1:
|
||||
base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, base_sha1, visited)
|
||||
if base_novtable:
|
||||
pass
|
||||
elif base_cvtable:
|
||||
is_cvtable = True
|
||||
parent_methods.extend(base_methods)
|
||||
else:
|
||||
# 无法找到基类的 sha1
|
||||
if base_name in Gen._cross_module_novtable:
|
||||
pass # 父类是 NoVTable,不继承 vtable
|
||||
|
||||
# 合并方法列表:基类方法在前,子类方法在后
|
||||
# 子类覆盖的方法放在父类的位置
|
||||
child_method_map: dict[str, str] = {}
|
||||
for m in self_methods:
|
||||
mn = m.split('.')[-1] if '.' in m else m
|
||||
child_method_map[mn] = m
|
||||
|
||||
merged: list[str] = []
|
||||
covered_names: set[str] = set()
|
||||
for pm in parent_methods:
|
||||
mn = pm.split('.')[-1] if '.' in pm else pm
|
||||
if mn in child_method_map:
|
||||
merged.append(child_method_map[mn])
|
||||
covered_names.add(mn)
|
||||
else:
|
||||
# 父类独有方法 — 用子类名(虚分派时函数查找会沿继承链回退)
|
||||
merged.append(f"{class_name}.{mn}")
|
||||
|
||||
for m in self_methods:
|
||||
mn = m.split('.')[-1] if '.' in m else m
|
||||
if mn not in covered_names:
|
||||
merged.append(m)
|
||||
|
||||
return (merged, is_cvtable, is_novtable, parent_name)
|
||||
|
||||
methods, is_cvtable, is_novtable, parent_name = collect_class_methods(ClassName, class_sha1, set())
|
||||
|
||||
if is_novtable:
|
||||
return
|
||||
with open(pyi_path, 'r', encoding='utf-8') as f:
|
||||
pyi_code = f.read()
|
||||
pyi_tree = ast.parse(pyi_code)
|
||||
# 查找目标 ClassDef
|
||||
target_node: ast.ClassDef | None = None
|
||||
for node in ast.iter_child_nodes(pyi_tree):
|
||||
if isinstance(node, ast.ClassDef) and node.name == ClassName:
|
||||
target_node = node
|
||||
break
|
||||
if target_node is None:
|
||||
return
|
||||
# 检查 @t.CVTable 装饰器
|
||||
is_cvtable: bool = False
|
||||
for decorator in target_node.decorator_list:
|
||||
if isinstance(decorator, ast.Attribute) and getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'CVTable':
|
||||
is_cvtable = True
|
||||
break
|
||||
if isinstance(decorator, ast.Call):
|
||||
inner = decorator.func
|
||||
if isinstance(inner, ast.Attribute) and getattr(inner.value, 'id', None) == 't' and inner.attr == 'CVTable':
|
||||
is_cvtable = True
|
||||
break
|
||||
if isinstance(inner, ast.Name) and inner.id == 'CVTable':
|
||||
is_cvtable = True
|
||||
break
|
||||
if isinstance(decorator, ast.Name) and decorator.id == 'CVTable':
|
||||
is_cvtable = True
|
||||
break
|
||||
if not is_cvtable:
|
||||
return
|
||||
|
||||
# 注册到 vtable 集合(共享集合)
|
||||
Gen._cross_module_vtable_classes.add(ClassName)
|
||||
Gen.class_vtable.add(ClassName)
|
||||
# 预注册方法列表(与 prescan 逻辑一致)
|
||||
if ClassName not in Gen.class_methods:
|
||||
Gen.class_methods[ClassName] = []
|
||||
for item in target_node.body:
|
||||
if isinstance(item, ast.FunctionDef):
|
||||
method_name = item.name
|
||||
# 构造函数不放入 vtable(避免子类与基类 vtable 大小不一致破坏多态分派)
|
||||
if method_name in ('__new__', '__init__', '__before_init__'):
|
||||
continue
|
||||
if method_name == '__init__':
|
||||
full_name = f"{ClassName}.__init__"
|
||||
elif method_name == '__call__':
|
||||
full_name = f"{ClassName}.__call__"
|
||||
else:
|
||||
full_name = f"{ClassName}.{method_name}"
|
||||
if full_name not in Gen.class_methods[ClassName]:
|
||||
Gen.class_methods[ClassName].append(full_name)
|
||||
# 设置方法列表(与 prescan 逻辑一致:基类方法在前)
|
||||
Gen.class_methods[ClassName] = methods
|
||||
# 设置 class_parent(用于虚分派时的函数查找回退)
|
||||
if parent_name and ClassName not in Gen.class_parent:
|
||||
Gen.class_parent[ClassName] = parent_name
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
Reference in New Issue
Block a user