重置上传,新增了多个标准库,开始 TransPyV 自举实验

This commit is contained in:
2026-07-19 11:38:15 +08:00
parent 796222a300
commit 4e66207ba1
1041 changed files with 6597 additions and 27814 deletions

View File

@@ -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