修复了一些错误
This commit is contained in:
1 parent
6af2dea917
commit
2cc816ac13
16 files changed
+1155
-230
No files matched your search
@@ -8,7 +8,9 @@ import llvmlite.ir as ir
|
||||
|
||||
from lib.includes import t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
from lib.core.SymbolUtils import IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode
|
||||
from lib.core.SymbolUtils import (
|
||||
IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode, IsCPtrNode,
|
||||
IsRawPtrSubscriptNode, IsPtrSubscriptNode, ResolveGenericTypeArgStr)
|
||||
|
||||
|
||||
class DeclarationGenerator:
|
||||
@@ -40,6 +42,13 @@ class DeclarationGenerator:
|
||||
self.typedef_map: dict[str, ast.AST] = typedef_map or {}
|
||||
self._pyi_tree: ast.Module | None = None
|
||||
self._t_alias_map: dict[str, type] = {}
|
||||
# 泛型模板类名(PEP 695 `class Box[T]`):声明端特化判定用,与定义端
|
||||
# HandlesClassDef._generic_class_templates 同源(ClassDef 的 type_params
|
||||
# 标记),generate() 里从本模块 pyi 与 class_def_map 收集
|
||||
self._generic_class_names: set[str] = set()
|
||||
# t/c 导入名表(from t import CInt as myint → 'myint' → ('t','CInt')),
|
||||
# 与定义端 Trans._t_c_imported_names 同口径,供泛型实参串解析使用
|
||||
self._t_c_imported_names: dict[str, tuple[str, str]] = {}
|
||||
# 跨模块类定义映射:{class_name: ClassDef_node},供 _get_inherited_members
|
||||
# 查找其他模块定义的父类(如 exprs.py 的 Name(AST) 查找 base.py 的 AST)
|
||||
self._cross_module_class_defs: dict[str, ast.ClassDef] = class_def_map or {}
|
||||
@@ -50,6 +59,16 @@ class DeclarationGenerator:
|
||||
|
||||
self._DefineConstants: dict[str, int | str] = {}
|
||||
self._pyi_tree = tree
|
||||
# 泛型模板类名(PEP 695 `class Box[T]`):class_def_map 覆盖所有已生成
|
||||
# .vpi 的模块(含本模块),本模块 pyi 直接解析的 ClassDef 优先,
|
||||
# 与定义端 HandlesClassDef 注册 _generic_class_templates 的判据一致
|
||||
# (都只看 ClassDef.type_params 是否非空,不看类名白名单)。
|
||||
self._generic_class_names = {
|
||||
node.name for node in ast.iter_child_nodes(tree)
|
||||
if isinstance(node, ast.ClassDef) and getattr(node, 'type_params', None)}
|
||||
for _gc_name, _gc_node in self._cross_module_class_defs.items():
|
||||
if getattr(_gc_node, 'type_params', None):
|
||||
self._generic_class_names.add(_gc_name)
|
||||
global_typedef_map: dict[str, ast.AST] = self.typedef_map
|
||||
self.typedef_map: dict[str, ast.AST] = {}
|
||||
if global_typedef_map:
|
||||
@@ -57,12 +76,14 @@ class DeclarationGenerator:
|
||||
|
||||
# 构建 t/c 类型别名映射(from t import CInt as myint)
|
||||
self._t_alias_map: dict[str, type] = {}
|
||||
self._t_c_imported_names: dict[str, tuple[str, str]] = {}
|
||||
for node in ast.iter_child_nodes(tree):
|
||||
if isinstance(node, ast.ImportFrom):
|
||||
if node.module in ('t', 'c'):
|
||||
for alias in node.names:
|
||||
name: str = alias.name
|
||||
asname: str = alias.asname or name
|
||||
self._t_c_imported_names[asname] = (node.module, name)
|
||||
if node.module == 't':
|
||||
t_cls: type | None = getattr(t, name, None)
|
||||
if isinstance(t_cls, type) and issubclass(t_cls, t.CType):
|
||||
@@ -1036,6 +1057,45 @@ class DeclarationGenerator:
|
||||
"""
|
||||
return base_type + '*' * self._ptr_level_of(cptr_sub_type)
|
||||
|
||||
def _ptr_subscript_type_str(self, annotation: ast.Subscript) -> str:
|
||||
"""指针下标(rawptr[T] / t.CPtr[T] / 裸名 CPtr[T],判据见
|
||||
SymbolUtils.IsPtrSubscriptNode)→ LLVM 类型串。
|
||||
|
||||
与定义端同源:SymbolUtils.DesugarPtrSubscriptToUnion 把三者折叠为等价
|
||||
联合写法 `T | t.CPtr` 后交 HandlesTypeMerge.MergeTypes,指针层数由
|
||||
_MergeAllComponentTypes 的"struct 基类型吸收一层 CPtr"决定 —— 裸类引用
|
||||
的非 embedded 形式本身即指针('%"sha1.X"*'),再包一层会被吸收 → 结果
|
||||
就是该指针本身;其余类型(标量 / 已是指针的 typedef / 泛型容器特化 /
|
||||
联合写法 / 嵌套指针下标)逐层外包。rawptr[...] 与 t.CPtr[...] 共用本条
|
||||
规则(此前 t.CPtr[list[X]] 在此得 list[X]**、rawptr[list[X]] 得
|
||||
list[X]*,同一指针语义两种结果)。
|
||||
"""
|
||||
inner: ast.AST = annotation.slice
|
||||
inner_type: str = self._get_type_str(inner)
|
||||
if self._is_bare_class_ref_annotation(inner, inner_type):
|
||||
return inner_type
|
||||
if inner_type in ('', 'void', 'void*'):
|
||||
return 'i8*'
|
||||
return f'{inner_type}*'
|
||||
|
||||
def _is_bare_class_ref_annotation(self, inner: ast.AST, inner_type: str) -> bool:
|
||||
"""节点是否为"裸类引用"(本身即指针 → 吸收一层 t.CPtr)。
|
||||
|
||||
与 _get_type_str 的既有约定一致:类引用的**非** embedded 形式本身就是
|
||||
指针('%"sha1.X"*'),所以 `AST | t.CPtr` 合并后仍是该指针(定义端
|
||||
_MergeAllComponentTypes 的 struct 吸收)。联合写法(ast.BinOp)与指针
|
||||
下标(rawptr[...] / t.CPtr[...])不是裸类引用——它们已自带指针层数,
|
||||
须逐层外包(rawptr[Node] | t.CPtr → Node**、ast.AST | t.CPtr | t.CPtr
|
||||
→ AST**,与定义端整体拉平后只吸收一次 CPtr 一致)。
|
||||
"""
|
||||
if not inner_type:
|
||||
return False
|
||||
if isinstance(inner, ast.BinOp):
|
||||
return False
|
||||
if isinstance(inner, ast.Subscript):
|
||||
return not (IsRawPtrSubscriptNode(inner) or IsCPtrSubscriptNode(inner))
|
||||
return inner_type.startswith('%') and inner_type.endswith('*')
|
||||
|
||||
def _get_type_str(self, annotation: ast.AST | None, embedded: bool = False) -> str:
|
||||
if annotation is None:
|
||||
return 'i8*'
|
||||
@@ -1164,13 +1224,23 @@ class DeclarationGenerator:
|
||||
# t.CPtr (i8*) 与 left 合并:对齐 Phase 2 _MergeAllComponentTypes 的
|
||||
# "first CPtr absorption" 语义:struct | t.CPtr → struct*(吸收,struct 变量默认是指针)。
|
||||
# 但对于本身已是指针的类型(如 bytes=str=i8*),bytes | t.CPtr → i8**(不吸收)。
|
||||
# 例外:泛型特化类型(含 '[')回退为 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] | t.CPtr 一并退化成 i8*,与定义端 %"mod.list[X]"* 不一致)。
|
||||
if right_type == 'i8*':
|
||||
if '[' in left_type:
|
||||
if left_type[:1] == '[':
|
||||
return 'i8*'
|
||||
if left_type in ('', 'void'):
|
||||
return 'i8*'
|
||||
if left_type.startswith('%"') and left_type.endswith('*'):
|
||||
# 吸收仅对"裸类引用"成立(其非 embedded 形式本身即指针):
|
||||
# ast.AST | t.CPtr → %"sha1.AST"*。已自带指针层数的左值
|
||||
# (rawptr[...] / t.CPtr[...] 下标 / 联合写法)须逐层外包:
|
||||
# rawptr[Node] | t.CPtr → Node**、ast.AST | t.CPtr | t.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}*'
|
||||
@@ -1185,27 +1255,40 @@ class DeclarationGenerator:
|
||||
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)
|
||||
# t.CPtr 裸标记在左侧(t.CPtr | X):与右侧写法(X | t.CPtr,见上)
|
||||
# 完全对称。缺此分支时左值 i8* 会吞掉右侧的指针层数:
|
||||
# t.CPtr | rawptr[Node] 声明端曾得 i8*,而定义端为 %"sha1.Node"**(差一层)。
|
||||
# 仅对裸标记 t.CPtr 生效(left 为 t.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):
|
||||
base: str = self._get_type_str(annotation.value)
|
||||
if base == 'i8*' and isinstance(annotation.slice, ast.Constant):
|
||||
return f'[{self._get_const_int(annotation.slice)} x i8]'
|
||||
# 处理 t.CPtr[Type] 语法(指向 Type 的指针)
|
||||
# 例如: t.CPtr[t.CPtr] -> i8** (void**), t.CPtr[t.CInt] -> i32* (int*)
|
||||
# t.CPtr[t.CPtr[t.CInt]] -> i32** (int**)
|
||||
# 指针下标(rawptr[T] / t.CPtr[T] / 裸名 CPtr[T] / 导入别名 X[T],以及带
|
||||
# 模块前缀书写的 X.CPtr[T])≡ 源码联合写法 `T | t.CPtr`:与定义端
|
||||
# **同一判据**(SymbolUtils.IsPtrSubscriptNode,别名经本模块的
|
||||
# _t_c_imported_names 表解析 X→CPtr)+ 同一层数规则
|
||||
# (_ptr_subscript_type_str:裸类引用吸收一层、其余逐层外包),内层 T
|
||||
# 照常解析(跨模块类由 struct_sha1_map 补 SHA1 前缀)。此前 rawptr[T]
|
||||
# 在此退化成 i8*,t.CPtr[T] 走的是"embedded + 追加一层"的独立分支:
|
||||
# 非同一规则,且对泛型容器特化多出一层(t.CPtr[list[X]] 得 list[X]**,
|
||||
# 而 rawptr[list[X]] 得 list[X]*)。
|
||||
ValueIsCPtr: bool = (
|
||||
(isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CPtr')
|
||||
or (isinstance(annotation.value, ast.Name) and annotation.value.id == 'CPtr')
|
||||
)
|
||||
if ValueIsCPtr and isinstance(annotation.slice, (ast.Attribute, ast.Name, ast.Subscript)):
|
||||
slice_type: str = self._get_type_str(annotation.slice, embedded=True)
|
||||
if slice_type and slice_type != 'void':
|
||||
return f'{slice_type}*'
|
||||
return 'i8*'
|
||||
if (IsPtrSubscriptNode(annotation, TCAliasMap=self._t_c_imported_names)
|
||||
or (ValueIsCPtr and isinstance(annotation.slice, (ast.Attribute, ast.Name, ast.Subscript)))):
|
||||
return self._ptr_subscript_type_str(annotation)
|
||||
base: str = self._get_type_str(annotation.value)
|
||||
if base == 'i8*' and isinstance(annotation.slice, ast.Constant):
|
||||
return f'[{self._get_const_int(annotation.slice)} x i8]'
|
||||
if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int):
|
||||
return f'[{annotation.slice.value} x {base}]'
|
||||
# 处理 t.CArray[elem_type, count] / rawarray[elem_type, count] 注解 → [count x elem_type]
|
||||
@@ -1235,49 +1318,50 @@ class DeclarationGenerator:
|
||||
else:
|
||||
elem_types = [self._get_type_str(slice_node, embedded=True)]
|
||||
return '{ ' + ', '.join(elem_types) + ' }'
|
||||
# 处理泛型类类型注解(如 list[str])
|
||||
# 处理泛型类类型注解(如 list[str] / list[rawptr[ast.AST]] /
|
||||
# 用户泛型类 Box[Node])
|
||||
# 实参串走 SymbolUtils.ResolveGenericTypeArgStr(与定义端
|
||||
# _mangle_generic_class_name 同一规则源):此前只认 Name / Name-Tuple
|
||||
# 实参,Attribute(ast.AST)/ Subscript(rawptr[...])/ BinOp
|
||||
# (X | t.CPtr)/ 混合 Tuple 一律退回未特化的 %"...list"*,
|
||||
# 与 define 端发射的 %"<mod>.list[ast.ASTptr]" 不一致
|
||||
# (Undefined method / 签名错位)。
|
||||
# 内建容器(non_struct_types)之外,**用户泛型类**同样特化:判据
|
||||
# _generic_class_names(ClassDef.type_params,与定义端
|
||||
# HandlesClassDef._generic_class_templates 同源),此前只有内建容器名
|
||||
# 会特化 → Box[Node] 字段在 stub 端是 %"<mod>.Box"*、定义端是
|
||||
# %"<mod>.Box[<已解析实参>]"*(Holder 字段布局两侧不一致)。
|
||||
if isinstance(annotation.value, ast.Name):
|
||||
gc_name: str = annotation.value.id
|
||||
if gc_name in non_struct_types and gc_name != 'tuple':
|
||||
if (gc_name in non_struct_types or gc_name in self._generic_class_names) \
|
||||
and gc_name != 'tuple':
|
||||
gc_slice: ast.AST = annotation.slice
|
||||
gc_args: list[str] = []
|
||||
if isinstance(gc_slice, ast.Name):
|
||||
gc_args.append(gc_slice.id)
|
||||
elif isinstance(gc_slice, ast.Tuple):
|
||||
gc_valid: bool = True
|
||||
for gc_elt in gc_slice.elts:
|
||||
if isinstance(gc_elt, ast.Name):
|
||||
gc_args.append(gc_elt.id)
|
||||
else:
|
||||
gc_valid = False
|
||||
break
|
||||
if not gc_valid:
|
||||
gc_args = []
|
||||
if gc_args:
|
||||
gc_mangled: list[str] = []
|
||||
for gc_ta in gc_args:
|
||||
# t.CPtr/CPtr → 'ptr'(与 _resolve_type_arg_str 的
|
||||
# 泛型 mangling 一致);NameToLLVM('CPtr') 返回 'i8*'
|
||||
# 会导致声明端 'list[i8*]' 与特化端 'list[ptr]' 不匹配
|
||||
if gc_ta == 'CPtr':
|
||||
gc_mangled.append('ptr')
|
||||
continue
|
||||
gc_llvm: str | None = CTypeRegistry.NameToLLVM(gc_ta)
|
||||
if gc_llvm:
|
||||
if gc_llvm in ('float', 'double', 'half', 'fp128'):
|
||||
gc_cls: type | None = CTypeRegistry.GetClassByName(gc_ta)
|
||||
gc_sz: int = gc_cls().Size if gc_cls else 0
|
||||
gc_mangled.append('f' + str(gc_sz))
|
||||
else:
|
||||
gc_mangled.append(gc_llvm)
|
||||
else:
|
||||
gc_mangled.append(gc_ta)
|
||||
gc_spec: str = gc_name + '[' + ']['.join(gc_mangled) + ']'
|
||||
gc_sha1: str | None = self.module_sha1
|
||||
gc_sname: str = f'%"{gc_sha1}.{gc_spec}"' if gc_sha1 else f'%struct.{gc_spec}'
|
||||
if embedded:
|
||||
return gc_sname
|
||||
return f'{gc_sname}*'
|
||||
# 多参数泛型(dict[K, V]):'][' 分隔,与
|
||||
# _mangle_generic_class_name 一致
|
||||
gc_nodes: list[ast.AST] = (
|
||||
list(gc_slice.elts) if isinstance(gc_slice, ast.Tuple) else [gc_slice])
|
||||
gc_mangled: list[str] = [
|
||||
ResolveGenericTypeArgStr(
|
||||
gc_node,
|
||||
TCAliasMap=self._t_c_imported_names,
|
||||
StructSha1Map=self.struct_sha1_map)
|
||||
for gc_node in gc_nodes]
|
||||
gc_spec: str = gc_name + '[' + ']['.join(gc_mangled) + ']'
|
||||
# 特化名前缀取**泛型模板类定义模块**的 SHA1(list → includes/_list.vp、
|
||||
# Box → 定义 Box 的模块,查 struct_sha1_map 即"类名 → 定义模块"表),
|
||||
# 与定义端 HandlesClassDef._specialize_generic_class 的
|
||||
# Gen.module_sha1 = template['sha1']、调用点
|
||||
# Gen._struct_sha1_map[spec_name] 同一条规则源。
|
||||
# 此前用 self.module_sha1(使用方模块):同一特化在 declare(使用方前缀)
|
||||
# 与 define/call(模板模块前缀)两侧不一致 → 跨模块 undefined symbol。
|
||||
gc_sha1: str | None = self.struct_sha1_map.get(gc_name, self.module_sha1)
|
||||
gc_sname: str = f'%"{gc_sha1}.{gc_spec}"' if gc_sha1 else f'%struct.{gc_spec}'
|
||||
# 一律以指针引用(不区分 embedded):定义端对嵌入式泛型容器
|
||||
# (字段 / t.CArray 元素)用不透明指针(实测字段 i8*,见
|
||||
# FieldForms/FieldBox/FieldOrder),嵌入 unsized opaque
|
||||
# 结构体值会让字段/元素偏移错位;非 embedded(参数/返回)
|
||||
# 亦与定义端同为指针
|
||||
return f'{gc_sname}*'
|
||||
return f'{base}'
|
||||
elif isinstance(annotation, ast.Constant):
|
||||
if annotation.value is None:
|
||||
|
||||
@@ -9,7 +9,7 @@ from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
from lib.core.SymbolUtils import IsListAnnotation, ParseListAnnotation, FindStructNameInAnnotation, AnnotationContainsName, IsCPtrNode
|
||||
from lib.core.SymbolUtils import IsListAnnotation, ParseListAnnotation, FindStructNameInAnnotationWithContext, AnnotationContainsName, IsCPtrNode
|
||||
|
||||
|
||||
def _IsGenericTpName(name: str) -> bool:
|
||||
@@ -492,7 +492,8 @@ class AnnAssignHandle(BaseHandle):
|
||||
self._HandleGenericListLiteralAssign(VarName, Node, Gen, list_sub)
|
||||
return
|
||||
if TypeInfo.IsVoid and isinstance(Node.annotation, ast.BinOp):
|
||||
found: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs)
|
||||
found: str | None = FindStructNameInAnnotationWithContext(
|
||||
Node.annotation, self.Trans, Gen)
|
||||
if found:
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = t.CStruct(name=found)
|
||||
@@ -547,7 +548,8 @@ class AnnAssignHandle(BaseHandle):
|
||||
# FindStructNameInAnnotation 以 attr/短名命中,找回真实类名。
|
||||
if (isinstance(Node.annotation, ast.BinOp)
|
||||
and isinstance(Node.annotation.op, ast.BitOr)):
|
||||
_union_struct_name2: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs)
|
||||
_union_struct_name2: str | None = FindStructNameInAnnotationWithContext(
|
||||
Node.annotation, self.Trans, Gen)
|
||||
# resolver 对模块限定 struct 联合(llvmlite.Value | t.CPtr)常给出
|
||||
# 指针占位名(如 '{sha1}.rawptr')且该占位恰好注册在 Gen.structs,
|
||||
# 使上方 TypeInfo.Name in Gen.structs 通过并登记错误类名 → 字段
|
||||
@@ -876,7 +878,8 @@ class AnnAssignHandle(BaseHandle):
|
||||
Gen.local_var_byteorders[VarName] = 'big'
|
||||
|
||||
if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr):
|
||||
found_struct: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs)
|
||||
found_struct: str | None = FindStructNameInAnnotationWithContext(
|
||||
Node.annotation, self.Trans, Gen)
|
||||
# 若 FindStructNameInAnnotation 仅返回裸模板名(如 'ndarray'),但注解中
|
||||
# 含泛型特化(如 numpy.ndarray[t.CDouble]),用 LLVM 类型名构造特化名
|
||||
# (如 'ndarray[double]')。main.py 的 Gen.structs 可能只有 opaque 'ndarray',
|
||||
|
||||
@@ -13,6 +13,7 @@ from lib.constants import config as _config
|
||||
from lib.includes import t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES
|
||||
from lib.core.SymbolUtils import IsPtrSubscriptNode, IsListAnnotation
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
|
||||
@@ -754,6 +755,17 @@ class BaseHandle:
|
||||
"""解析注解类型,BinOp(BitOr) 优先使用 MergeTypes,其他使用 FromNode。
|
||||
|
||||
统一处理函数返回类型和参数类型的 BinOp 联合类型解析。
|
||||
指针下标(rawptr[T] 内置裸指针 / t.CPtr[T] / 裸名 CPtr[T],三者等价
|
||||
`T | t.CPtr`)同样交给 TypeMerge 解析:内层 T 走通用类型解析(含跨模块
|
||||
类经 Gen.structs 反查 SHA1 前缀),指针层数与源码 `T | t.CPtr` 一致;
|
||||
若交给 CTypeInfo.FromNode(TypeAnnotationResolver)解析,
|
||||
rawptr[ast.AST] 会退化成 CVoid/1(i8*)、t.CPtr[ast.AST] 亦退化成
|
||||
CVoid/1(其 Subscript-CPtr 分支不带 Gen.structs 反查),与 declare 端
|
||||
%"<sha1>.AST"* 分裂。
|
||||
命中泛型模板的泛型容器下标(list[X] / rawptr[list[X]] 等)同样交
|
||||
TypeMerge:字段(embedded)位置与参数/返回注解**同一解析**,否则
|
||||
CTypeInfo.FromNode 把容器折叠成 i8*,字段类型与 declare/stub 端
|
||||
的特化名指针不一致(同一结构体在定义端/声明端布局描述不同)。
|
||||
"""
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
merger: Any = getattr(self.Trans, 'TypeMergeHandler', None)
|
||||
@@ -761,7 +773,90 @@ class BaseHandle:
|
||||
info: CTypeInfo | None = merger.MergeTypes(annotation)
|
||||
if info is not None and isinstance(info, CTypeInfo):
|
||||
return info
|
||||
return CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
|
||||
if IsPtrSubscriptNode(annotation, self.Trans.SymbolTable):
|
||||
merger = getattr(self.Trans, 'TypeMergeHandler', None)
|
||||
if merger:
|
||||
info = merger.GetCTypeInfo(annotation)
|
||||
if isinstance(info, CTypeInfo) and info.BaseType is not None:
|
||||
return info
|
||||
if (isinstance(annotation, ast.Subscript)
|
||||
and self._SubscriptHitsGenericTemplate(annotation)
|
||||
and getattr(self.Trans, 'TypeMergeHandler', None) is not None):
|
||||
gci: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(annotation)
|
||||
if isinstance(gci, CTypeInfo) and gci.BaseType is not None:
|
||||
return gci
|
||||
if isinstance(annotation, ast.Attribute):
|
||||
return self._ResolveAttributeAnnotationType(annotation)
|
||||
Fallback: CTypeInfo | None = CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
|
||||
return self._ResolveStackArrayElementFallback(annotation, Fallback)
|
||||
|
||||
def _ResolveStackArrayElementFallback(
|
||||
self, annotation: ast.expr, Fallback: CTypeInfo | None) -> CTypeInfo | None:
|
||||
"""固定数组注解(`t.CArray[T, N]` / `list[T, N]`)元素类型兜底解析。
|
||||
|
||||
CTypeInfo.FromNode(TypeAnnotationResolver 的 IsListAnnotation 分支)只
|
||||
会用自身解析元素类型:元素命中泛型模板时(list[X] / list[rawptr[X]])解
|
||||
析为空 → 整个注解 BaseType=None → 调用方(CollectAnnAssignMember)把
|
||||
VoidType 换成 i8*,字段即塌成 i8*,与声明端
|
||||
DeclarationGenerator._get_type_str 的 ValueIsCArray 分支给出的
|
||||
`[N x <元素>]` 布局不一致(规则 4:能不变 i8* 的就不变 i8*)。
|
||||
此处仅在该元素解析为空时兜底:用**与参数注解同一解析**
|
||||
(ResolveAnnotationType 递归,泛型容器因此走 TypeMerge 特化,跨模块类
|
||||
经 Gen.structs 反查 SHA1)解析元素,再套上数组维度(维度序与
|
||||
TypeAnnotationResolver 的 `insert(0, count)` 一致)。
|
||||
元素可解析的形态(t.CArray[t.CInt, 8] / t.CArray[Node, 4] / 嵌套 CArray)
|
||||
保持 FromNode 结果原样,避免改动既有布局。
|
||||
"""
|
||||
if isinstance(Fallback, CTypeInfo) and Fallback.BaseType is not None:
|
||||
return Fallback
|
||||
if not (isinstance(annotation, ast.Subscript) and IsListAnnotation(annotation)):
|
||||
return Fallback
|
||||
SliceNode: ast.AST = annotation.slice
|
||||
if not (isinstance(SliceNode, ast.Tuple) and len(SliceNode.elts) == 2):
|
||||
return Fallback
|
||||
ElemInfo: CTypeInfo | None = self.ResolveAnnotationType(SliceNode.elts[0])
|
||||
if not isinstance(ElemInfo, CTypeInfo) or ElemInfo.BaseType is None:
|
||||
return Fallback
|
||||
CountVal: int | None = CTypeInfo.TryEvalConstExpr(SliceNode.elts[1], self.Trans.SymbolTable)
|
||||
if not isinstance(CountVal, int) or CountVal <= 0:
|
||||
return Fallback
|
||||
Result: CTypeInfo = ElemInfo.Copy()
|
||||
Result.ArrayDims = [str(CountVal)] + list(ElemInfo.ArrayDims)
|
||||
return Result
|
||||
|
||||
def _ResolveAttributeAnnotationType(self, annotation: ast.Attribute) -> CTypeInfo | None:
|
||||
"""Attribute 注解(`t.CInt` / `ast.AST` / `<sha1>.CLS`)解析。
|
||||
|
||||
先走 CTypeInfo.FromNode(TypeAnnotationResolver,覆盖 t/c 内建与已在本模块
|
||||
SymbolTable 注册的类):其 BaseType 已解析时语义不变。
|
||||
**仅在 FromNode 解析不出来时**(BaseType 为 None,即该类未随本模块
|
||||
import/预扫描注册)按类名查 `Gen.structs` / `Gen._struct_sha1_map` 后交
|
||||
TypeMerge(HandlesTypeMerge 的 Attribute 分支,与声明端
|
||||
DeclarationGenerator._get_type_str 的 `attr_name in struct_names`、名称域
|
||||
SymbolUtils._ResolveAttributeArgStr 同一条"类名 → SHA1"规则)。
|
||||
|
||||
不修此路时跨模块类 Attribute(`rawptr[<sha1>.CLS]` 脱糖后的
|
||||
`<sha1>.CLS | t.CPtr`、泛型 T 替换出的裸 `<sha1>.CLS`、`list[ast.AST]`
|
||||
特化的 `append(item: T)`)在定义端判为"无法识别的参数类型注解"抛
|
||||
SyntaxError,被上层 broad except 吞掉后退化为 i32/i8*,而声明端给
|
||||
`%"<sha1>.CLS"*`,字段/签名两侧不一致。
|
||||
"""
|
||||
fallback: CTypeInfo | None = CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
|
||||
if fallback is not None and fallback.BaseType is not None:
|
||||
return fallback
|
||||
attr_name: str = getattr(annotation, 'attr', '') or ''
|
||||
gen: Any = getattr(self.Trans, 'LlvmGen', None)
|
||||
if not attr_name or gen is None:
|
||||
return fallback
|
||||
if (attr_name not in getattr(gen, 'structs', {})
|
||||
and attr_name not in getattr(gen, '_struct_sha1_map', {})):
|
||||
return fallback
|
||||
merger: Any = getattr(self.Trans, 'TypeMergeHandler', None)
|
||||
if merger is not None:
|
||||
info: CTypeInfo | None = merger.GetCTypeInfo(annotation)
|
||||
if isinstance(info, CTypeInfo) and info.BaseType is not None:
|
||||
return info
|
||||
return fallback
|
||||
|
||||
def ResolveParamAnnotation(self, annotation: ast.expr) -> CTypeInfo | None:
|
||||
"""函数参数注解解析(阻塞 B 同根第三处修复)。
|
||||
@@ -781,6 +876,13 @@ class BaseHandle:
|
||||
info: CTypeInfo | None = merger.MergeTypes(annotation)
|
||||
if info is not None and isinstance(info, CTypeInfo):
|
||||
return info
|
||||
# 指针下标参数注解(rawptr[T] / t.CPtr[T] / 裸名 CPtr[T],含
|
||||
# rawptr[list[X]] 等容器:_SubscriptHitsGenericTemplate 也命中,但统一交
|
||||
# ResolveAnnotationType 处理更简单——它已把指针下标路由到 TypeMerge)。
|
||||
if IsPtrSubscriptNode(annotation, self.Trans.SymbolTable):
|
||||
info = self.ResolveAnnotationType(annotation)
|
||||
if isinstance(info, CTypeInfo) and info.BaseType is not None:
|
||||
return info
|
||||
if isinstance(annotation, ast.Subscript) and getattr(self.Trans, 'TypeMergeHandler', None):
|
||||
if self._SubscriptHitsGenericTemplate(annotation):
|
||||
try:
|
||||
@@ -789,7 +891,16 @@ class BaseHandle:
|
||||
return _gci
|
||||
except Exception:
|
||||
pass
|
||||
return CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
|
||||
# Attribute 参数注解(`<sha1>.CLS` 裸引用 / 泛型 T 替换出的 `<sha1>.CLS`)
|
||||
# 与 ResolveAnnotationType 共用同一条规则(_ResolveAttributeAnnotationType →
|
||||
# TypeMergeHandler.GetCTypeInfo 的 Attribute 分支查 Gen.structs /
|
||||
# Gen._struct_sha1_map),不在此复制第二套查表;否则 list[X] 特化方法
|
||||
# `append(item: T)` 的参数 T(= 裸 `<sha1>.CLS`)解析为空 → VoidType →
|
||||
# 抛"无法识别的参数类型注解" → 特化模板方法未注册。
|
||||
if isinstance(annotation, ast.Attribute):
|
||||
return self.ResolveAnnotationType(annotation)
|
||||
Fallback: CTypeInfo | None = CTypeInfo.FromNode(annotation, self.Trans.SymbolTable)
|
||||
return self._ResolveStackArrayElementFallback(annotation, Fallback)
|
||||
|
||||
def _SubscriptHitsGenericTemplate(self, annotation: ast.Subscript) -> bool:
|
||||
"""判断 Subscript 是否命中泛型模板:裸模板名(list[X]/GSList[X]),
|
||||
|
||||
@@ -8,7 +8,8 @@ import copy
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Exportable import EnumMember as ExportEnumMember
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
|
||||
from lib.core.SymbolUtils import IsTModule, FindStructNameInAnnotation
|
||||
from lib.core.SymbolUtils import (
|
||||
IsTModule, FindStructNameInAnnotationWithContext, MangleTypeArgByRegistry)
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
@@ -66,19 +67,52 @@ class ClassHandle(BaseHandle):
|
||||
return False
|
||||
|
||||
def _mangle_generic_class_name(self, class_name: str, type_args: list[str]) -> str:
|
||||
mangled_args: list[str] = []
|
||||
for ta in type_args:
|
||||
llvm_str: str | None = CTypeRegistry.NameToLLVM(ta)
|
||||
if llvm_str:
|
||||
if llvm_str in ('float', 'double', 'half', 'fp128'):
|
||||
mangled: str = 'f' + str(CTypeRegistry.GetClassByName(ta)().Size)
|
||||
else:
|
||||
mangled = llvm_str
|
||||
else:
|
||||
mangled = ta
|
||||
mangled_args.append(mangled)
|
||||
"""泛型类特化名:class_name + '[arg1][arg2]'。
|
||||
|
||||
单项 mangling 走 SymbolUtils.MangleTypeArgByRegistry(声明端
|
||||
DeclarationGenerator 的泛型分支以 ResolveGenericTypeArgStr 调用同一函数,
|
||||
两侧拼名规则唯一),'][' 分隔与 HandlesTypeMerge / DeclarationGenerator 一致。
|
||||
"""
|
||||
mangled_args: list[str] = [MangleTypeArgByRegistry(ta) for ta in type_args]
|
||||
return class_name + '[' + ']['.join(mangled_args) + ']'
|
||||
|
||||
def _HasClassDefinition(self, Name: str, Gen: LlvmGeneratorMixin) -> bool:
|
||||
"""类型名是否有类定义——泛型"类类型参数"的唯一判据。
|
||||
|
||||
数据来源就是"是否存在类定义"这一事实本身:Gen._struct_sha1_map
|
||||
(类名 → 定义模块 SHA1,Phase2 从各 .vpi 扫描构建)与 Gen.structs
|
||||
(本模块已发射的 struct 名,键形如 '{sha1}.{名}')。
|
||||
因此内建值类型(int/CInt/…,LLVM 映射 i32 等)与语言内建 `str`
|
||||
(LLVM 映射 i8*)都不在两张表里 → 自然判为值类型,不需要任何
|
||||
内建名白名单/黑名单参与判定。
|
||||
"""
|
||||
if not Name:
|
||||
return False
|
||||
if Name in Gen._struct_sha1_map or Name in Gen.structs:
|
||||
return True
|
||||
for Sha1 in Gen._struct_sha1_map.values():
|
||||
if f'{Sha1}.{Name}' in Gen.structs:
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _BareClassAnnotationName(Node: ast.AST) -> str | None:
|
||||
"""取注解节点的裸类名(供 class_type_names 判定),非类名形态返回 None。
|
||||
|
||||
T 替换后的两种形态都要认:
|
||||
- ast.Name:'AST'(未注册类)或 'sha1.AST'(旧式点号名)→ 去前缀;
|
||||
- ast.Attribute:'sha1.AST' 经 _make_replacement_node/_make_name_node
|
||||
产出的 Attribute 链(Name('sha1').AST)→ attr 名。
|
||||
其余(Union `X | t.CPtr`、Subscript `list[T]`、内建)→ None,不追加
|
||||
指针层(已显式写了 `| t.CPtr` 的注解不再重复加层)。
|
||||
"""
|
||||
if isinstance(Node, ast.Name):
|
||||
Name: str = Node.id
|
||||
return Name.split('.')[-1] if '.' in Name else Name
|
||||
if isinstance(Node, ast.Attribute):
|
||||
return Node.attr
|
||||
return None
|
||||
|
||||
def _specialize_generic_class(self, ClassName: str, type_args: list[str], Gen: LlvmGeneratorMixin, type_names: list[str] | None = None, declare_only: bool = False) -> str | None:
|
||||
if not hasattr(self, '_generic_class_templates') or ClassName not in self._generic_class_templates:
|
||||
return None
|
||||
@@ -125,6 +159,17 @@ class ClassHandle(BaseHandle):
|
||||
'int', 'double', 'float', 'i8', 'i16', 'i32', 'i64', 'void',
|
||||
'half', 'fp128', 'char', 'bool',
|
||||
}
|
||||
# 值类型/类类型不再用"内建名白名单"判定:见下方 class_type_names,
|
||||
# 唯一判据是"是否有类定义"(_HasClassDefinition:Gen._struct_sha1_map
|
||||
# / Gen.structs)。内建(int/CInt/…)与语言内建 `str`(LLVM 映射 i8*)
|
||||
# 都不在类表里 → 天然判为值类型,无需名表。
|
||||
# 历史教训(名表判据的代价,保留以便回归时理解):`str` 曾漏在
|
||||
# "非类类型名"集合外 → `list[str]` 的类型参数被误判为类类型,特化后
|
||||
# 方法签名被额外包一层 `| t.CPtr`(append/set 形参 i8**、get/pop 返回
|
||||
# i8**)→ 调用点多解一层 load(读字符串首 8 字节)→ ASan 崩溃。
|
||||
# 注意 _BUILTIN_TYPE_NAMES 本身仍保留:它用于 type_map 替换
|
||||
# 与 _t_c_imported_names 注册,不能把 'str' 并进去
|
||||
# (否则 HandlesTypeMerge 会把注解 `str` 当 `t.str` 解析)。
|
||||
type_map: dict[str, str] = {}
|
||||
for i, tp_name in enumerate(type_param_names):
|
||||
if type_names and i < len(type_names):
|
||||
@@ -147,15 +192,15 @@ class ClassHandle(BaseHandle):
|
||||
type_map[tp_name] = tn
|
||||
else:
|
||||
type_map[tp_name] = type_args[i]
|
||||
# 检测哪些类型参数在原始类型实参中带有 | t.CPtr
|
||||
# 当 type_arg 以 'ptr' 结尾(_resolve_type_arg_str 将 t.CPtr 规范化为 'ptr')
|
||||
# 且对应的 type_name(去模块前缀后)不是内建类型名时,
|
||||
# 说明调用方写了 list[AST | t.CPtr]。注意用 tn_bare 判断:
|
||||
# 检测哪些类型参数在原始类型实参中带有指针语义(| t.CPtr / rawptr[T])
|
||||
# 当 type_arg 以 '*' 结尾(mangling 把每个 CPtr 层渲染为一层 '*')且对应的
|
||||
# type_name(去模块前缀后)不是内建类型名时,说明调用方写了
|
||||
# list[AST | t.CPtr] / list[rawptr[AST]]。注意用 tn_bare 判断:
|
||||
# 't.CPtr' 去前缀后是 'CPtr'(内建),不算类类型参数。
|
||||
cptr_params: set[str] = set()
|
||||
for i, tp_name in enumerate(type_param_names):
|
||||
type_arg: str = type_args[i]
|
||||
if type_arg.endswith('ptr'):
|
||||
if type_arg.endswith('*'):
|
||||
tn: str = type_names[i] if type_names and i < len(type_names) else type_args[i]
|
||||
tn_bare_c: str = tn.split('.')[-1] if '.' in tn else tn
|
||||
if tn_bare_c not in _BUILTIN_TYPE_NAMES:
|
||||
@@ -163,12 +208,15 @@ class ClassHandle(BaseHandle):
|
||||
# Bug 2 修复:识别特化为 class 类型的类型参数
|
||||
# 这类参数在方法签名中是裸 T(无 | t.CPtr),特化后为裸 ClassName(值类型)
|
||||
# 需要加 | t.CPtr 使其成为指针类型(class 实例应按指针传递)
|
||||
# 判据 = "是否有类定义"(_HasClassDefinition),存**裸名**:注解侧的
|
||||
# 比较也用裸名(T 替换后的 'sha1.Param' 去前缀)——此前存带模块前缀的
|
||||
# tn(如 'ast.AST')而比较用裸名 'AST',前缀形态永不命中。
|
||||
class_type_names: set[str] = set()
|
||||
for i, tp_name in enumerate(type_param_names):
|
||||
tn: str = type_names[i] if type_names and i < len(type_names) else type_args[i]
|
||||
tn_bare_cls: str = tn.split('.')[-1] if '.' in tn else tn
|
||||
if tn_bare_cls not in _BUILTIN_TYPE_NAMES:
|
||||
class_type_names.add(tn)
|
||||
if self._HasClassDefinition(tn_bare_cls, Gen):
|
||||
class_type_names.add(tn_bare_cls)
|
||||
# 仅对 t 模块内建类型名注册 _t_c_imported_names(如 CInt -> ('t','CInt'))
|
||||
# 类名(如 AST)不应注册为 t.AST,否则会污染名称解析
|
||||
if type_names:
|
||||
@@ -189,30 +237,27 @@ class ClassHandle(BaseHandle):
|
||||
if arg.annotation:
|
||||
arg.annotation = self.Trans.FunctionHandler._replace_type_in_annotation(arg.annotation, type_map, cptr_params)
|
||||
# class 类型参数加指针语义:T -> GNode -> GNode | t.CPtr
|
||||
# 去除 SHA1 前缀后检查(如 fc06023a9bcfc93a.AST -> AST)
|
||||
if isinstance(arg.annotation, ast.Name):
|
||||
raw_name: str = arg.annotation.id
|
||||
if '.' in raw_name:
|
||||
raw_name = raw_name.split('.')[-1]
|
||||
if raw_name in class_type_names:
|
||||
arg.annotation = ast.BinOp(
|
||||
left=ast.Name(id=arg.annotation.id, ctx=ast.Load()),
|
||||
op=ast.BitOr(),
|
||||
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
|
||||
)
|
||||
if item.returns:
|
||||
item.returns = self.Trans.FunctionHandler._replace_type_in_annotation(item.returns, type_map, cptr_params)
|
||||
# 返回类型也加指针语义
|
||||
if isinstance(item.returns, ast.Name):
|
||||
raw_name: str = item.returns.id
|
||||
if '.' in raw_name:
|
||||
raw_name = raw_name.split('.')[-1]
|
||||
if raw_name in class_type_names:
|
||||
item.returns = ast.BinOp(
|
||||
left=ast.Name(id=item.returns.id, ctx=ast.Load()),
|
||||
# T 替换后的真实形态是 Attribute 链('<sha1>.GNode' →
|
||||
# Name('<sha1>').GNode,见 _make_replacement_node/_make_name_node),
|
||||
# 不是 ast.Name:此前只认 ast.Name → 方法形参漏加 | t.CPtr,
|
||||
# 特化后按值结构体传参(被调者栈帧副本地址入链 → 悬垂写)。
|
||||
raw_name: str | None = self._BareClassAnnotationName(arg.annotation)
|
||||
if raw_name is not None and raw_name in class_type_names:
|
||||
arg.annotation = ast.BinOp(
|
||||
left=arg.annotation,
|
||||
op=ast.BitOr(),
|
||||
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
|
||||
)
|
||||
if item.returns:
|
||||
item.returns = self.Trans.FunctionHandler._replace_type_in_annotation(item.returns, type_map, cptr_params)
|
||||
# 返回类型也加指针语义(同一裸名判据,形态同上)
|
||||
raw_name: str | None = self._BareClassAnnotationName(item.returns)
|
||||
if raw_name is not None and raw_name in class_type_names:
|
||||
item.returns = ast.BinOp(
|
||||
left=item.returns,
|
||||
op=ast.BitOr(),
|
||||
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
|
||||
)
|
||||
self.Trans.FunctionHandler._apply_type_map_to_body(item.body, type_map, cptr_params)
|
||||
saved_builder: ir.IRBuilder = Gen.builder
|
||||
saved_func: ir.Function = Gen.func
|
||||
@@ -228,7 +273,14 @@ class ClassHandle(BaseHandle):
|
||||
# 切换 module_sha1 为泛型模板定义模块的 SHA1,
|
||||
# 使结构体类型名和方法定义名都用定义模块的 SHA1 前缀,
|
||||
# 与调用端 _struct_sha1_map 查到的 SHA1 一致。
|
||||
template_sha1: str | None = template.get('sha1')
|
||||
template_sha1: str | None = template.get('sha1')
|
||||
if not template_sha1:
|
||||
# 模板注册表缺 sha1 时回退到"模板类定义模块"(_struct_sha1_map 即
|
||||
# 类名 → 定义模块表,Phase2 从各 .vpi 扫描构建):与声明端
|
||||
# DeclarationGenerator._get_type_str 的泛型前缀、调用点
|
||||
# Gen._struct_sha1_map[spec_name] 同一条规则源;否则 declare/define
|
||||
# 两侧前缀分裂(使用方模块 vs 模板模块)→ 跨模块 undefined symbol。
|
||||
template_sha1 = Gen._struct_sha1_map.get(ClassName)
|
||||
saved_gen_sha1: str | None = getattr(Gen, 'module_sha1', None)
|
||||
saved_trans_sha1: str | None = getattr(self.Trans, '_module_sha1', None)
|
||||
if template_sha1:
|
||||
@@ -507,6 +559,40 @@ class ClassHandle(BaseHandle):
|
||||
ancestor = Gen.class_parent.get(ancestor)
|
||||
return IsCpythonObject, IsCVTable, ParentClassName, IsNoVTable
|
||||
|
||||
def _RegisterGenericClassTemplate(self, Node: ast.ClassDef) -> None:
|
||||
"""注册泛型类模板到 `_generic_class_templates`(判据唯一:`_is_generic_class`)。
|
||||
|
||||
调用点两处:类处理阶段(_EmitClassLlvm)与前置声明之前的本模块预扫描
|
||||
(PrescanModuleGenericClassTemplates)。注册内容唯一(node/type_params/
|
||||
定义模块 SHA1),两个调用点不得各写一份。
|
||||
"""
|
||||
if not hasattr(self, '_generic_class_templates'):
|
||||
self._generic_class_templates = {}
|
||||
self._generic_class_templates[Node.name] = {
|
||||
'node': Node,
|
||||
'type_params': [tp.name for tp in Node.type_params],
|
||||
# 记录泛型模板定义模块的 SHA1,用于特化时统一命名空间
|
||||
'sha1': getattr(self.Trans, '_module_sha1', None),
|
||||
}
|
||||
|
||||
def PrescanModuleGenericClassTemplates(self, ModuleBody: object) -> None:
|
||||
"""前置声明之前预注册**本模块**泛型类模板。
|
||||
|
||||
判据与 includes 侧对泛型类的注册(HandlesImports._LoadModuleDeclarationsFromFile/
|
||||
_EmitImportFromDeclarations 的 `node.type_params` 非空)**同源**,即
|
||||
_is_generic_class,不看类名白名单。
|
||||
|
||||
类处理阶段(下方 _EmitClassLlvm)才注册本模块模板,而顶层函数前置声明
|
||||
(GenerateLlvmDirect 的 _EmitFunctionForwardDeclLlvm)已需要它:模块级函数
|
||||
参数/返回注解写自身泛型类(`def f(b: Box[Node])`)时
|
||||
_SubscriptHitsGenericTemplate 判为不命中 → TypeAnnotationResolver 解析为空 →
|
||||
VoidType → 抛"无法识别的参数类型注解";而同模块方法参数(类处理阶段之后)
|
||||
却可用,二者分裂。预注册后两处走同一 _generic_class_templates。
|
||||
"""
|
||||
for Node in ModuleBody:
|
||||
if isinstance(Node, ast.ClassDef) and self._is_generic_class(Node):
|
||||
self._RegisterGenericClassTemplate(Node)
|
||||
|
||||
def _EmitClassLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin, declare_only: bool = False) -> None:
|
||||
ClassName: str = Node.name
|
||||
# t.CType 及其子类(CChar/CInt/CVoid/CPtr/CTypeDefault 等)是"类型强转"标记,
|
||||
@@ -515,16 +601,7 @@ class ClassHandle(BaseHandle):
|
||||
if self._is_classname_ctype_marker(ClassName):
|
||||
return
|
||||
if self._is_generic_class(Node):
|
||||
if not hasattr(self, '_generic_class_templates'):
|
||||
self._generic_class_templates = {}
|
||||
type_params: list[str] = [tp.name for tp in Node.type_params]
|
||||
# 记录泛型模板定义模块的 SHA1,用于特化时统一命名空间
|
||||
template_sha1: str | None = getattr(self.Trans, '_module_sha1', None)
|
||||
self._generic_class_templates[ClassName] = {
|
||||
'node': Node,
|
||||
'type_params': type_params,
|
||||
'sha1': template_sha1,
|
||||
}
|
||||
self._RegisterGenericClassTemplate(Node)
|
||||
return
|
||||
if self._is_exception_class(Node):
|
||||
self._RegisterExceptionClass(Node)
|
||||
@@ -797,10 +874,11 @@ class ClassHandle(BaseHandle):
|
||||
if TypeInfo:
|
||||
if isinstance(MemberType, ir.PointerType) and isinstance(MemberType.pointee, ir.IntType) and MemberType.pointee.width == 8:
|
||||
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
|
||||
element_class: str | None = FindStructNameInAnnotation(item.annotation, Gen.structs)
|
||||
element_class: str | None = FindStructNameInAnnotationWithContext(
|
||||
item.annotation, self.Trans, Gen)
|
||||
# Fallback: FindStructNameInAnnotation 不处理 Subscript slice 为 BinOp 的情况
|
||||
# (如 list[AST | t.CPtr] | t.CPtr),使用 TypeInfo.Name 作为回退。
|
||||
# TypeInfo.Name 由 _HandleSubscript 设置为特化名(如 'list[sha1.ASTptr]'),
|
||||
# TypeInfo.Name 由 _HandleSubscript 设置为特化名(如 'list[sha1.AST*]'),
|
||||
# 经 _MergeCTypeInfoInto 传播后保留。
|
||||
if not element_class and TypeInfo.IsStruct and TypeInfo.Name and TypeInfo.Name in Gen.structs:
|
||||
element_class = TypeInfo.Name
|
||||
@@ -816,7 +894,8 @@ class ClassHandle(BaseHandle):
|
||||
and isinstance(MemberType.pointee, ir.IdentifiedStructType)
|
||||
and isinstance(item.annotation, ast.BinOp)
|
||||
and isinstance(item.annotation.op, ast.BitOr)):
|
||||
spec_in_anno: str | None = FindStructNameInAnnotation(item.annotation, Gen.structs)
|
||||
spec_in_anno: str | None = FindStructNameInAnnotationWithContext(
|
||||
item.annotation, self.Trans, Gen)
|
||||
if spec_in_anno and '[' in spec_in_anno:
|
||||
if ClassName not in Gen.class_member_element_class:
|
||||
Gen.class_member_element_class[ClassName] = {}
|
||||
|
||||
@@ -547,8 +547,15 @@ class ExprAttrHandle(BaseHandle):
|
||||
if self._is_char_pointer(ObjVal):
|
||||
if ClassName in Gen.structs:
|
||||
ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
|
||||
# 二级指针解引用
|
||||
if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||||
# 二级指针解引用。模块级全局指针变量(如 _g_gen: rawptr[Generator.Generator])
|
||||
# 的全局元素类型比实际存值多一层:写入端(main.vp `GenApi._g_gen = gen`)生成
|
||||
# 为 bitcast T*→T** 后直接存值,未取地址;读取端必须做其逆运算 bitcast,绝不能
|
||||
# 再 load——否则把 T* 当 T** 再解引用,接收者被取成对象首字段的位,方法内读
|
||||
# self->Gen 即野指针(ASan: CallGenBase.SetTempDir 读悬空地址崩溃)。
|
||||
if (isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType)
|
||||
and isinstance(Node.value, ast.Name) and Node.value.id in Gen.module.globals):
|
||||
ObjVal = Gen.builder.bitcast(ObjVal, ObjVal.type.pointee, name=f"cast_{VarName}_global")
|
||||
elif isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType):
|
||||
ObjVal = Gen._load(ObjVal, name=f"Load_{VarName}")
|
||||
|
||||
# 检查结构体匹配
|
||||
|
||||
@@ -12,7 +12,9 @@ from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp
|
||||
from lib.core.SymbolUtils import (
|
||||
IsTModule, ExtractTypeNameFromBinOp, IsPtrSubscriptNode, DesugarPtrSubscriptToUnion,
|
||||
ResolveTypeArgStr, GenericArgRawName)
|
||||
|
||||
|
||||
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
|
||||
@@ -3684,46 +3686,18 @@ class ExprCallHandle(BaseHandle):
|
||||
def _resolve_type_arg_str(self, node: ast.AST) -> str:
|
||||
"""将类型参数 AST 节点解析为规范化的类型字符串(用于泛型特化的 mangling)。
|
||||
|
||||
走和普通类型签名同样的规范化路径(不单独创建规则):
|
||||
- ast.Name: 若为已注册结构体,加 SHA1 前缀(如 'AST' → '9ada227b160c07a1.AST'),
|
||||
与 DeclarationGenerator._get_type_str 对 ast.Name 的处理一致
|
||||
- ast.Attribute: t.CPtr → 'ptr'(指针标记,等价于普通签名中 t.CPtr → i8* 的指针语义;
|
||||
用 'ptr' 而非 '*' 是因为 _get_or_create_struct 的 clean_name 会移除 '*',
|
||||
导致 Phase2 直接编译与 .stub.ll 加载路径的 mangled 名不一致);
|
||||
其他 t 模块类型按 CTypeRegistry.NameToLLVM 解析
|
||||
- ast.BinOp: 递归处理左右操作数并直接拼接(如 AST | t.CPtr → 'sha1.ASTptr'),
|
||||
避免空格/管道符导致 _get_or_create_struct 的 clean_name 清洗不一致
|
||||
规则本体在 SymbolUtils.ResolveTypeArgStr(定义端/声明端唯一规则源,
|
||||
声明端 DeclarationGenerator 的泛型分支亦调用同一函数),此处仅注入
|
||||
翻译器上下文:
|
||||
- t/c 导入别名表(from t import CInt as myint → 't.CInt')
|
||||
- 跨模块结构体 SHA1 表(ast.Name/Attribute 命中 → '{sha1}.{名}',与普通签名一致)
|
||||
"""
|
||||
if isinstance(node, ast.Name):
|
||||
tn: str = node.id
|
||||
t_c_imported = getattr(self.Trans, '_t_c_imported_names', {})
|
||||
if tn in t_c_imported:
|
||||
src_module, src_name = t_c_imported[tn]
|
||||
return f'{src_module}.{src_name}'
|
||||
# 若为已注册结构体,加 SHA1 前缀(和普通签名路径一致)
|
||||
Gen = self.Trans.LlvmGen
|
||||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) if Gen is not None else {}
|
||||
if tn in struct_sha1_map:
|
||||
return f'{struct_sha1_map[tn]}.{tn}'
|
||||
return tn
|
||||
if isinstance(node, ast.Attribute):
|
||||
if isinstance(node.value, ast.Name):
|
||||
full_name: str = f'{node.value.id}.{node.attr}'
|
||||
# t.CPtr → 'ptr'(指针标记,和普通签名中 t.CPtr 被解析为指针类型 i8* 语义一致)
|
||||
if full_name == 't.CPtr':
|
||||
return 'ptr'
|
||||
# 其他 t 模块类型按 CTypeRegistry 解析(和普通签名路径一致)
|
||||
llvm_str: str | None = CTypeRegistry.NameToLLVM(node.attr)
|
||||
if llvm_str is not None:
|
||||
return llvm_str
|
||||
return full_name
|
||||
return ast.unparse(node)
|
||||
if isinstance(node, ast.BinOp):
|
||||
left_str: str = self._resolve_type_arg_str(node.left)
|
||||
right_str: str = self._resolve_type_arg_str(node.right)
|
||||
# 直接拼接(如 'sha1.AST' + 'ptr' = 'sha1.ASTptr'),避免空格导致清洗不一致
|
||||
return f'{left_str}{right_str}'
|
||||
return ast.unparse(node)
|
||||
Gen = self.Trans.LlvmGen
|
||||
StructSha1Map: dict[str, str] = getattr(Gen, '_struct_sha1_map', {}) if Gen is not None else {}
|
||||
return ResolveTypeArgStr(
|
||||
node,
|
||||
TCAliasMap=getattr(self.Trans, '_t_c_imported_names', {}),
|
||||
StructSha1Map=StructSha1Map)
|
||||
|
||||
def _get_raw_type_name(self, node: ast.AST) -> str:
|
||||
"""获取类型节点的原始名称(不带模块前缀),用于泛型 T 替换。
|
||||
@@ -3743,30 +3717,24 @@ class ExprCallHandle(BaseHandle):
|
||||
def _resolve_generic_slice_type(self, sn: ast.AST) -> tuple[str, str] | None:
|
||||
"""解析泛型 slice 中的单个类型参数节点,返回 (type_arg, type_name) 或 None。
|
||||
|
||||
type_arg: 用于 mangling,走和普通签名同样的规范化路径
|
||||
(如 'AST | t.CPtr' → '9ada227b160c07a1.ASTptr',AST 加 SHA1 前缀,t.CPtr 处理为 ptr)
|
||||
type_name: 用于替换泛型类型参数 T(如 'AST' 或 'CInt',_specialize_generic_class 会自动加 | t.CPtr 给类名)
|
||||
type_arg: 用于 mangling,走**唯一规则源** _resolve_type_arg_str
|
||||
(内层与参数注解同解析:'AST | t.CPtr' / 'rawptr[AST]' →
|
||||
'{sha1}.AST*'、裸类名 'AST' → '{sha1}.AST'、标量按
|
||||
NormalizeGenericArgName 归一)
|
||||
type_name: 用于替换泛型类型参数 T(原始源码名,如 'AST' / 'CInt',
|
||||
_specialize_generic_class 会自动给类名加 | t.CPtr)
|
||||
指针下标 rawptr[T] 先折叠成等价的 `T | t.CPtr` 再解析,
|
||||
与源码联合写法得到同一 (type_arg, type_name):否则 list[rawptr[ast.AST]]
|
||||
会拼出 'rawptr[ast.AST]' 实参串(内层未混淆)→ 与 list[ast.AST | t.CPtr]
|
||||
的 '<sha1>.AST*' 分裂成两个特化名(结构体/方法声明/调用点三端不一致)。
|
||||
"""
|
||||
if IsPtrSubscriptNode(sn, self.Trans.SymbolTable):
|
||||
sn = DesugarPtrSubscriptToUnion(sn, self.Trans.SymbolTable)
|
||||
if isinstance(sn, ast.Name):
|
||||
tn: str = sn.id
|
||||
ts: str = 'int'
|
||||
if tn == 'int':
|
||||
ts, tn = 'int', 'CInt'
|
||||
elif tn == 'double':
|
||||
ts, tn = 'double', 'CDouble'
|
||||
elif tn == 'float':
|
||||
ts, tn = 'float', 'CFloat'
|
||||
elif tn == 'char':
|
||||
ts, tn = 'i8', 'CChar'
|
||||
elif tn == 'bool':
|
||||
ts, tn = 'i8', 'CBool'
|
||||
elif tn in ('CInt', 'CUInt', 'CInt32T', 'CUInt32T', 'CInt64T', 'CUInt64T', 'CInt16T', 'CUInt16T', 'CInt8T', 'CUInt8T', 'CChar', 'CShort', 'CLong'):
|
||||
ts = 'int'
|
||||
elif tn in ('CDouble', 'CFloat', 'CFloat64T', 'CFloat32T'):
|
||||
ts = 'double'
|
||||
else:
|
||||
ts = tn
|
||||
return (ts, tn)
|
||||
# type_arg 走唯一规则源(命中注册类加 SHA1 前缀,裸名与
|
||||
# `list[X]`/`rawptr[X]` 内层收敛到同一名字);
|
||||
# type_name 保留源码名供 T 替换与内建/类类型判定(两张表收拢在 SymbolUtils)
|
||||
return (self._resolve_type_arg_str(sn), GenericArgRawName(sn.id))
|
||||
# BinOp (如 AST | CPtr) 或 Attribute (如 t.CPtr / t.CInt)
|
||||
type_str: str = self._resolve_type_arg_str(sn)
|
||||
# type_name 保留模块前缀(如 't.CUnsignedChar'),避免 T(0) 替换为
|
||||
|
||||
@@ -8,7 +8,9 @@ import copy
|
||||
import traceback
|
||||
import llvmlite.ir as ir
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta
|
||||
from lib.core.SymbolUtils import IsTModule, FindStructNameInAnnotation, AnnotationContainsName
|
||||
from lib.core.SymbolUtils import (
|
||||
IsTModule, FindStructNameInAnnotationWithContext, AnnotationContainsName,
|
||||
IsPtrSubscriptNode, DesugarPtrSubscriptToUnion)
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
@@ -520,7 +522,8 @@ class FunctionHandle(BaseHandle):
|
||||
if not isinstance(ReturnTypeInfo, CTypeInfo):
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = t.CVoid()
|
||||
if (ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState) or ReturnTypeInfo.PtrCount >= 2:
|
||||
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] = []
|
||||
@@ -557,7 +560,10 @@ class FunctionHandle(BaseHandle):
|
||||
is_str_type: bool = False
|
||||
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
|
||||
is_str_type = True
|
||||
ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
|
||||
# 走 ResolveAnnotationType 而非 CTypeInfo.FromNode:指针下标
|
||||
# 返回注解(rawptr[T] / t.CPtr[T])需走 TypeMerge 通用解析,
|
||||
# 否则内层跨模块类解析不出 → CVoid/1(i8*)。
|
||||
ReturnTypeInfo = self.ResolveAnnotationType(Node.returns)
|
||||
if ReturnTypeInfo and ReturnTypeInfo.IsDefine:
|
||||
inferred: Any = self._infer_return_type_from_body(Node, Gen, ClassName)
|
||||
if inferred:
|
||||
@@ -637,9 +643,15 @@ class FunctionHandle(BaseHandle):
|
||||
ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0
|
||||
IsPtr = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
|
||||
ReturnType: ir.Type = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||||
if isinstance(ReturnType, ir.PointerType) and isinstance(ReturnType.pointee, ir.PointerType):
|
||||
if isinstance(ReturnType.pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
ReturnType = ir.PointerType(ReturnType.pointee.pointee)
|
||||
# 此处原有 "Ptr(Ptr(Struct)) → Ptr(Struct)" 的压层(历史遗留):会把已解析的
|
||||
# 多层指针返回类型(`-> rawptr[rawptr[X]]` / `-> X | t.CPtr | t.CPtr`)
|
||||
# 与泛型特化方法返回(`list[X**]` 的 get/pop/__getitem__/__next__)少算一层,
|
||||
# 与同函数的形参(`append(item: T)` 保留 `X**`)、声明端
|
||||
# DeclarationGenerator._get_type_str 的 BinOp 分支(同样不压层,见
|
||||
# '_is_bare_class_ref_annotation' 为假时逐层外包)以及 _EmitFunctionLlvm
|
||||
# 的定义体路径全部不一致。违反"多层指针已解析时照原样保留层数"。
|
||||
# 实测(36 用例 A/B)删除后仅 `list[X**]` 的 4 个方法 declare 由 `X*` 变
|
||||
# `X**`,与 append/set 的形参一致;stub 逐字节不变。
|
||||
if isinstance(ReturnType, ir.IntType) and ReturnType.width == 8:
|
||||
if RawFuncName == '__str__':
|
||||
ReturnType = ir.PointerType(ir.IntType(8))
|
||||
@@ -681,7 +693,12 @@ class FunctionHandle(BaseHandle):
|
||||
if Arg.annotation:
|
||||
try:
|
||||
ParamTypeInfo: Any
|
||||
ParamTypeInfo = self.ResolveAnnotationType(Arg.annotation)
|
||||
# 走 ResolveParamAnnotation(= ResolveAnnotationType + 泛型模板
|
||||
# 识别):参数注解中的泛型容器(list[X] / rawptr[list[X]])与
|
||||
# 指针下标(rawptr[X])需走 TypeMerge 通用解析,否则
|
||||
# TypeAnnotationResolver 解析不出 → VoidType → 报
|
||||
# "无法识别的参数类型注解"。
|
||||
ParamTypeInfo = self.ResolveParamAnnotation(Arg.annotation)
|
||||
if ParamTypeInfo is None:
|
||||
ParamTypeInfo = CTypeInfo()
|
||||
ParamTypeInfo.BaseType = t.CInt()
|
||||
@@ -820,20 +837,113 @@ class FunctionHandle(BaseHandle):
|
||||
|
||||
def _make_replacement_node(self, replacement: str) -> ast.AST:
|
||||
"""将 type_map 中的替换字符串转换为 AST 节点。
|
||||
mangled 名称如 'sha1.ASTptr' 需要还原为 AST | t.CPtr 结构,
|
||||
mangled 名称如 '<sha1>.AST*' 需要还原为 AST | t.CPtr 结构,
|
||||
否则类型解析会丢失 PtrCount 信息。
|
||||
含点号的名称(如 'sha1.AST')需解析为 ast.Attribute 链。
|
||||
含点号的名称(如 '<sha1>.AST')需解析为 ast.Attribute 链。
|
||||
下标形态('rawptr[ast.AST]' / 'list[AST]' 等)必须整体解析为 Subscript:
|
||||
_make_name_node 只按 '.' 切分会把 'rawptr[ast.AST]' 拆成
|
||||
Name('rawptr[ast') + Attribute('AST]'),两段都不是有效类型名 →
|
||||
参数/返回注解解析为空 → VoidType → "无法识别的参数类型注解"。
|
||||
指针下标(rawptr[T] / t.CPtr[T])再折叠为等价的 `T | t.CPtr`,与源码
|
||||
联合写法同解析路径(对齐 TPV TypeGenResolve._parse_type_string 的 '['
|
||||
分支 + ClassGenGeneric._clone_annotation 的 T 替换)。
|
||||
内层为已混淆名(数字开头,如 'rawptr[7565e081d88517ac.AST]')时
|
||||
ast.parse 无法解析(数字开头的令牌),改用手工拆 base/slice(同 TPV
|
||||
TypeGenResolve._parse_type_string 的数字开头手工拆分分支)。
|
||||
尾部 '*'(泛型实参 '<sha1>.Node*' / '<sha1>.Node**',来自 rawptr[T] /
|
||||
t.CPtr 的逐层 mangling)逐层还原为 `Node | t.CPtr [| t.CPtr]` → 对应
|
||||
层数指针;只剥一层会把 'Node*' 当结构体名建出 phantom opaque
|
||||
(item 类型与特化名 '<sha1>.Node**' 的语义不一致)。
|
||||
尾部 'ptr'(旧规则 mangling,如 'Nodeptr' / 'ast.ASTptr')保留兼容:
|
||||
.vpi/stub 缓存里仍是旧名时按同样方式还原。
|
||||
"""
|
||||
StarCount: int = len(replacement) - len(replacement.rstrip('*'))
|
||||
if StarCount > 0:
|
||||
BaseName: str = replacement[:len(replacement) - StarCount]
|
||||
base_node: ast.AST
|
||||
if BaseName in ('i8', 'void', 'void*'):
|
||||
# i8*(void*)在源码侧写作 t.CPtr;再叠加 StarCount-1 层
|
||||
base_node = ast.Attribute(
|
||||
value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
|
||||
StarCount -= 1
|
||||
else:
|
||||
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.Attribute(
|
||||
value=ast.Name(id='t', ctx=ast.Load()),
|
||||
attr='CPtr', ctx=ast.Load()),
|
||||
)
|
||||
return node
|
||||
if replacement.endswith('ptr'):
|
||||
# 提取基础名称: 'sha1.ASTptr' -> 'sha1.AST'
|
||||
base: str = replacement[:-3]
|
||||
return ast.BinOp(
|
||||
left=self._make_name_node(base),
|
||||
op=ast.BitOr(),
|
||||
right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load())
|
||||
)
|
||||
# 提取基础名称:'sha1.ASTptr' → 'sha1.AST';'Nodeptrptr' → 'Node'(2 层)
|
||||
base: str = replacement
|
||||
levels: int = 0
|
||||
while base.endswith('ptr') and len(base) > 3:
|
||||
base = base[:-3]
|
||||
levels += 1
|
||||
node: ast.AST = self._make_name_node(base)
|
||||
for _ in range(levels):
|
||||
node = ast.BinOp(
|
||||
left=node,
|
||||
op=ast.BitOr(),
|
||||
right=ast.Attribute(
|
||||
value=ast.Name(id='t', ctx=ast.Load()),
|
||||
attr='CPtr', ctx=ast.Load()),
|
||||
)
|
||||
return node
|
||||
if '[' in replacement:
|
||||
SubNode: ast.AST | None = None
|
||||
try:
|
||||
SubNode = ast.parse(replacement, mode='eval').body
|
||||
except Exception:
|
||||
SubNode = None
|
||||
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)
|
||||
|
||||
def _parse_subscript_manually(self, replacement: str) -> ast.AST | None:
|
||||
"""手工拆分单实参下标字符串(ast.parse 因数字开头标识符失败时使用)。
|
||||
|
||||
处理 `<base>[<inner>]`(整体以 ']' 结尾、单实参、无逗号;内层可为嵌套
|
||||
单实参下标):'rawptr[7565e081d88517ac.AST]' → Subscript(Name('rawptr'),
|
||||
Attribute(Name('7565e081d88517ac'), 'AST'));
|
||||
'rawptr[rawptr[7565e081d88517ac.AST]]' → 外层 Subscript 的 slice 递归
|
||||
拆出内层 Subscript(嵌套 rawptr 需两层指针)。带逗号等复杂形态返回
|
||||
None(交调用方按普通名称处理),不做字符串猜测。
|
||||
"""
|
||||
open_idx: int = replacement.find('[')
|
||||
if open_idx <= 0 or not replacement.endswith(']'):
|
||||
return None
|
||||
inner: str = replacement[open_idx + 1:-1]
|
||||
if not inner or ',' in inner:
|
||||
return None
|
||||
base_name: str = replacement[:open_idx].strip()
|
||||
inner_name: str = inner.strip()
|
||||
if not base_name or not inner_name:
|
||||
return None
|
||||
slice_node: ast.AST | None
|
||||
if '[' in inner_name or inner_name.endswith('*'):
|
||||
# 嵌套单实参下标 / 指针层数内层(如 rawptr[rawptr[<sha1>.CLS]]、
|
||||
# <sha1>.list[<sha1>.X*]):递归按同一还原规则拆解
|
||||
slice_node = self._make_replacement_node(inner_name)
|
||||
else:
|
||||
try:
|
||||
slice_node = ast.parse(inner_name, mode='eval').body
|
||||
except Exception:
|
||||
slice_node = self._make_name_node(inner_name)
|
||||
if slice_node is None:
|
||||
return None
|
||||
return ast.Subscript(
|
||||
value=self._make_name_node(base_name), slice=slice_node, ctx=ast.Load())
|
||||
|
||||
@staticmethod
|
||||
def _make_name_node(name: str) -> ast.AST:
|
||||
"""将可能含点号的名称转换为 ast.Name 或 ast.Attribute 链。
|
||||
@@ -1323,7 +1433,8 @@ class FunctionHandle(BaseHandle):
|
||||
if not isinstance(ReturnTypeInfo, CTypeInfo):
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = t.CVoid()
|
||||
if (ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState) or ReturnTypeInfo.PtrCount >= 2:
|
||||
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 = []
|
||||
@@ -1359,7 +1470,10 @@ class FunctionHandle(BaseHandle):
|
||||
is_str_type = False
|
||||
if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'):
|
||||
is_str_type = True
|
||||
ReturnTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
|
||||
# 与 _GetFunctionSignatureLlvm 同口径:指针下标返回注解
|
||||
# (rawptr[T] / t.CPtr[T])走 ResolveAnnotationType 的
|
||||
# TypeMerge 通用解析,避免内层跨模块类退化为 i8*。
|
||||
ReturnTypeInfo = self.ResolveAnnotationType(Node.returns)
|
||||
if ReturnTypeInfo and ReturnTypeInfo.IsDefine:
|
||||
inferred = self._infer_return_type_from_body(Node, Gen, ClassName)
|
||||
if inferred:
|
||||
@@ -1807,7 +1921,8 @@ class FunctionHandle(BaseHandle):
|
||||
if not (_existing_ps == 'rawptr' or '.rawptr' in _existing_ps
|
||||
or _existing_ps.startswith('rawptr[')):
|
||||
continue
|
||||
found_struct: str | None = FindStructNameInAnnotation(arg.annotation, Gen.structs)
|
||||
found_struct: str | None = FindStructNameInAnnotationWithContext(
|
||||
arg.annotation, self.Trans, Gen)
|
||||
if found_struct:
|
||||
Gen.var_struct_class[param_name] = found_struct
|
||||
# 普通类注解形参(非 BinOp 联合):rawptr[X] / t.CPtr[X] / X / t.X
|
||||
|
||||
@@ -14,7 +14,7 @@ from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.includes import t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
from lib.core.SymbolUtils import ParseListAnnotation, ExtractTypeNameFromBinOp, AnnotationContainsName, FindStructNameInAnnotation
|
||||
from lib.core.SymbolUtils import ParseListAnnotation, ExtractTypeNameFromBinOp, AnnotationContainsName, FindStructNameInAnnotationWithContext
|
||||
|
||||
|
||||
# 注解里的存储类 / 限定符标记:这些名字**不是类名**(联合注解里与指针类混写,
|
||||
@@ -1855,6 +1855,19 @@ class ImportHandle(BaseHandle):
|
||||
Gen.class_requires[ClassName] = values
|
||||
elif field_name == '__require_must__':
|
||||
Gen.class_require_must[ClassName] = values
|
||||
# 字段收集中保护(与 _EmitClassLlvm 的 _collecting_members_set 同源):
|
||||
# 本节的成员解析会重入结构体发射 —— CollectAnnAssignMember →
|
||||
# ResolveAnnotationType → HandlesTypeMerge._HandleSubscript → CollectAll →
|
||||
# _ResolveGenericSlice → _specialize_generic_class → _EmitClassLlvm →
|
||||
# _generate_structs(),而此刻 class_members[ClassName] 只含"已扫到的
|
||||
# 自有字段"(继承字段展平尚未执行,见下方 _all_inherited 段),
|
||||
# 且 llvmlite 的 set_body 只允许调用一次 → 残缺布局被永久固化:
|
||||
# BasicBlock.Lines: rawptr[GSList[Line]] → body 只到 Name 即止
|
||||
# Function.Params: rawptr[GSList[Param]] → body 只到 RetTy 即止
|
||||
# Line/Param 等则整类丢失继承字段 Next(GEP 索引整体前移一位)。
|
||||
# 置入保护后重入的 _generate_structs 会跳过本类(StructGen.py:461),
|
||||
# 待本节收集+展平完成后由下方显式 _generate_structs() 一次性 set_body。
|
||||
Gen._collecting_members_set.add(ClassName)
|
||||
_existing_member_names = {m[0] for m in Gen.class_members[ClassName]}
|
||||
for item in Node.body:
|
||||
# 跳过编译期元数据字段(__provides__/__requires__/__require_must__)
|
||||
@@ -1884,7 +1897,8 @@ class ImportHandle(BaseHandle):
|
||||
# 无法识别字段为 list → len() 误编译为 strlen → stdint 崩溃。
|
||||
if isinstance(MemberType, ir.PointerType) and isinstance(MemberType.pointee, ir.IntType) and MemberType.pointee.width == 8:
|
||||
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
|
||||
element_class: str | None = FindStructNameInAnnotation(item.annotation, Gen.structs)
|
||||
element_class: str | None = FindStructNameInAnnotationWithContext(
|
||||
item.annotation, self.Trans, Gen)
|
||||
if not element_class and TypeInfo.IsStruct and TypeInfo.Name and TypeInfo.Name in Gen.structs:
|
||||
element_class = TypeInfo.Name
|
||||
if element_class:
|
||||
@@ -1895,7 +1909,8 @@ class ImportHandle(BaseHandle):
|
||||
and isinstance(MemberType.pointee, ir.IdentifiedStructType)
|
||||
and isinstance(item.annotation, ast.BinOp)
|
||||
and isinstance(item.annotation.op, ast.BitOr)):
|
||||
spec_in_anno: str | None = FindStructNameInAnnotation(item.annotation, Gen.structs)
|
||||
spec_in_anno: str | None = FindStructNameInAnnotationWithContext(
|
||||
item.annotation, self.Trans, Gen)
|
||||
if spec_in_anno and '[' in spec_in_anno:
|
||||
if ClassName not in Gen.class_member_element_class:
|
||||
Gen.class_member_element_class[ClassName] = {}
|
||||
@@ -2255,6 +2270,13 @@ class ImportHandle(BaseHandle):
|
||||
_inherited_ph: list[tuple] = [(f'__inherited_{i}', _st.elements[i]) for i in range(_num_inherited)]
|
||||
# 占位符路径同样整体前置(继承字段在 struct 头部),与主路径保持一致
|
||||
Gen.class_members[ClassName] = _inherited_ph + Gen.class_members[ClassName]
|
||||
# 成员收集 + 继承展平完成 → 解除收集中保护,并用完整 class_members 设置 body。
|
||||
# 必须在此显式触发一次 _generate_structs():保护期内(上方 add)所有重入的
|
||||
# _generate_structs 都跳过了本类,若此处不再触发,本类 struct 将保持 opaque
|
||||
# (opaque 结构体上的 GEP 是非法 IR,llvm-as 会直接报错),而残缺布局正是
|
||||
# 本保护要消除的目标。
|
||||
Gen._collecting_members_set.discard(ClassName)
|
||||
Gen._generate_structs()
|
||||
# ============================================================
|
||||
# 跨模块 vtable 槽布局与定义模块一致:父类方法在前(子类覆盖放父类槽位),
|
||||
# 子类新增方法在后。定义模块(HandlesClassDef)已按此合并,跨模块若只
|
||||
@@ -3144,7 +3166,13 @@ class ImportHandle(BaseHandle):
|
||||
return ir.ArrayType(elem_type, size)
|
||||
|
||||
typedef_names = {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}
|
||||
struct_match = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.\[\]]+)"?', type_str)
|
||||
# 类型名内允许 '*':泛型特化名可带指针层实参(如
|
||||
# %"<模sha1>.list[<sha1>.AST*]"*)。此前字符集缺 '*' 会把名字截断在
|
||||
# 内层 '*' 处(丢掉尾随 ']'),随后 gc_base/gc_args 重解析出
|
||||
# list[<sha1>.AST](少一层指针)并 declare_only 特化出无方法体的
|
||||
# 假类型 → 调用点引用未定义的 <模sha1>.list[<sha1>.AST].__len__
|
||||
# (链接期 undefined symbol 根因)。
|
||||
struct_match = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.\[\]*]+)"?', type_str)
|
||||
if struct_match:
|
||||
raw_name = struct_match.group(1)
|
||||
actual_source_sha1 = source_sha1
|
||||
|
||||
@@ -4,7 +4,9 @@ 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 IsTModule, IsListAnnotation
|
||||
from lib.core.SymbolUtils import (
|
||||
IsTModule, IsListAnnotation, IsPtrSubscriptNode,
|
||||
DesugarPtrSubscriptToUnion)
|
||||
from lib.includes import t
|
||||
import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes)
|
||||
import vast as ast
|
||||
@@ -248,6 +250,24 @@ class HandlesTypeMerge(BaseHandle):
|
||||
Result.PtrCount = 1
|
||||
return Result
|
||||
|
||||
# 跨模块类引用(`<sha1>.CLS` / `ast.CLS`):按类名查 _struct_sha1_map,
|
||||
# 与 ast.Name 路径(FromTypeName → _get_or_create_struct 的
|
||||
# `clean_name in self._struct_sha1_map` 分支,BaseGen.py:421)、声明端
|
||||
# DeclarationGenerator._get_type_str(`attr_name in struct_names`,
|
||||
# DeclarationGenerator.py:1185)以及名称域 SymbolUtils._ResolveAttributeArgStr
|
||||
# (SymbolUtils.py:491)**同一条"类名 → SHA1"规则**。
|
||||
# 此前此处只查 Gen.structs(仅本模块已创建的结构体)→ 本模块未 import
|
||||
# 的类(如 rawptr[e4c92b87b98424db.AST])落空 → 返回 BaseType=None →
|
||||
# 裸引用抛"无法识别的参数类型注解"/脱糖合并后 CVoid/1(i8*),
|
||||
# 与声明端 %"<sha1>.CLS"* 分裂。
|
||||
if _Gen is not None and TypeName in getattr(_Gen, '_struct_sha1_map', {}):
|
||||
Result = CTypeInfo()
|
||||
Result.BaseType = t.CStruct(name=TypeName)
|
||||
Result.IsStruct = True
|
||||
Result.Name = TypeName
|
||||
Result.PtrCount = 1
|
||||
return Result
|
||||
|
||||
Entry = self.Trans.SymbolTable.lookup(TypeName)
|
||||
if Entry and Entry.IsTypedef:
|
||||
if isinstance(Entry, CTypeInfo) and Entry.BaseType:
|
||||
@@ -436,6 +456,15 @@ class HandlesTypeMerge(BaseHandle):
|
||||
t.CArrayPtr[t.CArrayPtr] -> void *(*)[]
|
||||
t.CPtr[t.CArrayPtr[t.CArrayPtr]] -> void *(*(*))[]
|
||||
"""
|
||||
# 指针下标(rawptr[T] 内置裸指针 / t.CPtr[T] 下标指针,含裸名 CPtr[T])
|
||||
# 折叠为等价的联合写法 `T | t.CPtr` 后交给 MergeTypes 统一解析:内层 T
|
||||
# 因此走通用解析路径(含跨模块类经 Gen.structs 反查 SHA1 前缀),指针
|
||||
# 层数与源码 `T | t.CPtr` 完全一致(此前 t.CPtr[ast.AST] 在此得
|
||||
# AST**(比 declare/`AST | t.CPtr` 多一层)、rawptr[ast.AST] 退化为
|
||||
# CVoid/1 → i8*)。
|
||||
if IsPtrSubscriptNode(Node, self.Trans.SymbolTable):
|
||||
return self.MergeTypes(DesugarPtrSubscriptToUnion(Node, self.Trans.SymbolTable))
|
||||
|
||||
def CollectAll(node: ast.AST, ParentIsArrayPtr: bool = False) -> CTypeInfo:
|
||||
"""鏀堕泦绫诲瀷淇℃伅锛岃繑鍥?CTypeInfo"""
|
||||
if isinstance(node, ast.Subscript):
|
||||
@@ -789,6 +818,13 @@ class HandlesTypeMerge(BaseHandle):
|
||||
"""递归收集所有操作数的类型(用于一次性合并)"""
|
||||
Types = []
|
||||
|
||||
# 指针下标(rawptr[T] / t.CPtr[T])先折叠成等价的 `T | t.CPtr`:使
|
||||
# `rawptr[T] | t.CPtr` 与 `T | t.CPtr | t.CPtr` 拉平成同一组操作数
|
||||
# (否则折叠结果作为单个 Subscript 操作数参与合并,指针层数少算一层);
|
||||
# t.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))
|
||||
|
||||
@@ -280,8 +280,27 @@ class BaseGenMixin:
|
||||
return prefix
|
||||
return ''
|
||||
|
||||
@staticmethod
|
||||
def _CleanStructName(name: str) -> str:
|
||||
"""结构体名清洗:去掉指针标记/空格/修饰符(clean_name 既有行为)。
|
||||
|
||||
但**保留**泛型特化名 '[...]' 段内的原样文本:特化实参里的 '*' 是类型
|
||||
身份的一部分('list[<sha1>.AST*]' 表示元素为指向 AST 的指针),若一并
|
||||
移除会让声明端引用名('list[<sha1>.AST*]')与定义端注册名
|
||||
('list[<sha1>.AST]')分裂成两个 struct。头部(首个 '[' 之前)行为不变;
|
||||
'[' 开头(LLVM 数组串 '[4 x i8*]')走原清洗,保持既有语义。
|
||||
"""
|
||||
lb: int = name.find('[')
|
||||
if lb > 0:
|
||||
head, tail = name[:lb], name[lb:]
|
||||
else:
|
||||
head, tail = name, ''
|
||||
head = (head.replace(' *', '').replace('*', '').replace(' ', '_')
|
||||
.replace('const', 'const_').replace('volatile', 'volatile_'))
|
||||
return head + tail
|
||||
|
||||
def _get_or_create_struct(self, name: str, source_sha1: str | None = None, packed: bool = False) -> ir.IdentifiedStructType:
|
||||
clean_name: str = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_')
|
||||
clean_name: str = self._CleanStructName(name)
|
||||
# 如果名称包含模块前缀(如 "a9fa0f6200c09e65.zbit_writer"),
|
||||
# 先尝试用短名称(如 "zbit_writer")查找已注册的 struct,
|
||||
# 避免为同一 struct 创建多个不同的类型对象导致跨模块引用类型不一致
|
||||
|
||||
@@ -487,10 +487,56 @@ class FuncGenMixin:
|
||||
_members_final: list = self.class_members.get(ClassName, [])
|
||||
_num_members_final: int = len(_members_final)
|
||||
if _num_elements_final > _num_members_final:
|
||||
_num_inherited_final: int = _num_elements_final - _num_members_final
|
||||
# base 是 vtable 占位(struct[0] = i8*),不是继承字段,必须扣除:
|
||||
# 不扣 base 时,凡"struct 元素数恰好多 1"的类,差值其实只是 vtable
|
||||
# 本身(class_members 不含 vtable),却会对任意字段名返回 base+0。
|
||||
# 实例:ast.ImportFrom 的 level/module → 静默返回偏移 1(=parent,
|
||||
# %"…AST"*)→ 调用点把 AST* 当 i32 传入 _resolve_relative_module
|
||||
# → llvmlite "Type of #4 arg mismatch: i32 != %"…AST"*"。
|
||||
# 成员表与 struct 不一致(少一个非 vtable 槽)时,先强制按定义模块
|
||||
# 的 .vpi 重载一次成员表再按名查:_TryLoadClassMembersFromPyi 的 guard
|
||||
# 会永久跳过"已存在但不完整"的表,此处即该冻结的解除点。重载后仍缺
|
||||
# 才走下方推断/fast-fail。每类只重载一次(避免递归与重复 IO)。
|
||||
_ReloadKey: tuple = (id(self), ClassName)
|
||||
_ReloadTried: set = getattr(self, '_MemberReloadTried', None)
|
||||
if _ReloadTried is None:
|
||||
_ReloadTried = set()
|
||||
self._MemberReloadTried = _ReloadTried
|
||||
if _ReloadKey not in _ReloadTried:
|
||||
_ReloadTried.add(_ReloadKey)
|
||||
_Sha1Final: str | None = getattr(self, 'class_sha1_map', {}).get(ClassName)
|
||||
if _Sha1Final and self._Trans and hasattr(self._Trans, 'ImportHandler'):
|
||||
_OldMembers = _members_final
|
||||
try:
|
||||
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(
|
||||
ClassName, f"{_Sha1Final}.stub.ll", self, force=True)
|
||||
except Exception:
|
||||
pass
|
||||
_ReloadedMembers: list = self.class_members.get(ClassName, [])
|
||||
if len(_ReloadedMembers) < len(_OldMembers):
|
||||
# 重载反而变少(.vpi 缺该类):回滚,避免丢字段
|
||||
self.class_members[ClassName] = _OldMembers
|
||||
_ReloadedMembers = _OldMembers
|
||||
_members_final = _ReloadedMembers
|
||||
_num_members_final = len(_members_final)
|
||||
for _Ri, (_Rn, _Rt) in enumerate(_members_final):
|
||||
if _Rn == field_name:
|
||||
return base + _Ri
|
||||
_num_inherited_final: int = _num_elements_final - _num_members_final - base
|
||||
if _num_inherited_final == 1:
|
||||
# 单继承字段,偏移 = base(vtable 之后第一个位置)
|
||||
return base + 0
|
||||
# 推断(缺失槽位 = 位于 base+0 的未展平继承字段)仅在成员表
|
||||
# 尚未含展平继承字段时成立:若成员表首项本身就是任一已加载
|
||||
# 祖先的字段名(如 ImportFrom 'parent' ← Stmt),说明继承字段
|
||||
# 已展平、缺的是类自身字段,推断 base+0 必然读错槽位。
|
||||
_ParentNamesFinal: set = set()
|
||||
for _ParentF in (getattr(self, 'class_parents', {}).get(ClassName) or []):
|
||||
for _Np, _Tp in self.class_members.get(_ParentF, []) or []:
|
||||
_ParentNamesFinal.add(_Np)
|
||||
if _members_final and _members_final[0][0] in _ParentNamesFinal:
|
||||
pass # 已含展平继承字段 → 落入下方 fast-fail 暴露真实缺失
|
||||
else:
|
||||
# 单继承字段,偏移 = base(vtable 之后第一个位置)
|
||||
return base + 0
|
||||
# fast-fail(治本修复 2026-08-10):字段未找到不再静默返回 None。
|
||||
# 静默 None 会让调用方(_gep_and_Load_member L26-27)直接 return None,
|
||||
# AnnAssign InitValue 变 None → 变量 alloca 未初始化 → 运行期读垃圾指针
|
||||
|
||||
@@ -490,6 +490,25 @@ class TypeConvertMixin:
|
||||
if IsPtr:
|
||||
return ir.PointerType(opaque_struct)
|
||||
return opaque_struct
|
||||
# 类名与枚举成员/异常类同名时的判据统一:类型注解语境下,只要该名
|
||||
# **有类定义**(Gen.structs 已建 / _struct_sha1_map 已登记类→模块),
|
||||
# 就按结构体解析,而不是被同名枚举成员/异常类降级成 i32(rawptr[Function]
|
||||
# → i32*:9 个模块 stub 里 LLVMModule.FuncHead/FuncTail、IRBuilder.Func
|
||||
# 被写成 i32*)。与上方 IsStruct 分支(L479)、HandlesTypeMerge.
|
||||
# _GetCTypeInfoInternal L241-251、StructGen 的"类名可能与 CEnum 成员名
|
||||
# 冲突"守卫同一条规则源 —— 判据是"是否有类定义",不往白名单加名字。
|
||||
if (type_str in self.structs
|
||||
or type_str in getattr(self, '_struct_sha1_map', {})):
|
||||
if type_str in self.structs:
|
||||
if IsPtr:
|
||||
return ir.PointerType(self.structs[type_str])
|
||||
return self.structs[type_str]
|
||||
_cls_sha1: str | None = self._get_source_sha1_from_type_str(type_str)
|
||||
_cls_struct: ir.IdentifiedStructType = self._get_or_create_struct(
|
||||
type_str, source_sha1=_cls_sha1)
|
||||
if IsPtr:
|
||||
return ir.PointerType(_cls_struct)
|
||||
return _cls_struct
|
||||
if _Entry and _Entry.IsEnum:
|
||||
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
|
||||
if _Entry and _Entry.IsExceptionClass:
|
||||
|
||||
@@ -18,7 +18,9 @@ if TYPE_CHECKING:
|
||||
from lib.core.SymbolTable import SymbolTable
|
||||
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap
|
||||
from lib.core.SymbolUtils import IsTModule, IsListAnnotation, IsCPtrNode, IsCPtrSubscriptNode
|
||||
from lib.core.SymbolUtils import (
|
||||
IsTModule, IsListAnnotation, IsCPtrNode, IsCPtrSubscriptNode,
|
||||
IsRawPtrSubscriptNode)
|
||||
from lib.includes import t as _t
|
||||
from lib.includes.t import CTypeRegistry
|
||||
|
||||
@@ -253,6 +255,11 @@ class LLVMTypeMapper:
|
||||
# t.CPtr[T] → Ptr(resolve(T))(对齐 TPV Subscript 分支
|
||||
# TypeGenResolve.vp:2769-2790;void 首层归一化为 i8*)
|
||||
return self._add_pointer_level(self.get_llvm_type_str(node.slice))
|
||||
if IsRawPtrSubscriptNode(node):
|
||||
# rawptr[T](内置裸指针下标)≡ `T | t.CPtr`:与定义端 TypeMerge 的
|
||||
# 合并语义同口径(裸类引用自身即指针,吸收这一层;其余逐层外包)。
|
||||
# 此前只认 IsCPtrSubscriptNode → rawptr[T] 落到下方 warn 并退化成 i32。
|
||||
return self._rawptr_subscript_type_str(node)
|
||||
if IsListAnnotation(node):
|
||||
slice_node: ast.AST = node.slice
|
||||
elem_type: str
|
||||
@@ -309,6 +316,23 @@ class LLVMTypeMapper:
|
||||
return ty + '*'
|
||||
return ty + '*'
|
||||
|
||||
def _rawptr_subscript_type_str(self, node: ast.Subscript) -> str:
|
||||
"""rawptr[T](内置裸指针下标)→ LLVM 类型串。
|
||||
|
||||
与定义端同口径(`T | t.CPtr` 的合并):裸类引用('%struct.X*' /
|
||||
'%"sha1.X"*' / 泛型特化等以 '%' 开头的结构指针)自身即指针,吸收这一层;
|
||||
其余(标量、已是指针的 typedef、联合写法、嵌套 rawptr / t.CPtr 下标)
|
||||
逐层外包(void → i8*)。
|
||||
"""
|
||||
inner: ast.AST = node.slice
|
||||
inner_type: str = self.get_llvm_type_str(inner)
|
||||
if (not isinstance(inner, ast.BinOp)
|
||||
and 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
|
||||
|
||||
@@ -150,7 +150,7 @@ class TypeResolver:
|
||||
# 会被 CTypeInfo.FromTypeName 当成 CStruct('ptr'),最终 _get_or_create_struct
|
||||
# 建出 %"<模块sha>.ptr" 不透明结构体(VLogger._console_handle: win32base.HANDLE
|
||||
# 报 "cannot store i8* to %"...ptr"*" 的根因)。按指针语义展开为 'void *',
|
||||
# 与改前 `t.CVoid | t.CPtr` 联合分支等价(_InsertTypedefSymbol 同样把
|
||||
# 与改前 `t.CPtr` 联合分支等价(_InsertTypedefSymbol 同样把
|
||||
# 'CVoid *' 归一化为 'void *')。
|
||||
if value_base_type == 'ptr':
|
||||
td.original_type_kind = 'typedef'
|
||||
|
||||
+399
-21
@@ -3,6 +3,7 @@ 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__})
|
||||
|
||||
@@ -169,11 +170,16 @@ def ExtractTypeNameFromBinOp(annotation: ast.expr) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str | 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]),构造特化名后检查是否在 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
|
||||
@@ -191,33 +197,40 @@ def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str |
|
||||
slice_node: ast.AST = node.slice
|
||||
if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index):
|
||||
slice_node = slice_node.value
|
||||
type_args: list[str] = []
|
||||
if isinstance(slice_node, ast.Name):
|
||||
# 裸 CPtr(i8*)与 t.CPtr 同规范化为 'ptr',与
|
||||
# _resolve_type_arg_str/_mangle_generic_class_name 一致
|
||||
type_args.append('ptr' if slice_node.id == 'CPtr' else slice_node.id)
|
||||
elif isinstance(slice_node, ast.Attribute):
|
||||
type_args.append('ptr' if slice_node.attr == 'CPtr' else slice_node.attr)
|
||||
elif isinstance(slice_node, ast.Tuple):
|
||||
for elt in slice_node.elts:
|
||||
if isinstance(elt, ast.Name):
|
||||
type_args.append('ptr' if elt.id == 'CPtr' else elt.id)
|
||||
elif isinstance(elt, ast.Attribute):
|
||||
type_args.append('ptr' if elt.attr == 'CPtr' else elt.attr)
|
||||
if type_args:
|
||||
spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args)
|
||||
if spec_name in struct_names:
|
||||
return spec_name
|
||||
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)
|
||||
result: str | None = FindStructNameInAnnotation(
|
||||
node.left, struct_names, TCAliasMap, StructSha1Map)
|
||||
if result:
|
||||
return result
|
||||
return FindStructNameInAnnotation(node.right, struct_names)
|
||||
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) 递归)。
|
||||
|
||||
@@ -250,3 +263,368 @@ def IsCPtrSubscriptNode(node: ast.AST) -> bool:
|
||||
"""
|
||||
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))
|
||||
@@ -170,6 +170,14 @@ class LlvmGeneratorMixin:
|
||||
line_info += ":\n %d | %s" % (lineno, source_line)
|
||||
self._ErrorStack.append((type(e).__name__, str(e), line_info))
|
||||
|
||||
# 本模块泛型类模板必须在前置声明之前注册(与 includes 侧注册判据同源,
|
||||
# 见 HandlesClassDef.PrescanModuleGenericClassTemplates):前置声明要解析
|
||||
# 参数/返回注解里的泛型类下标(`def f(b: Box[Node])`),而类处理阶段
|
||||
# (下方 _EmitClassLlvm)才注册模板 → 注解解析为空 → VoidType →
|
||||
# "无法识别的参数类型注解"。放在 import 扫描之后,保证本地类覆盖同名
|
||||
# 导入类(与 _EmitClassLlvm 的覆盖顺序一致)。
|
||||
self.ClassHandler.PrescanModuleGenericClassTemplates(ast.iter_child_nodes(Tree))
|
||||
|
||||
# 前向声明所有顶层函数,确保全局变量初始化时能引用函数指针
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
if isinstance(Node, ast.FunctionDef):
|
||||
|
||||
Reference in new issue
Block a user