"""共享工具函数:符号表处理中使用的 AST 分析工具""" from __future__ import annotations import vast as ast import re from lib.includes import t from lib.includes.t import CTypeRegistry _T_MODULE_NAMES: frozenset[str] = frozenset({'t', t.__name__}) # Viper 软关键字 fn/fun/func/function 是 def 的别名(行首 + 空白 + 标识符才算函数定义, # 变量名/调用/注解中的 fn 不受影响)。展开为 def 后行号不变,供 ast.parse 使用。 _SOFT_KEYWORD_RE: re.Pattern[str] = re.compile( r'^(\s*)(function|func|fun|fn)(\s+)(?=[A-Za-z_])', re.MULTILINE ) def ExpandSoftKeywords(Code: str) -> str: """将 Viper 软关键字 fn/fun/func/function 展开为 def(函数定义行)。 仅在"行首缩进 + 关键字 + 空白 + 标识符"的函数定义形态匹配, 变量名(fn = 5)、调用(fn(x))、注解(x: fn)与字符串内容不受影响。 展开为 def 与关键字等宽或更短,行号不变,AST 行号映射保持有效。 """ if not Code: return Code return _SOFT_KEYWORD_RE.sub(lambda m: f'{m.group(1)}def{m.group(3)}', Code) def IsTModule(module_id: str, symtable: object | None = None) -> bool: """检查模块标识符是否指向 t 类型模块(支持别名如 import t as tt)""" if module_id in _T_MODULE_NAMES: return True if symtable is not None and hasattr(symtable, 'import_aliases'): resolved: str = symtable.import_aliases.get(module_id, module_id) if resolved in _T_MODULE_NAMES: return True return False def IsTModulePath(module_path: str) -> bool: """检查模块路径是否指向 t 类型模块""" if module_path in _T_MODULE_NAMES: return True if module_path: t_name: str for t_name in _T_MODULE_NAMES: if module_path == t_name or module_path.startswith(t_name + '.'): return True return False def AnnotationContainsTType(node: ast.AST, TypeName: str) -> bool: """检测 AST 节点中是否包含指定名称的 t 模块类型""" if isinstance(node, ast.Attribute): if (hasattr(node.value, 'id') and IsTModule(node.value.id) and node.attr == TypeName): return True elif isinstance(node, ast.BinOp): return AnnotationContainsTType(node.left, TypeName) or AnnotationContainsTType(node.right, TypeName) elif isinstance(node, ast.Call): if AnnotationContainsTType(node.func, TypeName): return True for arg in node.args: if AnnotationContainsTType(arg, TypeName): return True elif isinstance(node, ast.Subscript): if AnnotationContainsTType(node.value, TypeName): return True if AnnotationContainsTType(node.slice, TypeName): return True return False def IsListAnnotation(annotation: ast.expr) -> bool: """检查注解是否为栈上固定数组类型(t.CArray[...] 或 list[type, count])""" if not isinstance(annotation, ast.Subscript): return False value = annotation.value # t.CArray[...] / c.CArray[...] if (isinstance(value, ast.Attribute) and isinstance(value.value, ast.Name) and value.value.id in ('t', 'c') and value.attr == 'CArray'): return True # 裸名 CArray[...](from t import *)/ 内建 rawarray[...]:与 t.CArray 等价 # rawarray 是 CArray 的内建复刻名(hashlib 等裸名化重构使用,免写 t. 前缀) if (isinstance(value, ast.Name) and value.id in ('CArray', 'rawarray')): return True # list[type, count] — 仅匹配双参数 Tuple 切片(固定数组), # 单参数 list[type] 不匹配(走泛型类 list[T] 路径) if (isinstance(value, ast.Name) and value.id == 'list' and isinstance(annotation.slice, ast.Tuple) and len(annotation.slice.elts) == 2): return True return False def ExtractListFromBinOp(annotation: ast.expr) -> ast.Subscript | None: """从 BinOp(BitOr) 注解中提取 list[...] 部分,如 list[i32] | t.CPtr""" if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): for side in (annotation.left, annotation.right): if IsListAnnotation(side): return side return None class ListAnnotationParseResult: """list[...] 注解解析结果。 is_pointer=True 表示单参数 list[type] → 指针模式; is_pointer=False 表示 Tuple(2) 模式 list[type, count]。 """ __slots__ = ('elem_type_node', 'count_node', 'is_pointer') def __init__(self, elem_type_node: ast.expr, count_node: ast.expr | None, is_pointer: bool) -> None: self.elem_type_node: ast.expr = elem_type_node self.count_node: ast.expr | None = count_node self.is_pointer: bool = is_pointer def ParseListAnnotation(annotation: ast.expr) -> ListAnnotationParseResult | None: """解析 list[...] 注解,统一处理 list[type, count] / list[type] / BinOp(BitOr) 形式。 自动处理 BinOp(BitOr) 包裹(如 list[i32, N] | t.CPtr)。 返回 None 表示不是 list 注解。 """ list_node: ast.expr = annotation if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): extracted: ast.Subscript | None = ExtractListFromBinOp(annotation) if extracted is None: return None list_node = extracted if not IsListAnnotation(list_node): return None slice_node: ast.AST = list_node.slice if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: return ListAnnotationParseResult(slice_node.elts[0], slice_node.elts[1], is_pointer=False) # 单参数 list[type] → 指针模式 return ListAnnotationParseResult(slice_node, None, is_pointer=True) def CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool: """检测注解节点中是否包含 CInline""" if annotation_node is None: return False if isinstance(annotation_node, ast.Attribute): if hasattr(annotation_node.value, 'id') and IsTModule(annotation_node.value.id) and annotation_node.attr == 'CInline': return True if isinstance(annotation_node, ast.Name): if annotation_node.id == 'CInline': return True if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): return CheckAnnotationHasCInline(annotation_node.left) or CheckAnnotationHasCInline(annotation_node.right) return False def ExtractTypeNameFromBinOp(annotation: ast.expr) -> str | None: """从 BinOp(BitOr) 注解左侧提取类型名(如 TypeA | TypeB → TypeA)。 返回 Name.id 或 Attribute.attr,非 BinOp 返回 None。 """ if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): left: ast.expr = annotation.left if isinstance(left, ast.Name): return left.id if isinstance(left, ast.Attribute): return left.attr return None def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set, TCAliasMap: dict[str, tuple[str, str]] | None = None, StructSha1Map: dict[str, str] | None = None) -> str | None: """递归在注解中查找结构体名(支持 BinOp(BitOr) 递归)。 检查 Name.id、Constant.str、Attribute.attr 是否在 struct_names 中。 支持泛型特化类型(如 GSList[Param]):特化名按**同一规则源** (ResolveTypeArgStr:sha1 前缀 + rawptr/CPtr 的 '*' 逐层)构造后在 struct_names 中查找——查表键与 _mangle_generic_class_name 产物逐字一致, 否则同一注解在"注解查找"与"特化注册"两处解析出不同名字(opaque 副本)。 """ if isinstance(node, ast.Name) and node.id in struct_names: return node.id if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in struct_names: return node.value if isinstance(node, ast.Attribute) and node.attr in struct_names: return node.attr if isinstance(node, ast.Subscript): base_name: str | None = None if isinstance(node.value, ast.Name): base_name = node.value.id elif isinstance(node.value, ast.Attribute): base_name = node.value.attr if base_name: slice_node: ast.AST = node.slice if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index): slice_node = slice_node.value elem_nodes: list[ast.AST] = ( list(slice_node.elts) if isinstance(slice_node, ast.Tuple) else [slice_node]) type_args: list[str] = [ ResolveTypeArgStr(E, TCAliasMap, StructSha1Map) for E in elem_nodes] spec_name: str = base_name + '[' + ']['.join(type_args) + ']' if spec_name in struct_names: return spec_name if base_name in struct_names: return base_name if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): result: str | None = FindStructNameInAnnotation( node.left, struct_names, TCAliasMap, StructSha1Map) if result: return result return FindStructNameInAnnotation( node.right, struct_names, TCAliasMap, StructSha1Map) return None def FindStructNameInAnnotationWithContext(Node: ast.AST, Trans: object, Gen: object, StructNames: dict | set | None = None) -> str | None: """按 Gen/Trans 上下文注入规则表后查找结构体名。 规则本体唯一(FindStructNameInAnnotation),此处只做与 HandlesExprCall._resolve_type_arg_str 同口径的上下文注入,避免各调用点 各写一套拼名(查表键必须与 _mangle_generic_class_name 产物逐字一致)。 """ Names: dict | set = StructNames if StructNames is not None else Gen.structs return FindStructNameInAnnotation( Node, Names, TCAliasMap=getattr(Trans, '_t_c_imported_names', {}), StructSha1Map=getattr(Gen, '_struct_sha1_map', {})) def AnnotationContainsName(annotation: ast.AST, name: str) -> bool: """检查注解中是否包含指定名称(支持 BinOp(BitOr) 递归)。 同时检查 Attribute.attr 和 Name.id,比 ast.dump 字符串匹配更精确。 """ if isinstance(annotation, ast.Attribute): return annotation.attr == name if isinstance(annotation, ast.Name): return annotation.id == name if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): return AnnotationContainsName(annotation.left, name) or AnnotationContainsName(annotation.right, name) return False def IsCPtrNode(node: ast.AST) -> bool: """检查节点是否为 t.CPtr 属性引用。""" return (isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name) and node.value.id == 't' and node.attr == 'CPtr') def IsCPtrSubscriptNode(node: ast.AST) -> bool: """检查节点是否为 t.CPtr[T] 下标指针类型(非裸标记,裸标记见 IsCPtrNode)。 与 TPV TypeGenResolve._is_cptr_subscript(TypeGenResolve.vp:1485-1505)同口径: value 必须是 t.CPtr 属性引用(只认 t 前缀,c.CPtr[...] 不认); 切片内的指针层级不限(t.CPtr[t.CPtr]、t.CPtr[t.CPtr[t.CInt]] 均命中)。 链式写法 t.CPtr[T][T](value 是 Subscript)两套编译器均不认作该标记。 """ return (isinstance(node, ast.Subscript) and IsCPtrNode(node.value)) # 指针下标的 base 名:rawptr 是编译器内置语法(TPC/TPV 双端保留字,见 # includes/builtins.vp 语义注释与 TypeAnnotationResolver._BUILTIN_ROWPTR_NAME), # 单独 rawptr 等价 t.CPtr(void*)。 _RAWPTR_SUBSCRIPT_NAME: str = 'rawptr' # 指针标记类型名(t.CPtr):裸名书写 `CPtr[T]` / 导入别名 `X`(from t import CPtr as X) # 都归一到本名。 _CPTR_TYPE_NAME: str = 'CPtr' def ResolveTCImportAliasName(NameId: str, symtable: object | None = None, TCAliasMap: dict[str, tuple[str, str]] | None = None) -> str: """t/c 导入别名 → 原始类型名('X' → 'CPtr'、'myint' → 'CInt');未命中原样返回。 两张同源别名表(注册点唯一:HandlesImports._EmitImportFromDeclarationsLlvm / _RegisterFromImportAliases,与 SymbolTable 序列化),调用方按手头有的表注入: - TCAliasMap:{别名: (模块, 原名)}(Trans._t_c_imported_names / DeclarationGenerator._t_c_imported_names 同结构) - symtable._t_type_symbols:{别名: t.CType 子类}(from t import CPtr as X → t.CPtr) 非 t/c 模块的 from 导入别名(from ast import AST as A)不参与归一。 """ if not NameId: return NameId if TCAliasMap: Entry: tuple[str, str] | None = TCAliasMap.get(NameId) if Entry: SrcModule, SrcName = Entry if IsTModule(SrcModule): return SrcName if symtable is not None: Cls: object | None = getattr(symtable, '_t_type_symbols', {}).get(NameId) if Cls is not None: return getattr(Cls, '__name__', NameId) return NameId def IsRawPtrSubscriptNode(node: ast.AST) -> bool: """检查节点是否为内置裸指针下标 `rawptr[T]`(非裸标记 rawptr)。 `rawptr[T]` 语义 = `t.CPtr[T]` = 源码联合写法 `T | t.CPtr`(Ptr(T)),三者 必须走同一解析与拼名路径,否则同一类型的不同书写会分裂出不同特化名 (结构体/方法声明/调用点三处不一致)。 注意:本判据**只**认 `rawptr[T]`;`t.CPtr[T]` / 裸名 `CPtr[T]` 由 IsPtrSubscriptNode 判定(见下),二者共用同一条脱糖规则 (DesugarPtrSubscriptToUnion),此处保持 rawptr 专用以便仍需区分书写时使用。 """ return (isinstance(node, ast.Subscript) and isinstance(node.value, ast.Name) and node.value.id == _RAWPTR_SUBSCRIPT_NAME) def IsPtrSubscriptNode(node: ast.AST, symtable: object | None = None, TCAliasMap: dict[str, tuple[str, str]] | None = None) -> bool: """检查节点是否为"指针下标类型":`rawptr[T]` / `t.CPtr[T]` / 裸名 `CPtr[T]` / 导入别名 `X[T]`(`from t import CPtr as X`)。 三者语义完全相同(= 源码联合写法 `T | t.CPtr` = Ptr(T),见 builtins.vp 与 t.py 的 CPtr 语义注释):内层 T 按**参数注解 `a: T` 的规则** 解析(跨模块类 → '.X'),再包一层指针——T 为类引用时该层被结构体 自身吸收('.X*'),其余(标量 / 已是指针的 typedef / 泛型容器特化 / 嵌套指针下标)逐层外包。 - 裸名 `CPtr[T]`(`from t import CPtr` / `from t import *`)与声明端 DeclarationGenerator._get_type_str 的 ValueIsCPtr 判据一致(那里同样接受 Attribute 'CPtr' 与 Name 'CPtr' 两种书写)。 - 传入 symtable 时,`import t as tt` 的 `tt.CPtr[T]` 一并命中(与声明端 "只看 attr 名"的 ValueIsCPtr 判据对齐,避免同一书写两端分裂); 不传(名称域 ResolveTypeArgStr 的字面名场景)时只认字面 't'。 - 导入名别名(`from t import CPtr as X` 的 `X[T]`)经别名表解析 X→CPtr (TCAliasMap 或 symtable._t_type_symbols,见 ResolveTCImportAliasName), 定义端与声明端各自注入手头的同一批表,判据只有这一处。 """ if IsRawPtrSubscriptNode(node): return True if not isinstance(node, ast.Subscript): return False value: ast.AST = node.value if isinstance(value, ast.Name) and value.id == _CPTR_TYPE_NAME: return True 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]` / `t.CPtr[T]` / 裸名 `CPtr[T]` / 别名 `X[T]`) 折叠成等价的联合写法 `T | t.CPtr`。 内层 T 递归折叠(`rawptr[rawptr[X]]` → `(X | t.CPtr) | t.CPtr`、 `t.CPtr[rawptr[X]]` → `(X | t.CPtr) | t.CPtr`), 与 TPV TypeGenResolve.resolve_annotation_type 的 Subscript 分支同语义 (T → Ptr(T),层数逐层外包);折叠后交给 HandlesTypeMerge 既有的 联合解析(_CollectAllOperandTypes 会把嵌套 BitOr 拉平成 [T, t.CPtr, ...], struct 基类型吸收一层、其余逐层累加),从而: - 内层 T 走通用类型解析(含跨模块类经 Gen.structs 反查 SHA1 前缀); - `rawptr[X]` / `t.CPtr[X]` / `X[T]` / `X | t.CPtr` 得到同一 CTypeInfo (PtrCount/BaseType 一致)与同一泛型实参串(逐层 '*')。 非指针下标节点原样返回(调用方无需先判类型);symtable/TCAliasMap 透传给 判据(识别 `import t as tt` 的 `tt.CPtr[T]` 与 `from t import CPtr as X` 的 `X[T]` 内层嵌套)。折叠产物统一用字面 `t.CPtr` 标记,与源码联合写法同形。 """ if not IsPtrSubscriptNode(node, symtable, TCAliasMap): return node inner: ast.AST = DesugarPtrSubscriptToUnion(node.slice, symtable, TCAliasMap) cptr_marker: ast.AST = ast.Attribute( value=ast.Name(id='t', ctx=ast.Load()), attr='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 分支,逐分支同构): int/double/float 保留源码名('list[int]' 而非 'list[i32]')、 char/bool → 'i8'、C 整数族 → 'int'、C 浮点族 → 'double'、其余原名。 """ if NameId in ('int', 'double', 'float'): return NameId if NameId in ('char', 'bool'): return 'i8' if NameId in _GENERIC_ARG_INT_NAMES: return 'int' if NameId in _GENERIC_ARG_FLOAT_NAMES: return 'double' return NameId def GenericArgRawName(NameId: str) -> str: """ast.Name 泛型实参 → 替换模板 T 用的原始类型名(_resolve_generic_slice_type 的第二返回值):'int' → 'CInt'(内建类型须用源码名替换 T,见 HandlesClassDef._specialize_generic_class 的 _BUILTIN_TYPE_NAMES 判定), 其余原名。仅定义端 T 替换用;mangling 只用 NormalizeGenericArgName。 """ return _GENERIC_ARG_RAW_NAMES.get(NameId, NameId) def MangleTypeArgByRegistry(ArgStr: str) -> str: """实参串 → 最终 mangled 实参(HandlesClassDef._mangle_generic_class_name 的单项逻辑,逐分支同构):t 类型名经 NameToLLVM 归一(CInt32T → 'i32', 't.CInt'/'c.CInt' 先去模块前缀再归一),浮点按 Size 归一为 f{n} (CDouble → 'f8'),未注册名原样保留(含指针层数与已解析的内层名)。 """ LookupStr: str = ArgStr if ArgStr.startswith('t.') or ArgStr.startswith('c.'): LookupStr = ArgStr[2:] LlvmStr: str | None = CTypeRegistry.NameToLLVM(LookupStr) if not LlvmStr: return ArgStr if LlvmStr in _LLVM_FLOAT_STRINGS: Cls: type | None = CTypeRegistry.GetClassByName(LookupStr) Size: int = Cls().Size if Cls is not None else 0 return 'f' + str(Size) return LlvmStr # 指针层数的首层归一化(与 LLVMTypeMapper._add_pointer_level 同口径) _POINTER_PLACEHOLDER_BASES: frozenset[str] = frozenset({'', 'void', 'void*'}) def AddPointerLayers(TypeStr: str, Layers: int) -> str: """给已解析的类型串追加 Layers 层指针(空/void/void* 的首层归一化为 i8*)。 与 LLVMTypeMapper._add_pointer_level 同口径;名称域与类型域因此对 rawptr[t.CVoid] 一致地给出 i8*(唯一允许的 void 兜底)。 """ Result: str = TypeStr for _ in range(Layers): if Result in _POINTER_PLACEHOLDER_BASES: Result = 'i8*' else: Result = Result + '*' return Result def IsCPtrMarkerNode(Node: ast.AST, symtable: object | None = None, TCAliasMap: dict[str, tuple[str, str]] | None = None) -> bool: """`t.CPtr` 裸指针标记(含 `import t as tt` 与 `from t import CPtr as X` 别名): 联合写法里贡献一层 '*'。 与 IsCPtrNode 的区别:仅按 attr 名 + t 模块前缀判定,不看切片 (`t.CPtr[T]` 下标是**基类型**而非层数标记,见 ResolveTypeArgStr 的 Subscript 分支)。 - Attribute:`t.CPtr` / `tt.CPtr`(t 模块别名经 symtable.import_aliases 解析)。 - Name:经别名表归一为 'CPtr' 的书写名(`from t import CPtr as X` 的 `X`); 字面裸名 `CPtr` 是否算标记取决于该模块是否 `from t import CPtr` (别名表命中一致:两端都由同一批表判定,不另设白名单)。 """ if isinstance(Node, ast.Attribute): return (Node.attr == _CPTR_TYPE_NAME and isinstance(Node.value, ast.Name) and IsTModule(Node.value.id, symtable)) if isinstance(Node, ast.Name): return ResolveTCImportAliasName(Node.id, symtable, TCAliasMap) == _CPTR_TYPE_NAME return False def FlattenUnionOperands(Node: ast.AST) -> list[ast.AST]: """拉平嵌套 BitOr,按书写顺序返回操作数(`A | t.CPtr | t.CPtr` → [A, CPtr, CPtr])。""" if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr): return FlattenUnionOperands(Node.left) + FlattenUnionOperands(Node.right) return [Node] def ResolveTypeArgStr(Node: ast.AST, TCAliasMap: dict[str, tuple[str, str]] | None = None, StructSha1Map: dict[str, str] | None = None) -> str: """将类型参数 AST 节点解析为规范化的类型字符串(泛型 mangling 用)。 规则(**与参数注解 `a: T` 完全同一套解析**,定义端/声明端唯一规则源): - ast.Name: t/c 导入别名 → '{module}.{name}';已注册类 → '{sha1}.{名}' (与参数注解的 %"{sha1}.X" 同前缀);其余按 NormalizeGenericArgName 归一('int'/'i32'/'str' 原名、'char'/'bool' → 'i8'、C 整数/浮点族 → 'int'/'double') - ast.Attribute: t 模块类型按 CTypeRegistry.NameToLLVM 解析(t.CPtr → i8*、 t.CInt → i32);跨模块类引用 module.X → '{sha1}.X';其余 '{mod}.{attr}' - ast.Subscript: 指针下标(`rawptr[T]` / `t.CPtr[T]` / 裸名 `CPtr[T]` / 导入别名 `X[T]`)已在入口脱糖为上面的联合写法(走同一规则),故此处只剩泛型容器: '<容器名>[<已解析实参>]'(多实参 '][' 分隔),容器名的 模块前缀由调用方(_mangle_name / '%"{模sha1}.{特化名}"')统一加 - ast.BinOp(BitOr)(含指针下标脱糖而来): 取非 CPtr 侧为基类型, 每个 `t.CPtr` 标记追加一层 '*'(`X | t.CPtr` ≡ `rawptr[X]` ≡ `t.CPtr[X]` → '.X*';`rawptr[rawptr[X]]` → '.X**'; 标量 `int | t.CPtr` → 'int*') - 其余形态: ast.unparse 注意:名称域**不做**"裸类引用吸收一层 CPtr"(那是注解→LLVM 类型域的规则, 见 DeclarationGenerator._is_bare_class_ref_annotation):名称域描述的是类型 身份('X' = X 本身、'X*' = 指向 X 的指针),逐层累加,否则 `rawptr[X]` 与 `X | t.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: # t 模块别名(from t import CInt as myint)按内建归一表解析到同一名字 # ('myint' 与 'CInt' 都 → 'int'),避免同义写法分裂特化名 SrcModule, SrcName = TCAliasMap[tn] if IsTModule(SrcModule): return NormalizeGenericArgName(SrcName) return f'{SrcModule}.{SrcName}' if StructSha1Map and tn in StructSha1Map: return f'{StructSha1Map[tn]}.{tn}' return NormalizeGenericArgName(tn) if isinstance(Node, ast.Attribute): return _ResolveAttributeArgStr(Node, TCAliasMap, StructSha1Map) if isinstance(Node, ast.Subscript): return _ResolveSubscriptArgStr(Node, TCAliasMap, StructSha1Map) if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr): return _ResolveUnionArgStr(Node, TCAliasMap, StructSha1Map) return ast.unparse(Node) def _ResolveAttributeArgStr(Node: ast.Attribute, TCAliasMap: dict[str, tuple[str, str]] | None, StructSha1Map: dict[str, str] | None) -> str: """Attribute 形态(t.CInt / ast.AST / .AST)→ 实参串。""" if not isinstance(Node.value, ast.Name): return ast.unparse(Node) ModName: str = Node.value.id AttrName: str = Node.attr if IsTModule(ModName) or (TCAliasMap and ModName in TCAliasMap): LlvmStr: str | None = CTypeRegistry.NameToLLVM(AttrName) if LlvmStr is not None: return LlvmStr return f'{ModName}.{AttrName}' # 跨模块类引用(ast.AST / .AST):与参数注解同一条 sha1 解析 if StructSha1Map and AttrName in StructSha1Map: return f'{StructSha1Map[AttrName]}.{AttrName}' return f'{ModName}.{AttrName}' def _ResolveSubscriptArgStr(Node: ast.Subscript, TCAliasMap: dict[str, tuple[str, str]] | None, StructSha1Map: dict[str, str] | None) -> str: """下标形态(t.CPtr[T] / 泛型容器 list[X] / dict[K,V])→ 实参串。 容器名('list' / 'dict' ...)**不带**模块前缀:它只是 _mangle_generic_class_name 的基名,特化名的模块前缀由调用方统一加(定义端 _mangle_name / 声明端 '%"{模sha1}.{特化名}"'),并保证 '_make_replacement_node' 能把实参串 重新解析成可用的注解 AST('.list[...]' 会因数字开头而解析失败)。 """ if IsCPtrSubscriptNode(Node): Inner: str = ResolveTypeArgStr(Node.slice, TCAliasMap, StructSha1Map) return AddPointerLayers(Inner, 1) BaseName: str = '' if isinstance(Node.value, ast.Name): BaseName = Node.value.id elif isinstance(Node.value, ast.Attribute): BaseName = Node.value.attr if not BaseName: return ast.unparse(Node) SliceNode: ast.AST = Node.slice ElemNodes: list[ast.AST] = list(SliceNode.elts) if isinstance(SliceNode, ast.Tuple) else [SliceNode] Resolved: list[str] = [ResolveTypeArgStr(E, TCAliasMap, StructSha1Map) for E in ElemNodes] return f'{BaseName}[' + ']['.join(Resolved) + ']' def _ResolveUnionArgStr(Node: ast.BinOp, TCAliasMap: dict[str, tuple[str, str]] | None, StructSha1Map: dict[str, str] | None) -> str: """联合形态(X | t.CPtr | ...)实参串:非 CPtr 侧为基类型,CPtr 标记逐层加 '*'。 标记判据是同一处 IsCPtrMarkerNode(含 `from t import CPtr as X` 的裸标记别名), 别名经 TCAliasMap 解析;没带别名表的 `import t as tt` 的 `tt.CPtr` 在此域 不做模块别名解析(两端口径一致的既有缺口)。 """ BaseType: str = '' Layers: int = 0 for Operand in FlattenUnionOperands(Node): if IsCPtrMarkerNode(Operand, TCAliasMap=TCAliasMap): Layers += 1 elif not BaseType: BaseType = ResolveTypeArgStr(Operand, TCAliasMap, StructSha1Map) if not BaseType: # 只有 CPtr 标记(如 `t.CPtr | t.CPtr`):等价 void* 逐层——首层 i8* return AddPointerLayers('void', Layers) return AddPointerLayers(BaseType, Layers) def ResolveGenericTypeArgStr(Node: ast.AST, TCAliasMap: dict[str, tuple[str, str]] | None = None, StructSha1Map: dict[str, str] | None = None) -> str: """泛型实参的最终 mangled 串(喂给 _mangle_generic_class_name 的单参数)。 与定义端(HandlesExprCall._resolve_generic_slice_type + _mangle_generic_class_name) 对单个实参的实际结果同一套规则: - ast.Name: NormalizeGenericArgName →(命中注册类则 '{sha1}.{名}')→ MangleTypeArgByRegistry ('int' → 'int'、'i32' → 'i32'、'str' → 'str'、'CInt32T' → 'int'、 'CFloat64T' → 'double'、'CChar' → 'i8') - 其余形态(Attribute / Subscript(含 rawptr[...])/ BinOp / 混合 Tuple 元素): ResolveTypeArgStr(rawptr[T] 脱糖 → 逐层 '*'、t.CPtr → 'i8*'、跨模块类 → sha1 前缀) → MangleTypeArgByRegistry """ return MangleTypeArgByRegistry(ResolveTypeArgStr(Node, TCAliasMap, StructSha1Map))