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:
TermiNexus committed 2026-10-18 18:01:20 +08:00
1 parent a410de2cf7
commit 0bded58999
23 files changed
+887 -694

No files matched your search

+29 -16
View File
@@ -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 一致。
+7 -12
View File
@@ -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:
+32 -13
View File
@@ -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":
+8 -1
View File
@@ -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
View File
@@ -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):
+9 -6
View File
@@ -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
+43 -26
View File
@@ -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
+37 -50
View File
@@ -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
+26 -21
View File
@@ -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(
+95 -62
View File
@@ -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):
+53 -12
View File
@@ -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
+25 -8
View File
@@ -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,
+5 -11
View File
@@ -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,
+24 -6
View File
@@ -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)
+5 -5
View File
@@ -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
View File
@@ -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}*'
+19 -3
View File
@@ -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
View File
@@ -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))
-4
View File
@@ -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):
+32 -31
View File
@@ -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,不要覆盖它
+29 -35
View File
@@ -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
View File
@@ -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('')
+6 -1
View File
@@ -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()