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:
1 parent
8d27747c7c
commit
f19d25782f
66 files changed
+2445
-3638
No files matched your search
@@ -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'
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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] = {}
|
||||
|
||||
@@ -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,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
|
||||
|
||||
|
||||
Reference in new issue
Block a user