From 660a15bef88d8895952d8f0f673c7d84605ed437 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sun, 18 Oct 2026 13:35:34 +0800 Subject: [PATCH] =?UTF-8?q?refactor(tpc):=20=E5=88=A0=E9=99=A4=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E8=81=94=E5=90=88=E8=AF=AD=E6=B3=95=E5=B9=B6=E5=B0=86?= =?UTF-8?q?=E4=BF=AE=E9=A5=B0=E8=BF=81=E7=A7=BB=E4=B8=BA=20AST=20=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 类型注解不再接受任何 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 解析器。 --- lib/Projectrans/DeclarationGenerator.py | 209 ++++-------- lib/core/Handles/HandlesAnnAssign.py | 207 ++++-------- lib/core/Handles/HandlesAssign.py | 65 +++- lib/core/Handles/HandlesBase.py | 16 +- lib/core/Handles/HandlesExprCall.py | 6 +- lib/core/Handles/HandlesFunctions.py | 231 ++++---------- lib/core/Handles/HandlesImports.py | 2 +- lib/core/Handles/HandlesTypeMerge.py | 388 ++++++----------------- lib/core/LLVMTypeMapper.py | 184 ++++------- lib/core/SymbolExtractor.py | 21 +- lib/core/SymbolTypeResolver.py | 90 ++---- lib/core/SymbolUtils.py | 202 +++--------- lib/core/TypeAnnotationResolver.py | 317 +++++-------------- lib/vast/ExprParser.py | 211 ++++++++++-- lib/vast/Nodes.py | 24 +- lib/vast/Parser.py | 184 ++++++++--- lib/vast/Unparser.py | 110 ++++--- lib/vast/__init__.py | 16 +- lib/vast_c/vast_c.c | 405 +++++++++++++++++++----- 19 files changed, 1312 insertions(+), 1576 deletions(-) diff --git a/lib/Projectrans/DeclarationGenerator.py b/lib/Projectrans/DeclarationGenerator.py index 12ffba7..e1330cb 100644 --- a/lib/Projectrans/DeclarationGenerator.py +++ b/lib/Projectrans/DeclarationGenerator.py @@ -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: diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index 64ce0ae..77c00ed 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -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)): diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index 31e2b13..c4a8bb1 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -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. 节点,命中返回该节点。 - 注解形态是 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 '' + 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 diff --git a/lib/core/Handles/HandlesBase.py b/lib/core/Handles/HandlesBase.py index b23f3fe..1b994fb 100644 --- a/lib/core/Handles/HandlesBase.py +++ b/lib/core/Handles/HandlesBase.py @@ -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)。 diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index eaff46f..5819eb8 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -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] 的 '.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]` 内层收敛到同一名字); diff --git a/lib/core/Handles/HandlesFunctions.py b/lib/core/Handles/HandlesFunctions.py index a5fc78d..7264082 100644 --- a/lib/core/Handles/HandlesFunctions.py +++ b/lib/core/Handles/HandlesFunctions.py @@ -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") diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index e9b1f6b..944089a 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -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): diff --git a/lib/core/Handles/HandlesTypeMerge.py b/lib/core/Handles/HandlesTypeMerge.py index 746ef0f..b0a3cd0 100644 --- a/lib/core/Handles/HandlesTypeMerge.py +++ b/lib/core/Handles/HandlesTypeMerge.py @@ -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],修饰符请用关键字") diff --git a/lib/core/LLVMTypeMapper.py b/lib/core/LLVMTypeMapper.py index 93ce774..a6db97c 100644 --- a/lib/core/LLVMTypeMapper.py +++ b/lib/core/LLVMTypeMapper.py @@ -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): diff --git a/lib/core/SymbolExtractor.py b/lib/core/SymbolExtractor.py index 229f6b9..c61a146 100644 --- a/lib/core/SymbolExtractor.py +++ b/lib/core/SymbolExtractor.py @@ -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, diff --git a/lib/core/SymbolTypeResolver.py b/lib/core/SymbolTypeResolver.py index 38c8c56..e3dc8f2 100644 --- a/lib/core/SymbolTypeResolver.py +++ b/lib/core/SymbolTypeResolver.py @@ -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 diff --git a/lib/core/SymbolUtils.py b/lib/core/SymbolUtils.py index d2491ae..8437833 100644 --- a/lib/core/SymbolUtils.py +++ b/lib/core/SymbolUtils.py @@ -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 → %".list[ast.ASTptr]")、 -# 各端方法名、以及 declare/stub 端引用的类型名必须逐字一致,否则会出现 -# Undefined method / 签名错位。此前 DeclarationGenerator._get_type_str 的泛型 -# 分支自带第二套(只认 Name / Name-Tuple 实参的)规则,其余形态(Attribute / -# Subscript / BinOp / 混合 Tuple)退回未特化的 %".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: diff --git a/lib/core/TypeAnnotationResolver.py b/lib/core/TypeAnnotationResolver.py index 750a428..959d46d 100644 --- a/lib/core/TypeAnnotationResolver.py +++ b/lib/core/TypeAnnotationResolver.py @@ -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), diff --git a/lib/vast/ExprParser.py b/lib/vast/ExprParser.py index c293f4c..e75d580 100644 --- a/lib/vast/ExprParser.py +++ b/lib/vast/ExprParser.py @@ -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 diff --git a/lib/vast/Nodes.py b/lib/vast/Nodes.py index 18071e5..e5374a0 100644 --- a/lib/vast/Nodes.py +++ b/lib/vast/Nodes.py @@ -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'), ()), diff --git a/lib/vast/Parser.py b/lib/vast/Parser.py index 0a784d4..519b893 100644 --- a/lib/vast/Parser.py +++ b/lib/vast/Parser.py @@ -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 diff --git a/lib/vast/Unparser.py b/lib/vast/Unparser.py index d2a8632..a5a9b12 100644 --- a/lib/vast/Unparser.py +++ b/lib/vast/Unparser.py @@ -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): diff --git a/lib/vast/__init__.py b/lib/vast/__init__.py index 99d148e..8c8cd45 100644 --- a/lib/vast/__init__.py +++ b/lib/vast/__init__.py @@ -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() diff --git a/lib/vast_c/vast_c.c b/lib/vast_c/vast_c.c index d5bcc28..7be6cbf 100644 --- a/lib/vast_c/vast_c.c +++ b/lib/vast_c/vast_c.c @@ -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;