refactor(tpc): 删除类型联合语法并将修饰迁移为 AST 字段
类型注解不再接受任何 T1 | T2;const/volatile/static/export/extern/inline/define/typedef/__attribute__/BigEndian/LittleEndian/Bit 改为注解节点字段 Markers/Attributes/ByteOrder/BitWidth;指针与引用改为 CPtr[T]/CRef[T]/CTempRef[T]/CArrayPtr[T]/CAutoPtr[T];Python 与 vast_c 两套解析器、类型解析与声明端同步;C 扩展早于 vast_c.c 时自动回退纯 Python 解析器。
This commit is contained in:
1 parent
3269775945
commit
660a15bef8
19 files changed
+1312
-1576
No files matched your search
@@ -10,7 +10,7 @@ import llvmlite.ir as ir
|
||||
from lib.core import TypeSystem
|
||||
from lib.core.TypeSystem import CTypeRegistry
|
||||
from lib.core.SymbolUtils import (
|
||||
IsListAnnotation, AnnotationContainsName, RejectTypeUnion, IsCPtrSubscriptNode, IsCPtrNode,
|
||||
IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode,
|
||||
IsRawPtrSubscriptNode, IsPtrSubscriptNode, ResolveGenericTypeArgStr,
|
||||
EnumClassIntWidth, ClassHasFuncLevelCVTable)
|
||||
|
||||
@@ -94,20 +94,16 @@ class DeclarationGenerator:
|
||||
self._DefineConstants[var_name] = node.value.value
|
||||
elif node.value and isinstance(node.value, ast.Name):
|
||||
self._DefineConstants[var_name] = node.value.id
|
||||
is_typedef: bool = False
|
||||
if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef':
|
||||
is_typedef = True
|
||||
elif isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef':
|
||||
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
|
||||
elif isinstance(node.annotation, ast.BinOp) and node.annotation.right:
|
||||
self.typedef_map[var_name] = node.annotation.right
|
||||
Markers: tuple[str, ...] = tuple(getattr(node, 'Markers', None) or ()) + tuple(
|
||||
getattr(node.annotation, 'Markers', None) or ())
|
||||
is_typedef: bool = 'typedef' in Markers
|
||||
if not is_typedef:
|
||||
if isinstance(node.annotation, ast.Attribute) and getattr(node.annotation, 'attr', '') == 'CTypedef':
|
||||
is_typedef = True
|
||||
elif isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef':
|
||||
is_typedef = True
|
||||
if is_typedef and node.value:
|
||||
self.typedef_map[var_name] = node.value
|
||||
|
||||
lines: list[str] = []
|
||||
lines.append('; ModuleID = "transpyc_decl"')
|
||||
@@ -235,35 +231,39 @@ class DeclarationGenerator:
|
||||
|
||||
def _is_export_func(self, node: ast.FunctionDef) -> bool:
|
||||
"""检查函数是否标记为 CExport"""
|
||||
Markers: tuple[str, ...] = getattr(node, 'Markers', None) or ()
|
||||
if 'export' in Markers or 'state' in Markers:
|
||||
return True
|
||||
if not node.returns:
|
||||
return False
|
||||
return self._check_annotation_for_export(node.returns)
|
||||
|
||||
def _check_annotation_for_export(self, annotation: ast.AST | None) -> bool:
|
||||
"""递归检查类型注解中是否包含 CExport 或 State"""
|
||||
return bool(annotation) and (AnnotationContainsName(annotation, 'CExport') or AnnotationContainsName(annotation, 'State'))
|
||||
"""检查类型注解是否带 export / state 标记"""
|
||||
if annotation is None:
|
||||
return False
|
||||
Markers: tuple[str, ...] = getattr(annotation, 'Markers', None) or ()
|
||||
if 'export' in Markers or 'state' in Markers:
|
||||
return True
|
||||
return AnnotationContainsName(annotation, 'CExport') or AnnotationContainsName(annotation, 'State')
|
||||
|
||||
def _generate_global_decl(self, node: ast.AnnAssign) -> str | None:
|
||||
"""生成全局变量声明"""
|
||||
if not isinstance(node.target, ast.Name):
|
||||
return None
|
||||
var_name: str = node.target.id
|
||||
# CDefine 是编译期常量,不是变量:stub 里**不得**生成 external global。
|
||||
# `define X: T = V` 会展开为注解 `T | CDefine`,故判据必须能识别**联合形态**——
|
||||
# 原判据只认裸 `CDefine`(注解为单个 Attribute),联合注解会漏判 →
|
||||
# stub 出现 `@X = external global i32` → 其他模块引用它时变成未定义符号(链接失败),
|
||||
# 且会遮住跨模块 CDefine 常量回退(同名全局优先于常量)。与 _check_annotation_for_export
|
||||
# 一样用递归判据。
|
||||
if AnnotationContainsName(node.annotation, 'CDefine'):
|
||||
# CDefine 是编译期常量,不是变量:stub 里**不得**生成 external global,
|
||||
# 否则其他模块引用它时变成未定义符号(链接失败)。标记由 Markers 字段承载。
|
||||
Markers: tuple[str, ...] = tuple(getattr(node, 'Markers', None) or ()) + tuple(
|
||||
getattr(node.annotation, 'Markers', None) or ())
|
||||
if 'define' in Markers or AnnotationContainsName(node.annotation, 'CDefine'):
|
||||
return None
|
||||
if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef':
|
||||
if 'typedef' in Markers:
|
||||
return None
|
||||
if isinstance(node.annotation, ast.Attribute) and getattr(node.annotation, 'attr', '') == 'CTypedef':
|
||||
return None
|
||||
if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef':
|
||||
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'):
|
||||
@@ -1108,35 +1108,13 @@ class DeclarationGenerator:
|
||||
# 其他未知类型保守估算
|
||||
return 8
|
||||
|
||||
@staticmethod
|
||||
def _ptr_level_of(type_str: str) -> int:
|
||||
"""统计类型字符串尾部的指针层数('i8***' → 3,'i32' → 0)"""
|
||||
return len(type_str) - len(type_str.rstrip('*'))
|
||||
|
||||
def _merge_cptr_subscript(self, base_type: str, cptr_sub_type: str) -> str:
|
||||
"""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
|
||||
逐层追加)同口径,对同一批形态两处结果一致。
|
||||
注:裸 | CPtr(非下标标记)仍走上方的 %"..."* 吸收分支,与本节无关。
|
||||
"""
|
||||
return base_type + '*' * self._ptr_level_of(cptr_sub_type)
|
||||
|
||||
def _ptr_subscript_type_str(self, annotation: ast.Subscript) -> str:
|
||||
"""指针下标(rawptr[T] / CPtr[T] / 裸名 CPtr[T],判据见
|
||||
SymbolUtils.IsPtrSubscriptNode)→ LLVM 类型串。
|
||||
|
||||
与定义端同源:SymbolUtils.DesugarPtrSubscriptToUnion 把三者折叠为等价
|
||||
联合写法 `T | CPtr` 后交 HandlesTypeMerge.MergeTypes,指针层数由
|
||||
_MergeAllComponentTypes 的"struct 基类型吸收一层 CPtr"决定 —— 裸类引用
|
||||
的非 embedded 形式本身即指针('%"sha1.X"*'),再包一层会被吸收 → 结果
|
||||
就是该指针本身;其余类型(标量 / 已是指针的 typedef / 泛型容器特化 /
|
||||
联合写法 / 嵌套指针下标)逐层外包。rawptr[...] 与 CPtr[...] 共用本条
|
||||
规则(此前 CPtr[list[X]] 在此得 list[X]**、rawptr[list[X]] 得
|
||||
list[X]*,同一指针语义两种结果)。
|
||||
裸类引用的非 embedded 形式本身即指针('%"sha1.X"*'),再包一层会被
|
||||
吸收 → 结果就是该指针本身;其余类型(标量 / 已是指针的 typedef /
|
||||
泛型容器特化 / 嵌套指针下标)逐层外包。
|
||||
"""
|
||||
inner: ast.AST = annotation.slice
|
||||
inner_type: str = self._get_type_str(inner)
|
||||
@@ -1149,36 +1127,12 @@ class DeclarationGenerator:
|
||||
def _is_bare_class_ref_annotation(self, inner: ast.AST, inner_type: str) -> bool:
|
||||
"""节点是否为"裸类引用"(本身即指针 → 吸收一层 CPtr)。
|
||||
|
||||
与 _get_type_str 的既有约定一致:类引用的**非** embedded 形式本身就是
|
||||
指针('%"sha1.X"*'),所以 `AST | CPtr` 合并后仍是该指针(定义端
|
||||
_MergeAllComponentTypes 的 struct 吸收)。联合写法(ast.BinOp)与指针
|
||||
下标(rawptr[...] / CPtr[...])不是裸类引用——它们已自带指针层数,
|
||||
须逐层外包(rawptr[Node] | CPtr → Node**、ast.AST | CPtr | CPtr
|
||||
→ AST**,与定义端整体拉平后只吸收一次 CPtr 一致)。
|
||||
|
||||
**例外:纯装饰器标记联合**。`CExtern | X` / `CExport | X` / `State | X`
|
||||
(vpi 记录的模块级全局就是这种写法,见 lib.Phase.Phase1.__init__.vpi 的
|
||||
`_mbuddy: CExtern | memhub.MemBuddy | CPtr`)里标记侧展开为**空串**
|
||||
(CTypeRegistry.NameToLLVM('CExtern') == ''),该联合语义上仍是 X 这一个
|
||||
裸类引用,故 `CExtern | X | CPtr` 必须与 `X | CPtr` 同判(吸收)——
|
||||
对齐 VPC TypeGenResolve 的第 3 条语义「ActualType | DecoratorMarker →
|
||||
ActualType」。漏此判据时联合被当成"已自带指针层数的左值"而多外包一层:
|
||||
声明端 `%"sha1.X"**` 与定义端 `%"sha1.X"*` 差一层,消费模块里
|
||||
`self.__mbuddy__ = _mbuddy` 之类的赋值即报"层数不同"fail-fast。
|
||||
类引用的**非** embedded 形式本身就是指针('%"sha1.X"*'),再包一层
|
||||
指针会被吸收;指针下标(rawptr[...] / CPtr[...])已自带指针层数,
|
||||
须逐层外包(CPtr[Node] → Node**)。
|
||||
"""
|
||||
if not inner_type:
|
||||
return False
|
||||
if isinstance(inner, ast.BinOp):
|
||||
if not isinstance(inner.op, ast.BitOr):
|
||||
return False
|
||||
LeftType: str = self._get_type_str(inner.left)
|
||||
RightType: str = self._get_type_str(inner.right)
|
||||
# 恰一侧是纯装饰器标记(展开为空/void)⇒ 类型全部来自另一侧,按另一侧判
|
||||
if LeftType in ('', 'void') and RightType not in ('', 'void'):
|
||||
return self._is_bare_class_ref_annotation(inner.right, RightType)
|
||||
if RightType in ('', 'void') and LeftType not in ('', 'void'):
|
||||
return self._is_bare_class_ref_annotation(inner.left, LeftType)
|
||||
return False
|
||||
if isinstance(inner, ast.Subscript):
|
||||
return not (IsRawPtrSubscriptNode(inner) or IsCPtrSubscriptNode(inner))
|
||||
return inner_type.startswith('%') and inner_type.endswith('*')
|
||||
@@ -1187,7 +1141,11 @@ class DeclarationGenerator:
|
||||
if annotation is None:
|
||||
return 'i8*'
|
||||
|
||||
RejectTypeUnion(annotation)
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
Line: int = getattr(annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
|
||||
non_struct_types: set[str] = {'list', 'dict', 'tuple', 'set', 'array', 'CArray', 'rawarray'}
|
||||
|
||||
@@ -1318,71 +1276,10 @@ class DeclarationGenerator:
|
||||
sname: str = f'%"{sha1}.{attr_name}"' if sha1 else f'%struct.{attr_name}'
|
||||
return f'{sname}*'
|
||||
return 'i32'
|
||||
elif isinstance(annotation, ast.BinOp):
|
||||
left_type: str = self._get_type_str(annotation.left, embedded=embedded)
|
||||
right_type: str = self._get_type_str(annotation.right, embedded=embedded)
|
||||
if left_type in ('', 'void'):
|
||||
return right_type if right_type not in ('', 'void') else (left_type or right_type)
|
||||
if right_type in ('', 'void'):
|
||||
return left_type
|
||||
# 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] | 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 | 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):
|
||||
return left_type
|
||||
if '*' in left_type:
|
||||
return f'{left_type}*'
|
||||
return f'{left_type}*'
|
||||
# X | CPtr[T](T 为下标段,非裸标记):CPtr 侧贡献自身指针层数 N,
|
||||
# 另一侧外包 N 层(Ptr^N(X));左右两侧写法对称(定义侧 VPC
|
||||
# TypeGenResolve.vp:2604-2609 亦两侧皆判)。必须先于下方
|
||||
# "'*' in left_type → 直接返回左值":否则左值本身已是指针
|
||||
# (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)
|
||||
# CPtr 裸标记在左侧(CPtr | X):与右侧写法(X | CPtr,见上)
|
||||
# 完全对称。缺此分支时左值 i8* 会吞掉右侧的指针层数:
|
||||
# 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):
|
||||
return right_type
|
||||
return f'{right_type}*'
|
||||
if '*' in left_type:
|
||||
return left_type
|
||||
if '*' in right_type:
|
||||
return right_type
|
||||
return left_type
|
||||
elif isinstance(annotation, ast.Subscript):
|
||||
# 指针下标(rawptr[T] / CPtr[T] / 裸名 CPtr[T] / 导入别名 X[T],以及带
|
||||
# 模块前缀书写的 X.CPtr[T])≡ 源码联合写法 `T | CPtr`:与定义端
|
||||
# **同一判据**(SymbolUtils.IsPtrSubscriptNode,别名经本模块的
|
||||
# _from_import_aliases 表解析 X→CPtr)+ 同一层数规则
|
||||
# (_ptr_subscript_type_str:裸类引用吸收一层、其余逐层外包),内层 T
|
||||
# 照常解析(跨模块类由 struct_sha1_map 补 SHA1 前缀)。此前 rawptr[T]
|
||||
# 在此退化成 i8*,CPtr[T] 走的是"embedded + 追加一层"的独立分支:
|
||||
# 非同一规则,且对泛型容器特化多出一层(CPtr[list[X]] 得 list[X]**,
|
||||
# 而 rawptr[list[X]] 得 list[X]*)。
|
||||
# 指针下标(rawptr[T] / CPtr[T] / 裸名 CPtr[T] / 导入别名 X[T]):
|
||||
# 裸类引用吸收一层、其余逐层外包,内层 T 照常解析
|
||||
# (跨模块类由 struct_sha1_map 补 SHA1 前缀)。
|
||||
ValueIsCPtr: bool = (
|
||||
(isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CPtr')
|
||||
or (isinstance(annotation.value, ast.Name) and annotation.value.id == 'CPtr')
|
||||
@@ -1390,6 +1287,18 @@ class DeclarationGenerator:
|
||||
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)
|
||||
MarkerName: str | None = None
|
||||
if isinstance(annotation.value, ast.Name):
|
||||
MarkerName = annotation.value.id
|
||||
elif isinstance(annotation.value, ast.Attribute):
|
||||
MarkerName = annotation.value.attr
|
||||
if MarkerName in ('CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
|
||||
InnerType: str = self._get_type_str(annotation.slice, embedded=embedded)
|
||||
if self._is_bare_class_ref_annotation(annotation.slice, InnerType):
|
||||
return InnerType
|
||||
if InnerType in ('', 'void', 'void*'):
|
||||
return 'i8*'
|
||||
return f'{InnerType}*'
|
||||
# 内建裸名函数指针构造子 callable[...] / Callable[...]:与 Attribute 分支的
|
||||
# Callable[...] 逐点等价(同为 i8*)。缺此分支时落到下方 Name 泛型特化 /
|
||||
# 兜底返回 'i32'(现场 Repl.vp:307 `ReplFragFn: callable[[rawptr], int]`
|
||||
@@ -1544,11 +1453,9 @@ class DeclarationGenerator:
|
||||
return 'i32'
|
||||
|
||||
def _get_bitfield_width(self, annotation: ast.AST) -> int | None:
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
right_width: int | None = self._get_bitfield_width(annotation.right)
|
||||
if right_width is not None:
|
||||
return right_width
|
||||
return self._get_bitfield_width(annotation.left)
|
||||
BitWidth: int | None = getattr(annotation, 'BitWidth', None)
|
||||
if BitWidth:
|
||||
return BitWidth
|
||||
if isinstance(annotation, ast.Call):
|
||||
if isinstance(annotation.func, ast.Attribute) and annotation.func.attr == 'Bit':
|
||||
if annotation.args:
|
||||
|
||||
Reference in new issue
Block a user