refactor(tpc): 退役 t/c 模块并将定宽类型升级为内建

删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
This commit is contained in:
TermiNexus committed 2026-10-18 13:00:58 +08:00
1 parent 8d27747c7c
commit f19d25782f
66 files changed
+2445 -3638

No files matched your search

+102 -129
View File
@@ -7,8 +7,8 @@ from typing import List
import llvmlite.ir as ir
from lib.includes import t
from lib.includes.t import CTypeRegistry
from lib.core import TypeSystem
from lib.core.TypeSystem import CTypeRegistry
from lib.core.SymbolUtils import (
IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode, IsCPtrNode,
IsRawPtrSubscriptNode, IsPtrSubscriptNode, ResolveGenericTypeArgStr,
@@ -53,13 +53,13 @@ class DeclarationGenerator:
# HandlesClassDef._generic_class_templates 同源(ClassDef 的 type_params
# 标记),generate() 里从本模块 pyi 与 class_def_map 收集
self._generic_class_names: set[str] = set()
# t/c 导入名表(from t import CInt as myint → 'myint' → ('t','CInt')),
# 与定义端 Trans._t_c_imported_names 同口径,供泛型实参串解析使用
self._t_c_imported_names: dict[str, tuple[str, str]] = {}
# 内建类型导入名表(CInt as myint → 'myint' → CInt),
# 与定义端 Trans._from_import_aliases 同口径,供泛型实参串解析使用
self._from_import_aliases: dict[str, tuple[str, str]] = {}
# 跨模块类定义映射:{class_name: ClassDef_node},供 _get_inherited_members
# 查找其他模块定义的父类(如 exprs.py 的 Name(AST) 查找 base.py 的 AST)
self._cross_module_class_defs: dict[str, ast.ClassDef] = class_def_map or {}
t.configure_platform(self.target_triple)
TypeSystem.configure_platform(self.target_triple)
def generate(self, pyi_content: str, src_path: str) -> str:
# 传 src_path:解析失败时报错/回退诊断才带得上来源(否则 vast 记为 <unknown>,
@@ -83,20 +83,9 @@ class DeclarationGenerator:
if global_typedef_map:
self.typedef_map.update(global_typedef_map)
# 构建 t/c 类型别名映射(from t import CInt as myint)
# 类型标记按裸名直接识别、不依赖导入:别名映射表保持为空。
self._t_alias_map: dict[str, type] = {}
self._t_c_imported_names: dict[str, tuple[str, str]] = {}
for node in ast.iter_child_nodes(tree):
if isinstance(node, ast.ImportFrom):
if node.module in ('t', 'c'):
for alias in node.names:
name: str = alias.name
asname: str = alias.asname or name
self._t_c_imported_names[asname] = (node.module, name)
if node.module == 't':
t_cls: type | None = getattr(t, name, None)
if isinstance(t_cls, type) and issubclass(t_cls, t.CType):
self._t_alias_map[asname] = t_cls
self._from_import_aliases: dict[str, tuple[str, str]] = {}
for node in ast.iter_child_nodes(tree):
if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
@@ -112,6 +101,8 @@ class DeclarationGenerator:
is_typedef = True
elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef':
is_typedef = True
elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Name) and node.annotation.left.id == 'CTypedef':
is_typedef = True
if is_typedef:
if node.value:
self.typedef_map[var_name] = node.value
@@ -191,14 +182,18 @@ class DeclarationGenerator:
MultiRetTypes: list[ast.AST] = []
if node.decorator_list:
for decorator in node.decorator_list:
# fail-fast:`@c.CReturn` 装饰器已移除,任何地方出现都必须报错,
# 不得静默忽略或改写;多返回值请改用 `-> tuple[ty1, ty2, ...]`。
if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute):
if decorator.func.attr == 'CReturn':
raise SyntaxError(
f"函数 '{node.name}':`@c.CReturn` 已移除:请改用返回注解 "
f"`-> tuple[ty1, ty2, ...]`(多返回值打包为 struct)"
)
# fail-fast:`CReturn` 不是内建标记;多返回值请改用 `-> tuple[ty1, ty2, ...]`。
_DecName: str = ''
if isinstance(decorator, ast.Call):
if isinstance(decorator.func, ast.Name):
_DecName = decorator.func.id
elif isinstance(decorator.func, ast.Attribute):
_DecName = decorator.func.attr
if _DecName == 'CReturn':
raise SyntaxError(
f"函数 '{node.name}':`CReturn` 不是内建标记;请改用返回注解 "
f"`-> tuple[ty1, ty2, ...]`(多返回值打包为 struct)"
)
if node.returns:
if isinstance(node.returns, ast.Subscript) and isinstance(node.returns.value, ast.Name) and node.returns.value.id == 'tuple':
slice_node: ast.AST = node.returns.slice
@@ -245,7 +240,7 @@ class DeclarationGenerator:
return self._check_annotation_for_export(node.returns)
def _check_annotation_for_export(self, annotation: ast.AST | None) -> bool:
"""递归检查类型注解中是否包含 CExport 或 t.State"""
"""递归检查类型注解中是否包含 CExport 或 State"""
return bool(annotation) and (AnnotationContainsName(annotation, 'CExport') or AnnotationContainsName(annotation, 'State'))
def _generate_global_decl(self, node: ast.AnnAssign) -> str | None:
@@ -254,8 +249,8 @@ class DeclarationGenerator:
return None
var_name: str = node.target.id
# CDefine 是编译期常量,不是变量:stub 里**不得**生成 external global。
# `define X: T = V` 会展开为注解 `T | t.CDefine`,故判据必须能识别**联合形态**——
# 原判据只认裸 `t.CDefine`(注解为单个 Attribute),联合注解会漏判 →
# `define X: T = V` 会展开为注解 `T | CDefine`,故判据必须能识别**联合形态**——
# 原判据只认裸 `CDefine`(注解为单个 Attribute),联合注解会漏判 →
# stub 出现 `@X = external global i32` → 其他模块引用它时变成未定义符号(链接失败),
# 且会遮住跨模块 CDefine 常量回退(同名全局优先于常量)。与 _check_annotation_for_export
# 一样用递归判据。
@@ -267,11 +262,13 @@ class DeclarationGenerator:
return None
if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef':
return None
if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Name) and node.annotation.left.id == 'CTypedef':
return None
if isinstance(node.annotation, ast.List):
for elt in node.annotation.elts:
if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'):
return None
if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Attribute) and isinstance(elt.value.value, ast.Name) and elt.value.value.id == 't' and elt.value.attr == 'Callable':
if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Name) and elt.value.id == 'Callable':
return None
VarType: str = self._get_type_str(node.annotation)
if VarType.startswith('[0 x ') and node.value:
@@ -305,28 +302,28 @@ class DeclarationGenerator:
Returns:
'enum' | 'union' | 'renum' | 'struct' | 'ctype_marker' | None
"""
# 1) 查 t 别名映射(from t import CEnum as en)
# 1) 查内建类型别名映射
if base_name in self._t_alias_map:
t_cls: type = self._t_alias_map[base_name]
if issubclass(t_cls, (t.CEnum, t.REnum)):
return 'renum' if issubclass(t_cls, t.REnum) else 'enum'
if issubclass(t_cls, t.CUnion):
if issubclass(t_cls, (TypeSystem.CEnum, TypeSystem.REnum)):
return 'renum' if issubclass(t_cls, TypeSystem.REnum) else 'enum'
if issubclass(t_cls, TypeSystem.CUnion):
return 'union'
if issubclass(t_cls, t.CStruct):
if issubclass(t_cls, TypeSystem.CStruct):
return 'struct'
# CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记,
# 不应被编译为真实结构体,也不应被生成 stub 声明。
if issubclass(t_cls, t.CType):
if issubclass(t_cls, TypeSystem.CType):
return 'ctype_marker'
# 2) 直接查 t 模块属性
t_cls: type | None = getattr(t, base_name, None)
if isinstance(t_cls, type) and issubclass(t_cls, t.CType):
if issubclass(t_cls, (t.CEnum, t.REnum)):
return 'renum' if issubclass(t_cls, t.REnum) else 'enum'
if issubclass(t_cls, t.CUnion):
# 2) 直接查内建类型类
t_cls: type | None = getattr(TypeSystem, base_name, None)
if isinstance(t_cls, type) and issubclass(t_cls, TypeSystem.CType):
if issubclass(t_cls, (TypeSystem.CEnum, TypeSystem.REnum)):
return 'renum' if issubclass(t_cls, TypeSystem.REnum) else 'enum'
if issubclass(t_cls, TypeSystem.CUnion):
return 'union'
if issubclass(t_cls, t.CStruct):
if issubclass(t_cls, TypeSystem.CStruct):
return 'struct'
# CType 及其子类是"类型强转"标记,不编译为结构体。
return 'ctype_marker'
@@ -453,15 +450,7 @@ class DeclarationGenerator:
is_novtable: bool = False
if hasattr(node, 'decorator_list') and node.decorator_list:
for decorator in node.decorator_list:
if isinstance(decorator, ast.Attribute):
if getattr(decorator.value, 'id', None) == 't':
if decorator.attr == 'CVTable':
is_cvtable = True
elif decorator.attr == 'Object':
is_cpython_object = True
elif decorator.attr == 'NoVTable':
is_novtable = True
elif isinstance(decorator, ast.Name):
if isinstance(decorator, ast.Name):
if decorator.id == 'CVTable':
is_cvtable = True
elif decorator.id == 'Object':
@@ -485,7 +474,7 @@ class DeclarationGenerator:
base_name = base.value.id
if base_name and not self._is_marker_base(base_name):
has_parent_class = True
# 检查父类是否为 @t.NoVTable(非多态继承)
# 检查父类是否为 @NoVTable(非多态继承)
_p_node: ast.ClassDef | None = None
for n in ast.iter_child_nodes(self._pyi_tree):
if isinstance(n, ast.ClassDef) and n.name == base_name:
@@ -495,16 +484,14 @@ class DeclarationGenerator:
_p_node = self._cross_module_class_defs.get(base_name)
if _p_node is not None and hasattr(_p_node, 'decorator_list') and _p_node.decorator_list:
for dec in _p_node.decorator_list:
if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'NoVTable':
parent_is_novtable = True
elif isinstance(dec, ast.Name) and dec.id == 'NoVTable':
if isinstance(dec, ast.Name) and dec.id == 'NoVTable':
parent_is_novtable = True
break
# 仅当非 NoVTable 且父类非 NoVTable 时才因继承启用 CVTable
# (@t.NoVTable 标记的类及其子类不使用 vtable,字段展平嵌入)
# (@NoVTable 标记的类及其子类不使用 vtable,字段展平嵌入)
if has_parent_class and not is_cvtable and not is_novtable and not parent_is_novtable:
is_cvtable = True
# 方法级 virtual(`virtual def m(...)` ⇒ 方法装饰器 @t.CVTable)触发类级 vtable:
# 方法级 virtual(`virtual def m(...)` ⇒ 方法装饰器 @CVTable)触发类级 vtable:
# 与 HandlesClassDef._resolve_class_flags / VPC _detect_vtable_status 的
# `_has_any_func_cvtable` 分支逐条对齐(类级 NoVTable / 无真实父类)。
# 必须在此同步:定义模块按 IsCVTable 在 struct 首部放 vptr,若 stub 不同步,
@@ -535,9 +522,7 @@ class DeclarationGenerator:
_base_node = self._cross_module_class_defs.get(base_name)
if _base_node is not None and hasattr(_base_node, 'decorator_list') and _base_node.decorator_list:
for dec in _base_node.decorator_list:
if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable':
base_has_vtable = True
elif isinstance(dec, ast.Name) and dec.id == 'CVTable':
if isinstance(dec, ast.Name) and dec.id == 'CVTable':
base_has_vtable = True
if base_has_vtable:
break
@@ -836,14 +821,14 @@ class DeclarationGenerator:
init_len = len(item.value.value) + 1
VarType = f'[{init_len} x {elem_type}]'
else:
# 固定大小数组: t.CArray[elem_type, count] → [count x elem_type]
# 固定大小数组: CArray[elem_type, count] → [count x elem_type]
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2:
elem_type = self._get_type_str(slice_node.elts[0], embedded=True)
count_val: int = self._get_const_int(slice_node.elts[1])
if count_val > 0:
VarType = f'[{count_val} x {elem_type}]'
elif isinstance(slice_node, (ast.Attribute, ast.Name, ast.Subscript)):
# 单参数 t.CArray[elem_type] → 指针模式
# 单参数 CArray[elem_type] → 指针模式
elem_type = self._get_type_str(slice_node, embedded=True)
VarType = f'{elem_type}*'
member_types.append(VarType)
@@ -910,15 +895,7 @@ class DeclarationGenerator:
is_novtable: bool = False
if hasattr(node, 'decorator_list') and node.decorator_list:
for decorator in node.decorator_list:
if isinstance(decorator, ast.Attribute):
if getattr(decorator.value, 'id', None) == 't':
if decorator.attr == 'CVTable':
is_cvtable = True
elif decorator.attr == 'Object':
is_cpython_object = True
elif decorator.attr == 'NoVTable':
is_novtable = True
elif isinstance(decorator, ast.Name):
if isinstance(decorator, ast.Name):
if decorator.id == 'CVTable':
is_cvtable = True
elif decorator.id == 'Object':
@@ -951,9 +928,7 @@ class DeclarationGenerator:
_base_node = self._cross_module_class_defs.get(base_name)
if _base_node is not None and hasattr(_base_node, 'decorator_list') and _base_node.decorator_list:
for dec in _base_node.decorator_list:
if isinstance(dec, ast.Attribute) and getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable':
base_has_vtable = True
elif isinstance(dec, ast.Name) and dec.id == 'CVTable':
if isinstance(dec, ast.Name) and dec.id == 'CVTable':
base_has_vtable = True
if base_has_vtable:
break
@@ -1071,7 +1046,7 @@ class DeclarationGenerator:
替换策略:使用 i8*(不透明指针)代替 T*,而非具体类型指针。
原因:跨模块场景中,具体类型指针的 SHA1 前缀可能与导入模块不一致,
导致 TransPyC 类型转换失败。i8* 作为通用指针类型,可安全赋值给
任何 Class | t.CPtr 注解的变量,运行时行为与 T* 相同(都是指针)。
任何 Class | CPtr 注解的变量,运行时行为与 T* 相同(都是指针)。
Args:
member_types: 基类成员类型字符串列表
@@ -1139,28 +1114,28 @@ class DeclarationGenerator:
return len(type_str) - len(type_str.rstrip('*'))
def _merge_cptr_subscript(self, base_type: str, cptr_sub_type: str) -> str:
"""base | t.CPtr[T] → Ptr^N(base_type),N = t.CPtr[T] 段自身指针层数。
"""base | CPtr[T] → Ptr^N(base_type),N = CPtr[T] 段自身指针层数。
与定义侧 VPC TypeGenResolve.vp:2610-2639 同口径:数 CPtr 侧已解析类型的
外层 Ptr 嵌套层 N(TypeGenResolve.vp:2616-2632),再给另一侧**纯外包**
N 层 Ptr(TypeGenResolve.vp:2633-2639,对 struct 基类型亦不吸收)。
与 LLVMTypeMapper._resolve_bitor 的 IsCPtrSubscriptNode 分支(_add_pointer_levels
逐层追加)同口径,对同一批形态两处结果一致。
注:裸 | t.CPtr(非下标标记)仍走上方的 %"..."* 吸收分支,与本节无关。
注:裸 | CPtr(非下标标记)仍走上方的 %"..."* 吸收分支,与本节无关。
"""
return base_type + '*' * self._ptr_level_of(cptr_sub_type)
def _ptr_subscript_type_str(self, annotation: ast.Subscript) -> str:
"""指针下标(rawptr[T] / t.CPtr[T] / 裸名 CPtr[T],判据见
"""指针下标(rawptr[T] / CPtr[T] / 裸名 CPtr[T],判据见
SymbolUtils.IsPtrSubscriptNode)→ LLVM 类型串。
与定义端同源:SymbolUtils.DesugarPtrSubscriptToUnion 把三者折叠为等价
联合写法 `T | t.CPtr` 后交 HandlesTypeMerge.MergeTypes,指针层数由
联合写法 `T | CPtr` 后交 HandlesTypeMerge.MergeTypes,指针层数由
_MergeAllComponentTypes 的"struct 基类型吸收一层 CPtr"决定 —— 裸类引用
的非 embedded 形式本身即指针('%"sha1.X"*'),再包一层会被吸收 → 结果
就是该指针本身;其余类型(标量 / 已是指针的 typedef / 泛型容器特化 /
联合写法 / 嵌套指针下标)逐层外包。rawptr[...] 与 t.CPtr[...] 共用本条
规则(此前 t.CPtr[list[X]] 在此得 list[X]**、rawptr[list[X]] 得
联合写法 / 嵌套指针下标)逐层外包。rawptr[...] 与 CPtr[...] 共用本条
规则(此前 CPtr[list[X]] 在此得 list[X]**、rawptr[list[X]] 得
list[X]*,同一指针语义两种结果)。
"""
inner: ast.AST = annotation.slice
@@ -1172,20 +1147,20 @@ class DeclarationGenerator:
return f'{inner_type}*'
def _is_bare_class_ref_annotation(self, inner: ast.AST, inner_type: str) -> bool:
"""节点是否为"裸类引用"(本身即指针 → 吸收一层 t.CPtr)。
"""节点是否为"裸类引用"(本身即指针 → 吸收一层 CPtr)。
与 _get_type_str 的既有约定一致:类引用的**非** embedded 形式本身就是
指针('%"sha1.X"*'),所以 `AST | t.CPtr` 合并后仍是该指针(定义端
指针('%"sha1.X"*'),所以 `AST | CPtr` 合并后仍是该指针(定义端
_MergeAllComponentTypes 的 struct 吸收)。联合写法(ast.BinOp)与指针
下标(rawptr[...] / t.CPtr[...])不是裸类引用——它们已自带指针层数,
须逐层外包(rawptr[Node] | t.CPtr → Node**、ast.AST | t.CPtr | t.CPtr
下标(rawptr[...] / CPtr[...])不是裸类引用——它们已自带指针层数,
须逐层外包(rawptr[Node] | CPtr → Node**、ast.AST | CPtr | CPtr
→ AST**,与定义端整体拉平后只吸收一次 CPtr 一致)。
**例外:纯装饰器标记联合**。`t.CExtern | X` / `t.CExport | X` / `t.State | X`
**例外:纯装饰器标记联合**。`CExtern | X` / `CExport | X` / `State | X`
(vpi 记录的模块级全局就是这种写法,见 lib.Phase.Phase1.__init__.vpi 的
`_mbuddy: t.CExtern | memhub.MemBuddy | t.CPtr`)里标记侧展开为**空串**
`_mbuddy: CExtern | memhub.MemBuddy | CPtr`)里标记侧展开为**空串**
(CTypeRegistry.NameToLLVM('CExtern') == ''),该联合语义上仍是 X 这一个
裸类引用,故 `t.CExtern | X | t.CPtr` 必须与 `X | t.CPtr` 同判(吸收)——
裸类引用,故 `CExtern | X | CPtr` 必须与 `X | CPtr` 同判(吸收)——
对齐 VPC TypeGenResolve 的第 3 条语义「ActualType | DecoratorMarker →
ActualType」。漏此判据时联合被当成"已自带指针层数的左值"而多外包一层:
声明端 `%"sha1.X"**` 与定义端 `%"sha1.X"*` 差一层,消费模块里
@@ -1219,6 +1194,10 @@ class DeclarationGenerator:
return 'void'
if annotation.id in ('str', 'bytes'):
return 'i8*'
# 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`,非真实类):按
# CPtr 同形的一层指针(i8*)参与联合合并(`T | CRef` → T*)。
if annotation.id in ('CRef', 'CTempRef'):
return 'i8*'
llvm_type: str | None = CTypeRegistry.NameToLLVM(annotation.id)
if llvm_type is not None:
return llvm_type
@@ -1249,7 +1228,7 @@ class DeclarationGenerator:
if annotation.id in self.typedef_map:
resolved_str: str = self._get_type_str(self.typedef_map[annotation.id], embedded=embedded)
return resolved_str
# 检查 t 类型别名(from t import CInt as myint)
# 检查内建类型别名
if annotation.id in self._t_alias_map:
t_cls: type = self._t_alias_map[annotation.id]
llvm: str | None = CTypeRegistry.CTypeToLLVM(t_cls)
@@ -1262,10 +1241,6 @@ class DeclarationGenerator:
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver as _DG_TAR
_dg_bv: str | None = _DG_TAR.builtins_typedef_value(annotation.id)
if _dg_bv:
if _dg_bv.startswith('t.'):
_dg_llvm: str | None = CTypeRegistry.NameToLLVM(_dg_bv[2:])
if _dg_llvm:
return _dg_llvm
_dg_node: ast.AST | None = None
try:
_dg_node = ast.parse(_dg_bv, '<DeclarationGenerator:type_expr>', mode='eval').body
@@ -1280,8 +1255,8 @@ class DeclarationGenerator:
return f'{sname}*'
elif isinstance(annotation, ast.Attribute):
attr_name: str = annotation.attr if hasattr(annotation, 'attr') else ''
# 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`,非真实类):按 t.CPtr
# 同形的「一层指针 = i8*」参与联合合并(`T | t.CRef` → T*),保证跨模块
# 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`,非真实类):按 CPtr
# 同形的「一层指针 = i8*」参与联合合并(`T | CRef` → T*),保证跨模块
# .vpi 声明端类型与定义端 _ctype_to_llvm 一致。
if attr_name in ('CRef', 'CTempRef'):
return 'i8*'
@@ -1295,15 +1270,15 @@ class DeclarationGenerator:
# 定义端以扁平名 `{外类}_{内类}` 发射(见 HandlesClassDef._EmitNestedClassDefs),
# 故此处按扁平名拼类型;命中与否由 struct_names 里是否存在该扁平名裁决
# (不存在即维持下方既有路径,不改变任何既有类型名)。
if module_name and module_name != 't' and module_name != 'c':
if module_name:
NestedName: str = f'{module_name}_{attr_name}'
if NestedName in self.struct_names:
NestedSha1: str | None = self.struct_sha1_map.get(NestedName, self.module_sha1)
NestedStr: str = f'%"{NestedSha1}.{NestedName}"' if NestedSha1 else f'%struct.{NestedName}'
return NestedStr if embedded else f'{NestedStr}*'
if (module_name == 't' and attr_name == 'State') or attr_name == 'State':
if attr_name == 'State':
return ''
if (module_name == 't' and attr_name == 'Callable') or attr_name == 'Callable':
if attr_name == 'Callable':
return 'i8*'
llvm_type: str | None = CTypeRegistry.NameToLLVM(attr_name)
if llvm_type is not None:
@@ -1348,23 +1323,23 @@ class DeclarationGenerator:
return right_type if right_type not in ('', 'void') else (left_type or right_type)
if right_type in ('', 'void'):
return left_type
# t.CPtr (i8*) 与 left 合并:对齐 Phase 2 _MergeAllComponentTypes 的
# "first CPtr absorption" 语义:struct | t.CPtr → struct*(吸收,struct 变量默认是指针)。
# 但对于本身已是指针的类型(如 bytes=str=i8*),bytes | t.CPtr → i8**(不吸收)。
# CPtr (i8*) 与 left 合并:对齐 Phase 2 _MergeAllComponentTypes 的
# "first CPtr absorption" 语义:struct | CPtr → struct*(吸收,struct 变量默认是指针)。
# 但对于本身已是指针的类型(如 bytes=str=i8*),bytes | CPtr → i8**(不吸收)。
# 例外:LLVM 聚合数组([N x T],字符串以 '[' 开头)不可再外包指针层 → i8*。
# 注:具名泛型特化(%"mod.list[X]"*)**不**走此回退——stub 已由
# _collect_undefined_type_decls 为其补 opaque 声明,保留名字才能与 define 端
# 的 %"mod.list[ast.ASTptr]"* 逐字一致(原 `'[' in left_type` 会把
# list[X] | t.CPtr 一并退化成 i8*,与定义端 %"mod.list[X]"* 不一致)。
# list[X] | CPtr 一并退化成 i8*,与定义端 %"mod.list[X]"* 不一致)。
if right_type == 'i8*':
if left_type[:1] == '[':
return 'i8*'
if left_type in ('', 'void'):
return 'i8*'
# 吸收仅对"裸类引用"成立(其非 embedded 形式本身即指针):
# ast.AST | t.CPtr → %"sha1.AST"*。已自带指针层数的左值
# (rawptr[...] / t.CPtr[...] 下标 / 联合写法)须逐层外包:
# rawptr[Node] | t.CPtr → Node**、ast.AST | t.CPtr | t.CPtr → AST**
# ast.AST | CPtr → %"sha1.AST"*。已自带指针层数的左值
# (rawptr[...] / CPtr[...] 下标 / 联合写法)须逐层外包:
# rawptr[Node] | CPtr → Node**、ast.AST | CPtr | CPtr → AST**
# ——与定义端 _CollectAllOperandTypes 整体拉平、只吸收一次 CPtr
# (_MergeAllComponentTypes 的 base_ptr_count>0 分支)一致。
if self._is_bare_class_ref_annotation(annotation.left, left_type):
@@ -1372,20 +1347,20 @@ class DeclarationGenerator:
if '*' in left_type:
return f'{left_type}*'
return f'{left_type}*'
# X | t.CPtr[T](T 为下标段,非裸标记):CPtr 侧贡献自身指针层数 N,
# X | CPtr[T](T 为下标段,非裸标记):CPtr 侧贡献自身指针层数 N,
# 另一侧外包 N 层(Ptr^N(X));左右两侧写法对称(定义侧 VPC
# TypeGenResolve.vp:2604-2609 亦两侧皆判)。必须先于下方
# "'*' in left_type → 直接返回左值":否则左值本身已是指针
# (BYTEPTR⇒i8*)时会吞掉右段层数(BYTEPTR | t.CPtr[t.CPtr] 改前得 i8*)。
# (BYTEPTR⇒i8*)时会吞掉右段层数(BYTEPTR | CPtr[CPtr] 改前得 i8*)。
# LLVM 聚合([N x T] / { ... })不可再外包指针层,保持既有行为(只报不改)。
if IsCPtrSubscriptNode(annotation.right) and left_type[:1] not in ('[', '{'):
return self._merge_cptr_subscript(left_type, right_type)
if IsCPtrSubscriptNode(annotation.left) and right_type[:1] not in ('[', '{'):
return self._merge_cptr_subscript(right_type, left_type)
# t.CPtr 裸标记在左侧(t.CPtr | X):与右侧写法(X | t.CPtr,见上)
# CPtr 裸标记在左侧(CPtr | X):与右侧写法(X | CPtr,见上)
# 完全对称。缺此分支时左值 i8* 会吞掉右侧的指针层数:
# t.CPtr | rawptr[Node] 声明端曾得 i8*,而定义端为 %"sha1.Node"**(差一层)。
# 仅对裸标记 t.CPtr 生效(left 为 t.CPtr[T] 下标走上一条分支;
# CPtr | rawptr[Node] 声明端曾得 i8*,而定义端为 %"sha1.Node"**(差一层)。
# 仅对裸标记 CPtr 生效(left 为 CPtr[T] 下标走上一条分支;
# str/bytes 等其它 i8* 左值不受影响)。
if IsCPtrNode(annotation.left) and right_type[:1] not in ('[', '{'):
if self._is_bare_class_ref_annotation(annotation.right, right_type):
@@ -1397,24 +1372,24 @@ class DeclarationGenerator:
return right_type
return left_type
elif isinstance(annotation, ast.Subscript):
# 指针下标(rawptr[T] / t.CPtr[T] / 裸名 CPtr[T] / 导入别名 X[T],以及带
# 模块前缀书写的 X.CPtr[T])≡ 源码联合写法 `T | t.CPtr`:与定义端
# 指针下标(rawptr[T] / CPtr[T] / 裸名 CPtr[T] / 导入别名 X[T],以及带
# 模块前缀书写的 X.CPtr[T])≡ 源码联合写法 `T | CPtr`:与定义端
# **同一判据**(SymbolUtils.IsPtrSubscriptNode,别名经本模块的
# _t_c_imported_names 表解析 X→CPtr)+ 同一层数规则
# _from_import_aliases 表解析 X→CPtr)+ 同一层数规则
# (_ptr_subscript_type_str:裸类引用吸收一层、其余逐层外包),内层 T
# 照常解析(跨模块类由 struct_sha1_map 补 SHA1 前缀)。此前 rawptr[T]
# 在此退化成 i8*,t.CPtr[T] 走的是"embedded + 追加一层"的独立分支:
# 非同一规则,且对泛型容器特化多出一层(t.CPtr[list[X]] 得 list[X]**,
# 在此退化成 i8*,CPtr[T] 走的是"embedded + 追加一层"的独立分支:
# 非同一规则,且对泛型容器特化多出一层(CPtr[list[X]] 得 list[X]**,
# 而 rawptr[list[X]] 得 list[X]*)。
ValueIsCPtr: bool = (
(isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CPtr')
or (isinstance(annotation.value, ast.Name) and annotation.value.id == 'CPtr')
)
if (IsPtrSubscriptNode(annotation, TCAliasMap=self._t_c_imported_names)
if (IsPtrSubscriptNode(annotation, TCAliasMap=self._from_import_aliases)
or (ValueIsCPtr and isinstance(annotation.slice, (ast.Attribute, ast.Name, ast.Subscript)))):
return self._ptr_subscript_type_str(annotation)
# 内建裸名函数指针构造子 callable[...] / Callable[...]:与 Attribute 分支的
# t.Callable[...] 逐点等价(同为 i8*)。缺此分支时落到下方 Name 泛型特化 /
# Callable[...] 逐点等价(同为 i8*)。缺此分支时落到下方 Name 泛型特化 /
# 兜底返回 'i32'(现场 Repl.vp:307 `ReplFragFn: callable[[rawptr], int]`
# 声明成 i32 全局 ⇒ 赋 i8* 触发「指针隐式转整数」)。
if isinstance(annotation.value, ast.Name) and (annotation.value.id == 'callable' or annotation.value.id == 'Callable'):
@@ -1424,10 +1399,10 @@ class DeclarationGenerator:
return f'[{self._get_const_int(annotation.slice)} x i8]'
if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int):
return f'[{annotation.slice.value} x {base}]'
# 处理 t.CArray[elem_type, count] / rawarray[elem_type, count] / array[elem_type, count]
# 处理 CArray[elem_type, count] / rawarray[elem_type, count] / array[elem_type, count]
# 注解 → [count x elem_type]
# 支持 t.CArray (ast.Attribute)、CArray/rawarray/array (ast.Name) 三种写法
# (array 为本轮新增的内建软关键字,与 t.CArray 逐点等价)
# 支持 CArray (ast.Attribute)、CArray/rawarray/array (ast.Name) 三种写法
# (array 为本轮新增的内建软关键字,与 CArray 逐点等价)
ValueIsCArray: bool = (
(isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CArray')
or (isinstance(annotation.value, ast.Name) and annotation.value.id in ('CArray', 'rawarray', 'array'))
@@ -1442,7 +1417,7 @@ class DeclarationGenerator:
# count 为 None 或 0 → 零长度数组(外部符号)
return f'[0 x {ElemType}]'
elif isinstance(SliceNode, (ast.Attribute, ast.Name, ast.Subscript)):
# 单参数 t.CArray[elem_type]:与 t.CArray[elem_type, None] 语义统一为
# 单参数 CArray[elem_type]:与 CArray[elem_type, None] 语义统一为
# "长度自动推导数组"。此处无初始化字面量可推导 → 与 ,None 分支同用
# [0 x elem] 占位,真实长度由 _generate_global_decl 按初始化字面量
# (List 长度 / str 长度+1) 修正。
@@ -1462,7 +1437,7 @@ class DeclarationGenerator:
# 实参串走 SymbolUtils.ResolveGenericTypeArgStr(与定义端
# _mangle_generic_class_name 同一规则源):此前只认 Name / Name-Tuple
# 实参,Attribute(ast.AST)/ Subscript(rawptr[...])/ BinOp
# (X | t.CPtr)/ 混合 Tuple 一律退回未特化的 %"...list"*,
# (X | CPtr)/ 混合 Tuple 一律退回未特化的 %"...list"*,
# 与 define 端发射的 %"<mod>.list[ast.ASTptr]" 不一致
# (Undefined method / 签名错位)。
# 内建容器(non_struct_types)之外,**用户泛型类**同样特化:判据
@@ -1482,7 +1457,7 @@ class DeclarationGenerator:
gc_mangled: list[str] = [
ResolveGenericTypeArgStr(
gc_node,
TCAliasMap=self._t_c_imported_names,
TCAliasMap=self._from_import_aliases,
StructSha1Map=self.struct_sha1_map)
for gc_node in gc_nodes]
gc_spec: str = gc_name + '[' + ']['.join(gc_mangled) + ']'
@@ -1496,7 +1471,7 @@ class DeclarationGenerator:
gc_sha1: str | None = self.struct_sha1_map.get(gc_name, self.module_sha1)
gc_sname: str = f'%"{gc_sha1}.{gc_spec}"' if gc_sha1 else f'%struct.{gc_spec}'
# 一律以指针引用(不区分 embedded):定义端对嵌入式泛型容器
# (字段 / t.CArray 元素)用不透明指针(实测字段 i8*,见
# (字段 / CArray 元素)用不透明指针(实测字段 i8*,见
# FieldForms/FieldBox/FieldOrder),嵌入 unsized opaque
# 结构体值会让字段/元素偏移错位;非 embedded(参数/返回)
# 亦与定义端同为指针
@@ -1539,9 +1514,7 @@ class DeclarationGenerator:
return f'{sname}*'
return 'i8*'
elif isinstance(annotation, ast.Call):
if isinstance(annotation.func, ast.Name) and annotation.func.id == 'callable':
return 'i8*'
if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Callable':
if isinstance(annotation.func, ast.Name) and annotation.func.id in ('callable', 'Callable'):
return 'i8*'
return 'i32'
+58 -56
View File
@@ -11,7 +11,7 @@ from lib.Projectrans.DeclarationGenerator import DeclarationGenerator
from lib.core.VLogger import get_logger as _vlog
from lib.core.SymbolUtils import ExpandSoftKeywords
from lib.constants.config import mode as _ConfigMode
from lib.includes import t
from lib.core import TypeSystem
from StubGen import PythonToStubConverter
# 全局缓存目录(不被 --clean 清除),用于缓存库文件的 .pyi / .stub.ll / .doc.json
@@ -387,6 +387,8 @@ class Phase1Generator:
is_typedef = True
elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef':
is_typedef = True
elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Name) and node.annotation.left.id == 'CTypedef':
is_typedef = True
if is_typedef and node.value and var_name not in typedef_map:
typedef_map[var_name] = node.value
except Exception as _e:
@@ -564,55 +566,55 @@ class Phase1Generator:
return body[0].value.value
return None
def _get_cached_pyi(self, src_path: str, module_name: str) -> str:
"""读取源文件并转换为 .pyi 内容;同一 (路径, 模块名) 且 mtime+size 未变时复用模块级缓存。
覆盖 _process_file_pyi 与 _process_include_py_files_pyi 两个入口,
避免对未变化的文件重复 open+read+convert(mtime+size 一致即视为内容未变,
与 _get_sha1 的 manifest 判定一致)。
"""
abs_path: str = os.path.abspath(src_path)
key: tuple[str, str] = (abs_path, module_name)
try:
st: os.stat_result = os.stat(abs_path)
except OSError:
st = None
if st is not None:
cached: tuple[float, int, str] | None = _PYI_CONVERT_CACHE.get(key)
if cached is not None and cached[0] == st.st_mtime and cached[1] == st.st_size:
return cached[2]
with open(abs_path, 'r', encoding='utf-8') as f:
content: str = f.read()
sig_content: str = PythonToStubConverter.convert(content, module_name)
if len(_PYI_CONVERT_CACHE) >= _PYI_CACHE_MAX_SIZE:
_PYI_CONVERT_CACHE.clear()
if st is not None:
_PYI_CONVERT_CACHE[key] = (st.st_mtime, st.st_size, sig_content)
return sig_content
def _get_cached_docstrings(self, src_path: str) -> dict[str, str]:
"""读取源文件并提取 docstring;同一路径且 mtime+size 未变时复用模块级缓存。
返回的 dict 仅供调用方 json.dump 只读使用,调用方不修改,故可安全复用缓存对象。
"""
abs_path: str = os.path.abspath(src_path)
try:
st: os.stat_result = os.stat(abs_path)
except OSError:
st = None
if st is not None:
cached: tuple[float, int, dict[str, str]] | None = _PYI_DOC_CACHE.get(abs_path)
if cached is not None and cached[0] == st.st_mtime and cached[1] == st.st_size:
return cached[2]
with open(abs_path, 'r', encoding='utf-8') as f:
content: str = f.read()
docs: dict[str, str] = self._extract_docstrings(content)
if len(_PYI_DOC_CACHE) >= _PYI_CACHE_MAX_SIZE:
_PYI_DOC_CACHE.clear()
if st is not None:
_PYI_DOC_CACHE[abs_path] = (st.st_mtime, st.st_size, docs)
return docs
def _get_cached_pyi(self, src_path: str, module_name: str) -> str:
"""读取源文件并转换为 .pyi 内容;同一 (路径, 模块名) 且 mtime+size 未变时复用模块级缓存。
覆盖 _process_file_pyi 与 _process_include_py_files_pyi 两个入口,
避免对未变化的文件重复 open+read+convert(mtime+size 一致即视为内容未变,
与 _get_sha1 的 manifest 判定一致)。
"""
abs_path: str = os.path.abspath(src_path)
key: tuple[str, str] = (abs_path, module_name)
try:
st: os.stat_result = os.stat(abs_path)
except OSError:
st = None
if st is not None:
cached: tuple[float, int, str] | None = _PYI_CONVERT_CACHE.get(key)
if cached is not None and cached[0] == st.st_mtime and cached[1] == st.st_size:
return cached[2]
with open(abs_path, 'r', encoding='utf-8') as f:
content: str = f.read()
sig_content: str = PythonToStubConverter.convert(content, module_name)
if len(_PYI_CONVERT_CACHE) >= _PYI_CACHE_MAX_SIZE:
_PYI_CONVERT_CACHE.clear()
if st is not None:
_PYI_CONVERT_CACHE[key] = (st.st_mtime, st.st_size, sig_content)
return sig_content
def _get_cached_docstrings(self, src_path: str) -> dict[str, str]:
"""读取源文件并提取 docstring;同一路径且 mtime+size 未变时复用模块级缓存。
返回的 dict 仅供调用方 json.dump 只读使用,调用方不修改,故可安全复用缓存对象。
"""
abs_path: str = os.path.abspath(src_path)
try:
st: os.stat_result = os.stat(abs_path)
except OSError:
st = None
if st is not None:
cached: tuple[float, int, dict[str, str]] | None = _PYI_DOC_CACHE.get(abs_path)
if cached is not None and cached[0] == st.st_mtime and cached[1] == st.st_size:
return cached[2]
with open(abs_path, 'r', encoding='utf-8') as f:
content: str = f.read()
docs: dict[str, str] = self._extract_docstrings(content)
if len(_PYI_DOC_CACHE) >= _PYI_CACHE_MAX_SIZE:
_PYI_DOC_CACHE.clear()
if st is not None:
_PYI_DOC_CACHE[abs_path] = (st.st_mtime, st.st_size, docs)
return docs
def _process_file_pyi(self, src_path: str, rel_path: str) -> None:
# 增量优化:先用 mtime+size 获取 sha1,未变更文件跳过 open+read
sha1: str = self._get_sha1(src_path)
@@ -687,13 +689,13 @@ class Phase1Generator:
exception_names: set[str] = set()
struct_sha1_map: dict[str, str] = {}
class_def_map: dict[str, ast.ClassDef] = {}
# 预先收集所有 CType 子类名称(来自 t 模块和别名映射),
# 预先收集所有 CType 子类名称(来自内建类型模型),
# 用于在 struct 注册表中跳过"类型强转"标记类。
ctype_marker_names: set[str] = set()
for attr_name in dir(t):
t_cls: type | None = getattr(t, attr_name, None)
if isinstance(t_cls, type) and issubclass(t_cls, t.CType) and t_cls is not t.CType:
if not issubclass(t_cls, (t.CEnum, t.REnum, t.CUnion, t.CStruct)):
for attr_name in dir(TypeSystem):
t_cls: type | None = getattr(TypeSystem, attr_name, None)
if isinstance(t_cls, type) and issubclass(t_cls, TypeSystem.CType) and t_cls is not TypeSystem.CType:
if not issubclass(t_cls, (TypeSystem.CEnum, TypeSystem.REnum, TypeSystem.CUnion, TypeSystem.CStruct)):
ctype_marker_names.add(t_cls.__name__)
ctype_marker_names.add(attr_name)
valid_sha1_keys: set[str] = set(self.sha1_map.keys())
@@ -742,7 +744,7 @@ class Phase1Generator:
elif base.id in ctype_marker_names:
is_ctype_marker = True
break
# 也检查装饰器形式 @t.CEnum / @t.REnum
# 也检查装饰器形式 @CEnum / @REnum
if not is_enum and not is_renum and not is_exception and not is_ctype_marker and hasattr(node, 'decorator_list') and node.decorator_list:
for deco in node.decorator_list:
deco_attr: str | None = None
+13 -16
View File
@@ -17,7 +17,7 @@ from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolData import ModuleSymbols
from lib.includes import t
from lib.core import TypeSystem
from lib.core.SymbolUtils import AnnotationContainsName, ExpandSoftKeywords, DefineDeclIntTypeFromAnnotation
from lib.core.SymbolUtils import ClassHasFuncLevelCVTable, IsVtableSlotMethod
from lib.Projectrans.Utils import compute_sha1, _check_annotation_for_export, find_reachable_files_from_entries, topological_sort_files, parse_python_file
@@ -609,11 +609,11 @@ def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object],
"""从 .pyi 文件中提取 CDefine 常量到 all_dc。文件不存在时静默跳过。
治本修复:原实现只支持 ast.Constant 和 float() 调用,
无法处理 t.CUnsignedLong(-11)(ast.Call)和
无法处理 CUnsignedLong(-11)(ast.Call)和
FOREGROUND_GREEN | FOREGROUND_INTENSITY(ast.BinOp)等复杂表达式。
现使用 ConstEvaluator.eval_full 统一求值,支持:
- ast.Constant: 简单常量 (0x0002)
- ast.Call: 类型构造 (t.CUnsignedLong(-11))
- ast.Call: 类型构造 (CUnsignedLong(-11))
- ast.BinOp: 位运算 (FOREGROUND_RED | FOREGROUND_GREEN)
- ast.UnaryOp: 一元运算 (-11)
- ast.Name: 引用其他 CDefine 常量
@@ -643,10 +643,10 @@ def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object],
if AnnotationContainsName(node.annotation, 'CDefine') and node.value:
val: object = ConstEvaluator.eval_full(node.value, ctx)
if val is None and isinstance(node.value, ast.Call) and len(node.value.args) == 1:
# 类型构造的**裸别名**形态(如 `DWORD(-11)`,非 `t.CUnsignedLong(-11)`):
# eval_full 只认 `t.X(...)` / `from t import X`(见 ConstEvaluator
# 类型构造的**裸别名**形态(如 `DWORD(-11)`,非 `CUnsignedLong(-11)`):
# eval_full 只认 `X(...)` / `from t import X`(见 ConstEvaluator
# _eval_compile_time_call),裸 typedef 别名既不在 _t_module 也不在
# mock ctx 的 _t_type_symbols 里 → 返回 None → 该常量被整条丢弃。
# mock ctx 的 _builtin_type_symbols 里 → 返回 None → 该常量被整条丢弃。
# 现场:win32file.vp 的 STD_INPUT/OUTPUT/ERROR_HANDLE 是全仓**唯一**用
# 别名构造写的 define → 唯独这三个进不了 _all_define_constants,导致
# 模块属性访问 `wf.STD_ERROR_HANDLE` 解析落空、退化成未定义的全局符号
@@ -668,7 +668,7 @@ def _CountUnresolvedTypedefs(module_symbols: object) -> int:
"""该模块"有值注解却解析不出类型"的 typedef 个数(供声明阶段判断是否要下一轮)。
typedef 右侧可以引用**其它模块**的 typedef:例 win32base 的
`HANDLE: t.CTypedef = VOIDPTR`(VOIDPTR 在 stdint)——本模块先 stage 时右侧
`HANDLE: CTypedef = VOIDPTR`(VOIDPTR 在 stdint)——本模块先 stage 时右侧
解析为空(original_type_kind/original_class 均为 None),要等依赖模块入表后
重 stage 才能补全。返回 0 表示本模块声明已完整(不再需要重跑)。
"""
@@ -3132,7 +3132,7 @@ class Phase2Translator:
sys.exit(1)
def _precollect_vtable_state(self) -> None:
"""预扫描 includes .py 文件,收集 @t.CVTable 类的虚表信息。
"""预扫描 includes .py 文件,收集 @CVTable 类的虚表信息。
并行编译(ProcessPoolExecutor)创建独立内存的 worker 进程,
vtable 状态必须预收集并通过 pickle 共享。
@@ -3150,7 +3150,7 @@ class Phase2Translator:
code, tree = parse_python_file(py_path)
# 字符串预过滤:不含 CVTable 的文件跳过 AST 遍历。
# `virtual class` / `virtual def` 修饰符在源码里写的是 `virtual`
# (AST 上才变成 @t.CVTable 装饰器),故预过滤必须同时放行
# (AST 上才变成 @CVTable 装饰器),故预过滤必须同时放行
# `virtual`/`novirtual`,否则含修饰符的 includes 类会被整段跳过——
# 静默不预收集虚表状态(与本题"不得静默丢弃修饰符"同族问题)。
if tree is None or ('CVTable' not in code and 'virtual' not in code):
@@ -3161,10 +3161,7 @@ class Phase2Translator:
continue
has_cvtable: bool = False
for dec in node.decorator_list:
if isinstance(dec, ast.Attribute):
if getattr(dec.value, 'id', None) == 't' and dec.attr == 'CVTable':
has_cvtable = True
elif isinstance(dec, ast.Name):
if isinstance(dec, ast.Name):
if dec.id == 'CVTable':
has_cvtable = True
# 方法级 virtual 触发类级 vtable(与
@@ -3199,7 +3196,7 @@ class Phase2Translator:
# 构造函数不放入 vtable(避免子类与基类 vtable 大小不一致破坏多态分派)
if method_name in ('__new__', '__init__', '__before_init__'):
continue
# 方法级修饰符:`novirtual def`(⇒ @t.NoVTable)不进槽;
# 方法级修饰符:`novirtual def`(⇒ @NoVTable)不进槽;
# 判据唯一源 = SymbolUtils.IsVtableSlotMethod,与
# HandlesClassDef / VPC _should_method_be_virtual 同口径。
if not IsVtableSlotMethod(item, class_level_cvtable):
@@ -4370,7 +4367,7 @@ class Phase2Translator:
info.IsInline = True
info.InlineBody = node.body
info.InlineParams = [arg.arg for arg in node.args.args]
info.Storage = t.CInline()
info.Storage = TypeSystem.CInline()
self.inline_func_symbols[func_name] = info
self.inline_func_symbols[sym_key] = info
except Exception as _e:
@@ -4440,7 +4437,7 @@ class Phase2Translator:
# ① 声明阶段(全部模块;多轮直到"本轮没有新增可解析的声明")
# 单轮仍会与模块顺序有关:typedef 右侧可以引用**其它模块**的 typedef,
# 例 win32base 的 `HANDLE: t.CTypedef = VOIDPTR`,VOIDPTR 在 stdint
# 例 win32base 的 `HANDLE: CTypedef = VOIDPTR`,VOIDPTR 在 stdint
# ⇒ 本模块先 stage 时右侧解析为空;下一轮把它重 stage 一遍(重 stage 覆盖
# 登记,条目随依赖入表而变完整)。无进展即停,最多再跑一轮。
_stage_map: dict[tuple[str, str], ModuleSymbols] = {}
+2 -2
View File
@@ -41,7 +41,7 @@ _FILE_AST_CACHE: dict[str, tuple[float, str, ast.Module]] = {}
def _check_annotation_for_export(annotation: ast.AST | None) -> bool:
"""递归检查类型注解中是否包含 CExport/CExtern/State(t.State = t.CExtern | t.CExport)"""
"""递归检查类型注解中是否包含 CExport/CExtern/State(State = CExtern | CExport)"""
if not annotation:
return False
return (AnnotationContainsName(annotation, 'CExport') or
@@ -78,7 +78,7 @@ def parse_python_file(filepath: str) -> tuple[str, ast.Module] | tuple[str, None
except Exception:
return ('', None)
try:
# 软关键字/语法糖展开:fn/fun/func/function -> def、enum 块 -> class X(t.CEnum)
# 软关键字/语法糖展开:fn/fun/func/function -> def、enum 块 -> class X(CEnum)
# (均同行替换,行号不变),供 ast.parse 使用。
# 注意 content 保持原始文本返回(compute_sha1 必须与 Phase1 一致),
# 仅 tree 基于展开后的代码解析。
+1 -1
View File
@@ -1,5 +1,5 @@
"""Projectrans 包 - 工程级 TransPyC 翻译器"""
import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes)
import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib)
from lib.core.VLogger import Logger, LogLevel, set_logger