From 0bded589994ddeaa6143b13d0f1eddbf9a366a13 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sun, 18 Oct 2026 18:01:20 +0800 Subject: [PATCH] =?UTF-8?q?refactor(type):=20=E5=85=A8=E9=9D=A2=E6=B8=85?= =?UTF-8?q?=E7=90=86=E6=97=A7=E8=81=94=E5=90=88=E4=B8=8E=20t/c=20=E6=A0=87?= =?UTF-8?q?=E8=AE=B0=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 审计并修复 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 输出统一新语法。 --- lib/Projectrans/DeclarationGenerator.py | 45 +-- lib/Projectrans/Phase1Generator.py | 19 +- lib/Projectrans/Phase2Translator.py | 45 ++- lib/Projectrans/Utils.py | 9 +- lib/StubGen/Converter.py | 263 +++++++++++------- lib/core/Handles/HandlesAssign.py | 15 +- lib/core/Handles/HandlesBase.py | 69 +++-- lib/core/Handles/HandlesClassDef.py | 87 +++--- lib/core/Handles/HandlesFunctions.py | 47 ++-- lib/core/Handles/HandlesImports.py | 157 ++++++----- lib/core/Handles/HandlesTypeMerge.py | 65 ++++- lib/core/LLVMCG/BaseGen.py | 33 ++- lib/core/LLVMCG/MemoryOps.py | 16 +- lib/core/LLVMCG/StructGen.py | 30 +- lib/core/LLVMCG/TypeConvert.py | 10 +- lib/core/LLVMTypeMapper.py | 50 ++-- lib/core/SymbolTypeResolver.py | 22 +- lib/core/SymbolUtils.py | 351 +++++++++++------------- lib/core/Translator/LlvmGenerator.py | 4 - lib/core/Translator/PythonParser.py | 63 ++--- lib/core/TypeAnnotationResolver.py | 64 ++--- lib/core/stub_generator.py | 110 ++++---- lib/vast/ExprParser.py | 7 +- 23 files changed, 887 insertions(+), 694 deletions(-) diff --git a/lib/Projectrans/DeclarationGenerator.py b/lib/Projectrans/DeclarationGenerator.py index e1330cb..f7a2267 100644 --- a/lib/Projectrans/DeclarationGenerator.py +++ b/lib/Projectrans/DeclarationGenerator.py @@ -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 一致。 diff --git a/lib/Projectrans/Phase1Generator.py b/lib/Projectrans/Phase1Generator.py index 56c1c0a..e0e69c1 100644 --- a/lib/Projectrans/Phase1Generator.py +++ b/lib/Projectrans/Phase1Generator.py @@ -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: diff --git a/lib/Projectrans/Phase2Translator.py b/lib/Projectrans/Phase2Translator.py index e260735..41c0315 100644 --- a/lib/Projectrans/Phase2Translator.py +++ b/lib/Projectrans/Phase2Translator.py @@ -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": diff --git a/lib/Projectrans/Utils.py b/lib/Projectrans/Utils.py index b7f6649..2700ea9 100644 --- a/lib/Projectrans/Utils.py +++ b/lib/Projectrans/Utils.py @@ -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')) diff --git a/lib/StubGen/Converter.py b/lib/StubGen/Converter.py index ffe4c6c..03b4568 100644 --- a/lib/StubGen/Converter.py +++ b/lib/StubGen/Converter.py @@ -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): diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index c4a8bb1..99b24b3 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -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 diff --git a/lib/core/Handles/HandlesBase.py b/lib/core/Handles/HandlesBase.py index 1b994fb..067c033 100644 --- a/lib/core/Handles/HandlesBase.py +++ b/lib/core/Handles/HandlesBase.py @@ -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[.CLS]` 脱糖后的 - `.CLS | CPtr`、泛型 T 替换出的裸 `.CLS`、`list[ast.AST]` + 不修此路时跨模块类 Attribute(`rawptr[.CLS]` / `CPtr[.CLS]`、 + 泛型 T 替换出的裸 `.CLS`、`list[ast.AST]` 特化的 `append(item: T)`)在定义端判为"无法识别的参数类型注解"抛 SyntaxError,被上层 broad except 吞掉后退化为 i32/i8*,而声明端给 `%".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 仍能解析出 %.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 diff --git a/lib/core/Handles/HandlesClassDef.py b/lib/core/Handles/HandlesClassDef.py index 0f3328a..2e7eafb 100644 --- a/lib/core/Handles/HandlesClassDef.py +++ b/lib/core/Handles/HandlesClassDef.py @@ -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, }), # 必须设置 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 diff --git a/lib/core/Handles/HandlesFunctions.py b/lib/core/Handles/HandlesFunctions.py index 7264082..d12af69 100644 --- a/lib/core/Handles/HandlesFunctions.py +++ b/lib/core/Handles/HandlesFunctions.py @@ -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 名称如 '.AST*' 需要还原为 AST | CPtr 结构, + mangled 名称如 '.AST*' 需要还原为 `CPtr[.AST]` 下标结构, 否则类型解析会丢失 PtrCount 信息。 含点号的名称(如 '.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 的数字开头手工拆分分支)。 尾部 '*'(泛型实参 '.Node*' / '.Node**',来自 rawptr[T] / - CPtr 的逐层 mangling)逐层还原为 `Node | CPtr [| CPtr]` → 对应 + CPtr 的逐层 mangling)逐层还原为嵌套 `CPtr[...]` → 对应 层数指针;只剥一层会把 'Node*' 当结构体名建出 phantom opaque (item 类型与特化名 '.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( diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index 64678b4..87266e9 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -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): diff --git a/lib/core/Handles/HandlesTypeMerge.py b/lib/core/Handles/HandlesTypeMerge.py index b0a3cd0..ee75991 100644 --- a/lib/core/Handles/HandlesTypeMerge.py +++ b/lib/core/Handles/HandlesTypeMerge.py @@ -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 diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index e0debfc..d29f5ea 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -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.`(与 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, diff --git a/lib/core/LLVMCG/MemoryOps.py b/lib/core/LLVMCG/MemoryOps.py index 1c0ee26..58ca8b6 100644 --- a/lib/core/LLVMCG/MemoryOps.py +++ b/lib/core/LLVMCG/MemoryOps.py @@ -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, diff --git a/lib/core/LLVMCG/StructGen.py b/lib/core/LLVMCG/StructGen.py index ebc34df..57281e3 100644 --- a/lib/core/LLVMCG/StructGen.py +++ b/lib/core/LLVMCG/StructGen.py @@ -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) diff --git a/lib/core/LLVMCG/TypeConvert.py b/lib/core/LLVMCG/TypeConvert.py index fda59f5..df744e3 100644 --- a/lib/core/LLVMCG/TypeConvert.py +++ b/lib/core/LLVMCG/TypeConvert.py @@ -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: diff --git a/lib/core/LLVMTypeMapper.py b/lib/core/LLVMTypeMapper.py index a6db97c..ef5396a 100644 --- a/lib/core/LLVMTypeMapper.py +++ b/lib/core/LLVMTypeMapper.py @@ -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}*' diff --git a/lib/core/SymbolTypeResolver.py b/lib/core/SymbolTypeResolver.py index e3dc8f2..b52648d 100644 --- a/lib/core/SymbolTypeResolver.py +++ b/lib/core/SymbolTypeResolver.py @@ -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 diff --git a/lib/core/SymbolUtils.py b/lib/core/SymbolUtils.py index 9f27b36..9ec8875 100644 --- a/lib/core/SymbolUtils.py +++ b/lib/core/SymbolUtils.py @@ -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` 的规则** 解析(跨模块类 → '.X'),再包一层指针——T 为类引用时该层被结构体 自身吸收('.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]` → '.X*';`rawptr[rawptr[X]]` → '.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('.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)) diff --git a/lib/core/Translator/LlvmGenerator.py b/lib/core/Translator/LlvmGenerator.py index 4b4359d..ab8f7e2 100644 --- a/lib/core/Translator/LlvmGenerator.py +++ b/lib/core/Translator/LlvmGenerator.py @@ -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): diff --git a/lib/core/Translator/PythonParser.py b/lib/core/Translator/PythonParser.py index 60188e2..cdac4ec 100644 --- a/lib/core/Translator/PythonParser.py +++ b/lib/core/Translator/PythonParser.py @@ -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,不要覆盖它 diff --git a/lib/core/TypeAnnotationResolver.py b/lib/core/TypeAnnotationResolver.py index ed7aaa9..b2fcec4 100644 --- a/lib/core/TypeAnnotationResolver.py +++ b/lib/core/TypeAnnotationResolver.py @@ -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)。 + + 使用 `名字: ` 形态而非 eval:注解位置的修饰前缀(const/volatile/ + static/export/extern/inline)与 C 风格指针后缀(`T*`)由解析器写成 + Markers / Subscript,从而与源码注解得到同一种 AST 表示。 + eval 回退仅用于极少数无法作为注解右值书写的表达式文本。 + """ + try: + tree: ast.AST = ast.parse( + f'__tpc_type__: {text}', '') + 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, '', mode='eval') body = getattr(expr_tree, 'body', None) diff --git a/lib/core/stub_generator.py b/lib/core/stub_generator.py index c4debbb..e5dc0a5 100644 --- a/lib/core/stub_generator.py +++ b/lib/core/stub_generator.py @@ -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('') diff --git a/lib/vast/ExprParser.py b/lib/vast/ExprParser.py index e75d580..de82adf 100644 --- a/lib/vast/ExprParser.py +++ b/lib/vast/ExprParser.py @@ -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()