refactor(type): 全面清理旧联合与 t/c 标记判断
审计并修复 23 个文件:类型注解中的 T1 | T2 一律 fail-fast;typedef/define/export/extern/static/const/volatile/attribute 优先读取 Markers/Attributes/ByteOrder/BitWidth;指针统一 CPtr/rawptr/CRef/CTempRef/CArrayPtr/CAutoPtr Subscript;stub 输出统一新语法。
This commit is contained in:
1 parent
a410de2cf7
commit
0bded58999
23 files changed
+887
-694
No files matched your search
@@ -97,11 +97,9 @@ class DeclarationGenerator:
|
||||
Markers: tuple[str, ...] = tuple(getattr(node, 'Markers', None) or ()) + tuple(
|
||||
getattr(node.annotation, 'Markers', None) or ())
|
||||
is_typedef: bool = 'typedef' in Markers
|
||||
if not is_typedef:
|
||||
if isinstance(node.annotation, ast.Attribute) and getattr(node.annotation, 'attr', '') == 'CTypedef':
|
||||
is_typedef = True
|
||||
elif isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef':
|
||||
is_typedef = True
|
||||
if not is_typedef and AnnotationContainsName(node.annotation, 'CTypedef'):
|
||||
# 兼容旧写法 `名字: CTypedef = 类型`(仅文本判据回落)。
|
||||
is_typedef = True
|
||||
if is_typedef and node.value:
|
||||
self.typedef_map[var_name] = node.value
|
||||
|
||||
@@ -230,22 +228,33 @@ class DeclarationGenerator:
|
||||
return f'declare {ret_type} @{func_name}({param_str})'
|
||||
|
||||
def _is_export_func(self, node: ast.FunctionDef) -> bool:
|
||||
"""检查函数是否标记为 CExport"""
|
||||
"""检查函数是否导出/外部可见(export / extern / state)。
|
||||
|
||||
新语法的 `export def` / `extern def` 由解析器写入 FunctionDef.Export /
|
||||
Extern;旧语法的 `-> CExport | T` / `-> State | T` 仍走注解兼容判据。
|
||||
"""
|
||||
if bool(getattr(node, 'Export', False)) or bool(getattr(node, 'Extern', False)):
|
||||
return True
|
||||
Markers: tuple[str, ...] = getattr(node, 'Markers', None) or ()
|
||||
if 'export' in Markers or 'state' in Markers:
|
||||
if 'export' in Markers or 'extern' in Markers or 'state' in Markers:
|
||||
return True
|
||||
if not node.returns:
|
||||
return False
|
||||
return self._check_annotation_for_export(node.returns)
|
||||
|
||||
def _check_annotation_for_export(self, annotation: ast.AST | None) -> bool:
|
||||
"""检查类型注解是否带 export / state 标记"""
|
||||
"""检查类型注解是否带 export / extern / state 标记。
|
||||
|
||||
优先读 AST 的 Markers 字段;旧的 CExport/State 文本判断仅作兼容。
|
||||
"""
|
||||
if annotation is None:
|
||||
return False
|
||||
Markers: tuple[str, ...] = getattr(annotation, 'Markers', None) or ()
|
||||
if 'export' in Markers or 'state' in Markers:
|
||||
if 'export' in Markers or 'extern' in Markers or 'state' in Markers:
|
||||
return True
|
||||
return AnnotationContainsName(annotation, 'CExport') or AnnotationContainsName(annotation, 'State')
|
||||
return (AnnotationContainsName(annotation, 'CExport')
|
||||
or AnnotationContainsName(annotation, 'CExtern')
|
||||
or AnnotationContainsName(annotation, 'State'))
|
||||
|
||||
def _generate_global_decl(self, node: ast.AnnAssign) -> str | None:
|
||||
"""生成全局变量声明"""
|
||||
@@ -258,11 +267,7 @@ class DeclarationGenerator:
|
||||
getattr(node.annotation, 'Markers', None) or ())
|
||||
if 'define' in Markers or AnnotationContainsName(node.annotation, 'CDefine'):
|
||||
return None
|
||||
if 'typedef' in Markers:
|
||||
return None
|
||||
if isinstance(node.annotation, ast.Attribute) and getattr(node.annotation, 'attr', '') == 'CTypedef':
|
||||
return None
|
||||
if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef':
|
||||
if 'typedef' in Markers or AnnotationContainsName(node.annotation, 'CTypedef'):
|
||||
return None
|
||||
if isinstance(node.annotation, ast.List):
|
||||
for elt in node.annotation.elts:
|
||||
@@ -1145,7 +1150,8 @@ class DeclarationGenerator:
|
||||
Line: int = getattr(annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
f"类型注解只能是单一类型:指针请写 `T*` 或 `rawptr[T]`,"
|
||||
f"修饰符请用关键字(const/volatile/static/export/extern)")
|
||||
|
||||
non_struct_types: set[str] = {'list', 'dict', 'tuple', 'set', 'array', 'CArray', 'rawarray'}
|
||||
|
||||
@@ -1154,6 +1160,10 @@ class DeclarationGenerator:
|
||||
return 'void'
|
||||
if annotation.id in ('str', 'bytes'):
|
||||
return 'i8*'
|
||||
# 裸指针标记(rawptr = void*,CPtr 亦为裸指针):一律 i8*。
|
||||
# 不得落入下方"未知类型 → %"{sha}.rawptr"*" 的伪结构体分支。
|
||||
if annotation.id in ('rawptr', 'CPtr'):
|
||||
return 'i8*'
|
||||
# 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`,非真实类):按
|
||||
# CPtr 同形的一层指针(i8*)参与联合合并(`T | CRef` → T*)。
|
||||
if annotation.id in ('CRef', 'CTempRef'):
|
||||
@@ -1215,6 +1225,9 @@ class DeclarationGenerator:
|
||||
return f'{sname}*'
|
||||
elif isinstance(annotation, ast.Attribute):
|
||||
attr_name: str = annotation.attr if hasattr(annotation, 'attr') else ''
|
||||
# 裸指针标记(t.rawptr / t.CPtr):i8*,不做结构体回落。
|
||||
if attr_name in ('rawptr', 'CPtr'):
|
||||
return 'i8*'
|
||||
# 值引用参数标记(CRef = `&T`、CTempRef = `&temp T`,非真实类):按 CPtr
|
||||
# 同形的「一层指针 = i8*」参与联合合并(`T | CRef` → T*),保证跨模块
|
||||
# .vpi 声明端类型与定义端 _ctype_to_llvm 一致。
|
||||
|
||||
@@ -9,7 +9,7 @@ import traceback
|
||||
from lib.Projectrans.Utils import compute_sha1, get_file_dependencies, find_reachable_files_from_entries, parse_python_file
|
||||
from lib.Projectrans.DeclarationGenerator import DeclarationGenerator
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.core.SymbolUtils import ExpandSoftKeywords
|
||||
from lib.core.SymbolUtils import ExpandSoftKeywords, AnnotationContainsName
|
||||
from lib.constants.config import mode as _ConfigMode
|
||||
from lib.core import TypeSystem
|
||||
from StubGen import PythonToStubConverter
|
||||
@@ -380,19 +380,14 @@ class Phase1Generator:
|
||||
for node in ast.iter_child_nodes(tree):
|
||||
if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
|
||||
var_name: str = node.target.id
|
||||
is_typedef: bool = False
|
||||
# 新语法 `typedef 名字 = 类型` 由解析器写入
|
||||
# node/annotation 的 Markers;旧 `名字: CTypedef = 类型`
|
||||
# 只作为兼容回落。
|
||||
_Markers: tuple[str, ...] = (tuple(getattr(node, 'Markers', None) or ())
|
||||
+ tuple(getattr(node.annotation, 'Markers', None) or ()))
|
||||
if 'typedef' in _Markers:
|
||||
is_typedef = True
|
||||
elif isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef':
|
||||
is_typedef = True
|
||||
elif isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef':
|
||||
is_typedef = True
|
||||
elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef':
|
||||
is_typedef = True
|
||||
elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Name) and node.annotation.left.id == 'CTypedef':
|
||||
is_typedef = True
|
||||
is_typedef: bool = (
|
||||
'typedef' in _Markers
|
||||
or AnnotationContainsName(node.annotation, 'CTypedef'))
|
||||
if is_typedef and node.value and var_name not in typedef_map:
|
||||
typedef_map[var_name] = node.value
|
||||
except Exception as _e:
|
||||
|
||||
@@ -640,7 +640,12 @@ def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object],
|
||||
|
||||
for node in ast.iter_child_nodes(tree):
|
||||
if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
|
||||
if AnnotationContainsName(node.annotation, 'CDefine') and node.value:
|
||||
Markers: tuple[str, ...] = (tuple(getattr(node, 'Markers', None) or ())
|
||||
+ tuple(getattr(node.annotation, 'Markers', None) or ()))
|
||||
# 新语法 `define NAME = v` 由解析器写入 Markers;旧
|
||||
# `NAME: CDefine = v` 仅作兼容回落。
|
||||
if ('define' in Markers
|
||||
or AnnotationContainsName(node.annotation, 'CDefine')) and node.value:
|
||||
val: object = ConstEvaluator.eval_full(node.value, ctx)
|
||||
if val is None and isinstance(node.value, ast.Call) and len(node.value.args) == 1:
|
||||
# 类型构造的**裸别名**形态(如 `DWORD(-11)`,非 `CUnsignedLong(-11)`):
|
||||
@@ -664,6 +669,17 @@ def _ExtractCDefineConstantsFromPyi(pyi_path: str, all_dc: dict[str, object],
|
||||
_vlog().warning(f"Phase2Translator: 忽略异常 {e}", exc_info=e)
|
||||
|
||||
|
||||
def _IsExportExternFuncNode(node: ast.FunctionDef) -> bool:
|
||||
"""函数是否导出/外部可见:优先读 `export def` / `extern def` 的 AST 标记,
|
||||
再回落到 Markers,最后兼容旧的 `-> CExport/CExtern/State` 注解写法。"""
|
||||
if bool(getattr(node, 'Export', False)) or bool(getattr(node, 'Extern', False)):
|
||||
return True
|
||||
Markers: tuple[str, ...] = getattr(node, 'Markers', None) or ()
|
||||
if 'export' in Markers or 'extern' in Markers or 'state' in Markers:
|
||||
return True
|
||||
return _check_annotation_for_export(node.returns)
|
||||
|
||||
|
||||
def _CountUnresolvedTypedefs(module_symbols: object) -> int:
|
||||
"""该模块"有值注解却解析不出类型"的 typedef 个数(供声明阶段判断是否要下一轮)。
|
||||
|
||||
@@ -2388,7 +2404,7 @@ class Phase2Translator:
|
||||
sig_tree = ast.parse(sig_content, sig_path)
|
||||
for node in ast.iter_child_nodes(sig_tree):
|
||||
if isinstance(node, ast.FunctionDef):
|
||||
if _check_annotation_for_export(node.returns):
|
||||
if _IsExportExternFuncNode(node):
|
||||
export_extern_funcs[node.name] = sha1_key
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
@@ -4345,19 +4361,19 @@ class Phase2Translator:
|
||||
module_name = os.path.splitext(os.path.basename(src_path))[0]
|
||||
for node in ast.iter_child_nodes(tree):
|
||||
if isinstance(node, ast.FunctionDef) and node.returns:
|
||||
is_inline = False
|
||||
if isinstance(node.returns, ast.BinOp) and isinstance(node.returns.op, ast.BitOr):
|
||||
for part in [node.returns.left, node.returns.right]:
|
||||
if isinstance(part, ast.Attribute) and part.attr == 'CInline':
|
||||
is_inline = True
|
||||
break
|
||||
if isinstance(part, ast.Name) and part.id == 'CInline':
|
||||
is_inline = True
|
||||
break
|
||||
elif isinstance(node.returns, ast.Attribute) and node.returns.attr == 'CInline':
|
||||
# 新语法 `inline` 由解析器写入返回注解的 Markers;
|
||||
# 旧 `-> CInline | T` 的联合形态已废止(下方 fail-fast)。
|
||||
ReturnMarkers: tuple[str, ...] = getattr(node.returns, 'Markers', None) or ()
|
||||
is_inline: bool = 'inline' in ReturnMarkers
|
||||
if isinstance(node.returns, ast.Attribute) and node.returns.attr == 'CInline':
|
||||
is_inline = True
|
||||
elif isinstance(node.returns, ast.Name) and node.returns.id == 'CInline':
|
||||
is_inline = True
|
||||
elif isinstance(node.returns, ast.BinOp) and isinstance(node.returns.op, ast.BitOr):
|
||||
_Line: int = getattr(node.returns, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {_Line} 行);"
|
||||
f"内联标记请写 `-> inline T`,类型注解只能是单一类型")
|
||||
if is_inline:
|
||||
func_name = node.name
|
||||
sym_key = f"{module_name}.{func_name}"
|
||||
@@ -4370,6 +4386,9 @@ class Phase2Translator:
|
||||
info.Storage = TypeSystem.CInline()
|
||||
self.inline_func_symbols[func_name] = info
|
||||
self.inline_func_symbols[sym_key] = info
|
||||
except TypeError:
|
||||
# 类型注解 fail-fast(BinOp(BitOr) 联合)不得被 strict 开关吞掉
|
||||
raise
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
@@ -4499,7 +4518,7 @@ class Phase2Translator:
|
||||
continue
|
||||
for node in ast.iter_child_nodes(sig_tree):
|
||||
if isinstance(node, ast.FunctionDef):
|
||||
if _check_annotation_for_export(node.returns):
|
||||
if _IsExportExternFuncNode(node):
|
||||
export_extern_funcs[node.name] = sha1_key
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
|
||||
@@ -41,9 +41,16 @@ _FILE_AST_CACHE: dict[str, tuple[float, str, ast.Module]] = {}
|
||||
|
||||
|
||||
def _check_annotation_for_export(annotation: ast.AST | None) -> bool:
|
||||
"""递归检查类型注解中是否包含 CExport/CExtern/State(State = CExtern | CExport)"""
|
||||
"""检查类型注解是否带 export / extern / state。
|
||||
|
||||
优先读解析器写入的 Markers 字段(export/extern/state);旧的
|
||||
CExport/CExtern/State 文本判断仅作兼容回落。
|
||||
"""
|
||||
if not annotation:
|
||||
return False
|
||||
Markers: tuple[str, ...] = getattr(annotation, 'Markers', None) or ()
|
||||
if 'export' in Markers or 'extern' in Markers or 'state' in Markers:
|
||||
return True
|
||||
return (AnnotationContainsName(annotation, 'CExport') or
|
||||
AnnotationContainsName(annotation, 'CExtern') or
|
||||
AnnotationContainsName(annotation, 'State'))
|
||||
|
||||
+163
-100
@@ -22,6 +22,19 @@ _RE_LINE_COMMENT: re.Pattern[str] = re.compile(r'#.*$')
|
||||
_STUB_TYPE_ALIASES: dict[str, str] = {
|
||||
'CPtr': 'rawptr', 'CArrayPtr': 'rawptr', 'CAutoPtr': 'rawptr',
|
||||
'CRef': 'rawptr', 'CTempRef': 'rawptr',
|
||||
# 旧内建类型名 → 新语法内建名(输入兼容;输出不得再出现 C* 标记)
|
||||
'CChar': 'char', 'CInt': 'int', 'CShort': 'short', 'CLong': 'long',
|
||||
'CLongLong': 'longlong', 'CFloat': 'float', 'CDouble': 'double',
|
||||
'CVoid': 'void', 'CUnsigned': 'uint', 'CUnsignedChar': 'uchar',
|
||||
'CUnsignedInt': 'uint', 'CUnsignedShort': 'ushort',
|
||||
'CUnsignedLong': 'ulong', 'CUnsignedLongLong': 'ulonglong',
|
||||
'CSignedChar': 'char', 'CBool': 'bool', 'CSizeT': 'sizet',
|
||||
'CInt8T': 'int8', 'CInt16T': 'int16', 'CInt32T': 'int32', 'CInt64T': 'int64',
|
||||
'CUInt8T': 'uint8', 'CUInt16T': 'uint16', 'CUInt32T': 'uint32', 'CUInt64T': 'uint64',
|
||||
'CIntPtrT': 'intptr', 'CUIntPtrT': 'uintptr', 'CPtrDiffT': 'ptrdifft',
|
||||
'CWCharT': 'wchar', 'CChar8T': 'char8', 'CChar16T': 'char16', 'CChar32T': 'char32',
|
||||
'CFloat8T': 'float8', 'CFloat16T': 'float16', 'CFloat32T': 'float32',
|
||||
'CFloat64T': 'float64', 'CFloat128T': 'float128',
|
||||
}
|
||||
|
||||
|
||||
@@ -158,8 +171,11 @@ class PythonToStubConverter:
|
||||
TypeStr = PythonToStubConverter._GetTypeString(node.annotation)
|
||||
if 'Postdefinition' in TypeStr:
|
||||
continue
|
||||
# 检查是否带有 CStatic 标志,如果有则不排除
|
||||
HasStatic: bool = 'CStatic' in TypeStr
|
||||
# 检查是否带有 static 标志(优先读 Markers),如果有则不排除
|
||||
_AnnMarkers: tuple[str, ...] = (
|
||||
tuple(getattr(node, 'Markers', None) or ())
|
||||
+ tuple(getattr(node.annotation, 'Markers', None) or ()))
|
||||
HasStatic: bool = 'static' in _AnnMarkers or 'CStatic' in TypeStr
|
||||
# 检查变量是否应该被排除
|
||||
ShouldExclude: bool = False
|
||||
if isinstance(node.target, ast.Name) and not HasStatic:
|
||||
@@ -247,9 +263,10 @@ class PythonToStubConverter:
|
||||
ClassPrefix: str = ''
|
||||
for decorator in node.decorator_list:
|
||||
DecoratorStr: str = PythonToStubConverter._GetDecoratorString(decorator)
|
||||
if DecoratorStr == 'NoVTable':
|
||||
DecoratorShort: str = DecoratorStr.rsplit('.', 1)[-1]
|
||||
if DecoratorShort == 'NoVTable':
|
||||
ClassPrefix = 'novirtual '
|
||||
elif DecoratorStr == 'CVTable':
|
||||
elif DecoratorShort == 'CVTable':
|
||||
ClassPrefix = 'virtual '
|
||||
elif DecoratorStr:
|
||||
lines.append(f'{IndentStr}@{DecoratorStr}')
|
||||
@@ -358,21 +375,29 @@ class PythonToStubConverter:
|
||||
else:
|
||||
lines.append(f'{MemberIndent}{item.target.id}: {TypeStr}')
|
||||
continue
|
||||
# 检查是否是宏变量(类型包含 CDefine)
|
||||
if 'CDefine' in TypeStr:
|
||||
# 检查是否是宏变量(Markers 标记 define;CDefine 仅兼容旧文本)
|
||||
_MemberMarkers: tuple[str, ...] = (
|
||||
tuple(getattr(item, 'Markers', None) or ())
|
||||
+ tuple(getattr(item.annotation, 'Markers', None) or ()))
|
||||
if 'define' in _MemberMarkers or 'CDefine' in TypeStr:
|
||||
# 检查宏变量是否应该被排除
|
||||
if isinstance(item.target, ast.Name):
|
||||
MacroName: str = item.target.id
|
||||
if PythonToStubConverter._ShouldExcludeMacro(MacroName):
|
||||
continue # 跳过该宏
|
||||
# 宏变量保持原样(包括赋值)
|
||||
if SourceLines and hasattr(item, 'lineno'):
|
||||
StartLine = item.lineno - 1
|
||||
EndLine = item.end_lineno if hasattr(item, 'end_lineno') and item.end_lineno else StartLine + 1
|
||||
for i in range(StartLine, min(EndLine, len(SourceLines))):
|
||||
lines.append(MemberIndent + SourceLines[i].lstrip())
|
||||
# 统一输出新语法 `define NAME[: 类型] = 值`
|
||||
ImplicitType: bool = (
|
||||
isinstance(item.annotation, ast.Name)
|
||||
and item.annotation.id == 'CDefine')
|
||||
TypePart: str = '' if ImplicitType else f': {TypeStr}'
|
||||
if item.value is not None:
|
||||
try:
|
||||
ValueStr: str = ast.unparse(item.value)
|
||||
except Exception:
|
||||
ValueStr = ''
|
||||
lines.append(f'{MemberIndent}define {item.target.id}{TypePart} = {ValueStr}')
|
||||
else:
|
||||
lines.append(f'{MemberIndent}{item.target.id}: {TypeStr}')
|
||||
lines.append(f'{MemberIndent}define {item.target.id}{TypePart} = 0')
|
||||
else:
|
||||
if isinstance(item.target, ast.Attribute):
|
||||
MemberName: str = item.target.attr
|
||||
@@ -461,8 +486,10 @@ class PythonToStubConverter:
|
||||
lines: list[str] = []
|
||||
IndentStr: str = ' ' * indent
|
||||
|
||||
# 检查是否是宏函数(返回类型包含 CDefine)
|
||||
is_macro_func: bool = False
|
||||
# 检查是否是宏函数:新语法由解析器写 node.Define;旧 `-> CDefine`
|
||||
# 返回注解仅作兼容回落。
|
||||
ReturnMarkers: tuple[str, ...] = getattr(node.returns, 'Markers', None) or () if node.returns else ()
|
||||
is_macro_func: bool = bool(getattr(node, 'Define', False)) or 'define' in ReturnMarkers
|
||||
if node.returns:
|
||||
ReturnType: str = PythonToStubConverter._GetTypeString(node.returns)
|
||||
if 'CDefine' in ReturnType:
|
||||
@@ -496,20 +523,48 @@ class PythonToStubConverter:
|
||||
lines.append(f'{IndentStr}pass')
|
||||
return lines
|
||||
|
||||
# 处理函数装饰器:存储类/一次性初始化还原为关键字前缀
|
||||
FuncPrefix: str = ''
|
||||
# 处理函数装饰器:存储类/一次性初始化还原为关键字前缀。
|
||||
# 新语法的 `extern def` / `export def` / `static def` 由解析器写入
|
||||
# FunctionDef.Extern/Export/Static;旧装饰器形态仅作兼容。
|
||||
IsExternFunc: bool = bool(getattr(node, 'Extern', False))
|
||||
IsExportFunc: bool = bool(getattr(node, 'Export', False))
|
||||
IsStaticFunc: bool = bool(getattr(node, 'Static', False))
|
||||
IsTlsFunc: bool = False
|
||||
IsVirtualFunc: bool = False
|
||||
IsNoVirtualFunc: bool = False
|
||||
PendingDecorators: list[str] = []
|
||||
for decorator in node.decorator_list:
|
||||
DecoratorStr: str = PythonToStubConverter._GetDecoratorString(decorator)
|
||||
if DecoratorStr == 'TLS':
|
||||
FuncPrefix = 'tls '
|
||||
elif DecoratorStr == 'CStatic':
|
||||
FuncPrefix = 'static '
|
||||
elif DecoratorStr == 'CExport':
|
||||
FuncPrefix = 'export '
|
||||
elif DecoratorStr == 'CExtern':
|
||||
FuncPrefix = 'extern '
|
||||
DecoratorShort: str = DecoratorStr.rsplit('.', 1)[-1]
|
||||
if DecoratorShort == 'TLS':
|
||||
IsTlsFunc = True
|
||||
elif DecoratorShort == 'CStatic':
|
||||
IsStaticFunc = True
|
||||
elif DecoratorShort == 'CExport':
|
||||
IsExportFunc = True
|
||||
elif DecoratorShort == 'CExtern':
|
||||
IsExternFunc = True
|
||||
elif DecoratorShort == 'CVTable':
|
||||
IsVirtualFunc = True
|
||||
elif DecoratorShort == 'NoVTable':
|
||||
IsNoVirtualFunc = True
|
||||
elif DecoratorStr:
|
||||
lines.append(f'{IndentStr}@{DecoratorStr}')
|
||||
PendingDecorators.append(DecoratorStr)
|
||||
FuncPrefix: str = ''
|
||||
if IsExternFunc:
|
||||
FuncPrefix = 'extern '
|
||||
elif IsExportFunc:
|
||||
FuncPrefix = 'export '
|
||||
elif IsStaticFunc:
|
||||
FuncPrefix = 'static '
|
||||
elif IsTlsFunc:
|
||||
FuncPrefix = 'tls '
|
||||
elif IsVirtualFunc:
|
||||
FuncPrefix = 'virtual '
|
||||
elif IsNoVirtualFunc:
|
||||
FuncPrefix = 'novirtual '
|
||||
for DecoratorStr in PendingDecorators:
|
||||
lines.append(f'{IndentStr}@{DecoratorStr}')
|
||||
|
||||
# 构建参数列表
|
||||
# 治本修复:原实现只遍历 node.args.args,完全忽略 node.args.defaults,
|
||||
@@ -565,7 +620,7 @@ class PythonToStubConverter:
|
||||
if node.returns:
|
||||
ReturnType = PythonToStubConverter._GetTypeString(node.returns)
|
||||
else:
|
||||
ReturnType = 'CInt'
|
||||
ReturnType = 'int'
|
||||
|
||||
TypeParamStr: str = ''
|
||||
if hasattr(node, 'type_params') and node.type_params:
|
||||
@@ -584,19 +639,25 @@ class PythonToStubConverter:
|
||||
TypeStr: str = PythonToStubConverter._GetTypeString(node.annotation)
|
||||
Markers: tuple[str, ...] = (tuple(getattr(node, 'Markers', None) or ())
|
||||
+ tuple(getattr(node.annotation, 'Markers', None) or ()))
|
||||
# 检查是否是宏变量(类型包含 CDefine 或 Markers 标记 define)
|
||||
# 检查是否是宏变量(优先读 Markers 的 define;CDefine 仅兼容旧文本)
|
||||
if 'CDefine' in TypeStr or 'define' in Markers:
|
||||
# 检查宏变量是否应该被排除
|
||||
if PythonToStubConverter._ShouldExcludeMacro(VarName):
|
||||
return lines # 返回空列表,排除该宏
|
||||
# 宏变量保持原样(包括赋值)
|
||||
if SourceLines and hasattr(node, 'lineno'):
|
||||
StartLine: int = node.lineno - 1
|
||||
EndLine: int = node.end_lineno if hasattr(node, 'end_lineno') and node.end_lineno else StartLine + 1
|
||||
for i in range(StartLine, min(EndLine, len(SourceLines))):
|
||||
lines.append(SourceLines[i])
|
||||
# 统一输出新语法 `define NAME[: 类型] = 值`(旧写法在此归一化)
|
||||
ImplicitType: bool = (
|
||||
isinstance(node.annotation, ast.Name)
|
||||
and node.annotation.id == 'CDefine')
|
||||
TypePart: str = '' if ImplicitType else f': {TypeStr}'
|
||||
if node.value is not None:
|
||||
try:
|
||||
ValueStr: str = ast.unparse(node.value)
|
||||
except Exception:
|
||||
ValueStr = ''
|
||||
lines.append(f'define {VarName}{TypePart} = {ValueStr}')
|
||||
else:
|
||||
lines.append(f'{VarName}: {TypeStr}')
|
||||
# 无初值的宏(C 头 `#define FOO`)在新语法下补 0 占位
|
||||
lines.append(f'define {VarName}{TypePart} = 0')
|
||||
return lines
|
||||
# 非宏变量:不加 State
|
||||
# 含有 typedef 的变量不加 extern,普通变量需要加 extern
|
||||
@@ -633,51 +694,67 @@ class PythonToStubConverter:
|
||||
if inferred_type:
|
||||
lines.append(f'{VarName}: {inferred_type}')
|
||||
else:
|
||||
lines.append(f'{VarName}: CInt')
|
||||
lines.append(f'{VarName}: int')
|
||||
|
||||
return lines
|
||||
|
||||
@staticmethod
|
||||
def _InferTypeFromValue(value: ast.AST) -> str | None:
|
||||
"""从值推断 C 类型"""
|
||||
"""从值推断内建类型名(新语法:int/float/char*/rawptr)"""
|
||||
if isinstance(value, ast.Constant):
|
||||
if isinstance(value.value, int):
|
||||
return 'CInt'
|
||||
if isinstance(value.value, bool):
|
||||
return 'int'
|
||||
elif isinstance(value.value, int):
|
||||
return 'int'
|
||||
elif isinstance(value.value, float):
|
||||
return 'CDouble'
|
||||
return 'double'
|
||||
elif isinstance(value.value, str):
|
||||
return 'CCharPtr'
|
||||
elif isinstance(value.value, bool):
|
||||
return 'CInt'
|
||||
return 'char*'
|
||||
elif isinstance(value, ast.List):
|
||||
return 'CVoidPtr'
|
||||
return 'rawptr'
|
||||
elif isinstance(value, ast.Dict):
|
||||
return 'CVoidPtr'
|
||||
return 'rawptr'
|
||||
elif isinstance(value, ast.Name):
|
||||
return 'CInt'
|
||||
return 'int'
|
||||
elif isinstance(value, ast.BinOp):
|
||||
left_type: str | None = PythonToStubConverter._InferTypeFromValue(value.left)
|
||||
if left_type:
|
||||
return left_type
|
||||
return 'CInt'
|
||||
return 'int'
|
||||
elif isinstance(value, ast.Call):
|
||||
# 函数调用返回值,假设为指针类型
|
||||
if isinstance(value.func, ast.Name):
|
||||
func_name: str = value.func.id
|
||||
if func_name == 'malloc':
|
||||
return 'CVoidPtr'
|
||||
elif func_name in ('ctypes.cast', 'cast'):
|
||||
return 'CVoidPtr'
|
||||
return 'CVoidPtr'
|
||||
if func_name in ('malloc', 'cast'):
|
||||
return 'rawptr'
|
||||
return 'rawptr'
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _GetTypeString(annotation: ast.AST) -> str:
|
||||
if annotation is None:
|
||||
return 'CVoid'
|
||||
return 'void'
|
||||
Core: str = PythonToStubConverter._GetTypeStringCore(annotation)
|
||||
# 语句级修饰(typedef/define/static/export/extern/state)由调用方在
|
||||
# 声明前缀输出,不能混进类型文本;const/volatile/inline 等类型修饰
|
||||
# 以及 Attributes/ByteOrder/BitWidth 按 Unparser 同一口径还原。
|
||||
_StatementMarkers: frozenset[str] = frozenset(
|
||||
('typedef', 'define', 'static', 'export', 'extern', 'state'))
|
||||
Markers: tuple[str, ...] = tuple(getattr(annotation, 'Markers', None) or ())
|
||||
Prefix: str = ''.join(f'{m} ' for m in Markers if m in ('const', 'volatile', 'inline'))
|
||||
PrefixParts: list[str] = [
|
||||
m for m in Markers if m not in _StatementMarkers]
|
||||
Attributes: tuple[str, ...] = tuple(getattr(annotation, 'Attributes', None) or ())
|
||||
if Attributes:
|
||||
PrefixParts.append('__attribute__((' + ', '.join(Attributes) + '))')
|
||||
ByteOrder: str = getattr(annotation, 'ByteOrder', '') or ''
|
||||
if ByteOrder == 'big':
|
||||
PrefixParts.append('BigEndian')
|
||||
elif ByteOrder == 'little':
|
||||
PrefixParts.append('LittleEndian')
|
||||
BitWidth: int = getattr(annotation, 'BitWidth', 0) or 0
|
||||
if BitWidth:
|
||||
PrefixParts.append(f'Bit({BitWidth})')
|
||||
Prefix: str = ''.join(f'{m} ' for m in PrefixParts)
|
||||
return Prefix + Core
|
||||
|
||||
@staticmethod
|
||||
@@ -689,10 +766,10 @@ class PythonToStubConverter:
|
||||
List/Call(VPC 另支持裸 Tuple,本侧仅在 Subscript.slice 位置接受 Tuple)。
|
||||
未支持的节点种类与运算符在此 fail-fast(不自造 'CVoid' 回落)。
|
||||
"""
|
||||
# 无注解(None):调用方未提供注解,沿用原语义返回 'CVoid';
|
||||
# 无注解(None):调用方未提供注解,按无返回类型处理(新语法 void);
|
||||
# 这不是"未知节点"——未知节点走函数尾 fail-fast。
|
||||
if annotation is None:
|
||||
return 'CVoid'
|
||||
return 'void'
|
||||
if isinstance(annotation, ast.Name):
|
||||
return _STUB_TYPE_ALIASES.get(annotation.id, annotation.id)
|
||||
elif isinstance(annotation, ast.Attribute):
|
||||
@@ -705,6 +782,17 @@ class PythonToStubConverter:
|
||||
ParentStr: str = PythonToStubConverter._GetTypeString(annotation.value)
|
||||
return f'{ParentStr}.{annotation.attr}'
|
||||
elif isinstance(annotation, ast.Subscript):
|
||||
# 值引用标记按节点原名判定(不能被 _STUB_TYPE_ALIASES 提前归一成
|
||||
# rawptr,否则 `&T` / `&temp T` 会被误写成 `T*`)。
|
||||
ValueName: str = ''
|
||||
if isinstance(annotation.value, ast.Name):
|
||||
ValueName = annotation.value.id
|
||||
elif isinstance(annotation.value, ast.Attribute):
|
||||
ValueName = annotation.value.attr
|
||||
if ValueName == 'CRef':
|
||||
return '&' + PythonToStubConverter._GetTypeString(annotation.slice)
|
||||
if ValueName == 'CTempRef':
|
||||
return '&temp ' + PythonToStubConverter._GetTypeString(annotation.slice)
|
||||
base: str = PythonToStubConverter._GetTypeString(annotation.value)
|
||||
if isinstance(annotation.slice, ast.Tuple):
|
||||
slice_strs: list[str] = [PythonToStubConverter._GetTypeString(e) for e in annotation.slice.elts]
|
||||
@@ -713,44 +801,19 @@ class PythonToStubConverter:
|
||||
SliceStr = PythonToStubConverter._GetTypeString(annotation.slice)
|
||||
if base in ('CPtr', 'rawptr'):
|
||||
return PythonToStubConverter._GetTypeString(annotation.slice) + '*'
|
||||
if base == 'CRef':
|
||||
return '&' + PythonToStubConverter._GetTypeString(annotation.slice)
|
||||
if base == 'CTempRef':
|
||||
return '&temp ' + PythonToStubConverter._GetTypeString(annotation.slice)
|
||||
return f'{base}[{SliceStr}]'
|
||||
elif isinstance(annotation, ast.BinOp):
|
||||
# 处理 BinOp,如 CExtern | fd_table.__set_default__(...)
|
||||
left: ast.AST = annotation.left
|
||||
right: ast.AST = annotation.right
|
||||
|
||||
# 值引用参数标记:联合形态 `T | CRef`(ref)/ `T | CTempRef`(temp)
|
||||
# 还原为源码写法 `&T` / `&temp T`,使跨模块 .vpi 往返保留取址模式。
|
||||
# 类型注解不再接受 `T1 | T2` 联合(包括旧的 CExtern | T /
|
||||
# CDefine | T / T | CRef):一律 fail-fast,不做任何合并。
|
||||
if isinstance(annotation.op, ast.BitOr):
|
||||
_ref_kind: str | None = None
|
||||
_type_side: ast.AST | None = None
|
||||
if isinstance(right, ast.Name) and right.id in ('CRef', 'CTempRef'):
|
||||
_ref_kind = right.id
|
||||
_type_side = left
|
||||
elif isinstance(left, ast.Name) and left.id in ('CRef', 'CTempRef'):
|
||||
_ref_kind = left.id
|
||||
_type_side = right
|
||||
if _ref_kind is not None and _type_side is not None:
|
||||
_inner: str = PythonToStubConverter._GetTypeString(_type_side)
|
||||
return f'&temp {_inner}' if _ref_kind == 'CTempRef' else f'&{_inner}'
|
||||
|
||||
# 检查右侧是否是 __set_default__ 调用
|
||||
if isinstance(right, ast.Call) and isinstance(right.func, ast.Attribute) and right.func.attr in ('__set_default__', '__set_default'):
|
||||
# 去除 __set_default__,保留左侧,右侧替换为函数名部分
|
||||
LeftStr: str = PythonToStubConverter._GetTypeString(left)
|
||||
RightStr: str = PythonToStubConverter._GetTypeString(right.func.value)
|
||||
if isinstance(annotation.op, ast.BitOr):
|
||||
return f'{LeftStr} | {RightStr}'
|
||||
|
||||
LeftStr = PythonToStubConverter._GetTypeString(left)
|
||||
RightStr = PythonToStubConverter._GetTypeString(right)
|
||||
if isinstance(annotation.op, ast.BitOr):
|
||||
return f'{LeftStr} | {RightStr}'
|
||||
elif isinstance(annotation.op, ast.Add):
|
||||
Line: int = getattr(annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 `T*` 或 `rawptr[T]`,"
|
||||
f"修饰符请用关键字(const/volatile/static/export/extern)")
|
||||
LeftStr: str = PythonToStubConverter._GetTypeString(annotation.left)
|
||||
RightStr: str = PythonToStubConverter._GetTypeString(annotation.right)
|
||||
if isinstance(annotation.op, ast.Add):
|
||||
return f'{LeftStr} + {RightStr}'
|
||||
elif isinstance(annotation.op, ast.Sub):
|
||||
return f'{LeftStr} - {RightStr}'
|
||||
@@ -852,16 +915,13 @@ class PythonToStubConverter:
|
||||
例如:Postdefinition(__buddy_system) -> '__buddy_system'
|
||||
Postdefinition(xxx) | CTypedef -> 'xxx'
|
||||
"""
|
||||
# 处理 BinOp (如: Postdefinition(xxx) | CTypedef)
|
||||
# 类型注解中的 BinOp(BitOr) 联合已废止:fail-fast,不做合并。
|
||||
if isinstance(annotation, ast.BinOp):
|
||||
# 递归检查左操作数
|
||||
left_result: str | None = PythonToStubConverter._ExtractPostdefClass(annotation.left)
|
||||
if left_result:
|
||||
return left_result
|
||||
# 递归检查右操作数
|
||||
right_result: str | None = PythonToStubConverter._ExtractPostdefClass(annotation.right)
|
||||
if right_result:
|
||||
return right_result
|
||||
if isinstance(annotation.op, ast.BitOr):
|
||||
Line: int = getattr(annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型")
|
||||
return None
|
||||
|
||||
# 处理函数调用 (如: Postdefinition(__buddy_system))
|
||||
@@ -988,6 +1048,9 @@ class PythonToStubConverter:
|
||||
return decorator.id
|
||||
elif isinstance(decorator, ast.Attribute):
|
||||
if isinstance(decorator.value, ast.Name):
|
||||
# 旧 `t.X` / `c.X` 前缀只作输入兼容:stub 输出按裸名书写。
|
||||
if decorator.value.id in ('t', 'c'):
|
||||
return decorator.attr
|
||||
return f'{decorator.value.id}.{decorator.attr}'
|
||||
return decorator.attr
|
||||
elif isinstance(decorator, ast.Call):
|
||||
|
||||
@@ -309,10 +309,10 @@ class AssignHandle(BaseHandle):
|
||||
else:
|
||||
if VarName in ('mctx', 's1ctx', 's2ctx', 's5ctx'):
|
||||
pass
|
||||
# 【联合返回注解的被指类恢复】RHS 是调用、且值的 LLVM 类型是**通用指针**
|
||||
# 【指针返回注解的被指类恢复】RHS 是调用、且值的 LLVM 类型是**通用指针**
|
||||
# (i8*/i8**,pointee 不是结构体)时,上面那块类名推断整块失效 —— 现场
|
||||
# `parts = s1.split(',')`:`split` 的返回注解 `list[str]*` ≡
|
||||
# `list[str] | CPtr`(只读探针确认二者 AST 逐字同形)被映射成 i8*
|
||||
# `CPtr[list[str]]` 被映射成 i8*
|
||||
# ⇒ 类名丢失 ⇒ 随后 `parts[0]` 不走 `list[str].__getitem__` 而按通用
|
||||
# 指针/字节索引 ⇒ 得到整数 ⇒ 赋给 `str` 时报"整数隐式转指针已禁止"
|
||||
# (真因在 4 行之前,报文完全指不到)。此处从被调者的**返回注解**
|
||||
@@ -1479,7 +1479,7 @@ class AssignHandle(BaseHandle):
|
||||
obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
|
||||
idx_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.slice)
|
||||
if obj_val and idx_val:
|
||||
# 处理 obj_val 为 i8(整数)的情况:联合类型 | CPtr 降级后可能被 load 为 i8
|
||||
# 处理 obj_val 为 i8(整数)的情况:指针下标类型降级后可能被 load 为 i8
|
||||
if isinstance(obj_val.type, ir.IntType) and obj_val.type.width == 8:
|
||||
obj_val = Gen.builder.inttoptr(obj_val, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
|
||||
if BaseHandle._is_char_pointer(obj_val):
|
||||
@@ -1495,7 +1495,7 @@ class AssignHandle(BaseHandle):
|
||||
IndexVal: ir.Value | None = self.HandleExprLlvm(Target.slice)
|
||||
if not ValueVal or not IndexVal:
|
||||
return
|
||||
# 当变量本身是二级指针(如 elem_ptr: T | CPtr = AST**),
|
||||
# 当变量本身是二级指针(如 elem_ptr: CPtr[CPtr[T]] = AST**),
|
||||
# 且存储的值也是指针时,elem_ptr[i] = item 应直接存储指针(8 字节),
|
||||
# 而非解引用后复制结构体(如 48 字节的 AST),避免对象切片
|
||||
if isinstance(Target.value, ast.Name):
|
||||
@@ -1550,7 +1550,7 @@ class AssignHandle(BaseHandle):
|
||||
and isinstance(Target.value, ast.Name)
|
||||
and (Gen.var_ptr_element.get(Target.value.id, False)
|
||||
or Gen.global_var_ptr_element.get(Target.value.id, False))):
|
||||
# 指针到 str/bytes 的变量 (BinOp 注解如 str | CPtr)
|
||||
# 指针到 str/bytes 的变量(指针下标注解如 CPtr[str])
|
||||
# elem_ptr 是 i8* 但实际指向 i8* (字符串指针), elem_ptr[0] = item 应存储 8 字节
|
||||
CastedPtrPtr: ir.Value = Gen.builder.bitcast(ValueVal, ir.PointerType(ir.PointerType(ir.IntType(8))), name="cast_pp_str_store")
|
||||
if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64:
|
||||
@@ -1680,7 +1680,7 @@ class AssignHandle(BaseHandle):
|
||||
f"而不是按指针写 {PtrSize} 字节。若该地址实际按 8 字节槽存放指针"
|
||||
f"(如 rawptr[T] 缓冲/空闲链表),每写一个元素就越界 {Over} 字节,"
|
||||
f"直接写穿相邻块。修法:把指针槽的基座类型写成指针元素形态"
|
||||
f"(`rawptr[T] | CPtr` 或 `rawptr[rawptr[T]]`)后再赋值;"
|
||||
f"(`CPtr[rawptr[T]]` 或 `rawptr[rawptr[T]]`)后再赋值;"
|
||||
f"或把基座显式转为 CPtr(无类型指针)后按 8 字节指针语义写入。{SrcInfo}")
|
||||
|
||||
def _DescribeMemberSlot(self, Gen: "Translator.LlvmGen", ClassName: str | None,
|
||||
@@ -2410,6 +2410,9 @@ class AssignHandle(BaseHandle):
|
||||
if isinstance(annotation, ast.Attribute):
|
||||
if annotation.attr in ('CTypedef', 'CDefine'):
|
||||
return True
|
||||
# 兼容旧 AST:裸标记名(新表示为 Markers,已在函数入口命中)。
|
||||
if isinstance(annotation, ast.Name):
|
||||
return annotation.id in ('CTypedef', 'CDefine')
|
||||
if isinstance(annotation, ast.Subscript):
|
||||
return self._IsTypedefAnnotation(annotation.value)
|
||||
return False
|
||||
|
||||
@@ -14,11 +14,17 @@ from lib.core import TypeSystem
|
||||
from lib.core.TypeSystem import CTypeRegistry
|
||||
from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES
|
||||
from lib.core.SymbolUtils import (
|
||||
IsPtrSubscriptNode, IsListAnnotation, IsCPtrMarkerNode,
|
||||
FlattenUnionOperands, IsI8DoublePtrType, IsClassRefPtrAnnotation,
|
||||
IsPtrSubscriptNode, IsListAnnotation,
|
||||
IsI8DoublePtrType, IsClassRefPtrAnnotation,
|
||||
FixedArrayKeywordAnnotationError, FindAutoAddrMode)
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
# 指针/引用下标包装名(`CPtr[T]` / `rawptr[T]` / `CRef[T]` ...):
|
||||
# 新表示下指针/引用统一是 Subscript,不再是 `T | CPtr` 联合。
|
||||
_PTR_SUBSCRIPT_NAMES: frozenset[str] = frozenset({
|
||||
'CPtr', 'rawptr', 'CArrayPtr', 'CRef', 'CTempRef', 'CAutoPtr',
|
||||
})
|
||||
|
||||
|
||||
EXCEPTION_CODE_MAP: dict[str, int] = {
|
||||
'ValueError': 1, 'TypeError': 2, 'RuntimeError': 3,
|
||||
@@ -1023,13 +1029,25 @@ class BaseHandle:
|
||||
|
||||
return 1
|
||||
|
||||
def ResolveAnnotationType(self, annotation: ast.expr) -> CTypeInfo | None:
|
||||
"""解析注解类型,BinOp(BitOr) 优先使用 MergeTypes,其他使用 FromNode。
|
||||
@staticmethod
|
||||
def _IsPtrOrRefSubscript(Annotation: ast.AST) -> bool:
|
||||
"""注解是否为指针/引用下标(CPtr/rawptr/CRef/CTempRef/CArrayPtr/CAutoPtr)。"""
|
||||
if not isinstance(Annotation, ast.Subscript):
|
||||
return False
|
||||
Base: ast.AST = Annotation.value
|
||||
BaseName: str = ''
|
||||
if isinstance(Base, ast.Name):
|
||||
BaseName = Base.id
|
||||
elif isinstance(Base, ast.Attribute):
|
||||
BaseName = Base.attr
|
||||
return BaseName in _PTR_SUBSCRIPT_NAMES
|
||||
|
||||
统一处理函数返回类型和参数类型的 BinOp 联合类型解析。
|
||||
指针下标(rawptr[T] 内置裸指针 / CPtr[T] / 裸名 CPtr[T],三者等价
|
||||
`T | CPtr`)同样交给 TypeMerge 解析:内层 T 走通用类型解析(含跨模块
|
||||
类经 Gen.structs 反查 SHA1 前缀),指针层数与源码 `T | CPtr` 一致;
|
||||
def ResolveAnnotationType(self, annotation: ast.expr) -> CTypeInfo | None:
|
||||
"""解析注解类型;类型联合 `T1 | T2` 一律 fail-fast。
|
||||
|
||||
指针/引用下标(rawptr[T] / CPtr[T] / CRef[T] / CTempRef[T] /
|
||||
CArrayPtr[T] / CAutoPtr[T])统一交给 TypeMerge 解析:内层 T 走通用类型
|
||||
解析(含跨模块类经 Gen.structs 反查 SHA1 前缀);
|
||||
若交给 CTypeInfo.FromNode(TypeAnnotationResolver)解析,
|
||||
rawptr[ast.AST] 会退化成 CVoid/1(i8*)、CPtr[ast.AST] 亦退化成
|
||||
CVoid/1(其 Subscript-CPtr 分支不带 Gen.structs 反查),与 declare 端
|
||||
@@ -1046,7 +1064,8 @@ class BaseHandle:
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {getattr(annotation, 'lineno', 0)} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
if IsPtrSubscriptNode(annotation, self.Trans.SymbolTable):
|
||||
if IsPtrSubscriptNode(annotation, self.Trans.SymbolTable) \
|
||||
or self._IsPtrOrRefSubscript(annotation):
|
||||
merger = getattr(self.Trans, 'TypeMergeHandler', None)
|
||||
if merger:
|
||||
info = merger.GetCTypeInfo(annotation)
|
||||
@@ -1108,8 +1127,8 @@ class BaseHandle:
|
||||
DeclarationGenerator._get_type_str 的 `attr_name in struct_names`、名称域
|
||||
SymbolUtils._ResolveAttributeArgStr 同一条"类名 → SHA1"规则)。
|
||||
|
||||
不修此路时跨模块类 Attribute(`rawptr[<sha1>.CLS]` 脱糖后的
|
||||
`<sha1>.CLS | CPtr`、泛型 T 替换出的裸 `<sha1>.CLS`、`list[ast.AST]`
|
||||
不修此路时跨模块类 Attribute(`rawptr[<sha1>.CLS]` / `CPtr[<sha1>.CLS]`、
|
||||
泛型 T 替换出的裸 `<sha1>.CLS`、`list[ast.AST]`
|
||||
特化的 `append(item: T)`)在定义端判为"无法识别的参数类型注解"抛
|
||||
SyntaxError,被上层 broad except 吞掉后退化为 i32/i8*,而声明端给
|
||||
`%"<sha1>.CLS"*`,字段/签名两侧不一致。
|
||||
@@ -1147,10 +1166,11 @@ class BaseHandle:
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {getattr(annotation, 'lineno', 0)} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
# 指针下标参数注解(rawptr[T] / CPtr[T] / 裸名 CPtr[T],含
|
||||
# rawptr[list[X]] 等容器:_SubscriptHitsGenericTemplate 也命中,但统一交
|
||||
# ResolveAnnotationType 处理更简单——它已把指针下标路由到 TypeMerge)。
|
||||
if IsPtrSubscriptNode(annotation, self.Trans.SymbolTable):
|
||||
# 指针/引用下标参数注解(rawptr[T] / CPtr[T] / CRef[T] / CTempRef[T] /
|
||||
# CArrayPtr[T] / CAutoPtr[T],含 rawptr[list[X]] 等容器:统一交
|
||||
# ResolveAnnotationType 处理——它已把指针/引用下标路由到 TypeMerge)。
|
||||
if IsPtrSubscriptNode(annotation, self.Trans.SymbolTable) \
|
||||
or self._IsPtrOrRefSubscript(annotation):
|
||||
info = self.ResolveAnnotationType(annotation)
|
||||
if isinstance(info, CTypeInfo) and info.BaseType is not None:
|
||||
return info
|
||||
@@ -1187,7 +1207,7 @@ class BaseHandle:
|
||||
inner: ast.AST = annotation.slice.value
|
||||
if isinstance(inner, ast.Name) and inner.id in tpls:
|
||||
return True
|
||||
elif isinstance(base, ast.Attribute) and base.attr == 'CPtr':
|
||||
elif isinstance(base, ast.Attribute) and base.attr in _PTR_SUBSCRIPT_NAMES:
|
||||
if isinstance(annotation.slice, ast.Subscript):
|
||||
inner = annotation.slice.value
|
||||
if isinstance(inner, ast.Name) and inner.id in tpls:
|
||||
@@ -1242,8 +1262,8 @@ class BaseHandle:
|
||||
|
||||
**不再静默兜底**(原实现:注解解析返回 None → i32;_ctype_to_llvm 得 void → i8*;
|
||||
任何异常 → i32 + TypeInfo=None)。这些兜底会把"注解没解析出来"伪装成一个
|
||||
具体类型,下游于是报出与真因无关的错——实测:`free_lists: uint64*`(脱糖为
|
||||
`uint64 | CPtr`)在解析异常时被当成 **i32**,`self.free_lists = base`(i8*)
|
||||
具体类型,下游于是报出与真因无关的错——实测:`free_lists: uint64*`(`CPtr[uint64]`)
|
||||
在解析异常时被当成 **i32**,`self.free_lists = base`(i8*)
|
||||
便误报"指针隐式转整数已禁止"。类型信息缺失一律响亮失败。
|
||||
非 AnnAssign/Name 目标时返回 None。
|
||||
"""
|
||||
@@ -1287,7 +1307,7 @@ class BaseHandle:
|
||||
f"Name={getattr(TypeInfo, 'Name', None)})—— 拒绝静默退化为 i8*"
|
||||
)
|
||||
# 「内层是类引用却解析成通用指针」fail-fast(降级源头定位):
|
||||
# `rawptr[Mod.Class]` / `Mod.Class | CPtr` 的语义是"指向该类",内层若确实是
|
||||
# `rawptr[Mod.Class]` / `CPtr[Mod.Class]` 的语义是"指向该类",内层若确实是
|
||||
# 已定义类,解析结果必须带该类 BaseType;退化成 void 基座(i8* / 多一层 i8**)
|
||||
# 就是类型信息被丢掉 —— 该值一旦进 class_members 就会被冻进 struct body
|
||||
# (llvmlite set_body 只能设一次),后期只修表不修体(现场:Generator 第 3/11
|
||||
@@ -1350,20 +1370,17 @@ class BaseHandle:
|
||||
if not (Info.BaseType is TypeSystem.CVoid or isinstance(Info.BaseType, TypeSystem.CVoid)):
|
||||
return
|
||||
# 只要还带着任何"类身份"(IsStruct / IsRenum / IsEnum / Name),就不是信息丢失:
|
||||
# REnum 类型条目本身 BaseType=None,`T | CPtr` 合并后会被默认填成 CVoid,但
|
||||
# REnum 类型条目本身 BaseType=None,指针下标解析时会被默认填成 CVoid,但
|
||||
# IsRenum/IsStruct/Name 齐备,_ctype_to_llvm 仍能解析出 %<sha1>.T* —— 误判会
|
||||
# 把合法注解(如 REnum 变体载荷 `Pointee: rawptr[LLVMType]`)打成致命错误。
|
||||
if (getattr(Info, 'IsStruct', False) or getattr(Info, 'IsRenum', False)
|
||||
or getattr(Info, 'IsEnum', False) or getattr(Info, 'Name', None)):
|
||||
return
|
||||
Inner: ast.AST | None = None
|
||||
if isinstance(Annotation, ast.Subscript) and IsPtrSubscriptNode(Annotation, self.Trans.SymbolTable):
|
||||
if isinstance(Annotation, ast.Subscript) and (
|
||||
IsPtrSubscriptNode(Annotation, self.Trans.SymbolTable)
|
||||
or self._IsPtrOrRefSubscript(Annotation)):
|
||||
Inner = Annotation.slice
|
||||
elif isinstance(Annotation, ast.BinOp) and isinstance(Annotation.op, ast.BitOr):
|
||||
for Side in FlattenUnionOperands(Annotation):
|
||||
if not IsCPtrMarkerNode(Side, self.Trans.SymbolTable):
|
||||
Inner = Side
|
||||
break
|
||||
if Inner is None:
|
||||
return
|
||||
InnerName: str | None = None
|
||||
|
||||
@@ -10,7 +10,7 @@ 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 (
|
||||
FindStructNameInAnnotationWithContext, MangleTypeArgByRegistry,
|
||||
MangleTypeArgByRegistry,
|
||||
EnumClassIntWidth,
|
||||
EnumBodyMemberNames, EnumMemberCountMismatchError,
|
||||
ClassHasFuncLevelCVTable, IsVtableSlotMethod)
|
||||
@@ -27,6 +27,12 @@ _ENUM_PTR_ANNOTATION_NAMES: frozenset[str] = frozenset({
|
||||
'CPtr', 'CAutoPtr', 'CRef', 'CTempRef', 'rawptr', 'str', 'bytes',
|
||||
})
|
||||
|
||||
# 指针/引用下标包装名(`CPtr[T]` / `rawptr[T]` / `CRef[T]` ...):
|
||||
# 新 AST 表示下指针是 Subscript,不再是 `T | CPtr` 联合的一翼。
|
||||
_PTR_SUBSCRIPT_NAMES: frozenset[str] = frozenset({
|
||||
'CPtr', 'rawptr', 'CArrayPtr', 'CRef', 'CTempRef', 'CAutoPtr',
|
||||
})
|
||||
|
||||
|
||||
class ClassHandle(BaseHandle):
|
||||
def _is_exception_class(self, Node: ast.ClassDef) -> bool:
|
||||
@@ -177,7 +183,7 @@ class ClassHandle(BaseHandle):
|
||||
# 都不在类表里 → 天然判为值类型,无需名表。
|
||||
# 历史教训(名表判据的代价,保留以便回归时理解):`str` 曾漏在
|
||||
# "非类类型名"集合外 → `list[str]` 的类型参数被误判为类类型,特化后
|
||||
# 方法签名被额外包一层 `| CPtr`(append/set 形参 i8**、get/pop 返回
|
||||
# 方法签名被额外包一层 `CPtr[...]`(append/set 形参 i8**、get/pop 返回
|
||||
# i8**)→ 调用点多解一层 load(读字符串首 8 字节)→ ASan 崩溃。
|
||||
# 注意 _BUILTIN_TYPE_NAMES 本身仍保留:它用于 type_map 替换
|
||||
# 与 _from_import_aliases 注册,不能把 'str' 并进去
|
||||
@@ -194,7 +200,7 @@ class ClassHandle(BaseHandle):
|
||||
# (带 sha1 前缀 + ptr 后缀),避免模板内部嵌套注解被替换成裸短名
|
||||
# 后重新特化出只有 declare、无方法体的错误特化(list[AST].__len__
|
||||
# undefined symbol 根因)。_make_replacement_node 会把 mangled 名
|
||||
# 还原为 'sha1.AST | CPtr',重新解析时拼回一致的 mangled 名。
|
||||
# 还原为 'CPtr[sha1.AST]',重新解析时拼回一致的 mangled 名。
|
||||
tn_bare: str = tn.split('.')[-1] if '.' in tn else tn
|
||||
if tn_bare in _BUILTIN_TYPE_NAMES:
|
||||
type_map[tp_name] = tn
|
||||
@@ -204,10 +210,10 @@ class ClassHandle(BaseHandle):
|
||||
type_map[tp_name] = tn
|
||||
else:
|
||||
type_map[tp_name] = type_args[i]
|
||||
# 检测哪些类型参数在原始类型实参中带有指针语义(| CPtr / rawptr[T])
|
||||
# 检测哪些类型参数在原始类型实参中带有指针语义(CPtr[T] / rawptr[T] 等)
|
||||
# 当 type_arg 以 '*' 结尾(mangling 把每个 CPtr 层渲染为一层 '*')且对应的
|
||||
# type_name(去模块前缀后)不是内建类型名时,说明调用方写了
|
||||
# list[AST | CPtr] / list[rawptr[AST]]。注意用 tn_bare 判断:
|
||||
# list[CPtr[AST]] / list[rawptr[AST]]。注意用 tn_bare 判断:
|
||||
# 'CPtr' 去前缀后是 'CPtr'(内建),不算类类型参数。
|
||||
cptr_params: set[str] = set()
|
||||
for i, tp_name in enumerate(type_param_names):
|
||||
@@ -218,8 +224,8 @@ class ClassHandle(BaseHandle):
|
||||
if tn_bare_c not in _BUILTIN_TYPE_NAMES:
|
||||
cptr_params.add(tp_name)
|
||||
# Bug 2 修复:识别特化为 class 类型的类型参数
|
||||
# 这类参数在方法签名中是裸 T(无 | CPtr),特化后为裸 ClassName(值类型)
|
||||
# 需要加 | CPtr 使其成为指针类型(class 实例应按指针传递)
|
||||
# 这类参数在方法签名中是裸 T,特化后为裸 ClassName(值类型)
|
||||
# 需要加 CPtr[...] 使其成为指针类型(class 实例应按指针传递)
|
||||
# 判据 = "是否有类定义"(_HasClassDefinition),存**裸名**:注解侧的
|
||||
# 比较也用裸名(T 替换后的 'sha1.Param' 去前缀)——此前存带模块前缀的
|
||||
# tn(如 'ast.AST')而比较用裸名 'AST',前缀形态永不命中。
|
||||
@@ -886,7 +892,7 @@ class ClassHandle(BaseHandle):
|
||||
# 由 HandlesImports.py:2647/2654 与 FuncGen.py:1057 触发;该分支不受
|
||||
# "字段收集中"保护,见 HandlesImports.py:3299 的 `not force` 豁免)。
|
||||
# 此时本循环后面的 `append` 会把**嵌套帧已经登记过的同一字段**再写一条 ——
|
||||
# 现场:AST 的最后一个字段 `children: list[rawptr[AST]] | CPtr` 是全类唯一
|
||||
# 现场:AST 的最后一个字段 `children: CPtr[list[rawptr[AST]]]` 是全类唯一
|
||||
# 触发泛型特化的注解,处理它时嵌套帧重填了 AST 表(7 项),本循环恢复后
|
||||
# 又追加一次 `children` ⇒ 表 8 项 / 去重 7 项,重名条目 `children@7`;
|
||||
# 该表又被祖先块展平**原样拷贝**给 AST 的每个子类(_FlattenInherited 只按
|
||||
@@ -901,6 +907,11 @@ class ClassHandle(BaseHandle):
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
if item.target.id in ('__provides__', '__requires__', '__require_must__'):
|
||||
continue
|
||||
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
|
||||
Line: int = getattr(item.annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
parsed = self.CollectAnnAssignMember(item, Gen)
|
||||
if parsed:
|
||||
VarName, MemberType, TypeInfo = parsed
|
||||
@@ -913,39 +924,13 @@ class ClassHandle(BaseHandle):
|
||||
# FieldEntry.IsConst/IsVolatile/PointeeVolatile 同口径。
|
||||
Gen.RegisterFieldQualifiers(ClassName, VarName, TypeInfo, item.annotation)
|
||||
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 = FindStructNameInAnnotationWithContext(
|
||||
item.annotation, self.Trans, Gen)
|
||||
# Fallback: FindStructNameInAnnotation 不处理 Subscript slice 为 BinOp 的情况
|
||||
# (如 list[AST | CPtr] | CPtr),使用 TypeInfo.Name 作为回退。
|
||||
# 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
|
||||
if element_class:
|
||||
if ClassName not in Gen.class_member_element_class:
|
||||
Gen.class_member_element_class[ClassName] = {}
|
||||
Gen.class_member_element_class[ClassName][VarName] = element_class
|
||||
# 泛型特化结构体指针字段(如 GSList[BasicBlock] | CPtr):
|
||||
# 记录特化名,供后续 _try_access_opaque_generic_member 在所有候选特化版本
|
||||
# 都有目标字段(如 Head/Tail/Count)时选择正确特化版本。
|
||||
# 现有 i8* 分支不覆盖结构体指针字段,这里补充。
|
||||
elif (isinstance(MemberType, ir.PointerType)
|
||||
and isinstance(MemberType.pointee, ir.IdentifiedStructType)
|
||||
and isinstance(item.annotation, ast.BinOp)
|
||||
and isinstance(item.annotation.op, ast.BitOr)):
|
||||
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] = {}
|
||||
Gen.class_member_element_class[ClassName][VarName] = spec_in_anno
|
||||
# Subscript 容器字段(list[X] / rawptr[list[X]]):非 BinOp 联合,
|
||||
# 上面的 i8*/BinOp 分支不命中 → 容器身份丢失 → 字段方法调用
|
||||
# (get/len…)分派失败 "Undefined method 'get' in class 'rawptr'"
|
||||
# (Converter.vp L190)。与 HandlesImports 对称,用与特化生成端
|
||||
# 同源的 _resolve_type_arg_str 记录 element_class。
|
||||
# Subscript 容器/指针字段(list[X] / CPtr[list[X]] /
|
||||
# rawptr[GSList[X]]):记录容器/特化名,供字段方法分派与
|
||||
# 泛型特化结构体指针字段解析使用;身份丢失会导致
|
||||
# "Undefined method 'get' in class 'rawptr'"(Converter.vp L190)。
|
||||
# 旧联合写法(如 `GSList[BasicBlock] | CPtr`)已由循环入口
|
||||
# fail-fast 拦截,不再走合并路径。与 HandlesImports 对称,
|
||||
# 用与特化生成端同源的 _resolve_type_arg_str 记录 element_class。
|
||||
if isinstance(item.annotation, ast.Subscript):
|
||||
_ann_sub_c: ast.Subscript = item.annotation
|
||||
_subv_c: ast.AST = _ann_sub_c.value
|
||||
@@ -953,7 +938,7 @@ class ClassHandle(BaseHandle):
|
||||
_elem_slice_c: ast.AST | None = None
|
||||
if _subname_c == 'list':
|
||||
_elem_slice_c = _ann_sub_c.slice
|
||||
elif _subname_c == 'rawptr':
|
||||
elif _subname_c in _PTR_SUBSCRIPT_NAMES:
|
||||
_slice_c: ast.AST = _ann_sub_c.slice
|
||||
if isinstance(_slice_c, ast.Subscript):
|
||||
# rawptr[泛型容器](rawptr[list[X]] / rawptr[GSList[Param]]):
|
||||
@@ -980,8 +965,8 @@ class ClassHandle(BaseHandle):
|
||||
else:
|
||||
# rawptr[裸结构](如 rawptr[Token]):跨模块 stub 会把自引用/类内
|
||||
# 指针字段退化为 i8*,链式成员访问(a.b.c)需 element_class 恢复
|
||||
# struct 身份走 char*→struct cast。HEAD 态 `Token | CPtr` 联合
|
||||
# 由上方 BinOp 分支登记;rawptr 重构后此分支补齐(阻塞 A 根因)。
|
||||
# struct 身份走 char*→struct cast。指针统一为 Subscript
|
||||
# (`rawptr[Token]` / `CPtr[Token]`),由本分支登记。
|
||||
# 与 HandlesImports 的 rawptr 分支对称。
|
||||
_slc_name_c: str | None = None
|
||||
if isinstance(_slice_c, ast.Name):
|
||||
@@ -1549,8 +1534,8 @@ class ClassHandle(BaseHandle):
|
||||
variant_names: list[str] = []
|
||||
|
||||
# 预注册 REnum opaque 结构体到 Gen.structs 和 SymbolTable,
|
||||
# 使自引用成员(如 LLVMType | CPtr)在收集成员时能正确解析为 %LLVMType*。
|
||||
# 若不预注册,GetCTypeInfo 找不到 LLVMType → 回退到 IsEnum → i32 → | CPtr → i32*(错误)。
|
||||
# 使自引用成员(如 CPtr[LLVMType] / rawptr[LLVMType])在收集成员时能正确解析为 %LLVMType*。
|
||||
# 若不预注册,GetCTypeInfo 找不到 LLVMType → 回退到 IsEnum → i32 → 再加一层指针 → i32*(错误)。
|
||||
PreRenumType: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, ClassName)
|
||||
Gen.structs[ClassName] = PreRenumType
|
||||
PreTypeInfo: CTypeInfo = CTypeInfo()
|
||||
@@ -1560,7 +1545,7 @@ class ClassHandle(BaseHandle):
|
||||
PreTypeInfo.IsEnum = True
|
||||
# REnum 在内存布局上是 struct({ i32 __tag, <max_payload> }),
|
||||
# 必须设置 IsStruct=True 才能让 HandlesTypeMerge 的 CPtr 吸收逻辑生效:
|
||||
# `REnumType | CPtr` 应得到 REnumType*(PtrCount=1)而非 REnumType**(PtrCount=2)。
|
||||
# `CPtr[REnumType]` 应得到 REnumType*(PtrCount=1)而非 REnumType**(PtrCount=2)。
|
||||
# 否则 include-imported 函数返回类型会出现双指针,与声明单指针不匹配 → 运行时崩溃。
|
||||
PreTypeInfo.IsStruct = True
|
||||
PreTypeInfo.RenumVariants = []
|
||||
@@ -1695,7 +1680,7 @@ class ClassHandle(BaseHandle):
|
||||
PreTypeInfo.RenumVariants = variant_names
|
||||
|
||||
def _EnumMemberAnnotationIsPtr(self, annotation: ast.AST | None) -> bool:
|
||||
"""枚举成员注解是否含指针形态(逐层下标 + 联合类型逐边),True=含指针
|
||||
"""枚举成员注解是否含指针形态(逐层下标),True=含指针
|
||||
|
||||
与 VPC 侧 ClassGenEnum._enum_member_annotation_is_ptr 同口径。枚举值是
|
||||
整数常量,指针成员语义不成立,必须明确报错(fail-fast)而非静默接受:
|
||||
@@ -1706,8 +1691,10 @@ class ClassHandle(BaseHandle):
|
||||
if annotation is None:
|
||||
return False
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
return (self._EnumMemberAnnotationIsPtr(annotation.left)
|
||||
or self._EnumMemberAnnotationIsPtr(annotation.right))
|
||||
Line: int = getattr(annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
if isinstance(annotation, ast.Subscript):
|
||||
return self._EnumMemberAnnotationIsPtr(annotation.value)
|
||||
name: str | None = None
|
||||
|
||||
@@ -60,14 +60,19 @@ def _IsVoidOrDeclAnnotation(Annot: ast.AST) -> bool:
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
# 新表示:修饰词写入注解节点的 Markers(State/CExport/CExtern -> state/export/extern)。
|
||||
Markers: tuple[str, ...] = getattr(Annot, 'Markers', None) or ()
|
||||
if 'state' in Markers or 'export' in Markers or 'extern' in Markers:
|
||||
return True
|
||||
if isinstance(Annot, ast.Constant):
|
||||
return Annot.value is None
|
||||
if isinstance(Annot, ast.Subscript):
|
||||
return _IsVoidOrDeclAnnotation(Annot.value)
|
||||
if isinstance(Annot, ast.Attribute):
|
||||
# 兼容旧 AST:t.CVoid / t.State / t.CExport / t.CExtern
|
||||
return getattr(Annot, 'attr', '') in ('CVoid', 'State', 'CExport', 'CExtern')
|
||||
if isinstance(Annot, ast.Name):
|
||||
Markers: tuple[str, ...] = getattr(Annot, 'Markers', None) or ()
|
||||
if 'state' in Markers or 'export' in Markers or 'extern' in Markers:
|
||||
return True
|
||||
# 兼容旧 AST:裸标记名
|
||||
return Annot.id in ('CVoid', 'State', 'CExport', 'CExtern')
|
||||
return False
|
||||
|
||||
@@ -555,7 +560,7 @@ class FunctionHandle(BaseHandle):
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
|
||||
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
|
||||
# `str | CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),不能压平。
|
||||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
|
||||
if is_str_type or (ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1):
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = TypeSystem.CChar()
|
||||
@@ -616,10 +621,10 @@ class FunctionHandle(BaseHandle):
|
||||
IsPtr = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False
|
||||
ReturnType: ir.Type = Gen._ctype_to_llvm(ReturnTypeInfo)
|
||||
# 此处原有 "Ptr(Ptr(Struct)) → Ptr(Struct)" 的压层(历史遗留):会把已解析的
|
||||
# 多层指针返回类型(`-> rawptr[rawptr[X]]` / `-> X | CPtr | CPtr`)
|
||||
# 多层指针返回类型(`-> rawptr[rawptr[X]]` / `-> CPtr[CPtr[X]]`)
|
||||
# 与泛型特化方法返回(`list[X**]` 的 get/pop/__getitem__/__next__)少算一层,
|
||||
# 与同函数的形参(`append(item: T)` 保留 `X**`)、声明端
|
||||
# DeclarationGenerator._get_type_str 的 BinOp 分支(同样不压层,见
|
||||
# DeclarationGenerator._get_type_str 的指针下标分支(同样不压层,见
|
||||
# '_is_bare_class_ref_annotation' 为假时逐层外包)以及 _EmitFunctionLlvm
|
||||
# 的定义体路径全部不一致。违反"多层指针已解析时照原样保留层数"。
|
||||
# 实测(36 用例 A/B)删除后仅 `list[X**]` 的 4 个方法 declare 由 `X*` 变
|
||||
@@ -649,7 +654,7 @@ class FunctionHandle(BaseHandle):
|
||||
for i, ReturnTypeNode in enumerate(MultiRetTypes):
|
||||
ReturnTypeInfo = CTypeInfo.FromNode(ReturnTypeNode, self.Trans.SymbolTable)
|
||||
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
|
||||
# `str | CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),不能压平。
|
||||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
|
||||
if ReturnTypeInfo and ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1:
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = TypeSystem.CChar()
|
||||
@@ -679,7 +684,7 @@ class FunctionHandle(BaseHandle):
|
||||
IsPtr = True
|
||||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||||
# 仅当指针层数 <=1 时才压平为 i8*(裸 str/bytes)。
|
||||
# `str | CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),
|
||||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,
|
||||
# 不能压平,否则形参类型错误导致 _adjust_args 多 load 一层崩溃。
|
||||
if (ParamTypeInfo.IsStr and ParamTypeInfo.PtrCount <= 1) or (isinstance(Arg.annotation, ast.Name) and Arg.annotation.id in ('str', 'bytes')):
|
||||
ParamTypeInfo = CTypeInfo()
|
||||
@@ -725,7 +730,7 @@ class FunctionHandle(BaseHandle):
|
||||
ParamNames.append(Arg.arg)
|
||||
ParamTypeStrs.append(ParamTypeStr)
|
||||
# 自动取址模式(由注解读出,不依赖 BaseType 类型):
|
||||
# 'ref' = &T、'temp' = &temp T(合成联合 T | CRef / CTempRef),
|
||||
# 'ref' = &T、'temp' = &temp T(合成下标 CRef[T] / CTempRef[T]),
|
||||
# 'always' = CAutoPtr。经 Gen._auto_addr_params 供调用点分流。
|
||||
auto_mode: str | None = FindAutoAddrMode(Arg.annotation)
|
||||
auto_addr_modes.append(auto_mode)
|
||||
@@ -805,21 +810,19 @@ class FunctionHandle(BaseHandle):
|
||||
|
||||
def _make_replacement_node(self, replacement: str) -> ast.AST:
|
||||
"""将 type_map 中的替换字符串转换为 AST 节点。
|
||||
mangled 名称如 '<sha1>.AST*' 需要还原为 AST | CPtr 结构,
|
||||
mangled 名称如 '<sha1>.AST*' 需要还原为 `CPtr[<sha1>.AST]` 下标结构,
|
||||
否则类型解析会丢失 PtrCount 信息。
|
||||
含点号的名称(如 '<sha1>.AST')需解析为 ast.Attribute 链。
|
||||
下标形态('rawptr[ast.AST]' / 'list[AST]' 等)必须整体解析为 Subscript:
|
||||
_make_name_node 只按 '.' 切分会把 'rawptr[ast.AST]' 拆成
|
||||
Name('rawptr[ast') + Attribute('AST]'),两段都不是有效类型名 →
|
||||
参数/返回注解解析为空 → VoidType → "无法识别的参数类型注解"。
|
||||
指针下标(rawptr[T] / CPtr[T])再折叠为等价的 `T | CPtr`,与源码
|
||||
联合写法同解析路径(对齐 VPC TypeGenResolve._parse_type_string 的 '['
|
||||
分支 + ClassGenGeneric._clone_annotation 的 T 替换)。
|
||||
指针下标统一保持 Subscript 形态(rawptr[T] / CPtr[T] / CRef[T] / ...)。
|
||||
内层为已混淆名(数字开头,如 'rawptr[7565e081d88517ac.AST]')时
|
||||
ast.parse 无法解析(数字开头的令牌),改用手工拆 base/slice(同 VPC
|
||||
TypeGenResolve._parse_type_string 的数字开头手工拆分分支)。
|
||||
尾部 '*'(泛型实参 '<sha1>.Node*' / '<sha1>.Node**',来自 rawptr[T] /
|
||||
CPtr 的逐层 mangling)逐层还原为 `Node | CPtr [| CPtr]` → 对应
|
||||
CPtr 的逐层 mangling)逐层还原为嵌套 `CPtr[...]` → 对应
|
||||
层数指针;只剥一层会把 'Node*' 当结构体名建出 phantom opaque
|
||||
(item 类型与特化名 '<sha1>.Node**' 的语义不一致)。
|
||||
尾部 'ptr'(旧规则 mangling,如 'Nodeptr' / 'ast.ASTptr')保留兼容:
|
||||
@@ -998,8 +1001,8 @@ class FunctionHandle(BaseHandle):
|
||||
elif isinstance(node.func, ast.Attribute):
|
||||
if isinstance(node.func.value, ast.Name) and node.func.value.id in type_map:
|
||||
replacement: str = type_map[node.func.value.id]
|
||||
# 指针类型参数(如 list[AST | CPtr] 中的 T)在表达式上下文中
|
||||
# 需替换为 BinOp(AST | CPtr),使 __sizeof__ 等处理器能正确识别
|
||||
# 指针类型参数(如 list[CPtr[AST]] 中的 T)在表达式上下文中
|
||||
# 需替换为 `CPtr[AST]` 下标,使 __sizeof__ 等处理器能正确识别
|
||||
# 指针语义并直接返回 8,避免触发 struct 加载和重入编译
|
||||
if cptr_params and node.func.value.id in cptr_params:
|
||||
node.func.value = ast.Subscript(
|
||||
@@ -1423,7 +1426,7 @@ class FunctionHandle(BaseHandle):
|
||||
try:
|
||||
rt_info = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
|
||||
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
|
||||
# `str | CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),
|
||||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,
|
||||
# 不能压平,否则返回类型错误。
|
||||
if rt_info and rt_info.IsStr and rt_info.PtrCount <= 1:
|
||||
is_str_return = True
|
||||
@@ -1471,7 +1474,7 @@ class FunctionHandle(BaseHandle):
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
|
||||
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
|
||||
# `str | CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),不能压平。
|
||||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
|
||||
if is_str_type or (ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1):
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = TypeSystem.CChar()
|
||||
@@ -1560,7 +1563,7 @@ class FunctionHandle(BaseHandle):
|
||||
IsPtr = True
|
||||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||||
# 仅当指针层数 <=1 时才压平为 i8*(裸 str/bytes)。
|
||||
# `str | CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),
|
||||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,
|
||||
# 不能压平,否则形参类型错误导致 _adjust_args 多 load 一层崩溃。
|
||||
if (ParamTypeInfo.IsStr and ParamTypeInfo.PtrCount <= 1) or (isinstance(Arg.annotation, ast.Name) and Arg.annotation.id in ('str', 'bytes')):
|
||||
ParamTypeInfo = CTypeInfo()
|
||||
@@ -1616,7 +1619,7 @@ class FunctionHandle(BaseHandle):
|
||||
for i, ReturnTypeNode in enumerate(MultiRetTypes):
|
||||
ReturnTypeInfo = CTypeInfo.FromNode(ReturnTypeNode, self.Trans.SymbolTable)
|
||||
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
|
||||
# `str | CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),不能压平。
|
||||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
|
||||
if ReturnTypeInfo and ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1:
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = TypeSystem.CChar()
|
||||
@@ -2083,7 +2086,9 @@ class FunctionHandle(BaseHandle):
|
||||
if Node.returns is not None and not _is_ret_or_ctrl_tail:
|
||||
# void(None / CVoid)/ extern|export 声明型辅助符号
|
||||
# (State / CExport / CExtern)→ 掉出合法,不 fail-fast
|
||||
_DeclMarkers: tuple[str, ...] = getattr(Node, 'Markers', None) or ()
|
||||
_DeclMarkers: tuple[str, ...] = (
|
||||
tuple(getattr(Node, 'Markers', None) or ())
|
||||
+ tuple(getattr(Node.returns, 'Markers', None) or ()))
|
||||
_IsDecl: bool = any(m in ('state', 'export', 'extern') for m in _DeclMarkers)
|
||||
if not _IsDecl and not _IsVoidOrDeclAnnotation(Node.returns):
|
||||
raise Exception(
|
||||
|
||||
@@ -14,7 +14,7 @@ from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.core import TypeSystem
|
||||
from lib.core.TypeSystem import CTypeRegistry
|
||||
from lib.core.SymbolUtils import ParseListAnnotation, ExtractTypeNameFromBinOp, AnnotationContainsName, FindStructNameInAnnotationWithContext, FindAutoAddrMode
|
||||
from lib.core.SymbolUtils import ParseListAnnotation, AnnotationContainsName, FindAutoAddrMode
|
||||
from lib.core.SymbolUtils import EnumClassIntWidth, ExpandSoftKeywords
|
||||
from lib.core.SymbolUtils import ClassHasFuncLevelCVTable, IsVtableSlotMethod
|
||||
|
||||
@@ -24,7 +24,13 @@ from lib.core.SymbolUtils import ClassHasFuncLevelCVTable, IsVtableSlotMethod
|
||||
_MARKER_ANNOT_NAMES: frozenset[str] = frozenset({
|
||||
'CExtern', 'CExport', 'CStatic', 'CInline', 'CConst', 'CVolatile', 'CRegister',
|
||||
'CAuto', 'CDefine', 'CTypedef', 'CPostdefinition', 'CPtr', 'CArrayPtr', 'CVoid',
|
||||
'State', 'TLS',
|
||||
'State', 'TLS', 'rawptr', 'CRef', 'CTempRef', 'CAutoPtr',
|
||||
})
|
||||
|
||||
# 指针/引用下标包装名(`CPtr[T]` / `rawptr[T]` / `CRef[T]` ...):
|
||||
# 新 AST 表示下指针是 Subscript,不再是 `T | CPtr` 联合的一翼。
|
||||
_PTR_SUBSCRIPT_NAMES: frozenset[str] = frozenset({
|
||||
'CPtr', 'rawptr', 'CArrayPtr', 'CRef', 'CTempRef', 'CAutoPtr',
|
||||
})
|
||||
|
||||
# 标记基类名(不是真实父类):与 HandlesClassDef._EmitClassLlvm 的 base 跳过表同口径。
|
||||
@@ -1257,18 +1263,18 @@ class ImportHandle(BaseHandle):
|
||||
def _AnnotationStructName(self, annotation: ast.AST) -> str | None:
|
||||
"""从注解里提取「指针指向的类」短名(递归,0 判定返回 None)
|
||||
|
||||
覆盖形态:`X` / `mod.X` / `rawptr[X]` / `CPtr[X]` / 联合 `A | B`(两翼都试)。
|
||||
覆盖形态:`X` / `mod.X` / 指针下标 `rawptr[X]` / `CPtr[X]` 等。
|
||||
存储类与限定符标记(`CExtern` / `CExport` / `CPtr` 等)不算类名,
|
||||
由 `_MARKER_ANNOT_NAMES` 过滤;返回的是**短名**,调用方再解析成
|
||||
`Gen.structs` 真实键。
|
||||
`Gen.structs` 真实键。旧联合注解一律 fail-fast。
|
||||
"""
|
||||
if annotation is None:
|
||||
return None
|
||||
if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
_left: str | None = self._AnnotationStructName(annotation.left)
|
||||
if _left:
|
||||
return _left
|
||||
return self._AnnotationStructName(annotation.right)
|
||||
Line: int = getattr(annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
if isinstance(annotation, ast.Subscript):
|
||||
_base: ast.AST = annotation.value
|
||||
_bn: str = ''
|
||||
@@ -1276,7 +1282,7 @@ class ImportHandle(BaseHandle):
|
||||
_bn = _base.id
|
||||
elif isinstance(_base, ast.Attribute):
|
||||
_bn = _base.attr
|
||||
if _bn in ('rawptr', 'CPtr', 'CArrayPtr'):
|
||||
if _bn in _PTR_SUBSCRIPT_NAMES:
|
||||
_sl: ast.AST = annotation.slice
|
||||
if hasattr(ast, 'Index') and isinstance(_sl, ast.Index):
|
||||
_sl = _sl.value
|
||||
@@ -1323,7 +1329,7 @@ class ImportHandle(BaseHandle):
|
||||
is_string_val = False
|
||||
TypeInfo = None
|
||||
# 【跨模块模块级变量的**类登记**】`CTypeInfo.FromNode` 对
|
||||
# `X | CPtr` / `rawptr[X]` 注解只给出指针占位(rawptr[X] 折叠成 i8*),
|
||||
# `CPtr[X]` / `rawptr[X]` 注解只给出指针占位(rawptr[X] 折叠成 i8*),
|
||||
# 且本函数**只算类型、不登记变量类** → 消费侧 `Mod.Var.Field` 链在
|
||||
# `_get_var_class` 里解析为空:StructGenMixin.vp:139 "属性访问未能解析出
|
||||
# 目标类型/成员"、CallGenLeafKit.vp:589 / ClassGenVTable.vp:99 误报
|
||||
@@ -1424,11 +1430,12 @@ class ImportHandle(BaseHandle):
|
||||
if existing_sym and isinstance(existing_sym, CTypeInfo) and existing_sym.IsTypedef and existing_sym.OriginalType:
|
||||
return
|
||||
if Node.value:
|
||||
ValueTypeInfo = None
|
||||
if isinstance(Node.value, ast.BinOp) and isinstance(Node.value.op, ast.BitOr):
|
||||
ValueTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.value)
|
||||
else:
|
||||
ValueTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.value)
|
||||
Line: int = getattr(Node.value, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
ValueTypeInfo = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.value)
|
||||
if isinstance(ValueTypeInfo, CTypeInfo) and (ValueTypeInfo.BaseType or ValueTypeInfo.PtrCount > 0):
|
||||
# GetCTypeInfo 对 CInt 等 Attribute 返回的 BaseType 可能是 CType 基类实例
|
||||
# (而非具体子类如 CInt),导致 _resolve_typedef_int_width 无法解析位宽。
|
||||
@@ -1442,7 +1449,7 @@ class ImportHandle(BaseHandle):
|
||||
ValueTypeInfo.OriginalType = type_name
|
||||
ValueTypeInfo.IsTypedef = True
|
||||
ValueTypeInfo.Name = VarName
|
||||
# 设置 OriginalType,确保 _resolve_name 能解析(MergeTypes 不为 BinOp 结果设置 OriginalType)
|
||||
# 设置 OriginalType,确保 _resolve_name 能解析(类型解析入口不保证设置 OriginalType)
|
||||
if not ValueTypeInfo.OriginalType:
|
||||
OriginalCopy: CTypeInfo = ValueTypeInfo.Copy()
|
||||
OriginalCopy.IsTypedef = False
|
||||
@@ -1621,15 +1628,18 @@ class ImportHandle(BaseHandle):
|
||||
if llvm_str:
|
||||
return llvm_str
|
||||
elif isinstance(value_node, ast.BinOp) and isinstance(value_node.op, ast.BitOr):
|
||||
left = self._ExtractTypedefOriginalType(value_node.left)
|
||||
right = self._ExtractTypedefOriginalType(value_node.right)
|
||||
parts = []
|
||||
if left:
|
||||
parts.append(left)
|
||||
if right:
|
||||
parts.append(right)
|
||||
if parts:
|
||||
return '|'.join(parts)
|
||||
Line: int = getattr(value_node, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
elif isinstance(value_node, ast.Subscript):
|
||||
base_node: ast.AST = value_node.value
|
||||
base_name: str | None = (
|
||||
base_node.id if isinstance(base_node, ast.Name)
|
||||
else (base_node.attr if isinstance(base_node, ast.Attribute) else None))
|
||||
if base_name in _PTR_SUBSCRIPT_NAMES:
|
||||
return self._ExtractTypedefOriginalType(value_node.slice)
|
||||
return self._ExtractTypedefOriginalType(base_node)
|
||||
elif isinstance(value_node, ast.Call):
|
||||
if isinstance(value_node.func, ast.Name):
|
||||
llvm_str = CTypeRegistry.NameToLLVM(value_node.func.id)
|
||||
@@ -1656,6 +1666,14 @@ class ImportHandle(BaseHandle):
|
||||
self.Trans.SymbolTable.insert(FullName, info)
|
||||
|
||||
def _check_annotation_for_state(self, annotation: ast.AST) -> bool:
|
||||
Markers: tuple[str, ...] = tuple(getattr(annotation, 'Markers', None) or ())
|
||||
if 'export' in Markers or 'extern' in Markers or 'state' in Markers:
|
||||
return True
|
||||
# 兼容旧 AST:修饰词曾是联合注解的一翼 / 裸标记名。
|
||||
if isinstance(annotation, ast.Subscript):
|
||||
return (AnnotationContainsName(annotation.value, 'CExport') or
|
||||
AnnotationContainsName(annotation.value, 'CExtern') or
|
||||
AnnotationContainsName(annotation.value, 'State'))
|
||||
return (AnnotationContainsName(annotation, 'CExport') or
|
||||
AnnotationContainsName(annotation, 'CExtern') or
|
||||
AnnotationContainsName(annotation, 'State'))
|
||||
@@ -1715,7 +1733,7 @@ class ImportHandle(BaseHandle):
|
||||
try:
|
||||
ReturnTypeInfo = self.ResolveAnnotationType(Node.returns)
|
||||
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
|
||||
# `str | CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),不能压平。
|
||||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
|
||||
if ReturnTypeInfo and ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1:
|
||||
ReturnTypeInfo = CTypeInfo()
|
||||
ReturnTypeInfo.BaseType = TypeSystem.CChar()
|
||||
@@ -1746,11 +1764,23 @@ class ImportHandle(BaseHandle):
|
||||
elif isinstance(Node.returns, ast.Attribute):
|
||||
RetAnnName = Node.returns.attr
|
||||
elif isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
|
||||
left = Node.returns.left
|
||||
if isinstance(left, ast.Name):
|
||||
RetAnnName = left.id
|
||||
elif isinstance(left, ast.Attribute):
|
||||
RetAnnName = left.attr
|
||||
Line: int = getattr(Node.returns, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
elif isinstance(Node.returns, ast.Subscript):
|
||||
_ret_base: ast.AST = Node.returns.value
|
||||
_ret_bn: str = (
|
||||
_ret_base.id if isinstance(_ret_base, ast.Name)
|
||||
else (_ret_base.attr if isinstance(_ret_base, ast.Attribute) else ''))
|
||||
if _ret_bn in _PTR_SUBSCRIPT_NAMES:
|
||||
_ret_sl: ast.AST = Node.returns.slice
|
||||
if hasattr(ast, 'Index') and isinstance(_ret_sl, ast.Index):
|
||||
_ret_sl = _ret_sl.value
|
||||
_ret_bn = (
|
||||
_ret_sl.id if isinstance(_ret_sl, ast.Name)
|
||||
else (_ret_sl.attr if isinstance(_ret_sl, ast.Attribute) else ''))
|
||||
RetAnnName = _ret_bn or None
|
||||
if RetAnnName and RetAnnName in Gen.structs:
|
||||
ReturnType = ir.PointerType(Gen.structs[RetAnnName])
|
||||
elif IsPtr or RetAnnName:
|
||||
@@ -1820,7 +1850,7 @@ class ImportHandle(BaseHandle):
|
||||
ParamIsPtr = True
|
||||
ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1)
|
||||
# 仅当指针层数 <=1 时才压平为 i8*(裸 str/bytes)。
|
||||
# `str | CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),
|
||||
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,
|
||||
# 不能压平,否则形参类型错误导致 _adjust_args 多 load 一层崩溃。
|
||||
if (ParamTypeInfo.IsStr and ParamTypeInfo.PtrCount <= 1) or (isinstance(Arg.annotation, ast.Name) and Arg.annotation.id in ('str', 'bytes')):
|
||||
ParamTypeInfo = CTypeInfo()
|
||||
@@ -1848,7 +1878,23 @@ class ImportHandle(BaseHandle):
|
||||
elif isinstance(Arg.annotation, ast.Attribute):
|
||||
AnnName = Arg.annotation.attr
|
||||
elif isinstance(Arg.annotation, ast.BinOp) and isinstance(Arg.annotation.op, ast.BitOr):
|
||||
AnnName = ExtractTypeNameFromBinOp(Arg.annotation)
|
||||
Line: int = getattr(Arg.annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
elif isinstance(Arg.annotation, ast.Subscript):
|
||||
_arg_base: ast.AST = Arg.annotation.value
|
||||
_arg_bn: str = (
|
||||
_arg_base.id if isinstance(_arg_base, ast.Name)
|
||||
else (_arg_base.attr if isinstance(_arg_base, ast.Attribute) else ''))
|
||||
if _arg_bn in _PTR_SUBSCRIPT_NAMES:
|
||||
_arg_sl: ast.AST = Arg.annotation.slice
|
||||
if hasattr(ast, 'Index') and isinstance(_arg_sl, ast.Index):
|
||||
_arg_sl = _arg_sl.value
|
||||
_arg_bn = (
|
||||
_arg_sl.id if isinstance(_arg_sl, ast.Name)
|
||||
else (_arg_sl.attr if isinstance(_arg_sl, ast.Attribute) else ''))
|
||||
AnnName = _arg_bn or None
|
||||
if AnnName and AnnName in Gen.structs:
|
||||
ParamType = ir.PointerType(Gen.structs[AnnName])
|
||||
else:
|
||||
@@ -2116,7 +2162,7 @@ class ImportHandle(BaseHandle):
|
||||
RenumTypeNode.IsRenum = True
|
||||
RenumTypeNode.IsEnum = True # 兼容 IsEnum 检查
|
||||
# REnum 在内存布局上是 struct,必须设置 IsStruct=True 才能让
|
||||
# HandlesTypeMerge 的 CPtr 吸收逻辑生效(REnumType | CPtr = REnumType*)
|
||||
# HandlesTypeMerge 的 CPtr 吸收逻辑生效(CPtr[REnumType] = REnumType*)
|
||||
RenumTypeNode.IsStruct = True
|
||||
if module_name:
|
||||
FullName = f"{module_name}.{ClassName}"
|
||||
@@ -2364,6 +2410,11 @@ class ImportHandle(BaseHandle):
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
if item.target.id in ('__provides__', '__requires__', '__require_must__'):
|
||||
continue
|
||||
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
|
||||
Line: int = getattr(item.annotation, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
parsed = self.CollectAnnAssignMember(item, Gen)
|
||||
if parsed:
|
||||
VarName, MemberType, TypeInfo = parsed
|
||||
@@ -2379,34 +2430,16 @@ class ImportHandle(BaseHandle):
|
||||
if VarName not in {m[0] for m in Gen.class_members[ClassName]}:
|
||||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||||
Gen.class_member_bitfields[ClassName][VarName] = 0
|
||||
# 与 HandlesClassDef 对齐:联合类型字段(如 `list[str] | CPtr`)
|
||||
# 记录泛型特化名到 class_member_element_class。否则跨模块 import
|
||||
# 的类(如 TypeGenBase.CTypedefNames)缺此记录,_HandleLenLlvm
|
||||
# 与 HandlesClassDef 对齐:指针/容器下标字段(`CPtr[list[str]]` /
|
||||
# `rawptr[GSList[X]]` / `list[X]`)记录泛型特化名到
|
||||
# class_member_element_class。否则跨模块 import 的类
|
||||
# (如 TypeGenBase.CTypedefNames)缺此记录,_HandleLenLlvm
|
||||
# 无法识别字段为 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 = 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:
|
||||
if ClassName not in Gen.class_member_element_class:
|
||||
Gen.class_member_element_class[ClassName] = {}
|
||||
Gen.class_member_element_class[ClassName][VarName] = element_class
|
||||
elif (isinstance(MemberType, ir.PointerType)
|
||||
and isinstance(MemberType.pointee, ir.IdentifiedStructType)
|
||||
and isinstance(item.annotation, ast.BinOp)
|
||||
and isinstance(item.annotation.op, ast.BitOr)):
|
||||
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] = {}
|
||||
Gen.class_member_element_class[ClassName][VarName] = spec_in_anno
|
||||
# 旧联合写法(`list[str] | CPtr`)已不再产生;见循环入口 fail-fast。
|
||||
# Subscript 容器字段(list[X] / rawptr[list[X]],如 includes/ast
|
||||
# 的 Call.args / Import.names: rawptr[list[rawptr[AST]]]):非 BinOp
|
||||
# 联合,上面两分支不命中 → 容器身份丢失 → 字段方法调用(get/len…)
|
||||
# 分派失败报 "Undefined method 'get' in class 'rawptr'"(Converter.vp)。
|
||||
# 的 Call.args / Import.names: rawptr[list[rawptr[AST]]]):
|
||||
# 容器身份丢失会导致字段方法调用(get/len…)分派失败并报
|
||||
# "Undefined method 'get' in class 'rawptr'"(Converter.vp)。
|
||||
# 用与特化生成端同源的 _resolve_type_arg_str 构造 element_class,
|
||||
# 键名与 Gen.structs 中 list 特化名保持一致。
|
||||
if isinstance(item.annotation, ast.Subscript):
|
||||
@@ -2416,7 +2449,7 @@ class ImportHandle(BaseHandle):
|
||||
_elem_slice_s: ast.AST | None = None
|
||||
if _subname_s == 'list':
|
||||
_elem_slice_s = _ann_sub_s.slice
|
||||
elif _subname_s == 'rawptr':
|
||||
elif _subname_s in _PTR_SUBSCRIPT_NAMES:
|
||||
_slice_s: ast.AST = _ann_sub_s.slice
|
||||
if isinstance(_slice_s, ast.Subscript):
|
||||
# rawptr[泛型容器](rawptr[list[X]] / rawptr[GSList[Param]]):
|
||||
@@ -2443,8 +2476,8 @@ class ImportHandle(BaseHandle):
|
||||
else:
|
||||
# rawptr[裸结构](如 rawptr[Token]):跨模块 stub 会把自引用/类内
|
||||
# 指针字段退化为 i8*,链式成员访问(a.b.c)需 element_class 恢复
|
||||
# struct 身份走 char*→struct cast。HEAD 态 `Token | CPtr` 联合
|
||||
# 由上方 BinOp 分支登记;rawptr 重构后此分支补齐(阻塞 A 根因)。
|
||||
# struct 身份走 char*→struct cast。指针统一为 Subscript
|
||||
# (`rawptr[Token]` / `CPtr[Token]`),由本分支登记。
|
||||
# 与 HandlesClassDef 的 rawptr 分支对称。
|
||||
_slc_name_s: str | None = None
|
||||
if isinstance(_slice_s, ast.Name):
|
||||
|
||||
@@ -130,6 +130,10 @@ class HandlesTypeMerge(BaseHandle):
|
||||
Info.DataVolatile = True
|
||||
Info.BaseType = TypeSystem.CVoid
|
||||
return Info
|
||||
if BuiltinCls == TypeSystem.State:
|
||||
Info.IsState = True
|
||||
Info.BaseType = TypeSystem.CVoid
|
||||
return Info
|
||||
if BuiltinCls in (TypeSystem.CInline, TypeSystem.CStatic,
|
||||
TypeSystem.CExtern, TypeSystem.CExport):
|
||||
Info.Storage = BuiltinCls()
|
||||
@@ -373,7 +377,7 @@ class HandlesTypeMerge(BaseHandle):
|
||||
|
||||
elif isinstance(Node, ast.Call):
|
||||
if isinstance(Node.func, ast.Name) and Node.func.id == 'callable':
|
||||
ReturnTypeInfo = self._GetCTypeInfoInternal(Node.args[0]) if Node.args else None
|
||||
ReturnTypeInfo = self.GetCTypeInfo(Node.args[0]) if Node.args else None
|
||||
if isinstance(ReturnTypeInfo, CTypeInfo):
|
||||
ReturnType = ReturnTypeInfo
|
||||
else:
|
||||
@@ -383,7 +387,7 @@ class HandlesTypeMerge(BaseHandle):
|
||||
ParamTypes = []
|
||||
ParamNames = []
|
||||
for kw in Node.keywords:
|
||||
ParamTypeInfo = self._GetCTypeInfoInternal(kw.value)
|
||||
ParamTypeInfo = self.GetCTypeInfo(kw.value)
|
||||
if not isinstance(ParamTypeInfo, CTypeInfo):
|
||||
ParamTypeInfo = self._MakeCTypeInfoFromName('int')
|
||||
ParamTypes.append(ParamTypeInfo)
|
||||
@@ -392,13 +396,13 @@ class HandlesTypeMerge(BaseHandle):
|
||||
for arg in Node.args[1:]:
|
||||
if isinstance(arg, ast.Tuple):
|
||||
for elt in arg.elts:
|
||||
ParamTypeInfo = self._GetCTypeInfoInternal(elt)
|
||||
ParamTypeInfo = self.GetCTypeInfo(elt)
|
||||
if not isinstance(ParamTypeInfo, CTypeInfo):
|
||||
ParamTypeInfo = self._MakeCTypeInfoFromName('int')
|
||||
ParamTypes.append(ParamTypeInfo)
|
||||
ParamNames.append('')
|
||||
else:
|
||||
ParamTypeInfo = self._GetCTypeInfoInternal(arg)
|
||||
ParamTypeInfo = self.GetCTypeInfo(arg)
|
||||
if not isinstance(ParamTypeInfo, CTypeInfo):
|
||||
ParamTypeInfo = self._MakeCTypeInfoFromName('int')
|
||||
ParamTypes.append(ParamTypeInfo)
|
||||
@@ -471,22 +475,59 @@ class HandlesTypeMerge(BaseHandle):
|
||||
return self._MakeVoidCTypeInfo()
|
||||
|
||||
def _ResolvePtrSubscript(self, Node: ast.Subscript) -> CTypeInfo:
|
||||
"""`CPtr[T]` / `rawptr[T]` → Ptr(T):struct 基类型吸收一层,其余逐层外包。"""
|
||||
"""`CPtr[T]` / `rawptr[T]` → Ptr(T):struct 基类型吸收一层,其余逐层外包。
|
||||
|
||||
嵌套指针下标(`CPtr[CPtr[X]]` / `rawptr[rawptr[X]]`)的内层已经是
|
||||
指针层,不能再被 struct 默认指针(Name 路径 PtrCount=1)吸收,
|
||||
否则两层会被折叠成一层。
|
||||
"""
|
||||
Inner: CTypeInfo = self.GetCTypeInfo(Node.slice)
|
||||
Result: CTypeInfo = Inner.Copy()
|
||||
if not Result.BaseType:
|
||||
Result.BaseType = TypeSystem.CVoid()
|
||||
if not (Result.IsStruct and Result.PtrCount > 0):
|
||||
_Slice: ast.AST = Node.slice
|
||||
_SliceIsPtr: bool = IsPtrSubscriptNode(_Slice, self.Trans.SymbolTable)
|
||||
if isinstance(_Slice, ast.Subscript):
|
||||
_SliceBase: ast.AST = _Slice.value
|
||||
_SliceName: str = ''
|
||||
if isinstance(_SliceBase, ast.Name):
|
||||
_SliceName = _SliceBase.id
|
||||
elif isinstance(_SliceBase, ast.Attribute):
|
||||
_SliceName = _SliceBase.attr
|
||||
if _SliceName in ('CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
|
||||
_SliceIsPtr = True
|
||||
if not (Result.IsStruct and Result.PtrCount > 0 and not _SliceIsPtr):
|
||||
Result.PtrCount += 1
|
||||
return Result
|
||||
|
||||
def _ResolveRefSubscript(self, Node: ast.Subscript, MarkerName: str) -> CTypeInfo:
|
||||
"""`CRef[T]` / `CTempRef[T]` / `CArrayPtr[T]` / `CAutoPtr[T]` → Ptr(T)。"""
|
||||
"""`CRef[T]` / `CTempRef[T]` / `CArrayPtr[T]` / `CAutoPtr[T]` → Ptr(T)。
|
||||
|
||||
- CRef / CTempRef 的取址模式('ref' / 'temp')对**已是指针**的实参原样传递,
|
||||
因此 T 是裸类引用(本语言以指针表示)时吸收其默认指针层,PtrCount 仍为 1;
|
||||
- CAutoPtr 无条件取址('always'),即使已是指针也再取一层;
|
||||
- CArrayPtr 表示"指向数组"的指针,裸类元素同样吸收默认指针层并置 IsArrayPtr。
|
||||
"""
|
||||
Inner: CTypeInfo = self.GetCTypeInfo(Node.slice)
|
||||
Result: CTypeInfo = Inner.Copy()
|
||||
if not Result.BaseType:
|
||||
Result.BaseType = TypeSystem.CVoid()
|
||||
Result.PtrCount += 1
|
||||
_Slice: ast.AST = Node.slice
|
||||
_SliceIsPtr: bool = IsPtrSubscriptNode(_Slice, self.Trans.SymbolTable)
|
||||
if isinstance(_Slice, ast.Subscript):
|
||||
_SliceBase: ast.AST = _Slice.value
|
||||
_SliceName: str = ''
|
||||
if isinstance(_SliceBase, ast.Name):
|
||||
_SliceName = _SliceBase.id
|
||||
elif isinstance(_SliceBase, ast.Attribute):
|
||||
_SliceName = _SliceBase.attr
|
||||
if _SliceName in ('CPtr', 'rawptr', 'CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
|
||||
_SliceIsPtr = True
|
||||
_AbsorbStructPtr: bool = (
|
||||
MarkerName != 'CAutoPtr'
|
||||
and Result.IsStruct and Result.PtrCount > 0 and not _SliceIsPtr)
|
||||
if not _AbsorbStructPtr:
|
||||
Result.PtrCount += 1
|
||||
if MarkerName == 'CArrayPtr':
|
||||
Result.IsArrayPtr = True
|
||||
return Result
|
||||
@@ -545,7 +586,7 @@ class HandlesTypeMerge(BaseHandle):
|
||||
ParamNames = []
|
||||
if isinstance(params_list, ast.List):
|
||||
for elt in params_list.elts:
|
||||
ParamTypeInfo = self._GetCTypeInfoInternal(elt)
|
||||
ParamTypeInfo = self.GetCTypeInfo(elt)
|
||||
if isinstance(ParamTypeInfo, CTypeInfo):
|
||||
ParamTypes.append(ParamTypeInfo)
|
||||
ParamNames.append('')
|
||||
@@ -555,7 +596,7 @@ class HandlesTypeMerge(BaseHandle):
|
||||
if not ParamTypes:
|
||||
ParamTypes.append(self._MakeCTypeInfoFromName('void'))
|
||||
ParamNames.append('')
|
||||
ReturnTypeInfo = self._GetCTypeInfoInternal(return_node)
|
||||
ReturnTypeInfo = self.GetCTypeInfo(return_node)
|
||||
if isinstance(ReturnTypeInfo, CTypeInfo):
|
||||
ReturnType = ReturnTypeInfo
|
||||
else:
|
||||
@@ -709,7 +750,7 @@ class HandlesTypeMerge(BaseHandle):
|
||||
ResultInfo = CTypeInfo()
|
||||
if IsListAnnotation(node):
|
||||
if not isinstance(slice_node, ast.Tuple):
|
||||
ElementType = self._GetCTypeInfoInternal(slice_node)
|
||||
ElementType = self.GetCTypeInfo(slice_node)
|
||||
if ElementType and isinstance(ElementType, CTypeInfo):
|
||||
ResultInfo.BaseType = ElementType.BaseType if ElementType.BaseType else TypeSystem.CVoid()
|
||||
ResultInfo.PtrCount = ElementType.PtrCount + 1
|
||||
@@ -720,7 +761,7 @@ class HandlesTypeMerge(BaseHandle):
|
||||
ResultInfo.BaseType = TypeSystem.CVoid()
|
||||
ResultInfo.PtrCount = 1
|
||||
elif isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1:
|
||||
ElementType = self._GetCTypeInfoInternal(slice_node.elts[0])
|
||||
ElementType = self.GetCTypeInfo(slice_node.elts[0])
|
||||
if ElementType and isinstance(ElementType, CTypeInfo):
|
||||
ResultInfo.BaseType = ElementType.BaseType if ElementType.BaseType else TypeSystem.CVoid()
|
||||
ResultInfo.PtrCount = ElementType.PtrCount
|
||||
|
||||
@@ -693,7 +693,7 @@ class BaseGenMixin:
|
||||
if packed and isinstance(existing, ir.IdentifiedStructType) and not existing.packed:
|
||||
existing.packed = True
|
||||
return existing
|
||||
if clean_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'Void', 'void'}:
|
||||
if clean_name in {'typedef', 'CType', 'CTypedef', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'Void', 'void'}:
|
||||
return ir.IntType(8)
|
||||
# typing.Any 是"任意类型"标记,应解析为 i8*(通用指针),
|
||||
# 而非创建为 opaque 结构体(否则包含 Any 字段的结构体会变成 unsized)。
|
||||
@@ -865,7 +865,7 @@ class BaseGenMixin:
|
||||
# 解决时序问题:_parse_llvm_declare 从 stub.ll 解析时 dict 可能尚未注册到 Gen.structs,
|
||||
# 但 SymbolTable 在 .pyi 解析阶段已就绪,可通过 is_struct 检查区分 class 和 typedef。
|
||||
_SPECIAL_TYPEDEFS: set[str] = {
|
||||
'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion',
|
||||
'typedef', 'CType', 'CTypedef', 'CEnum', 'CUnion',
|
||||
'CStruct', 'enum', 'REnum', 'renum',
|
||||
'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', 'type', 'CArray',
|
||||
}
|
||||
@@ -1431,26 +1431,43 @@ class BaseGenMixin:
|
||||
|
||||
@staticmethod
|
||||
def _AnnotationHasQualifier(Annotation: Any, AttrName: str) -> bool:
|
||||
"""注解子树里是否出现 `t.<AttrName>`(与 ViperC TypeGenErr.has_decorator_marker 同口径)。"""
|
||||
"""注解子树里是否带指定限定符(读取 AST 的 Markers 字段)。
|
||||
|
||||
AttrName 兼容旧书写名(CConst/CVolatile)与关键字名(const/volatile);
|
||||
修饰信息一律来自 `Markers`,不再匹配裸名/Attribute 文本。
|
||||
"""
|
||||
if Annotation is None:
|
||||
return False
|
||||
from lib.core.SymbolUtils import RejectTypeUnionAnnotation
|
||||
RejectTypeUnionAnnotation(Annotation)
|
||||
MarkerName: str = {
|
||||
'CConst': 'const', 'CVolatile': 'volatile',
|
||||
'const': 'const', 'volatile': 'volatile',
|
||||
}.get(AttrName, AttrName)
|
||||
for n in ast.walk(Annotation):
|
||||
if isinstance(n, ast.Attribute) and n.attr == AttrName:
|
||||
if MarkerName in (getattr(n, 'Markers', None) or ()):
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _AnnotationHasPointeeVolatile(Annotation: Any) -> bool:
|
||||
"""注解是否为 `rawptr[CVolatile | T]`(volatile 指针指向物,等价 C 的 volatile T*)。
|
||||
"""注解是否为「指向物 volatile」(`volatile T*` / `volatile rawptr[T]`)。
|
||||
|
||||
与 ViperC TypeGenErr.has_pointee_volatile_marker 同口径:只看 `rawptr[...]`
|
||||
的下标实参子树里有没有 CVolatile;多级指针(slice 仍是 Subscript)明确不支持。
|
||||
读取 AST 字段:`rawptr[...]` / `CPtr[...]` 节点自身的 Markers 含
|
||||
'volatile',或其下标子树的 Markers 含 'volatile'(多级指针不另行展开)。
|
||||
"""
|
||||
if not isinstance(Annotation, ast.Subscript):
|
||||
return False
|
||||
base: Any = Annotation.value
|
||||
if not isinstance(base, ast.Name) or base.id != 'rawptr':
|
||||
BaseName: str = ''
|
||||
if isinstance(base, ast.Name):
|
||||
BaseName = base.id
|
||||
elif isinstance(base, ast.Attribute):
|
||||
BaseName = base.attr
|
||||
if BaseName not in ('rawptr', 'CPtr'):
|
||||
return False
|
||||
if 'volatile' in (getattr(Annotation, 'Markers', None) or ()):
|
||||
return True
|
||||
return BaseGenMixin._AnnotationHasQualifier(Annotation.slice, 'CVolatile')
|
||||
|
||||
def RegisterVarQualifiers(self, Name: str, Info: Any, Annotation: Any,
|
||||
|
||||
@@ -276,28 +276,22 @@ class MemoryOpsMixin:
|
||||
形式(TPC 解析产物的共同点 = ast.Call 且 func 是**指针类型表达式**):
|
||||
- `CPtr(x)`
|
||||
- `rawptr[T](x)` / `CPtr[T](x)` / 裸名 `CPtr[T](x)`
|
||||
- `(T*)x` / `(T*)(x)` / `T*(x)`(含 `**` 两层;ExprParser 把三种写法统一
|
||||
产成 Call(func = `T | CPtr`))
|
||||
- `(T*)x` / `(T*)(x)` / `T*(x)`(含 `**` 两层;ExprParser 统一产成
|
||||
Call(func = `CPtr[T]` Subscript)
|
||||
- 裸 `rawptr(x)`(≡ CPtr)
|
||||
非 cast 调用(构造函数 / 普通函数,如 `MemBuddy(x)`、`list[X](...)`)不命中
|
||||
⇒ 仍按隐式转换规则判定。只判 func 节点形状,不做类型解析(不与 Gen 耦合)。
|
||||
|
||||
必要性:`includes/_list.vp:60` 的 `elem_ptr: T | CPtr = CPtr(地址)` 在
|
||||
`list[X*]` 特化下 T | CPtr = `X**`(T 本身是指针),而 `CPtr(...)` 的值是
|
||||
`i8*`——层数不同被判"隐式转换已禁止",与报错自己给的"如需转换请显式 cast
|
||||
(如 CPtr(...))"建议自相矛盾。显式 cast 一律放行后按 bitcast 重解释。
|
||||
`T1 | T2` 类型联合已禁止,故不再有 `Call(func=BinOp(BitOr))` 形态。
|
||||
"""
|
||||
if not isinstance(Node, ast.Call):
|
||||
return False
|
||||
Func: Any = Node.func
|
||||
from lib.core.SymbolUtils import (IsCPtrNode, IsPtrSubscriptNode,
|
||||
AnnotationContainsName)
|
||||
from lib.core.SymbolUtils import IsCPtrNode, IsPtrSubscriptNode
|
||||
if IsCPtrNode(Func) or IsPtrSubscriptNode(Func):
|
||||
return True
|
||||
if isinstance(Func, ast.Name) and Func.id in ('CPtr', 'rawptr'):
|
||||
if isinstance(Func, ast.Name) and Func.id == 'rawptr':
|
||||
return True
|
||||
if isinstance(Func, ast.BinOp) and isinstance(Func.op, ast.BitOr):
|
||||
return AnnotationContainsName(Func, 'CPtr')
|
||||
return False
|
||||
|
||||
def _ClassifyPtrImplicitConvert(self, Src: Any, Dst: Any,
|
||||
|
||||
@@ -13,6 +13,12 @@ from lib.core.VLogger import get_logger as _vlog
|
||||
# (profile:`_TypedPointerType.__init__` 3,750,259 次中有一份来自这里)。
|
||||
_I8_PTR: ir.Type = ir.PointerType(ir.IntType(8))
|
||||
|
||||
# 指针/引用下标包装名(`CPtr[T]` / `rawptr[T]` / `CRef[T]` ...):
|
||||
# 新表示下指针/引用统一是 Subscript,不再是 `T | CPtr` 联合。
|
||||
_PTR_SUBSCRIPT_NAMES: frozenset[str] = frozenset({
|
||||
'CPtr', 'rawptr', 'CArrayPtr', 'CRef', 'CTempRef', 'CAutoPtr',
|
||||
})
|
||||
|
||||
# `_strip_unnecessary_quotes` 识别 LLVM IR 裸标识符 / 给引用名去引号用的**预编译**正则
|
||||
# (性能:该函数对整段 IR 文本做替换,字面量正则预编译避免 re 缓存查找与编译开销)。
|
||||
_RE_IR_IDENTIFIER: re.Pattern[str] = re.compile(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$')
|
||||
@@ -477,12 +483,24 @@ class StructGenMixin:
|
||||
ClassTypeName: str = annotation.attr
|
||||
if ClassTypeName in self.structs:
|
||||
ResolvedType = self.structs[ClassTypeName]
|
||||
elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
|
||||
left: Any = annotation.left
|
||||
if isinstance(left, ast.Attribute):
|
||||
ClassTypeName: str = left.attr
|
||||
if ClassTypeName in self.structs:
|
||||
ResolvedType = self.structs[ClassTypeName]
|
||||
elif isinstance(annotation, ast.Subscript):
|
||||
# 指针/引用下标:逐层拆到内层被指类型(CPtr[X] / rawptr[X] / ...)。
|
||||
inner: Any = annotation.slice
|
||||
while isinstance(inner, ast.Subscript):
|
||||
_base: Any = inner.value
|
||||
_base_name: str = (
|
||||
_base.id if isinstance(_base, ast.Name)
|
||||
else (_base.attr if isinstance(_base, ast.Attribute) else ''))
|
||||
if _base_name not in _PTR_SUBSCRIPT_NAMES:
|
||||
break
|
||||
inner = inner.slice
|
||||
ClassTypeName = ''
|
||||
if isinstance(inner, ast.Attribute):
|
||||
ClassTypeName = inner.attr
|
||||
elif isinstance(inner, ast.Name):
|
||||
ClassTypeName = inner.id
|
||||
if ClassTypeName in self.structs:
|
||||
ResolvedType = self.structs[ClassTypeName]
|
||||
|
||||
if ResolvedType:
|
||||
self.class_members[ClassName][i] = (member_name, ResolvedType)
|
||||
|
||||
@@ -226,7 +226,7 @@ class TypeConvertMixin:
|
||||
return source_sha1
|
||||
|
||||
def _resolve_typedef(self, type_name: str) -> str:
|
||||
if type_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'CPtr'}:
|
||||
if type_name in {'typedef', 'CTypedef', 'CType', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'CPtr'}:
|
||||
return type_name
|
||||
if type_name == 'Callable':
|
||||
return 'Callable'
|
||||
@@ -361,14 +361,14 @@ class TypeConvertMixin:
|
||||
_is_ptr_td = True
|
||||
except Exception:
|
||||
_is_ptr_td = False
|
||||
if not _is_ptr_td and _sub_base in ('CPtr', 'CPtr', 'CPtr'):
|
||||
if not _is_ptr_td and _sub_base in ('CPtr', 'rawptr', 'CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
|
||||
_is_ptr_td = True
|
||||
if _is_ptr_td and _sub_arg:
|
||||
_sub_inner: ir.Type = self._type_str_to_llvm(_sub_arg, True)
|
||||
if IsPtr:
|
||||
return ir.PointerType(_sub_inner)
|
||||
return _sub_inner
|
||||
if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}:
|
||||
if type_str in {'typedef', 'CTypedef', 'CType', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}:
|
||||
result: ir.Type
|
||||
if IsPtr:
|
||||
result = ir.IntType(8).as_pointer()
|
||||
@@ -441,11 +441,11 @@ class TypeConvertMixin:
|
||||
if elem_types:
|
||||
return ir.LiteralStructType(elem_types)
|
||||
return ir.IntType(32)
|
||||
if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}:
|
||||
if type_str in {'typedef', 'CTypedef', 'CType', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}:
|
||||
return ir.IntType(32)
|
||||
if type_str.startswith('%'):
|
||||
stripped: str = type_str[1:]
|
||||
if stripped in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}:
|
||||
if stripped in {'typedef', 'CTypedef', 'CType', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}:
|
||||
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
|
||||
basic_stripped: ir.Type | None = self._basic_type_to_llvm(stripped)
|
||||
if basic_stripped is not None:
|
||||
|
||||
+23
-27
@@ -26,11 +26,8 @@ from lib.core import TypeSystem as _t
|
||||
from lib.core.TypeSystem import CTypeRegistry
|
||||
|
||||
|
||||
# typedef 值位置的类型限定符标记:它们自身不是类型(名下有 const/volatile 语义,
|
||||
# 由注解解析器累积),在 typedef 值里只修饰 `|` 另一侧。历史写法
|
||||
# `CConst | char | CPtr` 恰好被 `char` 一侧掩盖;新语法 `const str`
|
||||
# (= `CConst | str`)暴露了这一点,故显式判为"无类型信息"。
|
||||
_TYPEDEF_VALUE_QUALIFIERS: frozenset[str] = frozenset({'CConst', 'CVolatile'})
|
||||
# 注:const/volatile 等修饰已迁到注解节点 Markers 字段;typedef 值文本解析
|
||||
# 不再内置"限定符标记名"白名单(旧 `CConst | ...` 联合语法已禁止)。
|
||||
|
||||
|
||||
class TypeNameUnresolvedError(NameError):
|
||||
@@ -173,7 +170,7 @@ class LLVMTypeMapper:
|
||||
result: str = self.get_llvm_type_str(annotation_node)
|
||||
if not result:
|
||||
result = 'i8*'
|
||||
if result == 'i32' and isinstance(annotation_node, (ast.Subscript, ast.BinOp)):
|
||||
if result == 'i32' and isinstance(annotation_node, ast.Subscript):
|
||||
_text: str
|
||||
try:
|
||||
_text = ast.unparse(annotation_node)
|
||||
@@ -211,6 +208,11 @@ class LLVMTypeMapper:
|
||||
_nm: str = (_bt if isinstance(_bt, str)
|
||||
else CTypeHelper.GetCName(_bt) if isinstance(_bt, type)
|
||||
else type(_bt).__name__)
|
||||
if _nm == 'CVoid':
|
||||
_nm = 'void'
|
||||
if _nm in ('CPtr', 'CArrayPtr', 'CAutoPtr'):
|
||||
# 通用指针类:C 类型串用 void *(不是 'CPtr *')
|
||||
return 'void *'
|
||||
if _nm and _nm != 'CType':
|
||||
return _nm + (' *' * (_binfo.PtrCount or 0))
|
||||
return ''
|
||||
@@ -218,13 +220,10 @@ class LLVMTypeMapper:
|
||||
if isinstance(node.value, ast.Name) :
|
||||
# 直接判断属性名是否为 CPtr(消除对 CName=='*' 的依赖)
|
||||
if node.attr == 'CPtr':
|
||||
return 'ptr'
|
||||
if node.attr in _TYPEDEF_VALUE_QUALIFIERS:
|
||||
# 类型限定符标记(const/volatile)本身不是类型
|
||||
return ''
|
||||
return 'void *'
|
||||
CName: str | None = CTypeHelper.GetCName(node.attr)
|
||||
if CName == 'CPtr':
|
||||
return 'ptr'
|
||||
return 'void *'
|
||||
if CName:
|
||||
return CName
|
||||
return ''
|
||||
@@ -311,6 +310,10 @@ class LLVMTypeMapper:
|
||||
}
|
||||
if node.id in id_map:
|
||||
return id_map[node.id]
|
||||
# CRef / CTempRef 非真实类(仅注解语法标记):裸用等价 void*,
|
||||
# 与 TypeAnnotationResolver._from_node_name 同口径。
|
||||
if node.id in ('CRef', 'CTempRef'):
|
||||
return 'i8*'
|
||||
# 通过 BuiltinTypeMap 解析 VOIDPTR、INTPTR 等指针别名
|
||||
builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(node.id)
|
||||
if builtin_entry:
|
||||
@@ -378,18 +381,6 @@ class LLVMTypeMapper:
|
||||
builtin_llvm: str = self._ctype_to_llvm_str(builtin_info)
|
||||
if builtin_llvm:
|
||||
return builtin_llvm
|
||||
# 存储类 / 类型限定符标记(CExport/CExtern/CStatic/CInline/CConst/
|
||||
# CVolatile/State 等,均以 `from t import ...` 裸名出现):自身不是类型,
|
||||
# 只作标记 ⇒ 贡献空串。与 _resolve_attribute 的 marker 分支、
|
||||
# TypeAnnotationResolver._ResolveNameNode 的 STORAGE_CLASS/TYPE_QUALIFIER
|
||||
# 判定同口径。
|
||||
_marker_cls: object = getattr(_t, node.id, None)
|
||||
if (isinstance(_marker_cls, type) and _marker_cls is not _t.CType
|
||||
and issubclass(_marker_cls, _t.CType)):
|
||||
_pos_tags: object = getattr(_marker_cls, 'position', None) or ()
|
||||
if _t.CType.BASE not in _pos_tags and (
|
||||
_t.CType.STORAGE_CLASS in _pos_tags or _t.CType.TYPE_QUALIFIER in _pos_tags):
|
||||
return ''
|
||||
# fail-fast:类型信息缺失不再静默退化成 i32
|
||||
_node_line: object = getattr(node, 'lineno', None)
|
||||
_node_col: object = getattr(node, 'col_offset', None)
|
||||
@@ -414,13 +405,18 @@ class LLVMTypeMapper:
|
||||
llvm_str: str | None = CTypeRegistry.NameToLLVM(attr_name)
|
||||
if llvm_str is not None:
|
||||
return llvm_str
|
||||
if attr_name in ('CState', 'CDefine', 'CTypedef', 'CExtern', 'CStatic', 'CConst', 'State'):
|
||||
return ''
|
||||
if attr_name in ('CCharPtr', 'CIntPtr', 'CVoidPtr', 'CArrayPtr'):
|
||||
return 'i8*'
|
||||
if attr_name == 'CVoidPtr':
|
||||
return 'i8*'
|
||||
if attr_name and attr_name[0].isupper() and attr_name not in CTypeRegistry._name_to_class:
|
||||
# 旧标记名不是类型(修饰信息由注解 Markers 承载):不得物化为结构体。
|
||||
if attr_name in ('CTypedef', 'CState'):
|
||||
return ''
|
||||
_attr_cls: object = getattr(_t, attr_name, None)
|
||||
if isinstance(_attr_cls, type) and issubclass(_attr_cls, _t.CType):
|
||||
_pos_tags: object = getattr(_attr_cls, 'position', None) or ()
|
||||
if _t.CType.BASE not in _pos_tags and (
|
||||
_t.CType.STORAGE_CLASS in _pos_tags or _t.CType.TYPE_QUALIFIER in _pos_tags):
|
||||
return ''
|
||||
return f'%struct.{attr_name}*'
|
||||
if attr_name and attr_name not in CTypeRegistry._name_to_class:
|
||||
return f'%struct.{attr_name}*'
|
||||
|
||||
@@ -125,7 +125,13 @@ class TypeResolver:
|
||||
def _resolve_ctypedef_typedef(self, td: TypedefSymbolData):
|
||||
"""解析 CTypedef 注解"""
|
||||
base_type_name: str | None = self._find_base_type(td.annotation)
|
||||
_TYPE_QUALIFIERS: frozenset[str] = frozenset({'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'})
|
||||
# 指针/引用下标包装名也视为"修饰符":具体被指类型交给 _resolve_typedef_from_value
|
||||
# 的 Subscript 分支解析(新 AST 中指针是 Subscript,不再是 `T | CPtr`)。
|
||||
_TYPE_QUALIFIERS: frozenset[str] = frozenset({
|
||||
'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern',
|
||||
'CDefine', 'CPostdefinition', 'ptr',
|
||||
'CPtr', 'rawptr', 'CArrayPtr', 'CRef', 'CTempRef', 'CAutoPtr',
|
||||
})
|
||||
|
||||
if base_type_name == 'Callable':
|
||||
original_type: CTypeInfo = CTypeInfo()
|
||||
@@ -166,7 +172,10 @@ class TypeResolver:
|
||||
return
|
||||
|
||||
value_base_type: str | None = self._find_base_type(td.value)
|
||||
_PTR_MODIFIERS: frozenset[str] = frozenset({'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'})
|
||||
_PTR_MODIFIERS: frozenset[str] = frozenset({
|
||||
'CPtr', 'rawptr', 'CArrayPtr', 'CRef', 'CTempRef', 'CAutoPtr',
|
||||
'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern',
|
||||
})
|
||||
|
||||
# 裸 CPtr(无 `[T]` 下标):_find_base_type 把 node.attr == 'CPtr'
|
||||
# 归一化为指针标记 'ptr'(拼写与 _PTR_MODIFIERS 的 'CPtr' 不一致 ⇒ 下方守卫命不中),
|
||||
@@ -319,7 +328,14 @@ class TypeResolver:
|
||||
return 'ptr'
|
||||
return node.attr
|
||||
elif isinstance(node, ast.Subscript):
|
||||
if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and node.value.attr == 'Callable':
|
||||
# 新表示:指针是 Subscript,base 名即标记名(CPtr[T] / rawptr[T] / ...)。
|
||||
_base: ast.AST = node.value
|
||||
_base_name: str | None = (
|
||||
_base.id if isinstance(_base, ast.Name)
|
||||
else (_base.attr if isinstance(_base, ast.Attribute) else None))
|
||||
if _base_name in ('CPtr', 'rawptr', 'CArrayPtr', 'CRef', 'CTempRef', 'CAutoPtr'):
|
||||
return _base_name
|
||||
if _base_name == 'Callable':
|
||||
return 'Callable'
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
Line: int = getattr(node, 'lineno', 0) or 0
|
||||
|
||||
+160
-191
@@ -1780,31 +1780,25 @@ def DefineIntSignednessOf(BaseType: object | None) -> bool | None:
|
||||
return None
|
||||
|
||||
|
||||
# CDefine 注解里参与"类型"判定的 t 标记(联合写法 `T | CDefine`、`T | State` 等):
|
||||
# 它们不是类型本身,取"声明类型"时必须跳过。
|
||||
_DEFINE_TYPE_MARKER_NAMES: frozenset[str] = frozenset({
|
||||
'CDefine', 'State', 'CExport', 'CExtern', 'CStatic', 'CTypedef',
|
||||
})
|
||||
# 无类型 define 的注解占位名(Parser 写入 `Name('CDefine').Markers=('define',)`):
|
||||
# 它不是类型,取"声明类型"时跳过。修饰信息一律读 Markers 字段。
|
||||
_DEFINE_PLACEHOLDER_NAME: str = 'CDefine'
|
||||
|
||||
|
||||
def _FirstTypeNameInAnnotation(node: object) -> str | None:
|
||||
"""从注解 AST 中取**第一个真正的类型名**(跳过 CDefine/State 等标记)。
|
||||
"""从注解 AST 中取**第一个真正的类型名**(修饰词由 Markers 承载)。
|
||||
|
||||
`DWORD | CDefine` → 'DWORD';`HANDLE | State` → 'HANDLE'。
|
||||
`define X: int = 1` → 'int'(int 节点 Markers 含 'define');
|
||||
无类型 `define X = 1` → None(占位名 CDefine)。
|
||||
"""
|
||||
if node is None:
|
||||
return None
|
||||
if isinstance(node, ast.Name):
|
||||
nm: str = node.id
|
||||
return None if nm in _DEFINE_TYPE_MARKER_NAMES else nm
|
||||
return None if node.id == _DEFINE_PLACEHOLDER_NAME else node.id
|
||||
if isinstance(node, ast.Attribute):
|
||||
at: str = node.attr
|
||||
return None if at in _DEFINE_TYPE_MARKER_NAMES else at
|
||||
if isinstance(node, ast.BinOp):
|
||||
left: str | None = _FirstTypeNameInAnnotation(node.left)
|
||||
if left is not None:
|
||||
return left
|
||||
return _FirstTypeNameInAnnotation(node.right)
|
||||
return node.attr
|
||||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
RejectTypeUnionAnnotation(node)
|
||||
if isinstance(node, ast.Tuple):
|
||||
for elt in node.elts:
|
||||
found: str | None = _FirstTypeNameInAnnotation(elt)
|
||||
@@ -2138,35 +2132,27 @@ def RequireNameDefined(Gen: object, Trans: object, Node: object, Name: str) -> N
|
||||
)
|
||||
|
||||
|
||||
# 类型注解中允许出现在 `|` 一侧的内建修饰标记。除此之外的任何 `T1 | T2`
|
||||
# 都视为「类型联合」并直接拒绝:类型注解只能是单一类型。
|
||||
_UNION_MARKER_NAMES: frozenset[str] = frozenset({
|
||||
'CConst', 'CVolatile', 'CExport', 'CExtern', 'CStatic', 'CInline', 'State',
|
||||
'CDefine', 'CTypedef', 'CPtr', 'CArrayPtr', 'CAutoPtr', 'CRef', 'CTempRef',
|
||||
'BigEndian', 'LittleEndian', 'Bit',
|
||||
# 注解修饰标记的旧书写名 → AST 字段 Markers 中的值。类型解析入口只认
|
||||
# Markers / ByteOrder / BitWidth 字段;任何 `T1 | T2` 联合一律 fail-fast。
|
||||
_ANNOTATION_MARKER_ALIASES: dict[str, str] = {
|
||||
'CConst': 'const', 'CVolatile': 'volatile', 'CStatic': 'static',
|
||||
'CExport': 'export', 'CExtern': 'extern', 'CInline': 'inline',
|
||||
'State': 'state', 'CDefine': 'define', 'CTypedef': 'typedef',
|
||||
}
|
||||
|
||||
# 指针/引用下标的 base 名:注解里出现这些名字即表示"指针层"(等价旧 CPtr 标记)。
|
||||
_POINTER_SUBSCRIPT_NAMES: frozenset[str] = frozenset({
|
||||
'CPtr', 'rawptr', 'CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr',
|
||||
})
|
||||
|
||||
|
||||
def _IsUnionMarkerNode(node: ast.AST) -> bool:
|
||||
"""节点是否为内建修饰标记(裸名、attr.* 或带调用括号的标记)。"""
|
||||
if isinstance(node, ast.Name):
|
||||
return node.id in _UNION_MARKER_NAMES
|
||||
if isinstance(node, ast.Attribute):
|
||||
cur: ast.AST = node
|
||||
while isinstance(cur, ast.Attribute):
|
||||
cur = cur.value
|
||||
return isinstance(cur, ast.Name) and cur.id == 'attr'
|
||||
if isinstance(node, ast.Call):
|
||||
return _IsUnionMarkerNode(node.func)
|
||||
return False
|
||||
|
||||
|
||||
def _ContainsUnionMarker(node: ast.AST) -> bool:
|
||||
if _IsUnionMarkerNode(node):
|
||||
return True
|
||||
def RejectTypeUnionAnnotation(node: ast.AST | None) -> None:
|
||||
"""类型注解位置遇到 `T1 | T2` 立即 fail-fast(不再合并/解析)。"""
|
||||
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
return _ContainsUnionMarker(node.left) or _ContainsUnionMarker(node.right)
|
||||
return False
|
||||
Line: int = getattr(node, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
|
||||
|
||||
def AnnotationContainsMarker(node: ast.AST, MarkerName: str) -> bool:
|
||||
@@ -2176,8 +2162,7 @@ def AnnotationContainsMarker(node: ast.AST, MarkerName: str) -> bool:
|
||||
if isinstance(node, ast.Attribute):
|
||||
return node.attr == MarkerName
|
||||
if isinstance(node, ast.BinOp):
|
||||
return (AnnotationContainsMarker(node.left, MarkerName)
|
||||
or AnnotationContainsMarker(node.right, MarkerName))
|
||||
RejectTypeUnionAnnotation(node)
|
||||
if isinstance(node, ast.Call):
|
||||
if AnnotationContainsMarker(node.func, MarkerName):
|
||||
return True
|
||||
@@ -2303,15 +2288,6 @@ def IsListAnnotation(annotation: ast.expr) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def ExtractListFromBinOp(annotation: ast.expr) -> ast.Subscript | None:
|
||||
"""从 BinOp(BitOr) 注解中提取定长数组部分,如 CArray[i32] | 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:
|
||||
"""定长数组注解(CArray / rawarray / array)解析结果。
|
||||
|
||||
@@ -2327,21 +2303,15 @@ class ListAnnotationParseResult:
|
||||
|
||||
|
||||
def ParseListAnnotation(annotation: ast.expr) -> ListAnnotationParseResult | None:
|
||||
"""解析定长数组注解(CArray / rawarray / array),处理 CArray[type, count] /
|
||||
CArray[type] / BinOp(BitOr) 形式。
|
||||
"""解析定长数组注解(CArray / rawarray / array)。
|
||||
|
||||
自动处理 BinOp(BitOr) 包裹(如 CArray[i32, N] | CPtr)。
|
||||
接受 `CArray[type, count]` / `CArray[type]`;`T1 | T2` 联合直接 fail-fast。
|
||||
返回 None 表示不是定长数组注解(`list[...]` 也返回 None —— 它是堆上 STL 容器)。
|
||||
"""
|
||||
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):
|
||||
RejectTypeUnionAnnotation(annotation)
|
||||
if not IsListAnnotation(annotation):
|
||||
return None
|
||||
slice_node: ast.AST = list_node.slice
|
||||
slice_node: ast.AST = annotation.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] → 指针模式
|
||||
@@ -2440,38 +2410,29 @@ def FixedArrayKeywordAnnotationError(Annotation: ast.AST,
|
||||
|
||||
|
||||
def CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool:
|
||||
"""检测注解节点中是否包含 CInline"""
|
||||
"""注解节点的 Markers 是否含 'inline'(`CInline` 旧名不再按文本判断)。"""
|
||||
if annotation_node is None:
|
||||
return False
|
||||
if isinstance(annotation_node, ast.Attribute):
|
||||
if hasattr(annotation_node.value, 'id') and annotation_node.attr == 'CInline':
|
||||
RejectTypeUnionAnnotation(annotation_node)
|
||||
for node in ast.walk(annotation_node):
|
||||
if 'inline' in (getattr(node, 'Markers', None) or ()):
|
||||
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)。
|
||||
"""旧联合写法的残留入口:`T1 | T2` 一律 fail-fast(返回 None 不再作为语义)。
|
||||
|
||||
返回 Name.id 或 Attribute.attr,非 BinOp 返回 None。
|
||||
保留函数名仅为兼容既有导入;合法调用不会命中 BinOp。
|
||||
"""
|
||||
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
|
||||
RejectTypeUnionAnnotation(annotation)
|
||||
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) 递归)。
|
||||
"""递归在注解中查找结构体名(`T1 | T2` 联合直接 fail-fast)。
|
||||
|
||||
检查 Name.id、Constant.str、Attribute.attr 是否在 struct_names 中。
|
||||
支持泛型特化类型(如 GSList[Param]):特化名按**同一规则源**
|
||||
@@ -2497,6 +2458,9 @@ def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set,
|
||||
slice_node = slice_node.value
|
||||
elem_nodes: list[ast.AST] = (
|
||||
list(slice_node.elts) if isinstance(slice_node, ast.Tuple) else [slice_node])
|
||||
if IsListAnnotation(node) and elem_nodes:
|
||||
# 定长数组只有第一个元素是类型;其余是长度常量表达式
|
||||
elem_nodes = elem_nodes[:1]
|
||||
type_args: list[str] = [
|
||||
ResolveTypeArgStr(E, TCAliasMap, StructSha1Map) for E in elem_nodes]
|
||||
spec_name: str = base_name + '[' + ']['.join(type_args) + ']'
|
||||
@@ -2505,12 +2469,7 @@ def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set,
|
||||
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)
|
||||
RejectTypeUnionAnnotation(node)
|
||||
return None
|
||||
|
||||
|
||||
@@ -2530,16 +2489,46 @@ def FindStructNameInAnnotationWithContext(Node: ast.AST, Trans: object, Gen: obj
|
||||
|
||||
|
||||
def AnnotationContainsName(annotation: ast.AST, name: str) -> bool:
|
||||
"""检查注解中是否包含指定名称(支持 BinOp(BitOr) 递归)。
|
||||
"""注解中是否包含指定名称(同时读取 AST 修饰字段)。
|
||||
|
||||
同时检查 Attribute.attr 和 Name.id,比 ast.dump 字符串匹配更精确。
|
||||
- 修饰词(CConst/CVolatile/CStatic/CExport/CExtern/CInline/State/CDefine/
|
||||
CTypedef)按节点 `Markers` 字段判断,不再依赖裸名/属性名;
|
||||
- 指针/引用下标(CPtr/rawptr/CRef/CTempRef/CArrayPtr/CAutoPtr)递归到
|
||||
Subscript 的 base/slice,故查询 'CPtr' 时 rawptr[X] 等指针注解同样命中;
|
||||
- 任何 `T1 | T2` 联合直接 fail-fast。
|
||||
"""
|
||||
if annotation is None:
|
||||
return False
|
||||
RejectTypeUnionAnnotation(annotation)
|
||||
marker: str | None = _ANNOTATION_MARKER_ALIASES.get(name)
|
||||
if marker is not None and marker in (getattr(annotation, 'Markers', None) or ()):
|
||||
return True
|
||||
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)
|
||||
if isinstance(annotation, ast.Subscript):
|
||||
base: ast.AST = annotation.value
|
||||
base_name: str = ''
|
||||
if isinstance(base, ast.Name):
|
||||
base_name = base.id
|
||||
elif isinstance(base, ast.Attribute):
|
||||
base_name = base.attr
|
||||
if name == 'CPtr' and base_name in _POINTER_SUBSCRIPT_NAMES:
|
||||
return True
|
||||
slice_node: ast.AST = annotation.slice
|
||||
if IsListAnnotation(annotation):
|
||||
# 定长数组只有第一个元素是类型;其余是长度常量表达式(可能是 `A | B` 位运算)
|
||||
if isinstance(slice_node, ast.Tuple) and slice_node.elts:
|
||||
slice_node = slice_node.elts[0]
|
||||
return (AnnotationContainsName(base, name)
|
||||
or AnnotationContainsName(slice_node, name))
|
||||
if isinstance(annotation, ast.Call):
|
||||
if AnnotationContainsName(annotation.func, name):
|
||||
return True
|
||||
return any(AnnotationContainsName(arg, name) for arg in annotation.args)
|
||||
if isinstance(annotation, (ast.Tuple, ast.List)):
|
||||
return any(AnnotationContainsName(elt, name) for elt in annotation.elts)
|
||||
return False
|
||||
|
||||
|
||||
@@ -2560,33 +2549,51 @@ _AUTO_ADDR_MARKER_MODES: dict[str, str] = {
|
||||
def FindAutoAddrMode(node: ast.AST | None) -> str | None:
|
||||
"""注解 AST 内查找自动取址模式标记,返回 'ref' / 'temp' / 'always';无则 None。
|
||||
|
||||
只按名字识别(Attribute.attr 或 Name.id),递归联合/嵌套注解;CRef/CTempRef
|
||||
非真实类,不出现在类型模型模块中。
|
||||
只按名字识别(Attribute.attr 或 Name.id),递归嵌套注解;CRef/CTempRef
|
||||
非真实类,不出现在类型模型模块中。`T1 | T2` 联合直接 fail-fast。
|
||||
"""
|
||||
if node is None:
|
||||
return None
|
||||
RejectTypeUnionAnnotation(node)
|
||||
if isinstance(node, ast.Attribute):
|
||||
mode = _AUTO_ADDR_MARKER_MODES.get(node.attr)
|
||||
if mode is not None:
|
||||
return mode
|
||||
elif isinstance(node, ast.Name):
|
||||
mode = _AUTO_ADDR_MARKER_MODES.get(node.id)
|
||||
return FindAutoAddrMode(node.value)
|
||||
if isinstance(node, ast.Name):
|
||||
return _AUTO_ADDR_MARKER_MODES.get(node.id)
|
||||
if isinstance(node, ast.Subscript):
|
||||
mode = FindAutoAddrMode(node.value)
|
||||
if mode is not None:
|
||||
return mode
|
||||
for child in ast.iter_child_nodes(node):
|
||||
mode = FindAutoAddrMode(child)
|
||||
slice_node: ast.AST = node.slice
|
||||
if IsListAnnotation(node) and isinstance(slice_node, ast.Tuple) and slice_node.elts:
|
||||
# 定长数组长度是常量表达式,不参与取址标记查找
|
||||
slice_node = slice_node.elts[0]
|
||||
return FindAutoAddrMode(slice_node)
|
||||
if isinstance(node, ast.Call):
|
||||
mode = FindAutoAddrMode(node.func)
|
||||
if mode is not None:
|
||||
return mode
|
||||
for arg in list(node.args) + [kw.value for kw in node.keywords]:
|
||||
mode = FindAutoAddrMode(arg)
|
||||
if mode is not None:
|
||||
return mode
|
||||
return None
|
||||
if isinstance(node, (ast.Tuple, ast.List)):
|
||||
for elt in node.elts:
|
||||
mode = FindAutoAddrMode(elt)
|
||||
if mode is not None:
|
||||
return mode
|
||||
return None
|
||||
|
||||
|
||||
def IsCPtrSubscriptNode(node: ast.AST) -> bool:
|
||||
"""检查节点是否为 CPtr[T] 下标指针类型(非裸标记,裸标记见 IsCPtrNode)。
|
||||
"""检查节点是否为 `CPtr[T]` 下标指针类型(非裸标记,裸标记见 IsCPtrNode)。
|
||||
|
||||
与 VPC TypeGenResolve._is_cptr_subscript(TypeGenResolve.vp:1485-1505)同口径:
|
||||
value 必须是 CPtr 属性引用(只认 t 前缀,CPtr[...] 不认);
|
||||
切片内的指针层级不限(CPtr[CPtr]、CPtr[CPtr[CInt]] 均命中)。
|
||||
链式写法 CPtr[T][T](value 是 Subscript)两套编译器均不认作该标记。
|
||||
与 VPC TypeGenResolve._is_cptr_subscript 同口径:value 必须是裸名 `CPtr`;
|
||||
切片内的指针层级不限(`CPtr[CPtr]` / `CPtr[CPtr[CInt]]` 均命中)。
|
||||
链式写法 CPtr[T][T](value 是 Subscript)不认作该标记。
|
||||
"""
|
||||
return (isinstance(node, ast.Subscript)
|
||||
and IsCPtrNode(node.value))
|
||||
@@ -2621,12 +2628,10 @@ def ResolveTCImportAliasName(NameId: str, symtable: object | None = None,
|
||||
def IsRawPtrSubscriptNode(node: ast.AST) -> bool:
|
||||
"""检查节点是否为内置裸指针下标 `rawptr[T]`(非裸标记 rawptr)。
|
||||
|
||||
`rawptr[T]` 语义 = `CPtr[T]` = 源码联合写法 `T | CPtr`(Ptr(T)),三者
|
||||
必须走同一解析与拼名路径,否则同一类型的不同书写会分裂出不同特化名
|
||||
(结构体/方法声明/调用点三处不一致)。
|
||||
`rawptr[T]` 语义 = `CPtr[T]` = Ptr(T),二者必须走同一解析与拼名路径,
|
||||
否则同一类型的不同书写会分裂出不同特化名(结构体/方法声明/调用点三处不一致)。
|
||||
注意:本判据**只**认 `rawptr[T]`;`CPtr[T]` / 裸名 `CPtr[T]` 由
|
||||
IsPtrSubscriptNode 判定(见下),二者共用同一条脱糖规则
|
||||
(DesugarPtrSubscriptToUnion),此处保持 rawptr 专用以便仍需区分书写时使用。
|
||||
IsPtrSubscriptNode 判定(见下),此处保持 rawptr 专用以便仍需区分书写时使用。
|
||||
"""
|
||||
return (isinstance(node, ast.Subscript)
|
||||
and isinstance(node.value, ast.Name)
|
||||
@@ -2647,27 +2652,21 @@ def IsI8DoublePtrType(T: object) -> bool:
|
||||
|
||||
|
||||
def IsClassRefPtrAnnotation(Ann: ast.AST, symtable: object | None = None) -> bool:
|
||||
"""注解是否为「**指针包装的类引用**」:`rawptr[Mod.Class]` / `Mod.Class | CPtr`。
|
||||
"""注解是否为「**指针包装的类引用**」:`rawptr[Mod.Class]` / `CPtr[Mod.Class]`。
|
||||
|
||||
只回答"这个注解**本应**解析出结构体指针",不做任何类型解析,判据保守:
|
||||
- 必须是指针包装:`rawptr[T]` / `CPtr[T]` / 裸名 `CPtr[T]`,或含 `CPtr`
|
||||
标记的联合写法 `T | CPtr`;
|
||||
- 必须是指针包装:`rawptr[T]` / `CPtr[T]` / 裸名 `CPtr[T]`(`T1 | T2` 联合
|
||||
已不再允许,命中即 fail-fast);
|
||||
- 内层须是类引用形态:`Attribute` 且**根模块不是 `t` / `c`**
|
||||
(如 `ExprGenFstr.ExprGenFstr`、`llvmlite.LLVMType`),或首字母大写的裸名
|
||||
(类名书写惯例)。
|
||||
模块名、`rawptr` / `CPtr` 标记本身、泛型特化实参(内层是 Subscript)、
|
||||
`str` / `int` 这类小写内建名一律**不算**。
|
||||
"""
|
||||
RejectTypeUnionAnnotation(Ann)
|
||||
Inner: ast.AST | None = None
|
||||
if IsRawPtrSubscriptNode(Ann) or IsCPtrSubscriptNode(Ann):
|
||||
Inner = Ann.slice
|
||||
elif isinstance(Ann, ast.BinOp) and isinstance(Ann.op, ast.BitOr):
|
||||
for Side in (Ann.left, Ann.right):
|
||||
if IsCPtrMarkerNode(Side, symtable):
|
||||
continue
|
||||
if Inner is not None:
|
||||
return False
|
||||
Inner = Side
|
||||
else:
|
||||
return False
|
||||
if isinstance(Inner, ast.Attribute):
|
||||
@@ -2686,8 +2685,7 @@ def IsPtrSubscriptNode(node: ast.AST, symtable: object | None = None,
|
||||
"""检查节点是否为"指针下标类型":`rawptr[T]` / `CPtr[T]` / 裸名 `CPtr[T]`
|
||||
/ 导入别名 `X[T]`(`from t import CPtr as X`)。
|
||||
|
||||
三者语义完全相同(= 源码联合写法 `T | CPtr` = Ptr(T),见
|
||||
builtins.vp 与 t.py 的 CPtr 语义注释):内层 T 按**参数注解 `a: T` 的规则**
|
||||
二者语义完全相同(= Ptr(T)):内层 T 按**参数注解 `a: T` 的规则**
|
||||
解析(跨模块类 → '<sha1>.X'),再包一层指针——T 为类引用时该层被结构体
|
||||
自身吸收('<sha1>.X*'),其余(标量 / 已是指针的 typedef / 泛型容器特化 /
|
||||
嵌套指针下标)逐层外包。
|
||||
@@ -2712,28 +2710,14 @@ def IsPtrSubscriptNode(node: ast.AST, symtable: object | None = None,
|
||||
return IsCPtrMarkerNode(value, symtable, TCAliasMap)
|
||||
|
||||
|
||||
_GENERIC_ARG_INT_NAMES: frozenset[str] = frozenset({
|
||||
'int8', 'int16', 'int32', 'int64',
|
||||
'uint8', 'uint16', 'uint32', 'uint64',
|
||||
'intfast8', 'intfast16', 'intfast32', 'intfast64',
|
||||
'uintfast8', 'uintfast16', 'uintfast32', 'uintfast64',
|
||||
'intleast8', 'intleast16', 'intleast32', 'intleast64',
|
||||
'uintleast8', 'uintleast16', 'uintleast32', 'uintleast64',
|
||||
'sizet', 'size_t', 'uchar', 'short', 'ushort', 'uint',
|
||||
'long', 'ulong', 'longlong', 'ulonglong', 'ptrdifft',
|
||||
})
|
||||
|
||||
def NormalizeGenericArgName(NameId: str) -> str:
|
||||
"""泛型实参名归一:int/double/float 保留,char/bool → 'i8',
|
||||
内建整数短名 → 'int',其余原样返回。
|
||||
"""泛型实参名归一:内建短名 → C 类名(int → CInt、uint64 → CUInt64T、
|
||||
sizet → CSizeT、char → CChar、bool → CBool…),C* 类名与其余名字原样返回。
|
||||
|
||||
归一结果再交给 `MangleTypeArgByRegistry` 变成 LLVM 名(CInt → i32、
|
||||
CUInt64T → i64),因此 `list[int]` 与 `list[CInt]` 得到同一特化名。
|
||||
"""
|
||||
if NameId in ('int', 'double', 'float'):
|
||||
return NameId
|
||||
if NameId in ('char', 'bool'):
|
||||
return 'i8'
|
||||
if NameId in _GENERIC_ARG_INT_NAMES:
|
||||
return 'int'
|
||||
return NameId
|
||||
return GenericArgRawName(NameId)
|
||||
|
||||
|
||||
_LLVM_FLOAT_STRINGS: frozenset[str] = frozenset({'half', 'float', 'double', 'fp128'})
|
||||
@@ -2757,19 +2741,24 @@ def GenericArgRawName(NameId: str) -> str:
|
||||
|
||||
def MangleTypeArgByRegistry(ArgStr: str) -> str:
|
||||
"""实参串 → 最终 mangled 实参(HandlesClassDef._mangle_generic_class_name
|
||||
的单项逻辑,逐分支同构):t 类型名经 NameToLLVM 归一(CInt32T → 'i32',
|
||||
'CInt'/'CInt' 先去模块前缀再归一),浮点按 Size 归一为 f{n}
|
||||
(CDouble → 'f64'),未注册名原样保留(含指针层数与已解析的内层名)。
|
||||
的单项逻辑,逐分支同构):t/c 模块前缀先剥离;C 类型名经 NameToLLVM 归一
|
||||
(CInt32T → 'i32'、CInt → 'i32'、CUInt64T → 'i64'),浮点按 Size 归一为
|
||||
f{n}(CDouble → 'f64'),未注册名原样保留(含指针层数与已解析的内层名)。
|
||||
"""
|
||||
LookupStr: str = ArgStr
|
||||
Stars: int = len(LookupStr) - len(LookupStr.rstrip('*'))
|
||||
if Stars:
|
||||
LookupStr = LookupStr[:-Stars]
|
||||
if LookupStr.startswith(('t.', 'c.')):
|
||||
LookupStr = LookupStr.split('.', 1)[1]
|
||||
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
|
||||
return 'f' + str(Size) + ('*' * Stars)
|
||||
return LlvmStr + ('*' * Stars)
|
||||
|
||||
|
||||
# 指针层数的首层归一化(与 LLVMTypeMapper._add_pointer_level 同口径)
|
||||
@@ -2793,12 +2782,11 @@ def AddPointerLayers(TypeStr: str, Layers: int) -> str:
|
||||
|
||||
def IsCPtrMarkerNode(Node: ast.AST, symtable: object | None = None,
|
||||
TCAliasMap: dict[str, tuple[str, str]] | None = None) -> bool:
|
||||
"""`CPtr` 裸指针标记(含 `import t as tt` 与 `from t import CPtr as X` 别名):
|
||||
联合写法里贡献一层 '*'。
|
||||
"""`CPtr` 裸指针标记(含 `import t as tt` 与 `from t import CPtr as X` 别名)。
|
||||
|
||||
与 IsCPtrNode 的区别:仅按 attr 名 + t 模块前缀判定,不看切片
|
||||
(`CPtr[T]` 下标是**基类型**而非层数标记,见 ResolveTypeArgStr 的
|
||||
Subscript 分支)。
|
||||
Subscript 分支)。注解联合 `T1 | T2` 已禁止,本判据仅用于类型实参解析。
|
||||
- Attribute:`CPtr` / `tt.CPtr`(t 模块别名经 symtable.import_aliases 解析)。
|
||||
- Name:经别名表归一为 'CPtr' 的书写名(`from t import CPtr as X` 的 `X`);
|
||||
字面裸名 `CPtr` 是否算标记取决于该模块是否 `from t import CPtr`
|
||||
@@ -2814,9 +2802,8 @@ def IsCPtrMarkerNode(Node: ast.AST, symtable: object | None = None,
|
||||
|
||||
|
||||
def FlattenUnionOperands(Node: ast.AST) -> list[ast.AST]:
|
||||
"""拉平嵌套 BitOr,按书写顺序返回操作数(`A | CPtr | CPtr` → [A, CPtr, CPtr])。"""
|
||||
if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr):
|
||||
return FlattenUnionOperands(Node.left) + FlattenUnionOperands(Node.right)
|
||||
"""旧联合辅助函数:`T1 | T2` 已不再允许,命中即 fail-fast;其余返回 [Node]。"""
|
||||
RejectTypeUnionAnnotation(Node)
|
||||
return [Node]
|
||||
|
||||
|
||||
@@ -2827,24 +2814,20 @@ def ResolveTypeArgStr(Node: ast.AST, TCAliasMap: dict[str, tuple[str, str]] | No
|
||||
规则(**与参数注解 `a: T` 完全同一套解析**,定义端/声明端唯一规则源):
|
||||
- ast.Name: t/c 导入别名 → '{module}.{name}';已注册类 → '{sha1}.{名}'
|
||||
(与参数注解的 %"{sha1}.X" 同前缀);其余按 NormalizeGenericArgName
|
||||
归一('int'/'i32'/'str' 原名、'char'/'bool' → 'i8'、C 整数/浮点族 →
|
||||
'int'/'double')
|
||||
归一(内建短名 → C 类名,再由 MangleTypeArgByRegistry 归一为 LLVM 名)
|
||||
- ast.Attribute: t 模块类型按 CTypeRegistry.NameToLLVM 解析(CPtr → i8*、
|
||||
CInt → i32);跨模块类引用 module.X → '{sha1}.X';其余 '{mod}.{attr}'
|
||||
- ast.Subscript: 指针下标(`rawptr[T]` / `CPtr[T]` / 裸名 `CPtr[T]` /
|
||||
导入别名 `X[T]`)已在入口脱糖为上面的联合写法(走同一规则),故此处只剩泛型容器:
|
||||
- ast.Subscript: 指针/引用下标(`rawptr[T]` / `CPtr[T]` / `CRef[T]` /
|
||||
`CTempRef[T]` / `CArrayPtr[T]` / `CAutoPtr[T]`)→ 内层实参串 + 一层 '*'
|
||||
(`_ResolveSubscriptArgStr`);其余为泛型容器:
|
||||
'<容器名>[<已解析实参>]'(多实参 '][' 分隔),容器名的
|
||||
模块前缀由调用方(_mangle_name / '%"{模sha1}.{特化名}"')统一加
|
||||
- ast.BinOp(BitOr)(含指针下标脱糖而来): 取非 CPtr 侧为基类型,
|
||||
每个 `CPtr` 标记追加一层 '*'(`X | CPtr` ≡ `rawptr[X]` ≡
|
||||
`CPtr[X]` → '<sha1>.X*';`rawptr[rawptr[X]]` → '<sha1>.X**';
|
||||
标量 `int | CPtr` → 'int*')
|
||||
- ast.BinOp(BitOr): `T1 | T2` 类型联合已禁止 ⇒ fail-fast
|
||||
- 其余形态: ast.unparse
|
||||
|
||||
注意:名称域**不做**"裸类引用吸收一层 CPtr"(那是注解→LLVM 类型域的规则,
|
||||
见 DeclarationGenerator._is_bare_class_ref_annotation):名称域描述的是类型
|
||||
身份('X' = X 本身、'X*' = 指向 X 的指针),逐层累加,否则
|
||||
`rawptr[X]` 与 `X | CPtr` 会分裂成两个名字。
|
||||
身份('X' = X 本身、'X*' = 指向 X 的指针),逐层累加。
|
||||
"""
|
||||
if isinstance(Node, ast.Name):
|
||||
tn: str = Node.id
|
||||
@@ -2859,7 +2842,7 @@ def ResolveTypeArgStr(Node: ast.AST, TCAliasMap: dict[str, tuple[str, str]] | No
|
||||
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)
|
||||
RejectTypeUnionAnnotation(Node)
|
||||
return ast.unparse(Node)
|
||||
|
||||
|
||||
@@ -2883,50 +2866,35 @@ def _ResolveAttributeArgStr(Node: ast.Attribute, TCAliasMap: dict[str, tuple[str
|
||||
|
||||
def _ResolveSubscriptArgStr(Node: ast.Subscript, TCAliasMap: dict[str, tuple[str, str]] | None,
|
||||
StructSha1Map: dict[str, str] | None) -> str:
|
||||
"""下标形态(CPtr[T] / 泛型容器 list[X] / dict[K,V])→ 实参串。
|
||||
"""下标形态(CPtr[T] / CRef[T] / 泛型容器 list[X] / dict[K,V])→ 实参串。
|
||||
|
||||
指针/引用下标(CPtr/rawptr/CRef/CTempRef/CArrayPtr/CAutoPtr)统一表示为
|
||||
"内层实参串 + 一层 '*'",与声明端逐层累加口径一致。
|
||||
容器名('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 IsPtrSubscriptNode(Node, TCAliasMap=TCAliasMap) \
|
||||
or BaseName in ('CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
|
||||
Inner: str = ResolveTypeArgStr(Node.slice, TCAliasMap, StructSha1Map)
|
||||
return AddPointerLayers(Inner, 1)
|
||||
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]
|
||||
if IsListAnnotation(Node) and ElemNodes:
|
||||
# 定长数组只有元素类型参与类型身份;长度是常量表达式,不参与 mangling
|
||||
ElemNodes = ElemNodes[:1]
|
||||
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 | 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 标记(如 `CPtr | CPtr`):等价 void* 逐层——首层 i8*
|
||||
return AddPointerLayers('void', Layers)
|
||||
return AddPointerLayers(BaseType, Layers)
|
||||
|
||||
|
||||
def GetStructSha1MapFromSymtab(Symtab: object | None) -> dict[str, str]:
|
||||
"""从符号表取「类名 → 定义模块 sha1」表(Phase2 在 Convert 前挂到 translator)。"""
|
||||
_Tr: Any = getattr(Symtab, 'translator', None)
|
||||
@@ -3016,11 +2984,12 @@ def ResolveGenericTypeArgStr(Node: ast.AST, TCAliasMap: dict[str, tuple[str, str
|
||||
|
||||
与定义端(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] 脱糖 → 逐层 '*'、CPtr → 'i8*'、跨模块类 → sha1 前缀)
|
||||
→ MangleTypeArgByRegistry
|
||||
- ast.Name: NormalizeGenericArgName(内建短名 → C 类名)→(命中注册类则
|
||||
'{sha1}.{名}')→ MangleTypeArgByRegistry
|
||||
('int' → 'i32'、'i64' → 'i64'、'str' → 'str'、'CInt32T' → 'i32'、
|
||||
'CFloat64T' → 'f64'、'CChar' → 'i8')
|
||||
- 其余形态(Attribute / Subscript / 混合 Tuple 元素):
|
||||
ResolveTypeArgStr(指针/引用下标 → 逐层 '*'、跨模块类 → sha1 前缀)
|
||||
→ MangleTypeArgByRegistry;`T1 | T2` 联合 fail-fast。
|
||||
"""
|
||||
return MangleTypeArgByRegistry(ResolveTypeArgStr(Node, TCAliasMap, StructSha1Map))
|
||||
@@ -482,10 +482,6 @@ class LlvmGeneratorMixin:
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = TypeSystem.CInt()
|
||||
IsPtr: bool = TypeInfo.IsPtr
|
||||
if not IsPtr:
|
||||
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
|
||||
if AnnotationContainsName(item.annotation, 'CPtr'):
|
||||
IsPtr = True
|
||||
dims: list[int] = []
|
||||
if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant):
|
||||
if isinstance(item.annotation.value, ast.Name):
|
||||
|
||||
@@ -6,11 +6,19 @@ import struct
|
||||
|
||||
from lib.utils.helpers import DetectFileType
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
from lib.core.SymbolUtils import AnnotationContainsName, ExpandSoftKeywords
|
||||
from lib.core.SymbolUtils import (
|
||||
AnnotationContainsName, ExpandSoftKeywords, RejectTypeUnionAnnotation,
|
||||
)
|
||||
from lib.core import TypeSystem
|
||||
from lib.constants.config import mode as _ConfigMode
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
# 指针/引用下标包装名(`CPtr[T]` / `rawptr[T]` / `CRef[T]` ...):
|
||||
# 新表示下指针/引用统一是 Subscript,不再是 `T | CPtr` 联合。
|
||||
_PTR_SUBSCRIPT_NAMES: frozenset[str] = frozenset({
|
||||
'CPtr', 'rawptr', 'CArrayPtr', 'CRef', 'CTempRef', 'CAutoPtr',
|
||||
})
|
||||
|
||||
|
||||
class PythonParserMixin:
|
||||
"""Python 文件解析 Mixin
|
||||
@@ -130,12 +138,7 @@ class PythonParserMixin:
|
||||
if hasattr(node.func.value, 'id') and node.func.attr == 'Postdefinition':
|
||||
return node
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
LeftResult: ast.Call | None = find_PostdefNode(node.left)
|
||||
if LeftResult:
|
||||
return LeftResult
|
||||
RightResult: ast.Call | None = find_PostdefNode(node.right)
|
||||
if RightResult:
|
||||
return RightResult
|
||||
RejectTypeUnionAnnotation(node)
|
||||
return None
|
||||
|
||||
PostdefNode = find_PostdefNode(annotation)
|
||||
@@ -179,8 +182,7 @@ class PythonParserMixin:
|
||||
# 递归提取更外层的维度
|
||||
dims.extend(extract_subscript_dims(node.value))
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
# 处理 Type | CPtr 的情况,检查左侧
|
||||
dims.extend(extract_subscript_dims(node.left))
|
||||
RejectTypeUnionAnnotation(node)
|
||||
return dims
|
||||
|
||||
# 从注解中提取维度
|
||||
@@ -241,8 +243,15 @@ class PythonParserMixin:
|
||||
continue
|
||||
# 再处理 xxx: CPtr = xxx:typedef 不合并进结构体定义,
|
||||
# 而应生成独立的 typedef 语句,故不添加到 TypedefAssignments
|
||||
elif (NextNode.annotation and isinstance(NextNode.annotation, ast.Name)
|
||||
and NextNode.annotation.id == TypeSystem.CPtr.__name__):
|
||||
elif (NextNode.annotation and (
|
||||
(isinstance(NextNode.annotation, ast.Name)
|
||||
and NextNode.annotation.id == TypeSystem.CPtr.__name__)
|
||||
or (isinstance(NextNode.annotation, ast.Subscript)
|
||||
and (
|
||||
(isinstance(NextNode.annotation.value, ast.Name)
|
||||
and NextNode.annotation.value.id in _PTR_SUBSCRIPT_NAMES)
|
||||
or (isinstance(NextNode.annotation.value, ast.Attribute)
|
||||
and NextNode.annotation.value.attr in _PTR_SUBSCRIPT_NAMES))))):
|
||||
if NextNode.value and isinstance(NextNode.value, ast.Name):
|
||||
ValueName: str = NextNode.value.id
|
||||
if ValueName == ClassName:
|
||||
@@ -368,10 +377,6 @@ class PythonParserMixin:
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = TypeSystem.CInt()
|
||||
IsPtr: bool = TypeInfo.IsPtr
|
||||
if not IsPtr:
|
||||
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
|
||||
if AnnotationContainsName(item.annotation, 'CPtr'):
|
||||
IsPtr = True
|
||||
dims: list[int] = []
|
||||
if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant):
|
||||
if isinstance(item.annotation.value, ast.Name):
|
||||
@@ -410,23 +415,19 @@ class PythonParserMixin:
|
||||
elif isinstance(node, ast.AnnAssign):
|
||||
if isinstance(node.target, ast.Name):
|
||||
VarName: str = node.target.id
|
||||
# 检查是否是 CTypedef 格式,如果是则跳过(由 HandleClassDef 处理)
|
||||
# 检查是否是 typedef 格式,如果是则跳过(由 HandleClassDef 处理)。
|
||||
# 新表示读注解 Markers;旧的 CTypedef 文本写法仅作兼容。
|
||||
is_ctypedef: bool = False
|
||||
if node.annotation:
|
||||
if isinstance(node.annotation, ast.Attribute):
|
||||
if isinstance(node.annotation.value, ast.Name):
|
||||
if node.annotation.attr == 'CTypedef':
|
||||
is_ctypedef = True
|
||||
elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.op, ast.BitOr):
|
||||
def _has_ctype(ann: ast.AST) -> bool:
|
||||
if isinstance(ann, ast.Attribute):
|
||||
return hasattr(ann.value, 'id') and ann.attr == 'CTypedef'
|
||||
if isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr):
|
||||
return _has_ctype(ann.left) or _has_ctype(ann.right)
|
||||
if isinstance(ann, ast.Subscript):
|
||||
return _has_ctype(ann.value)
|
||||
return False
|
||||
if _has_ctype(node.annotation):
|
||||
if 'typedef' in (getattr(node, 'Markers', None) or ()):
|
||||
is_ctypedef = True
|
||||
if not is_ctypedef and node.annotation:
|
||||
for _ann_node in ast.walk(node.annotation):
|
||||
if 'typedef' in (getattr(_ann_node, 'Markers', None) or ()):
|
||||
is_ctypedef = True
|
||||
break
|
||||
if not is_ctypedef and isinstance(node.annotation, ast.Attribute):
|
||||
if isinstance(node.annotation.value, ast.Name):
|
||||
if node.annotation.attr == 'CTypedef':
|
||||
is_ctypedef = True
|
||||
if not is_ctypedef:
|
||||
# 如果符号已经存在且是 typedef,不要覆盖它
|
||||
|
||||
@@ -193,46 +193,23 @@ class TypeAnnotationResolver:
|
||||
_TYPEDEF_SUGAR_RE: re.Pattern = re.compile(
|
||||
r'^typedef\s+([A-Za-z_]\w*)\s*=(?!=)\s*(.+?)\s*$')
|
||||
|
||||
@staticmethod
|
||||
def _NormalizeTypedefRhsText(text: str) -> str:
|
||||
"""把 typedef 右值的 C 式写法归一成规范 `|` 联合文本(供**文本回退路径**使用)。
|
||||
|
||||
磁盘原文里 `X: CTypedef = const str` / `= const uint16*` 的右值带描述符与指针
|
||||
后缀,而本路径(_parse_typedef_line → _resolve_builtins_type_str)按表达式文本解析,
|
||||
故先归一:
|
||||
- 前导 `const` / `volatile`(可组合) → `CConst` / `CVolatile` 前缀;
|
||||
- 末尾 `*` / `**` 串 → 逐层 `| CPtr`。
|
||||
不含上述形态的文本原样返回(幂等)。无算术语义风险:typedef 右值不含乘法。
|
||||
"""
|
||||
s: str = text.strip()
|
||||
if not s:
|
||||
return text
|
||||
markers: list[str] = []
|
||||
while True:
|
||||
m: re.Match | None = re.match(r'^(const|volatile)\s+', s)
|
||||
if m is None:
|
||||
break
|
||||
markers.append('CConst' if m.group(1) == 'const' else 'CVolatile')
|
||||
s = s[m.end():].lstrip()
|
||||
ptrs: int = 0
|
||||
while s.endswith('*'):
|
||||
s = s[:-1].rstrip()
|
||||
ptrs += 1
|
||||
if not markers and ptrs == 0:
|
||||
return text
|
||||
parts: list[str] = markers + [s] + ['CPtr'] * ptrs
|
||||
return ' | '.join(p for p in parts if p)
|
||||
# 文本回退路径中需要按**注解语法**解析的 typedef 右值形态:指针/下标、
|
||||
# 联合(会被 from_node fail-fast 拒绝)、以及注解前缀修饰词。
|
||||
_TYPE_EXPR_SPECIAL_RE: re.Pattern = re.compile(
|
||||
r'[|\[\]*]|^\s*(?:const|volatile|static|export|extern|inline)\b')
|
||||
|
||||
@staticmethod
|
||||
def _parse_typedef_line(stripped: str) -> tuple[str, str] | None:
|
||||
"""单行源码文本 → typedef 声明 (名字, 类型值);非 typedef 行返回 None
|
||||
|
||||
兼容 `typedef 名字 = 类型`(语法糖)与 `名字: CTypedef = 类型`(注解)。
|
||||
右值的 C 式写法(`const T` / `T*`)经 _NormalizeTypedefRhsText 归一为 `|` 联合。
|
||||
右值保持源码原样(含 `const` / `T*` 等),交由 `_parse_type_expr` 按
|
||||
注解语法解析——注解修饰词由解析器写入 Markers/ByteOrder/BitWidth,
|
||||
不再在文本层拼出 `T1 | T2` 联合。
|
||||
"""
|
||||
m: re.Match | None = TypeAnnotationResolver._TYPEDEF_SUGAR_RE.match(stripped)
|
||||
if m is not None:
|
||||
return m.group(1), TypeAnnotationResolver._NormalizeTypedefRhsText(m.group(2))
|
||||
return m.group(1), m.group(2).strip()
|
||||
if ':' not in stripped or 'CTypedef' not in stripped:
|
||||
return None
|
||||
name, _, rest = stripped.partition(':')
|
||||
@@ -242,7 +219,7 @@ class TypeAnnotationResolver:
|
||||
name = name.strip()
|
||||
if not name or not value:
|
||||
return None
|
||||
return name, TypeAnnotationResolver._NormalizeTypedefRhsText(value)
|
||||
return name, value
|
||||
|
||||
@staticmethod
|
||||
def _builtins_include_dirs() -> list[str]:
|
||||
@@ -345,8 +322,9 @@ class TypeAnnotationResolver:
|
||||
type_str = type_str.strip()
|
||||
if not type_str:
|
||||
return None
|
||||
# 复合表达式(联合/泛型)交给常规 AST 解析
|
||||
if '|' in type_str or '[' in type_str:
|
||||
# 复合表达式(指针后缀 / 泛型下标 / 注解前缀 / 联合)交给注解语法解析。
|
||||
# 联合 `T1 | T2` 会由 from_node 直接 fail-fast(TypeError),不再合并。
|
||||
if TypeAnnotationResolver._TYPE_EXPR_SPECIAL_RE.search(type_str):
|
||||
try:
|
||||
node: ast.AST | None = TypeAnnotationResolver._parse_type_expr(type_str)
|
||||
except Exception:
|
||||
@@ -413,7 +391,23 @@ class TypeAnnotationResolver:
|
||||
|
||||
@staticmethod
|
||||
def _parse_type_expr(text: str) -> ast.AST | None:
|
||||
"""vast mode='eval' 解析单个表达式,返回表达式节点或 None"""
|
||||
"""把类型文本按**注解语法**解析为表达式节点(失败返回 None)。
|
||||
|
||||
使用 `名字: <text>` 形态而非 eval:注解位置的修饰前缀(const/volatile/
|
||||
static/export/extern/inline)与 C 风格指针后缀(`T*`)由解析器写成
|
||||
Markers / Subscript,从而与源码注解得到同一种 AST 表示。
|
||||
eval 回退仅用于极少数无法作为注解右值书写的表达式文本。
|
||||
"""
|
||||
try:
|
||||
tree: ast.AST = ast.parse(
|
||||
f'__tpc_type__: {text}', '<TypeAnnotationResolver:type_expr>')
|
||||
body = getattr(tree, 'body', None)
|
||||
if isinstance(body, list) and body:
|
||||
ann = getattr(body[0], 'annotation', None)
|
||||
if ann is not None:
|
||||
return ann
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
expr_tree: ast.AST = ast.parse(text, '<TypeAnnotationResolver:type_expr>', mode='eval')
|
||||
body = getattr(expr_tree, 'body', None)
|
||||
|
||||
+57
-53
@@ -43,45 +43,44 @@ _RE_ARRAY_PARAM: re.Pattern[str] = re.compile(r'([\w\s\*]+?)\s+(\w+)\s*\[\d*\]')
|
||||
|
||||
class CTypeMapper:
|
||||
|
||||
# 硬编码 C 类型名 → Python 类型映射表
|
||||
# 这是 stub 生成器(C 头文件 → Python stub)专用的固定映射,
|
||||
# 不再依赖运行时 CTypeRegistry._cname_to_class(该映射已删除)。
|
||||
# C 类型名 → 新语法内建类型名
|
||||
# (int/uint/int8..uint64/sizet/short/long/uchar/float8..float128/char8..char32/rawptr)
|
||||
_CNAME_TO_PY: dict[str, str] = {
|
||||
# 基本类型
|
||||
'char': 'CChar', 'int': 'CInt', 'short': 'CShort',
|
||||
'long': 'CLong', 'long long': 'CLongLong',
|
||||
'float': 'CFloat', 'double': 'CDouble', 'void': 'CVoid',
|
||||
'char': 'char', 'int': 'int', 'short': 'short',
|
||||
'long': 'long', 'long long': 'longlong',
|
||||
'float': 'float', 'double': 'double', 'void': 'void',
|
||||
# unsigned / signed 变体
|
||||
'unsigned': 'CUnsigned', 'unsigned char': 'CUnsignedChar',
|
||||
'unsigned int': 'CUnsignedInt', 'unsigned short': 'CUnsignedShort',
|
||||
'unsigned long': 'CUnsignedLong',
|
||||
'unsigned long long': 'CUnsignedLongLong',
|
||||
'signed char': 'CSignedChar',
|
||||
'unsigned': 'uint', 'unsigned char': 'uchar',
|
||||
'unsigned int': 'uint', 'unsigned short': 'ushort',
|
||||
'unsigned long': 'ulong',
|
||||
'unsigned long long': 'ulonglong',
|
||||
'signed char': 'char',
|
||||
# bool / size_t
|
||||
'bool': 'CBool', '_Bool': 'CBool', 'size_t': 'CSizeT',
|
||||
'ssize_t': 'CLong',
|
||||
'bool': 'bool', '_Bool': 'bool', 'size_t': 'sizet',
|
||||
'ssize_t': 'ptrdifft',
|
||||
# stdint 固定宽度类型
|
||||
'int8_t': 'CInt8T', 'int16_t': 'CInt16T',
|
||||
'int32_t': 'CInt32T', 'int64_t': 'CInt64T',
|
||||
'uint8_t': 'CUInt8T', 'uint16_t': 'CUInt16T',
|
||||
'uint32_t': 'CUInt32T', 'uint64_t': 'CUInt64T',
|
||||
'intptr_t': 'CIntPtrT', 'uintptr_t': 'CUIntPtrT',
|
||||
'ptrdiff_t': 'CPtrDiffT',
|
||||
'int8_t': 'int8', 'int16_t': 'int16',
|
||||
'int32_t': 'int32', 'int64_t': 'int64',
|
||||
'uint8_t': 'uint8', 'uint16_t': 'uint16',
|
||||
'uint32_t': 'uint32', 'uint64_t': 'uint64',
|
||||
'intptr_t': 'intptr', 'uintptr_t': 'uintptr',
|
||||
'ptrdiff_t': 'ptrdifft',
|
||||
# 宽字符 / 字符类型
|
||||
'wchar_t': 'CWCharT', 'char8_t': 'CChar8T',
|
||||
'char16_t': 'CChar16T', 'char32_t': 'CChar32T',
|
||||
'wchar_t': 'wchar', 'char8_t': 'char8',
|
||||
'char16_t': 'char16', 'char32_t': 'char32',
|
||||
# 浮点特化类型
|
||||
'float8_t': 'CFloat8T', 'float16_t': 'CFloat16T',
|
||||
'float32_t': 'CFloat32T', 'float64_t': 'CFloat64T',
|
||||
'float128_t': 'CFloat128T',
|
||||
'float8_t': 'float8', 'float16_t': 'float16',
|
||||
'float32_t': 'float32', 'float64_t': 'float64',
|
||||
'float128_t': 'float128',
|
||||
# signed 速记
|
||||
'signed': 'CInt', 'signed int': 'CInt',
|
||||
'signed short': 'CShort', 'signed long': 'CLong',
|
||||
'signed': 'int', 'signed int': 'int',
|
||||
'signed short': 'short', 'signed long': 'long',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def _ResolveCNameToPyType(cls, c_type: str) -> str:
|
||||
"""将 C 类型名解析为 Python 类型字符串(如 'int' → 'CInt')
|
||||
"""将 C 类型名解析为新语法内建类型名(如 'int' → 'int')
|
||||
|
||||
使用硬编码映射表,不再依赖 CTypeRegistry._cname_to_class。
|
||||
未识别的类型原样返回(用于 struct/union/enum/typedef 用户自定义名)。
|
||||
@@ -93,25 +92,24 @@ class CTypeMapper:
|
||||
|
||||
@classmethod
|
||||
def MapType(cls, c_type: str, IsPtr: bool = False, IsArray: bool = False) -> str:
|
||||
"""C 类型 → 新语法类型(指针写成 `T*`,不再产出 `T | CPtr`)。"""
|
||||
c_type = c_type.strip()
|
||||
|
||||
IsConst: bool = 'const ' in c_type
|
||||
c_type = c_type.replace('const ', '').replace('const', '').strip()
|
||||
IsVolatile: bool = 'volatile ' in c_type
|
||||
c_type = c_type.replace('volatile ', '').replace('volatile', '').strip()
|
||||
IsStatic: bool = 'static ' in c_type
|
||||
# static / extern / register / inline 是声明级修饰,不是类型的一部分。
|
||||
c_type = c_type.replace('static ', '').replace('static', '').strip()
|
||||
IsExtern: bool = 'extern ' in c_type
|
||||
c_type = c_type.replace('extern ', '').replace('extern', '').strip()
|
||||
IsRegister: bool = 'register ' in c_type
|
||||
c_type = c_type.replace('register ', '').replace('register', '').strip()
|
||||
IsInline: bool = 'inline ' in c_type
|
||||
c_type = c_type.replace('inline ', '').replace('inline', '').strip()
|
||||
|
||||
PtrSuffix: str = ''
|
||||
if IsPtr or c_type.endswith('*'):
|
||||
PtrSuffix = ' | CPtr'
|
||||
c_type = c_type.rstrip('*').strip()
|
||||
# 指针层数:类型文本里的 '*' 已表达层数;IsPtr 只在文本无 '*' 时补一层,
|
||||
# 避免 `IsPtr=True` + 文本 '*' 被重复计数(Node**)。
|
||||
StarCount: int = len(c_type) - len(c_type.rstrip('*'))
|
||||
PtrCount: int = StarCount if StarCount > 0 else (1 if IsPtr else 0)
|
||||
c_type = c_type.rstrip('*').strip()
|
||||
|
||||
if c_type.startswith('struct '):
|
||||
c_type = c_type[7:].strip()
|
||||
@@ -122,12 +120,13 @@ class CTypeMapper:
|
||||
|
||||
PyType: str = cls._ResolveCNameToPyType(c_type)
|
||||
|
||||
result: str = PyType + PtrSuffix
|
||||
Prefix: str = ''
|
||||
if IsConst:
|
||||
Prefix += 'const '
|
||||
if IsVolatile:
|
||||
Prefix += 'volatile '
|
||||
|
||||
if IsArray:
|
||||
result += ' | CArrayPtr'
|
||||
|
||||
return result
|
||||
return Prefix + PyType + ('*' * PtrCount)
|
||||
|
||||
|
||||
def _find_matching_brace(text: str, start: int) -> int:
|
||||
@@ -352,7 +351,7 @@ class CHeaderParser:
|
||||
|
||||
def _ParseSimpleTypedefs(self, content: str) -> None:
|
||||
stripped: str = self._StripBodies(content)
|
||||
pattern: str = r'typedef\s+([\w\s\*]+?)\s+(\w+)\s*;'
|
||||
pattern: str = r'typedef[ \t]+([\w \t\*]+?)[ \t]+(\w+)[ \t]*;'
|
||||
for match in re.finditer(pattern, stripped):
|
||||
BaseType: str = match.group(1).strip()
|
||||
AliasName: str = match.group(2)
|
||||
@@ -429,7 +428,7 @@ class CHeaderParser:
|
||||
}
|
||||
|
||||
def _ParseFunctions(self, content: str) -> None:
|
||||
pattern: str = r'(?:(?:static|extern|inline)\s+)*([\w][\w\s\*]*?)\b(\w+)\s*\(([^)]*)\)\s*;'
|
||||
pattern: str = r'(?:(?:static|extern|inline)[ \t]+)*([\w][\w \t\*]*?)\b(\w+)[ \t]*\(([^)]*)\)[ \t]*;'
|
||||
for match in re.finditer(pattern, content):
|
||||
ReturnType: str = match.group(1).strip()
|
||||
FuncName: str = match.group(2)
|
||||
@@ -454,7 +453,7 @@ class CHeaderParser:
|
||||
}
|
||||
|
||||
def _ParseVariables(self, content: str) -> None:
|
||||
pattern: str = r'(?:(?:static|extern|volatile|const)\s+)*([\w][\w\s\*]*?)\s+(\w+)\s*(?:\[(\d*)\])?\s*;'
|
||||
pattern: str = r'(?:(?:static|extern|volatile|const)[ \t]+)*([\w][\w \t\*]*?)[ \t]+(\w+)[ \t]*(?:\[(\d*)\])?[ \t]*;'
|
||||
for match in re.finditer(pattern, content):
|
||||
TypeStr: str = match.group(1).strip()
|
||||
VarName: str = match.group(2)
|
||||
@@ -629,9 +628,10 @@ class PythonStubGenerator:
|
||||
Name: str = define['name']
|
||||
Value: str | None = define['value']
|
||||
if Value is not None:
|
||||
self.OutputLines.append(f'{Name}: CDefine = {Value}')
|
||||
self.OutputLines.append(f'define {Name} = {Value}')
|
||||
else:
|
||||
self.OutputLines.append(f'{Name}: CDefine')
|
||||
# 新语法要求 define 带初值;无值宏(#define FOO)以 0 占位
|
||||
self.OutputLines.append(f'define {Name} = 0')
|
||||
self.OutputLines.append('')
|
||||
|
||||
def _GenerateFuncPtrTypedefs(self) -> None:
|
||||
@@ -643,7 +643,7 @@ class PythonStubGenerator:
|
||||
for p in Info['params']:
|
||||
ParamTypes.append(CTypeMapper.MapType(p['type']))
|
||||
ParamStr: str = ', '.join(ParamTypes) if ParamTypes else ''
|
||||
self.OutputLines.append(f'{Name}: CTypedef = Callable[[{ParamStr}], {RetType}]')
|
||||
self.OutputLines.append(f'typedef {Name} = callable[[{ParamStr}], {RetType}]')
|
||||
self.OutputLines.append('')
|
||||
|
||||
def _GenerateSimpleTypedefs(self) -> None:
|
||||
@@ -653,7 +653,7 @@ class PythonStubGenerator:
|
||||
AliasName: str = td['name']
|
||||
BaseType: str = td['base']
|
||||
PyType: str = CTypeMapper.MapType(BaseType)
|
||||
self.OutputLines.append(f'{AliasName}: CTypedef | {PyType}')
|
||||
self.OutputLines.append(f'typedef {AliasName} = {PyType}')
|
||||
self.OutputLines.append('')
|
||||
|
||||
def _GenerateStructs(self) -> None:
|
||||
@@ -670,9 +670,9 @@ class PythonStubGenerator:
|
||||
ArraySize: int | None = member.get('array_size')
|
||||
PyType: str = CTypeMapper.MapType(member['type'], IsPtr=IsPtr)
|
||||
if IsArray and ArraySize is not None:
|
||||
self.OutputLines.append(f' {MemberName}: list[{PyType}, {ArraySize}]')
|
||||
self.OutputLines.append(f' {MemberName}: CArray[{PyType}, {ArraySize}]')
|
||||
elif IsArray:
|
||||
self.OutputLines.append(f' {MemberName}: {PyType} | CArrayPtr')
|
||||
self.OutputLines.append(f' {MemberName}: CArray[{PyType}, None]')
|
||||
else:
|
||||
self.OutputLines.append(f' {MemberName}: {PyType}')
|
||||
else:
|
||||
@@ -701,19 +701,23 @@ class PythonStubGenerator:
|
||||
if EnumInfo['values']:
|
||||
for value in EnumInfo['values']:
|
||||
if value['value'] is not None:
|
||||
self.OutputLines.append(f' {value["name"]}: CDefine = {value["value"]}')
|
||||
self.OutputLines.append(f' {value["name"]}: int = {value["value"]}')
|
||||
else:
|
||||
self.OutputLines.append(f' {value["name"]}: CDefine')
|
||||
self.OutputLines.append(f' {value["name"]}: int')
|
||||
else:
|
||||
self.OutputLines.append(' pass')
|
||||
self.OutputLines.append(f'{EnumName}: CTypedef = __{EnumName.lower()}')
|
||||
self.OutputLines.append(f'typedef {EnumName} = __{EnumName.lower()}')
|
||||
self.OutputLines.append('')
|
||||
|
||||
def _GenerateVariables(self) -> None:
|
||||
if not self.parser.variables:
|
||||
return
|
||||
for VarName, VarInfo in self.parser.variables.items():
|
||||
PyType: str = CTypeMapper.MapType(VarInfo['type'], IsPtr=VarInfo['IsPtr'], IsArray=VarInfo['is_array'])
|
||||
PyType: str = CTypeMapper.MapType(VarInfo['type'], IsPtr=VarInfo['IsPtr'])
|
||||
if VarInfo['is_array']:
|
||||
ArraySize: int | None = VarInfo.get('array_size')
|
||||
SizeStr: str = str(ArraySize) if ArraySize is not None else 'None'
|
||||
PyType = f'CArray[{PyType}, {SizeStr}]'
|
||||
self.OutputLines.append(f'{VarName}: {PyType}')
|
||||
self.OutputLines.append('')
|
||||
|
||||
|
||||
@@ -1687,7 +1687,7 @@ class ExprParserMixin(TokenStream):
|
||||
|
||||
# 注解起始的修饰词:只在该位置生效,写入类型节点的 Markers 字段。
|
||||
_TYPE_MARKER_WORDS: frozenset[str] = frozenset({
|
||||
'const', 'volatile', 'static', 'export', 'extern', 'inline',
|
||||
'const', 'volatile', 'static', 'export', 'extern', 'inline', 'state',
|
||||
})
|
||||
|
||||
def _ParseTypeAnnotation(self) -> N.expr:
|
||||
@@ -1782,6 +1782,11 @@ class ExprParserMixin(TokenStream):
|
||||
raise SyntaxError(
|
||||
"[vast] 类型注解的修饰词后缺少类型(如 `x: const int`)。")
|
||||
return None
|
||||
if isinstance(expr, N.BinOp) and isinstance(expr.op, N.BitOr):
|
||||
Line: int = getattr(expr, 'lineno', 0) or 0
|
||||
raise TypeError(
|
||||
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
|
||||
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
|
||||
if self._AtPtrSuffix(expr):
|
||||
expr = self._ConsumePtrSuffix(expr)
|
||||
tok: Token = self._Peek()
|
||||
|
||||
Reference in new issue
Block a user