631 lines
31 KiB
Python
631 lines
31 KiB
Python
"""共享工具函数:符号表处理中使用的 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` 的规则**
|
||
解析(跨模块类 → '<sha1>.X'),再包一层指针——T 为类引用时该层被结构体
|
||
自身吸收('<sha1>.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 → %"<mod>.list[ast.ASTptr]")、
|
||
# 各端方法名、以及 declare/stub 端引用的类型名必须逐字一致,否则会出现
|
||
# Undefined method / 签名错位。此前 DeclarationGenerator._get_type_str 的泛型
|
||
# 分支自带第二套(只认 Name / Name-Tuple 实参的)规则,其余形态(Attribute /
|
||
# Subscript / BinOp / 混合 Tuple)退回未特化的 %"<mod>.list"*,与 define 端
|
||
# 不一致。故此处收拢唯一规则,两端皆调用本组函数。
|
||
|
||
# 定义端 _resolve_generic_slice_type 的 ast.Name 规范化表:
|
||
# 源码里的 C 定长类型名 → 喂给 _mangle_generic_class_name 的 type_arg。
|
||
_GENERIC_ARG_INT_NAMES: frozenset[str] = frozenset({
|
||
'CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T',
|
||
'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong',
|
||
})
|
||
_GENERIC_ARG_FLOAT_NAMES: frozenset[str] = frozenset({
|
||
'CDouble', 'CFloat', 'CFloat64T', 'CFloat32T',
|
||
})
|
||
# 源码名 → 泛型 T 替换用的原始类型名(_resolve_generic_slice_type 的第二返回值)
|
||
_GENERIC_ARG_RAW_NAMES: dict[str, str] = {
|
||
'int': 'CInt', 'double': 'CDouble', 'float': 'CFloat',
|
||
'char': 'CChar', 'bool': 'CBool',
|
||
}
|
||
# _mangle_generic_class_name 的浮点归一集合(LLVM 浮点串 → 'f' + Size)
|
||
_LLVM_FLOAT_STRINGS: frozenset[str] = frozenset({'float', 'double', 'half', 'fp128'})
|
||
|
||
|
||
def NormalizeGenericArgName(NameId: str) -> str:
|
||
"""ast.Name 泛型实参 → 定义端 type_arg(HandlesExprCall._resolve_generic_slice_type
|
||
的 ast.Name 分支,逐分支同构):
|
||
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]` → '<sha1>.X*';`rawptr[rawptr[X]]` → '<sha1>.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 / <sha1>.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 / <sha1>.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('<sha1>.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))
|