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:
TermiNexus committed 2026-10-18 13:35:34 +08:00
1 parent 3269775945
commit 660a15bef8
19 files changed
+1312 -1576

No files matched your search

+58 -151
View File
@@ -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:
+61 -146
View File
@@ -10,8 +10,7 @@ from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
from lib.core import TypeSystem
from lib.core.SymbolUtils import (
IsListAnnotation, ParseListAnnotation, FindStructNameInAnnotationWithContext,
AnnotationContainsName, IsCPtrNode, RequireDefineConstStorable,
IsListAnnotation, ParseListAnnotation, RequireDefineConstStorable,
FindAutoAddrMode,
)
@@ -461,10 +460,12 @@ class AnnAssignHandle(BaseHandle):
Gen.builder.call(append_func, adjusted_append, name=f"append_{VarName}_{i}")
# 10. 创建变量并存储堆指针
# 判断变量类型:list[T] | CPtr → i8*;list[T] → Ptr(StructType)
is_cptr_union: bool = isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr)
# 判断变量类型:解析不出具体基类型的指针(如 CPtr[list[T]] 内层未知)→ i8*;
# 其余 → Ptr(StructType)
_AnnInfo: CTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation)
is_cptr_union: bool = _AnnInfo.IsVoid and _AnnInfo.PtrCount > 0
if is_cptr_union:
# list[T] | CPtr → 变量类型为 i8*
# 变量类型为 i8*
i8_ptr_type: ir.PointerType = ir.PointerType(ir.IntType(8))
var: ir.AllocaInstr = Gen._allocaEntry(i8_ptr_type, name=VarName)
# bitcast heap_ptr (Ptr(StructType)) → i8*
@@ -514,6 +515,11 @@ class AnnAssignHandle(BaseHandle):
def _HandleAnnAssignLlvmInner(self, Node: ast.AnnAssign) -> None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
Line: int = getattr(Node.annotation, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
# 值引用标记(`&T` / `&temp T`)仅用于函数参数位:局部/全局变量注解出现即 fail-fast。
_ref_mode: str | None = FindAutoAddrMode(Node.annotation)
if _ref_mode is not None:
@@ -591,14 +597,12 @@ class AnnAssignHandle(BaseHandle):
_meta_name: str = f"{VarName}__meta__"
_meta_var: ir.AllocaInstr = Gen._allocaEntry(Gen.structs['_str'], name=_meta_name)
Gen.variables[_meta_name] = _meta_var
# 标记指针到 str/bytes 的变量 (BinOp 注解如 str | CPtr)
# 标记指向字符串指针的变量(i8**):
# elem_ptr[0] 应加载/存储 8 字节 (指针), 而非 1 字节 (字符)
# 仅当注解包含 str 或 bytes 时设置(CChar | CPtr 不应设置,它是纯字符指针)
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
if AnnotationContainsName(Node.annotation, 'str') or AnnotationContainsName(Node.annotation, 'bytes'):
Gen.var_ptr_element[VarName] = True
# 同时记录到全局字典,使全局变量在跨函数访问时仍能用 8 字节指针步长
Gen.global_var_ptr_element[VarName] = True
if TypeInfo.IsStr and TypeInfo.PtrCount >= 2:
Gen.var_ptr_element[VarName] = True
# 同时记录到全局字典,使全局变量在跨函数访问时仍能用 8 字节指针步长
Gen.global_var_ptr_element[VarName] = True
parse_result = ParseListAnnotation(Node.annotation)
if parse_result:
elem_type_node: ast.expr = parse_result.elem_type_node
@@ -652,20 +656,17 @@ class AnnAssignHandle(BaseHandle):
return
# list[T] 泛型类注解 + list 字面量值 → 构造 list[T] 对象 + append 序列
# (list[str] = ["a", "b"] 不应走 C 数组路径,而应构造 list[str] 对象)
# 支持两种注解形式:list[T] 和 list[T] | CPtr
# 支持注解形式:list[T] 与 CPtr[list[T]]
list_sub: ast.Subscript | None = None
if (isinstance(Node.annotation, ast.Subscript)
and isinstance(Node.annotation.value, ast.Name)
and Node.annotation.value.id == 'list'):
list_sub = Node.annotation
elif (isinstance(Node.annotation, ast.BinOp)
and isinstance(Node.annotation.op, ast.BitOr)):
for side in (Node.annotation.left, Node.annotation.right):
if (isinstance(side, ast.Subscript)
and isinstance(side.value, ast.Name)
and side.value.id == 'list'):
list_sub = side
break
elif (isinstance(Node.annotation, ast.Subscript)
and isinstance(Node.annotation.slice, ast.Subscript)
and isinstance(Node.annotation.slice.value, ast.Name)
and Node.annotation.slice.value.id == 'list'):
list_sub = Node.annotation.slice
if (list_sub is not None
and not isinstance(list_sub.slice, ast.Tuple)
and Node.value is not None
@@ -674,27 +675,7 @@ class AnnAssignHandle(BaseHandle):
and 'list' in self.Trans.ClassHandler._generic_class_templates):
self._HandleGenericListLiteralAssign(VarName, Node, Gen, list_sub)
return
# Only fall back to the left operand when the union neither resolved a base
# type nor accumulated multi-level pointers. A pointer-marker based union
# (`CPtr*` = `CPtr | CPtr` => CVoid/2) is already a fully resolved
# multi-level pointer; falling back to its left operand (`CPtr` => 1 layer)
# used to silently degrade it to i8*. Keep PtrCount > 1 untouched.
if (TypeInfo.IsVoid and TypeInfo.PtrCount <= 1
and isinstance(Node.annotation, ast.BinOp)):
found: str | None = FindStructNameInAnnotationWithContext(
Node.annotation, self.Trans, Gen)
if found:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = TypeSystem.CStruct(name=found)
TypeInfo.PtrCount = 1
IsPtr = True
elif isinstance(Node.annotation.left, ast.Attribute):
AttrTypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation.left)
if AttrTypeInfo and AttrTypeInfo.BaseType:
TypeInfo = AttrTypeInfo
TypeInfo.PtrCount = max(TypeInfo.PtrCount, 1)
IsPtr = True
# 对于局部变量声明 s: TestStruct(不带 | CPtr),应为栈上结构体而非指针
# 对于局部变量声明 s: TestStruct,应为栈上结构体而非指针
# GetCTypeInfo 默认设置 PtrCount=1,但纯结构体名注解应为值类型
if (isinstance(Node.annotation, ast.Name)
and Node.annotation.id in Gen.structs
@@ -724,36 +705,13 @@ class AnnAssignHandle(BaseHandle):
if isinstance(VarType, ir.VoidType):
VarType = ir.IntType(32)
IsUnsigned: bool = TypeInfo.IsUInt
# 修复 3: BinOp 注解(如 ast.Arguments | CPtr)的 var_struct_class 设置
# TypeInfo.Name 由 _HandleSubscript 设置(特化名如 list[sha1.ASTptr])或
# GetCTypeInfo 设置(普通结构体名),经 _MergeCTypeInfoInto 传播后保留。
# 此处确保 BinOp 注解的变量也能被 _get_var_class 识别,避免方法调用分派
# fallthrough 到 char pointer fallback 错误匹配其他类(如 AST.__len__)。
# 使用 not in 条件,不覆盖后续 L337-339/L396-398 对 ast.Name 注解的精确设置。
# 结构体注解的 var_struct_class 设置:TypeInfo.Name 由 _HandleSubscript
# 设置(泛型特化名)或 GetCTypeInfo 设置(普通结构体名)。
# 使用 not in 条件,不覆盖后续对 ast.Name 注解的精确设置。
if TypeInfo.IsStruct and TypeInfo.Name and TypeInfo.Name in Gen.structs:
if VarName not in Gen.var_struct_class:
Gen.var_struct_class[VarName] = TypeInfo.Name
Gen.global_struct_class[VarName] = TypeInfo.Name
# 联合指针注解(X | CPtr)短名回退:resolver 对模块限定 struct
# 段(如 llvmlite.Value)无法精确 in Gen.structs(键可能是 'Value'
# 或带 sha1 前缀),Name 常退化为指针别名 'rawptr'(被注册成 opaque
# struct)→ 变量 var_struct_class 登记为 rawptr → 字段访问
# "属性 'Next' 在类 'rawptr' 中找不到"(FuncGenMixin.vp L307)。
# FindStructNameInAnnotation 以 attr/短名命中,找回真实类名。
if (isinstance(Node.annotation, ast.BinOp)
and isinstance(Node.annotation.op, ast.BitOr)):
_union_struct_name2: str | None = FindStructNameInAnnotationWithContext(
Node.annotation, self.Trans, Gen)
# resolver 对模块限定 struct 联合(llvmlite.Value | CPtr)常给出
# 指针占位名(如 '{sha1}.rawptr')且该占位恰好注册在 Gen.structs,
# 使上方 TypeInfo.Name in Gen.structs 通过并登记错误类名 → 字段
# 访问 "属性 'Next' 在类 'rawptr' 中找不到"。凡短名命中真实类
# (attr 精确 in structs),一律覆盖为真实类名(Value)。
if _union_struct_name2 and _union_struct_name2 in Gen.structs:
if Gen.var_struct_class.get(VarName) != _union_struct_name2:
Gen.var_struct_class[VarName] = _union_struct_name2
if getattr(Gen, 'global_struct_class', None) is not None:
Gen.global_struct_class[VarName] = _union_struct_name2
# Subscript rawptr[X] / CPtr[X] 注解的本地结构指针变量(如
# includes/ast/parser.vp _fix_store_ctx 里 `tp: rawptr[Tuple] =
# (rawptr[Tuple])(node)`,随后 `tp_elts = tp.elts`):TypeMerge 的
@@ -771,7 +729,7 @@ class AnnAssignHandle(BaseHandle):
_rst_nm = _rst_v.id
elif isinstance(_rst_v, ast.Attribute) and isinstance(_rst_v.value, ast.Name):
_rst_nm = f'{_rst_v.value.id}.{_rst_v.attr}'
if _rst_nm in ('rawptr', 'CPtr'):
if _rst_nm in ('rawptr', 'CPtr', 'CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
_rst_sub = Node.annotation
if _rst_sub is not None:
_rst_sl: ast.AST = _rst_sub.slice
@@ -804,31 +762,16 @@ class AnnAssignHandle(BaseHandle):
Gen.var_struct_class[VarName] = _rst_tk
if getattr(Gen, 'global_struct_class', None) is not None:
Gen.global_struct_class[VarName] = _rst_tk
# 检测指针到指针缓冲区变量:注解为 StructName | CPtr,且赋值来自 CPtr(...) 调用。
# 这种变量(如 list[T].__getitem__ 中的 elem_ptr: T | CPtr = CPtr(...))
# 实际指向存储结构体指针的缓冲区(T=AST|CPtr 时特化为 AST*,缓冲区存 AST* 数组)。
# [index] 应 bitcast 为 AST** 后 GEP 指针数组再 load,而非 GEP 结构体数组。
# 泛型特化将 T|CPtr 降级为 StructName|CPtr(丢失一层指针),故通过赋值来源区分:
# elem_ptr 的值是 CPtr(buf + idx*elem_size)(原始指针运算,缓冲区内容未知),
# pts 的值是 (Point|CPtr)(...)(类型转换,明确指向 Point 结构体)。
# 检测指针到指针缓冲区变量:注解为指针下标(如 CPtr[T]),且赋值来自
# CPtr(...) 调用。这种变量实际指向存储结构体指针的缓冲区,
# [index] 应 bitcast 为 T** 后 GEP 指针数组再 load。
_is_cptr_assign: bool = (
isinstance(Node.value, ast.Call)
and isinstance(Node.value.func, ast.Name)
and Node.value.func.id == 'CPtr'
)
_is_struct_ptr_union: bool = (
isinstance(Node.annotation, ast.BinOp)
and isinstance(Node.annotation.op, ast.BitOr)
and ((IsCPtrNode(Node.annotation.left)
and isinstance(Node.annotation.right, ast.Name)
and (Node.annotation.right.id in Gen.structs
or _IsGenericTpName(Node.annotation.right.id)))
or (IsCPtrNode(Node.annotation.right)
and isinstance(Node.annotation.left, ast.Name)
and (Node.annotation.left.id in Gen.structs
or _IsGenericTpName(Node.annotation.left.id))))
)
if _is_cptr_assign and _is_struct_ptr_union:
_is_struct_ptr_annotation: bool = _rst_sub is not None and TypeInfo.IsPtr
if _is_cptr_assign and _is_struct_ptr_annotation:
Gen.var_ptr_element[VarName] = True
Gen.global_var_ptr_element[VarName] = True
if VarName in Gen._reg_values:
@@ -959,20 +902,23 @@ class AnnAssignHandle(BaseHandle):
Gen.global_struct_class[VarName] = Node.annotation.id
Gen._record_var_signedness(VarName, IsUnsigned)
return
# 方向判定用:取注解一侧的泛型基名(`Base[...]` 或 `Base[...] | CPtr`
# 方向判定用:取注解中的泛型基名(`Base[...]` 或 `CPtr[Base[...]]`
# 形态中的 Base)。此判据**不依赖泛型模板注册表**(list/dict 等内建
# 容器可能未登记),只做结构性识别;仅 Name 形态可识别,属性链
# (如 CPtr[...])不参与。
# 容器可能未登记),只做结构性识别;仅 Name 形态可识别。
_ann_gen_base: str | None = None
_ann_sub_side: ast.expr | None = None
if isinstance(Node.annotation, ast.Subscript):
_ann_sub_side = Node.annotation
elif (isinstance(Node.annotation, ast.BinOp)
and isinstance(Node.annotation.op, ast.BitOr)):
for _ann_side in (Node.annotation.left, Node.annotation.right):
if isinstance(_ann_side, ast.Subscript):
_ann_sub_side = _ann_side
break
_ann_side: ast.expr = Node.annotation
_ann_probe: ast.expr = _ann_side.value
while isinstance(_ann_probe, ast.Subscript):
_ann_probe = _ann_probe.value
_ann_probe_nm: str | None = (
_ann_probe.id if isinstance(_ann_probe, ast.Name)
else (_ann_probe.attr if isinstance(_ann_probe, ast.Attribute) else None))
if (_ann_probe_nm in ('CPtr', 'rawptr', 'CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr')
and isinstance(_ann_side.slice, ast.Subscript)):
_ann_side = _ann_side.slice
_ann_sub_side = _ann_side
if _ann_sub_side is not None:
_ann_base_v: ast.expr = _ann_sub_side.value
# 兼容嵌套下标链(Base[...][...]):逐层剥到最内层 Name
@@ -1010,27 +956,24 @@ class AnnAssignHandle(BaseHandle):
if CN == 'rawptr' or CN.endswith('.rawptr') or CN.startswith('rawptr['):
continue
if pointee is ST or pointee == ST:
# 若注解是泛型特化(如 ndarray[CDouble] | CPtr),
# 若注解是泛型特化(如 CPtr[ndarray[CDouble]]),
# 构造正确的特化名(如 ndarray[double]),而非用 opaque 基础名
resolved_cn: str = CN
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr) and '[' not in CN:
for side in (Node.annotation.left, Node.annotation.right):
if isinstance(side, ast.Subscript):
bn: ast.expr = side.value
bnm: str | None = bn.id if isinstance(bn, ast.Name) else (bn.attr if isinstance(bn, ast.Attribute) else None)
# 归一化比较:CN 可能带 16 位 sha1 模块前缀
# (如 'e94ef9e139461915.list'),注解侧裸名为
# 'list',直接与 CN 比较恒不等 ⇒ 特化名恢复失败
# ⇒ 写入裸泛型基名 ⇒ .get() 按错误元素类型
# 分派崩溃。用 _cn_short(已去前缀)比较。
if bnm and bnm == _cn_short:
sn2: ast.AST = side.slice
if hasattr(ast, 'Index') and isinstance(sn2, ast.Index):
sn2 = sn2.value
r2: tuple[str, str] | None = self.Trans.ExprCallHandle._resolve_generic_slice_type(sn2)
if r2:
resolved_cn = f'{CN}[{r2[0]}]'
break
if _ann_sub_side is not None and '[' not in CN:
bn: ast.expr = _ann_sub_side.value
bnm: str | None = bn.id if isinstance(bn, ast.Name) else (bn.attr if isinstance(bn, ast.Attribute) else None)
# 归一化比较:CN 可能带 16 位 sha1 模块前缀
# (如 'e94ef9e139461915.list'),注解侧裸名为
# 'list',直接与 CN 比较恒不等 ⇒ 特化名恢复失败
# ⇒ 写入裸泛型基名 ⇒ .get() 按错误元素类型
# 分派崩溃。用 _cn_short(已去前缀)比较。
if bnm and bnm == _cn_short:
sn2: ast.AST = _ann_sub_side.slice
if hasattr(ast, 'Index') and isinstance(sn2, ast.Index):
sn2 = sn2.value
r2: tuple[str, str] | None = self.Trans.ExprCallHandle._resolve_generic_slice_type(sn2)
if r2:
resolved_cn = f'{CN}[{r2[0]}]'
if resolved_cn != Gen.var_struct_class.get(VarName):
Gen.var_struct_class[VarName] = resolved_cn
Gen.global_struct_class[VarName] = resolved_cn
@@ -1144,34 +1087,6 @@ class AnnAssignHandle(BaseHandle):
elif isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width in (16, 32, 64):
Gen.local_var_byteorders[VarName] = 'big'
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
found_struct: str | None = FindStructNameInAnnotationWithContext(
Node.annotation, self.Trans, Gen)
# 若 FindStructNameInAnnotation 仅返回裸模板名(如 'ndarray'),但注解中
# 含泛型特化(如 numpy.ndarray[CDouble]),用 LLVM 类型名构造特化名
# (如 'ndarray[double]')。main.py 的 Gen.structs 可能只有 opaque 'ndarray',
# 但 numpy 模块已特化 ndarray[double],方法调用通过 sha1 前缀查找。
if found_struct and '[' not in found_struct:
for side in (Node.annotation.left, Node.annotation.right):
if isinstance(side, ast.Subscript):
base_node: ast.expr = side.value
base_nm: str | None = None
if isinstance(base_node, ast.Name):
base_nm = base_node.id
elif isinstance(base_node, ast.Attribute):
base_nm = base_node.attr
if base_nm and base_nm == found_struct:
slice_node: ast.AST = side.slice
if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index):
slice_node = slice_node.value
result: tuple[str, str] | None = self.Trans.ExprCallHandle._resolve_generic_slice_type(slice_node)
if result:
found_struct = f'{base_nm}[{result[0]}]'
break
if found_struct:
Gen.var_struct_class[VarName] = found_struct
Gen.global_struct_class[VarName] = found_struct
if InitValue and isinstance(InitValue.type, ir.PointerType):
pointee: ir.Type = InitValue.type.pointee
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
+49 -16
View File
@@ -11,7 +11,7 @@ from lib.core.ConstEvaluator import ConstEvaluator, EvalContext
from lib.constants.config import mode as _config_mode
from lib.core import TypeSystem
from lib.core.TypeSystem import CTypeRegistry
from lib.core.SymbolUtils import ParseListAnnotation, AnnotationContainsName
from lib.core.SymbolUtils import ParseListAnnotation
class AssignHandle(BaseHandle):
def __init__(self, translator: "Translator") -> None:
@@ -2029,11 +2029,10 @@ class AssignHandle(BaseHandle):
Gen.global_struct_class[VarName] = TypeInfo.Name
return
GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName)
# 全局变量指针元素标志:bytes|CPtr 或 str|CPtr 注解的变量,
# 全局变量指针元素标志:指向字符串指针(i8**)的变量,
# 使 var[index] 使用 8 字节指针步长(而非 1 字节字符步长)
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
if AnnotationContainsName(Node.annotation, 'str') or AnnotationContainsName(Node.annotation, 'bytes'):
Gen.global_var_ptr_element[VarName] = True
if TypeInfo is not None and TypeInfo.IsStr and TypeInfo.PtrCount >= 2:
Gen.global_var_ptr_element[VarName] = True
if Node.value:
if isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str) and isinstance(VarType, ir.PointerType):
# 字符串字面量全局:初始化器 = 指向 @{VarName}_str 常量数组首元素
@@ -2117,19 +2116,12 @@ class AssignHandle(BaseHandle):
def _ScanGlobalTAttr(self, node: ast.AST | None, want_name: str) -> ast.AST | None:
"""在全局变量注解中查找 attr.<want_name> 节点,命中返回该节点。
注解形态是 BinOp(BitOr) 左深链(`A | B | C` = BinOp(BinOp(A,B),C)),
递归左右子节点。命中节点形态:Call(attr.aligned(16))或
Attribute(attr.weak)。同时兼容包装写法
`T | Attribute(attr.section("..."))`(解包参考 ViperC
命中节点形态:Call(attr.aligned(16))或 Attribute(attr.weak)。
同时兼容包装写法 `Attribute(attr.section("..."))`(解包参考 ViperC
ClassGenBase._class_has_tattr,.vp:375-389)。
"""
if node is None:
return None
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
hit_left: ast.AST | None = self._ScanGlobalTAttr(node.left, want_name)
if hit_left is not None:
return hit_left
return self._ScanGlobalTAttr(node.right, want_name)
# 包装写法:Attribute(attr.xxx / attr.xxx(...)) → 拆 args 再扫
# (与 HandlesFunctions.py 装饰器侧同一判据:func.id == 'Attribute')
if (isinstance(node, ast.Call) and isinstance(node.func, ast.Name)
@@ -2188,6 +2180,19 @@ class AssignHandle(BaseHandle):
f"模块级变量 '{VarName}' 的 {Msg}(位置 {loc})", src_file, lineno, '')
sys.exit(1)
@staticmethod
def _ParseAttrText(Raw: object) -> tuple[str, str | None]:
"""解析 Attributes 字段中的单条文本(如 'section(".x")' / 'aligned(16)')。"""
text: str = str(Raw).strip()
name, sep, rest = text.partition('(')
name = name.strip()
if not sep:
return name, None
rest = rest.rstrip(')').strip()
if len(rest) >= 2 and rest[0] == rest[-1] and rest[0] in ('"', "'"):
rest = rest[1:-1]
return name, rest
def _ExtractGlobalAttrs(self, Node: ast.AnnAssign, Gen: "Translator.LlvmGen") -> dict[str, Any]:
"""从模块级全局注解提取 attr.section/aligned/weak。
@@ -2198,6 +2203,28 @@ class AssignHandle(BaseHandle):
Attrs: dict[str, Any] = {'section': None, 'align': 0, 'weak': False}
Ann: ast.AST = Node.annotation
VarName: str = Node.target.id if isinstance(Node.target, ast.Name) else '<anonymous>'
RawAttrs: list[object] = list(getattr(Node, 'Attributes', None) or ()) + list(
getattr(Ann, 'Attributes', None) or ())
for RawAttr in RawAttrs:
attr_name, attr_arg = self._ParseAttrText(RawAttr)
if attr_name == 'section':
if not attr_arg:
self._RaiseGlobalAttrError(
"attr.section(...) 段名缺失或为空(空段名会生成非法的 section \"\")",
Ann, Gen, VarName)
Attrs['section'] = attr_arg
elif attr_name == 'aligned':
align_val: int | None = None
try:
align_val = int(attr_arg) if attr_arg else None
except ValueError:
align_val = None
if align_val is None or align_val <= 0:
self._RaiseGlobalAttrError(
"attr.aligned(N) 需要正整数字面量 N", Ann, Gen, VarName)
Attrs['align'] = align_val
elif attr_name == 'weak':
Attrs['weak'] = True
sec_node: ast.AST | None = self._ScanGlobalTAttr(Ann, 'section')
if sec_node is not None:
sec_val: str | None = self._TAttrArgStr(sec_node)
@@ -2372,11 +2399,17 @@ class AssignHandle(BaseHandle):
return None
def _IsTypedefAnnotation(self, annotation: ast.expr) -> bool:
Markers: tuple[str, ...] = getattr(annotation, 'Markers', None) or ()
if 'typedef' in Markers or 'define' in Markers:
return True
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],修饰符请用关键字")
if isinstance(annotation, ast.Attribute):
if annotation.attr in ('CTypedef', 'CDefine'):
return True
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
return self._IsTypedefAnnotation(annotation.left) or self._IsTypedefAnnotation(annotation.right)
if isinstance(annotation, ast.Subscript):
return self._IsTypedefAnnotation(annotation.value)
return False
+6 -10
View File
@@ -1043,11 +1043,9 @@ class BaseHandle:
# 本方法覆盖函数参数/返回注解与类字段(CollectAnnAssignMember 亦经此)。
self._CheckFixedArrayKeyword(annotation)
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
merger: Any = getattr(self.Trans, 'TypeMergeHandler', None)
if merger:
info: CTypeInfo | None = merger.MergeTypes(annotation)
if info is not None and isinstance(info, CTypeInfo):
return info
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {getattr(annotation, 'lineno', 0)} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
if IsPtrSubscriptNode(annotation, self.Trans.SymbolTable):
merger = getattr(self.Trans, 'TypeMergeHandler', None)
if merger:
@@ -1146,11 +1144,9 @@ class BaseHandle:
改走 TypeMerge 泛型识别路径,其余保持 ResolveAnnotationType 语义。
"""
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
merger: Any = getattr(self.Trans, 'TypeMergeHandler', None)
if merger:
info: CTypeInfo | None = merger.MergeTypes(annotation)
if info is not None and isinstance(info, CTypeInfo):
return info
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {getattr(annotation, 'lineno', 0)} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
# 指针下标参数注解(rawptr[T] / CPtr[T] / 裸名 CPtr[T],含
# rawptr[list[X]] 等容器:_SubscriptHitsGenericTemplate 也命中,但统一交
# ResolveAnnotationType 处理更简单——它已把指针下标路由到 TypeMerge)。
+2 -4
View File
@@ -13,7 +13,7 @@ from lib.constants.config import mode as _config_mode
from lib.core import TypeSystem
from lib.core.TypeSystem import CTypeRegistry
from lib.core.SymbolUtils import (
ExtractTypeNameFromBinOp, IsPtrSubscriptNode, DesugarPtrSubscriptToUnion,
ExtractTypeNameFromBinOp, IsPtrSubscriptNode,
ResolveTypeArgStr, GenericArgRawName,
ClassHasFuncLevelCVTable, IsVtableSlotMethod)
from lib.core.Handles.HandlesExpr import DefineUseWidthFromLLVMType
@@ -2066,7 +2066,7 @@ class ExprCallHandle(BaseHandle):
type_info = None
MergeException = None
try:
type_info = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.func)
type_info = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.GetCTypeInfo(Node.func)
except Exception as _e:
MergeException = _e
if _config_mode == "strict":
@@ -4233,8 +4233,6 @@ class ExprCallHandle(BaseHandle):
会拼出 'rawptr[ast.AST]' 实参串(内层未混淆)→ 与 list[ast.AST | CPtr]
的 '<sha1>.AST*' 分裂成两个特化名(结构体/方法声明/调用点三端不一致)。
"""
if IsPtrSubscriptNode(sn, self.Trans.SymbolTable):
sn = DesugarPtrSubscriptToUnion(sn, self.Trans.SymbolTable)
if isinstance(sn, ast.Name):
# type_arg 走唯一规则源(命中注册类加 SHA1 前缀,裸名与
# `list[X]`/`rawptr[X]` 内层收敛到同一名字);
+65 -166
View File
@@ -8,9 +8,7 @@ import copy
import traceback
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
from lib.core.SymbolUtils import (
FindStructNameInAnnotationWithContext, AnnotationContainsName,
IsPtrSubscriptNode, DesugarPtrSubscriptToUnion, FindAutoAddrMode)
from lib.core.SymbolUtils import FindAutoAddrMode
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
from lib.core import TypeSystem
@@ -53,36 +51,24 @@ def _RejectRefReturnAnnotation(node: ast.AST) -> None:
def _IsVoidOrDeclAnnotation(Annot: ast.AST) -> bool:
"""判断函数返回注解是否为 void 或 extern/export 声明型辅助符号。
void:None / CVoid,含 `|` 联合形式(注解中 `|` 表示 and),
如 `-> CVoid | CExport`(sprintf 先例)→ 掉出末尾 ret void 合法。
void:None / CVoid。
声明型辅助符号:State(extern)/ CExport(export)/ CExtern——
此类函数返回注解被改写为 `<原类型> | 辅助符号` 且 body 为空(extern 声明),
掉出末尾是正常形态,必须豁免 fail-fast。
此类函数 body 为空(extern 声明),掉出末尾是正常形态,必须豁免 fail-fast。
"""
if isinstance(Annot, ast.BinOp) and isinstance(Annot.op, ast.BitOr):
Line: int = getattr(Annot, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
if isinstance(Annot, ast.Constant):
return Annot.value is None
if isinstance(Annot, ast.Attribute):
return getattr(Annot, 'attr', '') in ('CVoid', 'State', 'CExport', 'CExtern')
if isinstance(Annot, ast.BinOp) and isinstance(Annot.op, ast.BitOr):
return _IsVoidOrDeclAnnotation(Annot.left) or _IsVoidOrDeclAnnotation(Annot.right)
return False
def _IsVoidOrDeclAnnotation(Annot: ast.AST) -> bool:
"""判断函数返回注解是否为 void 或 extern/export 声明型辅助符号。
void:None / CVoid,含 `|` 联合形式(注解中 `|` 表示 and),
如 `-> CVoid | CExport`(sprintf 先例)→ 掉出末尾 ret void 合法。
声明型辅助符号:State(extern)/ CExport(export)/ CExtern——
此类函数返回注解被改写为 `<原类型> | 辅助符号` 且 body 为空(extern 声明),
掉出末尾是正常形态,必须豁免 fail-fast。
"""
if isinstance(Annot, ast.Constant):
return Annot.value is None
if isinstance(Annot, ast.Attribute):
return getattr(Annot, 'attr', '') in ('CVoid', 'State', 'CExport', 'CExtern')
if isinstance(Annot, ast.BinOp) and isinstance(Annot.op, ast.BitOr):
return _IsVoidOrDeclAnnotation(Annot.left) or _IsVoidOrDeclAnnotation(Annot.right)
if isinstance(Annot, ast.Name):
Markers: tuple[str, ...] = getattr(Annot, 'Markers', None) or ()
if 'state' in Markers or 'export' in Markers or 'extern' in Markers:
return True
return Annot.id in ('CVoid', 'State', 'CExport', 'CExtern')
return False
@@ -310,13 +296,14 @@ class FunctionHandle(BaseHandle):
def _ExtractLLVMAttrs(self, node: ast.AST) -> list[str]:
attrs: list[str] = []
if isinstance(node, ast.BinOp):
attrs.extend(self._ExtractLLVMAttrs(node.left))
attrs.extend(self._ExtractLLVMAttrs(node.right))
elif isinstance(node, ast.Attribute):
attr_name: str | None = self._GetAttrLLVMName(node)
if attr_name:
for raw_attr in getattr(node, 'Attributes', None) or ():
attr_name: str = str(raw_attr).split('(', 1)[0].strip()
if attr_name in self._LLVM_ATTR_NAMES:
attrs.append(attr_name)
if isinstance(node, ast.Attribute):
resolved: str | None = self._GetAttrLLVMName(node)
if resolved:
attrs.append(resolved)
return attrs
def _GetAttrLLVMName(self, node: ast.AST) -> str | None:
@@ -535,44 +522,10 @@ class FunctionHandle(BaseHandle):
else:
try:
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
ReturnTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns)
if not isinstance(ReturnTypeInfo, CTypeInfo):
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
if ((ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState)
or (ReturnTypeInfo.PtrCount >= 2 and ReturnTypeInfo.BaseType is None)):
def _FindNonVoidCTypeInfo(node: ast.AST) -> Any:
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
results: list[Any] = []
for child in [node.left, node.right]:
r: Any = _FindNonVoidCTypeInfo(child)
if r and not r.IsVoid:
results.append(r)
for r in results:
if not r.IsPtr and not r.IsStruct:
return r
return results[0] if results else None
try:
SideInfo: Any = CTypeInfo.FromNode(node, self.Trans.SymbolTable)
if SideInfo:
return SideInfo
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
return None
found: Any = _FindNonVoidCTypeInfo(Node.returns)
if found and not found.IsVoid:
ReturnTypeInfo = found
if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CInt()
# define 宏函数(返回注解含 CDefine,如 `int | CDefine`):
# 标记为编译期内联宏(alwaysinline),对齐裸 `-> CDefine` 路径
# (合并路径丢失 IsDefine 时仍能命中)
if AnnotationContainsName(Node.returns, 'CDefine'):
if not hasattr(self, '_cdefine_funcs'):
self._cdefine_funcs = set()
self._cdefine_funcs.add(FuncName)
Line: int = getattr(Node.returns, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
else:
is_str_type: bool = False
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
@@ -648,6 +601,8 @@ class FunctionHandle(BaseHandle):
if (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CInt()
except TypeError:
raise
except Exception: # 回退:设置默认返回类型为 CInt
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CInt()
@@ -834,12 +789,10 @@ class FunctionHandle(BaseHandle):
replacement: str = type_map[node.id]
return self._make_replacement_node(replacement)
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
if isinstance(node.left, ast.Name) and node.left.id in type_map:
replacement: str = type_map[node.left.id]
node.left = self._make_replacement_node(replacement)
return node
node.left = self._replace_type_in_annotation(node.left, type_map, cptr_params)
node.right = self._replace_type_in_annotation(node.right, type_map, cptr_params)
Line: int = getattr(node, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
elif isinstance(node, ast.Attribute):
if hasattr(node, 'attr') and node.attr in type_map:
replacement: str = type_map[node.attr]
@@ -884,10 +837,10 @@ class FunctionHandle(BaseHandle):
base_node = self._make_name_node(BaseName)
node: ast.AST = base_node
for _ in range(StarCount):
node = ast.BinOp(
left=node,
op=ast.BitOr(),
right=ast.Name(id='CPtr', ctx=ast.Load()),
node = ast.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=node,
ctx=ast.Load(),
)
return node
if replacement.endswith('ptr'):
@@ -899,10 +852,10 @@ class FunctionHandle(BaseHandle):
levels += 1
node: ast.AST = self._make_name_node(base)
for _ in range(levels):
node = ast.BinOp(
left=node,
op=ast.BitOr(),
right=ast.Name(id='CPtr', ctx=ast.Load()),
node = ast.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=node,
ctx=ast.Load(),
)
return node
if '[' in replacement:
@@ -914,8 +867,6 @@ class FunctionHandle(BaseHandle):
if not isinstance(SubNode, ast.Subscript):
SubNode = self._parse_subscript_manually(replacement)
if isinstance(SubNode, ast.Subscript):
if IsPtrSubscriptNode(SubNode, self.Trans.SymbolTable):
return DesugarPtrSubscriptToUnion(SubNode, self.Trans.SymbolTable)
return SubNode
return self._make_name_node(replacement)
@@ -1051,10 +1002,10 @@ class FunctionHandle(BaseHandle):
# 需替换为 BinOp(AST | CPtr),使 __sizeof__ 等处理器能正确识别
# 指针语义并直接返回 8,避免触发 struct 加载和重入编译
if cptr_params and node.func.value.id in cptr_params:
node.func.value = ast.BinOp(
left=self._make_name_node(replacement),
op=ast.BitOr(),
right=ast.Name(id='CPtr', ctx=ast.Load())
node.func.value = ast.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=self._make_name_node(replacement),
ctx=ast.Load()
)
else:
node.func.value = self._make_name_node(replacement)
@@ -1066,10 +1017,10 @@ class FunctionHandle(BaseHandle):
if isinstance(node.value, ast.Name) and node.value.id in type_map:
replacement: str = type_map[node.value.id]
if cptr_params and node.value.id in cptr_params:
node.value = ast.BinOp(
left=self._make_name_node(replacement),
op=ast.BitOr(),
right=ast.Name(id='CPtr', ctx=ast.Load())
node.value = ast.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=self._make_name_node(replacement),
ctx=ast.Load()
)
else:
node.value = ast.Name(id=replacement, ctx=ast.Load())
@@ -1134,11 +1085,7 @@ class FunctionHandle(BaseHandle):
has_cexport: bool = False
if Node.returns:
try:
RetTypeInfo: Any = None
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
RetTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Node.returns)
else:
RetTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
RetTypeInfo: Any = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, TypeSystem.CExport):
has_cexport = True
except Exception as _e:
@@ -1495,43 +1442,10 @@ class FunctionHandle(BaseHandle):
else:
try:
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
ReturnTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns)
if not isinstance(ReturnTypeInfo, CTypeInfo):
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
if ((ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState)
or (ReturnTypeInfo.PtrCount >= 2 and ReturnTypeInfo.BaseType is None)):
def _FindNonVoidCTypeInfo(node):
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
results = []
for child in [node.left, node.right]:
r = _FindNonVoidCTypeInfo(child)
if r and not r.IsVoid:
results.append(r)
for r in results:
if not r.IsPtr and not r.IsStruct:
return r
return results[0] if results else None
try:
SideInfo = CTypeInfo.FromNode(node, self.Trans.SymbolTable)
if SideInfo:
return SideInfo
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
return None
found = _FindNonVoidCTypeInfo(Node.returns)
if found and not found.IsVoid:
ReturnTypeInfo = found
if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CInt()
# define 宏函数(返回注解含 CDefine,如 `int | CDefine`):
# 标记为编译期内联宏(alwaysinline),对齐裸 `-> CDefine` 路径
if AnnotationContainsName(Node.returns, 'CDefine'):
if not hasattr(self, '_cdefine_funcs'):
self._cdefine_funcs = set()
self._cdefine_funcs.add(FuncName)
Line: int = getattr(Node.returns, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
else:
is_str_type = False
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
@@ -1602,6 +1516,8 @@ class FunctionHandle(BaseHandle):
if (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CInt()
except TypeError:
raise
except Exception: # 回退:设置默认返回类型为 CInt
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CInt()
@@ -1977,31 +1893,7 @@ class FunctionHandle(BaseHandle):
var = Gen._allocaEntry(param.type, name=param_name)
Gen._store(param, var)
Gen.variables[param_name] = var
# 为联合类型注解(如 Function | CPtr)的参数设置 var_struct_class,
# 确保编译器能正确生成 GEP 访问结构体成员(如 func.Blocks、func.Params)
for i, arg in enumerate(Node.args.args):
if arg.annotation and isinstance(arg.annotation, ast.BinOp) and isinstance(arg.annotation.op, ast.BitOr):
param_name: str = ParamNames[i] if i < len(ParamNames) else arg.arg
if param_name in Gen.variables:
# 若 L1650-1657 已根据 param.type.pointee 匹配到正确的特化名
# (如 ndarray[double]),不覆盖:FindStructNameInAnnotation 对
# 泛型注解 ndarray[CDouble] 会构造 ndarray[CDouble](与实际
# ndarray[double] 不匹配),回退到裸模板类名 ndarray(opaque),
# 导致方法调用查找 ndarray.sum 而非 ndarray[double].sum。
if param_name in Gen.var_struct_class:
_existing_ps: str = Gen.var_struct_class[param_name]
# 指针占位名(rawptr / {sha1}.rawptr / rawptr[...])是模块限定
# struct 联合(llvmlite.Function | CPtr)被 resolver 退化
# 的产物,必须允许 FindStructNameInAnnotation 短名修正
# (否则 func.IsVarArg → "属性在类 'rawptr' 中找不到")。
if not (_existing_ps == 'rawptr' or '.rawptr' in _existing_ps
or _existing_ps.startswith('rawptr[')):
continue
found_struct: str | None = FindStructNameInAnnotationWithContext(
arg.annotation, self.Trans, Gen)
if found_struct:
Gen.var_struct_class[param_name] = found_struct
# 普通类注解形参(非 BinOp 联合):rawptr[X] / CPtr[X] / X / X
# 类注释形参:rawptr[X] / CPtr[X] / X
# 一律按"声明类"登记 var_struct_class。避免按 param.type.pointee 匹配
# 到泛型父特化(如 class Function(GSListNode[Function]) 的形参 func 被
# 登记成 GSListNode[Function],其 struct 仅含 Next → func.Blocks 访问
@@ -2011,7 +1903,10 @@ class FunctionHandle(BaseHandle):
if arg.annotation is None:
continue
if isinstance(arg.annotation, ast.BinOp) and isinstance(arg.annotation.op, ast.BitOr):
continue # 联合注解由上方循环处理
Line: int = getattr(arg.annotation, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
param_name = ParamNames[i] if i < len(ParamNames) else arg.arg
if param_name not in Gen.variables:
continue
@@ -2024,8 +1919,10 @@ class FunctionHandle(BaseHandle):
elif isinstance(ann, ast.Subscript):
subv = ann.value
subname = getattr(subv, 'id', None) or getattr(subv, 'attr', '')
if subname in ('rawptr', 'CPtr', 'Ptr'):
if subname in ('rawptr', 'CPtr', 'Ptr', 'CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
slc = ann.slice
while isinstance(slc, ast.Subscript):
slc = slc.value
if isinstance(slc, ast.Name):
target = slc.id
elif isinstance(slc, ast.Attribute):
@@ -2184,9 +2081,11 @@ class FunctionHandle(BaseHandle):
_is_ret_or_ctrl_tail: bool = isinstance(_last_stmt, (
ast.Return, ast.If, ast.Match, ast.While, ast.For, ast.Try, ast.With))
if Node.returns is not None and not _is_ret_or_ctrl_tail:
# void(None / CVoid,含 | 联合)/ extern|export 声明型辅助符号
# void(None / CVoid)/ extern|export 声明型辅助符号
# (State / CExport / CExtern)→ 掉出合法,不 fail-fast
if not _IsVoidOrDeclAnnotation(Node.returns):
_DeclMarkers: tuple[str, ...] = getattr(Node, 'Markers', None) or ()
_IsDecl: bool = any(m in ('state', 'export', 'extern') for m in _DeclMarkers)
if not _IsDecl and not _IsVoidOrDeclAnnotation(Node.returns):
raise Exception(
f"函数 {Node.name} 声明了返回类型但函数体可能掉出末尾(缺少 return 语句);"
f"普通语句掉出末尾 + 有返回注解属于定义缺陷,请补显式 return")
+1 -1
View File
@@ -1404,7 +1404,7 @@ class ImportHandle(BaseHandle):
if Node.value:
ValueTypeInfo = None
if isinstance(Node.value, ast.BinOp) and isinstance(Node.value.op, ast.BitOr):
ValueTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Node.value)
ValueTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.value)
else:
ValueTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.value)
if isinstance(ValueTypeInfo, CTypeInfo) and (ValueTypeInfo.BaseType or ValueTypeInfo.PtrCount > 0):
+89 -299
View File
@@ -2,11 +2,9 @@ from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from typing import List
from lib.core.Handles.HandlesBase import BaseHandle, CTypeHelper, CTypeInfo
from lib.core.SymbolUtils import (
IsListAnnotation, IsPtrSubscriptNode, IsCPtrMarkerNode, RejectTypeUnion,
DesugarPtrSubscriptToUnion)
IsListAnnotation, IsPtrSubscriptNode, IsCPtrMarkerNode)
from lib.core import TypeSystem
import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib)
import vast as ast
@@ -25,19 +23,67 @@ class HandlesTypeMerge(BaseHandle):
"""直接从类型名构造 CTypeInfo,不经过 FromStr/字符串解析"""
return CTypeInfo.FromTypeName(TypeName)
_STORAGE_MARKER_CLASSES: dict[str, str] = {
'static': 'CStatic',
'export': 'CExport',
'extern': 'CExtern',
'inline': 'CInline',
}
@staticmethod
def _ApplyTypeModifiers(Info: CTypeInfo, Node: ast.AST) -> CTypeInfo:
"""把注解节点上的 Markers / ByteOrder / BitWidth 写入 CTypeInfo。"""
Markers: tuple[str, ...] = getattr(Node, 'Markers', None) or ()
ByteOrder: str | None = getattr(Node, 'ByteOrder', None)
BitWidth: int | None = getattr(Node, 'BitWidth', None)
if not Markers and not ByteOrder and not BitWidth:
return Info
Info = Info.Copy()
for Marker in Markers:
if Marker == 'const':
Info.DataConst = True
elif Marker == 'volatile':
Info.DataVolatile = True
elif Marker == 'state':
Info.IsState = True
elif Marker == 'define':
Info.IsDefine = True
elif Marker == 'typedef':
Info.IsTypedef = True
else:
StorageClassName: str | None = HandlesTypeMerge._STORAGE_MARKER_CLASSES.get(Marker)
if StorageClassName:
Info.Storage = getattr(TypeSystem, StorageClassName)()
if ByteOrder:
Info.ByteOrder = ByteOrder
if BitWidth:
Info.IsBitField = True
Info.BitWidth = BitWidth
return Info
def GetCTypeInfo(self, Node: ast.AST) -> CTypeInfo:
"""获取 CTypeInfo 对象"""
RejectTypeUnion(Node)
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
Line: int = getattr(Node, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
Result = self._GetCTypeInfoInternal(Node)
if isinstance(Result, CTypeInfo):
return Result
Info = Result
elif isinstance(Result, str):
return self._MakeCTypeInfoFromName(Result)
Info = self._MakeCTypeInfoFromName(Result)
else:
return self._MakeVoidCTypeInfo()
Info = self._MakeVoidCTypeInfo()
return self._ApplyTypeModifiers(Info, Node)
def _GetCTypeInfoInternal(self, Node: ast.AST) -> CTypeInfo | str | None:
"""鍐呴儴鏂规硶锛岃繑鍥?CTypeInfo"""
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
Line: int = getattr(Node, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
LineNum = getattr(Node, 'lineno', None)
if getattr(self.Trans, 'DebugFile', None):
@@ -409,9 +455,6 @@ class HandlesTypeMerge(BaseHandle):
return Result
return self._HandleSubscript(Node)
elif isinstance(Node, ast.BinOp):
return self.MergeTypes(Node)
elif isinstance(Node, ast.List):
if Node.elts:
BaseTypes = []
@@ -427,6 +470,27 @@ class HandlesTypeMerge(BaseHandle):
return self._MakeVoidCTypeInfo()
def _ResolvePtrSubscript(self, Node: ast.Subscript) -> CTypeInfo:
"""`CPtr[T]` / `rawptr[T]` → Ptr(T):struct 基类型吸收一层,其余逐层外包。"""
Inner: CTypeInfo = self.GetCTypeInfo(Node.slice)
Result: CTypeInfo = Inner.Copy()
if not Result.BaseType:
Result.BaseType = TypeSystem.CVoid()
if not (Result.IsStruct and Result.PtrCount > 0):
Result.PtrCount += 1
return Result
def _ResolveRefSubscript(self, Node: ast.Subscript, MarkerName: str) -> CTypeInfo:
"""`CRef[T]` / `CTempRef[T]` / `CArrayPtr[T]` / `CAutoPtr[T]` → Ptr(T)。"""
Inner: CTypeInfo = self.GetCTypeInfo(Node.slice)
Result: CTypeInfo = Inner.Copy()
if not Result.BaseType:
Result.BaseType = TypeSystem.CVoid()
Result.PtrCount += 1
if MarkerName == 'CArrayPtr':
Result.IsArrayPtr = True
return Result
def _HandleSubscript(self, Node: ast.Subscript) -> CTypeInfo:
"""澶勭悊 Subscript 鑺傜偣锛屼娇鐢?CTypeInfo 鏍戝舰缁撴瀯鍒嗘瀽 AST
@@ -437,13 +501,17 @@ class HandlesTypeMerge(BaseHandle):
CPtr[CArrayPtr[CArrayPtr]] -> void *(*(*))[]
"""
# 指针下标(rawptr[T] 内置裸指针 / CPtr[T] 下标指针,含裸名 CPtr[T])
# 折叠为等价的联合写法 `T | CPtr` 后交给 MergeTypes 统一解析:内层 T
# 因此走通用解析路径(含跨模块类经 Gen.structs 反查 SHA1 前缀),指针
# 层数与源码 `T | CPtr` 完全一致(此前 CPtr[ast.AST] 在此得
# AST**(比 declare/`AST | CPtr` 多一层)、rawptr[ast.AST] 退化为
# CVoid/1 → i8*)。
# 内层 T 走通用解析路径(含跨模块类经 Gen.structs 反查 SHA1 前缀);
# 裸类引用自身即指针,吸收这一层,其余逐层外包。
if IsPtrSubscriptNode(Node, self.Trans.SymbolTable):
return self.MergeTypes(DesugarPtrSubscriptToUnion(Node, self.Trans.SymbolTable))
return self._ResolvePtrSubscript(Node)
MarkerName: str | None = None
if isinstance(Node.value, ast.Name):
MarkerName = Node.value.id
elif isinstance(Node.value, ast.Attribute):
MarkerName = Node.value.attr
if MarkerName in ('CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
return self._ResolveRefSubscript(Node, MarkerName)
# 判据自洽守卫(fail-fast):base 是指针标记(`rawptr` / `CPtr` / 裸名
# `CPtr` / 别名 `X[...]`,见 IsPtrSubscriptNode)却被上面那条判据漏掉 ⇒
@@ -571,14 +639,6 @@ class HandlesTypeMerge(BaseHandle):
ResultInfo.ArrayPtr = inner
else:
ResultInfo.BaseType = CTypeInfo.CreateFromTypeName(slice_node.id).BaseType
elif isinstance(slice_node, ast.BinOp):
merged = self.MergeTypes(slice_node)
if merged:
ResultInfo.PtrCount += merged.PtrCount
if merged.BaseType and not isinstance(merged.BaseType, TypeSystem.CVoid):
ResultInfo.BaseType = merged.BaseType
if merged.ArrayPtr:
ResultInfo.ArrayPtr = merged.ArrayPtr
elif isinstance(slice_node, ast.Constant):
ResultInfo.ArrayDims.append(str(slice_node.value))
elif VtInfo:
@@ -809,279 +869,9 @@ class HandlesTypeMerge(BaseHandle):
return CollectAll(Node)
def _CollectAllOperandTypes(self, Node: ast.AST) -> List:
"""递归收集所有操作数的类型(用于一次性合并)"""
Types = []
# 指针下标(rawptr[T] / CPtr[T])先折叠成等价的 `T | CPtr`:使
# `rawptr[T] | CPtr` 与 `T | CPtr | CPtr` 拉平成同一组操作数
# (否则折叠结果作为单个 Subscript 操作数参与合并,指针层数少算一层);
# CPtr[T] 与 rawptr[T] 同一条规则(见 SymbolUtils.IsPtrSubscriptNode)。
if IsPtrSubscriptNode(Node, self.Trans.SymbolTable):
Node = DesugarPtrSubscriptToUnion(Node, self.Trans.SymbolTable)
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
Types.extend(self._CollectAllOperandTypes(Node.left))
Types.extend(self._CollectAllOperandTypes(Node.right))
else:
Types.append(Node)
return Types
def _GetTypeFromNode(self, Node: ast.AST) -> CTypeInfo:
"""浠?AST 鑺傜偣鑾峰彇绫诲瀷"""
if isinstance(Node, ast.Call):
if isinstance(Node.func, ast.Name) and Node.func.id == 'callable':
return self.GetCTypeInfo(Node)
elif isinstance(Node.func, ast.Attribute) and CTypeHelper.GetTModuleCType(Node.func.attr) == TypeSystem._CTypedef:
return self.GetCTypeInfo(Node)
elif isinstance(Node.func, ast.Attribute) and Node.func.attr == 'Bit':
if Node.args and isinstance(Node.args[0], ast.Constant):
Result = CTypeInfo()
Result.BaseType = TypeSystem.CInt
Result.IsBitField = True
Result.BitWidth = Node.args[0].value
return Result
return self._MakeVoidCTypeInfo()
elif isinstance(Node, ast.Subscript):
if (isinstance(Node.value, ast.Attribute)
and isinstance(Node.value.value, ast.Name)
and Node.value.attr == 'Bit'):
if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int):
Result = CTypeInfo()
Result.BaseType = TypeSystem.CInt
Result.IsBitField = True
Result.BitWidth = Node.slice.value
return Result
return self.GetCTypeInfo(Node)
else:
return self.GetCTypeInfo(Node)
def MergeTypes(self, Node: ast.BinOp):
"""处理类型组合,如 CInt | CPtr ?CStatic | CInt
这是 | 运算符的类型合并处理函数
收集所有操作数,一次性合?
"""
if not isinstance(Node, ast.BinOp) or not isinstance(Node.op, ast.BitOr):
return None
AllOperands = self._CollectAllOperandTypes(Node)
AllTypes = []
for Operand in AllOperands:
TypeItem = self._GetTypeFromNode(Operand)
AllTypes.append(TypeItem)
if isinstance(Node.left, ast.Attribute):
LeftParts = []
current = Node.left
while isinstance(current, ast.Attribute):
attr_type = getattr(TypeSystem, current.attr, None)
if attr_type and isinstance(attr_type, type) and issubclass(attr_type, TypeSystem.CType):
LeftParts.insert(0, attr_type)
current = current.value
if isinstance(current, ast.Name):
name_type = getattr(TypeSystem, current.id, None)
if name_type and isinstance(name_type, type) and issubclass(name_type, TypeSystem.CType):
LeftParts.insert(0, name_type)
if LeftParts and LeftParts[-1] == TypeSystem._CTypedef:
for type_item in AllTypes:
if isinstance(type_item, CTypeInfo) and type_item.IsFuncPtr:
type_item.IsTypedef = True
type_item.OriginalType = CTypeInfo()
type_item.OriginalType.IsFuncPtr = True
type_item.OriginalType.FuncPtrReturn = type_item.FuncPtrReturn or CTypeInfo.VoidTypeInfo()
type_item.OriginalType.FuncPtrParams = list(type_item.FuncPtrParams) if type_item.FuncPtrParams else []
return type_item
Result = CTypeInfo()
if isinstance(AllTypes[-1], CTypeInfo):
Result.BaseType = AllTypes[-1].BaseType
else:
Result.BaseType = TypeSystem.CInt
Result.IsTypedef = True
return Result
return self._MergeAllComponentTypes(*AllTypes)
def _MergeAllComponentTypes(self, *Types: CTypeInfo) -> CTypeInfo:
"""合并多个类型 - 直接使用 CTypeInfo 类"""
if not Types:
return CTypeInfo()
Result = CTypeInfo()
# 统计 CPtr(CVoid + PtrCount=1)的个数,用于正确累加指针层数
# 因为 (AST | CPtr) | CPtr 展开后会包含多个 CPtr,每个都需要累加
cptr_count: int = 0
for TypeItem in Types:
if TypeItem is None:
continue
if TypeItem.IsDefine:
# CDefine 标记在 | 合并中传播(对齐 IsState):
# `int | CDefine`(define 宏函数返回注解)合并后仍保持
# IsDefine=True,下游才能识别为编译期宏(alwaysinline/#define)
Result.IsDefine = True
if TypeItem.IsState:
Result.IsState = True
if not Result.Storage:
Result.Storage = TypeSystem.CExport()
continue
if TypeItem.IsBitField:
Result.BaseType = TypeSystem.CInt
Result.IsBitField = True
Result.BitWidth = TypeItem.BitWidth
return Result
if TypeItem.IsFuncPtr:
Result.BaseType = TypeSystem.CVoid
Result.IsFuncPtr = True
Result.FuncPtrParams = TypeItem.FuncPtrParams
Result.FuncPtrReturn = TypeItem.FuncPtrReturn
return Result
if TypeItem.IsTypedef:
if TypeItem.BaseType and (not isinstance(TypeItem.BaseType, (TypeSystem._CTypedef,)) or TypeItem.PtrCount > 0):
if Result.BaseType is None or isinstance(Result.BaseType, (TypeSystem.CVoid, TypeSystem._CTypedef)):
Result.BaseType = TypeItem.BaseType
Result.Name = TypeItem.Name
Result.IsTypedef = True
Result.PtrCount = max(Result.PtrCount, TypeItem.PtrCount)
if TypeItem.OriginalType:
Result.OriginalType = TypeItem.OriginalType
else:
Result.IsTypedef = True
Result.Name = TypeItem.Name
if TypeItem.OriginalType:
Result.OriginalType = TypeItem.OriginalType
continue
# 统计 CPtr(CVoid + PtrCount>0)
# 注意: CPtr[CPtr] 的 PtrCount=2(双重指针),需要完整累加
if TypeItem.PtrCount > 0 and TypeItem.BaseType and (TypeItem.BaseType is TypeSystem.CVoid or isinstance(TypeItem.BaseType, TypeSystem.CVoid)):
cptr_count += TypeItem.PtrCount
# BaseType 保持不变,只计数,后续统一累加
if TypeItem.IsRenum and TypeItem.Name:
Result.IsRenum = True
Result.IsEnum = True
Result.IsStruct = True
if not Result.Name:
Result.Name = TypeItem.Name
continue
self._MergeCTypeInfoInto(Result, TypeItem)
# 对所有 CPtr 统一累加指针层数
# 仅对 struct 类型吸收第一个 CPtr(struct 变量默认是指针,AST | CPtr = AST*)。
# 对于本身已是指针的类型(如 bytes=CChar*),bytes | CPtr = i8**(不吸收)。
base_ptr_count: int = Result.PtrCount
Result.PtrCount += cptr_count
if Result.IsStruct and base_ptr_count > 0 and cptr_count > 0:
Result.PtrCount -= 1
if Result.BaseType is None:
Result.BaseType = TypeSystem.CVoid
return Result
def _MergeCTypeInfoInto(self, Target: CTypeInfo, Source: CTypeInfo):
if Source.PtrCount > 0 and Source.BaseType and (Source.BaseType is TypeSystem.CVoid or isinstance(Source.BaseType, TypeSystem.CVoid)):
# CPtr 的处理已提升到 _MergeAllComponentTypes 中统一计数累加,
# 此处保留仅作为兜底(从其他路径直接调用 _MergeCTypeInfoInto 时)
if Target.PtrCount < Source.PtrCount:
Target.PtrCount = Source.PtrCount
elif Source.PtrCount > 0 and Source.BaseType and Source.BaseType is not TypeSystem.CVoid and not isinstance(Source.BaseType, TypeSystem.CVoid):
if Target.BaseType is None or Target.BaseType is TypeSystem.CVoid or isinstance(Target.BaseType, TypeSystem.CVoid):
Target.BaseType = Source.BaseType
# 当 Target 已有 PtrCount(来自之前的 CPtr),累加而非替换
Target.PtrCount = Source.PtrCount + Target.PtrCount
elif Target.PtrCount == 0:
Target.PtrCount = Source.PtrCount
elif Source.PtrCount > Target.PtrCount:
Target.PtrCount = Source.PtrCount
elif Source.PtrCount > Target.PtrCount:
Target.PtrCount = Source.PtrCount
if Source.BaseType and Source.BaseType is not TypeSystem.CVoid and not isinstance(Source.BaseType, (TypeSystem.CVoid, TypeSystem._CTypedef)):
if Target.BaseType is None:
Target.BaseType = Source.BaseType
elif (Target.BaseType is TypeSystem.CVoid or isinstance(Target.BaseType, TypeSystem.CVoid)) and Target.PtrCount == 0:
Target.BaseType = Source.BaseType
elif (Source.BaseType is TypeSystem.CVoid or isinstance(Source.BaseType, TypeSystem.CVoid)) and Target.BaseType is None:
Target.BaseType = Source.BaseType
# Struct 名称保留:BinOp `list[AST | CPtr] | CPtr` 合并时,
# _HandleSubscript 已在 Source.Name 设置了特化名(如 'list[5dab8cb390496d22.ASTptr]'),
# 合并后 Target.Name 必须保留此名称,否则 class_member_element_class
# 无法获取正确的特化类名 → 方法分派 fallback 到错误的类
if Source.IsStruct and Source.Name and not Target.Name:
Target.Name = Source.Name
# 【IsStruct 必须随 Name 一起传播】`_MergeAllComponentTypes` 的
# "struct 吸收第一个 CPtr"规则(见该函数 :1022-1027 的注释:
# struct 变量默认是指针 ⇒ `AST | CPtr = AST*`)以 `Result.IsStruct` 为**闸门**:
# 此前本函数只复制 Name、从不置 IsStruct ⇒ 闸门恒假 ⇒ 闸门后的
# `Result.PtrCount -= 1` 永不执行 ⇒ 「类 + CPtr」的联合(如
# `list[str] | CPtr`)合并后指针层数**多算一层**(得 `list[str]**`,应为
# `list[str]*`)⇒ 调用点/字段拿到的值类型 pointee 是指针而不是结构体 ⇒
# 类名在下游被当作通用指针处理(现场:`parts = s1.split(',')` 的返回值
# pointee 非结构体 ⇒ HandlesAssign 的类名推断整块跳过 ⇒ 随后 `parts[0]`
# 退化成按字节索引并得到整数)。
# 语义上这两个标志同源(合并结果就是那个 struct),故成对传播。
if Source.IsStruct:
Target.IsStruct = True
# REnum 标志和名称保留(BinOp `LLVMType | CPtr` 合并时不能丢失 REnum 语义)
# 同时传播 IsStruct=True,让 CPtr 吸收逻辑生效(REnum 在内存布局上是 struct)
if Source.IsRenum and Source.Name:
Target.IsRenum = True
Target.IsEnum = True
Target.IsStruct = True
if not Target.Name:
Target.Name = Source.Name
if Source.IsTypedef and Source.Name:
if Source.BaseType and (not isinstance(Source.BaseType, (TypeSystem._CTypedef,)) or Source.PtrCount > 0):
if Target.BaseType is None or isinstance(Target.BaseType, (TypeSystem.CVoid, TypeSystem._CTypedef)):
Target.BaseType = Source.BaseType
Target.IsTypedef = True
Target.Name = Source.Name
if Source.OriginalType:
Target.OriginalType = Source.OriginalType
elif Target.BaseType is None or isinstance(Target.BaseType, (TypeSystem.CVoid, TypeSystem._CTypedef)):
if Source.OriginalType:
if isinstance(Source.OriginalType, CTypeInfo) and Source.OriginalType.BaseType:
Target.BaseType = Source.OriginalType.BaseType
Target.PtrCount = max(Target.PtrCount, Source.OriginalType.PtrCount)
Target.IsTypedef = True
Target.Name = Source.Name
Target.OriginalType = Source.OriginalType
elif isinstance(Source.OriginalType, CTypeInfo):
Target.IsTypedef = True
Target.Name = Source.Name
Target.OriginalType = Source.OriginalType
else:
Target.BaseType = TypeSystem.CStruct(name=Source.Name)
Target.IsStruct = True
else:
Target.BaseType = TypeSystem.CStruct(name=Source.Name)
Target.IsStruct = True
if Source.ArrayPtr:
if Target.ArrayPtr is None:
Target.ArrayPtr = Source.ArrayPtr
else:
if Source.PtrCount > Target.PtrCount:
Target.PtrCount = Source.PtrCount
Target.ArrayPtr = Source.ArrayPtr
if Source.PtrCount > 0:
Target.ArrayDims = []
elif Source.ArrayDims:
Target.ArrayDims.extend(Source.ArrayDims)
if Source.VarConst:
Target.VarConst = True
if Source.VarVolatile:
Target.VarVolatile = True
if Source.DataConst:
Target.DataConst = True
if Source.DataVolatile:
Target.DataVolatile = True
if Source.IsFuncPtr:
Target.IsFuncPtr = True
Target.FuncPtrParams = Source.FuncPtrParams
Target.FuncPtrReturn = Source.FuncPtrReturn
if Source.Storage and not Target.Storage:
Target.Storage = Source.Storage
if Source.ByteOrder and not Target.ByteOrder:
Target.ByteOrder = Source.ByteOrder
def MergeTypes(self, Node: ast.BinOp) -> None:
Line: int = getattr(Node, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
+63 -121
View File
@@ -19,7 +19,7 @@ if TYPE_CHECKING:
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap
from lib.core.SymbolUtils import (
IsListAnnotation, RejectTypeUnion, IsCPtrNode, IsCPtrSubscriptNode,
IsListAnnotation, IsCPtrSubscriptNode,
IsRawPtrSubscriptNode, EnumIntWidth,
ResolveGenericClassSpecName, GetStructSha1MapFromSymtab, GetTCAliasMapFromSymtab)
from lib.core import TypeSystem as _t
@@ -116,61 +116,63 @@ class LLVMTypeMapper:
# 公共 API
# ==================================================================
@staticmethod
def _RejectTypeUnion(node: ast.AST) -> None:
"""遇到 `T1 | T2` 类型联合立即 fail-fast。"""
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
Line: int = getattr(node, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
def get_llvm_type_str(self, node: ast.AST | None) -> str:
"""将 AST 注解节点转换为 LLVM IR 类型字符串"""
if node is None:
self._symtab.diagnostics.warn('', 0, "类型注解为 None,回退到 i32")
return 'i32'
RejectTypeUnion(node)
self._RejectTypeUnion(node)
result: str
if isinstance(node, ast.Name):
return self._resolve_name(node)
result = self._resolve_name(node)
elif isinstance(node, ast.Attribute):
return self._resolve_attribute(node)
result = self._resolve_attribute(node)
elif isinstance(node, ast.Subscript):
return self._resolve_subscript(node)
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
return self._resolve_bitor(node)
result = self._resolve_subscript(node)
elif isinstance(node, ast.Constant):
if isinstance(node.value, bool):
return 'i8'
return 'i32'
result = 'i8' if isinstance(node.value, bool) else 'i32'
elif isinstance(node, ast.Call):
return self._resolve_call(node)
self._symtab.diagnostics.warn('', 0, f"无法解析类型节点 {type(node).__name__},回退到 i32")
return 'i32'
result = self._resolve_call(node)
else:
self._symtab.diagnostics.warn('', 0, f"无法解析类型节点 {type(node).__name__},回退到 i32")
result = 'i32'
if not result and getattr(node, 'BitWidth', None):
return 'i32'
return result
def get_func_ret_type_str(self, returns_node: ast.AST | None) -> str:
"""提取函数返回类型的 LLVM 字符串"""
if returns_node is None:
return 'i32'
if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr):
# 统一走 CPtr 感知的联合解析(int | CPtr → i32*、str | CPtr → i8**)
return self._resolve_bitor(returns_node)
result: str = self.get_llvm_type_str(returns_node)
return result if result else 'i32'
def get_func_param_type_str(self, annotation_node: ast.AST | None) -> str:
"""提取函数参数类型的 LLVM 字符串。
末尾的「不许静默变 i32」守卫:`Subscript` / 联合(`|`)形态的形参注解若解析结果
末尾的「不许静默变 i32」守卫:`Subscript` 形态的形参注解若解析结果
是 `'i32'`,只可能是**解析失败后的兜底** —— 合法的下标注解是容器 / 泛型 / 定长数组
(解析出指针、数组或结构体指针),合法的联合写法是 `T | CPtr` 这类指针叠加,都
不会是 i32。该串会被 `_InsertFuncSymbol` 原样存进符号表(`FuncPtrParams`),再由
`BuildLLVMFuncTypeFromSig` 物化成形参类型 —— 一旦是 i32,调用点就在 `_adjust_args`
报「实参 %X* 不能隐式转为 i32」,把真因(**注解没解析出来**)掩盖成"调用点类型
不匹配"(现场:CallGenMixin.vp:149 调用 `_specialize_generic_class` 的
`type_args: list[str]*`)。故此处响亮失败,并带上注解原文。
(解析出指针、数组或结构体指针),不会是 i32。该串会被 `_InsertFuncSymbol` 原样存进
符号表(`FuncPtrParams`),再由 `BuildLLVMFuncTypeFromSig` 物化成形参类型 —— 一旦是
i32,调用点就在 `_adjust_args` 报「实参 %X* 不能隐式转为 i32」,把真因(**注解没
解析出来**)掩盖成"调用点类型不匹配"(现场:CallGenMixin.vp:149 调用
`_specialize_generic_class` 的 `type_args: list[str]*`)。故此处响亮失败,并带上
注解原文。
"""
if annotation_node is None:
return 'i8*'
result: str
if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
# 统一走 CPtr 感知的联合解析
result = self._resolve_bitor(annotation_node)
else:
result = self.get_llvm_type_str(annotation_node)
if not result:
result = 'i8*'
result: str = self.get_llvm_type_str(annotation_node)
if not result:
result = 'i8*'
if result == 'i32' and isinstance(annotation_node, (ast.Subscript, ast.BinOp)):
_text: str
try:
@@ -178,7 +180,7 @@ class LLVMTypeMapper:
except Exception:
_text = f'<{type(annotation_node).__name__}>'
raise TypeNameUnresolvedError(
f"形参注解 '{_text}' 解析失败并落到 i32(下标 / 联合形态的合法结果应为"
f"形参注解 '{_text}' 解析失败并落到 i32(下标形态的合法结果应为"
f"指针、数组或结构体指针,不会是 i32)—— 拒绝静默降级为 i32")
return result
@@ -186,6 +188,7 @@ class LLVMTypeMapper:
"""解析 typedef 值表达式的 C 类型字符串"""
if node is None:
return ''
self._RejectTypeUnion(node)
if isinstance(node, ast.Name):
if node.id in self._symtab:
Entry: CTypeInfo = self._symtab[node.id]
@@ -217,10 +220,7 @@ class LLVMTypeMapper:
if node.attr == 'CPtr':
return 'ptr'
if node.attr in _TYPEDEF_VALUE_QUALIFIERS:
# 类型限定符标记(const/volatile)本身不是类型:它只修饰 `|` 另一侧。
# 旧写法 `CConst | char | CPtr` 靠 char 一侧掩盖了这一点;一旦写成
# `CConst | str`(`const str`),把 'CConst' 当基类型会得到 'CConst *',
# 于是别名登记失败、所有使用处报「裸名 … 无法解析为类型」。
# 类型限定符标记(const/volatile)本身不是类型
return ''
CName: str | None = CTypeHelper.GetCName(node.attr)
if CName == 'CPtr':
@@ -228,28 +228,21 @@ class LLVMTypeMapper:
if CName:
return CName
return ''
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_str: str = self.resolve_typedef_value_type(node.left)
right_str: str = self.resolve_typedef_value_type(node.right)
# 限定符侧解析为空串 ⇒ 另一侧就是完整类型(见 _TYPEDEF_VALUE_QUALIFIERS)。
# 只在两侧都有类型信息时才按"基类型 + 指针标记"合并。
if not left_str:
return 'void *' if right_str == 'ptr' else right_str
if not right_str:
return 'void *' if left_str == 'ptr' else left_str
if right_str == 'ptr' or right_str.endswith('*'):
if left_str != 'ptr':
return left_str + ' *'
return right_str if right_str.endswith('*') else 'void *'
if left_str == 'ptr' or left_str.endswith('*'):
if right_str != 'ptr':
return right_str + ' *'
return left_str if left_str.endswith('*') else 'void *'
if right_str not in ('ptr', 'void', 'i32', 'i64'):
return right_str
if left_str not in ('ptr', 'void', 'i32', 'i64'):
return left_str
return left_str if left_str else right_str
if isinstance(node, ast.Subscript):
BaseNode: ast.AST = node.value
BaseName: str = ''
if isinstance(BaseNode, ast.Name):
BaseName = BaseNode.id
elif isinstance(BaseNode, ast.Attribute):
BaseName = BaseNode.attr
if BaseName in ('CPtr', 'rawptr', 'CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
InnerType: str = self.resolve_typedef_value_type(node.slice)
if not InnerType or InnerType == 'ptr':
return 'void *'
return InnerType + ' *'
return ''
if getattr(node, 'BitWidth', None):
return 'CInt'
return ''
# ==================================================================
@@ -387,12 +380,9 @@ class LLVMTypeMapper:
return builtin_llvm
# 存储类 / 类型限定符标记(CExport/CExtern/CStatic/CInline/CConst/
# CVolatile/State 等,均以 `from t import ...` 裸名出现):自身不是类型,
# 只作标记 ⇒ 贡献空串,由 _resolve_bitor 取另一侧真实类型
# (`CInt | CExport` → i32)。与 _resolve_attribute 的 marker 分支、
# 只作标记 ⇒ 贡献空串。与 _resolve_attribute 的 marker 分支、
# TypeAnnotationResolver._ResolveNameNode 的 STORAGE_CLASS/TYPE_QUALIFIER
# 判定同口径。缺此分支时裸名标记会落到下方 fail-fast —— 而带前缀写作
# `CExport` 时却能通过(走 Attribute 路径),同一语义两种写法结果不同。
# 现场:Test/AstTest `def main() -> CInt | CExport`(第 108 行)。
# 判定同口径。
_marker_cls: object = getattr(_t, node.id, None)
if (isinstance(_marker_cls, type) and _marker_cls is not _t.CType
and issubclass(_marker_cls, _t.CType)):
@@ -455,10 +445,16 @@ class LLVMTypeMapper:
# TypeGenResolve.vp:2769-2790;void 首层归一化为 i8*)
return self._add_pointer_level(self.get_llvm_type_str(node.slice))
if IsRawPtrSubscriptNode(node):
# rawptr[T](内置裸指针下标)≡ `T | CPtr`:与定义端 TypeMerge 的
# 合并语义同口径(裸类引用自身即指针,吸收这一层;其余逐层外包)。
# 此前只认 IsCPtrSubscriptNode → rawptr[T] 落到下方 warn 并退化成 i32。
# rawptr[T](内置裸指针下标):裸类引用自身即指针,吸收这一层;
# 其余逐层外包。
return self._rawptr_subscript_type_str(node)
MarkerName: str | None = None
if isinstance(node.value, ast.Name):
MarkerName = node.value.id
elif isinstance(node.value, ast.Attribute):
MarkerName = node.value.attr
if MarkerName in ('CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
return self._add_pointer_level(self.get_llvm_type_str(node.slice))
if IsListAnnotation(node):
slice_node: ast.AST = node.slice
elem_type: str
@@ -484,41 +480,6 @@ class LLVMTypeMapper:
self._symtab.diagnostics.warn('', 0, "无法解析 Subscript 类型,回退到 i32")
return 'i32'
def _resolve_bitor(self, node: ast.BinOp) -> str:
"""解析 ast.BinOp(BitOr) 节点(CPtr 感知的指针层级叠加)。
T | CPtr 一侧为 CPtr 标记时,另一侧追加一层 '*':
int | CPtr → i32* (原逻辑误降级为 i8*)
str | CPtr → i8** (原逻辑误降级为 i8*)
(int | CPtr) | CPtr → i32**(嵌套递归叠加)
T | CPtr[...] 一侧为下标指针类型时,另一侧叠加该下标的指针层级 N
(N = 1 + 切片自身层数,不含 struct 吸收,对齐 VPC BinOp 下标分支
TypeGenResolve.vp:2596-2639):
CUInt8T | CPtr[CPtr] → i8**(原逻辑误降级为首段 i8)
"""
left: str = self.get_llvm_type_str(node.left)
right: str = self.get_llvm_type_str(node.right)
left_is_cptr: bool = IsCPtrNode(node.left)
right_is_cptr: bool = IsCPtrNode(node.right)
if right_is_cptr:
return self._add_pointer_level(left)
if left_is_cptr:
return self._add_pointer_level(right)
# CPtr[...] 下标指针标记:X | CPtr[...] → Ptr^N(X)
if IsCPtrSubscriptNode(node.right):
return self._add_pointer_levels(left, self._cptr_subscript_ptr_level(node.right))
if IsCPtrSubscriptNode(node.left):
return self._add_pointer_levels(right, self._cptr_subscript_ptr_level(node.left))
if right and right.endswith('*'):
return right
if left and left.endswith('*'):
return left
if left and left not in ('i32', 'void', 'i64'):
return left
if right and right not in ('i32', 'void', 'i64'):
return right
return left if left else right
def _add_pointer_level(self, ty: str) -> str:
"""给类型字符串追加一层指针 '*'(void/void* → i8*)。"""
if not ty:
@@ -539,31 +500,12 @@ class LLVMTypeMapper:
"""
inner: ast.AST = node.slice
inner_type: str = self.get_llvm_type_str(inner)
if (not isinstance(inner, ast.BinOp)
and not IsRawPtrSubscriptNode(inner)
if (not IsRawPtrSubscriptNode(inner)
and not IsCPtrSubscriptNode(inner)
and inner_type.startswith('%') and inner_type.endswith('*')):
return inner_type
return self._add_pointer_level(inner_type)
def _add_pointer_levels(self, ty: str, count: int) -> str:
"""给类型字符串叠加 count 层指针(void/void* 首层归一化为 i8*)。"""
result: str = ty
for _ in range(count):
result = self._add_pointer_level(result)
return result
def _cptr_subscript_ptr_level(self, node: ast.AST) -> int:
"""CPtr[T] 下标指针标记贡献的指针层级 N(= 1 + 切片自身层数)。
复用定义侧解析器 TypeAnnotationResolver.from_node(其 _from_node_subscript
已实现 CPtr[T] → Ptr(T) 的层级叠加,见 TypeAnnotationResolver.py:756-783),
与 HandlesTypeMerge._HandleSubscript(HandlesTypeMerge.py:512-531)同口径。
调用前须经 IsCPtrSubscriptNode 判据过滤,故 PtrCount 至少为 1。
"""
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver as _TAR
return _TAR.from_node(node, self._symtab).PtrCount
def _resolve_call(self, node: ast.Call) -> str:
"""解析 ast.Call 节点"""
if isinstance(node.func, ast.Name):
+12 -9
View File
@@ -10,7 +10,7 @@ from lib.core.SymbolData import (
FuncSymbolData, DefineSymbolData, AnonymousTypeData
)
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolUtils import AnnotationContainsMarker, CheckAnnotationHasCInline, AnnotationContainsName
from lib.core.SymbolUtils import AnnotationContainsMarker
from lib.core.SymbolUtils import EnumClassIntWidth, _ENUM_DEFAULT_INT_WIDTH
from lib.core import TypeSystem
@@ -63,10 +63,6 @@ class ASTSymbolExtractor:
if member_type is None:
member_type = CTypeInfo()
member_type.BaseType = TypeSystem.CInt()
is_ptr: bool = member_type.IsPtr
if isinstance(item.annotation, ast.BinOp):
if AnnotationContainsName(item.annotation, 'CPtr'):
is_ptr = True
members[full_name] = member_type.Copy()
elif isinstance(item, ast.ClassDef):
@@ -272,9 +268,14 @@ class ASTSymbolExtractor:
def _extract_ann_assign(self, node: ast.AnnAssign, result: ModuleSymbols) -> None:
"""从 AnnAssign 节点提取 typedef 或 define 数据"""
var_name: str = node.target.id
has_cdefine: bool = AnnotationContainsMarker(node.annotation, 'CDefine') if node.annotation else False
has_postdef: bool = AnnotationContainsMarker(node.annotation, 'Postdefinition') if node.annotation else False
has_ctypedef: bool = AnnotationContainsMarker(node.annotation, 'CTypedef') if node.annotation else False
Markers: tuple[str, ...] = tuple(getattr(node, 'Markers', None) or ()) + tuple(
getattr(node.annotation, 'Markers', None) or ())
has_cdefine: bool = 'define' in Markers
has_ctypedef: bool = 'typedef' in Markers
has_postdef: bool = 'postdefinition' in Markers or (
isinstance(node.annotation, ast.Call)
and isinstance(node.annotation.func, ast.Attribute)
and node.annotation.func.attr == 'Postdefinition')
if has_cdefine:
result.defines.append(DefineSymbolData(
@@ -305,7 +306,9 @@ class ASTSymbolExtractor:
"""从 FunctionDef 节点提取函数符号数据"""
params: list[tuple[str, ast.AST | None]] = [(arg.arg, arg.annotation) for arg in node.args.args]
is_variadic: bool = node.args.vararg is not None
is_inline: bool = CheckAnnotationHasCInline(node.returns)
is_inline: bool = 'inline' in (getattr(node, 'Markers', None) or ()) or (
node.returns is not None
and 'inline' in (getattr(node.returns, 'Markers', None) or ()))
return FuncSymbolData(
name=node.name,
+22 -68
View File
@@ -146,49 +146,33 @@ class TypeResolver:
self._resolve_typedef_from_value(td)
def _resolve_typedef_from_value(self, td: TypedefSymbolData):
"""从值表达式解析 typedef 类型
BinOp(如 UINT | CPtr)优先于 _find_base_type 处理,
因为 _find_base_type 是静态方法无法解析 Name 引用(如 UINT)。
"""
"""从值表达式解析 typedef 类型"""
if not td.value:
td.original_type_kind = None
td.original_class = None
return
# 优先处理 BinOp(_find_base_type 无法解析 Name 引用)
if isinstance(td.value, ast.BinOp) and isinstance(td.value.op, ast.BitOr):
left_type: str = self._resolve_type_expr(td.value.left)
right_type: str = self._resolve_type_expr(td.value.right)
is_ptr_type: bool = right_type == 'ptr' or left_type == 'ptr'
if is_ptr_type:
base_name: str = left_type if left_type != 'ptr' else (right_type if right_type != 'ptr' else '')
original_type: str = (base_name + ' *') if base_name else 'void *'
td.original_class = original_type
td.original_type_kind = 'typedef'
elif left_type:
td.original_class = left_type
td.original_type_kind = 'typedef'
elif right_type:
td.original_class = right_type
td.original_type_kind = 'typedef'
else:
td.original_type_kind = None
td.original_class = None
return
Line: int = getattr(td.value, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
if isinstance(td.value, ast.Subscript):
resolved_subscript: str = self._type_mapper.resolve_typedef_value_type(td.value)
if resolved_subscript:
td.original_class = resolved_subscript
td.original_type_kind = 'typedef'
return
# 非 BinOp:使用 _find_base_type
value_base_type: str | None = self._find_base_type(td.value)
_PTR_MODIFIERS: frozenset[str] = frozenset({'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'})
# 裸 CPtr(无 `|` 联合、无 `[T]` 下标):_find_base_type 把 node.attr == 'CPtr'
# 裸 CPtr(无 `[T]` 下标):_find_base_type 把 node.attr == 'CPtr'
# 归一化为指针标记 'ptr'(拼写与 _PTR_MODIFIERS 的 'CPtr' 不一致 ⇒ 下方守卫命不中),
# 若让 'ptr' 落进 original_class,经 _InsertTypedefSymbol 存入 symtab.OriginalType 后
# 会被 CTypeInfo.FromTypeName 当成 CStruct('ptr'),最终 _get_or_create_struct
# 建出 %"<模块sha>.ptr" 不透明结构体(VLogger._console_handle: win32base.HANDLE
# 报 "cannot store i8* to %"...ptr"*" 的根因)。按指针语义展开为 'void *',
# 与改前 `CPtr` 联合分支等价(_InsertTypedefSymbol 同样把
# 'CVoid *' 归一化为 'void *')。
# 建出 %"<模块sha>.ptr" 不透明结构体。按指针语义展开为 'void *'。
if value_base_type == 'ptr':
td.original_type_kind = 'typedef'
td.original_class = 'void *'
@@ -254,17 +238,6 @@ class TypeResolver:
td.original_type_kind = None
td.original_class = None
def _resolve_type_expr(self, node: ast.AST) -> str:
"""解析类型表达式为 C 类型名字符串,优先查本模块已解析的 typedef
解决同模块 typedef 间引用(如 UINTPTR = UINT | CPtr 中的 UINT)
在 TypeResolver 阶段尚未插入 symtab 的问题。
"""
if isinstance(node, ast.Name):
if node.id in self._resolved_typedefs:
return self._resolved_typedefs[node.id] or ''
return self._type_mapper.resolve_typedef_value_type(node)
# ------------------------------------------------------------------
# 函数签名解析
# ------------------------------------------------------------------
@@ -349,27 +322,10 @@ class TypeResolver:
if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and node.value.attr == 'Callable':
return 'Callable'
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_result: str | None = TypeResolver._find_base_type(node.left)
if left_result == 'ptr':
right_result: str | None = TypeResolver._find_base_type(node.right)
return (right_result if right_result and right_result != 'ptr' else 'void') + ' *'
if left_result == 'Callable':
return 'Callable'
right_result: str | None = TypeResolver._find_base_type(node.right)
if right_result == 'ptr':
return (left_result if left_result and left_result != 'ptr' else 'void') + ' *'
if right_result == 'Callable':
return 'Callable'
# 类型拼接语义:CLong | CLong → CLongLong, CUnsignedLong | CLong → CUnsignedLongLong
long_types: frozenset[str] = frozenset({'CLong', 'CUnsignedLong'})
if left_result in long_types and right_result in long_types:
if left_result == 'CUnsignedLong' or right_result == 'CUnsignedLong':
return 'CUnsignedLongLong'
return 'CLongLong'
if left_result:
return left_result
if right_result:
return right_result
Line: int = getattr(node, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
return None
@staticmethod
@@ -381,10 +337,8 @@ class TypeResolver:
if node.args and isinstance(node.args[0], ast.Name):
return node.args[0].id
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_result: str | None = TypeResolver._find_postdef_arg(node.left)
if left_result:
return left_result
right_result: str | None = TypeResolver._find_postdef_arg(node.right)
if right_result:
return right_result
Line: int = getattr(node, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
return None
+52 -150
View File
@@ -623,8 +623,8 @@ def _DesugarArrayPrefix(Tokens: list, BracketIdx: int, Count: int,
# Bare C-style leading array declarator `[N]T` / `[]T` at annotation positions (no
# descriptor), desugared to `CArray[T, N]` / `CArray[T, None]` — same shape as the
# const/volatile path and VPC _parse_array_prefix_declarator.
# descriptor), desugared to `CArray[T, N]` / `CArray[T, None]` — same shape as
# VPC _parse_array_prefix_declarator.
_ARRAY_PREFIX_HINT: str = (
'`名字: [长度]元素类型`(长度可省略:`[]元素类型`);'
'形参 / 返回值写作 `def f(p: [N]T) -> [M]U`'
@@ -635,6 +635,14 @@ _ARRAY_PREFIX_EXAMPLE: str = (
_ARRAY_STMT_BOUNDARY: tuple[int, ...] = (
tokenize.NEWLINE, tokenize.INDENT, tokenize.DEDENT
)
# 注解位置的前置修饰词(由 vast 解析器原生解析为 AST 字段):数组前缀
# `[N]T` 的注解位置判据需要跳过它们,例如 `const [80]uint64` /
# `__attribute__(...) [N]T` / `BigEndian [2]uint16`。
_ANNOTATION_PREFIX_WORDS: frozenset[str] = frozenset({
'const', 'volatile', 'static', 'export', 'extern', 'inline',
'BigEndian', 'LittleEndian',
})
_ANNOTATION_PREFIX_CALLS: frozenset[str] = frozenset({'__attribute__', 'Bit'})
def _ArrayPrefixSyntaxError(Detail: str, Lineno: int, Col: int, Snippet: str) -> SyntaxError:
@@ -684,14 +692,11 @@ def _AtAnnotationColon(Tokens: list, ColonIdx: int, Stack: list) -> bool:
if BoundIdx < 0:
return True
Bound = Tokens[BoundIdx]
# `export 名字: T` / `extern 名字: T` / `static 名字: T`(变量声明的存储类
# 修饰符,见 _ExpandExportExternVar):修饰符与名字之间已构成语句起始,同样算
# 注解位置。本判据必须在修饰符展开**之前**成立——`[N]T` 数组前缀与
# `__attribute__(...)` 两条路径都先于该展开运行,靠它把
# `export 名字: T` / `extern 名字: T` / `static 名字: T`(存储类修饰符,
# 由 vast.Parser 原生解析):修饰符与名字之间已构成语句起始,同样算注解位置。
# 本判据必须在数组前缀脱糖时成立——靠它把
# `export gdt: [7]gdt_entry = []` / `static g: [7]int = []` 正常脱糖成
# `CArray[...]` 形态(若等到展开后再插入 ` | CExport` / 前置 `CStatic | `,
# `|` 不在 _TYPE_EXPR_STOP_TOKENS 中,会被并进数组元素类型 →
# `CArray[gdt_entry | CExport, 7]`)。
# `CArray[...]` 形态。
if Bound.type == tokenize.NAME and Bound.string in _EXPORT_EXTERN_MODIFIERS:
return True
return Bound.type in _ARRAY_STMT_BOUNDARY or Bound.string == ';'
@@ -703,17 +708,35 @@ def _InArrayAnnotationPosition(Tokens: list, Index: int, Stack: list) -> bool:
Stack holds open brackets before Index as (char, open_index). AnnAssign / class
field: ':' preceded by a (possibly dotted) target name at a statement boundary.
Parameter: ':' inside a def's parameter paren. Return annotation: '->' before '['.
Dict / slice / lambda colons are excluded so right-hand `[...]` literals stay put.
Annotation prefix modifiers (const/volatile/... / __attribute__(...) / BigEndian /
Bit(...)) between the delimiter and '[' are skipped. Dict / slice / lambda colons
are excluded so right-hand `[...]` literals stay put.
"""
PrevIdx: int = _PrevSignificantTokenIndex(Tokens, Index)
if PrevIdx < 0:
j: int = _PrevSignificantTokenIndex(Tokens, Index)
while j >= 0:
Prev = Tokens[j]
if Prev.type == tokenize.NAME and Prev.string in _ANNOTATION_PREFIX_WORDS:
j = _PrevSignificantTokenIndex(Tokens, j)
continue
if Prev.type == tokenize.OP and Prev.string in (')', ']'):
OpenIdx: int = _MatchOpenBracket(Tokens, j)
if OpenIdx < 0:
return False
CalleeIdx: int = _PrevSignificantTokenIndex(Tokens, OpenIdx)
if (CalleeIdx >= 0 and Tokens[CalleeIdx].type == tokenize.NAME
and Tokens[CalleeIdx].string in _ANNOTATION_PREFIX_CALLS):
j = _PrevSignificantTokenIndex(Tokens, CalleeIdx)
continue
return False
break
if j < 0:
return False
Prev = Tokens[PrevIdx]
Prev = Tokens[j]
if Prev.string == '->':
return True
if Prev.string != ':':
return False
return _AtAnnotationColon(Tokens, PrevIdx, Stack)
return _AtAnnotationColon(Tokens, j, Stack)
def _ApplySameLineEdits(Code: str, Edits: list[tuple[int, int, int, str, str]]) -> str:
@@ -1564,10 +1587,10 @@ def EnumMemberCountMismatchError(ClassName: str, Visible: list[tuple[str, object
)
# ExpandSoftKeywords 是 Code 的纯函数(全程无全局可变状态,见其"九种展开"实现):
# ExpandSoftKeywords 是 Code 的纯函数(全程无全局可变状态):
# 同一文件内容在一次编译里会被多处重复展开(Phase1 / Phase2 / 依赖扫描),
# 缓存结果避免重复正则替换与 tokenize(cProfile:_ExpandTypeDescriptors 里的
# tokenize.generate_tokens 全程 ~590 万次 TokenInfo._make)。纯函数缓存不改输出;有界防膨胀。
# 缓存结果避免重复正则替换与 tokenize(数组前缀展开需要词法切分)。
# 纯函数缓存不改输出;有界防膨胀。
_EXPAND_CACHE: dict[str, str] = {}
_EXPAND_CACHE_LIMIT: int = 256
@@ -1581,41 +1604,22 @@ def ExpandSoftKeywords(Code: str) -> str:
2) `enum Name:` 块 → `class Name(CEnum):` 块(裸成员补 `: State`):
与手写继承式枚举产出**同一 AST**,故语义(默认编号 0..N、自定义成员类型、
宽度取最宽成员)完全一致。
3) `define NAME[: T] = 值` → `NAME: [T |] CDefine = 值`:编译期常量声明,
与手写 `NAME: CDefine = 值` 产出**同一 AST/同一注册路径**(见
_ExpandDefineConsts)。`define NAME(...)`(宏函数)不受影响。
4) `typedef T1 = T2` → `T1: CTypedef = T2`:类型别名声明,与手写
`T1: CTypedef = T2` 产出**同一 AST/同一注册路径**(见 _ExpandTypedefs)。
行首 `typedef` 的非声明形态**响亮失败**(该词不在任何既有源码中作标识符)。
5) 类型描述符 `const T` / `volatile T` → `CConst | T` / `CVolatile | T`:
与手写 `CConst | T` 产出**同一 AST/同一解析路径**(见 _ExpandTypeDescriptors)。
只在注解位置生效的软关键字(`attr.const()` 等非类型位置原样保留);
缺类型 / 后随非类型 / 裸用**响亮失败**(SyntaxError)。`static` 已从注解位置
迁出——注解位置出现 `static`(`名字: static 类型`)**响亮失败**。
6) `union NAME:` → `class NAME(CUnion):`:与手写 `class NAME(CUnion):` 产出
3) `union NAME:` → `class NAME(CUnion):`:与手写 `class NAME(CUnion):` 产出
**同一 AST/同一注册路径**(见 _ExpandUnionBlocks)。成员为普通注解字段。
行首 `union` 的非 `union 名字:` 形态**响亮失败**(该词不在任何源码中作标识符)。
7) 裸数组前缀 `[N]T` / `[]T` → `CArray[T, N]` / `CArray[T, None]`(见
_ExpandArrayPrefixAnnotations):只在注解位置生效(AnnAssign 的 ':' 之后 /
形参 / '->' 之后 / 类字段),右值列表字面量**绝不改动**;无法脱糖的注解位置
数组前缀**响亮失败**(SyntaxError,绝不静默产出 List 注解)。
8) `renum NAME:` → `class NAME(REnum):`:与手写 `class NAME(REnum):` 产出
4) `renum NAME:` → `class NAME(REnum):`:与手写 `class NAME(REnum):` 产出
**同一 AST/同一注册路径**(见 _ExpandRenumBlocks)。成员为普通类体(嵌套
`class 变体:` + 无载荷赋值)。行首 `renum` 的非 `renum 名字:` 形态**响亮失败**
(该词不在任何源码中作标识符)。
9) `export 名字: T [= 初值]` → `名字: T | CExport [= 初值]`;
`extern 名字: T` → `名字: T | State`;`static 名字: T [= 初值]` →
`名字: CStatic | T [= 初值]`(见 _ExpandExportExternVar)。
与 VPC 同一标记、同一消费路径;export/extern 在类型右侧追加标记,static 在
类型左侧前置标记(与 VPC `_ParseStaticModified` 的 `pending_static` 同源);
函数形态(`export def f()` / `export f()` / `extern def f()` / `static def f()`,
后者由 vast.Parser._ParseStaticDef 处理)不受影响;
`extern` 带初值**响亮失败**(外部定义不写初值)。
5) 裸数组前缀 `[N]T` / `[]T` → `CArray[T, N]` / `CArray[T, None]`(见
_ExpandArrayPrefixAnnotations):只在注解位置生效(AnnAssign 的 ':' 之后 /
形参 / '->' 之后 / 类字段),右值列表字面量**绝不改动**;无法脱糖的注解位置
数组前缀**响亮失败**(SyntaxError,绝不静默产出 List 注解)。
`define` / `typedef` / `const` / `volatile` / `static` / `export` / `extern` /
`inline` / `__attribute__(...)` / 字节序与位宽修饰由 vast 解析器在注解位置原生
解析成 AST 字段(Markers / Attributes / ByteOrder / BitWidth),本层不再做文本展开。
以上展开都同行替换(长度可增,不增删换行),AST 行号映射保持有效。
10) `new [描述符...] T(args)`:**已不在本层展开**——vast 解析器原生解析成 New
节点(lib/vast/ExprParser._ParseNewExpr),存储/构造语义由 Handles 落地
(HandlesExprCall._HandleNewExprLlvm);`new = 1` / `new.x` / `new(1)` /
`for new in` 仍是标识符。
"""
if not Code:
return Code
@@ -1632,42 +1636,16 @@ def ExpandSoftKeywords(Code: str) -> str:
def _ExpandSoftKeywordsImpl(Code: str) -> str:
"""ExpandSoftKeywords 的实现体(无缓存,供缓存未命中时调用)。"""
Code = _SOFT_KEYWORD_RE.sub(lambda m: f'{m.group(1)}def{m.group(3)}', Code)
# `new` 生命周期软关键字(VPC):**不再**在此层展开——vast 解析器已原生解析成
# New 节点(lib/vast/ExprParser._ParseNewExpr),存储语义由 Handles 落地。
if 'enum' in Code:
Code = _ExpandEnumBlocks(Code)
if 'union' in Code:
Code = _ExpandUnionBlocks(Code)
if 'renum' in Code:
Code = _ExpandRenumBlocks(Code)
if 'define' in Code:
Code = _ExpandDefineConsts(Code)
if 'typedef' in Code:
Code = _ExpandTypedefs(Code)
# 描述符放在最后:先让语句级语法糖(enum/union/define/typedef)落到规范形态,
# 本层再看规范注解(如 `define X: const int = 1` → `X: const int | CDefine = 1`
# → `X: CConst | int | CDefine = 1`,两种顺序结果相同)。
# `__attribute__(...)` 排在 const/volatile 之前:其注解位置判据需能回溯到**原始**
# 描述符串(`const __attribute__(x) int` 的 `const` 尚未被改写为 `CConst |`),
# 且它自身产出的 `attr.X |` 不会干扰紧随的 const/volatile 展开。
if _ATTRIBUTE_CALLEE in Code:
Code = _ExpandAttributeDescriptors(Code)
# const/volatile 是注解位置的存储类描述符;`static` 已从注解位置迁出为**前置**
# 修饰符(`static 名字: 类型 = 值`),本层进入 _ExpandTypeDescriptors 只为让旧位置
# `名字: static 类型` 能被扫描到并**响亮失败**(见 _StaticPositionSyntaxError)。
if 'const' in Code or 'volatile' in Code or 'static' in Code:
Code = _ExpandTypeDescriptors(Code)
# 裸 `[N]T` 数组前缀在描述符之后:`const [N]T` 已由 _ExpandTypeDescriptors 消化为
# `CConst | CArray[T, N]`(此处不再有注解位置的裸 '['),避免两条路径重复改写。
# 裸 `[N]T` 数组前缀(只改注解位置):`const [N]T` 中的 `const` 由解析器
# 作为注解前缀消费,本层只需把数组前缀脱糖成 `CArray[T, N]`。
if '[' in Code:
Code = _ExpandArrayPrefixAnnotations(Code)
# export / extern / static 变量声明(语句级软关键字):必须排在**最后**——此时注解
# 已由数组前缀 / 描述符两层脱糖成规范形态(`CArray[T, N]` / `CConst | ...`),
# 本层只删修饰符 + 插入存储类标记(export/extern 右追加 `| CExport` / `| State`;
# static 左前置 `CStatic | `)。顺序若反过来,`|` 会被数组前缀展开并进元素类型
# (见 _ExpandExportExternVar)。
if 'export' in Code or 'extern' in Code or 'static' in Code:
Code = _ExpandExportExternVar(Code)
return Code
@@ -2191,20 +2169,6 @@ def _ContainsUnionMarker(node: ast.AST) -> bool:
return False
def RejectTypeUnion(Annotation: ast.AST | None) -> None:
"""拒绝 `T1 | T2` 类型联合;只允许「单一类型 | 内建修饰标记」。"""
if not (isinstance(Annotation, ast.BinOp) and isinstance(Annotation.op, ast.BitOr)):
return
if _ContainsUnionMarker(Annotation):
return
Line: int = getattr(Annotation, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行)。"
f"类型注解只能是单一类型:指针请写 CPtr[T] / rawptr[T];"
f"const / volatile / static / export / extern 请使用对应关键字。"
)
def AnnotationContainsMarker(node: ast.AST, MarkerName: str) -> bool:
"""注解 AST 中是否出现指定内建标记名(裸名,或属性形态的尾名)。"""
if isinstance(node, ast.Name):
@@ -2748,66 +2712,6 @@ def IsPtrSubscriptNode(node: ast.AST, symtable: object | None = None,
return IsCPtrMarkerNode(value, symtable, TCAliasMap)
def DesugarPtrSubscriptToUnion(node: ast.AST, symtable: object | None = None,
TCAliasMap: dict[str, tuple[str, str]] | None = None) -> ast.AST:
"""把指针下标(`rawptr[T]` / `CPtr[T]` / 裸名 `CPtr[T]` / 别名 `X[T]`)
折叠成等价的联合写法 `T | CPtr`。
内层 T 递归折叠(`rawptr[rawptr[X]]` → `(X | CPtr) | CPtr`、
`CPtr[rawptr[X]]` → `(X | CPtr) | CPtr`),
与 VPC TypeGenResolve.resolve_annotation_type 的 Subscript 分支同语义
(T → Ptr(T),层数逐层外包);折叠后交给 HandlesTypeMerge 既有的
联合解析(_CollectAllOperandTypes 会把嵌套 BitOr 拉平成 [T, CPtr, ...],
struct 基类型吸收一层、其余逐层累加),从而:
- 内层 T 走通用类型解析(含跨模块类经 Gen.structs 反查 SHA1 前缀);
- `rawptr[X]` / `CPtr[X]` / `X[T]` / `X | CPtr` 得到同一 CTypeInfo
(PtrCount/BaseType 一致)与同一泛型实参串(逐层 '*')。
非指针下标节点原样返回(调用方无需先判类型);symtable/TCAliasMap 透传给
判据(识别 `import t as tt` 的 `tt.CPtr[T]` 与 `from t import CPtr as X` 的
`X[T]` 内层嵌套)。折叠产物统一用字面 `CPtr` 标记,与源码联合写法同形。
"""
if not IsPtrSubscriptNode(node, symtable, TCAliasMap):
return node
inner: ast.AST = DesugarPtrSubscriptToUnion(node.slice, symtable, TCAliasMap)
cptr_marker: ast.AST = ast.Name(id='CPtr', ctx=ast.Load())
union_node: ast.AST = ast.BinOp(left=inner, op=ast.BitOr(), right=cptr_marker)
try:
ast.copy_location(union_node, node)
except Exception:
pass
return union_node
# ---------------------------------------------------------------------------
# 泛型实参串(mangling):定义端与声明端唯一规则源
# ---------------------------------------------------------------------------
# 同一泛型特化(如 list[rawptr[ast.AST]])在 define 端发射的结构体名
# (HandlesClassDef._mangle_generic_class_name → %"<mod>.list[ast.ASTptr]")、
# 各端方法名、以及 declare/stub 端引用的类型名必须逐字一致,否则会出现
# Undefined method / 签名错位。此前 DeclarationGenerator._get_type_str 的泛型
# 分支自带第二套(只认 Name / Name-Tuple 实参的)规则,其余形态(Attribute /
# Subscript / BinOp / 混合 Tuple)退回未特化的 %"<mod>.list"*,与 define 端
# 不一致。故此处收拢唯一规则,两端皆调用本组函数。
# 定义端 _resolve_generic_slice_type 的 ast.Name 规范化表:
# 源码里的 C 定长类型名 → 喂给 _mangle_generic_class_name 的 type_arg。
_GENERIC_ARG_INT_NAMES: frozenset[str] = frozenset({
'CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T',
'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong',
})
_GENERIC_ARG_FLOAT_NAMES: frozenset[str] = frozenset({
'CDouble', 'CFloat', 'CFloat64T', 'CFloat32T',
})
# 源码名 → 泛型 T 替换用的原始类型名(_resolve_generic_slice_type 的第二返回值)
_GENERIC_ARG_RAW_NAMES: dict[str, str] = {
'int': 'CInt', 'double': 'CDouble', 'float': 'CFloat',
'char': 'CChar', 'bool': 'CBool',
}
# _mangle_generic_class_name 的浮点归一集合(LLVM 浮点串 → 'f' + Size)
_LLVM_FLOAT_STRINGS: frozenset[str] = frozenset({'float', 'double', 'half', 'fp128'})
def NormalizeGenericArgName(NameId: str) -> str:
"""ast.Name 泛型实参 → 定义端 type_arg(HandlesExprCall._resolve_generic_slice_type
的 ast.Name 分支,逐分支同构):
@@ -2925,8 +2829,6 @@ def ResolveTypeArgStr(Node: ast.AST, TCAliasMap: dict[str, tuple[str, str]] | No
身份('X' = X 本身、'X*' = 指向 X 的指针),逐层累加,否则
`rawptr[X]` 与 `X | CPtr` 会分裂成两个名字。
"""
if IsPtrSubscriptNode(Node, TCAliasMap=TCAliasMap):
Node = DesugarPtrSubscriptToUnion(Node, TCAliasMap=TCAliasMap)
if isinstance(Node, ast.Name):
tn: str = Node.id
if TCAliasMap and tn in TCAliasMap:
+85 -232
View File
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING
from lib.core.Handles.HandlesBase import CTypeInfo, BuiltinTypeMap, CTypeHelper
from lib.core.ConstEvaluator import ConstEvaluator
from lib.core.SymbolUtils import (
IsListAnnotation, RejectTypeUnion,
IsListAnnotation,
ResolveGenericClassSpecName, GetStructSha1MapFromSymtab, GetTCAliasMapFromSymtab)
from lib.core import TypeSystem
from lib.constants.config import mode as _config_mode
@@ -83,6 +83,45 @@ class TypeAnnotationResolver:
def try_eval_const_expr(node: ast.AST, SymbolTable: SymbolTable) -> int | float | str | None:
return ConstEvaluator.eval_with_symtab(node, SymbolTable)
# 说明符标记('const' / 'volatile' 等)→ 存储类 CType 类名
_STORAGE_MARKER_CLASSES: dict[str, str] = {
'static': 'CStatic',
'export': 'CExport',
'extern': 'CExtern',
'inline': 'CInline',
}
@staticmethod
def _ApplyTypeModifiers(Info: CTypeInfo, Node: ast.AST) -> CTypeInfo:
"""把注解节点上的 Markers / ByteOrder / BitWidth 写入 CTypeInfo。"""
Markers: tuple[str, ...] = getattr(Node, 'Markers', None) or ()
ByteOrder: str | None = getattr(Node, 'ByteOrder', None)
BitWidth: int | None = getattr(Node, 'BitWidth', None)
if not Markers and not ByteOrder and not BitWidth:
return Info
Info = Info.Copy()
for Marker in Markers:
if Marker == 'const':
Info.DataConst = True
elif Marker == 'volatile':
Info.DataVolatile = True
elif Marker == 'state':
Info.IsState = True
elif Marker == 'define':
Info.IsDefine = True
elif Marker == 'typedef':
Info.IsTypedef = True
else:
StorageClassName: str | None = TypeAnnotationResolver._STORAGE_MARKER_CLASSES.get(Marker)
if StorageClassName:
Info.Storage = getattr(TypeSystem, StorageClassName)()
if ByteOrder:
Info.ByteOrder = ByteOrder
if BitWidth:
Info.IsBitField = True
Info.BitWidth = BitWidth
return Info
@staticmethod
def from_node(Node: ast.AST, SymbolTable: dict | SymbolTable) -> CTypeInfo:
"""从 AST 节点解析 CTypeInfo
@@ -91,20 +130,24 @@ class TypeAnnotationResolver:
Node: AST 节点(如 ast.Name, ast.Attribute 等)
SymbolTable: 符号表字典
"""
RejectTypeUnion(Node)
if isinstance(Node, ast.Constant):
return TypeAnnotationResolver._from_node_constant(Node, SymbolTable)
if isinstance(Node, ast.Name):
return TypeAnnotationResolver._from_node_name(Node, SymbolTable)
if isinstance(Node, ast.Call):
return TypeAnnotationResolver._from_node_call(Node, SymbolTable)
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
return TypeAnnotationResolver._from_node_binop(Node, SymbolTable)
if isinstance(Node, ast.Subscript):
return TypeAnnotationResolver._from_node_subscript(Node, SymbolTable)
if isinstance(Node, ast.Attribute):
return TypeAnnotationResolver._from_node_attribute(Node, SymbolTable)
return CTypeInfo()
Line: int = getattr(Node, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
if isinstance(Node, ast.Constant):
Info: CTypeInfo = TypeAnnotationResolver._from_node_constant(Node, SymbolTable)
elif isinstance(Node, ast.Name):
Info = TypeAnnotationResolver._from_node_name(Node, SymbolTable)
elif isinstance(Node, ast.Call):
Info = TypeAnnotationResolver._from_node_call(Node, SymbolTable)
elif isinstance(Node, ast.Subscript):
Info = TypeAnnotationResolver._from_node_subscript(Node, SymbolTable)
elif isinstance(Node, ast.Attribute):
Info = TypeAnnotationResolver._from_node_attribute(Node, SymbolTable)
else:
Info = CTypeInfo()
return TypeAnnotationResolver._ApplyTypeModifiers(Info, Node)
# ============================================================
# builtins 最后匹配(对齐 VPC TypeGenResolve._lookup_builtins_typedef):
@@ -718,218 +761,6 @@ class TypeAnnotationResolver:
return Result
return CTypeInfo()
@staticmethod
def _from_node_binop(Node: ast.BinOp, SymbolTable: dict | SymbolTable) -> CTypeInfo:
"""处理 ast.BinOp (BitOr) 节点"""
LeftInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.left, SymbolTable)
RightInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.right, SymbolTable)
if LeftInfo.IsState or RightInfo.IsState:
Result: CTypeInfo = CTypeInfo()
Result.IsState = True
NonStateInfo: CTypeInfo = LeftInfo if not LeftInfo.IsState else RightInfo
StateInfo: CTypeInfo = LeftInfo if LeftInfo.IsState else RightInfo
if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (TypeSystem._CTypedef,)) or NonStateInfo.PtrCount > 0):
Result.BaseType = NonStateInfo.BaseType
elif NonStateInfo.IsTypedef and NonStateInfo.Name:
if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (TypeSystem._CTypedef,)) or NonStateInfo.PtrCount > 0):
Result.BaseType = NonStateInfo.BaseType
Result.PtrCount = NonStateInfo.PtrCount
Result.IsTypedef = True
Result.Name = NonStateInfo.Name
if NonStateInfo.OriginalType:
Result.OriginalType = NonStateInfo.OriginalType
else:
Result.BaseType = TypeSystem.CStruct(name=NonStateInfo.Name)
Result.IsStruct = True
Result.IsTypedef = True
Result.Name = NonStateInfo.Name
if NonStateInfo.OriginalType:
Result.OriginalType = NonStateInfo.OriginalType
else:
Result.BaseType = TypeSystem.CVoid()
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if not Result.Storage:
Result.Storage = TypeSystem.CExport()
if LeftInfo.Storage and not isinstance(LeftInfo.Storage, TypeSystem.CExport):
Result.Storage = LeftInfo.Storage
elif RightInfo.Storage and not isinstance(RightInfo.Storage, TypeSystem.CExport):
Result.Storage = RightInfo.Storage
if LeftInfo.DataConst or RightInfo.DataConst:
Result.DataConst = True
if LeftInfo.VarConst or RightInfo.VarConst:
Result.VarConst = True
return Result
if LeftInfo.IsPtr or RightInfo.IsPtr:
Result = CTypeInfo()
# 当双方都是指针时(如 (AST | CPtr) | CPtr),PtrCount 应相加
# 而非取 max,否则 AST** 会被折叠为 AST*,导致对象切片问题
if LeftInfo.IsPtr and RightInfo.IsPtr:
Result.PtrCount = LeftInfo.PtrCount + RightInfo.PtrCount
# BaseType 优先取非 void 侧(如 AST),而非 CPtr 的 void
if LeftInfo.BaseType and not isinstance(LeftInfo.BaseType, TypeSystem.CVoid):
Result.BaseType = LeftInfo.BaseType
elif RightInfo.BaseType and not isinstance(RightInfo.BaseType, TypeSystem.CVoid):
Result.BaseType = RightInfo.BaseType
else:
Result.BaseType = TypeSystem.CUnsignedChar()
else:
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
NonPtrInfo = LeftInfo if not LeftInfo.IsPtr else RightInfo
PtrInfo = RightInfo if RightInfo.IsPtr else LeftInfo
if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (TypeSystem._CTypedef,)) or NonPtrInfo.PtrCount > 0):
Result.BaseType = NonPtrInfo.BaseType
elif NonPtrInfo.IsTypedef and NonPtrInfo.Name:
if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (TypeSystem._CTypedef,)) or NonPtrInfo.PtrCount > 0):
Result.BaseType = NonPtrInfo.BaseType
Result.IsTypedef = True
Result.Name = NonPtrInfo.Name
if NonPtrInfo.OriginalType:
Result.OriginalType = NonPtrInfo.OriginalType
else:
Result.BaseType = TypeSystem.CStruct(name=NonPtrInfo.Name)
Result.IsStruct = True
elif PtrInfo.BaseType and (not isinstance(PtrInfo.BaseType, (TypeSystem._CTypedef,)) or PtrInfo.PtrCount > 0):
Result.BaseType = PtrInfo.BaseType
else:
Result.BaseType = TypeSystem.CUnsignedChar()
if LeftInfo.DataConst or RightInfo.DataConst:
Result.DataConst = True
if LeftInfo.VarConst or RightInfo.VarConst:
Result.VarConst = True
if LeftInfo.DataVolatile or RightInfo.DataVolatile:
Result.DataVolatile = True
if LeftInfo.VarVolatile or RightInfo.VarVolatile:
Result.VarVolatile = True
if LeftInfo.Storage:
Result.Storage = LeftInfo.Storage
elif RightInfo.Storage:
Result.Storage = RightInfo.Storage
return Result
if LeftInfo.DataConst or RightInfo.DataConst:
Result = CTypeInfo()
BaseTypeSide = LeftInfo if not LeftInfo.DataConst else RightInfo
QualSide = LeftInfo if LeftInfo.DataConst else RightInfo
Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, TypeSystem.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType
if not Result.BaseType:
Result.BaseType = TypeSystem.CInt()
Result.DataConst = True
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if LeftInfo.VarConst or RightInfo.VarConst:
Result.VarConst = True
if LeftInfo.DataVolatile or RightInfo.DataVolatile:
Result.DataVolatile = True
if LeftInfo.Storage:
Result.Storage = LeftInfo.Storage
elif RightInfo.Storage:
Result.Storage = RightInfo.Storage
return Result
if LeftInfo.DataVolatile or RightInfo.DataVolatile:
Result = CTypeInfo()
BaseTypeSide = LeftInfo if not LeftInfo.DataVolatile else RightInfo
QualSide = LeftInfo if LeftInfo.DataVolatile else RightInfo
Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, TypeSystem.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType
if not Result.BaseType:
Result.BaseType = TypeSystem.CInt()
Result.DataVolatile = True
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if LeftInfo.VarConst or RightInfo.VarConst:
Result.VarConst = True
if LeftInfo.Storage:
Result.Storage = LeftInfo.Storage
elif RightInfo.Storage:
Result.Storage = RightInfo.Storage
return Result
if LeftInfo.Storage or RightInfo.Storage:
Result = CTypeInfo()
BaseTypeSide = LeftInfo if not LeftInfo.Storage else RightInfo
StorageSide = LeftInfo if LeftInfo.Storage else RightInfo
# CExtern | CExport 等价于 State:两边都有 Storage 时设置 IsState
if BaseTypeSide.IsState or StorageSide.IsState or (LeftInfo.Storage and RightInfo.Storage):
Result.IsState = True
Result.BaseType = TypeSystem.CVoid()
Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage
return Result
Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, TypeSystem.CVoid) or BaseTypeSide.PtrCount > 0) else StorageSide.BaseType
if not Result.BaseType:
Result.BaseType = TypeSystem.CInt()
Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if LeftInfo.DataConst or RightInfo.DataConst:
Result.DataConst = True
if LeftInfo.VarConst or RightInfo.VarConst:
Result.VarConst = True
return Result
# 检查是否有位域类型 (Bit)
if LeftInfo.IsBitField:
Result = CTypeInfo()
Result.BaseType = LeftInfo.BaseType if LeftInfo.BaseType else TypeSystem.CInt()
Result.IsBitField = True
Result.BitWidth = LeftInfo.BitWidth
return Result
if RightInfo.IsBitField:
Result = CTypeInfo()
Result.BaseType = RightInfo.BaseType if RightInfo.BaseType else TypeSystem.CInt()
Result.IsBitField = True
Result.BitWidth = RightInfo.BitWidth
return Result
# 处理字节序类型 (BigEndian, LittleEndian)
# 合并两侧:保留非字节序侧的实际类型(如 CUInt64T),取字节序侧的 ByteOrder
if LeftInfo.ByteOrder or RightInfo.ByteOrder:
Result = CTypeInfo()
ByteOrderSide: CTypeInfo = LeftInfo if LeftInfo.ByteOrder else RightInfo
OtherSide: CTypeInfo = RightInfo if LeftInfo.ByteOrder else LeftInfo
if OtherSide.BaseType and (not isinstance(OtherSide.BaseType, (TypeSystem._CTypedef,)) or OtherSide.PtrCount > 0):
Result.BaseType = OtherSide.BaseType
elif ByteOrderSide.BaseType and (not isinstance(ByteOrderSide.BaseType, (TypeSystem._CTypedef,)) or ByteOrderSide.PtrCount > 0):
Result.BaseType = ByteOrderSide.BaseType
else:
Result.BaseType = TypeSystem.CInt()
Result.ByteOrder = LeftInfo.ByteOrder or RightInfo.ByteOrder
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
return Result
if LeftInfo.IsFuncPtr or RightInfo.IsFuncPtr:
Result = CTypeInfo()
FuncPtrSide = LeftInfo if LeftInfo.IsFuncPtr else RightInfo
Result.IsFuncPtr = True
Result.FuncPtrParams = list(FuncPtrSide.FuncPtrParams)
Result.FuncPtrReturn = FuncPtrSide.FuncPtrReturn
if LeftInfo.Storage:
Result.Storage = LeftInfo.Storage
elif RightInfo.Storage:
Result.Storage = RightInfo.Storage
return Result
if LeftInfo.IsTypedef and RightInfo.BaseType:
if LeftInfo.BaseType and (not isinstance(LeftInfo.BaseType, (TypeSystem._CTypedef,)) or LeftInfo.PtrCount > 0):
Result = LeftInfo.Copy()
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if RightInfo.Storage:
Result.Storage = RightInfo.Storage
return Result
return RightInfo
if RightInfo.IsTypedef and LeftInfo.BaseType:
if RightInfo.BaseType and (not isinstance(RightInfo.BaseType, (TypeSystem._CTypedef,)) or RightInfo.PtrCount > 0):
Result = RightInfo.Copy()
Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount)
if LeftInfo.Storage:
Result.Storage = LeftInfo.Storage
return Result
return LeftInfo
if LeftInfo.BaseType:
return LeftInfo
elif RightInfo.BaseType:
return RightInfo
return CTypeInfo()
@staticmethod
def _from_node_subscript(Node: ast.Subscript, SymbolTable: dict | SymbolTable) -> CTypeInfo:
"""处理 ast.Subscript 节点"""
@@ -944,6 +775,31 @@ class TypeAnnotationResolver:
else:
Result.BitWidth = 1
return Result
MarkerName: str | None = None
if isinstance(base, ast.Name):
MarkerName = base.id
elif isinstance(base, ast.Attribute):
MarkerName = base.attr
if MarkerName in ('CPtr', 'rawptr'):
SliceInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.slice, SymbolTable)
Result: CTypeInfo = CTypeInfo()
if SliceInfo and SliceInfo.BaseType and not isinstance(SliceInfo.BaseType, TypeSystem.CVoid):
Result.BaseType = SliceInfo.BaseType
else:
Result.BaseType = TypeSystem.CVoid()
Result.PtrCount = (SliceInfo.PtrCount if SliceInfo else 0) + 1
return TypeAnnotationResolver._ApplyTypeModifiers(Result, Node)
if MarkerName in ('CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
SliceInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.slice, SymbolTable)
Result: CTypeInfo = CTypeInfo()
if SliceInfo and SliceInfo.BaseType:
Result.BaseType = SliceInfo.BaseType
else:
Result.BaseType = TypeSystem.CVoid()
Result.PtrCount = (SliceInfo.PtrCount if SliceInfo else 0) + 1
if MarkerName == 'CArrayPtr':
Result.IsArrayPtr = True
return Result
if IsListAnnotation(Node):
slice_node: ast.AST = Node.slice
elts: list[ast.AST] = []
@@ -1068,12 +924,9 @@ class TypeAnnotationResolver:
return Result
# 泛型类下标(单/多参):list[str] / dict[str][int] / 用户泛型 Box[Node]。
# 特化名与声明端(DeclarationGenerator 泛型分支)同口径,见
# SymbolUtils.ResolveGenericClassSpecName。此前单参泛型下标在下方直接落到
# "未知类型"空 CTypeInfo ⇒ 形参/成员类型退化成 i32 或 void 指针链
# (现场:type_args: list[str]* 的形参 i32;CTypedefNames: list[str] | CPtr → i8*)。
# 表示口径与本文件既有结构体 promotion 逐字一致(BaseType=CStruct + IsStruct +
# Name,PtrCount 保持 0):`X | CPtr` 由 _from_node_binop 取 max → 1 层,
# `rawptr[X]` 由上方分支 +1 → 1 层,均与 declare 侧 %"{sha}.X[*]"* 一致。
# SymbolUtils.ResolveGenericClassSpecName。表示口径与本文件既有结构体
# promotion 逐字一致(BaseType=CStruct + IsStruct + Name,PtrCount 保持 0),
# 与 declare 侧 %"{sha}.X[*]"* 一致。
_Spec: str | None = ResolveGenericClassSpecName(
Node, SymbolTable,
GetStructSha1MapFromSymtab(SymbolTable),
+190 -21
View File
@@ -110,7 +110,7 @@ class TokenStream:
self._PeekCacheIdx: int = -1
self._PeekCacheTok: Token | None = None
# 类型注解解析模式:为 True 时 '*' / '**' 按 C 风格指针后缀处理
# (int* → int | CPtr、int** → 嵌套两层),不按乘法/幂运算消费。
# (int* → CPtr[int]、int** → 嵌套两层),不按乘法/幂运算消费。
self._InTypeAnnotation: bool = False
# 下标实参嵌套层数:'[' 实参内是表达式位置(CArray[T, A * B] 的尺寸),
# 此处的 '*' 在有右操作数时按乘法解析(见 _ParseTerm / _AtOperandAfterStarRun)。
@@ -463,7 +463,7 @@ class ExprParserMixin(TokenStream):
op_type: type | None = None
if tok.Type == OP:
if tok.Value == '*' and self._AtPtrSuffix(left):
# C 风格指针后缀('*' 一层);展开为 base | CPtr 后继续。
# C 风格指针后缀('*' 一层);折叠为 CPtr[...] 后继续。
left = self._ConsumePtrSuffix(left)
continue
if self._InTypeAnnotation and tok.Value == '*':
@@ -1300,7 +1300,7 @@ class ExprParserMixin(TokenStream):
first: N.expr = self.ParseExpr()
# Paren-less C cast `(T*)x`: the inner expression ends with a pointer suffix
# (_Prev() is that suffix's tail token) and the operand follows ')'. Same
# product as `(T*)(x)` / `T*(x)`: a Call whose func is `T | CPtr`.
# product as `(T*)(x)` / `T*(x)`: a Call whose func is `CPtr[T]`.
is_ptr_cast: bool = self._PtrSuffixTail is not None and self._AtOp(')') and self._Prev() is self._PtrSuffixTail
self._SkipNL()
# 生成器表达式 (x for ...)
@@ -1685,29 +1685,66 @@ class ExprParserMixin(TokenStream):
self._FixLoc(a, start)
return a
# 注解起始的修饰词:只在该位置生效,写入类型节点的 Markers 字段。
_TYPE_MARKER_WORDS: frozenset[str] = frozenset({
'const', 'volatile', 'static', 'export', 'extern', 'inline',
})
def _ParseTypeAnnotation(self) -> N.expr:
"""解析类型注解,支持 C 风格指针后缀(* / **)。
"""解析类型注解,支持修饰前缀与 C 风格指针后缀(* / **)。
修饰前缀(任意顺序、可组合)写入类型节点的 AST 字段,不再展开为
`T1 | T2` 联合:
const volatile int → Name('int').Markers = ('const', 'volatile')
x: __attribute__((...)) T → T.Attributes = (...)
BigEndian uint16 → ByteOrder = 'big'
Bit(3) int / Bit[3] int → BitWidth = 3
注解模式开启后,'_ParseTerm'/'_ParsePower' 不再把 '*' / '**' 当
乘法/幂运算消费,而由本方法统一循环消费并展开为嵌套联合类型:
乘法/幂运算消费,而由本方法统一循环消费并折叠为 Subscript:
int* → int | CPtr (i32*)
int** → (int | CPtr) | CPtr (i32**)
int****** → 6 层嵌套 (i32******)
展开为 BinOp(BitOr) 链后,TPC/VPC 现有类型解析(TypeAnnotationResolver
的 PtrCount 相加、VPC TypeGenResolve 的递归 BinOp 分支)零改动即可
生成多级指针 LLVM 类型。
int* → CPtr[int] (i32*)
int** → CPtr[CPtr[int]] (i32**)
int****** → 6 层嵌套 (i32******)
无法解析的后缀形态**响亮失败**(SyntaxError,含 行:列 + 源码片段 + 形态 +
正确写法示例),绝不静默丢弃:注解末尾若仍遗留未被 `_AtPtrSuffix` 接受的
'*'/'**'(如 `a: int * 2` / `a: int* | CPtr`),判据拒绝消费即终止编译
(历史事故:静默退化会产出错误的指针层数)。
(静默退化会产出错误的指针层数)。
值引用参数注解(仅形参位有效):前导 `&` 为 ref 模式、`&temp` 为 temp 模式,
合成联合形态 `T | CRef` / `T | CTempRef` 承载(CRef/CTempRef 非真实类,
合成 Subscript 形态 `CRef[T]` / `CTempRef[T]`(CRef/CTempRef 非真实类,
仅按名字识别;语义侧见 HandlesFunctions / FuncGen)。表达式位的 `&x` 不受影响。
"""
markers: list[str] = []
attributes: list[str] = []
byte_order: str = ''
bit_width: int = 0
while True:
tok: Token = self._Peek()
if tok.Type != NAME:
break
word: str = tok.Value
if word in self._TYPE_MARKER_WORDS:
self._Next()
markers.append(word)
continue
if word == '__attribute__' and self._Peek(1).Type == OP \
and self._Peek(1).Value == '(':
self._Next()
attributes.extend(self._ParseAttributeSpecifier())
continue
if word in ('BigEndian', 'LittleEndian') and self._AtTypeStart(1):
self._Next()
byte_order = 'big' if word == 'BigEndian' else 'little'
continue
if word == 'Bit' and self._Peek(1).Type == OP \
and self._Peek(1).Value in ('(', '['):
self._Next()
bit_width = self._ParseBitWidth()
continue
break
ref_mode: str | None = None
ref_tok: Token = self._Peek()
if self._AtOp('&'):
@@ -1741,6 +1778,9 @@ class ExprParserMixin(TokenStream):
raise SyntaxError(
"[vast] 值引用参数注解缺少类型:`&` 后必须紧跟类型 T"
"(ref:`&T`;temp:`&temp T`)。")
if markers or attributes or byte_order or bit_width:
raise SyntaxError(
"[vast] 类型注解的修饰词后缺少类型(如 `x: const int`)。")
return None
if self._AtPtrSuffix(expr):
expr = self._ConsumePtrSuffix(expr)
@@ -1763,17 +1803,147 @@ class ExprParserMixin(TokenStream):
)
if ref_mode is not None:
expr = self._MakeRefMarker(expr, ref_mode, ref_tok)
self._ApplyTypePrefix(expr, markers, attributes, byte_order, bit_width)
return expr
def _AtTypeStart(self, offset: int) -> bool:
"""offset 处的 token 是否可作为类型起点(用于识别字节序前缀)。"""
tok: Token = self._Peek(offset)
if tok.Type in (NAME, NUMBER, STRING):
return True
return tok.Type == OP and tok.Value in ('[', '(', '&')
@staticmethod
def _SplitTopLevel(text: str, sep: str = ',') -> list[str]:
"""按顶层分隔符切分文本(忽略括号/方括号/花括号内与字符串内的分隔符)。"""
parts: list[str] = []
buf: list[str] = []
depth: int = 0
quote: str = ''
escaped: bool = False
for ch in text:
if quote:
buf.append(ch)
if escaped:
escaped = False
elif ch == '\\':
escaped = True
elif ch == quote:
quote = ''
continue
if ch in ('"', "'"):
quote = ch
buf.append(ch)
continue
if ch in '([{':
depth += 1
elif ch in ')]}':
depth -= 1
if ch == sep and depth == 0:
parts.append(''.join(buf))
buf = []
continue
buf.append(ch)
parts.append(''.join(buf))
return parts
@staticmethod
def _StripOuterParens(text: str) -> str:
"""去掉一对完整包裹文本的圆括号(`((a), (b))` 不误删)。"""
s: str = text.strip()
if not (s.startswith('(') and s.endswith(')')):
return s
depth: int = 0
quote: str = ''
escaped: bool = False
for i, ch in enumerate(s):
if quote:
if escaped:
escaped = False
elif ch == '\\':
escaped = True
elif ch == quote:
quote = ''
continue
if ch in ('"', "'"):
quote = ch
elif ch == '(':
depth += 1
elif ch == ')':
depth -= 1
if depth == 0 and i != len(s) - 1:
return s
if depth != 0:
return s
return s[1:-1].strip()
def _ParseAttributeSpecifier(self) -> tuple[str, ...]:
"""解析 `__attribute__(...)` 的括号内容(调用名已消费),返回属性文本元组。"""
open_tok: Token = self._ExpectOp('(')
depth: int = 1
inner: str = ''
while True:
tok: Token = self._Next()
if tok.Type == ENDMARKER:
raise SyntaxError(
"[vast] __attribute__ 描述符缺少右括号:"
"期望 `__attribute__((aligned(16)))` 形态。")
if tok.Type == OP and tok.Value == '(':
depth += 1
elif tok.Type == OP and tok.Value == ')':
depth -= 1
if depth == 0:
inner = self.Source[open_tok.End:tok.Start].strip()
break
inner = self._StripOuterParens(inner)
return tuple(part.strip() for part in self._SplitTopLevel(inner) if part.strip())
def _ParseBitWidth(self) -> int:
"""解析 `Bit(N)` / `Bit[N]` 的位宽(调用名已消费)。"""
open_tok: Token = self._Next()
close: str = ')' if open_tok.Value == '(' else ']'
self._SkipNL()
width_tok: Token = self._Next()
if width_tok.Type != NUMBER:
raise SyntaxError(
f"[vast] Bit 描述符缺少整数位宽:第 {width_tok.Line} 行"
f"第 {width_tok.Col} 列,期望 `Bit(N)` / `Bit[N]`。")
try:
width: int = int(width_tok.Value.replace('_', ''), 0)
except ValueError as exc:
raise SyntaxError(
f"[vast] Bit 描述符的位宽必须是整数字面量,得到 {width_tok.Value!r}。"
) from exc
self._SkipNL()
self._ExpectOp(close)
return width
@staticmethod
def _ApplyTypePrefix(node: N.expr, markers: list[str], attributes: list[str],
byte_order: str, bit_width: int) -> None:
"""把注解前缀写入类型节点的 Markers / Attributes / ByteOrder / BitWidth。"""
if not hasattr(type(node), 'Markers'):
return
if markers:
existing: tuple[str, ...] = tuple(getattr(node, 'Markers', ()) or ())
node.Markers = tuple(markers) + tuple(m for m in existing if m not in markers)
if attributes:
existing_attrs: tuple[str, ...] = tuple(getattr(node, 'Attributes', ()) or ())
node.Attributes = existing_attrs + tuple(attributes)
if byte_order:
node.ByteOrder = byte_order
if bit_width:
node.BitWidth = bit_width
def _MakeRefMarker(self, base: N.expr, mode: str, tok: Token) -> N.expr:
"""构造值引用标记联合:`base | CRef`(ref)/ `base | CTempRef`(temp)。
"""构造值引用包装:`CRef[T]`(ref)/ `CTempRef[T]`(temp)。
CRef / CTempRef 非真实类,仅作为注解 AST 内的名字标记(语义侧按名字识别)。
"""
marker: N.expr = N.Name(
id='CRef' if mode == 'ref' else 'CTempRef',
ctx=N.Load())
node: N.BinOp = N.BinOp(left=base, op=N.BitOr(), right=marker)
node: N.Subscript = N.Subscript(value=marker, slice=base, ctx=N.Load())
self._FixLoc(node, tok)
return node
@@ -1828,7 +1998,7 @@ class ExprParserMixin(TokenStream):
return False
def _ConsumePtrSuffix(self, expr: N.expr) -> N.expr:
"""消费连续的 C 风格指针后缀('*' 一层 / '**' 两层),展开为 base | CPtr 链。"""
"""消费连续的 C 风格指针后缀('*' 一层 / '**' 两层),折叠为 CPtr[...] 嵌套。"""
while True:
tok: Token = self._Peek()
if tok.Type == OP and tok.Value == '*':
@@ -1921,16 +2091,15 @@ class ExprParserMixin(TokenStream):
def _ConsumePtrSuffixCall(self, base: N.expr, start: Token) -> N.expr:
"""把已认定为 `T*(...)` 的指针后缀强转解析为**调用**。
产物与既有强转形态 `(T | CPtr)(...)` 逐字同形:同为 `ast.Call`
(func = `T` 展开的 `base | CPtr` 链,args/keywords = 括号实参),
产物为 `ast.Call`(func = `CPtr[T]` 指针包装,args/keywords = 括号实参),
不新造第二套 cast 表示。
"""
func: N.expr = self._ConsumePtrSuffix(base)
return self._ParseCallTail(func, start)
def _MakePtrType(self, base: N.expr, tok: Token) -> N.expr:
"""构造一层指针包装:base | CPtr。"""
"""构造一层指针包装:`CPtr[base]`。"""
cptr: N.expr = N.Name(id='CPtr', ctx=N.Load())
node: N.BinOp = N.BinOp(left=base, op=N.BitOr(), right=cptr)
node: N.Subscript = N.Subscript(value=cptr, slice=base, ctx=N.Load())
self._FixLoc(node, tok)
return node
+15 -9
View File
@@ -53,6 +53,12 @@ _POS_ATTRS: tuple[str, ...] = ('lineno', 'col_offset', 'end_lineno', 'end_col_of
# 写入,unparse 还原)。__slots__ 类无 __dict__,必须纳入槽位,否则
# node.Extern = True 抛 AttributeError。
_FUNC_ATTRS: tuple[str, ...] = _POS_ATTRS + ('Extern', 'Export', 'Define')
# 类型注解修饰(由 Parser 直接写入注解节点,不再用 `T1 | T2` 组合表示):
# Markers: ('const','volatile','static','export','extern','inline','state','define','typedef')
# Attributes: ('section(".x")', 'aligned(16)', ...)
# ByteOrder: '' | 'big' | 'little'
# BitWidth: 0 = 非位域
_TYPE_ATTRS: tuple[str, ...] = _POS_ATTRS + ('Markers', 'Attributes', 'ByteOrder', 'BitWidth')
_NODE_DEFS: dict[str, tuple[tuple[str, ...], tuple[str, ...]]] = {
# ---- 模块/交互/表达式顶层 ----
@@ -63,14 +69,14 @@ _NODE_DEFS: dict[str, tuple[tuple[str, ...], tuple[str, ...]]] = {
'Suite': ((), ()),
# ---- 语句 ----
'FunctionDef': (('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), _FUNC_ATTRS),
'AsyncFunctionDef': (('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), _FUNC_ATTRS),
'FunctionDef': (('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), _FUNC_ATTRS + _TYPE_ATTRS),
'AsyncFunctionDef': (('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), _FUNC_ATTRS + _TYPE_ATTRS),
'ClassDef': (('name', 'bases', 'keywords', 'body', 'decorator_list', 'type_params'), _POS_ATTRS),
'Return': (('value',), _POS_ATTRS),
'Delete': (('targets',), _POS_ATTRS),
'Assign': (('targets', 'value', 'type_comment'), _POS_ATTRS),
'AugAssign': (('target', 'op', 'value'), _POS_ATTRS),
'AnnAssign': (('target', 'annotation', 'value', 'simple'), _POS_ATTRS),
'AnnAssign': (('target', 'annotation', 'value', 'simple'), _TYPE_ATTRS),
'For': (('target', 'iter', 'body', 'orelse', 'type_comment'), _POS_ATTRS),
'AsyncFor': (('target', 'iter', 'body', 'orelse', 'type_comment'), _POS_ATTRS),
'While': (('test', 'body', 'orelse'), _POS_ATTRS),
@@ -108,7 +114,7 @@ _NODE_DEFS: dict[str, tuple[tuple[str, ...], tuple[str, ...]]] = {
'Yield': (('value',), _POS_ATTRS),
'YieldFrom': (('value',), _POS_ATTRS),
'Compare': (('left', 'ops', 'comparators'), _POS_ATTRS),
'Call': (('func', 'args', 'keywords'), _POS_ATTRS),
'Call': (('func', 'args', 'keywords'), _TYPE_ATTRS),
# Viper `new` 生命周期分配表达式(软关键字):new [描述符...] T(args)。
# Source/Life 为描述符整数(见 NEW_SRC_*/NEW_LIFE_*);memgr 为 `memgr(x)` 的 x
# (无 memgr 描述符时为 None);func 是被构造的 callee(Name/Attribute/Subscript),
@@ -116,11 +122,11 @@ _NODE_DEFS: dict[str, tuple[tuple[str, ...], tuple[str, ...]]] = {
'New': (('Source', 'Life', 'memgr', 'func', 'args'), _POS_ATTRS),
'FormattedValue': (('value', 'conversion', 'format_spec'), _POS_ATTRS),
'JoinedStr': (('values',), _POS_ATTRS),
'Constant': (('value', 'kind'), _POS_ATTRS + ('int_width', 'int_unsigned')),
'Attribute': (('value', 'attr', 'ctx'), _POS_ATTRS),
'Subscript': (('value', 'slice', 'ctx'), _POS_ATTRS),
'Constant': (('value', 'kind'), _TYPE_ATTRS + ('int_width', 'int_unsigned')),
'Attribute': (('value', 'attr', 'ctx'), _TYPE_ATTRS),
'Subscript': (('value', 'slice', 'ctx'), _TYPE_ATTRS),
'Starred': (('value', 'ctx'), _POS_ATTRS),
'Name': (('id', 'ctx'), _POS_ATTRS),
'Name': (('id', 'ctx'), _TYPE_ATTRS),
'List': (('elts', 'ctx'), _POS_ATTRS),
'Tuple': (('elts', 'ctx'), _POS_ATTRS),
'Slice': (('lower', 'upper', 'step'), _POS_ATTRS),
@@ -145,7 +151,7 @@ _NODE_DEFS: dict[str, tuple[tuple[str, ...], tuple[str, ...]]] = {
'comprehension': (('target', 'iter', 'ifs', 'is_async'), ()),
'ExceptHandler': (('type', 'name', 'body'), _POS_ATTRS),
'arguments': (('posonlyargs', 'args', 'vararg', 'kwonlyargs', 'kw_defaults', 'kwarg', 'defaults'), ()),
'arg': (('arg', 'annotation', 'type_comment'), _POS_ATTRS),
'arg': (('arg', 'annotation', 'type_comment'), _TYPE_ATTRS),
'keyword': (('arg', 'value'), _POS_ATTRS),
'alias': (('name', 'asname'), _POS_ATTRS),
'withitem': (('context_expr', 'optional_vars'), ()),
+132 -52
View File
@@ -166,27 +166,37 @@ class Parser(ExprParserMixin):
tok: Token = self._Peek()
if tok.Type == NAME:
v: str = tok.Value
# extern 函数声明(FFI,等价 State)——必须在软关键字 def 分派之前
# extern:变量声明 `extern 名字: 类型`(禁止初值)与函数声明
# `extern [def] 名字(...)` 共用起始关键字;第二个 token 是 NAME 且
# 再后随 ':' / '=' 时按变量声明解析,否则按函数声明解析。
if v == 'extern':
if self._IsStorageVarStart():
return self._ParseStorageVar('extern')
return self._ParseExternDef()
# export 函数声明(等价 CExport,裸名导出不增加 SHA1 头)——
# 必须在软关键字 def 分派之前
# export:变量声明 `export 名字: 类型 [= 初值]` 与函数声明
# `export [def] 名字(...)` 同理分派。
if v == 'export':
if self._IsStorageVarStart():
return self._ParseStorageVar('export')
return self._ParseExportDef()
# static 存储类软关键字(已从"注解位置"迁出为**语句起始前置**修饰符):
# 仅 `static def 名字` 形态判定为函数定义——判据必须同时要求第二个 token
# 是 `def`,故 `static = 5` / `static x = 5` 不会被误吃成函数定义。
# 变量形式 `static 名字: 类型 = 值` 不在本层处理,由 SymbolUtils 的前置
# 修饰符展开统一脱糖为 `名字: CStatic | 类型 = 值`。
if (v == 'static' and self._Peek(1).Type == NAME
and self._Peek(1).Value == 'def'):
return self._ParseStaticDef()
# define 宏函数定义(与 def 语义一致,返回注解自动追加 CDefine
# 标记为宏函数;软关键字:仅"define + 标识符"形态才判定为函数定义,
# 变量名/调用(define = 5、define(x))不受影响)——必须在软关键字
# def 分派之前
# static:`static def 名字` 为函数定义;`static 名字: 类型` 为变量声明。
# 判据要求第二个 token 是 NAME 且再后随 ':' / '=',故
# `static = 5` / `static x` 不会被误吃成修饰声明。
if v == 'static':
if (self._Peek(1).Type == NAME
and self._Peek(1).Value == 'def'):
return self._ParseStaticDef()
if self._IsStorageVarStart():
return self._ParseStorageVar('static')
# define:`define 名字 = 值` / `define 名字: 类型 = 值` 为编译期常量
# 声明;`define 名字(...)` / `define 名字[T](...)` 为宏函数定义。
if v == 'define' and self._Peek(1).Type == NAME:
if self._IsStorageVarStart():
return self._ParseDefineVar()
return self._ParseDefineDef()
# typedef 名字 = 类型:类型别名声明(右值按类型注解解析)。
if v == 'typedef' and self._Peek(1).Type == NAME:
return self._ParseTypedefVar()
# virtual / novirtual 修饰符(软关键字):只在"语句起始 + 紧跟 class/def"
# 时生效,合成既有装饰器 @CVTable / @NoVTable(见 _ParseVirtualModified)。
# 放在 def/class 分派之前:修饰符必须先被消费,class/def 才能照常分派。
@@ -285,6 +295,102 @@ class Parser(ExprParserMixin):
return self._ParseDecorated()
return self._ParseSimpleStmt()
# ==================================================================
# 语句级变量修饰形态(static / export / extern / define / typedef)
# ==================================================================
def _IsStorageVarStart(self) -> bool:
"""当前修饰词之后是否为变量声明形态:`修饰词 名字 :` 或 `修饰词 名字 =`。"""
if self._Peek(1).Type != NAME:
return False
nxt: Token = self._Peek(2)
return nxt.Type == OP and nxt.Value in (':', '=')
@staticmethod
def _AddTypeMarkers(node: N.AST, marker: str) -> None:
"""把修饰词追加到类型节点的 Markers 字段(保持出现顺序、去重)。"""
if not hasattr(type(node), 'Markers'):
return
existing: tuple[str, ...] = tuple(getattr(node, 'Markers', ()) or ())
if marker not in existing:
node.Markers = existing + (marker,)
def _ParseStorageVar(self, marker: str) -> N.AnnAssign:
"""解析 `static|export|extern 名字: 类型 [= 初值]` 为 AnnAssign。
`extern` 变量只声明不定义,禁止初值。
"""
start: Token = self._Next() # 修饰词
name_tok: Token = self._ExpectName()
if not self._AtOp(':'):
raise SyntaxError(
f"[vast] `{marker} 名字` 变量声明必须带类型注解:"
f"期望 `{marker} {name_tok.Value}: 类型"
f"{' [= 初值]' if marker != 'extern' else ''}`。")
self._Next() # ':'
annotation: N.expr = self._ParseTypeAnnotation()
value: N.expr | None = None
if self._AtOp('='):
if marker == 'extern':
raise SyntaxError(
f"[vast] extern 变量声明不能带初始值(符号定义在外部):"
f"`extern {name_tok.Value}: 类型`。")
self._Next()
value = self.ParseExpr()
self._AddTypeMarkers(annotation, marker)
target: N.Name = N.Name(id=name_tok.Value, ctx=N.Store())
self._FixLoc(target, name_tok)
node: N.AnnAssign = N.AnnAssign(
target=target, annotation=annotation, value=value, simple=1)
self._FixLoc(node, start)
return node
def _ParseDefineVar(self) -> N.AnnAssign:
"""解析 `define 名字[: 类型] = 值` 为编译期常量声明(Markers += 'define')。"""
start: Token = self._Next() # 'define'
name_tok: Token = self._ExpectName()
annotation: N.expr | None = None
if self._AtOp(':'):
self._Next()
annotation = self._ParseTypeAnnotation()
if not self._AtOp('='):
raise SyntaxError(
f"[vast] define 常量声明缺少初值:"
f"期望 `define {name_tok.Value}[: 类型] = 值`。")
self._Next() # '='
value: N.expr = self.ParseExpr()
if annotation is None:
# 未标注类型:注解占位为 CDefine(Markers 仍承载 'define')。
annotation = N.Name(id='CDefine', ctx=N.Load())
self._FixLoc(annotation, start)
self._AddTypeMarkers(annotation, 'define')
target: N.Name = N.Name(id=name_tok.Value, ctx=N.Store())
self._FixLoc(target, name_tok)
node: N.AnnAssign = N.AnnAssign(
target=target, annotation=annotation, value=value, simple=1)
self._FixLoc(node, start)
return node
def _ParseTypedefVar(self) -> N.AnnAssign:
"""解析 `typedef 名字 = 类型` 为类型别名声明(Markers += 'typedef')。
右值按类型注解解析(支持 `T*` 等 C 风格后缀)。
"""
start: Token = self._Next() # 'typedef'
name_tok: Token = self._ExpectName()
if not self._AtOp('='):
raise SyntaxError(
f"[vast] typedef 语法错误:"
f"期望 `typedef {name_tok.Value} = 类型`。")
self._Next() # '='
type_node: N.expr = self._ParseTypeAnnotation()
self._AddTypeMarkers(type_node, 'typedef')
target: N.Name = N.Name(id=name_tok.Value, ctx=N.Store())
self._FixLoc(target, name_tok)
node: N.AnnAssign = N.AnnAssign(
target=target, annotation=type_node, value=type_node, simple=1)
self._FixLoc(node, start)
return node
# ==================================================================
# fallthrough 关键字(语句级)
# ==================================================================
@@ -422,12 +528,11 @@ class Parser(ExprParserMixin):
@staticmethod
def _IsCTypedefAnnotation(annotation: N.expr | None) -> bool:
"""注解是否为 typedef 标记(裸 `CTypedef` / `CTypedef` / 含它的 `|` 联合)。
"""注解是否为 typedef 标记(裸 `CTypedef` / 含它的 `|` 联合)。
用于把 typedef 的右值按**类型位置**解析(`X: CTypedef = const uint16*`
里的 `*` 后缀由 _ParseTypeAnnotation 消费,与注解位同一规则;描述符
`const`/`volatile` 已由 SymbolUtils._ExpandTypeDescriptors 在文本层展开)。
仅按标记名判定,不依赖 import 别名表(与 VPC `_IsCTypedefAnnotation` 同口径)。
用于把 typedef 的右值按**类型位置**解析(`X: CTypedef = T` 里的 `*`
后缀由 _ParseTypeAnnotation 消费,与注解位同一规则)。仅按标记名判定,
不依赖 import 别名表(与 VPC `_IsCTypedefAnnotation` 同口径)。
"""
if annotation is None:
return False
@@ -921,7 +1026,7 @@ class Parser(ExprParserMixin):
return node
def _ParseExternDef(self, decorators: list[N.expr] | None = None) -> N.FunctionDef:
"""解析 extern 函数声明(FFI,与 State 作用相当)。
"""解析 extern 函数声明(FFI,仅声明不定义)。
允许语法(均声明不定义,不生成函数体):
extern def A(x: int) -> int: pass
@@ -929,9 +1034,8 @@ class Parser(ExprParserMixin):
extern def A(x: int) -> int
extern A(x: int) -> int
产出标准 FunctionDef 节点,返回注解改写为 ``<原类型> | State``
以复用 TPC 的 IsState 路径;并设自定义属性 ``Extern = True``
供 Unparser 还原 extern 语法。
产出标准 FunctionDef 节点,``Extern = True`` 供 Unparser 还原 extern 语法;
返回注解保持源码原样(不追加 `| State`)。
"""
start: Token = self._Next() # 'extern'
if self._AtName('def'):
@@ -955,12 +1059,6 @@ class Parser(ExprParserMixin):
type_comment=None, type_params=type_params,
)
node.Extern = True
# 返回注解改写为 <原类型> | State,使 TPC 识别为 State 函数(仅声明)
state_attr: N.expr = N.Name(id='State', ctx=N.Load())
if returns is not None:
node.returns = N.BinOp(left=returns, op=N.BitOr(), right=state_attr)
else:
node.returns = state_attr
self._FixLoc(node, start)
return node
@@ -973,9 +1071,8 @@ class Parser(ExprParserMixin):
export def A(x: int) -> int
export A(x: int) -> int
产出标准 FunctionDef 节点,返回注解改写为 ``<原类型> | CExport``
以复用 TPC 的 CExport 路径(符号名不增加 SHA1 前缀);并设自定义
属性 ``Export = True`` 供 Unparser 还原 export 语法。
产出标准 FunctionDef 节点,``Export = True`` 供 Unparser 还原 export 语法;
返回注解保持源码原样(不追加 `| CExport`)。
"""
start: Token = self._Next() # 'export'
if self._AtName('def'):
@@ -999,13 +1096,6 @@ class Parser(ExprParserMixin):
type_comment=None, type_params=type_params,
)
node.Export = True
# 返回注解改写为 <原类型> | CExport,使 TPC 识别为 CExport 函数
# (导出裸名,不增加模块 SHA1 头;有条件情况下导出)
export_attr: N.expr = N.Name(id='CExport', ctx=N.Load())
if returns is not None:
node.returns = N.BinOp(left=returns, op=N.BitOr(), right=export_attr)
else:
node.returns = export_attr
self._FixLoc(node, start)
return node
@@ -1072,11 +1162,8 @@ class Parser(ExprParserMixin):
define A(x: int) -> int: ...
define A(x: int): ...
产出标准 FunctionDef 节点,返回注解改写为 ``<原类型> | CDefine``
(无显式返回注解时单独 ``CDefine``),使 TPC/VPC 复用既有的
CDefine 宏函数识别路径(StubGen 原样保留生成 C #define、
alwaysinline 内联);并设自定义属性 ``Define = True`` 供
Unparser 还原 define 语法。
产出标准 FunctionDef 节点,``Define = True`` 供 Unparser 还原 define 语法;
返回注解保持源码原样(不追加 `| CDefine`)。
"""
start: Token = self._Next() # 'define'
name_tok: Token = self._ExpectName()
@@ -1096,13 +1183,6 @@ class Parser(ExprParserMixin):
type_comment=None, type_params=type_params,
)
node.Define = True
# 返回注解改写为 <原类型> | CDefine,使下游识别为宏函数
# (StubGen 保留原样输出 C #define;TPC 标记 alwaysinline 内联)
define_attr: N.expr = N.Name(id='CDefine', ctx=N.Load())
if returns is not None:
node.returns = N.BinOp(left=returns, op=N.BitOr(), right=define_attr)
else:
node.returns = define_attr
self._FixLoc(node, start)
return node
+74 -36
View File
@@ -12,8 +12,17 @@ from lib.vast import Nodes as N
class Unparser:
"""递归将 vast 节点还原为源码文本。"""
# 语句级修饰词:由 _AnnAssign 渲染在目标名之前(而非类型前)。
_STATEMENT_MARKERS: frozenset[str] = frozenset({
'static', 'export', 'extern', 'define', 'typedef',
})
# 未显式标注类型的 define 常量以 CDefine 作为注解占位,还原时省略类型部分。
_IMPLICIT_ANNOTATION_NAMES: frozenset[str] = frozenset({'CDefine'})
def __init__(self) -> None:
self._Depth: int = 0
# 当前正在渲染的注解上被语句级修饰词消费掉的 Markers(不再输出为类型前缀)。
self._SuppressedMarkers: frozenset[str] = frozenset()
# ------------------------------------------------------------------
# 顶层
@@ -87,21 +96,6 @@ class Unparser:
params: str = self._Arguments(node.args)
ret: str = ''
returns: N.expr | None = node.returns
if is_extern and isinstance(returns, N.BinOp) and isinstance(returns.op, N.BitOr):
# 还原 extern 原始注解:去掉改写时追加的 | State
right: N.expr = returns.right
if isinstance(right, N.Name) and right.id == 'State':
returns = returns.left
if is_export and isinstance(returns, N.BinOp) and isinstance(returns.op, N.BitOr):
# 还原 export 原始注解:去掉改写时追加的 | CExport
right = returns.right
if isinstance(right, N.Name) and right.id == 'CExport':
returns = returns.left
if is_define and isinstance(returns, N.BinOp) and isinstance(returns.op, N.BitOr):
# 还原 define 原始注解:去掉改写时追加的 | CDefine
right = returns.right
if isinstance(right, N.Name) and right.id == 'CDefine':
returns = returns.left
if returns is not None:
ret = f' -> {self._expr(returns)}'
body: str = self._Block(node.body)
@@ -134,8 +128,56 @@ class Unparser:
return f'{self._expr(node.target)} {op}= {self._expr(node.value)}'
def _AnnAssign(self, node: N.AnnAssign) -> str:
val: str = f' = {self._expr(node.value)}' if node.value is not None else ''
return f'{self._expr(node.target)}: {self._expr(node.annotation)}{val}'
annotation: N.expr = node.annotation
markers: tuple[str, ...] = tuple(getattr(annotation, 'Markers', ()) or ())
saved: frozenset[str] = self._SuppressedMarkers
self._SuppressedMarkers = frozenset(
m for m in markers if m in self._STATEMENT_MARKERS)
try:
type_text: str = self._expr(annotation)
target_text: str = self._expr(node.target)
if 'typedef' in markers:
rhs: str = (self._expr(node.value) if node.value is not None
else type_text)
return f'typedef {target_text} = {rhs}'
if 'define' in markers:
head: str = f'define {target_text}'
implicit: bool = (
isinstance(annotation, N.Name)
and annotation.id in self._IMPLICIT_ANNOTATION_NAMES)
if not implicit:
head += f': {type_text}'
if node.value is not None:
head += f' = {self._expr(node.value)}'
return head
stmt_prefix: str = ''.join(
f'{m} ' for m in ('extern', 'export', 'static') if m in markers)
val: str = f' = {self._expr(node.value)}' if node.value is not None else ''
return f'{stmt_prefix}{target_text}: {type_text}{val}'
finally:
self._SuppressedMarkers = saved
def _TypeModifierPrefix(self, node: N.AST) -> str:
"""把注解节点的 Markers / Attributes / ByteOrder / BitWidth 还原为前缀关键字。"""
parts: list[str] = [
m for m in (getattr(node, 'Markers', ()) or ())
if m not in self._SuppressedMarkers
]
attrs: tuple[str, ...] = tuple(getattr(node, 'Attributes', ()) or ())
if attrs:
parts.append('__attribute__((' + ', '.join(attrs) + '))')
order: str = getattr(node, 'ByteOrder', '') or ''
if order == 'big':
parts.append('BigEndian')
elif order == 'little':
parts.append('LittleEndian')
width: int = getattr(node, 'BitWidth', 0) or 0
if width:
parts.append(f'Bit({width})')
return ''.join(f'{p} ' for p in parts)
def _WithTypeModifiers(self, node: N.AST, text: str) -> str:
return self._TypeModifierPrefix(node) + text
def _For(self, node: N.For) -> str:
kw: str = 'async for' if isinstance(node, N.AsyncFor) else 'for'
@@ -344,29 +386,24 @@ class Unparser:
return f'{out} {callee}'
def _Name(self, node: N.Name) -> str:
return node.id
return self._WithTypeModifiers(node, node.id)
def _Constant(self, node: N.Constant) -> str:
v = node.value
if v is Ellipsis:
return '...'
if v is None:
return 'None'
if v is True:
return 'True'
if v is False:
return 'False'
if isinstance(v, str):
return repr(v)
if isinstance(v, bytes):
return repr(v)
if isinstance(v, complex):
# 复数文本
return repr(v)
return repr(v)
text = '...'
elif v is None:
text = 'None'
elif v is True:
text = 'True'
elif v is False:
text = 'False'
else:
text = repr(v)
return self._WithTypeModifiers(node, text)
def _Attribute(self, node: N.Attribute) -> str:
return f'{self._expr(node.value)}.{node.attr}'
return self._WithTypeModifiers(node, f'{self._expr(node.value)}.{node.attr}')
def _Call(self, node: N.Call) -> str:
args: list[str] = [self._expr(a) for a in node.args]
@@ -375,7 +412,7 @@ class Unparser:
args.append(f'**{self._expr(kw.value)}')
else:
args.append(f'{kw.arg}={self._expr(kw.value)}')
return f'{self._expr(node.func)}({", ".join(args)})'
return self._WithTypeModifiers(node, f'{self._expr(node.func)}({", ".join(args)})')
_BINOP_OPS: dict[type, str] = {
N.Add: '+', N.Sub: '-', N.Mult: '*', N.Div: '/', N.FloorDiv: '//',
@@ -410,7 +447,8 @@ class Unparser:
return ' '.join(parts)
def _Subscript(self, node: N.Subscript) -> str:
return f'{self._expr(node.value)}[{self._SliceLike(node.slice)}]'
return self._WithTypeModifiers(
node, f'{self._expr(node.value)}[{self._SliceLike(node.slice)}]')
def _SliceLike(self, node: N.AST) -> str:
if isinstance(node, N.Slice):
+14 -2
View File
@@ -62,10 +62,22 @@ def _ParsePure(source: str, mode: str) -> AST:
# 信息(文件名 + 异常)。该回退**不会**改变产出——纯 Python 是本包语义基准,
# 故绝不静默产出与纯 Python 不同的 AST。连续相同的(文件, 异常)只打印一次。
_VAST_C_PARSE = None
_VAST_C_STALE = False
try:
from lib.vast_c import parse as _VAST_C_PARSE
import glob as _glob
_vast_c_dir: str = _os.path.join(_os.path.dirname(_os.path.abspath(__file__)), '..', 'vast_c')
_vast_c_src: str = _os.path.join(_vast_c_dir, 'vast_c.c')
_vast_c_pyd: list[str] = _glob.glob(_os.path.join(_vast_c_dir, '_parser*.pyd'))
if _vast_c_pyd and _os.path.exists(_vast_c_src):
if max(_os.path.getmtime(_f) for _f in _vast_c_pyd) < _os.path.getmtime(_vast_c_src):
_VAST_C_STALE = True
except Exception:
_VAST_C_PARSE = None
_VAST_C_STALE = False
if not _VAST_C_STALE:
try:
from lib.vast_c import parse as _VAST_C_PARSE
except Exception:
_VAST_C_PARSE = None
_CFallbackSeen: set = set()
+322 -83
View File
@@ -2557,27 +2557,33 @@ static PyObject *ParseArith(Parser *P) {
/* ============ C 风格指针后缀(* / **,对齐 vast ExprParser) ============ */
/* 构造一层指针包装 base | t.CPtr(对齐 Python _MakePtrType)。 */
static PyObject *MakePtrType(Parser *P, PyObject *Base, Token *Tok) {
PyObject *CPtr = MakeTAttrNode(P, "CPtr");
if (CPtr == NULL) {
/* 构造类型包装 Subscript(Name(WrapperName), Inner):CPtr[T] / CRef[T] / CTempRef[T]。 */
static PyObject *MakeTypeWrapperSubscript(Parser *P, const char *WrapperName,
PyObject *Inner, Token *Tok) {
PyObject *Wrapper = MakeTAttrNode(P, WrapperName);
if (Wrapper == NULL) {
return NULL;
}
PyObject *Op = MakeSingleton(P, "BitOr");
if (Op == NULL) {
Py_DECREF(CPtr);
PyObject *Load = MakeCtx(P, "Load");
if (Load == NULL) {
Py_DECREF(Wrapper);
return NULL;
}
PyObject *Argv[3] = { Base, Op, CPtr };
PyObject *Node = NewNode(P, "BinOp", Argv, 3);
Py_DECREF(Op);
Py_DECREF(CPtr);
PyObject *Argv[3] = { Wrapper, Inner, Load };
PyObject *Node = NewNode(P, "Subscript", Argv, 3);
Py_DECREF(Wrapper);
Py_DECREF(Load);
if (Node != NULL) {
FixLoc(P, Node, Tok);
}
return Node;
}
/* 构造一层指针包装 CPtr[T](对齐 Python _MakePtrType)。 */
static PyObject *MakePtrType(Parser *P, PyObject *Base, Token *Tok) {
return MakeTypeWrapperSubscript(P, "CPtr", Base, Tok);
}
/* 判定当前位置的 '*'/'**' 串是否为 C 风格指针后缀(作用于"类型原子"节点)。
*
* 判据(两条同时成立,对齐 Python ExprParser._AtPtrSuffix):
@@ -2712,13 +2718,295 @@ static PyObject *ConsumePtrSuffixCall(Parser *P, PyObject *Base, Token *Start) {
return Call;
}
/* ============ 类型注解修饰前缀(const/volatile/... / __attribute__ / 字节序) ============ */
static int IsSpaceByte(char C) {
return C == ' ' || C == '\t' || C == '\r' || C == '\n';
}
/* 追加一个字符串到惰性创建的 Python list;失败返回 0。 */
static int AppendStringItem(PyObject **List, const char *Text, Py_ssize_t Len) {
if (*List == NULL) {
*List = NewList();
if (*List == NULL) {
return 0;
}
}
PyObject *Item = PyUnicode_FromStringAndSize(Text, Len);
if (Item == NULL) {
return 0;
}
int Rc = PyList_Append(*List, Item);
Py_DECREF(Item);
return Rc == 0;
}
/* 追加单个 __attribute__ 属性(去掉首尾空白)。 */
static int AppendAttributeSlice(PyObject **List, const char *Text, Py_ssize_t Len) {
while (Len > 0 && IsSpaceByte(*Text)) {
Text++;
Len--;
}
while (Len > 0 && IsSpaceByte(Text[Len - 1])) {
Len--;
}
if (Len == 0) {
return 1;
}
return AppendStringItem(List, Text, Len);
}
/* 从 `__attribute__((...))` 源码片段提取属性列表,按顶层逗号拆分后写入 List。
* 例:__attribute__((section(".x"), aligned(16))) -> ["section(\".x\")", "aligned(16)"] */
static int AppendAttributesFromText(PyObject **List, const char *Text, Py_ssize_t Len) {
Py_ssize_t I = 0;
while (I < Len && Text[I] != '(') {
I++;
}
if (I >= Len) {
return 1;
}
I++; /* 跳过 __attribute__ 后的 '(' */
Py_ssize_t J = Len;
while (J > I && Text[J - 1] != ')') {
J--;
}
if (J <= I) {
return 1;
}
J--; /* 去掉与之配对的 ')' */
while (I < J && IsSpaceByte(Text[I])) {
I++;
}
while (J > I && IsSpaceByte(Text[J - 1])) {
J--;
}
/* GNU 双括号形式 __attribute__((...)):剥掉内层一对括号 */
if (J - I >= 2 && Text[I] == '(' && Text[J - 1] == ')') {
I++;
J--;
}
Py_ssize_t Start = I;
int Depth = 0;
char Quote = 0;
for (Py_ssize_t K = I; K < J; K++) {
char C = Text[K];
if (Quote != 0) {
if (C == '\\' && K + 1 < J) {
K++;
} else if (C == Quote) {
Quote = 0;
}
continue;
}
if (C == '"' || C == '\'') {
Quote = C;
} else if (C == '(' || C == '[' || C == '{') {
Depth++;
} else if (C == ')' || C == ']' || C == '}') {
if (Depth > 0) {
Depth--;
}
} else if (C == ',' && Depth == 0) {
if (!AppendAttributeSlice(List, Text + Start, K - Start)) {
return 0;
}
Start = K + 1;
}
}
return AppendAttributeSlice(List, Text + Start, J - Start);
}
/* 下一 token 能否作为类型起点(前缀修饰后必须仍跟着实际类型)。 */
static int TokStartsType(Parser *P, int Off) {
Token *T = PeekTok(P, Off);
if (T->Kind == TK_NAME) {
return 1;
}
return T->Kind == TK_OP
&& (TokIsOp(T, "&") || TokIsOp(T, "[") || TokIsOp(T, "("));
}
/* 消费注解前缀:const/volatile/static/export/extern/inline/state/define/typedef、
* __attribute__((...))、BigEndian/bigend、LittleEndian/littlend。
* 裸标记名(后面没有类型)不消费,按普通类型名解析。 */
static int ParseTypePrefixes(Parser *P, PyObject **Markers, PyObject **Attributes,
const char **ByteOrder) {
for (;;) {
Token *T = PeekTok(P, 0);
if (T->Kind != TK_NAME || !TokStartsType(P, 1)) {
break;
}
if (TokIsName(T, "__attribute__")) {
if (!TokIsOp(PeekTok(P, 1), "(")) {
break;
}
Token *AttrTok = NextTok(P);
const char *End = NULL;
int Depth = 0;
for (;;) {
Token *U = PeekTok(P, 0);
if (U->Kind == TK_ENDMARKER) {
SyntaxErrorAt(P, U, "`__attribute__(...)` 括号未闭合");
return 0;
}
NextTok(P);
if (TokIsOp(U, "(")) {
Depth++;
} else if (TokIsOp(U, ")")) {
Depth--;
if (Depth == 0) {
End = U->End;
break;
}
}
}
if (!AppendAttributesFromText(Attributes, AttrTok->Start, End - AttrTok->Start)) {
return 0;
}
continue;
}
static const char *MarkerNames[] = {
"const", "volatile", "static", "export", "extern",
"inline", "state", "define", "typedef"
};
const char *Marker = NULL;
for (size_t I = 0; I < sizeof(MarkerNames) / sizeof(MarkerNames[0]); I++) {
if (TokIsName(T, MarkerNames[I])) {
Marker = MarkerNames[I];
break;
}
}
if (Marker != NULL) {
if (!AppendStringItem(Markers, Marker, (Py_ssize_t)strlen(Marker))) {
return 0;
}
NextTok(P);
continue;
}
if (TokIsName(T, "BigEndian") || TokIsName(T, "bigend")) {
*ByteOrder = "big";
NextTok(P);
continue;
}
if (TokIsName(T, "LittleEndian") || TokIsName(T, "littlend")) {
*ByteOrder = "little";
NextTok(P);
continue;
}
break;
}
return 1;
}
/* 名称或属性名是否等于 Name(Name.id / Attribute.attr)。 */
static int IsNameOrAttrNamed(PyObject *Node, const char *Name) {
const char *Field = NodeIs(Node, "Name") ? "id"
: (NodeIs(Node, "Attribute") ? "attr" : NULL);
if (Field == NULL) {
return 0;
}
PyObject *V = PyObject_GetAttrString(Node, Field);
if (V == NULL) {
PyErr_Clear();
return 0;
}
int Hit = PyUnicode_Check(V) && PyUnicode_CompareWithASCIIString(V, Name) == 0;
Py_DECREF(V);
return Hit;
}
/* Constant 节点的整数值;非整数返回 0。 */
static int ConstantIntValue(PyObject *Node, long *Out) {
if (Node == NULL || !NodeIs(Node, "Constant")) {
return 0;
}
PyObject *V = PyObject_GetAttrString(Node, "value");
if (V == NULL) {
PyErr_Clear();
return 0;
}
int Ok = 0;
if (PyLong_Check(V)) {
long L = PyLong_AsLong(V);
if (L == -1 && PyErr_Occurred()) {
PyErr_Clear();
} else {
*Out = L;
Ok = 1;
}
}
Py_DECREF(V);
return Ok;
}
/* Bit(N) / Bit[N] 注解:设 BitWidth(无法求值宽度时记 1)。 */
static void ApplyBitWidthAttr(PyObject *Node) {
PyObject *Value = NULL;
PyObject *WidthNode = NULL;
if (NodeIs(Node, "Call")) {
Value = PyObject_GetAttrString(Node, "func");
if (Value != NULL && IsNameOrAttrNamed(Value, "Bit")) {
PyObject *Args = PyObject_GetAttrString(Node, "args");
if (Args != NULL && PyList_Check(Args) && PyList_GET_SIZE(Args) > 0) {
WidthNode = PyList_GET_ITEM(Args, 0);
Py_INCREF(WidthNode);
}
Py_XDECREF(Args);
}
} else if (NodeIs(Node, "Subscript")) {
Value = PyObject_GetAttrString(Node, "value");
if (Value != NULL && IsNameOrAttrNamed(Value, "Bit")) {
WidthNode = PyObject_GetAttrString(Node, "slice");
}
}
if (WidthNode != NULL) {
long Width = 0;
SetAttrLong(Node, "BitWidth", ConstantIntValue(WidthNode, &Width) ? Width : 1);
Py_DECREF(WidthNode);
}
Py_XDECREF(Value);
}
/* 把前缀修饰写入注解节点的 Markers / Attributes / ByteOrder。 */
static void ApplyTypeModifiers(PyObject *Node, PyObject *Markers, PyObject *Attributes,
const char *ByteOrder) {
if (Markers != NULL && PyList_GET_SIZE(Markers) > 0) {
if (PyObject_SetAttrString(Node, "Markers", Markers) < 0) {
PyErr_Clear();
}
}
if (Attributes != NULL && PyList_GET_SIZE(Attributes) > 0) {
if (PyObject_SetAttrString(Node, "Attributes", Attributes) < 0) {
PyErr_Clear();
}
}
if (ByteOrder != NULL) {
PyObject *Order = PyUnicode_FromString(ByteOrder);
if (Order != NULL) {
if (PyObject_SetAttrString(Node, "ByteOrder", Order) < 0) {
PyErr_Clear();
}
Py_DECREF(Order);
}
}
}
/* 类型注解入口:置注解模式标志(对齐 Python ExprParser._ParseTypeAnnotation)。
*
* 值引用参数注解(仅形参位有效,对齐纯 Python 端):
* 前导 '&' + 可选名 'temp',合成联合形态 base | t.CRef(ref)/ base | t.CTempRef(temp)。
* 前导 '&' + 可选名 'temp',构造 Subscript(Name('CRef'), T) / Subscript(Name('CTempRef'), T)。
* CRef/CTempRef 非真实类,仅作注解 AST 内的名字标记(语义侧按名字识别)。
* '&'/'&temp' 之后缺类型(行尾 / ')' / ',' / ':' / '=' / ']' / '}' / ';')时响亮失败。 */
static PyObject *ParseTypeAnnotation(Parser *P) {
PyObject *Markers = NULL;
PyObject *Attributes = NULL;
const char *ByteOrder = NULL;
if (!ParseTypePrefixes(P, &Markers, &Attributes, &ByteOrder)) {
Py_XDECREF(Markers);
Py_XDECREF(Attributes);
return NULL;
}
int RefTemp = 0; /* 0=非值引用 1=ref 2=temp */
Token *RefTok = PeekTok(P, 0);
if (AtOp(P, "&")) {
@@ -2737,6 +3025,8 @@ static PyObject *ParseTypeAnnotation(Parser *P) {
|| TokIsOp(End, ";")) {
SyntaxErrorAt(P, End,
"值引用参数注解缺少类型:`&` 后必须紧跟类型 T(ref:`&T`;temp:`&temp T`)");
Py_XDECREF(Markers);
Py_XDECREF(Attributes);
return NULL;
}
}
@@ -2745,31 +3035,26 @@ static PyObject *ParseTypeAnnotation(Parser *P) {
PyObject *Node = ParseExpr(P);
P->InTypeAnnotation = Saved;
if (Node == NULL) {
Py_XDECREF(Markers);
Py_XDECREF(Attributes);
return NULL;
}
if (RefTemp == 0) {
return Node;
}
PyObject *Marker = MakeTAttrNode(P, RefTemp == 2 ? "CTempRef" : "CRef");
if (Marker == NULL) {
if (RefTemp != 0) {
PyObject *Wrap = MakeTypeWrapperSubscript(
P, RefTemp == 2 ? "CTempRef" : "CRef", Node, RefTok);
Py_DECREF(Node);
return NULL;
if (Wrap == NULL) {
Py_XDECREF(Markers);
Py_XDECREF(Attributes);
return NULL;
}
Node = Wrap;
}
PyObject *Op = MakeSingleton(P, "BitOr");
if (Op == NULL) {
Py_DECREF(Node);
Py_DECREF(Marker);
return NULL;
}
PyObject *Argv[3] = { Node, Op, Marker };
PyObject *Wrap = NewNode(P, "BinOp", Argv, 3);
Py_DECREF(Op);
Py_DECREF(Marker);
Py_DECREF(Node);
if (Wrap != NULL) {
FixLoc(P, Wrap, RefTok);
}
return Wrap;
ApplyTypeModifiers(Node, Markers, Attributes, ByteOrder);
ApplyBitWidthAttr(Node);
Py_XDECREF(Markers);
Py_XDECREF(Attributes);
return Node;
}
/* term:factor (*|/|//|%|@ factor)* */
@@ -5489,7 +5774,7 @@ static PyObject *ParseFunctionDef(Parser *P, int IsAsync, PyObject *Decorators)
if (Start->Kind == TK_NAME && TokIsName(Start, "async")) {
Start = NextTok(P); /* def */
}
/* define 宏函数关键字(语法与 def 一致,返回注解自动追加 t.CDefine) */
/* define 宏函数关键字(语法与 def 一致,产出 FunctionDef.Define=True) */
int IsDefine = (Start->Kind == TK_NAME && TokIsName(Start, "define"));
Token *NameTok = ExpectName(P, NULL);
if (NameTok == NULL) {
@@ -5566,31 +5851,8 @@ static PyObject *ParseFunctionDef(Parser *P, int IsAsync, PyObject *Decorators)
Py_DECREF(Argv[3]);
}
if (Node != NULL && IsDefine) {
/* 标记 define 宏函数(Unparser 据此还原语法) */
/* 标记 define 宏函数(Unparser 据此还原语法);返回注解保持原样 */
PyObject_SetAttrString(Node, "Define", Py_True);
/* 返回注解改写:<原类型> | t.CDefine / 单独 t.CDefine(宏函数标记,
NewNode 后 Returns 引用仍有效,此处仅替换 Node.returns) */
PyObject *TAttr = MakeTAttrNode(P, "CDefine");
if (TAttr != NULL) {
if (Returns != NULL) {
PyObject *Op = MakeSingleton(P, "BitOr");
if (Op != NULL) {
PyObject *ArgvB[3];
ArgvB[0] = Returns;
ArgvB[1] = Op;
ArgvB[2] = TAttr;
PyObject *Bin = NewNode(P, "BinOp", ArgvB, 3);
if (Bin != NULL) {
PyObject_SetAttrString(Node, "returns", Bin);
Py_DECREF(Bin);
}
Py_DECREF(Op);
}
} else {
PyObject_SetAttrString(Node, "returns", TAttr);
}
Py_DECREF(TAttr);
}
}
Py_XDECREF(Returns);
Py_DECREF(TypeParams);
@@ -5619,8 +5881,7 @@ static PyObject *MakeTAttrNode(Parser *P, const char *AttrName) {
/* extern/export 函数声明(FFI/裸名导出,对齐 vast Parser._ParseExternDef/_ParseExportDef)。
* 允许语法(4 种,配不配 def 都一样,无 `:` 时 body 为空):
* extern [def] A(x: int) -> int [': pass']
* 产出标准 FunctionDef:返回注解改写为 <原类型> | t.State(extern)/ <原类型> | t.CExport(export),
* 并设 Extern=True / Export=True 供 Unparser 还原。 */
* 产出标准 FunctionDef:返回注解保持原样,设 Extern=True / Export=True 供 Unparser 还原。 */
static PyObject *ParseExternDef(Parser *P, int IsExport, PyObject *Decorators) {
Token *Start = NextTok(P); /* 'extern' / 'export' */
if (AtName(P, "def")) {
@@ -5710,30 +5971,8 @@ static PyObject *ParseExternDef(Parser *P, int IsExport, PyObject *Decorators) {
Py_XDECREF(Returns);
return NULL;
}
/* 标记 extern/export(Unparser 据此还原语法) */
/* 标记 extern/export(Unparser 据此还原语法);返回注解保持原样 */
PyObject_SetAttrString(Node, IsExport ? "Export" : "Extern", Py_True);
/* 返回注解改写:<原类型> | t.State / <原类型> | t.CExport(NewNode 后 Returns 引用仍有效) */
PyObject *TAttr = MakeTAttrNode(P, IsExport ? "CExport" : "State");
if (TAttr != NULL) {
if (Returns != NULL) {
PyObject *Op = MakeSingleton(P, "BitOr");
if (Op != NULL) {
PyObject *ArgvB[3];
ArgvB[0] = Returns;
ArgvB[1] = Op;
ArgvB[2] = TAttr;
PyObject *Bin = NewNode(P, "BinOp", ArgvB, 3);
if (Bin != NULL) {
PyObject_SetAttrString(Node, "returns", Bin);
Py_DECREF(Bin);
}
Py_DECREF(Op);
}
} else {
PyObject_SetAttrString(Node, "returns", TAttr);
}
Py_DECREF(TAttr);
}
Py_XDECREF(Returns);
FixLoc(P, Node, Start);
return Node;