diff --git a/lib/Projectrans/Config.py b/lib/Projectrans/Config.py index 7761fe0..0131672 100644 --- a/lib/Projectrans/Config.py +++ b/lib/Projectrans/Config.py @@ -147,6 +147,7 @@ def main() -> None: parser.add_argument('--run', action='store_true', help='编译成功后立即执行生成的可执行文件') parser.add_argument('--rebuild-includes', action='store_true', help='删除 includes.binary 预编译缓存并重新编译所有 includes') parser.add_argument('--clear-cache', action='store_true', help='清除 .transpyc_cache 全局缓存(.vpi/.stub.ll/.doc.json)') + parser.add_argument('--nowarn-register', action='store_true', help='抑制"外部函数返回类型未登记"类 WARN 输出(透传给自举编译的 TransPyV.exe)') args: argparse.Namespace = parser.parse_args() diff --git a/lib/Projectrans/DeclarationGenerator.py b/lib/Projectrans/DeclarationGenerator.py index 8449070..b887c5c 100644 --- a/lib/Projectrans/DeclarationGenerator.py +++ b/lib/Projectrans/DeclarationGenerator.py @@ -1,6 +1,6 @@ from __future__ import annotations -import ast +import vast as ast import re from typing import List @@ -214,85 +214,85 @@ class DeclarationGenerator: """递归检查类型注解中是否包含 CExport 或 t.State""" return bool(annotation) and (AnnotationContainsName(annotation, 'CExport') or AnnotationContainsName(annotation, 'State')) - def _generate_global_decl(self, node: ast.AnnAssign) -> str | None: - """生成全局变量声明""" - if not isinstance(node.target, ast.Name): - return None - var_name: str = node.target.id - if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine': - return None - if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': - return None - if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': - return None - if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': - return None - if isinstance(node.annotation, ast.List): - for elt in node.annotation.elts: - if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'): - return None - if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Attribute) and isinstance(elt.value.value, ast.Name) and elt.value.value.id == 't' and elt.value.attr == 'Callable': - return None - VarType: str = self._get_type_str(node.annotation) - if VarType.startswith('[0 x ') and node.value and isinstance(node.value, ast.List): - elem_type: str = VarType[5:-1] - actual_count: int = len(node.value.elts) - if actual_count > 0: - VarType = f'[{actual_count} x {elem_type}]' - return f'@{var_name} = external global {VarType}' - - def _generate_global_assign_decl(self, node: ast.Assign) -> str | None: - """从无类型标注赋值推断并生成全局变量声明""" - if not node.targets or not isinstance(node.targets[0], ast.Name): - return None - var_name: str = node.targets[0].id - VarType: str | None = self._infer_type(node.value) - if VarType: - return f'@{var_name} = external global {VarType}' - return None - - def _resolve_base_kind(self, base_name: str) -> str | None: - """解析基类名称的类型种类(支持别名) - - Returns: - 'enum' | 'union' | 'renum' | 'struct' | 'ctype_marker' | None - """ - # 1) 查 t 别名映射(from t import CEnum as en) - if base_name in self._t_alias_map: - t_cls: type = self._t_alias_map[base_name] - if issubclass(t_cls, (t.CEnum, t.REnum)): - return 'renum' if issubclass(t_cls, t.REnum) else 'enum' - if issubclass(t_cls, t.CUnion): - return 'union' - if issubclass(t_cls, t.CStruct): - return 'struct' - # CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记, - # 不应被编译为真实结构体,也不应被生成 stub 声明。 - if issubclass(t_cls, t.CType): - return 'ctype_marker' - - # 2) 直接查 t 模块属性 - t_cls: type | None = getattr(t, base_name, None) - if isinstance(t_cls, type) and issubclass(t_cls, t.CType): - if issubclass(t_cls, (t.CEnum, t.REnum)): - return 'renum' if issubclass(t_cls, t.REnum) else 'enum' - if issubclass(t_cls, t.CUnion): - return 'union' - if issubclass(t_cls, t.CStruct): - return 'struct' - # CType 及其子类是"类型强转"标记,不编译为结构体。 - return 'ctype_marker' - - return None - - def _is_marker_base(self, base_name: str) -> bool: - """检查是否为标记基类(Object/CVTable/Exception/CEnum/CUnion/CStruct/REnum 及其别名)""" - if base_name in ('Object', 'CVTable', 'Exception', 'CEnum', 'Enum', 'CStruct', 'CUnion', 'REnum'): - return True - if self._resolve_base_kind(base_name) is not None: - return True - return False - + def _generate_global_decl(self, node: ast.AnnAssign) -> str | None: + """生成全局变量声明""" + if not isinstance(node.target, ast.Name): + return None + var_name: str = node.target.id + if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine': + return None + if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': + return None + if isinstance(node.annotation, ast.Name) and node.annotation.id == 'CTypedef': + return None + if isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.left, ast.Attribute) and hasattr(node.annotation.left, 'attr') and node.annotation.left.attr == 'CTypedef': + return None + if isinstance(node.annotation, ast.List): + for elt in node.annotation.elts: + if isinstance(elt, ast.Attribute) and hasattr(elt, 'attr') and elt.attr in ('CTypedef', 'Callable'): + return None + if isinstance(elt, ast.Subscript) and isinstance(elt.value, ast.Attribute) and isinstance(elt.value.value, ast.Name) and elt.value.value.id == 't' and elt.value.attr == 'Callable': + return None + VarType: str = self._get_type_str(node.annotation) + if VarType.startswith('[0 x ') and node.value and isinstance(node.value, ast.List): + elem_type: str = VarType[5:-1] + actual_count: int = len(node.value.elts) + if actual_count > 0: + VarType = f'[{actual_count} x {elem_type}]' + return f'@{var_name} = external global {VarType}' + + def _generate_global_assign_decl(self, node: ast.Assign) -> str | None: + """从无类型标注赋值推断并生成全局变量声明""" + if not node.targets or not isinstance(node.targets[0], ast.Name): + return None + var_name: str = node.targets[0].id + VarType: str | None = self._infer_type(node.value) + if VarType: + return f'@{var_name} = external global {VarType}' + return None + + def _resolve_base_kind(self, base_name: str) -> str | None: + """解析基类名称的类型种类(支持别名) + + Returns: + 'enum' | 'union' | 'renum' | 'struct' | 'ctype_marker' | None + """ + # 1) 查 t 别名映射(from t import CEnum as en) + if base_name in self._t_alias_map: + t_cls: type = self._t_alias_map[base_name] + if issubclass(t_cls, (t.CEnum, t.REnum)): + return 'renum' if issubclass(t_cls, t.REnum) else 'enum' + if issubclass(t_cls, t.CUnion): + return 'union' + if issubclass(t_cls, t.CStruct): + return 'struct' + # CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记, + # 不应被编译为真实结构体,也不应被生成 stub 声明。 + if issubclass(t_cls, t.CType): + return 'ctype_marker' + + # 2) 直接查 t 模块属性 + t_cls: type | None = getattr(t, base_name, None) + if isinstance(t_cls, type) and issubclass(t_cls, t.CType): + if issubclass(t_cls, (t.CEnum, t.REnum)): + return 'renum' if issubclass(t_cls, t.REnum) else 'enum' + if issubclass(t_cls, t.CUnion): + return 'union' + if issubclass(t_cls, t.CStruct): + return 'struct' + # CType 及其子类是"类型强转"标记,不编译为结构体。 + return 'ctype_marker' + + return None + + def _is_marker_base(self, base_name: str) -> bool: + """检查是否为标记基类(Object/CVTable/Exception/CEnum/CUnion/CStruct/REnum 及其别名)""" + if base_name in ('Object', 'CVTable', 'Exception', 'CEnum', 'Enum', 'CStruct', 'CUnion', 'REnum'): + return True + if self._resolve_base_kind(base_name) is not None: + return True + return False + def _generate_class_decl(self, node: ast.ClassDef) -> List[str]: """生成结构体/类声明""" decls: list[str] = [] diff --git a/lib/Projectrans/Phase1Generator.py b/lib/Projectrans/Phase1Generator.py index ee8ec4e..8252959 100644 --- a/lib/Projectrans/Phase1Generator.py +++ b/lib/Projectrans/Phase1Generator.py @@ -1,7 +1,7 @@ from __future__ import annotations import os -import ast +import vast as ast import json import shutil import traceback diff --git a/lib/Projectrans/Phase2Translator.py b/lib/Projectrans/Phase2Translator.py index 53c3bb8..08b13cf 100644 --- a/lib/Projectrans/Phase2Translator.py +++ b/lib/Projectrans/Phase2Translator.py @@ -5,7 +5,7 @@ import os import re import shutil import subprocess -import ast +import vast as ast import traceback import json import pickle @@ -1730,7 +1730,7 @@ class Phase2Translator: for root, dirs, files in os.walk(includes_dir): dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] for fname in files: - if fname.endswith('.vp') or fname.endswith('.py'): + if fname.endswith('.vp') or fname.endswith('.py'): py_index.add(os.path.normcase(os.path.join(root, fname))) return py_index diff --git a/lib/Projectrans/Utils.py b/lib/Projectrans/Utils.py index 2bff1d0..830453a 100644 --- a/lib/Projectrans/Utils.py +++ b/lib/Projectrans/Utils.py @@ -2,7 +2,7 @@ from __future__ import annotations import hashlib import os -import ast +import vast as ast from lib.core.VLogger import get_logger as _vlog from lib.constants.config import mode as _ConfigMode diff --git a/lib/Shell/TransPyC.py b/lib/Shell/TransPyC.py index dea23a3..9872b3a 100644 --- a/lib/Shell/TransPyC.py +++ b/lib/Shell/TransPyC.py @@ -2,7 +2,7 @@ from __future__ import annotations import sys import os -import ast +import vast as ast import shlex import datetime import tempfile diff --git a/lib/StubGen/Converter.py b/lib/StubGen/Converter.py index d49665d..fa63741 100644 --- a/lib/StubGen/Converter.py +++ b/lib/StubGen/Converter.py @@ -1,1002 +1,1002 @@ -"""StubGen 转换器模块 - 将 Python 文件转换为存根格式""" -from __future__ import annotations -import ast -import re -import fnmatch -from typing import List, Dict -from lib.core.SymbolUtils import IsListAnnotation, ExpandSoftKeywords - - -class PythonToStubConverter: - """将 Python 文件转换为存根格式""" - - # __include 别名映射表 {alias: ModuleName} - IncludeAliasMap: Dict[str, str] = {} - - # 变量排除列表 - 匹配这些模式的变量不会被添加到存根文件 - VarExcludeList: List[str] = [] - - # 宏排除列表 - 匹配这些模式的宏不会被添加到存根文件 - MacroExcludeList: List[str] = [] - - @classmethod - def SetIncludeAliasMap(cls, alias_map: Dict[str, str]) -> None: - """设置 __include 别名映射表""" - cls.IncludeAliasMap = alias_map - - @classmethod - def SetVarExcludeList(cls, exclude_list: List[str]) -> None: - """设置变量排除列表""" - cls.VarExcludeList = exclude_list - - @classmethod - def SetMacroExcludeList(cls, exclude_list: List[str]) -> None: - """设置宏排除列表""" - cls.MacroExcludeList = exclude_list - - @classmethod - def _ShouldExcludeVar(cls, VarName: str) -> bool: - """检查变量是否应该被排除""" - for pattern in cls.VarExcludeList: - if fnmatch.fnmatch(VarName, pattern): - return True - return False - - @classmethod - def _ShouldExcludeMacro(cls, MacroName: str) -> bool: - """检查宏是否应该被排除""" - for pattern in cls.MacroExcludeList: - if fnmatch.fnmatch(MacroName, pattern): - return True - return False - - @staticmethod - def convert(PyContent: str, ModuleName: str) -> str: - """将 Python 代码转换为存根格式""" - # 软关键字展开:fn/fun/func/function -> def(行内等宽/更短,行号不变), - # 保证后续 ast.parse 与 SourceLines 回读行号一致。 - PyContent = ExpandSoftKeywords(PyContent) - lines: list[str] = PyContent.split('\n') - StubLines: list[str] = [] - - # 添加文件头 - StubLines.append('"""') - StubLines.append(f'Auto-generated Python stub file from {ModuleName}.vp') - StubLines.append(f'Module: {ModuleName}') - StubLines.append('"""') - StubLines.append('') - - # 解析 Python 代码,检查是否已经导入了 t 和 c - HasImportT: bool = False - HasImportC: bool = False - try: - tree: ast.Module = ast.parse(PyContent) - for node in tree.body: - if isinstance(node, ast.Import): - for alias in node.names: - if alias.name == 't': - HasImportT = True - elif alias.name == 'c': - HasImportC = True - except: - pass - - # 添加默认导入(如果源代码中没有) - if not HasImportT: - StubLines.append('import t') - if not HasImportC: - StubLines.append('import c') - if not HasImportT or not HasImportC: - StubLines.append('') - - # 添加 c.CPragma("once") - # StubLines.append('c.CPragma("once")') - StubLines.append('') - - # 生成文件级别宏守卫名称 - #FileGuardName = f'__{ModuleName.upper()}_DEFINE__' - - # 添加文件开头宏守卫 - #StubLines.append(f'c.CIfndef({FileGuardName})') - #StubLines.append(f'{FileGuardName}: t.CDefine') - #StubLines.append('') - - # 解析 Python 代码,提取类型定义 - try: - tree = ast.parse(PyContent) - - # 第一遍扫描:收集 Postdefinition 变量 - PostdefVars: dict[str, list[tuple[str, str, ast.AnnAssign]]] = {} # {ClassName: [(VarName, TypeStr, node), ...]} - for node in tree.body: - if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): - TypeStr: str = PythonToStubConverter._GetTypeString(node.annotation) - # 检查是否是 Postdefinition 类型 - if 't.Postdefinition' in TypeStr: - # 提取引用的类名 - ClassName: str | None = PythonToStubConverter._ExtractPostdefClass(node.annotation) - if ClassName: - if ClassName not in PostdefVars: - PostdefVars[ClassName] = [] - PostdefVars[ClassName].append((node.target.id, TypeStr, node)) - - # 按原始顺序处理节点,保持代码的原始顺序 - PrevType: str | None = None # 记录前一个节点的类型 - - for node in tree.body: - CurrentType: str | None = None - - if isinstance(node, ast.ClassDef): - CurrentType = 'class' - # 如果前一个不是类,添加空行分隔 - if PrevType is not None and PrevType != 'class': - StubLines.append('') - # 检查是否有对应的 Postdefinition 变量 - ClassPostdefs: list[tuple[str, str, ast.AnnAssign]] = PostdefVars.get(node.name, []) - ClassLines: list[str] = PythonToStubConverter._ConvertClass( - node, SourceLines=lines, PostdefVars=ClassPostdefs - ) - StubLines.extend(ClassLines) - elif isinstance(node, ast.FunctionDef): - CurrentType = 'function' - # 如果前一个是类或者是第一个函数,添加空行分隔 - if PrevType == 'class' or (PrevType is not None and PrevType != 'function'): - StubLines.append('') - FuncLines: list[str] = PythonToStubConverter._ConvertFunction(node, SourceLines=lines) - StubLines.extend(FuncLines) - StubLines.append('') # 函数后空行 - elif isinstance(node, ast.AnnAssign): - CurrentType = 'variable' - # 跳过 Postdefinition 变量(已经在类中处理) - TypeStr = PythonToStubConverter._GetTypeString(node.annotation) - if 't.Postdefinition' in TypeStr: - continue - # 检查是否带有 t.CStatic 标志,如果有则不排除 - HasStatic: bool = 't.CStatic' in TypeStr - # 检查变量是否应该被排除 - ShouldExclude: bool = False - if isinstance(node.target, ast.Name) and not HasStatic: - VarName: str = node.target.id - if PythonToStubConverter._ShouldExcludeVar(VarName): - ShouldExclude = True - if ShouldExclude: - continue - # 如果前一个不是变量,添加空行分隔 - if PrevType is not None and PrevType != 'variable': - StubLines.append('') - VarLines: list[str] = PythonToStubConverter._ConvertVariable(node, SourceLines=lines) - # 移除多余的空行 - VarLines = [line for line in VarLines if line.strip()] - StubLines.extend(VarLines) - elif isinstance(node, ast.Import): - # 处理导入语句 - CurrentType = 'import' - ImportStr: str = PythonToStubConverter._GetImportString(node, SourceLines=lines) - if ImportStr: - if PrevType is not None and PrevType != 'import': - StubLines.append('') - StubLines.append(ImportStr) - elif isinstance(node, ast.Assign): - CurrentType = 'variable' - # 处理模块级别的全局变量(无类型标注) - if PrevType is not None and PrevType != 'variable': - StubLines.append('') - AssignLines: list[str] = PythonToStubConverter._ConvertGlobalAssign(node) - StubLines.extend(AssignLines) - elif isinstance(node, ast.ImportFrom): - # 处理 from ... import ... 语句 - CurrentType = 'import' - ImportStr = PythonToStubConverter._GetImportFromString(node, SourceLines=lines) - if ImportStr: - if PrevType is not None and PrevType != 'import': - StubLines.append('') - StubLines.append(ImportStr) - elif isinstance(node, ast.Expr): - # 处理模块级别的宏调用,如 c.CIf(...), c.CEndif() - ExprStr: str = PythonToStubConverter._GetExprString(node.value) - if ExprStr: - CurrentType = 'macro' - StubLines.append(ExprStr) - StubLines.append('') # 宏后空行 - elif isinstance(node, ast.If): - # 处理模块级别的 if 宏条件,如 if c.CIf(FF_MULTI_PARTITION): - IfStr: str = PythonToStubConverter._GetModuleIfMacroString(node) - if IfStr: - CurrentType = 'macro' - StubLines.append(IfStr) - StubLines.append('') # 宏后空行 - - if CurrentType: - PrevType = CurrentType - - # 添加文件结尾宏守卫 - #StubLines.append('') - #StubLines.append('c.CEndif()') - - except SyntaxError as e: - # 语法错误直接终止(fail-fast),不允许生成残缺 stub 被全局缓存命中。 - # 残缺 vpi 只含 import 头,函数/类型声明全缺,会在后续阶段以 - # undefined symbol / mangle 错误形式爆发(如 ExpandKeywordsTest 链接失败)。 - raise - - return '\n'.join(StubLines) - - @staticmethod - def _ConvertClass(node: ast.ClassDef, SourceLines: list[str] | None = None, PostdefVars: list[tuple[str, str, ast.AnnAssign]] | None = None, indent: int = 0) -> list[str]: - """转换类定义 - - Args: - node: 类定义节点 - SourceLines: 源代码行列表 - PostdefVars: Postdefinition 变量列表 [(VarName, TypeStr, node), ...] - indent: 缩进级别(用于嵌套类) - """ - lines: list[str] = [] - PostdefVars = PostdefVars or [] - IndentStr: str = ' ' * indent - - # 处理类装饰器 - for decorator in node.decorator_list: - DecoratorStr: str = PythonToStubConverter._GetDecoratorString(decorator) - if DecoratorStr: - lines.append(f'{IndentStr}@{DecoratorStr}') - - # 检查是否是结构体、联合体或枚举 - BaseNames: list[str] = [base.attr if isinstance(base, ast.Attribute) else base.id - for base in node.bases - if isinstance(base, (ast.Name, ast.Attribute))] - - # 保留原始基类 - if node.bases: - BaseStrs: list[str] = [] - for base in node.bases: - if isinstance(base, ast.Name): - BaseStrs.append(base.id) - elif isinstance(base, ast.Attribute): - BaseStrs.append(f'{base.value.id}.{base.attr}') - elif isinstance(base, ast.Subscript): - # 处理泛型类型,如 memory_block_t[MAX_ORDER + 1] - BaseStrs.append(PythonToStubConverter._GetTypeString(base)) - ClassTypeParamStr: str = '' - if hasattr(node, 'type_params') and node.type_params: - param_names: list[str] = [tp.name for tp in node.type_params] - ClassTypeParamStr = f'[{", ".join(param_names)}]' - if BaseStrs: - lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}({", ".join(BaseStrs)}):') - else: - lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}:') - else: - ClassTypeParamStr = '' - if hasattr(node, 'type_params') and node.type_params: - param_names = [tp.name for tp in node.type_params] - ClassTypeParamStr = f'[{", ".join(param_names)}]' - lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}:') - - # 处理类成员 - HasMembers: bool = False - seen_member_names: set[str] = set() - for item in node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - seen_member_names.add(item.target.id) - init_members: list[ast.AnnAssign] = [] - for item in node.body: - if isinstance(item, ast.FunctionDef) and item.name == '__init__': - for stmt in item.body: - if (isinstance(stmt, ast.AnnAssign) - and isinstance(stmt.target, ast.Attribute) - and isinstance(stmt.target.value, ast.Name) - and stmt.target.value.id == 'self'): - init_members.append(stmt) - untyped_self_members: list[ast.Assign] = [] - for m_name in [m.target.attr for m in init_members if isinstance(m.target, ast.Attribute)]: - seen_member_names.add(m_name) - for item in node.body: - if isinstance(item, ast.FunctionDef): - for stmt in item.body: - if (isinstance(stmt, ast.Assign) - and len(stmt.targets) == 1 - and isinstance(stmt.targets[0], ast.Attribute) - and isinstance(stmt.targets[0].value, ast.Name) - and stmt.targets[0].value.id == 'self'): - attr_name: str = stmt.targets[0].attr - if attr_name not in seen_member_names: - seen_member_names.add(attr_name) - untyped_self_members.append(stmt) - for item in list(node.body) + init_members + untyped_self_members: - if isinstance(item, ast.Assign): - if (len(item.targets) == 1 - and isinstance(item.targets[0], ast.Attribute) - and isinstance(item.targets[0].value, ast.Name) - and item.targets[0].value.id == 'self'): - HasMembers = True - MemberIndent: str = IndentStr + ' ' - attr_name = item.targets[0].attr - if attr_name in seen_member_names: - continue - InferredType: str = 'int' - if item.value and isinstance(item.value, ast.Constant): - if isinstance(item.value.value, float): - InferredType = 'float' - elif isinstance(item.value.value, bool): - InferredType = 'bool' - elif isinstance(item.value.value, str): - InferredType = 'str' - lines.append(f'{MemberIndent}{attr_name}: {InferredType}') - else: - HasMembers = True - MemberIndent = IndentStr + ' ' - if SourceLines and hasattr(item, 'lineno'): - StartLine: int = item.lineno - 1 - EndLine: int = 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()) - elif isinstance(item, ast.AnnAssign): - HasMembers = True - TypeStr: str = PythonToStubConverter._GetTypeString(item.annotation) - MemberIndent = IndentStr + ' ' - # __provides__/__requires__/__require_must__ 元数据:保留值以便跨模块加载 - if isinstance(item.target, ast.Name) and item.target.id in ('__provides__', '__requires__', '__require_must__'): - if item.value is not None: - try: - value_str: str = ast.unparse(item.value) - except Exception: - value_str = '' - lines.append(f'{MemberIndent}{item.target.id}: {TypeStr} = {value_str}') - else: - lines.append(f'{MemberIndent}{item.target.id}: {TypeStr}') - continue - # 检查是否是宏变量(类型包含 t.CDefine) - if 't.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()) - else: - lines.append(f'{MemberIndent}{item.target.id}: {TypeStr}') - else: - if isinstance(item.target, ast.Attribute): - MemberName: str = item.target.attr - else: - MemberName = item.target.id - FinalTypeStr: str = TypeStr - if IsListAnnotation(item.annotation): - slice_node: ast.AST = item.annotation.slice - has_size: bool = False - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: - count_node: ast.AST = slice_node.elts[1] - if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int) and count_node.value > 0: - has_size = True - else: - try: - count_expr: str = ast.unparse(count_node) - except Exception: - count_expr = '' - if count_expr and count_expr != 'None': - has_size = True - elem_type_str: str = PythonToStubConverter._GetTypeString(slice_node.elts[0]) - FinalTypeStr = f't.CArray[{elem_type_str}, {count_expr}]' - if not has_size: - elem_type_str = PythonToStubConverter._GetTypeString(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0]) - init_len: int = 0 - if item.value is not None: - if isinstance(item.value, ast.List): - init_len = len(item.value.elts) - elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str): - init_len = len(item.value.value) + 1 - if init_len > 0: - FinalTypeStr = f't.CArray[{elem_type_str}, {init_len}]' - else: - FinalTypeStr = f't.CArray[{elem_type_str}, None]' - if item.value is not None and isinstance(item.value, ast.Constant): - try: - value_repr: str = ast.unparse(item.value) - lines.append(f'{MemberIndent}{MemberName}: {FinalTypeStr} = {value_repr}') - except Exception: - lines.append(f'{MemberIndent}{MemberName}: {FinalTypeStr}') - else: - lines.append(f'{MemberIndent}{MemberName}: {FinalTypeStr}') - elif isinstance(item, ast.FunctionDef): - HasMembers = True - FuncStub: list[str] = PythonToStubConverter._ConvertFunction(item, indent=indent+1, SourceLines=SourceLines, class_name=node.name) - lines.extend(FuncStub) - elif isinstance(item, ast.Expr): - # 处理宏调用,如 c.CIf(...), c.CEndif(), c.CElif(), c.CElse() - ExprStr: str = PythonToStubConverter._GetExprString(item.value) - if ExprStr: - lines.append(f'{IndentStr} {ExprStr}') - elif isinstance(item, ast.If): - # 处理 if c.CIf(...): 形式的宏条件 - IfStr: str = PythonToStubConverter._get_if_macro_string(item, indent=indent+1) - if IfStr: - lines.append(IfStr) - elif isinstance(item, ast.ClassDef): - # 处理嵌套类 - HasMembers = True - NestedClassLines: list[str] = PythonToStubConverter._ConvertClass(item, SourceLines=SourceLines, PostdefVars=[], indent=indent+1) - # 移除嵌套类的宏守卫(因为已经在父类的宏守卫内) - FilteredLines: list[str] = [] - for line in NestedClassLines: - # 跳过宏守卫相关行 - if line.strip().startswith('c.CIfndef(') or line.strip().startswith('c.CEndif()'): - continue - if ': t.CDefine' in line and '__' in line: - continue - FilteredLines.append(line) - lines.extend(FilteredLines) - - if not HasMembers: - lines.append(f'{IndentStr} pass') - - # 添加 Postdefinition 变量 - if PostdefVars: - lines.append('') - for VarName, TypeStr, _ in PostdefVars: - lines.append(f'{VarName}: {TypeStr}') - - return lines - - @staticmethod - def _ConvertFunction(node: ast.FunctionDef, indent: int = 0, SourceLines: list[str] | None = None, class_name: str | None = None) -> list[str]: - """转换函数定义""" - lines: list[str] = [] - IndentStr: str = ' ' * indent - - # 检查是否是宏函数(返回类型包含 t.CDefine) - is_macro_func: bool = False - if node.returns: - ReturnType: str = PythonToStubConverter._GetTypeString(node.returns) - if 't.CDefine' in ReturnType: - is_macro_func = True - - # 如果是宏函数,检查是否应该被排除 - if is_macro_func: - if PythonToStubConverter._ShouldExcludeMacro(node.name): - return lines # 返回空列表,排除该宏 - - # 保持原样(包括代码块) - if SourceLines: - 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]) - if lines and lines[-1].strip() and not lines[-1].rstrip().endswith(':'): - pass - else: - lines.append(f'{IndentStr} pass') - return lines - - # 处理函数装饰器 - for decorator in node.decorator_list: - DecoratorStr: str = PythonToStubConverter._GetDecoratorString(decorator) - if DecoratorStr: - lines.append(f'{IndentStr}@{DecoratorStr}') - - # 构建参数列表 - # 治本修复:原实现只遍历 node.args.args,完全忽略 node.args.defaults, - # 导致带默认值的参数(如 category: str = "")在 .pyi 中丢失默认值。 - # 下游 DeclarationGenerator 据此生成 stub.ll 时,会因缺少默认参数而 - # 生成参数数量不足的 declare,进而造成调用方 ABI 不匹配崩溃。 - # 修复:按 Python AST 语义,defaults 从右向左对应 args 末尾的参数, - # 对有默认值的参数附加 '= '。 - params: list[str] = [] - NumDefaults: int = len(node.args.defaults) if node.args.defaults else 0 - DefaultsStart: int = len(node.args.args) - NumDefaults - for arg_idx, arg in enumerate(node.args.args): - ArgName: str = arg.arg - if arg.annotation: - TypeStr: str = PythonToStubConverter._GetTypeString(arg.annotation) - ParamPart: str = f'{ArgName}: {TypeStr}' - elif class_name and arg_idx == 0 and ArgName == 'self': - ParamPart = f'self: {class_name}' - else: - ParamPart = ArgName - # 附加默认值:defaults[i] 对应 args[DefaultsStart + i] - if NumDefaults > 0 and arg_idx >= DefaultsStart: - DefaultIdx: int = arg_idx - DefaultsStart - try: - DefaultStr: str = ast.unparse(node.args.defaults[DefaultIdx]) - ParamPart = f'{ParamPart} = {DefaultStr}' - except Exception: - # unparse 失败时保留无默认值形式,避免阻塞生成 - pass - params.append(ParamPart) - - # 处理 *args - if node.args.vararg: - ArgName = node.args.vararg.arg - if node.args.vararg.annotation: - TypeStr = PythonToStubConverter._GetTypeString(node.args.vararg.annotation) - params.append(f'*{ArgName}: {TypeStr}') - else: - params.append(f'*{ArgName}') - - # 处理 **kwargs - if node.args.kwarg: - ArgName = node.args.kwarg.arg - if node.args.kwarg.annotation: - TypeStr = PythonToStubConverter._GetTypeString(node.args.kwarg.annotation) - params.append(f'**{ArgName}: {TypeStr}') - else: - params.append(f'**{ArgName}') - - ParamStr: str = ', '.join(params) - - # 返回类型 - 保持原始类型(不添加t.State) - if node.returns: - ReturnType = PythonToStubConverter._GetTypeString(node.returns) - else: - ReturnType = 't.CInt' - - TypeParamStr: str = '' - if hasattr(node, 'type_params') and node.type_params: - param_names: list[str] = [tp.name for tp in node.type_params] - TypeParamStr = f'[{", ".join(param_names)}]' - - lines.append(f'{IndentStr}def {node.name}{TypeParamStr}({ParamStr}) -> {ReturnType}: pass') - return lines - - @staticmethod - def _ConvertVariable(node: ast.AnnAssign, SourceLines: list[str] | None = None) -> list[str]: - """转换变量定义""" - lines: list[str] = [] - if isinstance(node.target, ast.Name): - VarName: str = node.target.id - TypeStr: str = PythonToStubConverter._GetTypeString(node.annotation) - # 检查是否是宏变量(类型包含 t.CDefine) - if 't.CDefine' in TypeStr: - # 检查宏变量是否应该被排除 - 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]) - else: - lines.append(f'{VarName}: {TypeStr}') - return lines - # 非宏变量:不加 t.State - # 含有 typedef 的变量不加 extern,普通变量需要加 extern - has_typedef: bool = 't.CTypedef' in TypeStr or 'CTypedef' in TypeStr - if has_typedef and node.value is not None: - ValueTypeStr: str = PythonToStubConverter._GetTypeString(node.value) - lines.append(f'{VarName}: {TypeStr} = {ValueTypeStr}') - else: - if not has_typedef and 't.CExtern' not in TypeStr and 't.CStatic' not in TypeStr: - TypeStr = f't.CExtern | {TypeStr}' - lines.append(f'{VarName}: {TypeStr}') - return lines - - @staticmethod - def _ConvertGlobalAssign(node: ast.Assign) -> list[str]: - """转换模块级别的全局变量(无类型标注)""" - lines: list[str] = [] - if not node.targets or not isinstance(node.targets[0], ast.Name): - return lines - - VarName: str = node.targets[0].id - - # 跳过私有变量(以下划线开头) - if VarName.startswith('_'): - return lines - - # 从值推断类型 - inferred_type: str | None = PythonToStubConverter._InferTypeFromValue(node.value) - if inferred_type: - lines.append(f'{VarName}: {inferred_type}') - else: - lines.append(f'{VarName}: t.CInt') - - return lines - - @staticmethod - def _InferTypeFromValue(value: ast.AST) -> str | None: - """从值推断 C 类型""" - if isinstance(value, ast.Constant): - if isinstance(value.value, int): - return 't.CInt' - elif isinstance(value.value, float): - return 't.CDouble' - elif isinstance(value.value, str): - return 't.CCharPtr' - elif isinstance(value.value, bool): - return 't.CInt' - elif isinstance(value, ast.List): - return 't.CVoidPtr' - elif isinstance(value, ast.Dict): - return 't.CVoidPtr' - elif isinstance(value, ast.Name): - return 't.CInt' - elif isinstance(value, ast.BinOp): - left_type: str | None = PythonToStubConverter._InferTypeFromValue(value.left) - if left_type: - return left_type - return 't.CInt' - elif isinstance(value, ast.Call): - # 函数调用返回值,假设为指针类型 - if isinstance(value.func, ast.Name): - func_name: str = value.func.id - if func_name == 'malloc': - return 't.CVoidPtr' - elif func_name in ('ctypes.cast', 'cast'): - return 't.CVoidPtr' - return 't.CVoidPtr' - return None - - @staticmethod - def _GetTypeString(annotation: ast.AST) -> str: - """获取类型字符串""" - if isinstance(annotation, ast.Name): - return annotation.id - elif isinstance(annotation, ast.Attribute): - if isinstance(annotation.value, ast.Name): - return f'{annotation.value.id}.{annotation.attr}' - else: - # 处理嵌套属性访问,如 t.attr.packed - ParentStr: str = PythonToStubConverter._GetTypeString(annotation.value) - return f'{ParentStr}.{annotation.attr}' - elif isinstance(annotation, ast.Subscript): - 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] - SliceStr: str = ', '.join(slice_strs) - else: - SliceStr = PythonToStubConverter._GetTypeString(annotation.slice) - return f'{base}[{SliceStr}]' - elif isinstance(annotation, ast.BinOp): - # 处理 BinOp,如 t.CExtern | fd_table.__set_default__(...) - left: ast.AST = annotation.left - right: ast.AST = annotation.right - - # 检查右侧是否是 __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): - return f'{LeftStr} + {RightStr}' - elif isinstance(annotation.op, ast.Sub): - return f'{LeftStr} - {RightStr}' - elif isinstance(annotation.op, ast.Mult): - return f'{LeftStr} * {RightStr}' - elif isinstance(annotation.op, ast.Div): - return f'{LeftStr} / {RightStr}' - elif isinstance(annotation.op, ast.Mod): - return f'{LeftStr} % {RightStr}' - elif isinstance(annotation, ast.UnaryOp): - if isinstance(annotation.op, ast.Not): - operand: str = PythonToStubConverter._GetTypeString(annotation.operand) - return f'not {operand}' - elif isinstance(annotation.op, ast.Invert): - operand = PythonToStubConverter._GetTypeString(annotation.operand) - return f'~{operand}' - elif isinstance(annotation.op, ast.USub): - operand = PythonToStubConverter._GetTypeString(annotation.operand) - return f'-{operand}' - elif isinstance(annotation, ast.Compare): - # 处理比较操作,如 FF_MAX_SS != FF_MIN_SS - left: str = PythonToStubConverter._GetTypeString(annotation.left) - comparators: list[str] = [PythonToStubConverter._GetTypeString(c) for c in annotation.comparators] - ops: list[str] = [] - for op in annotation.ops: - if isinstance(op, ast.Eq): - ops.append('==') - elif isinstance(op, ast.NotEq): - ops.append('!=') - elif isinstance(op, ast.Lt): - ops.append('<') - elif isinstance(op, ast.LtE): - ops.append('<=') - elif isinstance(op, ast.Gt): - ops.append('>') - elif isinstance(op, ast.GtE): - ops.append('>=') - else: - ops.append('?') - result: str = left - for i, op in enumerate(ops): - result += f' {op} {comparators[i]}' - return result - elif isinstance(annotation, ast.Constant): - return repr(annotation.value) - elif isinstance(annotation, ast.Index): - return PythonToStubConverter._GetTypeString(annotation.value) - elif isinstance(annotation, ast.List): - # 处理列表,如 [MAX_FILE_DESCRIPTORS] - elements: list[str] = [PythonToStubConverter._GetTypeString(elem) for elem in annotation.elts] - return f'[{", ".join(elements)}]' - elif isinstance(annotation, ast.Call): - # 处理函数调用形式的类型注解,如 t.Postdefinition(xxa) 或 callable(t.CVoid, app_id = t.CInt) - # 如果是 __set_default__ 调用,只返回函数名部分 - if isinstance(annotation.func, ast.Attribute) and annotation.func.attr in ('__set_default__', '__set_default'): - return PythonToStubConverter._GetTypeString(annotation.func.value) - - FuncStr: str = PythonToStubConverter._GetTypeString(annotation.func) - ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in annotation.args]) - # 处理关键字参数 - keywords_str: str = ', '.join([f'{kw.arg} = {PythonToStubConverter._GetTypeString(kw.value)}' for kw in annotation.keywords]) - # 合并位置参数和关键字参数 - if ArgsStr and keywords_str: - return f'{FuncStr}({ArgsStr}, {keywords_str})' - elif keywords_str: - return f'{FuncStr}({keywords_str})' - else: - return f'{FuncStr}({ArgsStr})' - return 't.CVoid' - - @staticmethod - def _ExtractPostdefClass(annotation: ast.AST) -> str | None: - """从 Postdefinition 类型注解中提取类名 - - 例如:t.Postdefinition(__buddy_system) -> '__buddy_system' - t.Postdefinition(xxx) | t.CTypedef -> 'xxx' - """ - # 处理 BinOp (如: t.Postdefinition(xxx) | t.CTypedef) - 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 - return None - - # 处理函数调用 (如: t.Postdefinition(__buddy_system)) - if isinstance(annotation, ast.Call): - FuncStr: str = PythonToStubConverter._GetTypeString(annotation.func) - if FuncStr == 't.Postdefinition' and annotation.args: - # 提取第一个参数 - first_arg: ast.AST = annotation.args[0] - if isinstance(first_arg, ast.Name): - return first_arg.id - elif isinstance(first_arg, ast.Attribute): - return f'{first_arg.value.id}.{first_arg.attr}' - - return None - - @staticmethod - def _GetImportString(node: ast.Import, SourceLines: list[str] | None = None) -> str: - """获取导入语句字符串""" - parts: list[str] = [] - IncludeAliasMap: dict[str, str] = PythonToStubConverter.IncludeAliasMap - - for alias in node.names: - ModuleName: str = alias.name - # 检查是否是 __include.xxx 格式的导入 - if ModuleName.startswith('__include.'): - # 提取别名(xxx 部分) - SubModule: str = ModuleName[len('__include.'):] - if SubModule in IncludeAliasMap: - # 替换为实际模块路径 - RealModule: str = IncludeAliasMap[SubModule] - if alias.asname: - parts.append(f'{RealModule} as {alias.asname}') - else: - parts.append(f'{RealModule} as {SubModule}') - else: - # 不在映射表中,保持原样 - if alias.asname: - parts.append(f'{ModuleName} as {alias.asname}') - else: - parts.append(ModuleName) - else: - if alias.asname: - parts.append(f'{alias.name} as {alias.asname}') - else: - parts.append(alias.name) - - result: str = f'import {", ".join(parts)}' - - # 提取并保留注释 - if SourceLines and hasattr(node, 'lineno'): - LineIdx: int = node.lineno - 1 - if 0 <= LineIdx < len(SourceLines): - line: str = SourceLines[LineIdx] - CommentMatch: re.Match | None = re.search(r'#.*$', line) - if CommentMatch: - result += ' ' + CommentMatch.group(0) - - return result - - @staticmethod - def _GetImportFromString(node: ast.ImportFrom, SourceLines: list[str] | None = None) -> str: - """获取 from ... import ... 语句字符串""" - module: str = node.module or '' - parts: list[str] = [] - IncludeAliasMap: dict[str, str] = PythonToStubConverter.IncludeAliasMap - - # 处理相对导入 (from . import xxx 或 from ..package import xxx) - if node.level > 0: - if module: - if node.level == 1: - full_module: str = f'.{module}' - else: - full_module = '.' * node.level + module - else: - full_module = '.' * node.level - for alias in node.names: - if alias.asname: - parts.append(f'{alias.name} as {alias.asname}') - else: - parts.append(alias.name) - return f'from {full_module} import {", ".join(parts)}' - - # 提取注释(在生成结果前获取) - comment: str = '' - if SourceLines and hasattr(node, 'lineno'): - LineIdx = node.lineno - 1 - if 0 <= LineIdx < len(SourceLines): - line = SourceLines[LineIdx] - CommentMatch: re.Match | None = re.search(r'#.*$', line) - if CommentMatch: - comment = ' ' + CommentMatch.group(0) - - # 检查是否是 from __include import xxx 格式 - if module == '__include': - for alias in node.names: - name: str = alias.name - if name in IncludeAliasMap: - # 替换为实际模块路径 - RealModule: str = IncludeAliasMap[name] - if alias.asname: - parts.append(f'import {RealModule} as {alias.asname}{comment}') - else: - parts.append(f'import {RealModule} as {name}{comment}') - else: - # 不在映射表中,保持原样 - if alias.asname: - parts.append(f'from {module} import {name} as {alias.asname}{comment}') - else: - parts.append(f'from {module} import {name}{comment}') - return '\n'.join(parts) - - # 普通 from ... import ... 语句 - for alias in node.names: - if alias.asname: - parts.append(f'{alias.name} as {alias.asname}') - else: - parts.append(alias.name) - return f'from {module} import {", ".join(parts)}{comment}' - - @staticmethod - def _GetDecoratorString(decorator: ast.AST) -> str: - """获取装饰器字符串""" - if isinstance(decorator, ast.Name): - return decorator.id - elif isinstance(decorator, ast.Attribute): - if isinstance(decorator.value, ast.Name): - return f'{decorator.value.id}.{decorator.attr}' - return decorator.attr - elif isinstance(decorator, ast.Call): - # 处理带参数的装饰器,如 @c.Attribute(t.attr.packed) - FuncStr: str = PythonToStubConverter._GetDecoratorString(decorator.func) - ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in decorator.args]) - return f'{FuncStr}({ArgsStr})' - return '' - - @staticmethod - def _GetExprString(expr: ast.AST) -> str: - """获取表达式字符串(用于宏调用)""" - if isinstance(expr, ast.Call): - # 处理函数调用,如 c.CIf(...), c.CEndif(), c.CUndef(...), c.CPragma(...) - FuncStr: str = PythonToStubConverter._GetDecoratorString(expr.func) - if FuncStr and ('CIf' in FuncStr or 'CEndif' in FuncStr or 'CElif' in FuncStr or 'CElse' in FuncStr or 'CUndef' in FuncStr or 'CPragma' in FuncStr): - ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in expr.args]) - return f'{FuncStr}({ArgsStr})' if ArgsStr else f'{FuncStr}()' - return '' - - @staticmethod - def _get_if_macro_string(node: ast.If, indent: int = 1) -> str: - """获取类内部的 if 宏字符串(如 if c.CIf(...):)""" - IndentStr: str = ' ' * indent - InnerIndent: str = ' ' * (indent + 1) - # 检查条件是否是宏调用 - if isinstance(node.test, ast.Call): - FuncStr: str = PythonToStubConverter._GetDecoratorString(node.test.func) - if FuncStr and 'CIf' in FuncStr: - ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args]) - result: list[str] = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():'] - # 处理 if 体内的语句 - for item in node.body: - if isinstance(item, ast.AnnAssign): - TypeStr: str = PythonToStubConverter._GetTypeString(item.annotation) - result.append(f'{InnerIndent}{item.target.id}: {TypeStr}') - elif isinstance(item, ast.Expr): - ExprStr: str = PythonToStubConverter._GetExprString(item.value) - if ExprStr: - result.append(f'{InnerIndent}{ExprStr}') - return '\n'.join(result) - return '' - - @staticmethod - def _GetModuleIfMacroString(node: ast.If) -> str: - """获取模块级别的 if 宏字符串(如 if c.CIf(FF_MULTI_PARTITION):)""" - return PythonToStubConverter._ProcessIfMacro(node, indent=0) - - @staticmethod - def _ProcessIfMacro(node: ast.If, indent: int = 0) -> str: - """处理 if 宏节点,支持 elif 和 else""" - IndentStr: str = ' ' * indent - - # 检查条件是否是宏调用 - if isinstance(node.test, ast.Call): - FuncStr: str = PythonToStubConverter._GetDecoratorString(node.test.func) - if FuncStr and 'CIf' in FuncStr: - ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args]) - result: list[str] = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():'] - # 处理 if 体内的语句 - for item in node.body: - result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) - - # 处理 elif 和 else - current: ast.If = node - while current.orelse: - if len(current.orelse) == 1 and isinstance(current.orelse[0], ast.If): - # elif 情况 - elif_node: ast.If = current.orelse[0] - if isinstance(elif_node.test, ast.Call): - ElifFuncStr: str = PythonToStubConverter._GetDecoratorString(elif_node.test.func) - if ElifFuncStr and 'CIf' in ElifFuncStr: - ElifArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in elif_node.test.args]) - result.append(f'{IndentStr}elif {ElifFuncStr}({ElifArgsStr}):' if ElifArgsStr else f'{IndentStr}elif {ElifFuncStr}():') - for item in elif_node.body: - result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) - current = elif_node - continue - break - else: - # else 情况 - result.append(f'{IndentStr}else:') - for item in current.orelse: - result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) - break - - return '\n'.join(result) - return '' - - @staticmethod - def _ProcessMacroBodyItem(item: ast.AST, indent: int = 0) -> list[str]: - """处理宏体内的单个语句""" - IndentStr: str = ' ' * indent - result: list[str] = [] - - if isinstance(item, ast.ClassDef): - class_stub: list[str] = PythonToStubConverter._ConvertClass(item) - for line in class_stub: - if line.strip(): - result.append(f'{IndentStr}{line}') - else: - result.append(line) - elif isinstance(item, ast.FunctionDef): - FuncStub: list[str] = PythonToStubConverter._ConvertFunction(item, indent=indent) - result.extend(FuncStub) - elif isinstance(item, ast.AnnAssign): - TypeStr: str = PythonToStubConverter._GetTypeString(item.annotation) - result.append(f'{IndentStr}{item.target.id}: {TypeStr}') - elif isinstance(item, ast.Expr): - ExprStr: str = PythonToStubConverter._GetExprString(item.value) - if ExprStr: - result.append(f'{IndentStr}{ExprStr}') - elif isinstance(item, ast.If): - # 处理嵌套的 if 宏 - NestedIf: str = PythonToStubConverter._ProcessIfMacro(item, indent=indent) - if NestedIf: - result.append(NestedIf) - +"""StubGen 转换器模块 - 将 Python 文件转换为存根格式""" +from __future__ import annotations +import vast as ast +import re +import fnmatch +from typing import List, Dict +from lib.core.SymbolUtils import IsListAnnotation, ExpandSoftKeywords + + +class PythonToStubConverter: + """将 Python 文件转换为存根格式""" + + # __include 别名映射表 {alias: ModuleName} + IncludeAliasMap: Dict[str, str] = {} + + # 变量排除列表 - 匹配这些模式的变量不会被添加到存根文件 + VarExcludeList: List[str] = [] + + # 宏排除列表 - 匹配这些模式的宏不会被添加到存根文件 + MacroExcludeList: List[str] = [] + + @classmethod + def SetIncludeAliasMap(cls, alias_map: Dict[str, str]) -> None: + """设置 __include 别名映射表""" + cls.IncludeAliasMap = alias_map + + @classmethod + def SetVarExcludeList(cls, exclude_list: List[str]) -> None: + """设置变量排除列表""" + cls.VarExcludeList = exclude_list + + @classmethod + def SetMacroExcludeList(cls, exclude_list: List[str]) -> None: + """设置宏排除列表""" + cls.MacroExcludeList = exclude_list + + @classmethod + def _ShouldExcludeVar(cls, VarName: str) -> bool: + """检查变量是否应该被排除""" + for pattern in cls.VarExcludeList: + if fnmatch.fnmatch(VarName, pattern): + return True + return False + + @classmethod + def _ShouldExcludeMacro(cls, MacroName: str) -> bool: + """检查宏是否应该被排除""" + for pattern in cls.MacroExcludeList: + if fnmatch.fnmatch(MacroName, pattern): + return True + return False + + @staticmethod + def convert(PyContent: str, ModuleName: str) -> str: + """将 Python 代码转换为存根格式""" + # 软关键字展开:fn/fun/func/function -> def(行内等宽/更短,行号不变), + # 保证后续 ast.parse 与 SourceLines 回读行号一致。 + PyContent = ExpandSoftKeywords(PyContent) + lines: list[str] = PyContent.split('\n') + StubLines: list[str] = [] + + # 添加文件头 + StubLines.append('"""') + StubLines.append(f'Auto-generated Python stub file from {ModuleName}.vp') + StubLines.append(f'Module: {ModuleName}') + StubLines.append('"""') + StubLines.append('') + + # 解析 Python 代码,检查是否已经导入了 t 和 c + HasImportT: bool = False + HasImportC: bool = False + try: + tree: ast.Module = ast.parse(PyContent) + for node in tree.body: + if isinstance(node, ast.Import): + for alias in node.names: + if alias.name == 't': + HasImportT = True + elif alias.name == 'c': + HasImportC = True + except: + pass + + # 添加默认导入(如果源代码中没有) + if not HasImportT: + StubLines.append('import t') + if not HasImportC: + StubLines.append('import c') + if not HasImportT or not HasImportC: + StubLines.append('') + + # 添加 c.CPragma("once") + # StubLines.append('c.CPragma("once")') + StubLines.append('') + + # 生成文件级别宏守卫名称 + #FileGuardName = f'__{ModuleName.upper()}_DEFINE__' + + # 添加文件开头宏守卫 + #StubLines.append(f'c.CIfndef({FileGuardName})') + #StubLines.append(f'{FileGuardName}: t.CDefine') + #StubLines.append('') + + # 解析 Python 代码,提取类型定义 + try: + tree = ast.parse(PyContent) + + # 第一遍扫描:收集 Postdefinition 变量 + PostdefVars: dict[str, list[tuple[str, str, ast.AnnAssign]]] = {} # {ClassName: [(VarName, TypeStr, node), ...]} + for node in tree.body: + if isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): + TypeStr: str = PythonToStubConverter._GetTypeString(node.annotation) + # 检查是否是 Postdefinition 类型 + if 't.Postdefinition' in TypeStr: + # 提取引用的类名 + ClassName: str | None = PythonToStubConverter._ExtractPostdefClass(node.annotation) + if ClassName: + if ClassName not in PostdefVars: + PostdefVars[ClassName] = [] + PostdefVars[ClassName].append((node.target.id, TypeStr, node)) + + # 按原始顺序处理节点,保持代码的原始顺序 + PrevType: str | None = None # 记录前一个节点的类型 + + for node in tree.body: + CurrentType: str | None = None + + if isinstance(node, ast.ClassDef): + CurrentType = 'class' + # 如果前一个不是类,添加空行分隔 + if PrevType is not None and PrevType != 'class': + StubLines.append('') + # 检查是否有对应的 Postdefinition 变量 + ClassPostdefs: list[tuple[str, str, ast.AnnAssign]] = PostdefVars.get(node.name, []) + ClassLines: list[str] = PythonToStubConverter._ConvertClass( + node, SourceLines=lines, PostdefVars=ClassPostdefs + ) + StubLines.extend(ClassLines) + elif isinstance(node, ast.FunctionDef): + CurrentType = 'function' + # 如果前一个是类或者是第一个函数,添加空行分隔 + if PrevType == 'class' or (PrevType is not None and PrevType != 'function'): + StubLines.append('') + FuncLines: list[str] = PythonToStubConverter._ConvertFunction(node, SourceLines=lines) + StubLines.extend(FuncLines) + StubLines.append('') # 函数后空行 + elif isinstance(node, ast.AnnAssign): + CurrentType = 'variable' + # 跳过 Postdefinition 变量(已经在类中处理) + TypeStr = PythonToStubConverter._GetTypeString(node.annotation) + if 't.Postdefinition' in TypeStr: + continue + # 检查是否带有 t.CStatic 标志,如果有则不排除 + HasStatic: bool = 't.CStatic' in TypeStr + # 检查变量是否应该被排除 + ShouldExclude: bool = False + if isinstance(node.target, ast.Name) and not HasStatic: + VarName: str = node.target.id + if PythonToStubConverter._ShouldExcludeVar(VarName): + ShouldExclude = True + if ShouldExclude: + continue + # 如果前一个不是变量,添加空行分隔 + if PrevType is not None and PrevType != 'variable': + StubLines.append('') + VarLines: list[str] = PythonToStubConverter._ConvertVariable(node, SourceLines=lines) + # 移除多余的空行 + VarLines = [line for line in VarLines if line.strip()] + StubLines.extend(VarLines) + elif isinstance(node, ast.Import): + # 处理导入语句 + CurrentType = 'import' + ImportStr: str = PythonToStubConverter._GetImportString(node, SourceLines=lines) + if ImportStr: + if PrevType is not None and PrevType != 'import': + StubLines.append('') + StubLines.append(ImportStr) + elif isinstance(node, ast.Assign): + CurrentType = 'variable' + # 处理模块级别的全局变量(无类型标注) + if PrevType is not None and PrevType != 'variable': + StubLines.append('') + AssignLines: list[str] = PythonToStubConverter._ConvertGlobalAssign(node) + StubLines.extend(AssignLines) + elif isinstance(node, ast.ImportFrom): + # 处理 from ... import ... 语句 + CurrentType = 'import' + ImportStr = PythonToStubConverter._GetImportFromString(node, SourceLines=lines) + if ImportStr: + if PrevType is not None and PrevType != 'import': + StubLines.append('') + StubLines.append(ImportStr) + elif isinstance(node, ast.Expr): + # 处理模块级别的宏调用,如 c.CIf(...), c.CEndif() + ExprStr: str = PythonToStubConverter._GetExprString(node.value) + if ExprStr: + CurrentType = 'macro' + StubLines.append(ExprStr) + StubLines.append('') # 宏后空行 + elif isinstance(node, ast.If): + # 处理模块级别的 if 宏条件,如 if c.CIf(FF_MULTI_PARTITION): + IfStr: str = PythonToStubConverter._GetModuleIfMacroString(node) + if IfStr: + CurrentType = 'macro' + StubLines.append(IfStr) + StubLines.append('') # 宏后空行 + + if CurrentType: + PrevType = CurrentType + + # 添加文件结尾宏守卫 + #StubLines.append('') + #StubLines.append('c.CEndif()') + + except SyntaxError as e: + # 语法错误直接终止(fail-fast),不允许生成残缺 stub 被全局缓存命中。 + # 残缺 vpi 只含 import 头,函数/类型声明全缺,会在后续阶段以 + # undefined symbol / mangle 错误形式爆发(如 ExpandKeywordsTest 链接失败)。 + raise + + return '\n'.join(StubLines) + + @staticmethod + def _ConvertClass(node: ast.ClassDef, SourceLines: list[str] | None = None, PostdefVars: list[tuple[str, str, ast.AnnAssign]] | None = None, indent: int = 0) -> list[str]: + """转换类定义 + + Args: + node: 类定义节点 + SourceLines: 源代码行列表 + PostdefVars: Postdefinition 变量列表 [(VarName, TypeStr, node), ...] + indent: 缩进级别(用于嵌套类) + """ + lines: list[str] = [] + PostdefVars = PostdefVars or [] + IndentStr: str = ' ' * indent + + # 处理类装饰器 + for decorator in node.decorator_list: + DecoratorStr: str = PythonToStubConverter._GetDecoratorString(decorator) + if DecoratorStr: + lines.append(f'{IndentStr}@{DecoratorStr}') + + # 检查是否是结构体、联合体或枚举 + BaseNames: list[str] = [base.attr if isinstance(base, ast.Attribute) else base.id + for base in node.bases + if isinstance(base, (ast.Name, ast.Attribute))] + + # 保留原始基类 + if node.bases: + BaseStrs: list[str] = [] + for base in node.bases: + if isinstance(base, ast.Name): + BaseStrs.append(base.id) + elif isinstance(base, ast.Attribute): + BaseStrs.append(f'{base.value.id}.{base.attr}') + elif isinstance(base, ast.Subscript): + # 处理泛型类型,如 memory_block_t[MAX_ORDER + 1] + BaseStrs.append(PythonToStubConverter._GetTypeString(base)) + ClassTypeParamStr: str = '' + if hasattr(node, 'type_params') and node.type_params: + param_names: list[str] = [tp.name for tp in node.type_params] + ClassTypeParamStr = f'[{", ".join(param_names)}]' + if BaseStrs: + lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}({", ".join(BaseStrs)}):') + else: + lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}:') + else: + ClassTypeParamStr = '' + if hasattr(node, 'type_params') and node.type_params: + param_names = [tp.name for tp in node.type_params] + ClassTypeParamStr = f'[{", ".join(param_names)}]' + lines.append(f'{IndentStr}class {node.name}{ClassTypeParamStr}:') + + # 处理类成员 + HasMembers: bool = False + seen_member_names: set[str] = set() + for item in node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + seen_member_names.add(item.target.id) + init_members: list[ast.AnnAssign] = [] + for item in node.body: + if isinstance(item, ast.FunctionDef) and item.name == '__init__': + for stmt in item.body: + if (isinstance(stmt, ast.AnnAssign) + and isinstance(stmt.target, ast.Attribute) + and isinstance(stmt.target.value, ast.Name) + and stmt.target.value.id == 'self'): + init_members.append(stmt) + untyped_self_members: list[ast.Assign] = [] + for m_name in [m.target.attr for m in init_members if isinstance(m.target, ast.Attribute)]: + seen_member_names.add(m_name) + for item in node.body: + if isinstance(item, ast.FunctionDef): + for stmt in item.body: + if (isinstance(stmt, ast.Assign) + and len(stmt.targets) == 1 + and isinstance(stmt.targets[0], ast.Attribute) + and isinstance(stmt.targets[0].value, ast.Name) + and stmt.targets[0].value.id == 'self'): + attr_name: str = stmt.targets[0].attr + if attr_name not in seen_member_names: + seen_member_names.add(attr_name) + untyped_self_members.append(stmt) + for item in list(node.body) + init_members + untyped_self_members: + if isinstance(item, ast.Assign): + if (len(item.targets) == 1 + and isinstance(item.targets[0], ast.Attribute) + and isinstance(item.targets[0].value, ast.Name) + and item.targets[0].value.id == 'self'): + HasMembers = True + MemberIndent: str = IndentStr + ' ' + attr_name = item.targets[0].attr + if attr_name in seen_member_names: + continue + InferredType: str = 'int' + if item.value and isinstance(item.value, ast.Constant): + if isinstance(item.value.value, float): + InferredType = 'float' + elif isinstance(item.value.value, bool): + InferredType = 'bool' + elif isinstance(item.value.value, str): + InferredType = 'str' + lines.append(f'{MemberIndent}{attr_name}: {InferredType}') + else: + HasMembers = True + MemberIndent = IndentStr + ' ' + if SourceLines and hasattr(item, 'lineno'): + StartLine: int = item.lineno - 1 + EndLine: int = 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()) + elif isinstance(item, ast.AnnAssign): + HasMembers = True + TypeStr: str = PythonToStubConverter._GetTypeString(item.annotation) + MemberIndent = IndentStr + ' ' + # __provides__/__requires__/__require_must__ 元数据:保留值以便跨模块加载 + if isinstance(item.target, ast.Name) and item.target.id in ('__provides__', '__requires__', '__require_must__'): + if item.value is not None: + try: + value_str: str = ast.unparse(item.value) + except Exception: + value_str = '' + lines.append(f'{MemberIndent}{item.target.id}: {TypeStr} = {value_str}') + else: + lines.append(f'{MemberIndent}{item.target.id}: {TypeStr}') + continue + # 检查是否是宏变量(类型包含 t.CDefine) + if 't.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()) + else: + lines.append(f'{MemberIndent}{item.target.id}: {TypeStr}') + else: + if isinstance(item.target, ast.Attribute): + MemberName: str = item.target.attr + else: + MemberName = item.target.id + FinalTypeStr: str = TypeStr + if IsListAnnotation(item.annotation): + slice_node: ast.AST = item.annotation.slice + has_size: bool = False + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + count_node: ast.AST = slice_node.elts[1] + if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int) and count_node.value > 0: + has_size = True + else: + try: + count_expr: str = ast.unparse(count_node) + except Exception: + count_expr = '' + if count_expr and count_expr != 'None': + has_size = True + elem_type_str: str = PythonToStubConverter._GetTypeString(slice_node.elts[0]) + FinalTypeStr = f't.CArray[{elem_type_str}, {count_expr}]' + if not has_size: + elem_type_str = PythonToStubConverter._GetTypeString(slice_node if not isinstance(slice_node, ast.Tuple) else slice_node.elts[0]) + init_len: int = 0 + if item.value is not None: + if isinstance(item.value, ast.List): + init_len = len(item.value.elts) + elif isinstance(item.value, ast.Constant) and isinstance(item.value.value, str): + init_len = len(item.value.value) + 1 + if init_len > 0: + FinalTypeStr = f't.CArray[{elem_type_str}, {init_len}]' + else: + FinalTypeStr = f't.CArray[{elem_type_str}, None]' + if item.value is not None and isinstance(item.value, ast.Constant): + try: + value_repr: str = ast.unparse(item.value) + lines.append(f'{MemberIndent}{MemberName}: {FinalTypeStr} = {value_repr}') + except Exception: + lines.append(f'{MemberIndent}{MemberName}: {FinalTypeStr}') + else: + lines.append(f'{MemberIndent}{MemberName}: {FinalTypeStr}') + elif isinstance(item, ast.FunctionDef): + HasMembers = True + FuncStub: list[str] = PythonToStubConverter._ConvertFunction(item, indent=indent+1, SourceLines=SourceLines, class_name=node.name) + lines.extend(FuncStub) + elif isinstance(item, ast.Expr): + # 处理宏调用,如 c.CIf(...), c.CEndif(), c.CElif(), c.CElse() + ExprStr: str = PythonToStubConverter._GetExprString(item.value) + if ExprStr: + lines.append(f'{IndentStr} {ExprStr}') + elif isinstance(item, ast.If): + # 处理 if c.CIf(...): 形式的宏条件 + IfStr: str = PythonToStubConverter._get_if_macro_string(item, indent=indent+1) + if IfStr: + lines.append(IfStr) + elif isinstance(item, ast.ClassDef): + # 处理嵌套类 + HasMembers = True + NestedClassLines: list[str] = PythonToStubConverter._ConvertClass(item, SourceLines=SourceLines, PostdefVars=[], indent=indent+1) + # 移除嵌套类的宏守卫(因为已经在父类的宏守卫内) + FilteredLines: list[str] = [] + for line in NestedClassLines: + # 跳过宏守卫相关行 + if line.strip().startswith('c.CIfndef(') or line.strip().startswith('c.CEndif()'): + continue + if ': t.CDefine' in line and '__' in line: + continue + FilteredLines.append(line) + lines.extend(FilteredLines) + + if not HasMembers: + lines.append(f'{IndentStr} pass') + + # 添加 Postdefinition 变量 + if PostdefVars: + lines.append('') + for VarName, TypeStr, _ in PostdefVars: + lines.append(f'{VarName}: {TypeStr}') + + return lines + + @staticmethod + def _ConvertFunction(node: ast.FunctionDef, indent: int = 0, SourceLines: list[str] | None = None, class_name: str | None = None) -> list[str]: + """转换函数定义""" + lines: list[str] = [] + IndentStr: str = ' ' * indent + + # 检查是否是宏函数(返回类型包含 t.CDefine) + is_macro_func: bool = False + if node.returns: + ReturnType: str = PythonToStubConverter._GetTypeString(node.returns) + if 't.CDefine' in ReturnType: + is_macro_func = True + + # 如果是宏函数,检查是否应该被排除 + if is_macro_func: + if PythonToStubConverter._ShouldExcludeMacro(node.name): + return lines # 返回空列表,排除该宏 + + # 保持原样(包括代码块) + if SourceLines: + 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]) + if lines and lines[-1].strip() and not lines[-1].rstrip().endswith(':'): + pass + else: + lines.append(f'{IndentStr} pass') + return lines + + # 处理函数装饰器 + for decorator in node.decorator_list: + DecoratorStr: str = PythonToStubConverter._GetDecoratorString(decorator) + if DecoratorStr: + lines.append(f'{IndentStr}@{DecoratorStr}') + + # 构建参数列表 + # 治本修复:原实现只遍历 node.args.args,完全忽略 node.args.defaults, + # 导致带默认值的参数(如 category: str = "")在 .pyi 中丢失默认值。 + # 下游 DeclarationGenerator 据此生成 stub.ll 时,会因缺少默认参数而 + # 生成参数数量不足的 declare,进而造成调用方 ABI 不匹配崩溃。 + # 修复:按 Python AST 语义,defaults 从右向左对应 args 末尾的参数, + # 对有默认值的参数附加 '= '。 + params: list[str] = [] + NumDefaults: int = len(node.args.defaults) if node.args.defaults else 0 + DefaultsStart: int = len(node.args.args) - NumDefaults + for arg_idx, arg in enumerate(node.args.args): + ArgName: str = arg.arg + if arg.annotation: + TypeStr: str = PythonToStubConverter._GetTypeString(arg.annotation) + ParamPart: str = f'{ArgName}: {TypeStr}' + elif class_name and arg_idx == 0 and ArgName == 'self': + ParamPart = f'self: {class_name}' + else: + ParamPart = ArgName + # 附加默认值:defaults[i] 对应 args[DefaultsStart + i] + if NumDefaults > 0 and arg_idx >= DefaultsStart: + DefaultIdx: int = arg_idx - DefaultsStart + try: + DefaultStr: str = ast.unparse(node.args.defaults[DefaultIdx]) + ParamPart = f'{ParamPart} = {DefaultStr}' + except Exception: + # unparse 失败时保留无默认值形式,避免阻塞生成 + pass + params.append(ParamPart) + + # 处理 *args + if node.args.vararg: + ArgName = node.args.vararg.arg + if node.args.vararg.annotation: + TypeStr = PythonToStubConverter._GetTypeString(node.args.vararg.annotation) + params.append(f'*{ArgName}: {TypeStr}') + else: + params.append(f'*{ArgName}') + + # 处理 **kwargs + if node.args.kwarg: + ArgName = node.args.kwarg.arg + if node.args.kwarg.annotation: + TypeStr = PythonToStubConverter._GetTypeString(node.args.kwarg.annotation) + params.append(f'**{ArgName}: {TypeStr}') + else: + params.append(f'**{ArgName}') + + ParamStr: str = ', '.join(params) + + # 返回类型 - 保持原始类型(不添加t.State) + if node.returns: + ReturnType = PythonToStubConverter._GetTypeString(node.returns) + else: + ReturnType = 't.CInt' + + TypeParamStr: str = '' + if hasattr(node, 'type_params') and node.type_params: + param_names: list[str] = [tp.name for tp in node.type_params] + TypeParamStr = f'[{", ".join(param_names)}]' + + lines.append(f'{IndentStr}def {node.name}{TypeParamStr}({ParamStr}) -> {ReturnType}: pass') + return lines + + @staticmethod + def _ConvertVariable(node: ast.AnnAssign, SourceLines: list[str] | None = None) -> list[str]: + """转换变量定义""" + lines: list[str] = [] + if isinstance(node.target, ast.Name): + VarName: str = node.target.id + TypeStr: str = PythonToStubConverter._GetTypeString(node.annotation) + # 检查是否是宏变量(类型包含 t.CDefine) + if 't.CDefine' in TypeStr: + # 检查宏变量是否应该被排除 + 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]) + else: + lines.append(f'{VarName}: {TypeStr}') + return lines + # 非宏变量:不加 t.State + # 含有 typedef 的变量不加 extern,普通变量需要加 extern + has_typedef: bool = 't.CTypedef' in TypeStr or 'CTypedef' in TypeStr + if has_typedef and node.value is not None: + ValueTypeStr: str = PythonToStubConverter._GetTypeString(node.value) + lines.append(f'{VarName}: {TypeStr} = {ValueTypeStr}') + else: + if not has_typedef and 't.CExtern' not in TypeStr and 't.CStatic' not in TypeStr: + TypeStr = f't.CExtern | {TypeStr}' + lines.append(f'{VarName}: {TypeStr}') + return lines + + @staticmethod + def _ConvertGlobalAssign(node: ast.Assign) -> list[str]: + """转换模块级别的全局变量(无类型标注)""" + lines: list[str] = [] + if not node.targets or not isinstance(node.targets[0], ast.Name): + return lines + + VarName: str = node.targets[0].id + + # 跳过私有变量(以下划线开头) + if VarName.startswith('_'): + return lines + + # 从值推断类型 + inferred_type: str | None = PythonToStubConverter._InferTypeFromValue(node.value) + if inferred_type: + lines.append(f'{VarName}: {inferred_type}') + else: + lines.append(f'{VarName}: t.CInt') + + return lines + + @staticmethod + def _InferTypeFromValue(value: ast.AST) -> str | None: + """从值推断 C 类型""" + if isinstance(value, ast.Constant): + if isinstance(value.value, int): + return 't.CInt' + elif isinstance(value.value, float): + return 't.CDouble' + elif isinstance(value.value, str): + return 't.CCharPtr' + elif isinstance(value.value, bool): + return 't.CInt' + elif isinstance(value, ast.List): + return 't.CVoidPtr' + elif isinstance(value, ast.Dict): + return 't.CVoidPtr' + elif isinstance(value, ast.Name): + return 't.CInt' + elif isinstance(value, ast.BinOp): + left_type: str | None = PythonToStubConverter._InferTypeFromValue(value.left) + if left_type: + return left_type + return 't.CInt' + elif isinstance(value, ast.Call): + # 函数调用返回值,假设为指针类型 + if isinstance(value.func, ast.Name): + func_name: str = value.func.id + if func_name == 'malloc': + return 't.CVoidPtr' + elif func_name in ('ctypes.cast', 'cast'): + return 't.CVoidPtr' + return 't.CVoidPtr' + return None + + @staticmethod + def _GetTypeString(annotation: ast.AST) -> str: + """获取类型字符串""" + if isinstance(annotation, ast.Name): + return annotation.id + elif isinstance(annotation, ast.Attribute): + if isinstance(annotation.value, ast.Name): + return f'{annotation.value.id}.{annotation.attr}' + else: + # 处理嵌套属性访问,如 t.attr.packed + ParentStr: str = PythonToStubConverter._GetTypeString(annotation.value) + return f'{ParentStr}.{annotation.attr}' + elif isinstance(annotation, ast.Subscript): + 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] + SliceStr: str = ', '.join(slice_strs) + else: + SliceStr = PythonToStubConverter._GetTypeString(annotation.slice) + return f'{base}[{SliceStr}]' + elif isinstance(annotation, ast.BinOp): + # 处理 BinOp,如 t.CExtern | fd_table.__set_default__(...) + left: ast.AST = annotation.left + right: ast.AST = annotation.right + + # 检查右侧是否是 __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): + return f'{LeftStr} + {RightStr}' + elif isinstance(annotation.op, ast.Sub): + return f'{LeftStr} - {RightStr}' + elif isinstance(annotation.op, ast.Mult): + return f'{LeftStr} * {RightStr}' + elif isinstance(annotation.op, ast.Div): + return f'{LeftStr} / {RightStr}' + elif isinstance(annotation.op, ast.Mod): + return f'{LeftStr} % {RightStr}' + elif isinstance(annotation, ast.UnaryOp): + if isinstance(annotation.op, ast.Not): + operand: str = PythonToStubConverter._GetTypeString(annotation.operand) + return f'not {operand}' + elif isinstance(annotation.op, ast.Invert): + operand = PythonToStubConverter._GetTypeString(annotation.operand) + return f'~{operand}' + elif isinstance(annotation.op, ast.USub): + operand = PythonToStubConverter._GetTypeString(annotation.operand) + return f'-{operand}' + elif isinstance(annotation, ast.Compare): + # 处理比较操作,如 FF_MAX_SS != FF_MIN_SS + left: str = PythonToStubConverter._GetTypeString(annotation.left) + comparators: list[str] = [PythonToStubConverter._GetTypeString(c) for c in annotation.comparators] + ops: list[str] = [] + for op in annotation.ops: + if isinstance(op, ast.Eq): + ops.append('==') + elif isinstance(op, ast.NotEq): + ops.append('!=') + elif isinstance(op, ast.Lt): + ops.append('<') + elif isinstance(op, ast.LtE): + ops.append('<=') + elif isinstance(op, ast.Gt): + ops.append('>') + elif isinstance(op, ast.GtE): + ops.append('>=') + else: + ops.append('?') + result: str = left + for i, op in enumerate(ops): + result += f' {op} {comparators[i]}' + return result + elif isinstance(annotation, ast.Constant): + return repr(annotation.value) + elif isinstance(annotation, ast.Index): + return PythonToStubConverter._GetTypeString(annotation.value) + elif isinstance(annotation, ast.List): + # 处理列表,如 [MAX_FILE_DESCRIPTORS] + elements: list[str] = [PythonToStubConverter._GetTypeString(elem) for elem in annotation.elts] + return f'[{", ".join(elements)}]' + elif isinstance(annotation, ast.Call): + # 处理函数调用形式的类型注解,如 t.Postdefinition(xxa) 或 callable(t.CVoid, app_id = t.CInt) + # 如果是 __set_default__ 调用,只返回函数名部分 + if isinstance(annotation.func, ast.Attribute) and annotation.func.attr in ('__set_default__', '__set_default'): + return PythonToStubConverter._GetTypeString(annotation.func.value) + + FuncStr: str = PythonToStubConverter._GetTypeString(annotation.func) + ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in annotation.args]) + # 处理关键字参数 + keywords_str: str = ', '.join([f'{kw.arg} = {PythonToStubConverter._GetTypeString(kw.value)}' for kw in annotation.keywords]) + # 合并位置参数和关键字参数 + if ArgsStr and keywords_str: + return f'{FuncStr}({ArgsStr}, {keywords_str})' + elif keywords_str: + return f'{FuncStr}({keywords_str})' + else: + return f'{FuncStr}({ArgsStr})' + return 't.CVoid' + + @staticmethod + def _ExtractPostdefClass(annotation: ast.AST) -> str | None: + """从 Postdefinition 类型注解中提取类名 + + 例如:t.Postdefinition(__buddy_system) -> '__buddy_system' + t.Postdefinition(xxx) | t.CTypedef -> 'xxx' + """ + # 处理 BinOp (如: t.Postdefinition(xxx) | t.CTypedef) + 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 + return None + + # 处理函数调用 (如: t.Postdefinition(__buddy_system)) + if isinstance(annotation, ast.Call): + FuncStr: str = PythonToStubConverter._GetTypeString(annotation.func) + if FuncStr == 't.Postdefinition' and annotation.args: + # 提取第一个参数 + first_arg: ast.AST = annotation.args[0] + if isinstance(first_arg, ast.Name): + return first_arg.id + elif isinstance(first_arg, ast.Attribute): + return f'{first_arg.value.id}.{first_arg.attr}' + + return None + + @staticmethod + def _GetImportString(node: ast.Import, SourceLines: list[str] | None = None) -> str: + """获取导入语句字符串""" + parts: list[str] = [] + IncludeAliasMap: dict[str, str] = PythonToStubConverter.IncludeAliasMap + + for alias in node.names: + ModuleName: str = alias.name + # 检查是否是 __include.xxx 格式的导入 + if ModuleName.startswith('__include.'): + # 提取别名(xxx 部分) + SubModule: str = ModuleName[len('__include.'):] + if SubModule in IncludeAliasMap: + # 替换为实际模块路径 + RealModule: str = IncludeAliasMap[SubModule] + if alias.asname: + parts.append(f'{RealModule} as {alias.asname}') + else: + parts.append(f'{RealModule} as {SubModule}') + else: + # 不在映射表中,保持原样 + if alias.asname: + parts.append(f'{ModuleName} as {alias.asname}') + else: + parts.append(ModuleName) + else: + if alias.asname: + parts.append(f'{alias.name} as {alias.asname}') + else: + parts.append(alias.name) + + result: str = f'import {", ".join(parts)}' + + # 提取并保留注释 + if SourceLines and hasattr(node, 'lineno'): + LineIdx: int = node.lineno - 1 + if 0 <= LineIdx < len(SourceLines): + line: str = SourceLines[LineIdx] + CommentMatch: re.Match | None = re.search(r'#.*$', line) + if CommentMatch: + result += ' ' + CommentMatch.group(0) + + return result + + @staticmethod + def _GetImportFromString(node: ast.ImportFrom, SourceLines: list[str] | None = None) -> str: + """获取 from ... import ... 语句字符串""" + module: str = node.module or '' + parts: list[str] = [] + IncludeAliasMap: dict[str, str] = PythonToStubConverter.IncludeAliasMap + + # 处理相对导入 (from . import xxx 或 from ..package import xxx) + if node.level > 0: + if module: + if node.level == 1: + full_module: str = f'.{module}' + else: + full_module = '.' * node.level + module + else: + full_module = '.' * node.level + for alias in node.names: + if alias.asname: + parts.append(f'{alias.name} as {alias.asname}') + else: + parts.append(alias.name) + return f'from {full_module} import {", ".join(parts)}' + + # 提取注释(在生成结果前获取) + comment: str = '' + if SourceLines and hasattr(node, 'lineno'): + LineIdx = node.lineno - 1 + if 0 <= LineIdx < len(SourceLines): + line = SourceLines[LineIdx] + CommentMatch: re.Match | None = re.search(r'#.*$', line) + if CommentMatch: + comment = ' ' + CommentMatch.group(0) + + # 检查是否是 from __include import xxx 格式 + if module == '__include': + for alias in node.names: + name: str = alias.name + if name in IncludeAliasMap: + # 替换为实际模块路径 + RealModule: str = IncludeAliasMap[name] + if alias.asname: + parts.append(f'import {RealModule} as {alias.asname}{comment}') + else: + parts.append(f'import {RealModule} as {name}{comment}') + else: + # 不在映射表中,保持原样 + if alias.asname: + parts.append(f'from {module} import {name} as {alias.asname}{comment}') + else: + parts.append(f'from {module} import {name}{comment}') + return '\n'.join(parts) + + # 普通 from ... import ... 语句 + for alias in node.names: + if alias.asname: + parts.append(f'{alias.name} as {alias.asname}') + else: + parts.append(alias.name) + return f'from {module} import {", ".join(parts)}{comment}' + + @staticmethod + def _GetDecoratorString(decorator: ast.AST) -> str: + """获取装饰器字符串""" + if isinstance(decorator, ast.Name): + return decorator.id + elif isinstance(decorator, ast.Attribute): + if isinstance(decorator.value, ast.Name): + return f'{decorator.value.id}.{decorator.attr}' + return decorator.attr + elif isinstance(decorator, ast.Call): + # 处理带参数的装饰器,如 @c.Attribute(t.attr.packed) + FuncStr: str = PythonToStubConverter._GetDecoratorString(decorator.func) + ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in decorator.args]) + return f'{FuncStr}({ArgsStr})' + return '' + + @staticmethod + def _GetExprString(expr: ast.AST) -> str: + """获取表达式字符串(用于宏调用)""" + if isinstance(expr, ast.Call): + # 处理函数调用,如 c.CIf(...), c.CEndif(), c.CUndef(...), c.CPragma(...) + FuncStr: str = PythonToStubConverter._GetDecoratorString(expr.func) + if FuncStr and ('CIf' in FuncStr or 'CEndif' in FuncStr or 'CElif' in FuncStr or 'CElse' in FuncStr or 'CUndef' in FuncStr or 'CPragma' in FuncStr): + ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in expr.args]) + return f'{FuncStr}({ArgsStr})' if ArgsStr else f'{FuncStr}()' + return '' + + @staticmethod + def _get_if_macro_string(node: ast.If, indent: int = 1) -> str: + """获取类内部的 if 宏字符串(如 if c.CIf(...):)""" + IndentStr: str = ' ' * indent + InnerIndent: str = ' ' * (indent + 1) + # 检查条件是否是宏调用 + if isinstance(node.test, ast.Call): + FuncStr: str = PythonToStubConverter._GetDecoratorString(node.test.func) + if FuncStr and 'CIf' in FuncStr: + ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args]) + result: list[str] = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():'] + # 处理 if 体内的语句 + for item in node.body: + if isinstance(item, ast.AnnAssign): + TypeStr: str = PythonToStubConverter._GetTypeString(item.annotation) + result.append(f'{InnerIndent}{item.target.id}: {TypeStr}') + elif isinstance(item, ast.Expr): + ExprStr: str = PythonToStubConverter._GetExprString(item.value) + if ExprStr: + result.append(f'{InnerIndent}{ExprStr}') + return '\n'.join(result) + return '' + + @staticmethod + def _GetModuleIfMacroString(node: ast.If) -> str: + """获取模块级别的 if 宏字符串(如 if c.CIf(FF_MULTI_PARTITION):)""" + return PythonToStubConverter._ProcessIfMacro(node, indent=0) + + @staticmethod + def _ProcessIfMacro(node: ast.If, indent: int = 0) -> str: + """处理 if 宏节点,支持 elif 和 else""" + IndentStr: str = ' ' * indent + + # 检查条件是否是宏调用 + if isinstance(node.test, ast.Call): + FuncStr: str = PythonToStubConverter._GetDecoratorString(node.test.func) + if FuncStr and 'CIf' in FuncStr: + ArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in node.test.args]) + result: list[str] = [f'{IndentStr}if {FuncStr}({ArgsStr}):' if ArgsStr else f'{IndentStr}if {FuncStr}():'] + # 处理 if 体内的语句 + for item in node.body: + result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) + + # 处理 elif 和 else + current: ast.If = node + while current.orelse: + if len(current.orelse) == 1 and isinstance(current.orelse[0], ast.If): + # elif 情况 + elif_node: ast.If = current.orelse[0] + if isinstance(elif_node.test, ast.Call): + ElifFuncStr: str = PythonToStubConverter._GetDecoratorString(elif_node.test.func) + if ElifFuncStr and 'CIf' in ElifFuncStr: + ElifArgsStr: str = ', '.join([PythonToStubConverter._GetTypeString(arg) for arg in elif_node.test.args]) + result.append(f'{IndentStr}elif {ElifFuncStr}({ElifArgsStr}):' if ElifArgsStr else f'{IndentStr}elif {ElifFuncStr}():') + for item in elif_node.body: + result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) + current = elif_node + continue + break + else: + # else 情况 + result.append(f'{IndentStr}else:') + for item in current.orelse: + result.extend(PythonToStubConverter._ProcessMacroBodyItem(item, indent + 1)) + break + + return '\n'.join(result) + return '' + + @staticmethod + def _ProcessMacroBodyItem(item: ast.AST, indent: int = 0) -> list[str]: + """处理宏体内的单个语句""" + IndentStr: str = ' ' * indent + result: list[str] = [] + + if isinstance(item, ast.ClassDef): + class_stub: list[str] = PythonToStubConverter._ConvertClass(item) + for line in class_stub: + if line.strip(): + result.append(f'{IndentStr}{line}') + else: + result.append(line) + elif isinstance(item, ast.FunctionDef): + FuncStub: list[str] = PythonToStubConverter._ConvertFunction(item, indent=indent) + result.extend(FuncStub) + elif isinstance(item, ast.AnnAssign): + TypeStr: str = PythonToStubConverter._GetTypeString(item.annotation) + result.append(f'{IndentStr}{item.target.id}: {TypeStr}') + elif isinstance(item, ast.Expr): + ExprStr: str = PythonToStubConverter._GetExprString(item.value) + if ExprStr: + result.append(f'{IndentStr}{ExprStr}') + elif isinstance(item, ast.If): + # 处理嵌套的 if 宏 + NestedIf: str = PythonToStubConverter._ProcessIfMacro(item, indent=indent) + if NestedIf: + result.append(NestedIf) + return result \ No newline at end of file diff --git a/lib/__init__.py b/lib/__init__.py index ea4ac0f..ce986a4 100644 --- a/lib/__init__.py +++ b/lib/__init__.py @@ -1 +1,6 @@ -"""TransPyC 编译器核心库""" +"""TransPyC 编译器核心库 + +任何 ``import lib.*`` 都会先触发 _bootstrap(sys.path 设置: +项目根 + lib 目录 + lib/includes),保证 ``import vast`` 直接可用。 +""" +import lib._bootstrap # noqa: F401 diff --git a/lib/_bootstrap.py b/lib/_bootstrap.py index 569dc45..4365e01 100644 --- a/lib/_bootstrap.py +++ b/lib/_bootstrap.py @@ -30,6 +30,9 @@ def _bootstrap() -> None: if _ProjectRoot not in sys.path: sys.path.insert(0, _ProjectRoot) + if _LibDir not in sys.path: + # lib 目录入 path:使 vast 包(lib/vast/)可直接 import vast + sys.path.append(_LibDir) if _IncludesDir not in sys.path: sys.path.append(_IncludesDir) diff --git a/lib/core/ConstEvaluator.py b/lib/core/ConstEvaluator.py index 47da8b2..a2a8326 100644 --- a/lib/core/ConstEvaluator.py +++ b/lib/core/ConstEvaluator.py @@ -1,652 +1,652 @@ -"""统一常量表达式求值器 - -整合了原先分散在 5 处的常量求值逻辑: - - SymbolTable._eval_const_expr - - CTypeInfo.TryEvalConstExpr - - ConstEvalMixin._try_eval_const_expr - - HandlesAssign._eval_const_expr - - HandlesIf._eval_const_expr - -ConstEvaluator 提供三个级别的求值: - 1. eval_basic(node) — 纯 AST 常量 + 算术(无外部依赖) - 2. eval_with_symtab(node) — + SymbolTable 中的 define 查找 - 3. eval_full(node, ctx) — + Gen._define_constants / _all_define_constants / 平台宏 -""" -from __future__ import annotations - -import ast -from typing import Any, Callable, Optional, TYPE_CHECKING - -import llvmlite.ir as ir - -from lib.core.Handles.HandlesBase import CTypeInfo -# 治本修复:导入 t 模块和 CType 基类,用于类型构造调用求值(如 t.CUnsignedLong(-11)) -from lib.includes import t as _t_module -from lib.includes.t import CType as _CType_base - -if TYPE_CHECKING: - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator - - -class ConstEvaluator: - """统一常量表达式求值器""" - - # ================================================================== - # Level 2: + SymbolTable define 查找 - # ================================================================== - - @staticmethod - def eval_with_symtab(node: ast.AST, symtab: Any) -> Optional[Any]: - """求值常量表达式,支持从 SymbolTable 查找 define 值。 - - 支持: Constant, BinOp, UnaryOp, Name(define), Attribute(define), Call(类型构造) - """ - if isinstance(node, ast.Constant): - return node.value - if isinstance(node, ast.Name): - if hasattr(symtab, '__contains__') and node.id in symtab: - info: CTypeInfo = symtab[node.id] - if info.IsDefine and isinstance(info.DefineValue, int): - return info.DefineValue - return None - if isinstance(node, ast.Attribute): - # 先尝试 t.CSizeT().Size 模式(类型构造调用 + .Size 属性) - size_val = ConstEvaluator._eval_ctype_size_attr(node) - if size_val is not None: - return size_val - return ConstEvaluator._eval_attribute_define(node, symtab) - # 治本修复:支持 t.CUnsignedLong(-11) 等类型构造调用 - if isinstance(node, ast.Call): - return ConstEvaluator._eval_ctype_ctor_call(node, symtab) - return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_with_symtab(n, symtab)) - - @staticmethod - def _eval_ctype_ctor_call(node: ast.Call, symtab: Any) -> Optional[Any]: - """求值类型构造调用,如 t.CUnsignedLong(-11)、CInt(42)。 - - 在无 ctx(EvalContext)的场景下,通过 symtab 和 t 模块直接求值。 - 按类型的 Size 和 IsSigned 应用位掩码。 - """ - func: ast.expr = node.func - func_name: str | None = None - module_name: str | None = None - if isinstance(func, ast.Attribute): - if isinstance(func.value, ast.Name): - module_name = func.value.id - func_name = func.attr - elif isinstance(func, ast.Name): - func_name = func.id - - ctype_cls: Any = None - if module_name == 't' and func_name: - ctype_cls = getattr(_t_module, func_name, None) - elif func_name and not module_name: - ctype_cls = getattr(_t_module, func_name, None) - if ctype_cls is None and symtab: - t_type_syms = getattr(symtab, '_t_type_symbols', {}) - cls_candidate = t_type_syms.get(func_name) - if cls_candidate is not None: - ctype_cls = cls_candidate - - if ctype_cls is None or not (isinstance(ctype_cls, type) and issubclass(ctype_cls, _CType_base)): - return None - if not node.args: - return None - - arg_val: Any = ConstEvaluator.eval_with_symtab(node.args[0], symtab) - if arg_val is None: - return None - - size: int | None = None - is_signed: bool | None = None - try: - tmp_inst = ctype_cls() - size = getattr(tmp_inst, 'Size', None) - is_signed = getattr(tmp_inst, 'IsSigned', None) - except Exception: - pass - - if isinstance(arg_val, int) and size and size > 0: - mask: int = (1 << size) - 1 - if is_signed: - masked: int = arg_val & mask - if masked >= (1 << (size - 1)): - masked -= (1 << size) - return masked - else: - return arg_val & mask - return arg_val - - # ================================================================== - # Level 3: + Gen._define_constants / _all_define_constants / 平台宏 - # ================================================================== - - @staticmethod - def eval_full(node: ast.AST, ctx: 'EvalContext') -> Optional[Any]: - """完整求值,支持 define_constants、平台宏、BoolOp、Compare。 - - ctx: EvalContext 实例,封装了 Gen、SymbolTable 等上下文。 - """ - # BoolOp (HandlesIf 逻辑) - if isinstance(node, ast.BoolOp): - if isinstance(node.op, ast.And): - for val in node.values: - result: Any = ConstEvaluator.eval_full(val, ctx) - if result is None: - return None - if not result: - return 0 - return 1 - elif isinstance(node.op, ast.Or): - for val in node.values: - result: Any = ConstEvaluator.eval_full(val, ctx) - if result is None: - return None - if result: - return 1 - return 0 - return None - - # Compare (HandlesIf 逻辑) - if isinstance(node, ast.Compare): - left: Any = ConstEvaluator.eval_full(node.left, ctx) - if left is None: - return None - op: ast.cmpop - comparator: ast.AST - for op, comparator in zip(node.ops, node.comparators): - right: Any = ConstEvaluator.eval_full(comparator, ctx) - if right is None: - return None - result: bool | None = ConstEvaluator._eval_compare_op(op, left, right) - if result is None: - return None - if not result: - return 0 - left = right - return 1 - - # Constant — 直接返回原始值,bool→0/1 转换由 HandlesIf 自行处理 - if isinstance(node, ast.Constant): - return node.value - - # Name — 查 define_constants / SymbolTable / 平台宏 - if isinstance(node, ast.Name): - return ctx.lookup_name(node.id) - - # Attribute — 查 define_constants / SymbolTable / 平台宏 - if isinstance(node, ast.Attribute): - # 先尝试 t.CSizeT().Size 模式(类型构造调用 + .Size 属性) - size_val = ConstEvaluator._eval_ctype_size_attr(node) - if size_val is not None: - return size_val - return ctx.lookup_attribute(node) - - # UnaryOp - if isinstance(node, ast.UnaryOp): - operand: Any = ConstEvaluator.eval_full(node.operand, ctx) - if operand is None: - return None - if isinstance(node.op, ast.Not): - return 1 if not operand else 0 - if isinstance(node.op, ast.USub): - return -operand - if isinstance(node.op, ast.UAdd): - return +operand - if isinstance(node.op, ast.Invert): - return ~operand - return None - - # Call — 编译时函数调用(如 ctraits.isptr(x)) - if isinstance(node, ast.Call): - return ConstEvaluator._eval_compile_time_call(node, ctx) - - # BinOp - return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_full(n, ctx)) - - # ================================================================== - # 内部辅助 - # ================================================================== - - @staticmethod - def _eval_compile_time_call(node: ast.Call, ctx: 'EvalContext') -> Optional[Any]: - """处理编译时函数调用,如 ctraits.isptr(x)、t.CUnsignedLong(-11)""" - func: ast.expr = node.func - func_name: str | None = None - module_name: str | None = None - - if isinstance(func, ast.Attribute): - if isinstance(func.value, ast.Name): - module_name = func.value.id - func_name = func.attr - elif isinstance(func, ast.Name): - func_name = func.id - - # ctraits.isptr(x) — 带模块前缀 - # isptr(x) — 通过 from ctraits import isptr 导入 - is_isptr: bool = False - if module_name == 'ctraits' and func_name == 'isptr': - is_isptr = True - elif func_name == 'isptr' and not module_name: - # 检查是否通过 from ctraits import isptr 导入 - t_c_imported = getattr(ctx.translator, '_t_c_imported_names', {}) if ctx.translator else {} - if func_name in t_c_imported: - src_module, _ = t_c_imported[func_name] - if src_module == 'ctraits': - is_isptr = True - # 也检查符号表中是否有 ctraits.isptr - if not is_isptr and ctx.symtab: - sym = ctx.symtab.lookup('ctraits.isptr') if hasattr(ctx.symtab, 'lookup') else None - if sym: - is_isptr = True - - if is_isptr and node.args and ctx.translator: - try: - arg_node: ast.expr = node.args[0] - # 局部变量:优先通过 LLVM 类型判断(GetCTypeInfo 无法解析局部变量名) - if ctx.Gen and isinstance(arg_node, ast.Name): - var_name: str = arg_node.id - variables: dict = getattr(ctx.Gen, 'variables', {}) - if var_name in variables: - var_val: Any = variables[var_name] - if hasattr(var_val, 'type') and isinstance(var_val.type, ir.PointerType): - pointee: ir.Type = var_val.type.pointee - if isinstance(pointee, ir.PointerType): - return 1 - return 0 - # 类型名 / typedef:通过 TypeMergeHandler 获取 CTypeInfo - type_info = ctx.translator.TypeMergeHandler.GetCTypeInfo(arg_node) - if type_info and (type_info.IsPtr or type_info.PtrCount > 0): - return 1 - if type_info and not (type_info.IsPtr or type_info.PtrCount > 0): - return 0 - return None - except Exception: - return None - - # 治本修复:支持 t.CUnsignedLong(-11) 等类型构造调用 - # 当 t.CUnsignedLong(value) / CUnsignedInt(value) / CInt(value) 等被用作常量表达式时, - # 求值参数并返回(按类型的无符号/有符号语义应用位掩码)。 - # 这修复了 stdint.py 中 INFINITE = t.CUnsignedLong(-1) 等常量无法被求值的问题。 - is_ctype_ctor: bool = False - ctype_cls: Any = None - if module_name == 't' and func_name: - ctype_cls = getattr(_t_module, func_name, None) - if ctype_cls is not None and isinstance(ctype_cls, type) and issubclass(ctype_cls, _CType_base): - is_ctype_ctor = True - elif func_name and not module_name: - # from t import CUnsignedLong 形式 - ctype_cls = getattr(_t_module, func_name, None) - if ctype_cls is not None and isinstance(ctype_cls, type) and issubclass(ctype_cls, _CType_base): - is_ctype_ctor = True - # 也检查 _t_type_symbols(符号表中的 t 模块类型符号) - if not is_ctype_ctor and ctx.symtab: - t_type_syms = getattr(ctx.symtab, '_t_type_symbols', {}) - cls_candidate = t_type_syms.get(func_name) - if cls_candidate is not None and isinstance(cls_candidate, type) and issubclass(cls_candidate, _CType_base): - ctype_cls = cls_candidate - is_ctype_ctor = True - - if is_ctype_ctor and node.args: - try: - arg_node: ast.expr = node.args[0] - arg_val: Any = ConstEvaluator.eval_full(arg_node, ctx) - if arg_val is None: - return None - # 按类型的 Size 和 IsSigned 应用位掩码 - size: int | None = getattr(ctype_cls, '_Size', None) - is_signed: bool | None = getattr(ctype_cls, '_IsSigned', None) - # 尝试创建临时实例获取 Size/IsSigned - try: - tmp_inst = ctype_cls() - size = getattr(tmp_inst, 'Size', size) - is_signed = getattr(tmp_inst, 'IsSigned', is_signed) - except Exception: - pass - if isinstance(arg_val, int) and size and size > 0: - mask: int = (1 << size) - 1 - if is_signed: - # 有符号类型:解释为补码 - masked: int = arg_val & mask - if masked >= (1 << (size - 1)): - masked -= (1 << size) - return masked - else: - # 无符号类型:直接掩码 - return arg_val & mask - return arg_val - except Exception: - return None - return None - - @staticmethod - def _eval_arith(node: ast.AST, recurse: Callable[[ast.AST], Any]) -> Optional[Any]: - """通用算术求值:BinOp + UnaryOp""" - if isinstance(node, ast.BinOp): - left: Any = recurse(node.left) - right: Any = recurse(node.right) - if left is None or right is None: - return None - return ConstEvaluator._apply_binop(node.op, left, right) - if isinstance(node, ast.UnaryOp): - operand: Any = recurse(node.operand) - if operand is None: - return None - if isinstance(node.op, ast.USub): - return -operand - if isinstance(node.op, ast.UAdd): - return +operand - if isinstance(node.op, ast.Invert): - return ~operand - return None - return None - - @staticmethod - def _apply_binop(op: ast.operator, left: Any, right: Any) -> Optional[Any]: - """应用二元运算符""" - try: - if isinstance(op, ast.Add): - return left + right - elif isinstance(op, ast.Sub): - return left - right - elif isinstance(op, ast.Mult): - return left * right - elif isinstance(op, ast.Div): - return left // right if isinstance(left, int) and isinstance(right, int) else left / right - elif isinstance(op, ast.FloorDiv): - if isinstance(right, (int, float)) and right == 0: - return None - return left // right - elif isinstance(op, ast.Mod): - if isinstance(right, (int, float)) and right == 0: - return None - return left % right - elif isinstance(op, ast.Pow): - return left ** right - elif isinstance(op, ast.LShift): - return left << right - elif isinstance(op, ast.RShift): - return left >> right - elif isinstance(op, ast.BitOr): - return left | right - elif isinstance(op, ast.BitXor): - return left ^ right - elif isinstance(op, ast.BitAnd): - return left & right - except Exception: - return None - return None - - @staticmethod - def _eval_compare_op(op: ast.cmpop, left: Any, right: Any) -> Optional[bool]: - """应用比较运算符""" - if isinstance(op, ast.Eq): - return left == right - elif isinstance(op, ast.NotEq): - return left != right - elif isinstance(op, ast.Lt): - return left < right - elif isinstance(op, ast.LtE): - return left <= right - elif isinstance(op, ast.Gt): - return left > right - elif isinstance(op, ast.GtE): - return left >= right - return None - - @staticmethod - def _eval_ctype_size_attr(node: ast.Attribute) -> Optional[int]: - """求值 t.CSizeT().Size 等类型构造调用 + .Size 属性模式。 - - 匹配 AST 形态: Attribute(attr='Size', value=Call(func=Attribute(value=Name(id='t'), attr='CSizeT'))) - 或直接 Call(func=Name(id='CSizeT'))(from t import CSizeT 后的使用方式)。 - 返回类型大小(位数),如 CSizeT().Size 返回 64(64 位平台)。 - """ - if node.attr != 'Size': - return None - if not isinstance(node.value, ast.Call): - return None - call_node: ast.Call = node.value - if call_node.args or call_node.keywords: - return None - func: ast.expr = call_node.func - type_name: str | None = None - if isinstance(func, ast.Attribute) and isinstance(func.value, ast.Name) and func.value.id == 't': - type_name = func.attr - elif isinstance(func, ast.Name): - type_name = func.id - if not type_name: - return None - # 延迟导入避免循环依赖 - try: - from lib.includes.t import CTypeRegistry - except Exception: - return None - cls = CTypeRegistry.GetClassByName(type_name) - if cls is None: - return None - try: - instance = cls() - size_val = getattr(instance, 'Size', None) - if isinstance(size_val, int): - return size_val - except Exception: - pass - return None - - @staticmethod - def _eval_attribute_define(node: ast.Attribute, symtab: Any) -> Optional[Any]: - """从 SymbolTable 查找 Attribute 形式的 define 值""" - parts: list[str] = [] - current: ast.AST = node - while isinstance(current, ast.Attribute): - parts.append(current.attr) - current = current.value - if isinstance(current, ast.Name): - parts.append(current.id) - parts.reverse() - attr_name: str = parts[-1] - possible_keys: list[str] = [attr_name, '.'.join(parts)] - for key in possible_keys: - if hasattr(symtab, '__contains__') and key in symtab: - info: CTypeInfo = symtab[key] - if info.IsDefine and isinstance(info.DefineValue, int): - return info.DefineValue - # 模糊匹配 - if len(parts) >= 2: - mod_key: str - mod_info: CTypeInfo - for mod_key, mod_info in (symtab.items() if hasattr(symtab, 'items') else []): - if mod_info.IsDefine and isinstance(mod_info.DefineValue, int): - if mod_key.endswith('.' + attr_name) or mod_key == attr_name: - return mod_info.DefineValue - return None - - @staticmethod - def _intify(val: Any) -> Any: - """float → int 转换(仅当 float 值恰好是整数时)""" - if isinstance(val, float) and val == int(val): - return int(val) - return val - - -class EvalContext: - """常量求值上下文,封装 Gen / SymbolTable / 平台宏查找逻辑。 - - 由调用方构造并传入 ConstEvaluator.eval_full()。 - """ - - def __init__(self, Gen: LlvmCodeGenerator | None = None, symtab: Any = None, platform_macros: dict | None = None, translator: Any = None): - self.Gen: LlvmCodeGenerator | None = Gen - self.symtab: Any = symtab - self._platform_macros: dict | None = platform_macros - self.translator: Any = translator - - def lookup_name(self, name: str) -> Optional[Any]: - """查找 Name 节点的值:define_constants → SymbolTable → 平台宏 - - 治本修复:不再把 module.globals 的 initializer 当常量返回。 - CDefine 不创建 LLVM global(不在 module.globals),仅可变全局变量在 - module.globals 中;把可变全局的 initializer 当编译期常量会让 - range(_sha1_store_count) 等读取处求值成初始值 0 而不生成 load。 - CDefine 通过下方 _define_constants 查询返回常量,双点 bug 不复发。 - """ - # 1. Gen._define_constants - if self.Gen and name in self.Gen._define_constants: - val: Any = self.Gen._define_constants[name] - # 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 通过 - # 共享 _define_constants 覆盖本模块常量 - # (VpiReader.SHA1_LEN=16 被 Phase1.SHA1_LEN=17 覆盖导致双点符号 bug) - _gvar: Any = None - try: - if hasattr(self.Gen, 'module') and name in self.Gen.module.globals: - _gvar = self.Gen.module.globals[name] - except Exception: - _gvar = None - if _gvar is not None and getattr(_gvar, 'initializer', None) is not None: - _init: Any = _gvar.initializer - if hasattr(_init, 'constant') and isinstance(_init.constant, (int, float)): - val = _init.constant - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - - # 2. Gen._DefineConstants (大写版本) - if self.Gen and hasattr(self.Gen, '_DefineConstants') and name in self.Gen._DefineConstants: - val: Any = self.Gen._DefineConstants[name] - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - - # 3. SymbolTable - if self.symtab and name in self.symtab: - info: CTypeInfo = self.symtab[name] - val: Any = info.value - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - if info.IsDefine and isinstance(info.DefineValue, (int, float)): - return ConstEvaluator._intify(info.DefineValue) - - # 4. 平台宏 - macros: dict = self._get_platform_macros() - if name in macros: - return macros[name] - - return None - - def lookup_attribute(self, node: ast.Attribute) -> Optional[Any]: - """查找 Attribute 节点的值""" - module_name: str | None = node.value.id if isinstance(node.value, ast.Name) else None - attr_name: str = node.attr - - if module_name and attr_name: - combined_key: str = f"{module_name}.{attr_name}" - - # 1. Gen._define_constants - if self.Gen and combined_key in self.Gen._define_constants: - val: Any = self.Gen._define_constants[combined_key] - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - - # 2. SymbolTable (精确匹配 + 后缀匹配) - if self.symtab: - key: str - info: CTypeInfo - for key, info in self.symtab.items(): - if key.endswith(f".{combined_key}") or key == combined_key: - if info.IsDefine and isinstance(info.DefineValue, (int, float)): - return ConstEvaluator._intify(info.DefineValue) - - # 3. _all_define_constants - all_dc: dict = self._get_all_define_constants() - if combined_key in all_dc: - val: Any = all_dc[combined_key] - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - if attr_name in all_dc: - val: Any = all_dc[attr_name] - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - dc_key: str - dc_val: Any - for dc_key, dc_val in all_dc.items(): - if dc_key == attr_name or dc_key.endswith(f".{attr_name}"): - if isinstance(dc_val, (int, float)): - return ConstEvaluator._intify(dc_val) - - # 4. SymbolTable 短名查找 - if self.symtab and attr_name in self.symtab: - info: CTypeInfo = self.symtab[attr_name] - if info.IsDefine and isinstance(info.DefineValue, (int, float)): - return ConstEvaluator._intify(info.DefineValue) - - # 5. Gen._define_constants 短名 - if self.Gen and attr_name in self.Gen._define_constants: - val: Any = self.Gen._define_constants[attr_name] - if isinstance(val, (int, float)): - return ConstEvaluator._intify(val) - - # 6. 平台宏 - macros: dict = self._get_platform_macros() - full_key: str | None = self._get_attr_full_name(node) - if full_key: - if full_key in macros: - return macros[full_key] - short_name: str = full_key.split('.')[-1] if '.' in full_key else full_key - if short_name in macros: - return macros[short_name] - - return None - - def _get_all_define_constants(self) -> dict: - """获取 _all_define_constants""" - if self.Gen and hasattr(self.Gen, '_all_define_constants'): - return self.Gen._all_define_constants - return {} - - def _get_platform_macros(self) -> dict: - """获取平台宏""" - if self._platform_macros is not None: - return self._platform_macros - if not self.Gen: - return {} - macros: dict[str, int] = {} - pi: dict = self.Gen._platform_info - ptr_size: int = self.Gen.ptr_size - if pi.get('is_windows'): - macros['_WIN32'] = 1 - if not pi.get('is_32bit'): - macros['_WIN64'] = 1 - macros['WIN64'] = 1 - macros['WIN32'] = 1 - if pi.get('is_linux'): - macros['__linux__'] = 1 - if pi.get('is_macos'): - macros['__APPLE__'] = 1 - macros['__MACH__'] = 1 - if pi.get('is_x86_64'): - macros['__x86_64__'] = 1 - macros['__x86_64'] = 1 - macros['_M_X64'] = 1 - elif pi.get('is_arm64'): - macros['__aarch64__'] = 1 - macros['_M_ARM64'] = 1 - if not pi.get('is_32bit') and pi.get('is_linux'): - macros['__LP64__'] = 1 - elif pi.get('is_32bit'): - macros['_ILP32'] = 1 - macros['SIZEOF_VOID_P'] = ptr_size - macros['__SIZEOF_POINTER__'] = ptr_size - macros['NDEBUG'] = 0 - return macros - - @staticmethod - def _get_attr_full_name(node: ast.Attribute) -> Optional[str]: - """从 Attribute 节点提取完整名称 (e.g. 'module.name')""" - parts: list[str] = [] - current: ast.AST = node - while isinstance(current, ast.Attribute): - parts.append(current.attr) - current = current.value - if isinstance(current, ast.Name): - parts.append(current.id) - parts.reverse() - return '.'.join(parts) if parts else None +"""统一常量表达式求值器 + +整合了原先分散在 5 处的常量求值逻辑: + - SymbolTable._eval_const_expr + - CTypeInfo.TryEvalConstExpr + - ConstEvalMixin._try_eval_const_expr + - HandlesAssign._eval_const_expr + - HandlesIf._eval_const_expr + +ConstEvaluator 提供三个级别的求值: + 1. eval_basic(node) — 纯 AST 常量 + 算术(无外部依赖) + 2. eval_with_symtab(node) — + SymbolTable 中的 define 查找 + 3. eval_full(node, ctx) — + Gen._define_constants / _all_define_constants / 平台宏 +""" +from __future__ import annotations + +import vast as ast +from typing import Any, Callable, Optional, TYPE_CHECKING + +import llvmlite.ir as ir + +from lib.core.Handles.HandlesBase import CTypeInfo +# 治本修复:导入 t 模块和 CType 基类,用于类型构造调用求值(如 t.CUnsignedLong(-11)) +from lib.includes import t as _t_module +from lib.includes.t import CType as _CType_base + +if TYPE_CHECKING: + from lib.core.LlvmCodeGenerator import LlvmCodeGenerator + + +class ConstEvaluator: + """统一常量表达式求值器""" + + # ================================================================== + # Level 2: + SymbolTable define 查找 + # ================================================================== + + @staticmethod + def eval_with_symtab(node: ast.AST, symtab: Any) -> Optional[Any]: + """求值常量表达式,支持从 SymbolTable 查找 define 值。 + + 支持: Constant, BinOp, UnaryOp, Name(define), Attribute(define), Call(类型构造) + """ + if isinstance(node, ast.Constant): + return node.value + if isinstance(node, ast.Name): + if hasattr(symtab, '__contains__') and node.id in symtab: + info: CTypeInfo = symtab[node.id] + if info.IsDefine and isinstance(info.DefineValue, int): + return info.DefineValue + return None + if isinstance(node, ast.Attribute): + # 先尝试 t.CSizeT().Size 模式(类型构造调用 + .Size 属性) + size_val = ConstEvaluator._eval_ctype_size_attr(node) + if size_val is not None: + return size_val + return ConstEvaluator._eval_attribute_define(node, symtab) + # 治本修复:支持 t.CUnsignedLong(-11) 等类型构造调用 + if isinstance(node, ast.Call): + return ConstEvaluator._eval_ctype_ctor_call(node, symtab) + return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_with_symtab(n, symtab)) + + @staticmethod + def _eval_ctype_ctor_call(node: ast.Call, symtab: Any) -> Optional[Any]: + """求值类型构造调用,如 t.CUnsignedLong(-11)、CInt(42)。 + + 在无 ctx(EvalContext)的场景下,通过 symtab 和 t 模块直接求值。 + 按类型的 Size 和 IsSigned 应用位掩码。 + """ + func: ast.expr = node.func + func_name: str | None = None + module_name: str | None = None + if isinstance(func, ast.Attribute): + if isinstance(func.value, ast.Name): + module_name = func.value.id + func_name = func.attr + elif isinstance(func, ast.Name): + func_name = func.id + + ctype_cls: Any = None + if module_name == 't' and func_name: + ctype_cls = getattr(_t_module, func_name, None) + elif func_name and not module_name: + ctype_cls = getattr(_t_module, func_name, None) + if ctype_cls is None and symtab: + t_type_syms = getattr(symtab, '_t_type_symbols', {}) + cls_candidate = t_type_syms.get(func_name) + if cls_candidate is not None: + ctype_cls = cls_candidate + + if ctype_cls is None or not (isinstance(ctype_cls, type) and issubclass(ctype_cls, _CType_base)): + return None + if not node.args: + return None + + arg_val: Any = ConstEvaluator.eval_with_symtab(node.args[0], symtab) + if arg_val is None: + return None + + size: int | None = None + is_signed: bool | None = None + try: + tmp_inst = ctype_cls() + size = getattr(tmp_inst, 'Size', None) + is_signed = getattr(tmp_inst, 'IsSigned', None) + except Exception: + pass + + if isinstance(arg_val, int) and size and size > 0: + mask: int = (1 << size) - 1 + if is_signed: + masked: int = arg_val & mask + if masked >= (1 << (size - 1)): + masked -= (1 << size) + return masked + else: + return arg_val & mask + return arg_val + + # ================================================================== + # Level 3: + Gen._define_constants / _all_define_constants / 平台宏 + # ================================================================== + + @staticmethod + def eval_full(node: ast.AST, ctx: 'EvalContext') -> Optional[Any]: + """完整求值,支持 define_constants、平台宏、BoolOp、Compare。 + + ctx: EvalContext 实例,封装了 Gen、SymbolTable 等上下文。 + """ + # BoolOp (HandlesIf 逻辑) + if isinstance(node, ast.BoolOp): + if isinstance(node.op, ast.And): + for val in node.values: + result: Any = ConstEvaluator.eval_full(val, ctx) + if result is None: + return None + if not result: + return 0 + return 1 + elif isinstance(node.op, ast.Or): + for val in node.values: + result: Any = ConstEvaluator.eval_full(val, ctx) + if result is None: + return None + if result: + return 1 + return 0 + return None + + # Compare (HandlesIf 逻辑) + if isinstance(node, ast.Compare): + left: Any = ConstEvaluator.eval_full(node.left, ctx) + if left is None: + return None + op: ast.cmpop + comparator: ast.AST + for op, comparator in zip(node.ops, node.comparators): + right: Any = ConstEvaluator.eval_full(comparator, ctx) + if right is None: + return None + result: bool | None = ConstEvaluator._eval_compare_op(op, left, right) + if result is None: + return None + if not result: + return 0 + left = right + return 1 + + # Constant — 直接返回原始值,bool→0/1 转换由 HandlesIf 自行处理 + if isinstance(node, ast.Constant): + return node.value + + # Name — 查 define_constants / SymbolTable / 平台宏 + if isinstance(node, ast.Name): + return ctx.lookup_name(node.id) + + # Attribute — 查 define_constants / SymbolTable / 平台宏 + if isinstance(node, ast.Attribute): + # 先尝试 t.CSizeT().Size 模式(类型构造调用 + .Size 属性) + size_val = ConstEvaluator._eval_ctype_size_attr(node) + if size_val is not None: + return size_val + return ctx.lookup_attribute(node) + + # UnaryOp + if isinstance(node, ast.UnaryOp): + operand: Any = ConstEvaluator.eval_full(node.operand, ctx) + if operand is None: + return None + if isinstance(node.op, ast.Not): + return 1 if not operand else 0 + if isinstance(node.op, ast.USub): + return -operand + if isinstance(node.op, ast.UAdd): + return +operand + if isinstance(node.op, ast.Invert): + return ~operand + return None + + # Call — 编译时函数调用(如 ctraits.isptr(x)) + if isinstance(node, ast.Call): + return ConstEvaluator._eval_compile_time_call(node, ctx) + + # BinOp + return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_full(n, ctx)) + + # ================================================================== + # 内部辅助 + # ================================================================== + + @staticmethod + def _eval_compile_time_call(node: ast.Call, ctx: 'EvalContext') -> Optional[Any]: + """处理编译时函数调用,如 ctraits.isptr(x)、t.CUnsignedLong(-11)""" + func: ast.expr = node.func + func_name: str | None = None + module_name: str | None = None + + if isinstance(func, ast.Attribute): + if isinstance(func.value, ast.Name): + module_name = func.value.id + func_name = func.attr + elif isinstance(func, ast.Name): + func_name = func.id + + # ctraits.isptr(x) — 带模块前缀 + # isptr(x) — 通过 from ctraits import isptr 导入 + is_isptr: bool = False + if module_name == 'ctraits' and func_name == 'isptr': + is_isptr = True + elif func_name == 'isptr' and not module_name: + # 检查是否通过 from ctraits import isptr 导入 + t_c_imported = getattr(ctx.translator, '_t_c_imported_names', {}) if ctx.translator else {} + if func_name in t_c_imported: + src_module, _ = t_c_imported[func_name] + if src_module == 'ctraits': + is_isptr = True + # 也检查符号表中是否有 ctraits.isptr + if not is_isptr and ctx.symtab: + sym = ctx.symtab.lookup('ctraits.isptr') if hasattr(ctx.symtab, 'lookup') else None + if sym: + is_isptr = True + + if is_isptr and node.args and ctx.translator: + try: + arg_node: ast.expr = node.args[0] + # 局部变量:优先通过 LLVM 类型判断(GetCTypeInfo 无法解析局部变量名) + if ctx.Gen and isinstance(arg_node, ast.Name): + var_name: str = arg_node.id + variables: dict = getattr(ctx.Gen, 'variables', {}) + if var_name in variables: + var_val: Any = variables[var_name] + if hasattr(var_val, 'type') and isinstance(var_val.type, ir.PointerType): + pointee: ir.Type = var_val.type.pointee + if isinstance(pointee, ir.PointerType): + return 1 + return 0 + # 类型名 / typedef:通过 TypeMergeHandler 获取 CTypeInfo + type_info = ctx.translator.TypeMergeHandler.GetCTypeInfo(arg_node) + if type_info and (type_info.IsPtr or type_info.PtrCount > 0): + return 1 + if type_info and not (type_info.IsPtr or type_info.PtrCount > 0): + return 0 + return None + except Exception: + return None + + # 治本修复:支持 t.CUnsignedLong(-11) 等类型构造调用 + # 当 t.CUnsignedLong(value) / CUnsignedInt(value) / CInt(value) 等被用作常量表达式时, + # 求值参数并返回(按类型的无符号/有符号语义应用位掩码)。 + # 这修复了 stdint.py 中 INFINITE = t.CUnsignedLong(-1) 等常量无法被求值的问题。 + is_ctype_ctor: bool = False + ctype_cls: Any = None + if module_name == 't' and func_name: + ctype_cls = getattr(_t_module, func_name, None) + if ctype_cls is not None and isinstance(ctype_cls, type) and issubclass(ctype_cls, _CType_base): + is_ctype_ctor = True + elif func_name and not module_name: + # from t import CUnsignedLong 形式 + ctype_cls = getattr(_t_module, func_name, None) + if ctype_cls is not None and isinstance(ctype_cls, type) and issubclass(ctype_cls, _CType_base): + is_ctype_ctor = True + # 也检查 _t_type_symbols(符号表中的 t 模块类型符号) + if not is_ctype_ctor and ctx.symtab: + t_type_syms = getattr(ctx.symtab, '_t_type_symbols', {}) + cls_candidate = t_type_syms.get(func_name) + if cls_candidate is not None and isinstance(cls_candidate, type) and issubclass(cls_candidate, _CType_base): + ctype_cls = cls_candidate + is_ctype_ctor = True + + if is_ctype_ctor and node.args: + try: + arg_node: ast.expr = node.args[0] + arg_val: Any = ConstEvaluator.eval_full(arg_node, ctx) + if arg_val is None: + return None + # 按类型的 Size 和 IsSigned 应用位掩码 + size: int | None = getattr(ctype_cls, '_Size', None) + is_signed: bool | None = getattr(ctype_cls, '_IsSigned', None) + # 尝试创建临时实例获取 Size/IsSigned + try: + tmp_inst = ctype_cls() + size = getattr(tmp_inst, 'Size', size) + is_signed = getattr(tmp_inst, 'IsSigned', is_signed) + except Exception: + pass + if isinstance(arg_val, int) and size and size > 0: + mask: int = (1 << size) - 1 + if is_signed: + # 有符号类型:解释为补码 + masked: int = arg_val & mask + if masked >= (1 << (size - 1)): + masked -= (1 << size) + return masked + else: + # 无符号类型:直接掩码 + return arg_val & mask + return arg_val + except Exception: + return None + return None + + @staticmethod + def _eval_arith(node: ast.AST, recurse: Callable[[ast.AST], Any]) -> Optional[Any]: + """通用算术求值:BinOp + UnaryOp""" + if isinstance(node, ast.BinOp): + left: Any = recurse(node.left) + right: Any = recurse(node.right) + if left is None or right is None: + return None + return ConstEvaluator._apply_binop(node.op, left, right) + if isinstance(node, ast.UnaryOp): + operand: Any = recurse(node.operand) + if operand is None: + return None + if isinstance(node.op, ast.USub): + return -operand + if isinstance(node.op, ast.UAdd): + return +operand + if isinstance(node.op, ast.Invert): + return ~operand + return None + return None + + @staticmethod + def _apply_binop(op: ast.operator, left: Any, right: Any) -> Optional[Any]: + """应用二元运算符""" + try: + if isinstance(op, ast.Add): + return left + right + elif isinstance(op, ast.Sub): + return left - right + elif isinstance(op, ast.Mult): + return left * right + elif isinstance(op, ast.Div): + return left // right if isinstance(left, int) and isinstance(right, int) else left / right + elif isinstance(op, ast.FloorDiv): + if isinstance(right, (int, float)) and right == 0: + return None + return left // right + elif isinstance(op, ast.Mod): + if isinstance(right, (int, float)) and right == 0: + return None + return left % right + elif isinstance(op, ast.Pow): + return left ** right + elif isinstance(op, ast.LShift): + return left << right + elif isinstance(op, ast.RShift): + return left >> right + elif isinstance(op, ast.BitOr): + return left | right + elif isinstance(op, ast.BitXor): + return left ^ right + elif isinstance(op, ast.BitAnd): + return left & right + except Exception: + return None + return None + + @staticmethod + def _eval_compare_op(op: ast.cmpop, left: Any, right: Any) -> Optional[bool]: + """应用比较运算符""" + if isinstance(op, ast.Eq): + return left == right + elif isinstance(op, ast.NotEq): + return left != right + elif isinstance(op, ast.Lt): + return left < right + elif isinstance(op, ast.LtE): + return left <= right + elif isinstance(op, ast.Gt): + return left > right + elif isinstance(op, ast.GtE): + return left >= right + return None + + @staticmethod + def _eval_ctype_size_attr(node: ast.Attribute) -> Optional[int]: + """求值 t.CSizeT().Size 等类型构造调用 + .Size 属性模式。 + + 匹配 AST 形态: Attribute(attr='Size', value=Call(func=Attribute(value=Name(id='t'), attr='CSizeT'))) + 或直接 Call(func=Name(id='CSizeT'))(from t import CSizeT 后的使用方式)。 + 返回类型大小(位数),如 CSizeT().Size 返回 64(64 位平台)。 + """ + if node.attr != 'Size': + return None + if not isinstance(node.value, ast.Call): + return None + call_node: ast.Call = node.value + if call_node.args or call_node.keywords: + return None + func: ast.expr = call_node.func + type_name: str | None = None + if isinstance(func, ast.Attribute) and isinstance(func.value, ast.Name) and func.value.id == 't': + type_name = func.attr + elif isinstance(func, ast.Name): + type_name = func.id + if not type_name: + return None + # 延迟导入避免循环依赖 + try: + from lib.includes.t import CTypeRegistry + except Exception: + return None + cls = CTypeRegistry.GetClassByName(type_name) + if cls is None: + return None + try: + instance = cls() + size_val = getattr(instance, 'Size', None) + if isinstance(size_val, int): + return size_val + except Exception: + pass + return None + + @staticmethod + def _eval_attribute_define(node: ast.Attribute, symtab: Any) -> Optional[Any]: + """从 SymbolTable 查找 Attribute 形式的 define 值""" + parts: list[str] = [] + current: ast.AST = node + while isinstance(current, ast.Attribute): + parts.append(current.attr) + current = current.value + if isinstance(current, ast.Name): + parts.append(current.id) + parts.reverse() + attr_name: str = parts[-1] + possible_keys: list[str] = [attr_name, '.'.join(parts)] + for key in possible_keys: + if hasattr(symtab, '__contains__') and key in symtab: + info: CTypeInfo = symtab[key] + if info.IsDefine and isinstance(info.DefineValue, int): + return info.DefineValue + # 模糊匹配 + if len(parts) >= 2: + mod_key: str + mod_info: CTypeInfo + for mod_key, mod_info in (symtab.items() if hasattr(symtab, 'items') else []): + if mod_info.IsDefine and isinstance(mod_info.DefineValue, int): + if mod_key.endswith('.' + attr_name) or mod_key == attr_name: + return mod_info.DefineValue + return None + + @staticmethod + def _intify(val: Any) -> Any: + """float → int 转换(仅当 float 值恰好是整数时)""" + if isinstance(val, float) and val == int(val): + return int(val) + return val + + +class EvalContext: + """常量求值上下文,封装 Gen / SymbolTable / 平台宏查找逻辑。 + + 由调用方构造并传入 ConstEvaluator.eval_full()。 + """ + + def __init__(self, Gen: LlvmCodeGenerator | None = None, symtab: Any = None, platform_macros: dict | None = None, translator: Any = None): + self.Gen: LlvmCodeGenerator | None = Gen + self.symtab: Any = symtab + self._platform_macros: dict | None = platform_macros + self.translator: Any = translator + + def lookup_name(self, name: str) -> Optional[Any]: + """查找 Name 节点的值:define_constants → SymbolTable → 平台宏 + + 治本修复:不再把 module.globals 的 initializer 当常量返回。 + CDefine 不创建 LLVM global(不在 module.globals),仅可变全局变量在 + module.globals 中;把可变全局的 initializer 当编译期常量会让 + range(_sha1_store_count) 等读取处求值成初始值 0 而不生成 load。 + CDefine 通过下方 _define_constants 查询返回常量,双点 bug 不复发。 + """ + # 1. Gen._define_constants + if self.Gen and name in self.Gen._define_constants: + val: Any = self.Gen._define_constants[name] + # 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 通过 + # 共享 _define_constants 覆盖本模块常量 + # (VpiReader.SHA1_LEN=16 被 Phase1.SHA1_LEN=17 覆盖导致双点符号 bug) + _gvar: Any = None + try: + if hasattr(self.Gen, 'module') and name in self.Gen.module.globals: + _gvar = self.Gen.module.globals[name] + except Exception: + _gvar = None + if _gvar is not None and getattr(_gvar, 'initializer', None) is not None: + _init: Any = _gvar.initializer + if hasattr(_init, 'constant') and isinstance(_init.constant, (int, float)): + val = _init.constant + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + + # 2. Gen._DefineConstants (大写版本) + if self.Gen and hasattr(self.Gen, '_DefineConstants') and name in self.Gen._DefineConstants: + val: Any = self.Gen._DefineConstants[name] + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + + # 3. SymbolTable + if self.symtab and name in self.symtab: + info: CTypeInfo = self.symtab[name] + val: Any = info.value + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + if info.IsDefine and isinstance(info.DefineValue, (int, float)): + return ConstEvaluator._intify(info.DefineValue) + + # 4. 平台宏 + macros: dict = self._get_platform_macros() + if name in macros: + return macros[name] + + return None + + def lookup_attribute(self, node: ast.Attribute) -> Optional[Any]: + """查找 Attribute 节点的值""" + module_name: str | None = node.value.id if isinstance(node.value, ast.Name) else None + attr_name: str = node.attr + + if module_name and attr_name: + combined_key: str = f"{module_name}.{attr_name}" + + # 1. Gen._define_constants + if self.Gen and combined_key in self.Gen._define_constants: + val: Any = self.Gen._define_constants[combined_key] + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + + # 2. SymbolTable (精确匹配 + 后缀匹配) + if self.symtab: + key: str + info: CTypeInfo + for key, info in self.symtab.items(): + if key.endswith(f".{combined_key}") or key == combined_key: + if info.IsDefine and isinstance(info.DefineValue, (int, float)): + return ConstEvaluator._intify(info.DefineValue) + + # 3. _all_define_constants + all_dc: dict = self._get_all_define_constants() + if combined_key in all_dc: + val: Any = all_dc[combined_key] + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + if attr_name in all_dc: + val: Any = all_dc[attr_name] + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + dc_key: str + dc_val: Any + for dc_key, dc_val in all_dc.items(): + if dc_key == attr_name or dc_key.endswith(f".{attr_name}"): + if isinstance(dc_val, (int, float)): + return ConstEvaluator._intify(dc_val) + + # 4. SymbolTable 短名查找 + if self.symtab and attr_name in self.symtab: + info: CTypeInfo = self.symtab[attr_name] + if info.IsDefine and isinstance(info.DefineValue, (int, float)): + return ConstEvaluator._intify(info.DefineValue) + + # 5. Gen._define_constants 短名 + if self.Gen and attr_name in self.Gen._define_constants: + val: Any = self.Gen._define_constants[attr_name] + if isinstance(val, (int, float)): + return ConstEvaluator._intify(val) + + # 6. 平台宏 + macros: dict = self._get_platform_macros() + full_key: str | None = self._get_attr_full_name(node) + if full_key: + if full_key in macros: + return macros[full_key] + short_name: str = full_key.split('.')[-1] if '.' in full_key else full_key + if short_name in macros: + return macros[short_name] + + return None + + def _get_all_define_constants(self) -> dict: + """获取 _all_define_constants""" + if self.Gen and hasattr(self.Gen, '_all_define_constants'): + return self.Gen._all_define_constants + return {} + + def _get_platform_macros(self) -> dict: + """获取平台宏""" + if self._platform_macros is not None: + return self._platform_macros + if not self.Gen: + return {} + macros: dict[str, int] = {} + pi: dict = self.Gen._platform_info + ptr_size: int = self.Gen.ptr_size + if pi.get('is_windows'): + macros['_WIN32'] = 1 + if not pi.get('is_32bit'): + macros['_WIN64'] = 1 + macros['WIN64'] = 1 + macros['WIN32'] = 1 + if pi.get('is_linux'): + macros['__linux__'] = 1 + if pi.get('is_macos'): + macros['__APPLE__'] = 1 + macros['__MACH__'] = 1 + if pi.get('is_x86_64'): + macros['__x86_64__'] = 1 + macros['__x86_64'] = 1 + macros['_M_X64'] = 1 + elif pi.get('is_arm64'): + macros['__aarch64__'] = 1 + macros['_M_ARM64'] = 1 + if not pi.get('is_32bit') and pi.get('is_linux'): + macros['__LP64__'] = 1 + elif pi.get('is_32bit'): + macros['_ILP32'] = 1 + macros['SIZEOF_VOID_P'] = ptr_size + macros['__SIZEOF_POINTER__'] = ptr_size + macros['NDEBUG'] = 0 + return macros + + @staticmethod + def _get_attr_full_name(node: ast.Attribute) -> Optional[str]: + """从 Attribute 节点提取完整名称 (e.g. 'module.name')""" + parts: list[str] = [] + current: ast.AST = node + while isinstance(current, ast.Attribute): + parts.append(current.attr) + current = current.value + if isinstance(current, ast.Name): + parts.append(current.id) + parts.reverse() + return '.'.join(parts) if parts else None diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index a1c8411..f6a4ec6 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -import ast +import vast as ast import llvmlite.ir as ir from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo from lib.core.VLogger import get_logger as _vlog diff --git a/lib/core/Handles/HandlesAssert.py b/lib/core/Handles/HandlesAssert.py index 93b0392..6cf2266 100644 --- a/lib/core/Handles/HandlesAssert.py +++ b/lib/core/Handles/HandlesAssert.py @@ -1,60 +1,60 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP -import ast -import llvmlite.ir as ir - -class AssertHandle(BaseHandle): - def _HandleAssertLlvm(self, Node: ast.Assert) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - cond_val: ir.Value | None = self.HandleExprLlvm(Node.test) - if not cond_val: - return - if not isinstance(cond_val.type, ir.IntType) or cond_val.type.width != 1: - zero: ir.Constant = ir.Constant(cond_val.type, 0) - cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond") - AssertFailBB: ir.Block = Gen.func.append_basic_block(name="assert.fail") - AssertOkBB: ir.Block = Gen.func.append_basic_block(name="assert.ok") - Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB) - Gen.builder.position_at_start(AssertFailBB) - exc_code: int = 9 - exc_msg: ir.Value | None = None - if Node.msg: - if isinstance(Node.msg, ast.Constant) and isinstance(Node.msg.value, str): - exc_msg = self.HandleExprLlvm(Node.msg) - elif isinstance(Node.msg, ast.Call) and isinstance(Node.msg.func, ast.Name): - exc_code = EXCEPTION_CODE_MAP.get(Node.msg.func.id, 99) - if Node.msg.args: - first_arg: ast.expr = Node.msg.args[0] - if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): - exc_msg = self.HandleExprLlvm(first_arg) - elif isinstance(Node.msg, ast.Name): - exc_code = EXCEPTION_CODE_MAP.get(Node.msg.id, 99) - else: - exc_msg = self.HandleExprLlvm(Node.msg) - if Gen.eh_except_block_stack: - ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0] - EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1] - exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2] - eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3] - Gen._store(ir.Constant(ir.IntType(32), exc_code), exception_code) - if exc_msg: - Gen._store(exc_msg, eh_message) - else: - null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) - Gen._store(null_ptr, eh_message) - Gen.builder.branch(ExceptBB) - else: - printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) - if exc_msg: - fmt: ir.Value = Gen.emit_constant("AssertionError: %s\n", 'string') - Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print") - else: - fmt: ir.Value = Gen.emit_constant("AssertionError\n", 'string') - Gen.builder.call(printf_func, [fmt], name="assert_fail_print") - exit_func: ir.Function = Gen.get_or_declare_c_func('exit', ir.FunctionType(ir.VoidType(), [ir.IntType(32)])) - Gen.builder.call(exit_func, [ir.Constant(ir.IntType(32), 1)], name="call_exit") - Gen.builder.unreachable() +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP +import vast as ast +import llvmlite.ir as ir + +class AssertHandle(BaseHandle): + def _HandleAssertLlvm(self, Node: ast.Assert) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + cond_val: ir.Value | None = self.HandleExprLlvm(Node.test) + if not cond_val: + return + if not isinstance(cond_val.type, ir.IntType) or cond_val.type.width != 1: + zero: ir.Constant = ir.Constant(cond_val.type, 0) + cond_val = Gen.builder.icmp_signed('!=', cond_val, zero, name="assert_cond") + AssertFailBB: ir.Block = Gen.func.append_basic_block(name="assert.fail") + AssertOkBB: ir.Block = Gen.func.append_basic_block(name="assert.ok") + Gen.builder.cbranch(cond_val, AssertOkBB, AssertFailBB) + Gen.builder.position_at_start(AssertFailBB) + exc_code: int = 9 + exc_msg: ir.Value | None = None + if Node.msg: + if isinstance(Node.msg, ast.Constant) and isinstance(Node.msg.value, str): + exc_msg = self.HandleExprLlvm(Node.msg) + elif isinstance(Node.msg, ast.Call) and isinstance(Node.msg.func, ast.Name): + exc_code = EXCEPTION_CODE_MAP.get(Node.msg.func.id, 99) + if Node.msg.args: + first_arg: ast.expr = Node.msg.args[0] + if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): + exc_msg = self.HandleExprLlvm(first_arg) + elif isinstance(Node.msg, ast.Name): + exc_code = EXCEPTION_CODE_MAP.get(Node.msg.id, 99) + else: + exc_msg = self.HandleExprLlvm(Node.msg) + if Gen.eh_except_block_stack: + ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0] + EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1] + exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2] + eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3] + Gen._store(ir.Constant(ir.IntType(32), exc_code), exception_code) + if exc_msg: + Gen._store(exc_msg, eh_message) + else: + null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) + Gen._store(null_ptr, eh_message) + Gen.builder.branch(ExceptBB) + else: + printf_func: ir.Function = Gen.get_or_declare_c_func('printf', ir.FunctionType(ir.IntType(32), [ir.PointerType(ir.IntType(8))], var_arg=True)) + if exc_msg: + fmt: ir.Value = Gen.emit_constant("AssertionError: %s\n", 'string') + Gen.builder.call(printf_func, [fmt, exc_msg], name="assert_fail_print") + else: + fmt: ir.Value = Gen.emit_constant("AssertionError\n", 'string') + Gen.builder.call(printf_func, [fmt], name="assert_fail_print") + exit_func: ir.Function = Gen.get_or_declare_c_func('exit', ir.FunctionType(ir.VoidType(), [ir.IntType(32)])) + Gen.builder.call(exit_func, [ir.Constant(ir.IntType(32), 1)], name="call_exit") + Gen.builder.unreachable() Gen.builder.position_at_start(AssertOkBB) \ No newline at end of file diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index a88957e..db7e20a 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -1,1754 +1,1754 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Any -if TYPE_CHECKING: - from lib.core.translator import Translator -import ast -import sys -import llvmlite.ir as ir -from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta -from lib.core.VLogger import get_logger as _vlog -from lib.core.ConstEvaluator import ConstEvaluator, EvalContext -from lib.constants.config import mode as _config_mode -from lib.includes import t -from lib.includes.t import CTypeRegistry -from lib.core.SymbolUtils import IsTModule, ParseListAnnotation, AnnotationContainsName - -class AssignHandle(BaseHandle): - def __init__(self, translator: "Translator") -> None: - super().__init__(translator) - self._CurrentCpythonObjectClass: str | None = None - - @staticmethod - def _contains_identified_struct(var_type: ir.Type) -> bool: - if isinstance(var_type, ir.IdentifiedStructType): - return True - if isinstance(var_type, ir.ArrayType): - return AssignHandle._contains_identified_struct(var_type.element) - if isinstance(var_type, ir.PointerType): - return AssignHandle._contains_identified_struct(var_type.pointee) - if isinstance(var_type, ir.BaseStructType): - if var_type.elements: - return any(AssignHandle._contains_identified_struct(e) for e in var_type.elements) - return False - - def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None: - return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType) - - def _HandleAssignLlvm(self, Node: ast.Assign) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - Gen._set_node_info(Node, "Assign") - if len(Node.targets) == 1: - Target: ast.expr = Node.targets[0] - if isinstance(Target, ast.Name): - VarName: str = Target.id - if VarName in Gen.var_const_flags: - src_info: str = Gen._get_node_info() - _vlog().error(f"不能对 const 变量 '{VarName}' 赋值{src_info}") - sys.exit(1) - if isinstance(Node.value, ast.Attribute) and isinstance(Node.value.value, ast.Name) and IsTModule(Node.value.value.id, self.Trans.SymbolTable): - AttrName: str = Node.value.attr - Gen.var_type_info[VarName] = {'type': 't_type', 'name': AttrName} - Gen.var_type_assignments.setdefault(VarName, []).append({'type': 't_type', 'name': AttrName}) - c_type_name: str = '' - resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(AttrName) - if resolved is not None: - ctype_cls: type = resolved[0] - ptr_level: int = resolved[1] - c_type_name = CTypeRegistry.CTypeToName(ctype_cls) - if ptr_level > 0 and c_type_name: - c_type_name = c_type_name + ' *' - if not c_type_name: - if AttrName == 'CPtr': - c_type_name = 'void *' - is_unsigned: bool = Gen._is_type_unsigned(c_type_name) if c_type_name else False - fmt_str: str = "%u\n" if is_unsigned else "%d\n" - fmt_ptr: ir.Value = Gen._create_string_global(fmt_str) - fmt_var_name: str = f"__{VarName}_fmt" - if fmt_var_name not in Gen.variables: - fmt_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) - Gen.variables[fmt_var_name] = fmt_alloca - Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name]) - kind_var_name: str = f"__{VarName}_kind" - if kind_var_name not in Gen.variables: - kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=kind_var_name) - Gen.variables[kind_var_name] = kind_alloca - Gen.builder.store(ir.Constant(ir.IntType(32), 0), Gen.variables[kind_var_name]) - if VarName not in Gen.variables: - dummy_var: ir.AllocaInstr = Gen._alloca(ir.IntType(8), name=VarName) - Gen.variables[VarName] = dummy_var - return - if isinstance(Node.value, ast.Name) and Node.value.id in Gen.structs: - ClassName: str = Node.value.id - Gen.var_type_info[VarName] = {'type': 'class_cast', 'name': ClassName} - Gen.var_type_assignments.setdefault(VarName, []).append({'type': 'class_cast', 'name': ClassName}) - fmt_str: str = "%p\n" - fmt_ptr: ir.Value = Gen._create_string_global(fmt_str) - fmt_var_name: str = f"__{VarName}_fmt" - if fmt_var_name not in Gen.variables: - fmt_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) - Gen.variables[fmt_var_name] = fmt_alloca - Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name]) - kind_var_name: str = f"__{VarName}_kind" - if kind_var_name not in Gen.variables: - kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=kind_var_name) - Gen.variables[kind_var_name] = kind_alloca - Gen.builder.store(ir.Constant(ir.IntType(32), 1), Gen.variables[kind_var_name]) - if VarName not in Gen.variables: - dummy_var: ir.AllocaInstr = Gen._alloca(ir.IntType(8), name=VarName) - Gen.variables[VarName] = dummy_var - return - if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == 'va_list': - va_list_ptr: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name="va_list") - Gen.variables[VarName] = va_list_ptr - return - IsStructCtor: bool = (isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) - and Node.value.func.id in Gen.structs) - if IsStructCtor: - ClassName: str = Node.value.func.id - StructType: ir.Type = Gen.structs[ClassName] - - IsUnion: bool = False - TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(ClassName) - if TypeInfo and TypeInfo.IsUnion: - IsUnion = True - - if IsUnion: - Value: ir.Value | None = self.HandleExprLlvm(Node.value) - if Value: - var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) - Gen._store(Value, var) - Gen.variables[VarName] = var - return - - ExistingPtr: ir.Value | None = None - # BUG-8 修复:清除读取全局变量时缓存的 GlobalVariable(非显式 global 声明) - if (VarName in Gen.variables and VarName not in Gen.global_vars - and isinstance(Gen.variables[VarName], ir.GlobalVariable)): - del Gen.variables[VarName] - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr: ir.Value = Gen.variables[VarName] - if isinstance(VarPtr.type.pointee, ir.PointerType): - ExistingPtr = VarPtr - elif VarName in Gen._reg_values: - OldVal: ir.Value = Gen._reg_values[VarName] - if isinstance(OldVal.type, ir.PointerType): - var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) - Gen._store(OldVal, var) - Gen.variables[VarName] = var - del Gen._reg_values[VarName] - ExistingPtr = var - elif VarName in Gen._direct_values: - OldVal: ir.Value = Gen._direct_values.pop(VarName) - if isinstance(OldVal.type, ir.PointerType): - var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) - Gen._store(OldVal, var) - Gen.variables[VarName] = var - ExistingPtr = var - if ExistingPtr: - pointee: ir.Type = ExistingPtr.type.pointee - # 仅当 alloca 直接存储结构体值(pointee 不是指针)时才 in-place 初始化。 - # 当 pointee 是 PointerType 时,alloca 存储的是堆对象指针: - # - 若 AnnAssign 分支未执行,alloca 内容是未初始化的栈垃圾 - # (可能恰好等于 pool 地址),_InitStructAtPtr 会向垃圾地址写字段 → 内存损坏 - # - 即使指针有效,node = Class(...) 的语义也是创建新对象并更新指针, - # 而非在旧对象位置 in-place 重初始化 - # 此时必须 fall through 到通用路径 HandleExprLlvm → _HandleClassNewLlvm - # 以正确调用 __new__/__before_init__/__init__ 构造新对象。 - if not isinstance(pointee, ir.PointerType) and pointee == StructType: - self._InitStructAtPtr(Node.value, ClassName, ExistingPtr) - return - if isinstance(Node.value, ast.Attribute): - enum_type_name: str | None = self._CheckEnumMemberAssignment(Node.value) - if enum_type_name: - Gen.var_type_info[VarName] = {'type': 'enum', 'name': enum_type_name} - var_type_for_list: ir.Type | None = None - if isinstance(Node.value, ast.List) and VarName in Gen.var_type_info: - type_info: dict[str, str] = Gen.var_type_info[VarName] - if type_info.get('type') == 'CArray': - var_type_for_list = type_info.get('full_type') - Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=var_type_for_list) - # 闭包变量追踪:当赋值右侧是返回闭包的函数调用时,记录变量为闭包类型 - if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): - CalledName: str = Node.value.func.id - if CalledName in Gen._closure_return_types: - Gen._closure_var_types[VarName] = Gen._closure_return_types[CalledName] - if not Value: - return - if isinstance(Value.type, ir.VoidType): - return - Gen._UnregisterTempPtr(Value) - # 大端局部变量:赋值时 bswap - Value = Gen._apply_bswap_if_big(Value, Gen.local_var_byteorders.get(VarName, ""), f"bswap_assign_{VarName}") - if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - found_class: str | None = None - found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(Value.type.pointee) - if found: - CN: str = found[0] - ST: ir.Type = found[1] - found_class = CN - Gen.var_struct_class[VarName] = CN - Gen._var_to_heap_ptr[VarName] = Value - if found_class is None and isinstance(Value.type.pointee, ir.IdentifiedStructType): - pointee_name: str = Value.type.pointee.name - pointee_short: str = Gen._extract_short_name(pointee_name) - best_elem_count: int = 0 - for CN, ST in Gen.structs.items(): - if isinstance(ST, ir.IdentifiedStructType): - st_short: str = Gen._extract_short_name(ST.name) - if st_short == pointee_short: - elem_count: int = len(ST.elements) if ST.elements else 0 - if elem_count > best_elem_count: - found_class = CN - best_elem_count = elem_count - if found_class: - Gen.var_struct_class[VarName] = found_class - Gen._var_to_heap_ptr[VarName] = Value - # 泛型类特化触发:返回类型是泛型类特化(如 list[str])但结构体尚未创建, - # 或虽然找到了结构体但它是 opaque(来自 stub 声明,尚未发射方法体) - _fd_struct_opaque: bool = False - if found_class and found_class in Gen.structs: - _fd_st: ir.IdentifiedStructType = Gen.structs[found_class] - if isinstance(_fd_st, ir.IdentifiedStructType) and (_fd_st.elements is None or len(_fd_st.elements) == 0): - _fd_struct_opaque = True - if (found_class is None or _fd_struct_opaque) and isinstance(Value.type.pointee, ir.IdentifiedStructType): - pn: str = Value.type.pointee.name - short_pn: str = pn - if '.' in pn: - pn_parts: list[str] = pn.split('.', 1) - if len(pn_parts[0]) >= 8 and all(c in '0123456789abcdef' for c in pn_parts[0]): - short_pn = pn_parts[1] - if '[' in short_pn and short_pn.endswith(']'): - gc_base: str = short_pn.split('[')[0] - gc_args_raw: str = short_pn[len(gc_base):] - gc_type_args: list[str] = [] - for gc_arg_part in gc_args_raw.split(']['): - gc_arg_part = gc_arg_part.strip('[]') - if gc_arg_part: - gc_type_args.append(gc_arg_part) - if (gc_type_args - and hasattr(self.Trans.ClassHandler, '_generic_class_templates') - and gc_base in self.Trans.ClassHandler._generic_class_templates): - gc_type_names: list[str] = [] - for gc_ta in gc_type_args: - gc_tn: str = gc_ta - if gc_ta == 'int': - gc_tn = 'CInt' - elif gc_ta == 'double': - gc_tn = 'CDouble' - elif gc_ta == 'float': - gc_tn = 'CFloat' - elif gc_ta == 'char': - gc_tn = 'CChar' - elif gc_ta == 'bool': - gc_tn = 'CBool' - gc_type_names.append(gc_tn) - gc_spec: str | None = self.Trans.ClassHandler._specialize_generic_class( - gc_base, gc_type_args, Gen, type_names=gc_type_names) - if gc_spec and gc_spec in Gen.structs: - found_class = gc_spec - Gen.var_struct_class[VarName] = gc_spec - Gen._var_to_heap_ptr[VarName] = Value - else: - if VarName in ('mctx', 's1ctx', 's2ctx', 's5ctx'): - pass - if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - # BUG-8 修复:清除读取全局变量时缓存的 GlobalVariable(非显式 global 声明) - if (VarName in Gen.variables and VarName not in Gen.global_vars - and isinstance(Gen.variables[VarName], ir.GlobalVariable)): - del Gen.variables[VarName] - if VarName in Gen.variables and Gen.variables[VarName] is not None: - Gen._store(Value, Gen.variables[VarName]) - else: - var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) - Gen._store(Value, var) - Gen.variables[VarName] = var - if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): - call_func_name: str = Node.value.func.id - if call_func_name in Gen.var_type_info: - type_info: dict[str, str] = Gen.var_type_info[call_func_name] - if type_info['type'] in ('t_type', 'class_cast'): - src_fmt_var: str = f"__{call_func_name}_fmt" - dst_fmt_var: str = f"__{VarName}_fmt" - if src_fmt_var in Gen.variables: - if dst_fmt_var not in Gen.variables: - dst_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) - Gen.variables[dst_fmt_var] = dst_alloca - src_fmt_ptr: ir.Value = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}") - Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var]) - src_kind_var: str = f"__{call_func_name}_kind" - dst_kind_var: str = f"__{VarName}_kind" - if src_kind_var in Gen.variables: - if dst_kind_var not in Gen.variables: - dst_kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var) - Gen.variables[dst_kind_var] = dst_kind_alloca - src_kind_val: ir.Value = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}") - Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var]) - Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} - return - if VarName in Gen.global_vars: - # 治本修复:global 声明的变量若未被模块级 AnnAssign 创建为 LLVM 全局 - # (注解无初始值的全局变量),此处自动创建零初始化全局变量 - GVar: ir.GlobalVariable - if VarName not in Gen.module.globals: - _gv_type: ir.Type = Value.type if isinstance(Value.type, (ir.IntType, ir.PointerType)) else ir.IntType(64) - GVar = ir.GlobalVariable(Gen.module, _gv_type, name=VarName) - GVar.initializer = ir.Constant(_gv_type, None) if isinstance(_gv_type, ir.PointerType) else ir.Constant(_gv_type, 0) - else: - GVar = Gen.module.globals[VarName] - Gen._store(Value, GVar) - Gen.variables[VarName] = GVar - if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(Value.type.pointee) - if found: - CN: str = found[0] - ST: ir.Type = found[1] - Gen.var_struct_class[VarName] = CN - return - if VarName in Gen._reg_values: - OldVal: ir.Value = Gen._reg_values[VarName] - var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) - Gen._store(OldVal, var) - Gen.variables[VarName] = var - del Gen._reg_values[VarName] - if VarName in Gen._direct_values: - OldVal: ir.Value = Gen._direct_values.pop(VarName) - var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) - Gen._store(OldVal, var) - Gen.variables[VarName] = var - # BUG-8 修复:清除读取全局变量时缓存的 GlobalVariable(非显式 global 声明)。 - # Python 语义:函数内无 global 声明时赋值应创建局部变量, - # 而非修改被读取缓存的全局变量。清除后走 L339 的正确逻辑。 - if (VarName in Gen.variables and VarName not in Gen.global_vars - and isinstance(Gen.variables[VarName], ir.GlobalVariable)): - del Gen.variables[VarName] - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr: ir.Value = Gen.variables[VarName] - TargetType: ir.Type | None = VarPtr.type.pointee if isinstance(VarPtr.type, ir.PointerType) else None - types_differ: bool - try: - types_differ = TargetType and Value.type != TargetType - except AssertionError: - types_differ = False - if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType): - LoadedValue: ir.Value = Gen._load(Value, name=f"Load_{VarName}") - Loaded_differ: bool - try: - Loaded_differ = TargetType and LoadedValue.type != TargetType - except AssertionError: - Loaded_differ = False - if Loaded_differ: - try: - Coerced: ir.Value | None = Gen._coerce_value(LoadedValue, TargetType) - if Coerced is not None: - LoadedValue = Coerced - except AssertionError: - pass - Gen._store(LoadedValue, VarPtr) - elif types_differ: - try: - Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType) - if Coerced is not None: - Gen._store(Coerced, VarPtr) - else: - Gen._store(Value, VarPtr) - except AssertionError: - Gen._store(Value, VarPtr) - else: - Gen._store(Value, VarPtr) - if VarName not in Gen.variables: - # 检查是否为模块级全局变量 - # main 函数代表模块级作用域,直接修改全局变量 - # 其他函数中,未声明 global 且未先读取的赋值创建局部变量(Python 作用域语义) - # 先读取过的变量已通过 HandleExprLlvm 加入 Gen.variables,会走 L289 分支存储到全局 - CurrentFuncName: str = getattr(Gen.func, 'name', '') if Gen.func else '' - IsMainScope: bool = CurrentFuncName == 'main' or CurrentFuncName.endswith('.main') - if VarName in Gen.module.globals and (VarName in Gen.global_vars or IsMainScope): - GVar: ir.GlobalVariable = Gen.module.globals[VarName] - Gen._store(Value, GVar) - Gen.variables[VarName] = GVar - elif isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType): - LoadedValue: ir.Value = Gen._load(Value, name=f"Load_{VarName}") - var: ir.AllocaInstr = Gen._allocaEntry(LoadedValue.type, name=VarName) - Gen._store(LoadedValue, var) - Gen.variables[VarName] = var - else: - var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) - Gen._store(Value, var) - Gen.variables[VarName] = var - is_u: bool = Gen._check_node_unsigned(Node.value) - Gen._record_var_signedness(VarName, 'unsigned int' if is_u else 'int') - if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): - call_func_name: str = Node.value.func.id - if call_func_name in Gen.var_type_info: - type_info: dict[str, str] = Gen.var_type_info[call_func_name] - if type_info['type'] in ('t_type', 'class_cast'): - src_fmt_var: str = f"__{call_func_name}_fmt" - dst_fmt_var: str = f"__{VarName}_fmt" - if src_fmt_var in Gen.variables: - if dst_fmt_var not in Gen.variables: - dst_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) - Gen.variables[dst_fmt_var] = dst_alloca - src_fmt_ptr: ir.Value = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}") - Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var]) - src_kind_var: str = f"__{call_func_name}_kind" - dst_kind_var: str = f"__{VarName}_kind" - if src_kind_var in Gen.variables: - if dst_kind_var not in Gen.variables: - dst_kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var) - Gen.variables[dst_kind_var] = dst_kind_alloca - src_kind_val: ir.Value = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}") - Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var]) - Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} - else: - Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} - elif isinstance(Target, ast.Attribute): - TargetType: ir.Type | None = None - AttrName: str = Target.attr - VarName: str | None = None - if isinstance(Target.value, ast.Name): - VarName = Target.value.id - if VarName: - ClassName: str | None = Gen.var_struct_class.get(VarName) - if not ClassName and Gen.global_struct_class: - ClassName = Gen.global_struct_class.get(VarName) - if ClassName: - Gen.var_struct_class[VarName] = ClassName - if not ClassName: - for CN in Gen.structs: - if VarName == CN.lower() or VarName.startswith(CN): - ClassName = CN - break - if ClassName and ClassName in Gen.class_members: - for m_name, m_type in Gen.class_members[ClassName]: - if m_name == AttrName: - TargetType = m_type - break - Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=TargetType) - if Value: - self._HandleAttributeStoreLlvm(Target, Value) - elif isinstance(Target, ast.Subscript): - TargetType: ir.Type | None = None - SubVarName: str | None = None - if isinstance(Target.value, ast.Name): - SubVarName = Target.value.id - if SubVarName in Gen.var_struct_class: - ClassName: str = Gen.var_struct_class[SubVarName] - if ClassName in Gen.class_members: - for m_name, m_type in Gen.class_members[ClassName]: - if m_name == SubVarName: - if isinstance(m_type, ir.PointerType): - pointee: ir.Type = m_type.pointee - if isinstance(pointee, ir.ArrayType): - TargetType = pointee.element - elif isinstance(m_type, ir.ArrayType): - TargetType = m_type.element - break - if not TargetType and isinstance(Target.value, ast.Name): - SubVarName = Target.value.id - var_val: ir.Value | None = Gen.variables.get(SubVarName) - if var_val is None and SubVarName in Gen._direct_values: - var_val = Gen._direct_values[SubVarName] - if var_val is not None: - var_type: ir.Type = var_val.type - if isinstance(var_type, ir.PointerType): - pointee: ir.Type = var_type.pointee - if isinstance(pointee, ir.ArrayType): - TargetType = pointee.element - elif isinstance(var_type, ir.ArrayType): - TargetType = var_type.element - Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=TargetType) - if Value: - self._HandleSubscriptStoreLlvm(Target, Value) - elif isinstance(Target, ast.Tuple): - if isinstance(Node.value, ast.Call): - FuncName: str | None = None - ModulePath: str | None = None - if isinstance(Node.value.func, ast.Name): - FuncName = Node.value.func.id - elif isinstance(Node.value.func, ast.Attribute): - FuncName = Node.value.func.attr - ModulePath = self.Trans.ExprCallHandle._get_ModulePath(Node.value.func.value) - CReturnTypes: list[ast.expr] = [] - FuncDef: ast.FunctionDef | None = self.Trans.FunctionDefCache.get(FuncName) if FuncName else None - if FuncDef: - if FuncDef.returns and isinstance(FuncDef.returns, ast.Subscript): - if isinstance(FuncDef.returns.value, ast.Name) and FuncDef.returns.value.id == 'tuple': - slice_node: ast.expr = FuncDef.returns.slice - if isinstance(slice_node, ast.Tuple): - CReturnTypes = slice_node.elts - else: - CReturnTypes = [slice_node] - if FuncDef.decorator_list: - for decorator in FuncDef.decorator_list: - if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): - if decorator.func.attr == 'CReturn': - for arg in decorator.args: - CReturnTypes.append(arg) - if not CReturnTypes and FuncName: - func: ir.Function | None = Gen.functions.get(FuncName) - if func: - func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) - if func_ft: - ret_type: ir.Type = func_ft.return_type - if isinstance(ret_type, ir.LiteralStructType): - CReturnTypes = [None] * len(ret_type.elements) - if not CReturnTypes: - sym_key: str = FuncName - if not self.Trans.SymbolTable.has(sym_key): - if ModulePath: - sym_key = f"{ModulePath}.{FuncName}" - sym_info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(sym_key) - if sym_info and sym_info.IsFunction: - ret_type_info: CTypeInfo | None = sym_info.FuncPtrReturn - param_type_infos: list[tuple[str, CTypeInfo]] = [pt for _, pt in (sym_info.FuncPtrParams or [])] - if ret_type_info: - if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: - ret_type: ir.Type = ret_type_info.ToLLVM(Gen) - else: - ret_type = Gen._type_str_to_llvm(str(ret_type_info) if ret_type_info else 'i32', False) - if isinstance(ret_type, ir.LiteralStructType): - CReturnTypes = [None] * len(ret_type.elements) - if FuncName not in Gen.functions: - if isinstance(ret_type, ir.VoidType): - ret_type = ir.IntType(32) - llvm_param_types: list[ir.Type] = [] - for pt in param_type_infos: - if isinstance(pt, CTypeInfo) and pt.BaseType: - lp: ir.Type = pt.ToLLVM(Gen) - else: - lp = Gen._type_str_to_llvm(str(pt) if pt else 'i32', '*' in str(pt) if isinstance(pt, str) else False) - if isinstance(lp, ir.VoidType): - lp = ir.IntType(8).as_pointer() - llvm_param_types.append(lp) - func_type: ir.FunctionType = ir.FunctionType(ret_type, llvm_param_types) - MangledName: str = Gen._mangle_func_name(FuncName) - func_decl: ir.Function = ir.Function(Gen.module, func_type, name=MangledName) - Gen.functions[MangledName] = func_decl - Gen.functions[FuncName] = func_decl - if not CReturnTypes and FuncName: - func: ir.Function | None = Gen.functions.get(FuncName) - if func: - func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) - if func_ft: - ret_type: ir.Type = func_ft.return_type - if isinstance(ret_type, ir.LiteralStructType): - CReturnTypes = [None] * len(ret_type.elements) - if not CReturnTypes: - # 跨模块多返回值兜底:短名未注册时(函数以 ModulePath.名 / - # sha1.名 全名注册),从其 LiteralStructType 返回类型恢复 CReturnTypes。 - # 否则 CReturnTypes 为空会走下方静默 return,目标变量未初始化, - # 运行期 free(垃圾指针) 触发堆损坏(HashLibTest 0xC0000374)。 - func = None - if ModulePath: - func = Gen.functions.get(f"{ModulePath}.{FuncName}") - if func is None: - for key in Gen.functions: - if key.endswith(f".{FuncName}"): - func = Gen.functions[key] - break - if func: - func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) - if func_ft: - ret_type: ir.Type = func_ft.return_type - if isinstance(ret_type, ir.LiteralStructType): - CReturnTypes = [None] * len(ret_type.elements) - if CReturnTypes and len(Target.elts) == len(CReturnTypes): - if func is None: - func = Gen.functions.get(FuncName) - CallArgs: list[ir.Value | None] = [] - for arg in Node.value.args: - ArgVal: ir.Value | None = self.HandleExprLlvm(arg) - if ArgVal: - CallArgs.append(ArgVal) - for kw in Node.value.keywords: - pass - func: ir.Function | None = Gen.functions.get(FuncName) - func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) if func else None - func_params: list[ir.Type] = list(getattr(func_ft, 'args', []) or []) if func_ft else [] - while len(CallArgs) < len(func_params): - FuncDef: ast.FunctionDef | None = self.Trans.FunctionDefCache.get(FuncName) - if FuncDef and len(CallArgs) < len(FuncDef.args.args): - arg_def: list[ast.expr] = FuncDef.args.defaults - arg_idx: int = len(CallArgs) - total_args: int = len(FuncDef.args.args) - default_start: int = total_args - len(arg_def) - if arg_idx >= default_start: - def_idx: int = arg_idx - default_start - if def_idx < len(arg_def): - DefVal: ir.Value | None = self.HandleExprLlvm(arg_def[def_idx]) - if DefVal: - expected_type: ir.Type = func_params[arg_idx] - if DefVal.type != expected_type: - if isinstance(expected_type, ir.IntType) and isinstance(DefVal.type, ir.IntType): - if DefVal.type.width < expected_type.width: - DefVal = Gen.builder.zext(DefVal, expected_type, name=f"zext_default_{arg_idx}") - elif DefVal.type.width > expected_type.width: - DefVal = Gen.builder.trunc(DefVal, expected_type, name=f"trunc_default_{arg_idx}") - CallArgs.append(DefVal) - continue - if len(CallArgs) < len(func_params): - CallArgs.append(ir.Constant(func_params[len(CallArgs)], 0)) - else: - break - adjusted: list[ir.Value] = Gen._adjust_args(CallArgs, func) - call_result: ir.Value = Gen.builder.call(func, adjusted, name=f"call_{FuncName}") - func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) - ret_type: ir.Type | None = getattr(func_ft, 'return_type', None) if func_ft else None - for j, elt in enumerate(Target.elts): - if isinstance(elt, ast.Name): - VarName: str = elt.id - field_val: ir.Value = Gen.builder.extract_value(call_result, j, name=f"extract_{FuncName}_{j}") - VarType: ir.Type - if CReturnTypes[j] is not None: - ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(CReturnTypes[j], self.Trans.SymbolTable) - if ReturnTypeInfo is None: - ReturnTypeInfo = CTypeInfo() - ReturnTypeInfo.BaseType = t.CInt() - VarType = Gen._ctype_to_llvm(ReturnTypeInfo) - elif ret_type and isinstance(ret_type, ir.LiteralStructType) and j < len(ret_type.elements): - VarType = ret_type.elements[j] - else: - VarType = field_val.type - if isinstance(VarType, ir.VoidType): - VarType = ir.IntType(32) - var: ir.AllocaInstr = Gen._alloca(VarType, name=VarName) - Gen.variables[VarName] = var - if CReturnTypes[j] is not None: - Gen._record_var_signedness(VarName, str(ReturnTypeInfo) if ReturnTypeInfo else '') - elif ret_type and isinstance(ret_type, ir.LiteralStructType) and j < len(ret_type.elements): - elem_type: ir.Type = ret_type.elements[j] - if isinstance(elem_type, ir.IntType): - if elem_type.width == 16: - Gen._record_var_signedness(VarName, 'unsigned short') - elif elem_type.width == 32: - Gen._record_var_signedness(VarName, 'unsigned int') - elif elem_type.width == 64: - Gen._record_var_signedness(VarName, 'unsigned long long') - Gen._store(field_val, var) - elif isinstance(Node.value, ast.Call): - # fail-fast:多返回值赋值但 CReturnTypes 解析失败(跨模块签名丢失), - # 绝不能静默跳过——目标变量不会被初始化,运行期 free(垃圾指针) - # 触发堆损坏(HashLibTest 0xC0000374)。 - target_names: list[str] = [ - e.id if isinstance(e, ast.Name) else '' for e in Target.elts - ] - raise Exception( - f"多返回值赋值解析失败: '{FuncName}' 的返回类型无法解析为" - f"元组/CReturn(ModulePath={ModulePath}),目标 {target_names} 未被初始化" - f"{Gen._get_node_info()}" - ) - return - - def _InitStructAtPtr(self, call_node: ast.Call, ClassName: str, VarPtr: ir.Value) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if ClassName not in Gen.structs: - return - StructType: ir.Type = Gen.structs[ClassName] - StructPtrType: ir.PointerType = ir.PointerType(StructType) - RawPtr: ir.Value = Gen._load(VarPtr, name=getattr(VarPtr, 'name', 'ptr')) - StructPtr: ir.Value = Gen.builder.bitcast(RawPtr, StructPtrType, name=ClassName) - members: list[tuple[str, ir.Type]] = Gen.class_members.get(ClassName, []) - defaults: dict[str, ir.Value] = Gen.class_member_defaults.get(ClassName, {}) - member_values: dict[str, ir.Value] = {} - for member_name, member_type in members: - if member_name in defaults: - member_values[member_name] = defaults[member_name] - if call_node.args: - for i, arg in enumerate(call_node.args): - if i < len(members): - member_name: str = members[i][0] - val: ir.Value | None = self.HandleExprLlvm(arg) - if val: - member_values[member_name] = val - if call_node.keywords: - for kw in call_node.keywords: - val: ir.Value | None = self.HandleExprLlvm(kw.value) - if val: - member_values[kw.arg] = val - has_vtable: bool = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes - base: int = 1 if has_vtable else 0 - for i, (member_name, member_type) in enumerate(members): - if isinstance(member_type, ir.VoidType): - continue - if member_name in member_values: - ElemPtr: ir.Value = Gen.builder.gep(StructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + i)], name=f"{ClassName}_{member_name}") - try: - Gen._store(member_values[member_name], ElemPtr) - except Exception as _e: - if _config_mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - InitFuncName: str = f'{ClassName}.__init__' - if Gen._has_function(InitFuncName): - Args: list[ir.Value | None] = [self.HandleExprLlvm(arg) for arg in call_node.args] - Args = [a for a in Args if a] - Gen.builder.call(Gen._get_function(InitFuncName), [StructPtr] + Args, name=f"call_{InitFuncName}") - - def _HandleAttributeStoreLlvm(self, Target: ast.Attribute, Value: ir.Value) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - AttrName: str = Target.attr - if isinstance(Target.value, ast.Name) and Target.value.id == 'self': - ClassName: str | None = self.Trans._CurrentCpythonObjectClass - if ClassName and ClassName in Gen.structs: - PropKey: str = f'{ClassName}.{AttrName}' - PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) - if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: - SelfVar: ir.Value | None = Gen._get_var_ptr('self') - if SelfVar: - SelfPtr: ir.Value = Gen._load(SelfVar, name="self") - SetterFunc: ir.Function | None = Gen._get_function(PropKey + '$set') - if SetterFunc and SelfPtr: - Gen.builder.call(SetterFunc, [SelfPtr, Value], name=f"prop_set_{PropKey}") - return - SelfVar: ir.Value | None = Gen._get_var_ptr('self') - if not SelfVar: - return - if SelfVar: - SelfPtr: ir.Value = Gen._load(SelfVar, name="self") - is_vtable_method: bool = False - method_idx: int = 0 - if ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes: - if ClassName in Gen.class_methods: - for mi, mn in enumerate(Gen.class_methods[ClassName]): - method_short: str = mn.split('.')[-1] if '.' in mn else mn - if method_short == AttrName or mn == AttrName: - is_vtable_method = True - method_idx = mi - break - if is_vtable_method: - VtableSlotPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}") - VtablePtr: ir.Value = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}") - methods: list[str] = Gen.class_methods[ClassName] - VtableArrayType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) - ClassVtable: ir.GlobalVariable | None = Gen.Vtables.get(ClassName) - if ClassVtable: - ClassVtableAddr: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}") - IsSameVtable: ir.Value = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}") - CopyBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_copy_self_{AttrName}") - SkipBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_skip_self_{AttrName}") - Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock) - Gen.builder.position_at_end(CopyBlock) - Gen._vtable_copy_counter += 1 - CopyName: str = f"{Gen._mangle_name(ClassName)}_vtable_copy_self_{Gen._vtable_copy_counter}" - VtableCopyGlobal: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VtableArrayType, name=CopyName) - VtableCopyGlobal.linkage = 'internal' - VtableCopyGlobal.initializer = ir.Constant(VtableArrayType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) - VtableCopyTyped: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed") - SrcTyped: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed") - VtableSize: int = len(methods) * Gen.ptr_size - MemcpyFunc: ir.Function | None = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64') - if not MemcpyFunc: - MemcpyType: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) - MemcpyFunc = ir.Function(Gen.module, MemcpyType, name='llvm.memcpy.p0i8.p0i8.i64') - Gen.functions['llvm.memcpy.p0i8.p0i8.i64'] = MemcpyFunc - Gen.builder.call(MemcpyFunc, [VtableCopyTyped, SrcTyped, ir.Constant(ir.IntType(64), VtableSize), ir.Constant(ir.IntType(1), 0)]) - VtableCopyGlobalAddr: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_addr") - Gen._store(VtableCopyGlobalAddr, VtableSlotPtr) - Gen.builder.branch(SkipBlock) - Gen.builder.position_at_end(SkipBlock) - VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_after_copy") - VtableTyped: ir.Value = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}") - MethodPtrAddr: ir.Value = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}") - FuncPtrI8: ir.Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}") - Gen._store(FuncPtrI8, MethodPtrAddr) - return - offset: int = Gen._get_member_offset(AttrName, ClassName) - struct_type: ir.Type = Gen.structs[ClassName] - max_offset: int = len(struct_type.elements) if isinstance(struct_type, ir.IdentifiedStructType) else 0 - if offset >= max_offset: - VarName: str = f"self.{AttrName}" - if VarName not in Gen.variables: - NewVar: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=AttrName) - Gen.variables[VarName] = NewVar - Gen._store(Value, Gen.variables[VarName]) - return - MemberPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) - elif isinstance(Target.value, ast.Name): - VarName: str = Target.value.id - - # FakeDuck: 检查是否有影子结构体 a__meta__ (str 变量的 per-instance 字段存储) - # 直接通过 a.__field__ = value 访问影子结构体字段 (语法糖) - _fd_meta_name: str = f"{VarName}__meta__" - if _fd_meta_name in Gen.variables and '_str' in Gen.structs: - _fd_offset = Gen._get_member_offset(AttrName, '_str') - if _fd_offset is not None: - _fd_meta_ptr: ir.Value = Gen.variables[_fd_meta_name] - _fd_field_ptr: ir.Value = Gen.builder.gep(_fd_meta_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _fd_offset)], name=f"{VarName}_{AttrName}_ptr") - self._StoreWithCoerce(Value, _fd_field_ptr) - return - - ClassName: str | None = Gen.var_struct_class.get(VarName) - - if not ClassName and Gen.global_struct_class: - ClassName = Gen.global_struct_class.get(VarName) - if ClassName: - Gen.var_struct_class[VarName] = ClassName - - if not ClassName: - for CN in Gen.structs: - if VarName == CN.lower() or VarName.startswith(CN): - ClassName = CN - break - - if not ClassName and VarName in Gen.module.globals: - GVar: ir.GlobalVariable = Gen.module.globals[VarName] - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(GVar.type.pointee) - if found: - ClassName = found[0] - Gen.var_struct_class[VarName] = ClassName - if Gen.global_struct_class: - Gen.global_struct_class[VarName] = ClassName - - if not ClassName and VarName in Gen.variables: - VarPtr: ir.Value = Gen.variables[VarName] - if isinstance(VarPtr.type, ir.PointerType): - pointee: ir.Type = VarPtr.type.pointee - if isinstance(pointee, ir.PointerType): - pointee = pointee.pointee - found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee) - if found: - CN: str = found[0] - ST: ir.Type = found[1] - ClassName = CN - elif isinstance(pointee, ir.IdentifiedStructType): - # sha1 冲突 fallback:find_struct_by_pointee 因 sha1 前缀不匹配失败时, - # 用短名(去掉 sha1 前缀)匹配,优先选字段最多的完整版本 - pointee_short: str = Gen._extract_short_name(pointee.name) - best_elem_count: int = 0 - for CN, ST in Gen.structs.items(): - if isinstance(ST, ir.IdentifiedStructType): - st_short: str = Gen._extract_short_name(ST.name) - if st_short == pointee_short: - elem_count: int = len(ST.elements) if ST.elements else 0 - if elem_count > best_elem_count: - ClassName = CN - best_elem_count = elem_count - - IsUnion: bool = False - if ClassName: - TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(ClassName) - if TypeInfo and TypeInfo.IsUnion: - IsUnion = True - - if ClassName and ClassName in Gen.structs: - PropKey: str = f'{ClassName}.{AttrName}' - PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) - if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: - ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) - SetterFunc: ir.Function | None = Gen._get_function(PropKey + '$set') - if SetterFunc and ObjVal: - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}") - Gen.builder.call(SetterFunc, [ObjVal, Value], name=f"prop_set_{PropKey}") - return - ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) - if ObjVal: - if BaseHandle._is_char_pointer(ObjVal): - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}") - # 跨模块 opaque 类型:ObjVal.type.pointee 与 Gen.structs[ClassName] 可能是 - # 不同的 IdentifiedStructType 对象(虽然 name 相同),== 返回 False。 - # 使用 name 匹配作为 fallback,与链式赋值路径(第 926-927 行)一致。 - # sha1 冲突时还需短名匹配(如 6bc91356c652f8ca.Function vs 8ad0c0a2934ca5b4.Function) - _ObjPointee = ObjVal.type.pointee if isinstance(ObjVal.type, ir.PointerType) else None - _TargetStruct = Gen.structs.get(ClassName) - _MatchesStruct = (_ObjPointee is not None and _TargetStruct is not None and - (_ObjPointee == _TargetStruct or - (isinstance(_ObjPointee, ir.IdentifiedStructType) and isinstance(_TargetStruct, ir.IdentifiedStructType) and - (_ObjPointee.name == _TargetStruct.name or - Gen._extract_short_name(_ObjPointee.name) == Gen._extract_short_name(_TargetStruct.name))))) - # opaque 泛型结构体 → 特化版本 bitcast - # 当 ObjVal 的 pointee 是 opaque 基础泛型结构体(如 GSList,来自跨模块 stub), - # 而 ClassName 是特化版本(如 GSList[BasicBlock])时,两者 short name 不同 - # (GSList vs GSList[BasicBlock]),_MatchesStruct 失败。 - # 验证特化 short name 以 基础名+'[' 开头,bitcast 到特化版本使后续 GEP 能正确访问字段。 - if (not _MatchesStruct - and isinstance(ObjVal.type, ir.PointerType) - and isinstance(_ObjPointee, ir.IdentifiedStructType) - and isinstance(_TargetStruct, ir.IdentifiedStructType) - and '[' in ClassName): - _BaseShort: str = Gen._extract_short_name(_ObjPointee.name) - _SpecShort: str = Gen._extract_short_name(_TargetStruct.name) - if _BaseShort and _SpecShort.startswith(_BaseShort + '['): - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(_TargetStruct), name=f"cast_spec_{ClassName}") - _MatchesStruct = True - if isinstance(ObjVal.type, ir.PointerType) and _MatchesStruct: - if IsUnion: - NestedStructName: str = f"{ClassName}_{AttrName}" - if NestedStructName in Gen.structs: - NestedStructType: ir.Type = Gen.structs[NestedStructName] - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") - offset: int | None = Gen._get_member_offset(AttrName, NestedStructName) - if offset is not None and offset < len(NestedStructType.elements): - MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) - return - bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(ClassName, {}) - if AttrName in bitfield_offsets: - self._store_bitfield_member(ObjVal, ClassName, AttrName, Value) - return - bitfields: dict[str, int] = Gen.class_member_bitfields.get(ClassName, {}) - if AttrName in bitfields and bitfields[AttrName] > 0: - if ClassName not in Gen.class_member_bitoffsets: - Gen.class_member_bitoffsets[ClassName] = {} - if AttrName not in Gen.class_member_bitoffsets[ClassName]: - bo: int = 0 - for bf_name, bf_width in bitfields.items(): - if bf_name == AttrName: - break - bo += bf_width - Gen.class_member_bitoffsets[ClassName][AttrName] = bo - self._store_bitfield_member(ObjVal, ClassName, AttrName, Value) - return - is_vtable_method: bool = False - method_idx: int = 0 - if ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes: - if ClassName in Gen.class_methods: - for mi, mn in enumerate(Gen.class_methods[ClassName]): - method_short: str = mn.split('.')[-1] if '.' in mn else mn - if method_short == AttrName or mn == AttrName: - is_vtable_method = True - method_idx = mi - break - if is_vtable_method: - VtableSlotPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}") - VtablePtr: ir.Value = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}") - methods: list[str] = Gen.class_methods[ClassName] - VtableArrayType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) - ClassVtable: ir.GlobalVariable | None = Gen.Vtables.get(ClassName) - if ClassVtable: - ClassVtableAddr: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}") - IsSameVtable: ir.Value = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}") - CopyBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_copy_{AttrName}") - SkipBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_skip_{AttrName}") - Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock) - Gen.builder.position_at_end(CopyBlock) - Gen._vtable_copy_counter += 1 - CopyName: str = f"{Gen._mangle_name(ClassName)}_vtable_copy_{Gen._vtable_copy_counter}" - VtableCopyGlobal: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VtableArrayType, name=CopyName) - VtableCopyGlobal.linkage = 'internal' - VtableCopyGlobal.initializer = ir.Constant(VtableArrayType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) - VtableCopyTyped: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed") - SrcTyped: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed") - VtableSize: int = len(methods) * Gen.ptr_size - MemcpyFunc: ir.Function | None = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64') - if not MemcpyFunc: - MemcpyType: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) - MemcpyFunc = ir.Function(Gen.module, MemcpyType, name='llvm.memcpy.p0i8.p0i8.i64') - Gen.functions['llvm.memcpy.p0i8.p0i8.i64'] = MemcpyFunc - Gen.builder.call(MemcpyFunc, [VtableCopyTyped, SrcTyped, ir.Constant(ir.IntType(64), VtableSize), ir.Constant(ir.IntType(1), 0)]) - VtableCopyGlobalAddr: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_addr") - Gen._store(VtableCopyGlobalAddr, VtableSlotPtr) - Gen.builder.branch(SkipBlock) - Gen.builder.position_at_end(SkipBlock) - VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_after_copy") - VtableTyped: ir.Value = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}") - MethodPtrAddr: ir.Value = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}") - FuncPtrI8: ir.Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}") - Gen._store(FuncPtrI8, MethodPtrAddr) - return - offset: int | None = Gen._get_member_offset(AttrName, ClassName) - StructType: ir.Type | None = Gen.structs.get(ClassName) - if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) - StructType = Gen.structs.get(ClassName) - if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0): - return - # 重新计算 offset:_TryLoadStructFromStub 刚加载了 struct body, - # 之前 offset 可能因 struct opaque / class_members 不完整而返回 None - offset = Gen._get_member_offset(AttrName, ClassName) - # sha1 冲突修复:Gen.structs[ClassName] 可能是字段不全的版本(如 2 字段 Function - # 来自 MetaType.py scope,而正确版本是 8 字段 Function 来自 __function.py)。 - # _get_member_offset 通过 class_sha1_map 已返回正确的 offset(如 5), - # 但 StructType 可能只有 2 个 elements,导致 offset < len(elements) 失败。 - # 在所有 structs 中查找同短名且字段最多的版本。 - if offset is not None and isinstance(StructType, ir.IdentifiedStructType) and StructType.elements is not None and offset >= len(StructType.elements): - _short: str = Gen._extract_short_name(StructType.name) - _best: int = len(StructType.elements) - for _cn, _st in Gen.structs.items(): - if isinstance(_st, ir.IdentifiedStructType) and _st.elements is not None: - if Gen._extract_short_name(_st.name) == _short and len(_st.elements) > _best: - StructType = _st - _best = len(_st.elements) - # bitcast:当 ObjVal 的 pointee 是 opaque 或与 StructType 不是同一个类型对象 - # (sha1 前缀不同但短名相同)时,需要 bitcast 到 StructType 才能正确 GEP - if StructType is not None and StructType.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and (ObjVal.type.pointee.elements is None or ObjVal.type.pointee != StructType): - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(StructType), name=f"cast_{ClassName}") - if offset is not None and StructType is not None and StructType.elements is not None and offset < len(StructType.elements): - MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - else: - return - - byte_order: str = Gen.class_member_byteorders.get(ClassName, {}).get(AttrName, "") - - if byte_order == 'big': - if StructType is None or StructType.elements is None or len(StructType.elements) == 0: - return - member_type: ir.Type = StructType.elements[offset] - if isinstance(member_type, ir.IntType): - Value = Gen._apply_bswap_if_big(Value, byte_order, f"bswap_store_{AttrName}") - - self._StoreWithCoerce(Value, MemberPtr) - if not ClassName: - imported_modules: list[str] | None = getattr(self.Trans, '_ImportedModules', None) - resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName) - if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules): - PossibleKeys: list[str] = [f"{VarName}.{AttrName}", AttrName] - for mod_name in imported_modules: - if mod_name.endswith(f".{VarName}") or mod_name == VarName: - key: str = f"{mod_name}.{AttrName}" - if key not in PossibleKeys: - PossibleKeys.append(key) - for key in PossibleKeys: - if key in Gen.module.globals: - GVar: ir.GlobalVariable = Gen.module.globals[key] - if isinstance(GVar, ir.Function): - return - if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return - self._StoreWithCoerce(Value, GVar) - return - ModuleSha1Map: dict[str, str] = Gen.ModuleSha1Map - sha1_candidates: list[str] = [VarName, resolved_mod] - for mod_name in imported_modules: - if mod_name.endswith(f".{VarName}") or mod_name == VarName: - if mod_name not in sha1_candidates: - sha1_candidates.append(mod_name) - for cand in sha1_candidates: - sha1: str | None = ModuleSha1Map.get(cand) - if sha1: - prefixed: str = f"{sha1}.{AttrName}" - if prefixed in Gen.module.globals: - GVar2: ir.GlobalVariable = Gen.module.globals[prefixed] - if isinstance(GVar2, ir.Function): - return - if isinstance(GVar2.type, ir.PointerType) and isinstance(GVar2.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - return - self._StoreWithCoerce(Value, GVar2) - return - elif isinstance(Target.value, ast.Attribute): - ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) - if ObjVal and isinstance(ObjVal.type, ir.PointerType): - pointee: ir.Type = ObjVal.type.pointee - if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None: - for CN, ST in Gen.structs.items(): - if isinstance(ST, ir.IdentifiedStructType) and ST.name == pointee.name and ST.elements is not None: - pointee = ST - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") - break - found_match: bool = False - for CN, ST in Gen.structs.items(): - if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): - found_match = True - if ST.elements is None: - self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) - ST = Gen.structs.get(CN, ST) - if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") - bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(CN, {}) - if AttrName in bitfield_offsets: - self._store_bitfield_member(ObjVal, CN, AttrName, Value) - return - offset: int = Gen._get_member_offset(AttrName, CN) - if offset is not None and ST.elements is not None and offset < len(ST.elements): - MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) - break - if not found_match: - if isinstance(pointee, ir.IdentifiedStructType): - matched_cn: str | None = None - for CN in Gen.class_members: - members: list[tuple[str, ir.Type]] = Gen.class_members[CN] - for mname, mtype in members: - if mname == AttrName: - matched_cn = CN - break - if matched_cn: - break - if matched_cn and matched_cn in Gen.structs: - ST: ir.Type = Gen.structs[matched_cn] - if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(matched_cn, Gen) - ST = Gen.structs.get(matched_cn, ST) - if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{matched_cn}") - offset: int = Gen._get_member_offset(AttrName, matched_cn) - if offset is not None and ST.elements is not None and offset < len(ST.elements): - MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) - return - elif isinstance(Target.value, ast.Call): - # Check if this is c.Deref(...) — we need the pointer, not the Loaded value - ObjVal: ir.Value | None = None - is_cderef: bool = (isinstance(Target.value.func, ast.Attribute) and - isinstance(Target.value.func.value, ast.Name) and - Target.value.func.value.id == 'c' and - Target.value.func.attr == 'Deref' and - Target.value.args) - if is_cderef: - # Get the pointer from c.Deref argument, don't Load the value - deref_arg: ast.expr = Target.value.args[0] - inner_val: ir.Value | None = self.HandleExprLlvm(deref_arg) - if inner_val and isinstance(inner_val.type, ir.PointerType): - if isinstance(inner_val.type.pointee, ir.PointerType): - ObjVal = Gen._load(inner_val, name="deref_load_ptr") - else: - ObjVal = inner_val - if ObjVal is None: - ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) - if ObjVal and isinstance(ObjVal.type, ir.PointerType): - pointee: ir.Type = ObjVal.type.pointee - if isinstance(pointee, ir.PointerType): - ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr") - pointee = ObjVal.type.pointee - for CN, ST in Gen.structs.items(): - if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): - if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) - ST = Gen.structs.get(CN, ST) - if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") - bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(CN, {}) - if AttrName in bitfield_offsets: - self._store_bitfield_member(ObjVal, CN, AttrName, Value) - return - offset: int = Gen._get_member_offset(AttrName, CN) - if offset is not None and ST.elements is not None and offset < len(ST.elements): - MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) - break - elif isinstance(Target.value, ast.Subscript): - SubPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) - if SubPtr and isinstance(SubPtr.type, ir.PointerType): - pointee: ir.Type = SubPtr.type.pointee - - if isinstance(Target.value.value, ast.Attribute): - AttrNameSub: str = Target.value.value.attr - if AttrNameSub == 'items' and 'Item' in Gen.structs: - ObjValCast: ir.Value = Gen.builder.bitcast(SubPtr, ir.PointerType(Gen.structs['Item']), name=f"cast_Item") - offset: int = Gen._get_member_offset(AttrName, 'Item') - MemberPtr: ir.Value = Gen.builder.gep(ObjValCast, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) - return - - if BaseHandle._is_char_pointer(SubPtr): - for CN, ST in Gen.structs.items(): - ObjValCast: ir.Value = Gen.builder.bitcast(SubPtr, ir.PointerType(ST), name=f"cast_{CN}") - offset: int = Gen._get_member_offset(AttrName, CN) - MemberPtr: ir.Value = Gen.builder.gep(ObjValCast, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) - break - elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee) - if found: - CN: str = found[0] - ST: ir.Type = found[1] - if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): - self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) - ST = Gen.structs.get(CN, ST) - if ST.elements is not None and isinstance(SubPtr.type, ir.PointerType) and isinstance(SubPtr.type.pointee, ir.IdentifiedStructType) and SubPtr.type.pointee.elements is None: - SubPtr = Gen.builder.bitcast(SubPtr, ir.PointerType(ST), name=f"cast_{CN}") - offset: int = Gen._get_member_offset(AttrName, CN) - if offset is not None and ST.elements is not None and offset < len(ST.elements): - MemberPtr: ir.Value = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) - elif isinstance(pointee, ir.PointerType): - LoadedPtr: ir.Value = Gen._load(SubPtr, name=f"Load_{AttrName}_ptr") - if isinstance(LoadedPtr.type, ir.PointerType) and isinstance(LoadedPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(LoadedPtr.type.pointee) - if found: - CN: str = found[0] - ST: ir.Type = found[1] - offset: int = Gen._get_member_offset(AttrName, CN) - MemberPtr: ir.Value = Gen.builder.gep(LoadedPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) - self._StoreWithCoerce(Value, MemberPtr) - - def _StoreArrElemWithCoerceBswap(self, Value: ir.Value, Ptr: ir.Value, arr_byte_order: str) -> None: - """对数组元素存储应用 bswap 后再 coerce 存储""" - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - Value = Gen._apply_bswap_if_big(Value, arr_byte_order, "bswap_arr_store") - self._StoreWithCoerce(Value, Ptr) - - def _HandleSubscriptStoreLlvm(self, Target: ast.Subscript, Value: ir.Value) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - # 查询数组元素字节序 - arr_byte_order: str = '' - if isinstance(Target.value, ast.Name) and Target.value.id in Gen.local_var_byteorders: - arr_byte_order = Gen.local_var_byteorders[Target.value.id] - if isinstance(Target.value, ast.Name): - SubVarName: str = Target.value.id - if SubVarName in Gen.var_const_flags: - src_info: str = Gen._get_node_info() - self.Trans.LogError(f"不能对 const 变量 '{SubVarName}' 的元素赋值{src_info}") - ClassName: str | None = self.Trans.ExprHandler._get_var_class(Target.value, Gen) - if ClassName and Gen._has_function(f'{ClassName}.__setitem__'): - 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(整数)的情况:联合类型 | t.CPtr 降级后可能被 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): - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - setitem_args: list[ir.Value] = [obj_val, idx_val, Value] - setitem_func_name: str = f'{ClassName}.__setitem__' - setitem_args = Gen._apply_auto_addr(setitem_func_name, setitem_args) - setitem_func: ir.Function = Gen._get_function(setitem_func_name) - setitem_args = Gen._adjust_args(setitem_args, setitem_func) - Gen.builder.call(setitem_func, setitem_args, name=f"call_{setitem_func_name}") - return - ValueVal: ir.Value | None = self.HandleExprLlvm(Target.value) - IndexVal: ir.Value | None = self.HandleExprLlvm(Target.slice) - if not ValueVal or not IndexVal: - return - # 当变量本身是二级指针(如 elem_ptr: T | t.CPtr = AST**), - # 且存储的值也是指针时,elem_ptr[i] = item 应直接存储指针(8 字节), - # 而非解引用后复制结构体(如 48 字节的 AST),避免对象切片 - if isinstance(Target.value, ast.Name): - VarName: str = Target.value.id - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarAlloca: ir.Value = Gen.variables[VarName] - if isinstance(VarAlloca.type, ir.PointerType) and isinstance(VarAlloca.type.pointee, ir.PointerType): - if (isinstance(ValueVal.type, ir.PointerType) and isinstance(Value.type, ir.PointerType) - and isinstance(Value.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_store") - # ValueVal 是 AST*(加载自 elem_ptr 的基指针), - # 但 GEP 默认将其视为 AST 结构体数组。需要先 bitcast 为 - # AST**(指向 AST* 的指针),让 GEP 正确索引 AST* 指针数组, - # 而非 AST 结构体数组。然后用 builder.store 直接存储指针, - # 避免 _store 的类型强制转换将指针解引用为结构体。 - PtrToStruct: ir.Type = Value.type.pointee - BaseAsPP: ir.Value = Gen.builder.bitcast(ValueVal, - ir.PointerType(ir.PointerType(PtrToStruct)), name="cast_base_pp") - ElemPtr: ir.Value = Gen.builder.gep(BaseAsPP, [IndexVal], name="subscript") - Gen.builder.store(Value, ElemPtr) - return - if BaseHandle._is_char_pointer(IndexVal): - Loaded_byte: ir.Value = Gen._load(IndexVal, name="Load_char_idx_store") - IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx_store") - if isinstance(ValueVal.type, ir.IntType): - var_ptr: ir.Value | None = self._get_int_ptr(Target.value) - if var_ptr: - i8_ptr: ir.Value = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr_store") - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index_store") - ptr: ir.Value = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr_store") - self._StoreWithCoerce(Value, ptr) - return - if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_store") - ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") - self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) - return - if isinstance(ValueVal.type, ir.PointerType): - pointee: ir.Type = ValueVal.type.pointee - if isinstance(pointee, ir.ArrayType): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript") - elif (isinstance(pointee, ir.IntType) and pointee.width == 8 - 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 | t.CPtr) - # 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: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_pp_str_index_store") - ElemPtr = Gen.builder.gep(CastedPtrPtr, [IndexVal], name="subscript") - self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) - return - else: - ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") - self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) - elif isinstance(ValueVal.type, ir.ArrayType): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - if isinstance(Target.value, ast.Name): - VarName: str = Target.value.id - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr: ir.Value = Gen.variables[VarName] - if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr: ir.Value = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript") - self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) - return - if isinstance(Target.value, ast.Subscript): - InnerPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) - if InnerPtr: - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr: ir.Value = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript") - self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) - return - if isinstance(Target.value, ast.Attribute): - AttrPtr: ir.Value | None = self.Trans.ExprAttrHandle._get_attr_ptr(Target.value) - if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): - if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: - if IndexVal.type.width < 32: - IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") - else: - IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") - ElemPtr: ir.Value = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript") - self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) - return - arr_alloc: ir.AllocaInstr = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp") - Gen._store(ValueVal, arr_alloc) - ElemPtr: ir.Value = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") - self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) - ModifiedArr: ir.Value = Gen._load(arr_alloc, name="modified_arr") - if isinstance(Target.value, ast.Subscript): - OuterPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) - if OuterPtr: - Gen._store(ModifiedArr, OuterPtr) - elif isinstance(Target.value, ast.Attribute): - OuterPtr: ir.Value | None = self.Trans.ExprAttrHandle._get_attr_ptr(Target.value) - if OuterPtr: - Gen._store(ModifiedArr, OuterPtr) - - def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if isinstance(Ptr.type, ir.PointerType): - TargetType: ir.Type = Ptr.type.pointee - if Value.type != TargetType: - if isinstance(TargetType, ir.ArrayType) and isinstance(Value.type, ir.PointerType): - ElemType: ir.Type = TargetType.element - ElemSize: int = Gen._get_struct_size(ElemType) - for i in range(TargetType.count): - DstElem: ir.Value = Gen.builder.gep(Ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"arr_dst_{i}") - SrcPtr: ir.Value - if ElemSize == 1: - SrcPtr = Gen.builder.gep(Value, [ir.Constant(ir.IntType(32), i)], name=f"arr_src_{i}") - else: - PtrInt: ir.Value = Gen.builder.ptrtoint(Value, ir.IntType(64)) - Offset: ir.Constant = ir.Constant(ir.IntType(64), i * ElemSize) - NewPtrInt: ir.Value = Gen.builder.add(PtrInt, Offset) - SrcPtr = Gen.builder.inttoptr(NewPtrInt, ir.PointerType(ElemType), name=f"arr_src_{i}") - SrcVal: ir.Value = Gen._load(SrcPtr, name=f"arr_elem_{i}") - if SrcVal.type != ElemType: - try: - SrcVal = Gen.builder.bitcast(SrcVal, ElemType, name=f"arr_cast_{i}") - except Exception: # 回退:bitcast 失败时跳过该元素 - continue - Gen._store(SrcVal, DstElem) - return - if isinstance(TargetType, ir.PointerType) and isinstance(Value, ir.Constant) and Value.constant is None: - Value = ir.Constant(TargetType, None) - elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType): - try: - Value = Gen.builder.bitcast(Value, TargetType, name="null_ptr_bitcast") - except Exception: # 回退:bitcast 失败时设为 null 常量 - Value = ir.Constant(TargetType, None) - else: - Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType) - if Coerced is not None: - Value = Coerced - Gen._store(Value, Ptr) - - - def _get_int_ptr(self, target: ast.expr) -> ir.Value | None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if isinstance(target, ast.Name): - VarName: str = target.id - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr: ir.Value = Gen.variables[VarName] - if isinstance(VarPtr.type, ir.PointerType): - pointee: ir.Type = VarPtr.type.pointee - if isinstance(pointee, ir.ArrayType): - return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}") - return None - - def _EmitGlobalAnnAssignLlvm(self, Node: ast.AnnAssign, Gen: "Translator.LlvmGen") -> None: - if isinstance(Node.target, ast.Name): - VarName: str = Node.target.id - Info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName) - if Info: - if Info.IsTypedef: - return - parse_result = ParseListAnnotation(Node.annotation) - if parse_result: - elem_type_node: ast.expr = parse_result.elem_type_node - ElemType, ElemTypeInfo = self.ResolveListElementType( - elem_type_node, Gen, - check_func_ptr=True, void_fallback_width=32, fallback_to_cint=True, - ) - if parse_result.is_pointer: - # 单参数 list[type] → 指针 - VarType: ir.Type = ir.PointerType(ElemType) - if VarName not in Gen.variables and VarName not in Gen.module.globals: - GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) - GlobalVar.initializer = ir.Constant(VarType, None) - Gen.variables[VarName] = GlobalVar - if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: - Gen.global_struct_class[VarName] = elem_type_node.id - return - count_node: ast.expr | None = parse_result.count_node - ArrayCount: int = self.ParseArrayCount(count_node, Gen, Node.value, mode='global') - VarType = ir.ArrayType(ElemType, ArrayCount) - if VarName not in Gen.variables and VarName not in Gen.module.globals: - GlobalVar = ir.GlobalVariable(Gen.module, VarType, name=VarName) - if isinstance(ElemType, ir.IdentifiedStructType): - GlobalVar.linkage = 'common' - elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): - str_val: str = Node.value.value + '\x00' - str_bytes: bytearray = bytearray(str_val, 'utf-8') - if len(str_bytes) < ArrayCount: - str_bytes.extend(b'\x00' * (ArrayCount - len(str_bytes))) - try: - GlobalVar.initializer = ir.Constant(VarType, str_bytes[:ArrayCount]) - except Exception: # 回退:初始化常量失败时用零值 - GlobalVar.initializer = Gen._zero_value_for_type(VarType) - else: - InitConstants: list[ir.Constant] | None = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen, byte_order=ElemTypeInfo.ByteOrder if ElemTypeInfo else '') - if InitConstants: - GlobalVar.initializer = ir.Constant(VarType, InitConstants) - elif ArrayCount > 256: - GlobalVar.linkage = 'common' - else: - if self._contains_identified_struct(VarType): - GlobalVar.linkage = 'common' - else: - GlobalVar.initializer = ir.Constant(VarType, [ir.Constant(ElemType, ir.Undefined)] * ArrayCount) - Gen.variables[VarName] = GlobalVar - if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: - Gen.global_struct_class[VarName] = elem_type_node.id - return - if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs: - StructName: str = Node.annotation.id - VarType: ir.Type = Gen.structs[StructName] - if VarName not in Gen.variables and VarName not in Gen.module.globals: - GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) - if Node.value and isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == StructName: - const: ir.Constant | None = self.Trans.ClassHandler._BuildStructConstant(Node.value, StructName, Gen) - if const: - GlobalVar.initializer = const - else: - GlobalVar.initializer = ir.Constant(VarType, None) - else: - GlobalVar.initializer = ir.Constant(VarType, None) - Gen.variables[VarName] = GlobalVar - Gen.global_struct_class[VarName] = StructName - return - TypeInfo: CTypeInfo | None = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) - IsCDefine: bool = False - if TypeInfo and TypeInfo.BaseType: - if isinstance(TypeInfo.BaseType, t._CTypedef): - return - if isinstance(TypeInfo.BaseType, t.CDefine): - IsCDefine = True - if not IsCDefine and self._IsTypedefAnnotation(Node.annotation): - IsCDefine = True - TTypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation) - if TTypeInfo: - TTypeInfo.IsTypedef = True - TTypeInfo.Name = VarName - self.Trans.SymbolTable.insert(VarName, TTypeInfo) - if IsCDefine: - if Node.value: - define_constants: dict[str, int | float] = vars(Gen).setdefault('_define_constants', {}) - try: - const_value: int | float | None = self._eval_const_expr(Node.value, Gen) - if const_value is not None: - define_constants[VarName] = const_value - except Exception as _e: - if _config_mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - return - if TypeInfo is None: - TypeInfo = CTypeInfo() - TypeInfo.BaseType = t.CInt() - VarType: ir.Type = Gen._ctype_to_llvm(TypeInfo) - if isinstance(VarType, ir.VoidType): - VarType = ir.IntType(32) - # 记录模块级注解类型:供函数内 global 变量的 += (HandlesAugAssign)参考, - # 避免用 RHS 字面量类型(i32)误建 i32 全局导致 i64/i32 类型不匹配。 - if not hasattr(Gen, '_module_ann_types'): - Gen._module_ann_types = {} - Gen._module_ann_types[VarName] = VarType - if VarName in Gen.variables or VarName in Gen.module.globals: - # 时序修复:第一遍创建全局时类未处理(SymbolTable 无枚举成员), - # initializer 回退为 0。第二遍类已处理,尝试用解析出的枚举值更新 initializer。 - if VarName in Gen.module.globals and Node.value: - existing: Any = Gen.module.globals[VarName] - if isinstance(existing, ir.GlobalVariable) and isinstance(VarType, ir.IntType): - new_init: ir.Constant | None = self._eval_global_const(Node.value, VarType, Gen) - if new_init is not None: - existing.initializer = new_init - return - if isinstance(VarType, (ir.IdentifiedStructType, ir.LiteralStructType)): - GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) - GlobalVar.initializer = ir.Constant(VarType, None) - Gen.variables[VarName] = GlobalVar - if TypeInfo and TypeInfo.IsStruct and TypeInfo.Name: - Gen.global_struct_class[VarName] = TypeInfo.Name - return - GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) - # 全局变量指针元素标志:bytes|t.CPtr 或 str|t.CPtr 注解的变量, - # 使 var[index] 使用 8 字节指针步长(而非 1 字节字符步长) - if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr): - if AnnotationContainsName(Node.annotation, 'str') or AnnotationContainsName(Node.annotation, 'bytes'): - Gen.global_var_ptr_element[VarName] = True - if Node.value: - if isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str) and isinstance(VarType, ir.PointerType): - str_val: str = Node.value.value + '\x00' - str_bytes: bytes = str_val.encode('utf-8') - arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes)) - str_gv_name: str = VarName + '_str' - str_gv: ir.GlobalVariable - if str_gv_name not in Gen.module.globals: - str_gv = ir.GlobalVariable(Gen.module, arr_type, name=str_gv_name) - str_gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) - str_gv.linkage = 'internal' - else: - str_gv = Gen.module.globals[str_gv_name] - ptr_type: ir.PointerType = ir.PointerType(ir.IntType(8)) - ptr_gv: ir.GlobalVariable - if VarName not in Gen.module.globals: - ptr_gv = ir.GlobalVariable(Gen.module, ptr_type, name=VarName) - ptr_gv.initializer = ir.Constant(ptr_type, str_gv) - ptr_gv.linkage = 'internal' - else: - ptr_gv = Gen.module.globals[VarName] - Gen.variables[VarName] = ptr_gv - elif isinstance(VarType, ir.PointerType) and isinstance(VarType.pointee, ir.FunctionType) and isinstance(Node.value, ast.Name): - # 函数指针赋值:f3: t.Callable[[int], int] = f - RefName: str = Node.value.id - SymInfo: Any = self.Trans.SymbolTable.lookup(RefName) - if SymInfo and (SymInfo.IsFunction or SymInfo.IsFuncPtr): - MangledName: str = Gen._mangle_func_name(RefName) - if MangledName in Gen.module.globals: - func: Any = Gen.module.globals[MangledName] - if isinstance(func, ir.Function): - GlobalVar.initializer = func - else: - if isinstance(VarType, ir.ArrayType) and isinstance(Node.value, (ast.List, ast.Set)): - InitConstants: list[ir.Constant] | None = self.Trans._BuildMultiDimArrayInitConstants(Node.value, VarType, Gen) - if InitConstants: - GlobalVar.initializer = ir.Constant(VarType, InitConstants) - else: - if self._contains_identified_struct(VarType): - GlobalVar.linkage = 'common' - else: - zv: ir.Constant | None = Gen._zero_value_for_type(VarType) - if zv: - GlobalVar.initializer = zv - else: - GlobalVar.linkage = 'common' - else: - init_val: ir.Constant | None = self._eval_global_const(Node.value, VarType, Gen) - if init_val: - GlobalVar.initializer = init_val - elif isinstance(VarType, ir.BaseStructType) or (isinstance(Node.value, ast.Constant) and Node.value.value is None): - # None 初值全局(如各 Handles 模块的 _g_gen: t.CVoid|t.CPtr = None): - # 多模块同名定义用 common linkage 让链接器合并(避免 - # ld.lld duplicate symbol)。common 无 initializer,合并为零值, - # 符合 None(=null) 语义。 - GlobalVar.linkage = 'common' - else: - GlobalVar.initializer = Gen._zero_value_for_type(VarType) - else: - if isinstance(VarType, ir.BaseStructType) or self._contains_identified_struct(VarType): - GlobalVar.linkage = 'common' - else: - GlobalVar.initializer = Gen._zero_value_for_type(VarType) - Gen.variables[VarName] = GlobalVar - - def _eval_global_const(self, value_node: ast.expr, var_type: ir.Type, Gen: "Translator.LlvmGen") -> ir.Constant | None: - if isinstance(value_node, ast.Constant): - if isinstance(value_node.value, bool): - if isinstance(var_type, ir.IntType): - return ir.Constant(var_type, int(value_node.value)) - elif isinstance(value_node.value, int): - if isinstance(var_type, ir.IntType): - return ir.Constant(var_type, value_node.value) - elif isinstance(var_type, (ir.FloatType, ir.DoubleType)): - return ir.Constant(var_type, float(value_node.value)) - elif isinstance(value_node.value, float): - if isinstance(var_type, (ir.FloatType, ir.DoubleType)): - return ir.Constant(var_type, value_node.value) - elif isinstance(var_type, ir.IntType): - return ir.Constant(var_type, int(value_node.value)) - elif isinstance(value_node.value, str): - return None - # Handle type constructor calls like t.CDouble(1e-9), t.CFloat(3.14), t.CInt(42) - if isinstance(value_node, ast.Call): - inner_val: ir.Constant | None = self._eval_type_ctor_const(value_node, var_type, Gen) - if inner_val is not None: - return inner_val - if isinstance(value_node, ast.UnaryOp) and isinstance(value_node.op, ast.USub): - inner: ir.Constant | None = self._eval_global_const(value_node.operand, var_type, Gen) - if inner: - return ir.Constant(var_type, -inner.constant) - # Handle enum member references like ASTVType.Module (ast.Attribute) - if isinstance(value_node, ast.Attribute): - attr_name: str = value_node.attr - # 优先用带前缀的 key 查找(避免短名被同名函数/变量覆盖) - if isinstance(value_node.value, ast.Name): - FullKey2: str = f"{value_node.value.id}.{attr_name}" - FullInfo: Any = self.Trans.SymbolTable.lookup(FullKey2) - if FullInfo and FullInfo.IsEnumMember and isinstance(FullInfo.value, int): - if isinstance(var_type, ir.IntType): - return ir.Constant(var_type, FullInfo.value) - SymInfo: Any = self.Trans.SymbolTable.lookup(attr_name) - if SymInfo: - if SymInfo.IsEnumMember and isinstance(SymInfo.value, int): - if isinstance(var_type, ir.IntType): - return ir.Constant(var_type, SymInfo.value) - return None - - def _eval_type_ctor_const(self, call_node: ast.Call, var_type: ir.Type, Gen: "Translator.LlvmGen") -> ir.Constant | None: - """Try to evaluate t.CDouble(val), t.CFloat(val), t.CInt(val) etc. as a compile-time constant.""" - if not isinstance(call_node.func, ast.Attribute): - return None - if not isinstance(call_node.func.value, ast.Name): - return None - if call_node.func.value.id != 't': - return None - if not call_node.args or len(call_node.args) != 1: - return None - arg: ast.expr = call_node.args[0] - # Recursively evaluate the argument as a constant - arg_val: ir.Constant | None = self._eval_global_const(arg, var_type, Gen) - if arg_val is not None: - return arg_val - return None - - def _store_bitfield_member(self, struct_ptr: ir.Value, ClassName: str, field_name: str, Value: ir.Value) -> bool: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(ClassName, {}) - bitfield_widths: dict[str, int] = Gen.class_member_bitfields.get(ClassName, {}) - if field_name not in bitfield_offsets: - return False - bit_offset: int = bitfield_offsets[field_name] - bit_width: int = bitfield_widths.get(field_name, 0) - if bit_width == 0: - return False - struct_type: ir.Type | None = Gen.structs.get(ClassName) - if struct_type is None or struct_type.elements is None or len(struct_type.elements) == 0: - return False - storage_type: ir.Type = struct_type.elements[0] - member_ptr: ir.Value = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{field_name}_storage_ptr") - old_val: ir.Value = Gen._load(member_ptr, name=f"{field_name}_old_storage") - mask: int = (1 << bit_width) - 1 - shifted_mask: int = mask << bit_offset - inverted_mask: ir.Constant = ir.Constant(storage_type, ~shifted_mask & ((1 << storage_type.width) - 1)) - cleared: ir.Value = Gen.builder.and_(old_val, inverted_mask, name=f"{field_name}_cleared") - if isinstance(Value.type, ir.IntType) and Value.type.width < storage_type.width: - if getattr(Value.type, 'is_signed', False): - Value = Gen.builder.sext(Value, storage_type, name=f"{field_name}_sext_store") - else: - Value = Gen.builder.zext(Value, storage_type, name=f"{field_name}_zext_store") - elif Value.type.width != storage_type.width: - Value = Gen.builder.trunc(Value, storage_type, name=f"{field_name}_trunc_store") if Value.type.width > storage_type.width else Gen.builder.zext(Value, storage_type, name=f"{field_name}_zext_store") - shifted_value: ir.Value = Gen.builder.shl(Value, ir.Constant(storage_type, bit_offset), name=f"{field_name}_shift_store") - masked_value: ir.Value = Gen.builder.and_(shifted_value, ir.Constant(storage_type, shifted_mask), name=f"{field_name}_mask_store") - new_val: ir.Value = Gen.builder.or_(cleared, masked_value, name=f"{field_name}_new_storage") - Gen._store(new_val, member_ptr) - return True - - def _CheckEnumMemberAssignment(self, node: ast.expr) -> str | None: - def _get_attr_path(n: ast.expr) -> str | None: - if isinstance(n, ast.Name): - return n.id - elif isinstance(n, ast.Attribute): - return f"{_get_attr_path(n.value)}.{n.attr}" - return None - attr_path: str | None = _get_attr_path(node) - if not attr_path: - return None - parts: list[str] = attr_path.split('.') - if len(parts) >= 2: - enum_class_name: str = parts[-2] - member_name: str = parts[-1] - qualified_name: str = f"{enum_class_name}.{member_name}" - info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(qualified_name) - if info: - if info.IsEnumMember and info.EnumName: - return info.EnumName - under_name: str = f"{enum_class_name}_{member_name}" - if self.Trans.SymbolTable.has(under_name): - info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable[under_name] - if info.IsEnumMember and info.EnumName: - return info.EnumName - for key in self.Trans.SymbolTable: - if key == member_name: - info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable[key] - if info.IsEnumMember and info.EnumName and info.EnumName == enum_class_name: - return enum_class_name - return None - - def _IsTypedefAnnotation(self, annotation: ast.expr) -> bool: - if isinstance(annotation, ast.Attribute): - if annotation.attr in ('CTypedef', 'CDefine'): - return True - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - return self._IsTypedefAnnotation(annotation.left) or self._IsTypedefAnnotation(annotation.right) - if isinstance(annotation, ast.Subscript): - return self._IsTypedefAnnotation(annotation.value) - return False - - def _EmitGlobalAssignLlvm(self, Node: ast.Assign, Gen: "Translator.LlvmGen") -> None: - if len(Node.targets) == 1 and isinstance(Node.targets[0], ast.Name): - VarName: str = Node.targets[0].id - if VarName in Gen.variables or VarName in Gen.module.globals: - return - if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): - FuncName: str = Node.value.func.id - if FuncName in Gen.structs: - IsUnion: bool = False - TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(FuncName) - if TypeInfo: - if TypeInfo.IsUnion: - IsUnion = True - if IsUnion: - StructType: ir.Type = Gen.structs[FuncName] - StructPtrType: ir.PointerType = ir.PointerType(StructType) - GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, StructPtrType, name=VarName) - GlobalVar.initializer = ir.Constant(StructPtrType, None) - Gen.variables[VarName] = GlobalVar - Gen.global_struct_class[VarName] = FuncName - return - StructName: str = FuncName - VarType: ir.Type = Gen.structs[StructName] - GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) - const: ir.Constant | None = self.Trans.ClassHandler._BuildStructConstant(Node.value, StructName, Gen) - if const: - GlobalVar.initializer = const - else: - GlobalVar.linkage = 'common' - Gen.variables[VarName] = GlobalVar - Gen.global_struct_class[VarName] = StructName - return - GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, ir.IntType(32), name=VarName) - init_val: ir.Constant | None = self._eval_global_const(Node.value, ir.IntType(32), Gen) - GlobalVar.initializer = init_val if init_val else ir.Constant(ir.IntType(32), 0) - Gen.variables[VarName] = GlobalVar - - def _eval_const_expr(self, node: ast.expr, Gen: "Translator.LlvmGen") -> int | float | None: - """计算常量表达式的值(委托到 ConstEvaluator)""" - ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans) - return ConstEvaluator.eval_full(node, ctx) - - def _eval_global_count(self, node: ast.expr, Gen: "Translator.LlvmGen") -> int | None: - val: int | float | None = self._eval_const_expr(node, Gen) - if val is not None: - if isinstance(val, float): - return int(val) - if isinstance(val, int): - return val +from __future__ import annotations +from typing import TYPE_CHECKING, Any +if TYPE_CHECKING: + from lib.core.translator import Translator +import vast as ast +import sys +import llvmlite.ir as ir +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta +from lib.core.VLogger import get_logger as _vlog +from lib.core.ConstEvaluator import ConstEvaluator, EvalContext +from lib.constants.config import mode as _config_mode +from lib.includes import t +from lib.includes.t import CTypeRegistry +from lib.core.SymbolUtils import IsTModule, ParseListAnnotation, AnnotationContainsName + +class AssignHandle(BaseHandle): + def __init__(self, translator: "Translator") -> None: + super().__init__(translator) + self._CurrentCpythonObjectClass: str | None = None + + @staticmethod + def _contains_identified_struct(var_type: ir.Type) -> bool: + if isinstance(var_type, ir.IdentifiedStructType): + return True + if isinstance(var_type, ir.ArrayType): + return AssignHandle._contains_identified_struct(var_type.element) + if isinstance(var_type, ir.PointerType): + return AssignHandle._contains_identified_struct(var_type.pointee) + if isinstance(var_type, ir.BaseStructType): + if var_type.elements: + return any(AssignHandle._contains_identified_struct(e) for e in var_type.elements) + return False + + def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None: + return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType) + + def _HandleAssignLlvm(self, Node: ast.Assign) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + Gen._set_node_info(Node, "Assign") + if len(Node.targets) == 1: + Target: ast.expr = Node.targets[0] + if isinstance(Target, ast.Name): + VarName: str = Target.id + if VarName in Gen.var_const_flags: + src_info: str = Gen._get_node_info() + _vlog().error(f"不能对 const 变量 '{VarName}' 赋值{src_info}") + sys.exit(1) + if isinstance(Node.value, ast.Attribute) and isinstance(Node.value.value, ast.Name) and IsTModule(Node.value.value.id, self.Trans.SymbolTable): + AttrName: str = Node.value.attr + Gen.var_type_info[VarName] = {'type': 't_type', 'name': AttrName} + Gen.var_type_assignments.setdefault(VarName, []).append({'type': 't_type', 'name': AttrName}) + c_type_name: str = '' + resolved: tuple[type, int] | None = CTypeRegistry.ResolveName(AttrName) + if resolved is not None: + ctype_cls: type = resolved[0] + ptr_level: int = resolved[1] + c_type_name = CTypeRegistry.CTypeToName(ctype_cls) + if ptr_level > 0 and c_type_name: + c_type_name = c_type_name + ' *' + if not c_type_name: + if AttrName == 'CPtr': + c_type_name = 'void *' + is_unsigned: bool = Gen._is_type_unsigned(c_type_name) if c_type_name else False + fmt_str: str = "%u\n" if is_unsigned else "%d\n" + fmt_ptr: ir.Value = Gen._create_string_global(fmt_str) + fmt_var_name: str = f"__{VarName}_fmt" + if fmt_var_name not in Gen.variables: + fmt_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) + Gen.variables[fmt_var_name] = fmt_alloca + Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name]) + kind_var_name: str = f"__{VarName}_kind" + if kind_var_name not in Gen.variables: + kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=kind_var_name) + Gen.variables[kind_var_name] = kind_alloca + Gen.builder.store(ir.Constant(ir.IntType(32), 0), Gen.variables[kind_var_name]) + if VarName not in Gen.variables: + dummy_var: ir.AllocaInstr = Gen._alloca(ir.IntType(8), name=VarName) + Gen.variables[VarName] = dummy_var + return + if isinstance(Node.value, ast.Name) and Node.value.id in Gen.structs: + ClassName: str = Node.value.id + Gen.var_type_info[VarName] = {'type': 'class_cast', 'name': ClassName} + Gen.var_type_assignments.setdefault(VarName, []).append({'type': 'class_cast', 'name': ClassName}) + fmt_str: str = "%p\n" + fmt_ptr: ir.Value = Gen._create_string_global(fmt_str) + fmt_var_name: str = f"__{VarName}_fmt" + if fmt_var_name not in Gen.variables: + fmt_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=fmt_var_name) + Gen.variables[fmt_var_name] = fmt_alloca + Gen.builder.store(fmt_ptr, Gen.variables[fmt_var_name]) + kind_var_name: str = f"__{VarName}_kind" + if kind_var_name not in Gen.variables: + kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=kind_var_name) + Gen.variables[kind_var_name] = kind_alloca + Gen.builder.store(ir.Constant(ir.IntType(32), 1), Gen.variables[kind_var_name]) + if VarName not in Gen.variables: + dummy_var: ir.AllocaInstr = Gen._alloca(ir.IntType(8), name=VarName) + Gen.variables[VarName] = dummy_var + return + if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == 'va_list': + va_list_ptr: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name="va_list") + Gen.variables[VarName] = va_list_ptr + return + IsStructCtor: bool = (isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) + and Node.value.func.id in Gen.structs) + if IsStructCtor: + ClassName: str = Node.value.func.id + StructType: ir.Type = Gen.structs[ClassName] + + IsUnion: bool = False + TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(ClassName) + if TypeInfo and TypeInfo.IsUnion: + IsUnion = True + + if IsUnion: + Value: ir.Value | None = self.HandleExprLlvm(Node.value) + if Value: + var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) + Gen._store(Value, var) + Gen.variables[VarName] = var + return + + ExistingPtr: ir.Value | None = None + # BUG-8 修复:清除读取全局变量时缓存的 GlobalVariable(非显式 global 声明) + if (VarName in Gen.variables and VarName not in Gen.global_vars + and isinstance(Gen.variables[VarName], ir.GlobalVariable)): + del Gen.variables[VarName] + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr: ir.Value = Gen.variables[VarName] + if isinstance(VarPtr.type.pointee, ir.PointerType): + ExistingPtr = VarPtr + elif VarName in Gen._reg_values: + OldVal: ir.Value = Gen._reg_values[VarName] + if isinstance(OldVal.type, ir.PointerType): + var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.variables[VarName] = var + del Gen._reg_values[VarName] + ExistingPtr = var + elif VarName in Gen._direct_values: + OldVal: ir.Value = Gen._direct_values.pop(VarName) + if isinstance(OldVal.type, ir.PointerType): + var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.variables[VarName] = var + ExistingPtr = var + if ExistingPtr: + pointee: ir.Type = ExistingPtr.type.pointee + # 仅当 alloca 直接存储结构体值(pointee 不是指针)时才 in-place 初始化。 + # 当 pointee 是 PointerType 时,alloca 存储的是堆对象指针: + # - 若 AnnAssign 分支未执行,alloca 内容是未初始化的栈垃圾 + # (可能恰好等于 pool 地址),_InitStructAtPtr 会向垃圾地址写字段 → 内存损坏 + # - 即使指针有效,node = Class(...) 的语义也是创建新对象并更新指针, + # 而非在旧对象位置 in-place 重初始化 + # 此时必须 fall through 到通用路径 HandleExprLlvm → _HandleClassNewLlvm + # 以正确调用 __new__/__before_init__/__init__ 构造新对象。 + if not isinstance(pointee, ir.PointerType) and pointee == StructType: + self._InitStructAtPtr(Node.value, ClassName, ExistingPtr) + return + if isinstance(Node.value, ast.Attribute): + enum_type_name: str | None = self._CheckEnumMemberAssignment(Node.value) + if enum_type_name: + Gen.var_type_info[VarName] = {'type': 'enum', 'name': enum_type_name} + var_type_for_list: ir.Type | None = None + if isinstance(Node.value, ast.List) and VarName in Gen.var_type_info: + type_info: dict[str, str] = Gen.var_type_info[VarName] + if type_info.get('type') == 'CArray': + var_type_for_list = type_info.get('full_type') + Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=var_type_for_list) + # 闭包变量追踪:当赋值右侧是返回闭包的函数调用时,记录变量为闭包类型 + if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): + CalledName: str = Node.value.func.id + if CalledName in Gen._closure_return_types: + Gen._closure_var_types[VarName] = Gen._closure_return_types[CalledName] + if not Value: + return + if isinstance(Value.type, ir.VoidType): + return + Gen._UnregisterTempPtr(Value) + # 大端局部变量:赋值时 bswap + Value = Gen._apply_bswap_if_big(Value, Gen.local_var_byteorders.get(VarName, ""), f"bswap_assign_{VarName}") + if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found_class: str | None = None + found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(Value.type.pointee) + if found: + CN: str = found[0] + ST: ir.Type = found[1] + found_class = CN + Gen.var_struct_class[VarName] = CN + Gen._var_to_heap_ptr[VarName] = Value + if found_class is None and isinstance(Value.type.pointee, ir.IdentifiedStructType): + pointee_name: str = Value.type.pointee.name + pointee_short: str = Gen._extract_short_name(pointee_name) + best_elem_count: int = 0 + for CN, ST in Gen.structs.items(): + if isinstance(ST, ir.IdentifiedStructType): + st_short: str = Gen._extract_short_name(ST.name) + if st_short == pointee_short: + elem_count: int = len(ST.elements) if ST.elements else 0 + if elem_count > best_elem_count: + found_class = CN + best_elem_count = elem_count + if found_class: + Gen.var_struct_class[VarName] = found_class + Gen._var_to_heap_ptr[VarName] = Value + # 泛型类特化触发:返回类型是泛型类特化(如 list[str])但结构体尚未创建, + # 或虽然找到了结构体但它是 opaque(来自 stub 声明,尚未发射方法体) + _fd_struct_opaque: bool = False + if found_class and found_class in Gen.structs: + _fd_st: ir.IdentifiedStructType = Gen.structs[found_class] + if isinstance(_fd_st, ir.IdentifiedStructType) and (_fd_st.elements is None or len(_fd_st.elements) == 0): + _fd_struct_opaque = True + if (found_class is None or _fd_struct_opaque) and isinstance(Value.type.pointee, ir.IdentifiedStructType): + pn: str = Value.type.pointee.name + short_pn: str = pn + if '.' in pn: + pn_parts: list[str] = pn.split('.', 1) + if len(pn_parts[0]) >= 8 and all(c in '0123456789abcdef' for c in pn_parts[0]): + short_pn = pn_parts[1] + if '[' in short_pn and short_pn.endswith(']'): + gc_base: str = short_pn.split('[')[0] + gc_args_raw: str = short_pn[len(gc_base):] + gc_type_args: list[str] = [] + for gc_arg_part in gc_args_raw.split(']['): + gc_arg_part = gc_arg_part.strip('[]') + if gc_arg_part: + gc_type_args.append(gc_arg_part) + if (gc_type_args + and hasattr(self.Trans.ClassHandler, '_generic_class_templates') + and gc_base in self.Trans.ClassHandler._generic_class_templates): + gc_type_names: list[str] = [] + for gc_ta in gc_type_args: + gc_tn: str = gc_ta + if gc_ta == 'int': + gc_tn = 'CInt' + elif gc_ta == 'double': + gc_tn = 'CDouble' + elif gc_ta == 'float': + gc_tn = 'CFloat' + elif gc_ta == 'char': + gc_tn = 'CChar' + elif gc_ta == 'bool': + gc_tn = 'CBool' + gc_type_names.append(gc_tn) + gc_spec: str | None = self.Trans.ClassHandler._specialize_generic_class( + gc_base, gc_type_args, Gen, type_names=gc_type_names) + if gc_spec and gc_spec in Gen.structs: + found_class = gc_spec + Gen.var_struct_class[VarName] = gc_spec + Gen._var_to_heap_ptr[VarName] = Value + else: + if VarName in ('mctx', 's1ctx', 's2ctx', 's5ctx'): + pass + if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + # BUG-8 修复:清除读取全局变量时缓存的 GlobalVariable(非显式 global 声明) + if (VarName in Gen.variables and VarName not in Gen.global_vars + and isinstance(Gen.variables[VarName], ir.GlobalVariable)): + del Gen.variables[VarName] + if VarName in Gen.variables and Gen.variables[VarName] is not None: + Gen._store(Value, Gen.variables[VarName]) + else: + var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) + Gen._store(Value, var) + Gen.variables[VarName] = var + if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): + call_func_name: str = Node.value.func.id + if call_func_name in Gen.var_type_info: + type_info: dict[str, str] = Gen.var_type_info[call_func_name] + if type_info['type'] in ('t_type', 'class_cast'): + src_fmt_var: str = f"__{call_func_name}_fmt" + dst_fmt_var: str = f"__{VarName}_fmt" + if src_fmt_var in Gen.variables: + if dst_fmt_var not in Gen.variables: + dst_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) + Gen.variables[dst_fmt_var] = dst_alloca + src_fmt_ptr: ir.Value = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}") + Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var]) + src_kind_var: str = f"__{call_func_name}_kind" + dst_kind_var: str = f"__{VarName}_kind" + if src_kind_var in Gen.variables: + if dst_kind_var not in Gen.variables: + dst_kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var) + Gen.variables[dst_kind_var] = dst_kind_alloca + src_kind_val: ir.Value = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}") + Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var]) + Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} + return + if VarName in Gen.global_vars: + # 治本修复:global 声明的变量若未被模块级 AnnAssign 创建为 LLVM 全局 + # (注解无初始值的全局变量),此处自动创建零初始化全局变量 + GVar: ir.GlobalVariable + if VarName not in Gen.module.globals: + _gv_type: ir.Type = Value.type if isinstance(Value.type, (ir.IntType, ir.PointerType)) else ir.IntType(64) + GVar = ir.GlobalVariable(Gen.module, _gv_type, name=VarName) + GVar.initializer = ir.Constant(_gv_type, None) if isinstance(_gv_type, ir.PointerType) else ir.Constant(_gv_type, 0) + else: + GVar = Gen.module.globals[VarName] + Gen._store(Value, GVar) + Gen.variables[VarName] = GVar + if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(Value.type.pointee) + if found: + CN: str = found[0] + ST: ir.Type = found[1] + Gen.var_struct_class[VarName] = CN + return + if VarName in Gen._reg_values: + OldVal: ir.Value = Gen._reg_values[VarName] + var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.variables[VarName] = var + del Gen._reg_values[VarName] + if VarName in Gen._direct_values: + OldVal: ir.Value = Gen._direct_values.pop(VarName) + var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.variables[VarName] = var + # BUG-8 修复:清除读取全局变量时缓存的 GlobalVariable(非显式 global 声明)。 + # Python 语义:函数内无 global 声明时赋值应创建局部变量, + # 而非修改被读取缓存的全局变量。清除后走 L339 的正确逻辑。 + if (VarName in Gen.variables and VarName not in Gen.global_vars + and isinstance(Gen.variables[VarName], ir.GlobalVariable)): + del Gen.variables[VarName] + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr: ir.Value = Gen.variables[VarName] + TargetType: ir.Type | None = VarPtr.type.pointee if isinstance(VarPtr.type, ir.PointerType) else None + types_differ: bool + try: + types_differ = TargetType and Value.type != TargetType + except AssertionError: + types_differ = False + if isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType): + LoadedValue: ir.Value = Gen._load(Value, name=f"Load_{VarName}") + Loaded_differ: bool + try: + Loaded_differ = TargetType and LoadedValue.type != TargetType + except AssertionError: + Loaded_differ = False + if Loaded_differ: + try: + Coerced: ir.Value | None = Gen._coerce_value(LoadedValue, TargetType) + if Coerced is not None: + LoadedValue = Coerced + except AssertionError: + pass + Gen._store(LoadedValue, VarPtr) + elif types_differ: + try: + Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType) + if Coerced is not None: + Gen._store(Coerced, VarPtr) + else: + Gen._store(Value, VarPtr) + except AssertionError: + Gen._store(Value, VarPtr) + else: + Gen._store(Value, VarPtr) + if VarName not in Gen.variables: + # 检查是否为模块级全局变量 + # main 函数代表模块级作用域,直接修改全局变量 + # 其他函数中,未声明 global 且未先读取的赋值创建局部变量(Python 作用域语义) + # 先读取过的变量已通过 HandleExprLlvm 加入 Gen.variables,会走 L289 分支存储到全局 + CurrentFuncName: str = getattr(Gen.func, 'name', '') if Gen.func else '' + IsMainScope: bool = CurrentFuncName == 'main' or CurrentFuncName.endswith('.main') + if VarName in Gen.module.globals and (VarName in Gen.global_vars or IsMainScope): + GVar: ir.GlobalVariable = Gen.module.globals[VarName] + Gen._store(Value, GVar) + Gen.variables[VarName] = GVar + elif isinstance(Value.type, ir.PointerType) and isinstance(Value.type.pointee, ir.PointerType): + LoadedValue: ir.Value = Gen._load(Value, name=f"Load_{VarName}") + var: ir.AllocaInstr = Gen._allocaEntry(LoadedValue.type, name=VarName) + Gen._store(LoadedValue, var) + Gen.variables[VarName] = var + else: + var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) + Gen._store(Value, var) + Gen.variables[VarName] = var + is_u: bool = Gen._check_node_unsigned(Node.value) + Gen._record_var_signedness(VarName, 'unsigned int' if is_u else 'int') + if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): + call_func_name: str = Node.value.func.id + if call_func_name in Gen.var_type_info: + type_info: dict[str, str] = Gen.var_type_info[call_func_name] + if type_info['type'] in ('t_type', 'class_cast'): + src_fmt_var: str = f"__{call_func_name}_fmt" + dst_fmt_var: str = f"__{VarName}_fmt" + if src_fmt_var in Gen.variables: + if dst_fmt_var not in Gen.variables: + dst_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name=dst_fmt_var) + Gen.variables[dst_fmt_var] = dst_alloca + src_fmt_ptr: ir.Value = Gen._load(Gen.variables[src_fmt_var], name=f"Load_{call_func_name}_fmt_for_{VarName}") + Gen.builder.store(src_fmt_ptr, Gen.variables[dst_fmt_var]) + src_kind_var: str = f"__{call_func_name}_kind" + dst_kind_var: str = f"__{VarName}_kind" + if src_kind_var in Gen.variables: + if dst_kind_var not in Gen.variables: + dst_kind_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=dst_kind_var) + Gen.variables[dst_kind_var] = dst_kind_alloca + src_kind_val: ir.Value = Gen._load(Gen.variables[src_kind_var], name=f"Load_{call_func_name}_kind_for_{VarName}") + Gen.builder.store(src_kind_val, Gen.variables[dst_kind_var]) + Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} + else: + Gen.var_type_info[VarName] = {'type': 't_type_runtime', 'source': call_func_name} + elif isinstance(Target, ast.Attribute): + TargetType: ir.Type | None = None + AttrName: str = Target.attr + VarName: str | None = None + if isinstance(Target.value, ast.Name): + VarName = Target.value.id + if VarName: + ClassName: str | None = Gen.var_struct_class.get(VarName) + if not ClassName and Gen.global_struct_class: + ClassName = Gen.global_struct_class.get(VarName) + if ClassName: + Gen.var_struct_class[VarName] = ClassName + if not ClassName: + for CN in Gen.structs: + if VarName == CN.lower() or VarName.startswith(CN): + ClassName = CN + break + if ClassName and ClassName in Gen.class_members: + for m_name, m_type in Gen.class_members[ClassName]: + if m_name == AttrName: + TargetType = m_type + break + Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=TargetType) + if Value: + self._HandleAttributeStoreLlvm(Target, Value) + elif isinstance(Target, ast.Subscript): + TargetType: ir.Type | None = None + SubVarName: str | None = None + if isinstance(Target.value, ast.Name): + SubVarName = Target.value.id + if SubVarName in Gen.var_struct_class: + ClassName: str = Gen.var_struct_class[SubVarName] + if ClassName in Gen.class_members: + for m_name, m_type in Gen.class_members[ClassName]: + if m_name == SubVarName: + if isinstance(m_type, ir.PointerType): + pointee: ir.Type = m_type.pointee + if isinstance(pointee, ir.ArrayType): + TargetType = pointee.element + elif isinstance(m_type, ir.ArrayType): + TargetType = m_type.element + break + if not TargetType and isinstance(Target.value, ast.Name): + SubVarName = Target.value.id + var_val: ir.Value | None = Gen.variables.get(SubVarName) + if var_val is None and SubVarName in Gen._direct_values: + var_val = Gen._direct_values[SubVarName] + if var_val is not None: + var_type: ir.Type = var_val.type + if isinstance(var_type, ir.PointerType): + pointee: ir.Type = var_type.pointee + if isinstance(pointee, ir.ArrayType): + TargetType = pointee.element + elif isinstance(var_type, ir.ArrayType): + TargetType = var_type.element + Value: ir.Value | None = self.HandleExprLlvm(Node.value, VarType=TargetType) + if Value: + self._HandleSubscriptStoreLlvm(Target, Value) + elif isinstance(Target, ast.Tuple): + if isinstance(Node.value, ast.Call): + FuncName: str | None = None + ModulePath: str | None = None + if isinstance(Node.value.func, ast.Name): + FuncName = Node.value.func.id + elif isinstance(Node.value.func, ast.Attribute): + FuncName = Node.value.func.attr + ModulePath = self.Trans.ExprCallHandle._get_ModulePath(Node.value.func.value) + CReturnTypes: list[ast.expr] = [] + FuncDef: ast.FunctionDef | None = self.Trans.FunctionDefCache.get(FuncName) if FuncName else None + if FuncDef: + if FuncDef.returns and isinstance(FuncDef.returns, ast.Subscript): + if isinstance(FuncDef.returns.value, ast.Name) and FuncDef.returns.value.id == 'tuple': + slice_node: ast.expr = FuncDef.returns.slice + if isinstance(slice_node, ast.Tuple): + CReturnTypes = slice_node.elts + else: + CReturnTypes = [slice_node] + if FuncDef.decorator_list: + for decorator in FuncDef.decorator_list: + if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): + if decorator.func.attr == 'CReturn': + for arg in decorator.args: + CReturnTypes.append(arg) + if not CReturnTypes and FuncName: + func: ir.Function | None = Gen.functions.get(FuncName) + if func: + func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) + if func_ft: + ret_type: ir.Type = func_ft.return_type + if isinstance(ret_type, ir.LiteralStructType): + CReturnTypes = [None] * len(ret_type.elements) + if not CReturnTypes: + sym_key: str = FuncName + if not self.Trans.SymbolTable.has(sym_key): + if ModulePath: + sym_key = f"{ModulePath}.{FuncName}" + sym_info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(sym_key) + if sym_info and sym_info.IsFunction: + ret_type_info: CTypeInfo | None = sym_info.FuncPtrReturn + param_type_infos: list[tuple[str, CTypeInfo]] = [pt for _, pt in (sym_info.FuncPtrParams or [])] + if ret_type_info: + if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: + ret_type: ir.Type = ret_type_info.ToLLVM(Gen) + else: + ret_type = Gen._type_str_to_llvm(str(ret_type_info) if ret_type_info else 'i32', False) + if isinstance(ret_type, ir.LiteralStructType): + CReturnTypes = [None] * len(ret_type.elements) + if FuncName not in Gen.functions: + if isinstance(ret_type, ir.VoidType): + ret_type = ir.IntType(32) + llvm_param_types: list[ir.Type] = [] + for pt in param_type_infos: + if isinstance(pt, CTypeInfo) and pt.BaseType: + lp: ir.Type = pt.ToLLVM(Gen) + else: + lp = Gen._type_str_to_llvm(str(pt) if pt else 'i32', '*' in str(pt) if isinstance(pt, str) else False) + if isinstance(lp, ir.VoidType): + lp = ir.IntType(8).as_pointer() + llvm_param_types.append(lp) + func_type: ir.FunctionType = ir.FunctionType(ret_type, llvm_param_types) + MangledName: str = Gen._mangle_func_name(FuncName) + func_decl: ir.Function = ir.Function(Gen.module, func_type, name=MangledName) + Gen.functions[MangledName] = func_decl + Gen.functions[FuncName] = func_decl + if not CReturnTypes and FuncName: + func: ir.Function | None = Gen.functions.get(FuncName) + if func: + func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) + if func_ft: + ret_type: ir.Type = func_ft.return_type + if isinstance(ret_type, ir.LiteralStructType): + CReturnTypes = [None] * len(ret_type.elements) + if not CReturnTypes: + # 跨模块多返回值兜底:短名未注册时(函数以 ModulePath.名 / + # sha1.名 全名注册),从其 LiteralStructType 返回类型恢复 CReturnTypes。 + # 否则 CReturnTypes 为空会走下方静默 return,目标变量未初始化, + # 运行期 free(垃圾指针) 触发堆损坏(HashLibTest 0xC0000374)。 + func = None + if ModulePath: + func = Gen.functions.get(f"{ModulePath}.{FuncName}") + if func is None: + for key in Gen.functions: + if key.endswith(f".{FuncName}"): + func = Gen.functions[key] + break + if func: + func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) + if func_ft: + ret_type: ir.Type = func_ft.return_type + if isinstance(ret_type, ir.LiteralStructType): + CReturnTypes = [None] * len(ret_type.elements) + if CReturnTypes and len(Target.elts) == len(CReturnTypes): + if func is None: + func = Gen.functions.get(FuncName) + CallArgs: list[ir.Value | None] = [] + for arg in Node.value.args: + ArgVal: ir.Value | None = self.HandleExprLlvm(arg) + if ArgVal: + CallArgs.append(ArgVal) + for kw in Node.value.keywords: + pass + func: ir.Function | None = Gen.functions.get(FuncName) + func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) if func else None + func_params: list[ir.Type] = list(getattr(func_ft, 'args', []) or []) if func_ft else [] + while len(CallArgs) < len(func_params): + FuncDef: ast.FunctionDef | None = self.Trans.FunctionDefCache.get(FuncName) + if FuncDef and len(CallArgs) < len(FuncDef.args.args): + arg_def: list[ast.expr] = FuncDef.args.defaults + arg_idx: int = len(CallArgs) + total_args: int = len(FuncDef.args.args) + default_start: int = total_args - len(arg_def) + if arg_idx >= default_start: + def_idx: int = arg_idx - default_start + if def_idx < len(arg_def): + DefVal: ir.Value | None = self.HandleExprLlvm(arg_def[def_idx]) + if DefVal: + expected_type: ir.Type = func_params[arg_idx] + if DefVal.type != expected_type: + if isinstance(expected_type, ir.IntType) and isinstance(DefVal.type, ir.IntType): + if DefVal.type.width < expected_type.width: + DefVal = Gen.builder.zext(DefVal, expected_type, name=f"zext_default_{arg_idx}") + elif DefVal.type.width > expected_type.width: + DefVal = Gen.builder.trunc(DefVal, expected_type, name=f"trunc_default_{arg_idx}") + CallArgs.append(DefVal) + continue + if len(CallArgs) < len(func_params): + CallArgs.append(ir.Constant(func_params[len(CallArgs)], 0)) + else: + break + adjusted: list[ir.Value] = Gen._adjust_args(CallArgs, func) + call_result: ir.Value = Gen.builder.call(func, adjusted, name=f"call_{FuncName}") + func_ft: ir.FunctionType | None = getattr(func, 'ftype', None) + ret_type: ir.Type | None = getattr(func_ft, 'return_type', None) if func_ft else None + for j, elt in enumerate(Target.elts): + if isinstance(elt, ast.Name): + VarName: str = elt.id + field_val: ir.Value = Gen.builder.extract_value(call_result, j, name=f"extract_{FuncName}_{j}") + VarType: ir.Type + if CReturnTypes[j] is not None: + ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(CReturnTypes[j], self.Trans.SymbolTable) + if ReturnTypeInfo is None: + ReturnTypeInfo = CTypeInfo() + ReturnTypeInfo.BaseType = t.CInt() + VarType = Gen._ctype_to_llvm(ReturnTypeInfo) + elif ret_type and isinstance(ret_type, ir.LiteralStructType) and j < len(ret_type.elements): + VarType = ret_type.elements[j] + else: + VarType = field_val.type + if isinstance(VarType, ir.VoidType): + VarType = ir.IntType(32) + var: ir.AllocaInstr = Gen._alloca(VarType, name=VarName) + Gen.variables[VarName] = var + if CReturnTypes[j] is not None: + Gen._record_var_signedness(VarName, str(ReturnTypeInfo) if ReturnTypeInfo else '') + elif ret_type and isinstance(ret_type, ir.LiteralStructType) and j < len(ret_type.elements): + elem_type: ir.Type = ret_type.elements[j] + if isinstance(elem_type, ir.IntType): + if elem_type.width == 16: + Gen._record_var_signedness(VarName, 'unsigned short') + elif elem_type.width == 32: + Gen._record_var_signedness(VarName, 'unsigned int') + elif elem_type.width == 64: + Gen._record_var_signedness(VarName, 'unsigned long long') + Gen._store(field_val, var) + elif isinstance(Node.value, ast.Call): + # fail-fast:多返回值赋值但 CReturnTypes 解析失败(跨模块签名丢失), + # 绝不能静默跳过——目标变量不会被初始化,运行期 free(垃圾指针) + # 触发堆损坏(HashLibTest 0xC0000374)。 + target_names: list[str] = [ + e.id if isinstance(e, ast.Name) else '' for e in Target.elts + ] + raise Exception( + f"多返回值赋值解析失败: '{FuncName}' 的返回类型无法解析为" + f"元组/CReturn(ModulePath={ModulePath}),目标 {target_names} 未被初始化" + f"{Gen._get_node_info()}" + ) + return + + def _InitStructAtPtr(self, call_node: ast.Call, ClassName: str, VarPtr: ir.Value) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if ClassName not in Gen.structs: + return + StructType: ir.Type = Gen.structs[ClassName] + StructPtrType: ir.PointerType = ir.PointerType(StructType) + RawPtr: ir.Value = Gen._load(VarPtr, name=getattr(VarPtr, 'name', 'ptr')) + StructPtr: ir.Value = Gen.builder.bitcast(RawPtr, StructPtrType, name=ClassName) + members: list[tuple[str, ir.Type]] = Gen.class_members.get(ClassName, []) + defaults: dict[str, ir.Value] = Gen.class_member_defaults.get(ClassName, {}) + member_values: dict[str, ir.Value] = {} + for member_name, member_type in members: + if member_name in defaults: + member_values[member_name] = defaults[member_name] + if call_node.args: + for i, arg in enumerate(call_node.args): + if i < len(members): + member_name: str = members[i][0] + val: ir.Value | None = self.HandleExprLlvm(arg) + if val: + member_values[member_name] = val + if call_node.keywords: + for kw in call_node.keywords: + val: ir.Value | None = self.HandleExprLlvm(kw.value) + if val: + member_values[kw.arg] = val + has_vtable: bool = ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes + base: int = 1 if has_vtable else 0 + for i, (member_name, member_type) in enumerate(members): + if isinstance(member_type, ir.VoidType): + continue + if member_name in member_values: + ElemPtr: ir.Value = Gen.builder.gep(StructPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), base + i)], name=f"{ClassName}_{member_name}") + try: + Gen._store(member_values[member_name], ElemPtr) + except Exception as _e: + if _config_mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + InitFuncName: str = f'{ClassName}.__init__' + if Gen._has_function(InitFuncName): + Args: list[ir.Value | None] = [self.HandleExprLlvm(arg) for arg in call_node.args] + Args = [a for a in Args if a] + Gen.builder.call(Gen._get_function(InitFuncName), [StructPtr] + Args, name=f"call_{InitFuncName}") + + def _HandleAttributeStoreLlvm(self, Target: ast.Attribute, Value: ir.Value) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + AttrName: str = Target.attr + if isinstance(Target.value, ast.Name) and Target.value.id == 'self': + ClassName: str | None = self.Trans._CurrentCpythonObjectClass + if ClassName and ClassName in Gen.structs: + PropKey: str = f'{ClassName}.{AttrName}' + PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) + if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: + SelfVar: ir.Value | None = Gen._get_var_ptr('self') + if SelfVar: + SelfPtr: ir.Value = Gen._load(SelfVar, name="self") + SetterFunc: ir.Function | None = Gen._get_function(PropKey + '$set') + if SetterFunc and SelfPtr: + Gen.builder.call(SetterFunc, [SelfPtr, Value], name=f"prop_set_{PropKey}") + return + SelfVar: ir.Value | None = Gen._get_var_ptr('self') + if not SelfVar: + return + if SelfVar: + SelfPtr: ir.Value = Gen._load(SelfVar, name="self") + is_vtable_method: bool = False + method_idx: int = 0 + if ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes: + if ClassName in Gen.class_methods: + for mi, mn in enumerate(Gen.class_methods[ClassName]): + method_short: str = mn.split('.')[-1] if '.' in mn else mn + if method_short == AttrName or mn == AttrName: + is_vtable_method = True + method_idx = mi + break + if is_vtable_method: + VtableSlotPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}") + VtablePtr: ir.Value = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}") + methods: list[str] = Gen.class_methods[ClassName] + VtableArrayType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) + ClassVtable: ir.GlobalVariable | None = Gen.Vtables.get(ClassName) + if ClassVtable: + ClassVtableAddr: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}") + IsSameVtable: ir.Value = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}") + CopyBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_copy_self_{AttrName}") + SkipBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_skip_self_{AttrName}") + Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock) + Gen.builder.position_at_end(CopyBlock) + Gen._vtable_copy_counter += 1 + CopyName: str = f"{Gen._mangle_name(ClassName)}_vtable_copy_self_{Gen._vtable_copy_counter}" + VtableCopyGlobal: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VtableArrayType, name=CopyName) + VtableCopyGlobal.linkage = 'internal' + VtableCopyGlobal.initializer = ir.Constant(VtableArrayType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) + VtableCopyTyped: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed") + SrcTyped: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed") + VtableSize: int = len(methods) * Gen.ptr_size + MemcpyFunc: ir.Function | None = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64') + if not MemcpyFunc: + MemcpyType: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) + MemcpyFunc = ir.Function(Gen.module, MemcpyType, name='llvm.memcpy.p0i8.p0i8.i64') + Gen.functions['llvm.memcpy.p0i8.p0i8.i64'] = MemcpyFunc + Gen.builder.call(MemcpyFunc, [VtableCopyTyped, SrcTyped, ir.Constant(ir.IntType(64), VtableSize), ir.Constant(ir.IntType(1), 0)]) + VtableCopyGlobalAddr: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_addr") + Gen._store(VtableCopyGlobalAddr, VtableSlotPtr) + Gen.builder.branch(SkipBlock) + Gen.builder.position_at_end(SkipBlock) + VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_after_copy") + VtableTyped: ir.Value = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}") + MethodPtrAddr: ir.Value = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}") + FuncPtrI8: ir.Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}") + Gen._store(FuncPtrI8, MethodPtrAddr) + return + offset: int = Gen._get_member_offset(AttrName, ClassName) + struct_type: ir.Type = Gen.structs[ClassName] + max_offset: int = len(struct_type.elements) if isinstance(struct_type, ir.IdentifiedStructType) else 0 + if offset >= max_offset: + VarName: str = f"self.{AttrName}" + if VarName not in Gen.variables: + NewVar: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=AttrName) + Gen.variables[VarName] = NewVar + Gen._store(Value, Gen.variables[VarName]) + return + MemberPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + elif isinstance(Target.value, ast.Name): + VarName: str = Target.value.id + + # FakeDuck: 检查是否有影子结构体 a__meta__ (str 变量的 per-instance 字段存储) + # 直接通过 a.__field__ = value 访问影子结构体字段 (语法糖) + _fd_meta_name: str = f"{VarName}__meta__" + if _fd_meta_name in Gen.variables and '_str' in Gen.structs: + _fd_offset = Gen._get_member_offset(AttrName, '_str') + if _fd_offset is not None: + _fd_meta_ptr: ir.Value = Gen.variables[_fd_meta_name] + _fd_field_ptr: ir.Value = Gen.builder.gep(_fd_meta_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), _fd_offset)], name=f"{VarName}_{AttrName}_ptr") + self._StoreWithCoerce(Value, _fd_field_ptr) + return + + ClassName: str | None = Gen.var_struct_class.get(VarName) + + if not ClassName and Gen.global_struct_class: + ClassName = Gen.global_struct_class.get(VarName) + if ClassName: + Gen.var_struct_class[VarName] = ClassName + + if not ClassName: + for CN in Gen.structs: + if VarName == CN.lower() or VarName.startswith(CN): + ClassName = CN + break + + if not ClassName and VarName in Gen.module.globals: + GVar: ir.GlobalVariable = Gen.module.globals[VarName] + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(GVar.type.pointee) + if found: + ClassName = found[0] + Gen.var_struct_class[VarName] = ClassName + if Gen.global_struct_class: + Gen.global_struct_class[VarName] = ClassName + + if not ClassName and VarName in Gen.variables: + VarPtr: ir.Value = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType): + pointee: ir.Type = VarPtr.type.pointee + if isinstance(pointee, ir.PointerType): + pointee = pointee.pointee + found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee) + if found: + CN: str = found[0] + ST: ir.Type = found[1] + ClassName = CN + elif isinstance(pointee, ir.IdentifiedStructType): + # sha1 冲突 fallback:find_struct_by_pointee 因 sha1 前缀不匹配失败时, + # 用短名(去掉 sha1 前缀)匹配,优先选字段最多的完整版本 + pointee_short: str = Gen._extract_short_name(pointee.name) + best_elem_count: int = 0 + for CN, ST in Gen.structs.items(): + if isinstance(ST, ir.IdentifiedStructType): + st_short: str = Gen._extract_short_name(ST.name) + if st_short == pointee_short: + elem_count: int = len(ST.elements) if ST.elements else 0 + if elem_count > best_elem_count: + ClassName = CN + best_elem_count = elem_count + + IsUnion: bool = False + if ClassName: + TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(ClassName) + if TypeInfo and TypeInfo.IsUnion: + IsUnion = True + + if ClassName and ClassName in Gen.structs: + PropKey: str = f'{ClassName}.{AttrName}' + PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) + if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList: + ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) + SetterFunc: ir.Function | None = Gen._get_function(PropKey + '$set') + if SetterFunc and ObjVal: + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}") + Gen.builder.call(SetterFunc, [ObjVal, Value], name=f"prop_set_{PropKey}") + return + ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) + if ObjVal: + if BaseHandle._is_char_pointer(ObjVal): + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + if isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name=f"Load_{ClassName}") + # 跨模块 opaque 类型:ObjVal.type.pointee 与 Gen.structs[ClassName] 可能是 + # 不同的 IdentifiedStructType 对象(虽然 name 相同),== 返回 False。 + # 使用 name 匹配作为 fallback,与链式赋值路径(第 926-927 行)一致。 + # sha1 冲突时还需短名匹配(如 6bc91356c652f8ca.Function vs 8ad0c0a2934ca5b4.Function) + _ObjPointee = ObjVal.type.pointee if isinstance(ObjVal.type, ir.PointerType) else None + _TargetStruct = Gen.structs.get(ClassName) + _MatchesStruct = (_ObjPointee is not None and _TargetStruct is not None and + (_ObjPointee == _TargetStruct or + (isinstance(_ObjPointee, ir.IdentifiedStructType) and isinstance(_TargetStruct, ir.IdentifiedStructType) and + (_ObjPointee.name == _TargetStruct.name or + Gen._extract_short_name(_ObjPointee.name) == Gen._extract_short_name(_TargetStruct.name))))) + # opaque 泛型结构体 → 特化版本 bitcast + # 当 ObjVal 的 pointee 是 opaque 基础泛型结构体(如 GSList,来自跨模块 stub), + # 而 ClassName 是特化版本(如 GSList[BasicBlock])时,两者 short name 不同 + # (GSList vs GSList[BasicBlock]),_MatchesStruct 失败。 + # 验证特化 short name 以 基础名+'[' 开头,bitcast 到特化版本使后续 GEP 能正确访问字段。 + if (not _MatchesStruct + and isinstance(ObjVal.type, ir.PointerType) + and isinstance(_ObjPointee, ir.IdentifiedStructType) + and isinstance(_TargetStruct, ir.IdentifiedStructType) + and '[' in ClassName): + _BaseShort: str = Gen._extract_short_name(_ObjPointee.name) + _SpecShort: str = Gen._extract_short_name(_TargetStruct.name) + if _BaseShort and _SpecShort.startswith(_BaseShort + '['): + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(_TargetStruct), name=f"cast_spec_{ClassName}") + _MatchesStruct = True + if isinstance(ObjVal.type, ir.PointerType) and _MatchesStruct: + if IsUnion: + NestedStructName: str = f"{ClassName}_{AttrName}" + if NestedStructName in Gen.structs: + NestedStructType: ir.Type = Gen.structs[NestedStructName] + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(NestedStructType), name=f"cast_{NestedStructName}") + offset: int | None = Gen._get_member_offset(AttrName, NestedStructName) + if offset is not None and offset < len(NestedStructType.elements): + MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + return + bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(ClassName, {}) + if AttrName in bitfield_offsets: + self._store_bitfield_member(ObjVal, ClassName, AttrName, Value) + return + bitfields: dict[str, int] = Gen.class_member_bitfields.get(ClassName, {}) + if AttrName in bitfields and bitfields[AttrName] > 0: + if ClassName not in Gen.class_member_bitoffsets: + Gen.class_member_bitoffsets[ClassName] = {} + if AttrName not in Gen.class_member_bitoffsets[ClassName]: + bo: int = 0 + for bf_name, bf_width in bitfields.items(): + if bf_name == AttrName: + break + bo += bf_width + Gen.class_member_bitoffsets[ClassName][AttrName] = bo + self._store_bitfield_member(ObjVal, ClassName, AttrName, Value) + return + is_vtable_method: bool = False + method_idx: int = 0 + if ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes: + if ClassName in Gen.class_methods: + for mi, mn in enumerate(Gen.class_methods[ClassName]): + method_short: str = mn.split('.')[-1] if '.' in mn else mn + if method_short == AttrName or mn == AttrName: + is_vtable_method = True + method_idx = mi + break + if is_vtable_method: + VtableSlotPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}") + VtablePtr: ir.Value = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}") + methods: list[str] = Gen.class_methods[ClassName] + VtableArrayType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) + ClassVtable: ir.GlobalVariable | None = Gen.Vtables.get(ClassName) + if ClassVtable: + ClassVtableAddr: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"class_vtable_addr_{ClassName}") + IsSameVtable: ir.Value = Gen.builder.icmp_unsigned('==', VtablePtr, ClassVtableAddr, name=f"is_same_vtable_{ClassName}") + CopyBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_copy_{AttrName}") + SkipBlock: ir.Block = Gen.func.append_basic_block(name=f"vtable_skip_{AttrName}") + Gen.builder.cbranch(IsSameVtable, CopyBlock, SkipBlock) + Gen.builder.position_at_end(CopyBlock) + Gen._vtable_copy_counter += 1 + CopyName: str = f"{Gen._mangle_name(ClassName)}_vtable_copy_{Gen._vtable_copy_counter}" + VtableCopyGlobal: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VtableArrayType, name=CopyName) + VtableCopyGlobal.linkage = 'internal' + VtableCopyGlobal.initializer = ir.Constant(VtableArrayType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) + VtableCopyTyped: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_typed") + SrcTyped: ir.Value = Gen.builder.bitcast(ClassVtable, ir.PointerType(ir.IntType(8)), name=f"src_vtable_typed") + VtableSize: int = len(methods) * Gen.ptr_size + MemcpyFunc: ir.Function | None = Gen._find_function('llvm.memcpy.p0i8.p0i8.i64') + if not MemcpyFunc: + MemcpyType: ir.FunctionType = ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8)), ir.PointerType(ir.IntType(8)), ir.IntType(64), ir.IntType(1)]) + MemcpyFunc = ir.Function(Gen.module, MemcpyType, name='llvm.memcpy.p0i8.p0i8.i64') + Gen.functions['llvm.memcpy.p0i8.p0i8.i64'] = MemcpyFunc + Gen.builder.call(MemcpyFunc, [VtableCopyTyped, SrcTyped, ir.Constant(ir.IntType(64), VtableSize), ir.Constant(ir.IntType(1), 0)]) + VtableCopyGlobalAddr: ir.Value = Gen.builder.bitcast(VtableCopyGlobal, ir.PointerType(ir.IntType(8)), name=f"vtable_copy_addr") + Gen._store(VtableCopyGlobalAddr, VtableSlotPtr) + Gen.builder.branch(SkipBlock) + Gen.builder.position_at_end(SkipBlock) + VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}_after_copy") + VtableTyped: ir.Value = Gen.builder.bitcast(VtablePtr, ir.PointerType(VtableArrayType), name=f"vtable_typed_{ClassName}") + MethodPtrAddr: ir.Value = Gen.builder.gep(VtableTyped, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), method_idx)], name=f"vmethod_slot_{AttrName}") + FuncPtrI8: ir.Value = Gen.builder.bitcast(Value, ir.PointerType(ir.IntType(8)), name=f"func_ptr_i8_{AttrName}") + Gen._store(FuncPtrI8, MethodPtrAddr) + return + offset: int | None = Gen._get_member_offset(AttrName, ClassName) + StructType: ir.Type | None = Gen.structs.get(ClassName) + if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(ClassName, Gen) + StructType = Gen.structs.get(ClassName) + if isinstance(StructType, ir.IdentifiedStructType) and (StructType.elements is None or len(StructType.elements) == 0): + return + # 重新计算 offset:_TryLoadStructFromStub 刚加载了 struct body, + # 之前 offset 可能因 struct opaque / class_members 不完整而返回 None + offset = Gen._get_member_offset(AttrName, ClassName) + # sha1 冲突修复:Gen.structs[ClassName] 可能是字段不全的版本(如 2 字段 Function + # 来自 MetaType.py scope,而正确版本是 8 字段 Function 来自 __function.py)。 + # _get_member_offset 通过 class_sha1_map 已返回正确的 offset(如 5), + # 但 StructType 可能只有 2 个 elements,导致 offset < len(elements) 失败。 + # 在所有 structs 中查找同短名且字段最多的版本。 + if offset is not None and isinstance(StructType, ir.IdentifiedStructType) and StructType.elements is not None and offset >= len(StructType.elements): + _short: str = Gen._extract_short_name(StructType.name) + _best: int = len(StructType.elements) + for _cn, _st in Gen.structs.items(): + if isinstance(_st, ir.IdentifiedStructType) and _st.elements is not None: + if Gen._extract_short_name(_st.name) == _short and len(_st.elements) > _best: + StructType = _st + _best = len(_st.elements) + # bitcast:当 ObjVal 的 pointee 是 opaque 或与 StructType 不是同一个类型对象 + # (sha1 前缀不同但短名相同)时,需要 bitcast 到 StructType 才能正确 GEP + if StructType is not None and StructType.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and (ObjVal.type.pointee.elements is None or ObjVal.type.pointee != StructType): + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(StructType), name=f"cast_{ClassName}") + if offset is not None and StructType is not None and StructType.elements is not None and offset < len(StructType.elements): + MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + else: + return + + byte_order: str = Gen.class_member_byteorders.get(ClassName, {}).get(AttrName, "") + + if byte_order == 'big': + if StructType is None or StructType.elements is None or len(StructType.elements) == 0: + return + member_type: ir.Type = StructType.elements[offset] + if isinstance(member_type, ir.IntType): + Value = Gen._apply_bswap_if_big(Value, byte_order, f"bswap_store_{AttrName}") + + self._StoreWithCoerce(Value, MemberPtr) + if not ClassName: + imported_modules: list[str] | None = getattr(self.Trans, '_ImportedModules', None) + resolved_mod: str = self.Trans.SymbolTable.resolve_alias(VarName) + if imported_modules and (VarName in imported_modules or resolved_mod in imported_modules): + PossibleKeys: list[str] = [f"{VarName}.{AttrName}", AttrName] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + key: str = f"{mod_name}.{AttrName}" + if key not in PossibleKeys: + PossibleKeys.append(key) + for key in PossibleKeys: + if key in Gen.module.globals: + GVar: ir.GlobalVariable = Gen.module.globals[key] + if isinstance(GVar, ir.Function): + return + if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return + self._StoreWithCoerce(Value, GVar) + return + ModuleSha1Map: dict[str, str] = Gen.ModuleSha1Map + sha1_candidates: list[str] = [VarName, resolved_mod] + for mod_name in imported_modules: + if mod_name.endswith(f".{VarName}") or mod_name == VarName: + if mod_name not in sha1_candidates: + sha1_candidates.append(mod_name) + for cand in sha1_candidates: + sha1: str | None = ModuleSha1Map.get(cand) + if sha1: + prefixed: str = f"{sha1}.{AttrName}" + if prefixed in Gen.module.globals: + GVar2: ir.GlobalVariable = Gen.module.globals[prefixed] + if isinstance(GVar2, ir.Function): + return + if isinstance(GVar2.type, ir.PointerType) and isinstance(GVar2.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + return + self._StoreWithCoerce(Value, GVar2) + return + elif isinstance(Target.value, ast.Attribute): + ObjVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Target.value) + if ObjVal and isinstance(ObjVal.type, ir.PointerType): + pointee: ir.Type = ObjVal.type.pointee + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + if isinstance(pointee, ir.IdentifiedStructType) and pointee.elements is None: + for CN, ST in Gen.structs.items(): + if isinstance(ST, ir.IdentifiedStructType) and ST.name == pointee.name and ST.elements is not None: + pointee = ST + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") + break + found_match: bool = False + for CN, ST in Gen.structs.items(): + if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): + found_match = True + if ST.elements is None: + self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) + ST = Gen.structs.get(CN, ST) + if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") + bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(CN, {}) + if AttrName in bitfield_offsets: + self._store_bitfield_member(ObjVal, CN, AttrName, Value) + return + offset: int = Gen._get_member_offset(AttrName, CN) + if offset is not None and ST.elements is not None and offset < len(ST.elements): + MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + break + if not found_match: + if isinstance(pointee, ir.IdentifiedStructType): + matched_cn: str | None = None + for CN in Gen.class_members: + members: list[tuple[str, ir.Type]] = Gen.class_members[CN] + for mname, mtype in members: + if mname == AttrName: + matched_cn = CN + break + if matched_cn: + break + if matched_cn and matched_cn in Gen.structs: + ST: ir.Type = Gen.structs[matched_cn] + if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(matched_cn, Gen) + ST = Gen.structs.get(matched_cn, ST) + if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{matched_cn}") + offset: int = Gen._get_member_offset(AttrName, matched_cn) + if offset is not None and ST.elements is not None and offset < len(ST.elements): + MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + return + elif isinstance(Target.value, ast.Call): + # Check if this is c.Deref(...) — we need the pointer, not the Loaded value + ObjVal: ir.Value | None = None + is_cderef: bool = (isinstance(Target.value.func, ast.Attribute) and + isinstance(Target.value.func.value, ast.Name) and + Target.value.func.value.id == 'c' and + Target.value.func.attr == 'Deref' and + Target.value.args) + if is_cderef: + # Get the pointer from c.Deref argument, don't Load the value + deref_arg: ast.expr = Target.value.args[0] + inner_val: ir.Value | None = self.HandleExprLlvm(deref_arg) + if inner_val and isinstance(inner_val.type, ir.PointerType): + if isinstance(inner_val.type.pointee, ir.PointerType): + ObjVal = Gen._load(inner_val, name="deref_load_ptr") + else: + ObjVal = inner_val + if ObjVal is None: + ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value) + if ObjVal and isinstance(ObjVal.type, ir.PointerType): + pointee: ir.Type = ObjVal.type.pointee + if isinstance(pointee, ir.PointerType): + ObjVal = Gen._load(ObjVal, name="load_ptr_for_attr") + pointee = ObjVal.type.pointee + for CN, ST in Gen.structs.items(): + if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): + if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) + ST = Gen.structs.get(CN, ST) + if ST.elements is not None and isinstance(ObjVal.type, ir.PointerType) and isinstance(ObjVal.type.pointee, ir.IdentifiedStructType) and ObjVal.type.pointee.elements is None: + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(ST), name=f"cast_{CN}") + bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(CN, {}) + if AttrName in bitfield_offsets: + self._store_bitfield_member(ObjVal, CN, AttrName, Value) + return + offset: int = Gen._get_member_offset(AttrName, CN) + if offset is not None and ST.elements is not None and offset < len(ST.elements): + MemberPtr: ir.Value = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + break + elif isinstance(Target.value, ast.Subscript): + SubPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) + if SubPtr and isinstance(SubPtr.type, ir.PointerType): + pointee: ir.Type = SubPtr.type.pointee + + if isinstance(Target.value.value, ast.Attribute): + AttrNameSub: str = Target.value.value.attr + if AttrNameSub == 'items' and 'Item' in Gen.structs: + ObjValCast: ir.Value = Gen.builder.bitcast(SubPtr, ir.PointerType(Gen.structs['Item']), name=f"cast_Item") + offset: int = Gen._get_member_offset(AttrName, 'Item') + MemberPtr: ir.Value = Gen.builder.gep(ObjValCast, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + return + + if BaseHandle._is_char_pointer(SubPtr): + for CN, ST in Gen.structs.items(): + ObjValCast: ir.Value = Gen.builder.bitcast(SubPtr, ir.PointerType(ST), name=f"cast_{CN}") + offset: int = Gen._get_member_offset(AttrName, CN) + MemberPtr: ir.Value = Gen.builder.gep(ObjValCast, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + break + elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee) + if found: + CN: str = found[0] + ST: ir.Type = found[1] + if isinstance(ST, ir.IdentifiedStructType) and (ST.elements is None or len(ST.elements) == 0): + self.Trans.ImportHandler._TryLoadStructFromStub(CN, Gen) + ST = Gen.structs.get(CN, ST) + if ST.elements is not None and isinstance(SubPtr.type, ir.PointerType) and isinstance(SubPtr.type.pointee, ir.IdentifiedStructType) and SubPtr.type.pointee.elements is None: + SubPtr = Gen.builder.bitcast(SubPtr, ir.PointerType(ST), name=f"cast_{CN}") + offset: int = Gen._get_member_offset(AttrName, CN) + if offset is not None and ST.elements is not None and offset < len(ST.elements): + MemberPtr: ir.Value = Gen.builder.gep(SubPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + elif isinstance(pointee, ir.PointerType): + LoadedPtr: ir.Value = Gen._load(SubPtr, name=f"Load_{AttrName}_ptr") + if isinstance(LoadedPtr.type, ir.PointerType) and isinstance(LoadedPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(LoadedPtr.type.pointee) + if found: + CN: str = found[0] + ST: ir.Type = found[1] + offset: int = Gen._get_member_offset(AttrName, CN) + MemberPtr: ir.Value = Gen.builder.gep(LoadedPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName) + self._StoreWithCoerce(Value, MemberPtr) + + def _StoreArrElemWithCoerceBswap(self, Value: ir.Value, Ptr: ir.Value, arr_byte_order: str) -> None: + """对数组元素存储应用 bswap 后再 coerce 存储""" + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + Value = Gen._apply_bswap_if_big(Value, arr_byte_order, "bswap_arr_store") + self._StoreWithCoerce(Value, Ptr) + + def _HandleSubscriptStoreLlvm(self, Target: ast.Subscript, Value: ir.Value) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + # 查询数组元素字节序 + arr_byte_order: str = '' + if isinstance(Target.value, ast.Name) and Target.value.id in Gen.local_var_byteorders: + arr_byte_order = Gen.local_var_byteorders[Target.value.id] + if isinstance(Target.value, ast.Name): + SubVarName: str = Target.value.id + if SubVarName in Gen.var_const_flags: + src_info: str = Gen._get_node_info() + self.Trans.LogError(f"不能对 const 变量 '{SubVarName}' 的元素赋值{src_info}") + ClassName: str | None = self.Trans.ExprHandler._get_var_class(Target.value, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__setitem__'): + 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(整数)的情况:联合类型 | t.CPtr 降级后可能被 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): + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + setitem_args: list[ir.Value] = [obj_val, idx_val, Value] + setitem_func_name: str = f'{ClassName}.__setitem__' + setitem_args = Gen._apply_auto_addr(setitem_func_name, setitem_args) + setitem_func: ir.Function = Gen._get_function(setitem_func_name) + setitem_args = Gen._adjust_args(setitem_args, setitem_func) + Gen.builder.call(setitem_func, setitem_args, name=f"call_{setitem_func_name}") + return + ValueVal: ir.Value | None = self.HandleExprLlvm(Target.value) + IndexVal: ir.Value | None = self.HandleExprLlvm(Target.slice) + if not ValueVal or not IndexVal: + return + # 当变量本身是二级指针(如 elem_ptr: T | t.CPtr = AST**), + # 且存储的值也是指针时,elem_ptr[i] = item 应直接存储指针(8 字节), + # 而非解引用后复制结构体(如 48 字节的 AST),避免对象切片 + if isinstance(Target.value, ast.Name): + VarName: str = Target.value.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarAlloca: ir.Value = Gen.variables[VarName] + if isinstance(VarAlloca.type, ir.PointerType) and isinstance(VarAlloca.type.pointee, ir.PointerType): + if (isinstance(ValueVal.type, ir.PointerType) and isinstance(Value.type, ir.PointerType) + and isinstance(Value.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_store") + # ValueVal 是 AST*(加载自 elem_ptr 的基指针), + # 但 GEP 默认将其视为 AST 结构体数组。需要先 bitcast 为 + # AST**(指向 AST* 的指针),让 GEP 正确索引 AST* 指针数组, + # 而非 AST 结构体数组。然后用 builder.store 直接存储指针, + # 避免 _store 的类型强制转换将指针解引用为结构体。 + PtrToStruct: ir.Type = Value.type.pointee + BaseAsPP: ir.Value = Gen.builder.bitcast(ValueVal, + ir.PointerType(ir.PointerType(PtrToStruct)), name="cast_base_pp") + ElemPtr: ir.Value = Gen.builder.gep(BaseAsPP, [IndexVal], name="subscript") + Gen.builder.store(Value, ElemPtr) + return + if BaseHandle._is_char_pointer(IndexVal): + Loaded_byte: ir.Value = Gen._load(IndexVal, name="Load_char_idx_store") + IndexVal = Gen.builder.zext(Loaded_byte, ir.IntType(32), name="char_to_int_idx_store") + if isinstance(ValueVal.type, ir.IntType): + var_ptr: ir.Value | None = self._get_int_ptr(Target.value) + if var_ptr: + i8_ptr: ir.Value = Gen.builder.bitcast(var_ptr, ir.PointerType(ir.IntType(8)), name="int_to_i8ptr_store") + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_int_index_store") + ptr: ir.Value = Gen.builder.gep(i8_ptr, [IndexVal], name="int_subscript_ptr_store") + self._StoreWithCoerce(Value, ptr) + return + if isinstance(ValueVal.type, ir.PointerType) and isinstance(ValueVal.type.pointee, ir.PointerType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width < 64: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_ptr_index_store") + ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") + self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) + return + if isinstance(ValueVal.type, ir.PointerType): + pointee: ir.Type = ValueVal.type.pointee + if isinstance(pointee, ir.ArrayType): + zero: ir.Constant = ir.Constant(ir.IntType(32), 0) + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [zero, IndexVal], name="subscript") + elif (isinstance(pointee, ir.IntType) and pointee.width == 8 + 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 | t.CPtr) + # 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: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(64), name="zext_pp_str_index_store") + ElemPtr = Gen.builder.gep(CastedPtrPtr, [IndexVal], name="subscript") + self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) + return + else: + ElemPtr: ir.Value = Gen.builder.gep(ValueVal, [IndexVal], name="subscript") + self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) + elif isinstance(ValueVal.type, ir.ArrayType): + zero: ir.Constant = ir.Constant(ir.IntType(32), 0) + if isinstance(Target.value, ast.Name): + VarName: str = Target.value.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr: ir.Value = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr: ir.Value = Gen.builder.gep(VarPtr, [zero, IndexVal], name="subscript") + self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) + return + if isinstance(Target.value, ast.Subscript): + InnerPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) + if InnerPtr: + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr: ir.Value = Gen.builder.gep(InnerPtr, [zero, IndexVal], name="subscript") + self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) + return + if isinstance(Target.value, ast.Attribute): + AttrPtr: ir.Value | None = self.Trans.ExprAttrHandle._get_attr_ptr(Target.value) + if AttrPtr and isinstance(AttrPtr.type, ir.PointerType) and isinstance(AttrPtr.type.pointee, ir.ArrayType): + if isinstance(IndexVal.type, ir.IntType) and IndexVal.type.width != 32: + if IndexVal.type.width < 32: + IndexVal = Gen.builder.zext(IndexVal, ir.IntType(32), name="zext_arr_index") + else: + IndexVal = Gen.builder.trunc(IndexVal, ir.IntType(32), name="trunc_arr_index") + ElemPtr: ir.Value = Gen.builder.gep(AttrPtr, [zero, IndexVal], name="subscript") + self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) + return + arr_alloc: ir.AllocaInstr = Gen._allocaEntry(ValueVal.type, name="arr_subscript_tmp") + Gen._store(ValueVal, arr_alloc) + ElemPtr: ir.Value = Gen.builder.gep(arr_alloc, [zero, IndexVal], name="subscript") + self._StoreArrElemWithCoerceBswap(Value, ElemPtr, arr_byte_order) + ModifiedArr: ir.Value = Gen._load(arr_alloc, name="modified_arr") + if isinstance(Target.value, ast.Subscript): + OuterPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Target.value) + if OuterPtr: + Gen._store(ModifiedArr, OuterPtr) + elif isinstance(Target.value, ast.Attribute): + OuterPtr: ir.Value | None = self.Trans.ExprAttrHandle._get_attr_ptr(Target.value) + if OuterPtr: + Gen._store(ModifiedArr, OuterPtr) + + def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if isinstance(Ptr.type, ir.PointerType): + TargetType: ir.Type = Ptr.type.pointee + if Value.type != TargetType: + if isinstance(TargetType, ir.ArrayType) and isinstance(Value.type, ir.PointerType): + ElemType: ir.Type = TargetType.element + ElemSize: int = Gen._get_struct_size(ElemType) + for i in range(TargetType.count): + DstElem: ir.Value = Gen.builder.gep(Ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"arr_dst_{i}") + SrcPtr: ir.Value + if ElemSize == 1: + SrcPtr = Gen.builder.gep(Value, [ir.Constant(ir.IntType(32), i)], name=f"arr_src_{i}") + else: + PtrInt: ir.Value = Gen.builder.ptrtoint(Value, ir.IntType(64)) + Offset: ir.Constant = ir.Constant(ir.IntType(64), i * ElemSize) + NewPtrInt: ir.Value = Gen.builder.add(PtrInt, Offset) + SrcPtr = Gen.builder.inttoptr(NewPtrInt, ir.PointerType(ElemType), name=f"arr_src_{i}") + SrcVal: ir.Value = Gen._load(SrcPtr, name=f"arr_elem_{i}") + if SrcVal.type != ElemType: + try: + SrcVal = Gen.builder.bitcast(SrcVal, ElemType, name=f"arr_cast_{i}") + except Exception: # 回退:bitcast 失败时跳过该元素 + continue + Gen._store(SrcVal, DstElem) + return + if isinstance(TargetType, ir.PointerType) and isinstance(Value, ir.Constant) and Value.constant is None: + Value = ir.Constant(TargetType, None) + elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType): + try: + Value = Gen.builder.bitcast(Value, TargetType, name="null_ptr_bitcast") + except Exception: # 回退:bitcast 失败时设为 null 常量 + Value = ir.Constant(TargetType, None) + else: + Coerced: ir.Value | None = Gen._coerce_value(Value, TargetType) + if Coerced is not None: + Value = Coerced + Gen._store(Value, Ptr) + + + def _get_int_ptr(self, target: ast.expr) -> ir.Value | None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if isinstance(target, ast.Name): + VarName: str = target.id + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr: ir.Value = Gen.variables[VarName] + if isinstance(VarPtr.type, ir.PointerType): + pointee: ir.Type = VarPtr.type.pointee + if isinstance(pointee, ir.ArrayType): + return Gen.builder.gep(VarPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"arr_start_{VarName}") + return None + + def _EmitGlobalAnnAssignLlvm(self, Node: ast.AnnAssign, Gen: "Translator.LlvmGen") -> None: + if isinstance(Node.target, ast.Name): + VarName: str = Node.target.id + Info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName) + if Info: + if Info.IsTypedef: + return + parse_result = ParseListAnnotation(Node.annotation) + if parse_result: + elem_type_node: ast.expr = parse_result.elem_type_node + ElemType, ElemTypeInfo = self.ResolveListElementType( + elem_type_node, Gen, + check_func_ptr=True, void_fallback_width=32, fallback_to_cint=True, + ) + if parse_result.is_pointer: + # 单参数 list[type] → 指针 + VarType: ir.Type = ir.PointerType(ElemType) + if VarName not in Gen.variables and VarName not in Gen.module.globals: + GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) + GlobalVar.initializer = ir.Constant(VarType, None) + Gen.variables[VarName] = GlobalVar + if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: + Gen.global_struct_class[VarName] = elem_type_node.id + return + count_node: ast.expr | None = parse_result.count_node + ArrayCount: int = self.ParseArrayCount(count_node, Gen, Node.value, mode='global') + VarType = ir.ArrayType(ElemType, ArrayCount) + if VarName not in Gen.variables and VarName not in Gen.module.globals: + GlobalVar = ir.GlobalVariable(Gen.module, VarType, name=VarName) + if isinstance(ElemType, ir.IdentifiedStructType): + GlobalVar.linkage = 'common' + elif Node.value and isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str): + str_val: str = Node.value.value + '\x00' + str_bytes: bytearray = bytearray(str_val, 'utf-8') + if len(str_bytes) < ArrayCount: + str_bytes.extend(b'\x00' * (ArrayCount - len(str_bytes))) + try: + GlobalVar.initializer = ir.Constant(VarType, str_bytes[:ArrayCount]) + except Exception: # 回退:初始化常量失败时用零值 + GlobalVar.initializer = Gen._zero_value_for_type(VarType) + else: + InitConstants: list[ir.Constant] | None = self.Trans._BuildArrayInitConstants(Node.value, ElemType, elem_type_node, ArrayCount, Gen, byte_order=ElemTypeInfo.ByteOrder if ElemTypeInfo else '') + if InitConstants: + GlobalVar.initializer = ir.Constant(VarType, InitConstants) + elif ArrayCount > 256: + GlobalVar.linkage = 'common' + else: + if self._contains_identified_struct(VarType): + GlobalVar.linkage = 'common' + else: + GlobalVar.initializer = ir.Constant(VarType, [ir.Constant(ElemType, ir.Undefined)] * ArrayCount) + Gen.variables[VarName] = GlobalVar + if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: + Gen.global_struct_class[VarName] = elem_type_node.id + return + if isinstance(Node.annotation, ast.Name) and Node.annotation.id in Gen.structs: + StructName: str = Node.annotation.id + VarType: ir.Type = Gen.structs[StructName] + if VarName not in Gen.variables and VarName not in Gen.module.globals: + GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) + if Node.value and isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name) and Node.value.func.id == StructName: + const: ir.Constant | None = self.Trans.ClassHandler._BuildStructConstant(Node.value, StructName, Gen) + if const: + GlobalVar.initializer = const + else: + GlobalVar.initializer = ir.Constant(VarType, None) + else: + GlobalVar.initializer = ir.Constant(VarType, None) + Gen.variables[VarName] = GlobalVar + Gen.global_struct_class[VarName] = StructName + return + TypeInfo: CTypeInfo | None = CTypeInfo.FromNode(Node.annotation, self.Trans.SymbolTable) + IsCDefine: bool = False + if TypeInfo and TypeInfo.BaseType: + if isinstance(TypeInfo.BaseType, t._CTypedef): + return + if isinstance(TypeInfo.BaseType, t.CDefine): + IsCDefine = True + if not IsCDefine and self._IsTypedefAnnotation(Node.annotation): + IsCDefine = True + TTypeInfo: CTypeInfo | None = self.Trans.TypeMergeHandler.GetCTypeInfo(Node.annotation) + if TTypeInfo: + TTypeInfo.IsTypedef = True + TTypeInfo.Name = VarName + self.Trans.SymbolTable.insert(VarName, TTypeInfo) + if IsCDefine: + if Node.value: + define_constants: dict[str, int | float] = vars(Gen).setdefault('_define_constants', {}) + try: + const_value: int | float | None = self._eval_const_expr(Node.value, Gen) + if const_value is not None: + define_constants[VarName] = const_value + except Exception as _e: + if _config_mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + return + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + VarType: ir.Type = Gen._ctype_to_llvm(TypeInfo) + if isinstance(VarType, ir.VoidType): + VarType = ir.IntType(32) + # 记录模块级注解类型:供函数内 global 变量的 += (HandlesAugAssign)参考, + # 避免用 RHS 字面量类型(i32)误建 i32 全局导致 i64/i32 类型不匹配。 + if not hasattr(Gen, '_module_ann_types'): + Gen._module_ann_types = {} + Gen._module_ann_types[VarName] = VarType + if VarName in Gen.variables or VarName in Gen.module.globals: + # 时序修复:第一遍创建全局时类未处理(SymbolTable 无枚举成员), + # initializer 回退为 0。第二遍类已处理,尝试用解析出的枚举值更新 initializer。 + if VarName in Gen.module.globals and Node.value: + existing: Any = Gen.module.globals[VarName] + if isinstance(existing, ir.GlobalVariable) and isinstance(VarType, ir.IntType): + new_init: ir.Constant | None = self._eval_global_const(Node.value, VarType, Gen) + if new_init is not None: + existing.initializer = new_init + return + if isinstance(VarType, (ir.IdentifiedStructType, ir.LiteralStructType)): + GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) + GlobalVar.initializer = ir.Constant(VarType, None) + Gen.variables[VarName] = GlobalVar + if TypeInfo and TypeInfo.IsStruct and TypeInfo.Name: + Gen.global_struct_class[VarName] = TypeInfo.Name + return + GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) + # 全局变量指针元素标志:bytes|t.CPtr 或 str|t.CPtr 注解的变量, + # 使 var[index] 使用 8 字节指针步长(而非 1 字节字符步长) + if isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr): + if AnnotationContainsName(Node.annotation, 'str') or AnnotationContainsName(Node.annotation, 'bytes'): + Gen.global_var_ptr_element[VarName] = True + if Node.value: + if isinstance(Node.value, ast.Constant) and isinstance(Node.value.value, str) and isinstance(VarType, ir.PointerType): + str_val: str = Node.value.value + '\x00' + str_bytes: bytes = str_val.encode('utf-8') + arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes)) + str_gv_name: str = VarName + '_str' + str_gv: ir.GlobalVariable + if str_gv_name not in Gen.module.globals: + str_gv = ir.GlobalVariable(Gen.module, arr_type, name=str_gv_name) + str_gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) + str_gv.linkage = 'internal' + else: + str_gv = Gen.module.globals[str_gv_name] + ptr_type: ir.PointerType = ir.PointerType(ir.IntType(8)) + ptr_gv: ir.GlobalVariable + if VarName not in Gen.module.globals: + ptr_gv = ir.GlobalVariable(Gen.module, ptr_type, name=VarName) + ptr_gv.initializer = ir.Constant(ptr_type, str_gv) + ptr_gv.linkage = 'internal' + else: + ptr_gv = Gen.module.globals[VarName] + Gen.variables[VarName] = ptr_gv + elif isinstance(VarType, ir.PointerType) and isinstance(VarType.pointee, ir.FunctionType) and isinstance(Node.value, ast.Name): + # 函数指针赋值:f3: t.Callable[[int], int] = f + RefName: str = Node.value.id + SymInfo: Any = self.Trans.SymbolTable.lookup(RefName) + if SymInfo and (SymInfo.IsFunction or SymInfo.IsFuncPtr): + MangledName: str = Gen._mangle_func_name(RefName) + if MangledName in Gen.module.globals: + func: Any = Gen.module.globals[MangledName] + if isinstance(func, ir.Function): + GlobalVar.initializer = func + else: + if isinstance(VarType, ir.ArrayType) and isinstance(Node.value, (ast.List, ast.Set)): + InitConstants: list[ir.Constant] | None = self.Trans._BuildMultiDimArrayInitConstants(Node.value, VarType, Gen) + if InitConstants: + GlobalVar.initializer = ir.Constant(VarType, InitConstants) + else: + if self._contains_identified_struct(VarType): + GlobalVar.linkage = 'common' + else: + zv: ir.Constant | None = Gen._zero_value_for_type(VarType) + if zv: + GlobalVar.initializer = zv + else: + GlobalVar.linkage = 'common' + else: + init_val: ir.Constant | None = self._eval_global_const(Node.value, VarType, Gen) + if init_val: + GlobalVar.initializer = init_val + elif isinstance(VarType, ir.BaseStructType) or (isinstance(Node.value, ast.Constant) and Node.value.value is None): + # None 初值全局(如各 Handles 模块的 _g_gen: t.CVoid|t.CPtr = None): + # 多模块同名定义用 common linkage 让链接器合并(避免 + # ld.lld duplicate symbol)。common 无 initializer,合并为零值, + # 符合 None(=null) 语义。 + GlobalVar.linkage = 'common' + else: + GlobalVar.initializer = Gen._zero_value_for_type(VarType) + else: + if isinstance(VarType, ir.BaseStructType) or self._contains_identified_struct(VarType): + GlobalVar.linkage = 'common' + else: + GlobalVar.initializer = Gen._zero_value_for_type(VarType) + Gen.variables[VarName] = GlobalVar + + def _eval_global_const(self, value_node: ast.expr, var_type: ir.Type, Gen: "Translator.LlvmGen") -> ir.Constant | None: + if isinstance(value_node, ast.Constant): + if isinstance(value_node.value, bool): + if isinstance(var_type, ir.IntType): + return ir.Constant(var_type, int(value_node.value)) + elif isinstance(value_node.value, int): + if isinstance(var_type, ir.IntType): + return ir.Constant(var_type, value_node.value) + elif isinstance(var_type, (ir.FloatType, ir.DoubleType)): + return ir.Constant(var_type, float(value_node.value)) + elif isinstance(value_node.value, float): + if isinstance(var_type, (ir.FloatType, ir.DoubleType)): + return ir.Constant(var_type, value_node.value) + elif isinstance(var_type, ir.IntType): + return ir.Constant(var_type, int(value_node.value)) + elif isinstance(value_node.value, str): + return None + # Handle type constructor calls like t.CDouble(1e-9), t.CFloat(3.14), t.CInt(42) + if isinstance(value_node, ast.Call): + inner_val: ir.Constant | None = self._eval_type_ctor_const(value_node, var_type, Gen) + if inner_val is not None: + return inner_val + if isinstance(value_node, ast.UnaryOp) and isinstance(value_node.op, ast.USub): + inner: ir.Constant | None = self._eval_global_const(value_node.operand, var_type, Gen) + if inner: + return ir.Constant(var_type, -inner.constant) + # Handle enum member references like ASTVType.Module (ast.Attribute) + if isinstance(value_node, ast.Attribute): + attr_name: str = value_node.attr + # 优先用带前缀的 key 查找(避免短名被同名函数/变量覆盖) + if isinstance(value_node.value, ast.Name): + FullKey2: str = f"{value_node.value.id}.{attr_name}" + FullInfo: Any = self.Trans.SymbolTable.lookup(FullKey2) + if FullInfo and FullInfo.IsEnumMember and isinstance(FullInfo.value, int): + if isinstance(var_type, ir.IntType): + return ir.Constant(var_type, FullInfo.value) + SymInfo: Any = self.Trans.SymbolTable.lookup(attr_name) + if SymInfo: + if SymInfo.IsEnumMember and isinstance(SymInfo.value, int): + if isinstance(var_type, ir.IntType): + return ir.Constant(var_type, SymInfo.value) + return None + + def _eval_type_ctor_const(self, call_node: ast.Call, var_type: ir.Type, Gen: "Translator.LlvmGen") -> ir.Constant | None: + """Try to evaluate t.CDouble(val), t.CFloat(val), t.CInt(val) etc. as a compile-time constant.""" + if not isinstance(call_node.func, ast.Attribute): + return None + if not isinstance(call_node.func.value, ast.Name): + return None + if call_node.func.value.id != 't': + return None + if not call_node.args or len(call_node.args) != 1: + return None + arg: ast.expr = call_node.args[0] + # Recursively evaluate the argument as a constant + arg_val: ir.Constant | None = self._eval_global_const(arg, var_type, Gen) + if arg_val is not None: + return arg_val + return None + + def _store_bitfield_member(self, struct_ptr: ir.Value, ClassName: str, field_name: str, Value: ir.Value) -> bool: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + bitfield_offsets: dict[str, int] = Gen.class_member_bitoffsets.get(ClassName, {}) + bitfield_widths: dict[str, int] = Gen.class_member_bitfields.get(ClassName, {}) + if field_name not in bitfield_offsets: + return False + bit_offset: int = bitfield_offsets[field_name] + bit_width: int = bitfield_widths.get(field_name, 0) + if bit_width == 0: + return False + struct_type: ir.Type | None = Gen.structs.get(ClassName) + if struct_type is None or struct_type.elements is None or len(struct_type.elements) == 0: + return False + storage_type: ir.Type = struct_type.elements[0] + member_ptr: ir.Value = Gen.builder.gep(struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{field_name}_storage_ptr") + old_val: ir.Value = Gen._load(member_ptr, name=f"{field_name}_old_storage") + mask: int = (1 << bit_width) - 1 + shifted_mask: int = mask << bit_offset + inverted_mask: ir.Constant = ir.Constant(storage_type, ~shifted_mask & ((1 << storage_type.width) - 1)) + cleared: ir.Value = Gen.builder.and_(old_val, inverted_mask, name=f"{field_name}_cleared") + if isinstance(Value.type, ir.IntType) and Value.type.width < storage_type.width: + if getattr(Value.type, 'is_signed', False): + Value = Gen.builder.sext(Value, storage_type, name=f"{field_name}_sext_store") + else: + Value = Gen.builder.zext(Value, storage_type, name=f"{field_name}_zext_store") + elif Value.type.width != storage_type.width: + Value = Gen.builder.trunc(Value, storage_type, name=f"{field_name}_trunc_store") if Value.type.width > storage_type.width else Gen.builder.zext(Value, storage_type, name=f"{field_name}_zext_store") + shifted_value: ir.Value = Gen.builder.shl(Value, ir.Constant(storage_type, bit_offset), name=f"{field_name}_shift_store") + masked_value: ir.Value = Gen.builder.and_(shifted_value, ir.Constant(storage_type, shifted_mask), name=f"{field_name}_mask_store") + new_val: ir.Value = Gen.builder.or_(cleared, masked_value, name=f"{field_name}_new_storage") + Gen._store(new_val, member_ptr) + return True + + def _CheckEnumMemberAssignment(self, node: ast.expr) -> str | None: + def _get_attr_path(n: ast.expr) -> str | None: + if isinstance(n, ast.Name): + return n.id + elif isinstance(n, ast.Attribute): + return f"{_get_attr_path(n.value)}.{n.attr}" + return None + attr_path: str | None = _get_attr_path(node) + if not attr_path: + return None + parts: list[str] = attr_path.split('.') + if len(parts) >= 2: + enum_class_name: str = parts[-2] + member_name: str = parts[-1] + qualified_name: str = f"{enum_class_name}.{member_name}" + info: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(qualified_name) + if info: + if info.IsEnumMember and info.EnumName: + return info.EnumName + under_name: str = f"{enum_class_name}_{member_name}" + if self.Trans.SymbolTable.has(under_name): + info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable[under_name] + if info.IsEnumMember and info.EnumName: + return info.EnumName + for key in self.Trans.SymbolTable: + if key == member_name: + info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable[key] + if info.IsEnumMember and info.EnumName and info.EnumName == enum_class_name: + return enum_class_name + return None + + def _IsTypedefAnnotation(self, annotation: ast.expr) -> bool: + if isinstance(annotation, ast.Attribute): + if annotation.attr in ('CTypedef', 'CDefine'): + return True + if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + return self._IsTypedefAnnotation(annotation.left) or self._IsTypedefAnnotation(annotation.right) + if isinstance(annotation, ast.Subscript): + return self._IsTypedefAnnotation(annotation.value) + return False + + def _EmitGlobalAssignLlvm(self, Node: ast.Assign, Gen: "Translator.LlvmGen") -> None: + if len(Node.targets) == 1 and isinstance(Node.targets[0], ast.Name): + VarName: str = Node.targets[0].id + if VarName in Gen.variables or VarName in Gen.module.globals: + return + if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.Name): + FuncName: str = Node.value.func.id + if FuncName in Gen.structs: + IsUnion: bool = False + TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(FuncName) + if TypeInfo: + if TypeInfo.IsUnion: + IsUnion = True + if IsUnion: + StructType: ir.Type = Gen.structs[FuncName] + StructPtrType: ir.PointerType = ir.PointerType(StructType) + GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, StructPtrType, name=VarName) + GlobalVar.initializer = ir.Constant(StructPtrType, None) + Gen.variables[VarName] = GlobalVar + Gen.global_struct_class[VarName] = FuncName + return + StructName: str = FuncName + VarType: ir.Type = Gen.structs[StructName] + GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, VarType, name=VarName) + const: ir.Constant | None = self.Trans.ClassHandler._BuildStructConstant(Node.value, StructName, Gen) + if const: + GlobalVar.initializer = const + else: + GlobalVar.linkage = 'common' + Gen.variables[VarName] = GlobalVar + Gen.global_struct_class[VarName] = StructName + return + GlobalVar: ir.GlobalVariable = ir.GlobalVariable(Gen.module, ir.IntType(32), name=VarName) + init_val: ir.Constant | None = self._eval_global_const(Node.value, ir.IntType(32), Gen) + GlobalVar.initializer = init_val if init_val else ir.Constant(ir.IntType(32), 0) + Gen.variables[VarName] = GlobalVar + + def _eval_const_expr(self, node: ast.expr, Gen: "Translator.LlvmGen") -> int | float | None: + """计算常量表达式的值(委托到 ConstEvaluator)""" + ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans) + return ConstEvaluator.eval_full(node, ctx) + + def _eval_global_count(self, node: ast.expr, Gen: "Translator.LlvmGen") -> int | None: + val: int | float | None = self._eval_const_expr(node, Gen) + if val is not None: + if isinstance(val, float): + return int(val) + if isinstance(val, int): + return val return None \ No newline at end of file diff --git a/lib/core/Handles/HandlesAugAssign.py b/lib/core/Handles/HandlesAugAssign.py index 9ed6030..588088e 100644 --- a/lib/core/Handles/HandlesAugAssign.py +++ b/lib/core/Handles/HandlesAugAssign.py @@ -1,243 +1,243 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -import ast -import sys -import llvmlite.ir as ir -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.VLogger import get_logger as _vlog -from lib.core.Handles.HandlesBase import BaseHandle - - -class AugAssignHandle(BaseHandle): - _AUGOP_MAP: dict[type, str] = { - ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__', - ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__', - } - _AUGOP_FALLBACK: dict[type, str] = { - ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__', - ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__', - } - - def _resolve_global_var_type(self, Gen: "Translator.LlvmGen", VarName: str, fallback: ir.Type) -> ir.Type: - """解析 global 变量的 LLVM 类型:优先用模块级 AnnAssign 的注解类型。 - - 问题场景:函数内 `_g_alloc_count += 1`(global 声明),模块级注解为 - `_g_alloc_count: t.CSizeT`(i64)。若不查模块级注解类型,此处会用 RHS 字面量 - 类型(i32)自动建 i32 全局,与模块内其他读取/写入(i64)类型不匹配, - 产生 "Operands must be the same type, got (i64, i32)" 类错误。 - 模块级 AnnAssign 已通过 _EmitGlobalAnnAssignLlvm 创建 LLVM 全局, - 但注解无初始值(如 `_g_alloc_max: t.CSizeT = 0`)时 initializer 为空、 - Gen.module.globals 中无该符号,故需在此兜底解析注解类型。 - """ - module_ann: dict = getattr(Gen, '_module_ann_types', None) - if module_ann and VarName in module_ann: - ann_type: ir.Type = module_ann[VarName] - if ann_type is not None: - return ann_type - if isinstance(fallback, ir.IntType): - return fallback - return ir.IntType(64) - - def _is_aug_unsigned(self, Node: ast.AugAssign, OldVal: ir.Value | None, Value: ir.Value) -> bool: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if isinstance(Node.target, ast.Name): - if Gen._check_node_unsigned(Node.target): - return True - elif isinstance(Node.target, ast.Attribute): - if Gen._check_node_unsigned(Node.target): - return True - elif isinstance(Node.target, ast.Subscript): - if Gen._check_node_unsigned(Node.target): - return True - if Node.value is not None and Gen._check_node_unsigned(Node.value): - return True - return False - - def _HandleAugAssignLlvm(self, Node: ast.AugAssign) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if isinstance(Node.target, ast.Name): - VarName: str = Node.target.id - if (VarName not in Gen.variables - and VarName not in Gen.global_vars - and VarName not in Gen._reg_values - and VarName not in Gen._direct_values): - src_info: str = Gen._get_node_info() - _vlog().error(f"变量 '{VarName}' 未声明,不能用于增量赋值(需用 global 声明或先声明局部变量){src_info}") - sys.exit(1) - if VarName in Gen.var_const_flags: - src_info: str = Gen._get_node_info() - _vlog().error(f"不能对 const 变量 '{VarName}' 增量赋值{src_info}") - sys.exit(1) - ClassName: str | None = Gen.var_struct_class.get(VarName) - iop_name: str | None = self._AUGOP_MAP.get(type(Node.op)) - if ClassName and iop_name: - iFuncName: str = f'{ClassName}.{iop_name}' - FuncName: str = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}' - if iFuncName in Gen.functions or FuncName in Gen.functions: - OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load())) - Value: ir.Value | None = self.HandleExprLlvm(Node.value) - if OldVal and Value: - result: ir.Value | None - if iFuncName in Gen.functions: - result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, iop_name, OldVal, Gen, Value) - else: - result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, self._AUGOP_FALLBACK[type(Node.op)], OldVal, Gen, Value) - if result is not None: - if VarName in Gen.variables and Gen.variables[VarName] is not None: - VarPtr: ir.Value = Gen.variables[VarName] - if VarPtr.type.pointee == result.type: - Gen._store(result, VarPtr) - elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(result.type, ir.PointerType): - CastedVal: ir.Value = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}") - Gen._store(CastedVal, VarPtr) - else: - NewVar: ir.AllocaInstr = Gen._allocaEntry(result.type, name=VarName) - Gen._store(result, NewVar) - Gen.variables[VarName] = NewVar - else: - Gen._reg_values[VarName] = result - Gen.variables[VarName] = None - return - Value: ir.Value | None = self.HandleExprLlvm(Node.value) - if not Value: - return - is_unsigned: bool = self._is_aug_unsigned(Node, None, Value) - if isinstance(Node.target, ast.Name): - VarName: str = Node.target.id - Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op) - if VarName in Gen.global_vars: - # 治本修复:global 声明的变量若未被模块级 AnnAssign 创建为 LLVM 全局 - # (注解无初始值的全局变量),此处自动创建零初始化全局变量 - GVar: ir.GlobalVariable - if VarName not in Gen.module.globals: - _gv_type: ir.Type = self._resolve_global_var_type(Gen, VarName, Value.type) - GVar = ir.GlobalVariable(Gen.module, _gv_type, name=VarName) - GVar.initializer = ir.Constant(_gv_type, 0) - else: - GVar = Gen.module.globals[VarName] - Gen.variables[VarName] = GVar - OldVal: ir.Value = Gen._load(GVar, name=VarName) - NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - Gen._store(NewVal, GVar) - return - if VarName in Gen._reg_values: - OldVal: ir.Value = Gen._reg_values[VarName] - var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) - Gen._store(OldVal, var) - Gen.variables[VarName] = var - del Gen._reg_values[VarName] - if VarName in Gen._direct_values: - OldVal: ir.Value = Gen._direct_values.pop(VarName) - var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) - Gen._store(OldVal, var) - Gen.variables[VarName] = var - if Gen.builder.block.is_terminated: - return - if VarName in Gen.variables and Gen.variables[VarName] is not None: - OldVal: ir.Value = Gen._load(Gen.variables[VarName], name=VarName) - store_ptr: ir.Value = Gen.variables[VarName] - if isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): - if Value.type.width != 64: - Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset") - NewVal: ir.Value - if Op == '-' or Op == '+': - if Op == '-': - NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset") - NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub") - else: - NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add") - else: - ptr_val: ir.Value = OldVal - OldVal = Gen._load(OldVal, name="deref_ptr_for_op") - orig_type: ir.Type = OldVal.type - if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): - if OldVal.type.width < Value.type.width: - OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left") - elif OldVal.type.width > Value.type.width: - Value = Gen.builder.zext(Value, OldVal.type, name="zext_right") - NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - if isinstance(NewVal.type, ir.IntType) and isinstance(orig_type, ir.IntType): - if NewVal.type.width > orig_type.width: - NewVal = Gen.builder.trunc(NewVal, orig_type, name="trunc_result") - store_ptr = ptr_val - else: - if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): - if OldVal.type.width < Value.type.width: - OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left") - elif OldVal.type.width > Value.type.width: - Value = Gen.builder.zext(Value, OldVal.type, name="zext_right") - elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): - if Op in ('+', '-'): - if Value.type.width < 64: - Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_aug") - NewVal: ir.Value - if Op == '-': - NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_aug") - NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_aug") - else: - NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_aug") - Gen._store(NewVal, store_ptr) - return - NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - if isinstance(store_ptr.type, ir.PointerType): - TargetType: ir.Type = store_ptr.type.pointee - if NewVal.type != TargetType: - Coerced: ir.Value | None = Gen._coerce_value(NewVal, TargetType) - if Coerced is not None: - NewVal = Coerced - Gen._store(NewVal, store_ptr) - elif VarName == 'pos': - var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) - Gen.variables[VarName] = var - OldVal: ir.Value = Gen._load(var, name=VarName) - NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - Gen._store(NewVal, var) - elif isinstance(Node.target, ast.Attribute): - AttrName: str = Node.target.attr - OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.target) - if OldVal: - def _deref_if_ptr(val: ir.Value) -> ir.Value: - if isinstance(val.type, ir.PointerType): - pointee: ir.Type = val.type.pointee - if isinstance(pointee, (ir.IntType, ir.FloatType, ir.DoubleType)): - return Gen._load(val, name="deref_aug") - return val - OldVal = _deref_if_ptr(OldVal) - Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op) - if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): - if OldVal.type.width < Value.type.width: - OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_attr") - elif OldVal.type.width > Value.type.width: - Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_attr") - NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - self.Trans.AssignHandler._HandleAttributeStoreLlvm(Node.target, NewVal) - elif isinstance(Node.target, ast.Subscript): - SubTarget: ast.Subscript = Node.target - ElemPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget) - if ElemPtr: - if isinstance(ElemPtr.type, ir.PointerType): - OldVal: ir.Value = Gen._load(ElemPtr, name="old_subscript_val") - Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op) - if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): - if OldVal.type.width < Value.type.width: - OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_sub") - elif OldVal.type.width > Value.type.width: - Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_sub") - elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): - if Op in ('+', '-'): - if Value.type.width < 64: - Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_sub") - NewVal: ir.Value - if Op == '-': - NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_sub") - NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_sub") - else: - NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_sub") - Gen._store(NewVal, ElemPtr) - return - NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) - if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType): - if NewVal.type.width > ElemPtr.type.pointee.width: - NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result") +from __future__ import annotations +from typing import TYPE_CHECKING +import vast as ast +import sys +import llvmlite.ir as ir +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.VLogger import get_logger as _vlog +from lib.core.Handles.HandlesBase import BaseHandle + + +class AugAssignHandle(BaseHandle): + _AUGOP_MAP: dict[type, str] = { + ast.Add: '__iadd__', ast.Sub: '__isub__', ast.Mult: '__imul__', + ast.Div: '__itruediv__', ast.FloorDiv: '__ifloordiv__', ast.Mod: '__imod__', ast.Pow: '__ipow__', + } + _AUGOP_FALLBACK: dict[type, str] = { + ast.Add: '__add__', ast.Sub: '__sub__', ast.Mult: '__mul__', + ast.Div: '__truediv__', ast.FloorDiv: '__floordiv__', ast.Mod: '__mod__', ast.Pow: '__pow__', + } + + def _resolve_global_var_type(self, Gen: "Translator.LlvmGen", VarName: str, fallback: ir.Type) -> ir.Type: + """解析 global 变量的 LLVM 类型:优先用模块级 AnnAssign 的注解类型。 + + 问题场景:函数内 `_g_alloc_count += 1`(global 声明),模块级注解为 + `_g_alloc_count: t.CSizeT`(i64)。若不查模块级注解类型,此处会用 RHS 字面量 + 类型(i32)自动建 i32 全局,与模块内其他读取/写入(i64)类型不匹配, + 产生 "Operands must be the same type, got (i64, i32)" 类错误。 + 模块级 AnnAssign 已通过 _EmitGlobalAnnAssignLlvm 创建 LLVM 全局, + 但注解无初始值(如 `_g_alloc_max: t.CSizeT = 0`)时 initializer 为空、 + Gen.module.globals 中无该符号,故需在此兜底解析注解类型。 + """ + module_ann: dict = getattr(Gen, '_module_ann_types', None) + if module_ann and VarName in module_ann: + ann_type: ir.Type = module_ann[VarName] + if ann_type is not None: + return ann_type + if isinstance(fallback, ir.IntType): + return fallback + return ir.IntType(64) + + def _is_aug_unsigned(self, Node: ast.AugAssign, OldVal: ir.Value | None, Value: ir.Value) -> bool: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if isinstance(Node.target, ast.Name): + if Gen._check_node_unsigned(Node.target): + return True + elif isinstance(Node.target, ast.Attribute): + if Gen._check_node_unsigned(Node.target): + return True + elif isinstance(Node.target, ast.Subscript): + if Gen._check_node_unsigned(Node.target): + return True + if Node.value is not None and Gen._check_node_unsigned(Node.value): + return True + return False + + def _HandleAugAssignLlvm(self, Node: ast.AugAssign) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if isinstance(Node.target, ast.Name): + VarName: str = Node.target.id + if (VarName not in Gen.variables + and VarName not in Gen.global_vars + and VarName not in Gen._reg_values + and VarName not in Gen._direct_values): + src_info: str = Gen._get_node_info() + _vlog().error(f"变量 '{VarName}' 未声明,不能用于增量赋值(需用 global 声明或先声明局部变量){src_info}") + sys.exit(1) + if VarName in Gen.var_const_flags: + src_info: str = Gen._get_node_info() + _vlog().error(f"不能对 const 变量 '{VarName}' 增量赋值{src_info}") + sys.exit(1) + ClassName: str | None = Gen.var_struct_class.get(VarName) + iop_name: str | None = self._AUGOP_MAP.get(type(Node.op)) + if ClassName and iop_name: + iFuncName: str = f'{ClassName}.{iop_name}' + FuncName: str = f'{ClassName}.{self._AUGOP_FALLBACK.get(type(Node.op), "")}' + if iFuncName in Gen.functions or FuncName in Gen.functions: + OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(ast.Name(id=VarName, ctx=ast.Load())) + Value: ir.Value | None = self.HandleExprLlvm(Node.value) + if OldVal and Value: + result: ir.Value | None + if iFuncName in Gen.functions: + result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, iop_name, OldVal, Gen, Value) + else: + result = self.Trans.ExprHandler._try_operator_overLoad(ClassName, self._AUGOP_FALLBACK[type(Node.op)], OldVal, Gen, Value) + if result is not None: + if VarName in Gen.variables and Gen.variables[VarName] is not None: + VarPtr: ir.Value = Gen.variables[VarName] + if VarPtr.type.pointee == result.type: + Gen._store(result, VarPtr) + elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(result.type, ir.PointerType): + CastedVal: ir.Value = Gen.builder.bitcast(result, VarPtr.type.pointee, name=f"cast_{VarName}") + Gen._store(CastedVal, VarPtr) + else: + NewVar: ir.AllocaInstr = Gen._allocaEntry(result.type, name=VarName) + Gen._store(result, NewVar) + Gen.variables[VarName] = NewVar + else: + Gen._reg_values[VarName] = result + Gen.variables[VarName] = None + return + Value: ir.Value | None = self.HandleExprLlvm(Node.value) + if not Value: + return + is_unsigned: bool = self._is_aug_unsigned(Node, None, Value) + if isinstance(Node.target, ast.Name): + VarName: str = Node.target.id + Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if VarName in Gen.global_vars: + # 治本修复:global 声明的变量若未被模块级 AnnAssign 创建为 LLVM 全局 + # (注解无初始值的全局变量),此处自动创建零初始化全局变量 + GVar: ir.GlobalVariable + if VarName not in Gen.module.globals: + _gv_type: ir.Type = self._resolve_global_var_type(Gen, VarName, Value.type) + GVar = ir.GlobalVariable(Gen.module, _gv_type, name=VarName) + GVar.initializer = ir.Constant(_gv_type, 0) + else: + GVar = Gen.module.globals[VarName] + Gen.variables[VarName] = GVar + OldVal: ir.Value = Gen._load(GVar, name=VarName) + NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + Gen._store(NewVal, GVar) + return + if VarName in Gen._reg_values: + OldVal: ir.Value = Gen._reg_values[VarName] + var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.variables[VarName] = var + del Gen._reg_values[VarName] + if VarName in Gen._direct_values: + OldVal: ir.Value = Gen._direct_values.pop(VarName) + var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=VarName) + Gen._store(OldVal, var) + Gen.variables[VarName] = var + if Gen.builder.block.is_terminated: + return + if VarName in Gen.variables and Gen.variables[VarName] is not None: + OldVal: ir.Value = Gen._load(Gen.variables[VarName], name=VarName) + store_ptr: ir.Value = Gen.variables[VarName] + if isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): + if Value.type.width != 64: + Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset") + NewVal: ir.Value + if Op == '-' or Op == '+': + if Op == '-': + NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset") + NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub") + else: + NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add") + else: + ptr_val: ir.Value = OldVal + OldVal = Gen._load(OldVal, name="deref_ptr_for_op") + orig_type: ir.Type = OldVal.type + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right") + NewVal = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + if isinstance(NewVal.type, ir.IntType) and isinstance(orig_type, ir.IntType): + if NewVal.type.width > orig_type.width: + NewVal = Gen.builder.trunc(NewVal, orig_type, name="trunc_result") + store_ptr = ptr_val + else: + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right") + elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): + if Op in ('+', '-'): + if Value.type.width < 64: + Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_aug") + NewVal: ir.Value + if Op == '-': + NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_aug") + NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_aug") + else: + NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_aug") + Gen._store(NewVal, store_ptr) + return + NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + if isinstance(store_ptr.type, ir.PointerType): + TargetType: ir.Type = store_ptr.type.pointee + if NewVal.type != TargetType: + Coerced: ir.Value | None = Gen._coerce_value(NewVal, TargetType) + if Coerced is not None: + NewVal = Coerced + Gen._store(NewVal, store_ptr) + elif VarName == 'pos': + var: ir.AllocaInstr = Gen._allocaEntry(Value.type, name=VarName) + Gen.variables[VarName] = var + OldVal: ir.Value = Gen._load(var, name=VarName) + NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + Gen._store(NewVal, var) + elif isinstance(Node.target, ast.Attribute): + AttrName: str = Node.target.attr + OldVal: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.target) + if OldVal: + def _deref_if_ptr(val: ir.Value) -> ir.Value: + if isinstance(val.type, ir.PointerType): + pointee: ir.Type = val.type.pointee + if isinstance(pointee, (ir.IntType, ir.FloatType, ir.DoubleType)): + return Gen._load(val, name="deref_aug") + return val + OldVal = _deref_if_ptr(OldVal) + Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_attr") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_attr") + NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + self.Trans.AssignHandler._HandleAttributeStoreLlvm(Node.target, NewVal) + elif isinstance(Node.target, ast.Subscript): + SubTarget: ast.Subscript = Node.target + ElemPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(SubTarget) + if ElemPtr: + if isinstance(ElemPtr.type, ir.PointerType): + OldVal: ir.Value = Gen._load(ElemPtr, name="old_subscript_val") + Op: str = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if isinstance(OldVal.type, ir.IntType) and isinstance(Value.type, ir.IntType): + if OldVal.type.width < Value.type.width: + OldVal = Gen.builder.zext(OldVal, Value.type, name="zext_left_sub") + elif OldVal.type.width > Value.type.width: + Value = Gen.builder.zext(Value, OldVal.type, name="zext_right_sub") + elif isinstance(OldVal.type, ir.PointerType) and isinstance(Value.type, ir.IntType): + if Op in ('+', '-'): + if Value.type.width < 64: + Value = Gen.builder.zext(Value, ir.IntType(64), name="zext_ptr_offset_sub") + NewVal: ir.Value + if Op == '-': + NegValue: ir.Value = Gen.builder.neg(Value, name="neg_ptr_offset_sub") + NewVal = Gen.builder.gep(OldVal, [NegValue], name="ptr_sub_sub") + else: + NewVal = Gen.builder.gep(OldVal, [Value], name="ptr_add_sub") + Gen._store(NewVal, ElemPtr) + return + NewVal: ir.Value = Gen.emit_binary_op(Op, OldVal, Value, is_unsigned=is_unsigned) + if isinstance(NewVal.type, ir.IntType) and isinstance(ElemPtr.type.pointee, ir.IntType): + if NewVal.type.width > ElemPtr.type.pointee.width: + NewVal = Gen.builder.trunc(NewVal, ElemPtr.type.pointee, name="trunc_sub_result") Gen._store(NewVal, ElemPtr) \ No newline at end of file diff --git a/lib/core/Handles/HandlesBase.py b/lib/core/Handles/HandlesBase.py index ae55c22..60d2e95 100644 --- a/lib/core/Handles/HandlesBase.py +++ b/lib/core/Handles/HandlesBase.py @@ -1,842 +1,842 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, List, Any -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator - -import ast -from enum import IntFlag, auto - -from llvmlite import ir as _ir - -from lib.constants import config as _config -from lib.includes import t -from lib.includes.t import CTypeRegistry -from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES -from lib.core.VLogger import get_logger as _vlog - - -EXCEPTION_CODE_MAP: dict[str, int] = { - 'ValueError': 1, 'TypeError': 2, 'RuntimeError': 3, - 'ZeroDivisionError': 4, 'IndexError': 5, 'KeyError': 6, - 'IOError': 7, 'OSError': 8, 'AssertionError': 9, 'Exception': 99, -} - - -class FuncMeta(IntFlag): - NONE = 0 - STATIC_METHOD = auto() - PROPERTY_GETTER = auto() - PROPERTY_SETTER = auto() - PROPERTY_DELETER = auto() - CLASS_METHOD = auto() - ABSTRACT = auto() - - -class _Delegated: - """CTypeInfo 旧字段名委托描述符 — 静态委托到 _ts/_sm 的字段 - - 替代旧的 FIELD_ROUTES + __setattr__/__getattr__ 动态路由: - 描述符在类创建时绑定,访问时直接走 __get__/__set__, - 无 dict 查找和字符串比较的运行时开销。 - """ - __slots__ = ('_target_attr', '_field_name') - - def __init__(self, target_attr: str, field_name: str) -> None: - self._target_attr: str = target_attr # '_ts' or '_sm' - self._field_name: str = field_name - - def __get__(self, obj: Any, objtype: type | None = None) -> Any: - if obj is None: - return self - target: Any = object.__getattribute__(obj, self._target_attr) - return getattr(target, self._field_name) - - def __set__(self, obj: Any, value: Any) -> None: - target: Any = object.__getattribute__(obj, self._target_attr) - setattr(target, self._field_name, value) - - -class CTypeInfo: - """ - C 类型信息对象 - 统一符号表条目和类型计算 - - 设计原则: - - BaseType 是 CType 实例(来自 t 模块),永远不使用硬编码字符串 - - 描述符分为两种: - - VarConst/VarVolatile: 变量本身(指针)的限定符,如 int * const - - DataConst/DataVolatile: 指向数据的限定符,如 const int * - - 属性(类型计算): - - BaseType: t.CType - 基础类型实例 (如 t.CInt(), t.CVoid()) - - PtrCount: int - 指针层数 - - VarConst: bool - 变量本身(指针)是否 const,如 int * const - - VarVolatile: bool - 变量本身(指针)是否 volatile - - DataConst: bool - 指向的数据是否 const,如 const int * - - DataVolatile: bool - 指向的数据是否 volatile - - ArrayDims: List[str] - 数组维度 - - Storage: t.CType - 存储类 (static, extern 等) - - IsFuncPtr: bool - 是否函数指针 - - FuncPtrParams: List[Tuple[str, CTypeInfo]] - 函数指针参数列表,每个元素是 (参数名, 参数类型) - - FuncPtrReturn: CTypeInfo - 函数指针返回类型 - - IsBitField: bool - 是否位域 - - BitWidth: int - 位域宽度 - - IsTypedef/IsStruct/IsEnum/IsUnion: bool - 类型种类 - - 属性(符号表元数据): - - Name: str - 名称(struct/enum/union/typedef 名) - - Members: Dict[str, CTypeInfo] - 成员字典(用于 struct/union) - - OriginalType: str - typedef 的原始类型 - - DeclaredType: str - 声明类型 - - CreturnTypes: list - C 返回类型列表 - - Lineno: int - 定义行号 - - IsAnonymous: bool - 是否匿名类型 - - IsCpythonObject: bool - 是否 CPython 对象 - - IsEnumMember: bool - 是否枚举成员 - """ - - def __init__(self) -> None: - object.__setattr__(self, '_ts', TypeSpec()) - sm: SymbolMeta = SymbolMeta() - sm.meta_list = FuncMeta.NONE - object.__setattr__(self, '_sm', sm) - - # --- 新公共 API:供新代码直接访问 TypeSpec / SymbolMeta / SymbolKind --- - @property - def ts(self) -> TypeSpec: - """TypeSpec — 纯类型描述(只读)""" - return self._ts - - @property - def sm(self) -> SymbolMeta: - """SymbolMeta — 符号表元数据(只读)""" - return self._sm - - @property - def kind(self) -> 'SymbolKind': - """SymbolKind — 符号类型种类枚举""" - return self._sm.kind - - # 注:旧字段名(PtrCount/IsStruct/Name 等)的委托通过 _Delegated 描述符实现, - # 在模块末尾从 FIELD_ROUTES 静态绑定,无需 __setattr__/__getattr__ 动态路由 - - - - @property - def BaseType(self) -> t.CType | tuple | None: - return self._ts._base_type - - @BaseType.setter - def BaseType(self, value: t.CType | type | tuple | List | None) -> None: - """设置 BaseType,接受以下类型: - - - None: 清空 - - t.CType 实例: 单个类型,自动设置 IsStruct/IsEnum/IsUnion 标志 - - type (CType 子类): 如 t.CStruct,自动实例化 - - tuple/list of t.CType: 多个组合类型 - """ - ts: TypeSpec = self._ts - sm: SymbolMeta = self._sm - - if value is None: - ts._base_type = None - sm.is_struct = False - sm.is_enum = False - sm.is_union = False - sm.is_renum = False - return - - if isinstance(value, (tuple, list)): - ts._base_type = tuple(value) - for v in value: - if isinstance(v, t.CStruct): - sm.is_struct = True - elif isinstance(v, t.CEnum): - sm.is_enum = True - elif isinstance(v, t.CUnion): - sm.is_union = True - elif isinstance(v, t.REnum): - sm.is_renum = True - sm.is_enum = True - return - - if isinstance(value, type) and issubclass(value, t.CType): - ts._base_type = value() - return - - if isinstance(value, t.CType): - ts._base_type = value - if isinstance(value, t.CStruct): - sm.is_struct = True - sm.is_enum = False - sm.is_union = False - sm.is_renum = False - elif isinstance(value, t.REnum): - sm.is_renum = True - sm.is_enum = True - sm.is_struct = False - sm.is_union = False - elif isinstance(value, t.CEnum): - sm.is_enum = True - sm.is_struct = False - sm.is_union = False - sm.is_renum = False - elif isinstance(value, t.CUnion): - sm.is_union = True - sm.is_struct = False - sm.is_enum = False - sm.is_renum = False - return - - raise TypeError(f"BaseType must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}") - - @property - def TypeCls(self) -> type | None: - """获取 CType 类(从 BaseType 推断)""" - bt: t.CType | tuple | None = self._ts._base_type - if bt: - return type(bt) - sm: SymbolMeta = self._sm - if sm.is_struct: - return t.CStruct - if sm.is_enum: - return t.CEnum - if sm.is_union: - return t.CUnion - if sm.is_typedef: - return t._CTypedef - return None - - @property - def IsPtr(self) -> bool: - return self._ts.ptr_count > 0 - - @property - def IsVoid(self) -> bool: - return isinstance(self._ts._base_type, t.CVoid) - - @property - def IsStr(self) -> bool: - return isinstance(self._ts._base_type, t.CChar) and self._ts.ptr_count > 0 - - @property - def IsInt(self) -> bool: - bt: t.CType | tuple | None = self._ts._base_type - return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is not None and bt.IsSigned is True and not isinstance(bt, t.CVoid) - - @property - def IsUInt(self) -> bool: - bt: t.CType | tuple | None = self._ts._base_type - return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is False - - @property - def IsFloat(self) -> bool: - bt: t.CType | tuple | None = self._ts._base_type - return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is None and getattr(bt, 'Size', 0) in (32, 64, 128) and not isinstance(bt, t.CVoid) - - def ToString(self) -> str: - ts: TypeSpec = self._ts - sm: SymbolMeta = self._sm - bt: t.CType | tuple | None = ts._base_type - - if ts.is_func_ptr: - return 'Callable' - parts: list[str] = [] - - if ts.storage and not isinstance(ts.storage, t.CExport): - parts.append(type(ts.storage).__name__) - - if ts.data_const or ts.data_volatile: - qualifiers: list[str] = [] - if ts.data_const: - qualifiers.append("const") - if ts.data_volatile: - qualifiers.append("volatile") - parts.append("_".join(qualifiers)) - - if sm.is_typedef and sm.name: - return sm.name - elif sm.is_renum and sm.name: - base_name: str = sm.name - elif bt: - if isinstance(bt, str): - base_name = bt - elif isinstance(bt, type) and issubclass(bt, t.CType): - base_name = bt.__name__ - elif isinstance(bt, t.CType): - # 对命名的 CType(CStruct/CEnum/CUnion/REnum),优先使用其 name 属性 - # 否则回退到类名(如 'CInt'、'CChar') - _named: str | None = getattr(bt, 'name', None) - base_name = _named if _named else type(bt).__name__ - else: - base_name = str(bt) - else: - base_name = "void" - - if ts.is_array_ptr: - ptr_str: str = "" - if ts.ptr_count > 0: - ptr_str = "*" * ts.ptr_count - if ts.array_ptr: - inner: str = ts.array_ptr.ToString() - if ptr_str: - parts.append(f"{base_name} {ptr_str}({inner})") - else: - parts.append(f"{base_name} ({inner})") - else: - if ptr_str: - parts.append(f"{base_name} {ptr_str}()") - else: - parts.append(f"{base_name} ()") - elif ts.array_ptr: - inner = ts.array_ptr.ToString() - if ts.ptr_count > 0: - parts.append(f"{base_name} {'*' * ts.ptr_count}({inner})") - else: - parts.append(f"{base_name} ({inner})") - else: - parts.append(base_name) - if ts.ptr_count > 0: - parts.append("*" * ts.ptr_count) - if ts.var_const: - parts.append("const") - if ts.var_volatile: - parts.append("volatile") - - for dim in ts.array_dims: - if dim: - parts.append(f"[{dim}]") - else: - parts.append("[]") - - return " ".join(parts) if parts else "void" - - @staticmethod - def CreateFromTypeName(TypeName: str) -> "CTypeInfo": - """从类型名字符串创建 CTypeInfo(兼容旧 API)""" - info: CTypeInfo = CTypeInfo() - if TypeName.startswith('struct '): - info.BaseType = t.CStruct(name=TypeName[7:].strip()) if TypeName[7:].strip() else t.CStruct() - elif TypeName.startswith('enum '): - info.BaseType = t.CEnum(name=TypeName[5:].strip()) if TypeName[5:].strip() else t.CEnum() - elif TypeName.startswith('union '): - info.BaseType = t.CUnion(name=TypeName[6:].strip()) if TypeName[6:].strip() else t.CUnion() - else: - info.BaseType = t.CStruct(name=TypeName) - return info - - # LLVM primitive type name → (CTypeClass, PtrCount) mapping - # Used when generic type inference produces LLVM type names like 'i64', 'double', etc. - _LLVM_PRIMITIVE_MAP: dict[str, tuple[type, int]] | None = None - - @classmethod - def _get_llvm_primitive_map(cls) -> dict[str, tuple[type, int]]: - if cls._LLVM_PRIMITIVE_MAP is not None: - return cls._LLVM_PRIMITIVE_MAP - cls._LLVM_PRIMITIVE_MAP = { - 'void': (t.CVoid, 0), - 'i1': (t.CInt, 0), - 'i8': (t.CChar, 0), - 'i16': (t.CShort, 0), - 'i32': (t.CInt, 0), - 'i64': (t.CLong, 0), - 'i128': (t.CInt, 0), - 'float': (t.CFloat, 0), - 'double': (t.CDouble, 0), - 'fp128': (t.CFloat128T, 0), - } - return cls._LLVM_PRIMITIVE_MAP - - @staticmethod - def FromTypeName(TypeName: str) -> "CTypeInfo": - """从简单类型名构造 CTypeInfo(不经过 FromStr 字符串解析)""" - from lib.core.TypeAnnotationResolver import TypeAnnotationResolver - return TypeAnnotationResolver.from_type_name(TypeName) - - # FromStr 已移除 - 类型解析不再经过中间字符串格式 - # typedef 展开直接走 CTypeInfo 对象,不经过字符串解析 - - @staticmethod - def TryEvalConstExpr(node: ast.AST, SymbolTable: Any) -> Any: - from lib.core.TypeAnnotationResolver import TypeAnnotationResolver - return TypeAnnotationResolver.try_eval_const_expr(node, SymbolTable) - - @classmethod - def FromNode(cls, Node: ast.AST, SymbolTable: Any) -> "CTypeInfo": - """从 AST 节点解析 CTypeInfo(类方法) - - Args: - Node: AST 节点(如 ast.Name, ast.Attribute 等) - SymbolTable: 符号表字典 - """ - from lib.core.TypeAnnotationResolver import TypeAnnotationResolver - return TypeAnnotationResolver.from_node(Node, SymbolTable) - - - def Copy(self) -> "CTypeInfo": - NewInfo: CTypeInfo = CTypeInfo() - NewInfo._ts = self._ts.copy() - NewInfo._sm = self._sm.copy() - # CTypeInfo 引用字段需要深拷贝 - if isinstance(NewInfo._ts.func_ptr_return, CTypeInfo): - NewInfo._ts.func_ptr_return = NewInfo._ts.func_ptr_return.Copy() - if isinstance(NewInfo._ts.original_type, CTypeInfo): - NewInfo._ts.original_type = NewInfo._ts.original_type.Copy() - if NewInfo._ts.array_ptr: - NewInfo._ts.array_ptr = NewInfo._ts.array_ptr.Copy() - return NewInfo - - def get(self, key: str, default: Any = None) -> Any: - """获取额外属性""" - return self._sm._extra.get(key, default) - - def set(self, key: str, value: Any) -> None: - """设置额外属性""" - self._sm._extra[key] = value - - @staticmethod - def VoidTypeInfo() -> "CTypeInfo": - info: CTypeInfo = CTypeInfo() - info.BaseType = t.CVoid() - return info - - def ToLLVM(self, Gen: LlvmCodeGenerator) -> _ir.Type: - if Gen is None: - return _ir.IntType(32) - return Gen._ctype_to_llvm(self) - - def __str__(self) -> str: - return self.ToString() - - def __repr__(self) -> str: - ts: TypeSpec = self._ts - sm: SymbolMeta = self._sm - return f"CTypeInfo(BaseType={ts._base_type}, PtrCount={ts.ptr_count}, IsTypedef={sm.is_typedef}, OriginalType={ts.original_type!r}, VarConst={ts.var_const}, DataConst={ts.data_const})" - - -# 从 FIELD_ROUTES 静态绑定 _Delegated 描述符到 CTypeInfo 类 -# 这是一次性配置(类创建期执行),替代运行时 __setattr__/__getattr__ 动态路由 -for _old_name, (_target, _field) in FIELD_ROUTES.items(): - setattr(CTypeInfo, _old_name, _Delegated('_' + _target, _field)) -del _old_name, _target, _field - - -class CTypeHelper: - - @staticmethod - def GetTModuleCType(TypeName: str) -> type | None: - result: type | None = CTypeRegistry.GetClassByName(TypeName) - if result is not None: - return result - TypeClass: type | None = getattr(t, TypeName, None) - if TypeClass and isinstance(TypeClass, type) and issubclass(TypeClass, t.CType): - return TypeClass - FallbackClass: type | None = getattr(t, f'_{TypeName}', None) - if FallbackClass and isinstance(FallbackClass, type) and issubclass(FallbackClass, t.CType): - return FallbackClass - return None - - @staticmethod - def GetCName(type_or_name: str | type) -> str: - if isinstance(type_or_name, str): - cls: type | None = CTypeRegistry.GetClassByName(type_or_name) - if cls is None: - cls = CTypeHelper.GetTModuleCType(type_or_name) - if cls: - return cls.__name__ - return type_or_name - elif isinstance(type_or_name, type) and issubclass(type_or_name, t.CType): - return type_or_name.__name__ - return '' - - -class BuiltinTypeMap: - """ - 内置类型映射表 - 字符串到 (CType类, PtrCount) 的映射 - - 用法:BuiltinTypeMap.Get('int') -> (t.CInt, 0) - BuiltinTypeMap.Get('BYTEPTR') -> (t.CUnsignedChar, 1) - """ - - _map: dict[str, tuple[type, int]] | None = None - - @classmethod - def _build_map(cls) -> dict[str, tuple[type, int]]: - if cls._map is not None: - return cls._map - CTypeRegistry._build() - cls._map = {} - # 仅使用 Python 类名 → (CType 类, ptr_level) 映射。 - # C 类型名(如 'int'、'int32_t')不再通过 _cname_to_class 提供。 - # C 头文件 stub 生成器使用独立的硬编码表(CTypeMapper._CNAME_TO_PY)。 - for pyname, ctype_cls in CTypeRegistry._name_to_class.items(): - pos: frozenset = getattr(ctype_cls, 'position', frozenset()) - if t.CType.POINTER in pos and t.CType.BASE not in pos: - cls._map[pyname] = (ctype_cls, 1) - else: - cls._map[pyname] = (ctype_cls, 0) - # 保留一些常用的字符串速记(这些不是 CName,而是硬编码的便捷别名)。 - # 包含 Python 内置类型名(int/float/bool)和 C 类型名速记(char/short/long 等)。 - _SPECIAL: dict[str, tuple[type, int]] = { - # Python 内置类型名 - 'str': (t.CChar, 1), 'bytes': (t.CChar, 1), - 'int': (t.CInt, 0), 'float': (t.CFloat, 0), 'bool': (t.CBool, 0), - # C 类型名速记 - 'char': (t.CChar, 0), 'short': (t.CShort, 0), - 'long': (t.CLong, 0), 'long long': (t.CLongLong, 0), - 'double': (t.CDouble, 0), - 'unsigned': (t.CUnsigned, 0), - 'signed': (t.CInt, 0), 'signed int': (t.CInt, 0), - 'signed char': (t.CSignedChar, 0), - 'void': (t.CVoid, 0), 'Void': (t.CVoid, 0), - } - for k, v in _SPECIAL.items(): - if k not in cls._map: - cls._map[k] = v - _FLOAT_ALIASES: dict[str, tuple[type, int]] = { - 'FLOAT8': (t.CFloat8T, 0), 'FLOAT16': (t.CFloat16T, 0), - 'FLOAT32': (t.CFloat32T, 0), 'FLOAT64': (t.CFloat64T, 0), - 'FLOAT128': (t.CFloat128T, 0), - } - for k, v in _FLOAT_ALIASES.items(): - if k not in cls._map: - cls._map[k] = v - return cls._map - - @classmethod - def Get(cls, type_name: str) -> tuple[type, int] | None: - """获取类型类和指针层级""" - return cls._build_map().get(type_name) - - -class BaseHandle: - def __init__(self, translator: "Translator") -> None: - self.Trans: Translator = translator - self._CurrentCpythonObjectClass: str | None = None - - @staticmethod - def _is_char_pointer(val: _ir.Value) -> bool: - """检查值是否为 char* (i8*) 指针""" - if not isinstance(val.type, _ir.PointerType): - return False - pointee: _ir.Type = val.type.pointee - return isinstance(pointee, _ir.IntType) and pointee.width == 8 - - def HandleExprLlvm(self, Node: ast.AST, VarType: _ir.Type | str | None = None) -> _ir.Value | None: - return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType) - - def HandleBodyLlvm(self, Body: ast.AST | list[ast.stmt]) -> Any: - return self.Trans.BodyHandler.HandleBodyLlvm(Body) - - def _get_int_ptr(self, Node: ast.AST) -> _ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - if isinstance(Node, ast.Name): - if Node.id in Gen.variables: - return Gen.variables[Node.id] - elif isinstance(Node, ast.Attribute): - obj_val: Any = self.HandleExprLlvm(Node.value) - if not obj_val: - return None - if isinstance(obj_val.type, _ir.PointerType): - pointee: _ir.Type = obj_val.type.pointee - if isinstance(pointee, (_ir.IdentifiedStructType, _ir.LiteralStructType)): - StructName: str | None = None - if isinstance(pointee, _ir.IdentifiedStructType): - StructName = pointee.name - if not StructName: - for ClassName, struct_type in Gen.structs.items(): - if struct_type == pointee: - StructName = ClassName - break - if StructName and StructName in Gen.structs: - offset: int = self.Trans.ExprHandler._get_llvm_member_offset(Node.attr, StructName, Gen) - member_ptr: Any = Gen.builder.gep(obj_val, [_ir.Constant(_ir.IntType(32), 0), _ir.Constant(_ir.IntType(32), offset)], name=f"{Node.attr}_ptr") - return member_ptr - return None - - def _IsTModuleType(self, TypeName: str) -> bool: - if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'): - return True - TypeClass: type | None = getattr(t, TypeName, None) - if TypeClass and isinstance(TypeClass, type): - if issubclass(TypeClass, t.CType): - return True - FallbackClass: type | None = getattr(t, f'_{TypeName}', None) - if FallbackClass and isinstance(FallbackClass, type): - if issubclass(FallbackClass, t.CType): - return True - return False - - def ResolveListElementType( - self, - elem_type_node: ast.expr, - Gen: Any, - *, - check_func_ptr: bool = False, - handle_str: bool = False, - void_fallback_width: int = 32, - fallback_to_cint: bool = False, - ) -> tuple[Any, CTypeInfo | None]: - """解析 list 元素类型,返回 (LLVM类型, CTypeInfo|None)。 - - 统一处理结构体、str、函数指针、VoidType 回退等变体。 - - Args: - check_func_ptr: 是否检查函数指针(全局变量路径需要) - handle_str: 是否处理 str → i8*(局部变量路径需要) - void_fallback_width: VoidType 回退宽度 (32 或 8) - fallback_to_cint: 无类型信息时回退到 CInt - """ - elem_type_info: CTypeInfo | None = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable) - - # 结构体类型 - if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: - if check_func_ptr: - sym_entry: CTypeInfo | None = self.Trans.SymbolTable.lookup(elem_type_node.id) - if sym_entry and isinstance(sym_entry, CTypeInfo) and sym_entry.IsFuncPtr: - return _ir.IntType(8).as_pointer(), elem_type_info - return Gen.structs[elem_type_node.id], elem_type_info - - # str → i8* - if handle_str and isinstance(elem_type_node, ast.Name) and elem_type_node.id == 'str': - return _ir.PointerType(_ir.IntType(8)), elem_type_info - - # 函数指针检查 - if check_func_ptr and elem_type_info and elem_type_info.IsFuncPtr: - return _ir.IntType(8).as_pointer(), elem_type_info - - # 回退到 CInt - if elem_type_info is None and fallback_to_cint: - elem_type_info = CTypeInfo() - elem_type_info.BaseType = t.CInt() - - elem_type: Any = Gen._ctype_to_llvm(elem_type_info) - if isinstance(elem_type, _ir.VoidType): - elem_type = _ir.IntType(void_fallback_width) - - return elem_type, elem_type_info - - def ParseArrayCount( - self, - count_node: ast.expr | None, - Gen: Any, - value_node: ast.expr | None = None, - *, - mode: str = 'global', - ) -> int: - """解析数组计数,返回计数(默认 1)。 - - 统一处理 Constant/Name/Attribute/BinOp/None 等形式。 - None 或 Constant(None) 时从 value_node 推断(List 长度或 str 长度+1)。 - - Args: - count_node: 计数 AST 节点 - value_node: 赋值右侧值节点(用于 count_node 为 None 时推断) - mode: 'global' 使用 _eval_global_count + SymbolTable + _define_constants; - 'local' 使用 TryEvalConstExpr - """ - # None 或 Constant(None) → 从 value_node 推断 - if count_node is None or (isinstance(count_node, ast.Constant) and count_node.value is None): - if value_node and isinstance(value_node, ast.List): - return len(value_node.elts) - if value_node and isinstance(value_node, ast.Constant) and isinstance(value_node.value, str): - return len(value_node.value) + 1 - return 1 - - # Constant(int) - if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int): - return count_node.value - - if mode == 'global': - # Name → SymbolTable + _define_constants - if isinstance(count_node, ast.Name): - ArrayCount: int = 1 - if self.Trans.SymbolTable.has(count_node.id): - sym_info: Any = self.Trans.SymbolTable[count_node.id] - if isinstance(sym_info.value, int): - ArrayCount = sym_info.value - if ArrayCount == 1 and count_node.id in Gen._define_constants: - def_val: Any = Gen._define_constants[count_node.id] - # 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 覆盖 - try: - if hasattr(Gen, 'module') and count_node.id in Gen.module.globals: - _gv: Any = Gen.module.globals[count_node.id] - if getattr(_gv, 'initializer', None) is not None: - _iv: Any = _gv.initializer - if hasattr(_iv, 'constant') and isinstance(_iv.constant, int): - def_val = _iv.constant - except Exception: - pass - if isinstance(def_val, int): - ArrayCount = def_val - return ArrayCount - # Attribute / BinOp → _eval_global_count - if isinstance(count_node, (ast.Attribute, ast.BinOp)): - eval_fn: Any = getattr(self, '_eval_global_count', None) - if eval_fn is not None: - ev: int | None = eval_fn(count_node, Gen) - if ev is not None: - return ev - return 1 - else: - # local mode → TryEvalConstExpr - eval_count: Any = CTypeInfo.TryEvalConstExpr(count_node, self.Trans.SymbolTable) - if eval_count is not None and isinstance(eval_count, int) and eval_count > 0: - return eval_count - return 1 - - return 1 - - def ResolveAnnotationType(self, annotation: ast.expr) -> CTypeInfo | None: - """解析注解类型,BinOp(BitOr) 优先使用 MergeTypes,其他使用 FromNode。 - - 统一处理函数返回类型和参数类型的 BinOp 联合类型解析。 - """ - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - merger: Any = getattr(self.Trans, 'TypeMergeHandler', None) - if merger: - info: CTypeInfo | None = merger.MergeTypes(annotation) - if info is not None and isinstance(info, CTypeInfo): - return info - return CTypeInfo.FromNode(annotation, self.Trans.SymbolTable) - - def CollectAnnAssignMember( - self, item: ast.AST, Gen: Any - ) -> tuple[str, _ir.Type, CTypeInfo | None] | None: - """从 ast.AnnAssign 节点解析成员信息。 - - 返回 (VarName, MemberType, TypeInfo);TypeInfo 为 None 表示解析回退到 i32。 - 非 AnnAssign/Name 目标时返回 None。 - """ - if not isinstance(item, ast.AnnAssign) or not isinstance(item.target, ast.Name): - return None - VarName: str = item.target.id - try: - TypeInfo: CTypeInfo | None = self.ResolveAnnotationType(item.annotation) - if TypeInfo is None: - TypeInfo = CTypeInfo() - TypeInfo.BaseType = t.CInt() - MemberType: _ir.Type = Gen._ctype_to_llvm(TypeInfo) - if isinstance(MemberType, _ir.VoidType): - MemberType = _ir.PointerType(_ir.IntType(8)) - return VarName, MemberType, TypeInfo - except Exception as e: - _vlog().warning(f"HandlesBase: 忽略异常 {e}", exc_info=e) - return VarName, _ir.IntType(32), None - - def LookupFunctionSymbol(self, name: str, *, module_path: str | None = None) -> CTypeInfo | None: - """查找函数符号,先尝试 module_path.name,再回退到 name。 - - 统一处理 HandlesExprCall / HandlesAssign 中重复的二级查找模式。 - 返回 CTypeInfo(不限定 IsFunction),由调用方检查标志位。 - """ - st = self.Trans.SymbolTable - if module_path: - sym: CTypeInfo | None = st.lookup(f'{module_path}.{name}') - if sym: - return sym - return st.lookup(name) - - def BuildLLVMFuncTypeFromSig( - self, - sym_info: CTypeInfo, - Gen: Any, - *, - mangled_name: str | None = None, - use_infer_fallback: bool = False, - ) -> tuple[Any, list[Any], bool] | None: - """从 CTypeInfo 函数签名构建 LLVM 函数类型。 - - 返回 (ret_type, llvm_param_types, is_variadic),非函数返回 None。 - 统一处理 FuncPtrReturn/FuncPtrParams → ToLLVM 转换、VoidType 回退。 - - Args: - mangled_name: 用于 _infer_return_type + stub 查找回退 - use_infer_fallback: 为 True 时启用 _infer_return_type + stub 查找回退链 - """ - if not sym_info.IsFunction: - return None - is_variadic: bool = sym_info.IsVariadic - ret_type_info = sym_info.FuncPtrReturn - if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: - ret_type: Any = ret_type_info.ToLLVM(Gen) - elif use_infer_fallback and mangled_name: - inferred: Any = Gen._infer_return_type(mangled_name) - if isinstance(inferred, _ir.IntType) and inferred.width == 32: - try: - stub_ft: Any = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen) - if stub_ft and hasattr(stub_ft, 'return_type'): - inferred = stub_ft.return_type - except Exception: - pass - ret_type = inferred - else: - ret_type = Gen._CType2LLVM('i32', False) - param_type_infos = [pt for _, pt in (sym_info.FuncPtrParams or [])] - if isinstance(ret_type, _ir.VoidType): - ret_type = _ir.IntType(32) - llvm_param_types: list[Any] = [] - for pt in param_type_infos: - if isinstance(pt, CTypeInfo) and pt.BaseType: - lp: Any = pt.ToLLVM(Gen) - else: - lp = Gen._CType2LLVM(pt if isinstance(pt, str) else 'i32', '*' in pt if isinstance(pt, str) else False) - if isinstance(lp, _ir.VoidType): - lp = _ir.IntType(8).as_pointer() - llvm_param_types.append(lp) - return ret_type, llvm_param_types, is_variadic - - def GetOrCreateFuncDecl( - self, - name: str, - ret_type: Any, - param_types: list[Any], - Gen: Any, - *, - is_variadic: bool = False, - replace_name: str | None = None, - ) -> Any: - """创建或替换 LLVM 函数声明。 - - 若 name 已存在且类型不匹配,通过 _replace_function_decl 替换。 - replace_name 传递给 _replace_function_decl(通常为未 mangle 的 func_name)。 - """ - if name not in Gen.functions: - func_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic) - func_decl = _ir.Function(Gen.module, func_type, name=name) - Gen.functions[name] = func_decl - else: - existing = Gen.functions[name] - existing_type = getattr(existing, 'ftype', None) - new_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic) - if existing_type and existing_type != new_type: - replaced = self.Trans.FunctionHandler._replace_function_decl(Gen, replace_name or name, new_type) - if replaced and replaced != existing: - Gen.functions[name] = replaced - return Gen.functions[name] - - def GetOrCreateStubFuncDecl( - self, - decl_name: str, - stub_func_type: Any, - Gen: Any, - *, - alias: str | None = None, - check_existing: bool = True, - ) -> Any: - """创建 stub 函数声明,可选注册别名。 - - check_existing=False 时跳过存在性检查(用于确定不存在的场景)。 - """ - if check_existing and decl_name in Gen.functions: - func_decl = Gen.functions[decl_name] - else: - func_decl = _ir.Function(Gen.module, stub_func_type, name=decl_name) - Gen.functions[decl_name] = func_decl - if alias and alias != decl_name: - if not check_existing or alias not in Gen.functions: - Gen.functions[alias] = func_decl - return func_decl - - +from __future__ import annotations +from typing import TYPE_CHECKING, List, Any +if TYPE_CHECKING: + from lib.core.translator import Translator + from lib.core.LlvmCodeGenerator import LlvmCodeGenerator + +import vast as ast +from enum import IntFlag, auto + +from llvmlite import ir as _ir + +from lib.constants import config as _config +from lib.includes import t +from lib.includes.t import CTypeRegistry +from lib.core.TypeSpec import TypeSpec, SymbolMeta, FIELD_ROUTES +from lib.core.VLogger import get_logger as _vlog + + +EXCEPTION_CODE_MAP: dict[str, int] = { + 'ValueError': 1, 'TypeError': 2, 'RuntimeError': 3, + 'ZeroDivisionError': 4, 'IndexError': 5, 'KeyError': 6, + 'IOError': 7, 'OSError': 8, 'AssertionError': 9, 'Exception': 99, +} + + +class FuncMeta(IntFlag): + NONE = 0 + STATIC_METHOD = auto() + PROPERTY_GETTER = auto() + PROPERTY_SETTER = auto() + PROPERTY_DELETER = auto() + CLASS_METHOD = auto() + ABSTRACT = auto() + + +class _Delegated: + """CTypeInfo 旧字段名委托描述符 — 静态委托到 _ts/_sm 的字段 + + 替代旧的 FIELD_ROUTES + __setattr__/__getattr__ 动态路由: + 描述符在类创建时绑定,访问时直接走 __get__/__set__, + 无 dict 查找和字符串比较的运行时开销。 + """ + __slots__ = ('_target_attr', '_field_name') + + def __init__(self, target_attr: str, field_name: str) -> None: + self._target_attr: str = target_attr # '_ts' or '_sm' + self._field_name: str = field_name + + def __get__(self, obj: Any, objtype: type | None = None) -> Any: + if obj is None: + return self + target: Any = object.__getattribute__(obj, self._target_attr) + return getattr(target, self._field_name) + + def __set__(self, obj: Any, value: Any) -> None: + target: Any = object.__getattribute__(obj, self._target_attr) + setattr(target, self._field_name, value) + + +class CTypeInfo: + """ + C 类型信息对象 - 统一符号表条目和类型计算 + + 设计原则: + - BaseType 是 CType 实例(来自 t 模块),永远不使用硬编码字符串 + - 描述符分为两种: + - VarConst/VarVolatile: 变量本身(指针)的限定符,如 int * const + - DataConst/DataVolatile: 指向数据的限定符,如 const int * + + 属性(类型计算): + - BaseType: t.CType - 基础类型实例 (如 t.CInt(), t.CVoid()) + - PtrCount: int - 指针层数 + - VarConst: bool - 变量本身(指针)是否 const,如 int * const + - VarVolatile: bool - 变量本身(指针)是否 volatile + - DataConst: bool - 指向的数据是否 const,如 const int * + - DataVolatile: bool - 指向的数据是否 volatile + - ArrayDims: List[str] - 数组维度 + - Storage: t.CType - 存储类 (static, extern 等) + - IsFuncPtr: bool - 是否函数指针 + - FuncPtrParams: List[Tuple[str, CTypeInfo]] - 函数指针参数列表,每个元素是 (参数名, 参数类型) + - FuncPtrReturn: CTypeInfo - 函数指针返回类型 + - IsBitField: bool - 是否位域 + - BitWidth: int - 位域宽度 + - IsTypedef/IsStruct/IsEnum/IsUnion: bool - 类型种类 + + 属性(符号表元数据): + - Name: str - 名称(struct/enum/union/typedef 名) + - Members: Dict[str, CTypeInfo] - 成员字典(用于 struct/union) + - OriginalType: str - typedef 的原始类型 + - DeclaredType: str - 声明类型 + - CreturnTypes: list - C 返回类型列表 + - Lineno: int - 定义行号 + - IsAnonymous: bool - 是否匿名类型 + - IsCpythonObject: bool - 是否 CPython 对象 + - IsEnumMember: bool - 是否枚举成员 + """ + + def __init__(self) -> None: + object.__setattr__(self, '_ts', TypeSpec()) + sm: SymbolMeta = SymbolMeta() + sm.meta_list = FuncMeta.NONE + object.__setattr__(self, '_sm', sm) + + # --- 新公共 API:供新代码直接访问 TypeSpec / SymbolMeta / SymbolKind --- + @property + def ts(self) -> TypeSpec: + """TypeSpec — 纯类型描述(只读)""" + return self._ts + + @property + def sm(self) -> SymbolMeta: + """SymbolMeta — 符号表元数据(只读)""" + return self._sm + + @property + def kind(self) -> 'SymbolKind': + """SymbolKind — 符号类型种类枚举""" + return self._sm.kind + + # 注:旧字段名(PtrCount/IsStruct/Name 等)的委托通过 _Delegated 描述符实现, + # 在模块末尾从 FIELD_ROUTES 静态绑定,无需 __setattr__/__getattr__ 动态路由 + + + + @property + def BaseType(self) -> t.CType | tuple | None: + return self._ts._base_type + + @BaseType.setter + def BaseType(self, value: t.CType | type | tuple | List | None) -> None: + """设置 BaseType,接受以下类型: + + - None: 清空 + - t.CType 实例: 单个类型,自动设置 IsStruct/IsEnum/IsUnion 标志 + - type (CType 子类): 如 t.CStruct,自动实例化 + - tuple/list of t.CType: 多个组合类型 + """ + ts: TypeSpec = self._ts + sm: SymbolMeta = self._sm + + if value is None: + ts._base_type = None + sm.is_struct = False + sm.is_enum = False + sm.is_union = False + sm.is_renum = False + return + + if isinstance(value, (tuple, list)): + ts._base_type = tuple(value) + for v in value: + if isinstance(v, t.CStruct): + sm.is_struct = True + elif isinstance(v, t.CEnum): + sm.is_enum = True + elif isinstance(v, t.CUnion): + sm.is_union = True + elif isinstance(v, t.REnum): + sm.is_renum = True + sm.is_enum = True + return + + if isinstance(value, type) and issubclass(value, t.CType): + ts._base_type = value() + return + + if isinstance(value, t.CType): + ts._base_type = value + if isinstance(value, t.CStruct): + sm.is_struct = True + sm.is_enum = False + sm.is_union = False + sm.is_renum = False + elif isinstance(value, t.REnum): + sm.is_renum = True + sm.is_enum = True + sm.is_struct = False + sm.is_union = False + elif isinstance(value, t.CEnum): + sm.is_enum = True + sm.is_struct = False + sm.is_union = False + sm.is_renum = False + elif isinstance(value, t.CUnion): + sm.is_union = True + sm.is_struct = False + sm.is_enum = False + sm.is_renum = False + return + + raise TypeError(f"BaseType must be t.CType instance, type subclass, or tuple of t.CType, got {type(value)}") + + @property + def TypeCls(self) -> type | None: + """获取 CType 类(从 BaseType 推断)""" + bt: t.CType | tuple | None = self._ts._base_type + if bt: + return type(bt) + sm: SymbolMeta = self._sm + if sm.is_struct: + return t.CStruct + if sm.is_enum: + return t.CEnum + if sm.is_union: + return t.CUnion + if sm.is_typedef: + return t._CTypedef + return None + + @property + def IsPtr(self) -> bool: + return self._ts.ptr_count > 0 + + @property + def IsVoid(self) -> bool: + return isinstance(self._ts._base_type, t.CVoid) + + @property + def IsStr(self) -> bool: + return isinstance(self._ts._base_type, t.CChar) and self._ts.ptr_count > 0 + + @property + def IsInt(self) -> bool: + bt: t.CType | tuple | None = self._ts._base_type + return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is not None and bt.IsSigned is True and not isinstance(bt, t.CVoid) + + @property + def IsUInt(self) -> bool: + bt: t.CType | tuple | None = self._ts._base_type + return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is False + + @property + def IsFloat(self) -> bool: + bt: t.CType | tuple | None = self._ts._base_type + return isinstance(bt, t.CType) and getattr(bt, 'IsSigned', None) is None and getattr(bt, 'Size', 0) in (32, 64, 128) and not isinstance(bt, t.CVoid) + + def ToString(self) -> str: + ts: TypeSpec = self._ts + sm: SymbolMeta = self._sm + bt: t.CType | tuple | None = ts._base_type + + if ts.is_func_ptr: + return 'Callable' + parts: list[str] = [] + + if ts.storage and not isinstance(ts.storage, t.CExport): + parts.append(type(ts.storage).__name__) + + if ts.data_const or ts.data_volatile: + qualifiers: list[str] = [] + if ts.data_const: + qualifiers.append("const") + if ts.data_volatile: + qualifiers.append("volatile") + parts.append("_".join(qualifiers)) + + if sm.is_typedef and sm.name: + return sm.name + elif sm.is_renum and sm.name: + base_name: str = sm.name + elif bt: + if isinstance(bt, str): + base_name = bt + elif isinstance(bt, type) and issubclass(bt, t.CType): + base_name = bt.__name__ + elif isinstance(bt, t.CType): + # 对命名的 CType(CStruct/CEnum/CUnion/REnum),优先使用其 name 属性 + # 否则回退到类名(如 'CInt'、'CChar') + _named: str | None = getattr(bt, 'name', None) + base_name = _named if _named else type(bt).__name__ + else: + base_name = str(bt) + else: + base_name = "void" + + if ts.is_array_ptr: + ptr_str: str = "" + if ts.ptr_count > 0: + ptr_str = "*" * ts.ptr_count + if ts.array_ptr: + inner: str = ts.array_ptr.ToString() + if ptr_str: + parts.append(f"{base_name} {ptr_str}({inner})") + else: + parts.append(f"{base_name} ({inner})") + else: + if ptr_str: + parts.append(f"{base_name} {ptr_str}()") + else: + parts.append(f"{base_name} ()") + elif ts.array_ptr: + inner = ts.array_ptr.ToString() + if ts.ptr_count > 0: + parts.append(f"{base_name} {'*' * ts.ptr_count}({inner})") + else: + parts.append(f"{base_name} ({inner})") + else: + parts.append(base_name) + if ts.ptr_count > 0: + parts.append("*" * ts.ptr_count) + if ts.var_const: + parts.append("const") + if ts.var_volatile: + parts.append("volatile") + + for dim in ts.array_dims: + if dim: + parts.append(f"[{dim}]") + else: + parts.append("[]") + + return " ".join(parts) if parts else "void" + + @staticmethod + def CreateFromTypeName(TypeName: str) -> "CTypeInfo": + """从类型名字符串创建 CTypeInfo(兼容旧 API)""" + info: CTypeInfo = CTypeInfo() + if TypeName.startswith('struct '): + info.BaseType = t.CStruct(name=TypeName[7:].strip()) if TypeName[7:].strip() else t.CStruct() + elif TypeName.startswith('enum '): + info.BaseType = t.CEnum(name=TypeName[5:].strip()) if TypeName[5:].strip() else t.CEnum() + elif TypeName.startswith('union '): + info.BaseType = t.CUnion(name=TypeName[6:].strip()) if TypeName[6:].strip() else t.CUnion() + else: + info.BaseType = t.CStruct(name=TypeName) + return info + + # LLVM primitive type name → (CTypeClass, PtrCount) mapping + # Used when generic type inference produces LLVM type names like 'i64', 'double', etc. + _LLVM_PRIMITIVE_MAP: dict[str, tuple[type, int]] | None = None + + @classmethod + def _get_llvm_primitive_map(cls) -> dict[str, tuple[type, int]]: + if cls._LLVM_PRIMITIVE_MAP is not None: + return cls._LLVM_PRIMITIVE_MAP + cls._LLVM_PRIMITIVE_MAP = { + 'void': (t.CVoid, 0), + 'i1': (t.CInt, 0), + 'i8': (t.CChar, 0), + 'i16': (t.CShort, 0), + 'i32': (t.CInt, 0), + 'i64': (t.CLong, 0), + 'i128': (t.CInt, 0), + 'float': (t.CFloat, 0), + 'double': (t.CDouble, 0), + 'fp128': (t.CFloat128T, 0), + } + return cls._LLVM_PRIMITIVE_MAP + + @staticmethod + def FromTypeName(TypeName: str) -> "CTypeInfo": + """从简单类型名构造 CTypeInfo(不经过 FromStr 字符串解析)""" + from lib.core.TypeAnnotationResolver import TypeAnnotationResolver + return TypeAnnotationResolver.from_type_name(TypeName) + + # FromStr 已移除 - 类型解析不再经过中间字符串格式 + # typedef 展开直接走 CTypeInfo 对象,不经过字符串解析 + + @staticmethod + def TryEvalConstExpr(node: ast.AST, SymbolTable: Any) -> Any: + from lib.core.TypeAnnotationResolver import TypeAnnotationResolver + return TypeAnnotationResolver.try_eval_const_expr(node, SymbolTable) + + @classmethod + def FromNode(cls, Node: ast.AST, SymbolTable: Any) -> "CTypeInfo": + """从 AST 节点解析 CTypeInfo(类方法) + + Args: + Node: AST 节点(如 ast.Name, ast.Attribute 等) + SymbolTable: 符号表字典 + """ + from lib.core.TypeAnnotationResolver import TypeAnnotationResolver + return TypeAnnotationResolver.from_node(Node, SymbolTable) + + + def Copy(self) -> "CTypeInfo": + NewInfo: CTypeInfo = CTypeInfo() + NewInfo._ts = self._ts.copy() + NewInfo._sm = self._sm.copy() + # CTypeInfo 引用字段需要深拷贝 + if isinstance(NewInfo._ts.func_ptr_return, CTypeInfo): + NewInfo._ts.func_ptr_return = NewInfo._ts.func_ptr_return.Copy() + if isinstance(NewInfo._ts.original_type, CTypeInfo): + NewInfo._ts.original_type = NewInfo._ts.original_type.Copy() + if NewInfo._ts.array_ptr: + NewInfo._ts.array_ptr = NewInfo._ts.array_ptr.Copy() + return NewInfo + + def get(self, key: str, default: Any = None) -> Any: + """获取额外属性""" + return self._sm._extra.get(key, default) + + def set(self, key: str, value: Any) -> None: + """设置额外属性""" + self._sm._extra[key] = value + + @staticmethod + def VoidTypeInfo() -> "CTypeInfo": + info: CTypeInfo = CTypeInfo() + info.BaseType = t.CVoid() + return info + + def ToLLVM(self, Gen: LlvmCodeGenerator) -> _ir.Type: + if Gen is None: + return _ir.IntType(32) + return Gen._ctype_to_llvm(self) + + def __str__(self) -> str: + return self.ToString() + + def __repr__(self) -> str: + ts: TypeSpec = self._ts + sm: SymbolMeta = self._sm + return f"CTypeInfo(BaseType={ts._base_type}, PtrCount={ts.ptr_count}, IsTypedef={sm.is_typedef}, OriginalType={ts.original_type!r}, VarConst={ts.var_const}, DataConst={ts.data_const})" + + +# 从 FIELD_ROUTES 静态绑定 _Delegated 描述符到 CTypeInfo 类 +# 这是一次性配置(类创建期执行),替代运行时 __setattr__/__getattr__ 动态路由 +for _old_name, (_target, _field) in FIELD_ROUTES.items(): + setattr(CTypeInfo, _old_name, _Delegated('_' + _target, _field)) +del _old_name, _target, _field + + +class CTypeHelper: + + @staticmethod + def GetTModuleCType(TypeName: str) -> type | None: + result: type | None = CTypeRegistry.GetClassByName(TypeName) + if result is not None: + return result + TypeClass: type | None = getattr(t, TypeName, None) + if TypeClass and isinstance(TypeClass, type) and issubclass(TypeClass, t.CType): + return TypeClass + FallbackClass: type | None = getattr(t, f'_{TypeName}', None) + if FallbackClass and isinstance(FallbackClass, type) and issubclass(FallbackClass, t.CType): + return FallbackClass + return None + + @staticmethod + def GetCName(type_or_name: str | type) -> str: + if isinstance(type_or_name, str): + cls: type | None = CTypeRegistry.GetClassByName(type_or_name) + if cls is None: + cls = CTypeHelper.GetTModuleCType(type_or_name) + if cls: + return cls.__name__ + return type_or_name + elif isinstance(type_or_name, type) and issubclass(type_or_name, t.CType): + return type_or_name.__name__ + return '' + + +class BuiltinTypeMap: + """ + 内置类型映射表 - 字符串到 (CType类, PtrCount) 的映射 + + 用法:BuiltinTypeMap.Get('int') -> (t.CInt, 0) + BuiltinTypeMap.Get('BYTEPTR') -> (t.CUnsignedChar, 1) + """ + + _map: dict[str, tuple[type, int]] | None = None + + @classmethod + def _build_map(cls) -> dict[str, tuple[type, int]]: + if cls._map is not None: + return cls._map + CTypeRegistry._build() + cls._map = {} + # 仅使用 Python 类名 → (CType 类, ptr_level) 映射。 + # C 类型名(如 'int'、'int32_t')不再通过 _cname_to_class 提供。 + # C 头文件 stub 生成器使用独立的硬编码表(CTypeMapper._CNAME_TO_PY)。 + for pyname, ctype_cls in CTypeRegistry._name_to_class.items(): + pos: frozenset = getattr(ctype_cls, 'position', frozenset()) + if t.CType.POINTER in pos and t.CType.BASE not in pos: + cls._map[pyname] = (ctype_cls, 1) + else: + cls._map[pyname] = (ctype_cls, 0) + # 保留一些常用的字符串速记(这些不是 CName,而是硬编码的便捷别名)。 + # 包含 Python 内置类型名(int/float/bool)和 C 类型名速记(char/short/long 等)。 + _SPECIAL: dict[str, tuple[type, int]] = { + # Python 内置类型名 + 'str': (t.CChar, 1), 'bytes': (t.CChar, 1), + 'int': (t.CInt, 0), 'float': (t.CFloat, 0), 'bool': (t.CBool, 0), + # C 类型名速记 + 'char': (t.CChar, 0), 'short': (t.CShort, 0), + 'long': (t.CLong, 0), 'long long': (t.CLongLong, 0), + 'double': (t.CDouble, 0), + 'unsigned': (t.CUnsigned, 0), + 'signed': (t.CInt, 0), 'signed int': (t.CInt, 0), + 'signed char': (t.CSignedChar, 0), + 'void': (t.CVoid, 0), 'Void': (t.CVoid, 0), + } + for k, v in _SPECIAL.items(): + if k not in cls._map: + cls._map[k] = v + _FLOAT_ALIASES: dict[str, tuple[type, int]] = { + 'FLOAT8': (t.CFloat8T, 0), 'FLOAT16': (t.CFloat16T, 0), + 'FLOAT32': (t.CFloat32T, 0), 'FLOAT64': (t.CFloat64T, 0), + 'FLOAT128': (t.CFloat128T, 0), + } + for k, v in _FLOAT_ALIASES.items(): + if k not in cls._map: + cls._map[k] = v + return cls._map + + @classmethod + def Get(cls, type_name: str) -> tuple[type, int] | None: + """获取类型类和指针层级""" + return cls._build_map().get(type_name) + + +class BaseHandle: + def __init__(self, translator: "Translator") -> None: + self.Trans: Translator = translator + self._CurrentCpythonObjectClass: str | None = None + + @staticmethod + def _is_char_pointer(val: _ir.Value) -> bool: + """检查值是否为 char* (i8*) 指针""" + if not isinstance(val.type, _ir.PointerType): + return False + pointee: _ir.Type = val.type.pointee + return isinstance(pointee, _ir.IntType) and pointee.width == 8 + + def HandleExprLlvm(self, Node: ast.AST, VarType: _ir.Type | str | None = None) -> _ir.Value | None: + return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType) + + def HandleBodyLlvm(self, Body: ast.AST | list[ast.stmt]) -> Any: + return self.Trans.BodyHandler.HandleBodyLlvm(Body) + + def _get_int_ptr(self, Node: ast.AST) -> _ir.Value | None: + Gen: LlvmCodeGenerator = self.Trans.LlvmGen + if isinstance(Node, ast.Name): + if Node.id in Gen.variables: + return Gen.variables[Node.id] + elif isinstance(Node, ast.Attribute): + obj_val: Any = self.HandleExprLlvm(Node.value) + if not obj_val: + return None + if isinstance(obj_val.type, _ir.PointerType): + pointee: _ir.Type = obj_val.type.pointee + if isinstance(pointee, (_ir.IdentifiedStructType, _ir.LiteralStructType)): + StructName: str | None = None + if isinstance(pointee, _ir.IdentifiedStructType): + StructName = pointee.name + if not StructName: + for ClassName, struct_type in Gen.structs.items(): + if struct_type == pointee: + StructName = ClassName + break + if StructName and StructName in Gen.structs: + offset: int = self.Trans.ExprHandler._get_llvm_member_offset(Node.attr, StructName, Gen) + member_ptr: Any = Gen.builder.gep(obj_val, [_ir.Constant(_ir.IntType(32), 0), _ir.Constant(_ir.IntType(32), offset)], name=f"{Node.attr}_ptr") + return member_ptr + return None + + def _IsTModuleType(self, TypeName: str) -> bool: + if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'): + return True + TypeClass: type | None = getattr(t, TypeName, None) + if TypeClass and isinstance(TypeClass, type): + if issubclass(TypeClass, t.CType): + return True + FallbackClass: type | None = getattr(t, f'_{TypeName}', None) + if FallbackClass and isinstance(FallbackClass, type): + if issubclass(FallbackClass, t.CType): + return True + return False + + def ResolveListElementType( + self, + elem_type_node: ast.expr, + Gen: Any, + *, + check_func_ptr: bool = False, + handle_str: bool = False, + void_fallback_width: int = 32, + fallback_to_cint: bool = False, + ) -> tuple[Any, CTypeInfo | None]: + """解析 list 元素类型,返回 (LLVM类型, CTypeInfo|None)。 + + 统一处理结构体、str、函数指针、VoidType 回退等变体。 + + Args: + check_func_ptr: 是否检查函数指针(全局变量路径需要) + handle_str: 是否处理 str → i8*(局部变量路径需要) + void_fallback_width: VoidType 回退宽度 (32 或 8) + fallback_to_cint: 无类型信息时回退到 CInt + """ + elem_type_info: CTypeInfo | None = CTypeInfo.FromNode(elem_type_node, self.Trans.SymbolTable) + + # 结构体类型 + if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs: + if check_func_ptr: + sym_entry: CTypeInfo | None = self.Trans.SymbolTable.lookup(elem_type_node.id) + if sym_entry and isinstance(sym_entry, CTypeInfo) and sym_entry.IsFuncPtr: + return _ir.IntType(8).as_pointer(), elem_type_info + return Gen.structs[elem_type_node.id], elem_type_info + + # str → i8* + if handle_str and isinstance(elem_type_node, ast.Name) and elem_type_node.id == 'str': + return _ir.PointerType(_ir.IntType(8)), elem_type_info + + # 函数指针检查 + if check_func_ptr and elem_type_info and elem_type_info.IsFuncPtr: + return _ir.IntType(8).as_pointer(), elem_type_info + + # 回退到 CInt + if elem_type_info is None and fallback_to_cint: + elem_type_info = CTypeInfo() + elem_type_info.BaseType = t.CInt() + + elem_type: Any = Gen._ctype_to_llvm(elem_type_info) + if isinstance(elem_type, _ir.VoidType): + elem_type = _ir.IntType(void_fallback_width) + + return elem_type, elem_type_info + + def ParseArrayCount( + self, + count_node: ast.expr | None, + Gen: Any, + value_node: ast.expr | None = None, + *, + mode: str = 'global', + ) -> int: + """解析数组计数,返回计数(默认 1)。 + + 统一处理 Constant/Name/Attribute/BinOp/None 等形式。 + None 或 Constant(None) 时从 value_node 推断(List 长度或 str 长度+1)。 + + Args: + count_node: 计数 AST 节点 + value_node: 赋值右侧值节点(用于 count_node 为 None 时推断) + mode: 'global' 使用 _eval_global_count + SymbolTable + _define_constants; + 'local' 使用 TryEvalConstExpr + """ + # None 或 Constant(None) → 从 value_node 推断 + if count_node is None or (isinstance(count_node, ast.Constant) and count_node.value is None): + if value_node and isinstance(value_node, ast.List): + return len(value_node.elts) + if value_node and isinstance(value_node, ast.Constant) and isinstance(value_node.value, str): + return len(value_node.value) + 1 + return 1 + + # Constant(int) + if isinstance(count_node, ast.Constant) and isinstance(count_node.value, int): + return count_node.value + + if mode == 'global': + # Name → SymbolTable + _define_constants + if isinstance(count_node, ast.Name): + ArrayCount: int = 1 + if self.Trans.SymbolTable.has(count_node.id): + sym_info: Any = self.Trans.SymbolTable[count_node.id] + if isinstance(sym_info.value, int): + ArrayCount = sym_info.value + if ArrayCount == 1 and count_node.id in Gen._define_constants: + def_val: Any = Gen._define_constants[count_node.id] + # 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 覆盖 + try: + if hasattr(Gen, 'module') and count_node.id in Gen.module.globals: + _gv: Any = Gen.module.globals[count_node.id] + if getattr(_gv, 'initializer', None) is not None: + _iv: Any = _gv.initializer + if hasattr(_iv, 'constant') and isinstance(_iv.constant, int): + def_val = _iv.constant + except Exception: + pass + if isinstance(def_val, int): + ArrayCount = def_val + return ArrayCount + # Attribute / BinOp → _eval_global_count + if isinstance(count_node, (ast.Attribute, ast.BinOp)): + eval_fn: Any = getattr(self, '_eval_global_count', None) + if eval_fn is not None: + ev: int | None = eval_fn(count_node, Gen) + if ev is not None: + return ev + return 1 + else: + # local mode → TryEvalConstExpr + eval_count: Any = CTypeInfo.TryEvalConstExpr(count_node, self.Trans.SymbolTable) + if eval_count is not None and isinstance(eval_count, int) and eval_count > 0: + return eval_count + return 1 + + return 1 + + def ResolveAnnotationType(self, annotation: ast.expr) -> CTypeInfo | None: + """解析注解类型,BinOp(BitOr) 优先使用 MergeTypes,其他使用 FromNode。 + + 统一处理函数返回类型和参数类型的 BinOp 联合类型解析。 + """ + if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + merger: Any = getattr(self.Trans, 'TypeMergeHandler', None) + if merger: + info: CTypeInfo | None = merger.MergeTypes(annotation) + if info is not None and isinstance(info, CTypeInfo): + return info + return CTypeInfo.FromNode(annotation, self.Trans.SymbolTable) + + def CollectAnnAssignMember( + self, item: ast.AST, Gen: Any + ) -> tuple[str, _ir.Type, CTypeInfo | None] | None: + """从 ast.AnnAssign 节点解析成员信息。 + + 返回 (VarName, MemberType, TypeInfo);TypeInfo 为 None 表示解析回退到 i32。 + 非 AnnAssign/Name 目标时返回 None。 + """ + if not isinstance(item, ast.AnnAssign) or not isinstance(item.target, ast.Name): + return None + VarName: str = item.target.id + try: + TypeInfo: CTypeInfo | None = self.ResolveAnnotationType(item.annotation) + if TypeInfo is None: + TypeInfo = CTypeInfo() + TypeInfo.BaseType = t.CInt() + MemberType: _ir.Type = Gen._ctype_to_llvm(TypeInfo) + if isinstance(MemberType, _ir.VoidType): + MemberType = _ir.PointerType(_ir.IntType(8)) + return VarName, MemberType, TypeInfo + except Exception as e: + _vlog().warning(f"HandlesBase: 忽略异常 {e}", exc_info=e) + return VarName, _ir.IntType(32), None + + def LookupFunctionSymbol(self, name: str, *, module_path: str | None = None) -> CTypeInfo | None: + """查找函数符号,先尝试 module_path.name,再回退到 name。 + + 统一处理 HandlesExprCall / HandlesAssign 中重复的二级查找模式。 + 返回 CTypeInfo(不限定 IsFunction),由调用方检查标志位。 + """ + st = self.Trans.SymbolTable + if module_path: + sym: CTypeInfo | None = st.lookup(f'{module_path}.{name}') + if sym: + return sym + return st.lookup(name) + + def BuildLLVMFuncTypeFromSig( + self, + sym_info: CTypeInfo, + Gen: Any, + *, + mangled_name: str | None = None, + use_infer_fallback: bool = False, + ) -> tuple[Any, list[Any], bool] | None: + """从 CTypeInfo 函数签名构建 LLVM 函数类型。 + + 返回 (ret_type, llvm_param_types, is_variadic),非函数返回 None。 + 统一处理 FuncPtrReturn/FuncPtrParams → ToLLVM 转换、VoidType 回退。 + + Args: + mangled_name: 用于 _infer_return_type + stub 查找回退 + use_infer_fallback: 为 True 时启用 _infer_return_type + stub 查找回退链 + """ + if not sym_info.IsFunction: + return None + is_variadic: bool = sym_info.IsVariadic + ret_type_info = sym_info.FuncPtrReturn + if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType: + ret_type: Any = ret_type_info.ToLLVM(Gen) + elif use_infer_fallback and mangled_name: + inferred: Any = Gen._infer_return_type(mangled_name) + if isinstance(inferred, _ir.IntType) and inferred.width == 32: + try: + stub_ft: Any = self.Trans.ImportHandler._LookupStubFuncType(mangled_name, Gen) + if stub_ft and hasattr(stub_ft, 'return_type'): + inferred = stub_ft.return_type + except Exception: + pass + ret_type = inferred + else: + ret_type = Gen._CType2LLVM('i32', False) + param_type_infos = [pt for _, pt in (sym_info.FuncPtrParams or [])] + if isinstance(ret_type, _ir.VoidType): + ret_type = _ir.IntType(32) + llvm_param_types: list[Any] = [] + for pt in param_type_infos: + if isinstance(pt, CTypeInfo) and pt.BaseType: + lp: Any = pt.ToLLVM(Gen) + else: + lp = Gen._CType2LLVM(pt if isinstance(pt, str) else 'i32', '*' in pt if isinstance(pt, str) else False) + if isinstance(lp, _ir.VoidType): + lp = _ir.IntType(8).as_pointer() + llvm_param_types.append(lp) + return ret_type, llvm_param_types, is_variadic + + def GetOrCreateFuncDecl( + self, + name: str, + ret_type: Any, + param_types: list[Any], + Gen: Any, + *, + is_variadic: bool = False, + replace_name: str | None = None, + ) -> Any: + """创建或替换 LLVM 函数声明。 + + 若 name 已存在且类型不匹配,通过 _replace_function_decl 替换。 + replace_name 传递给 _replace_function_decl(通常为未 mangle 的 func_name)。 + """ + if name not in Gen.functions: + func_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic) + func_decl = _ir.Function(Gen.module, func_type, name=name) + Gen.functions[name] = func_decl + else: + existing = Gen.functions[name] + existing_type = getattr(existing, 'ftype', None) + new_type = _ir.FunctionType(ret_type, param_types, var_arg=is_variadic) + if existing_type and existing_type != new_type: + replaced = self.Trans.FunctionHandler._replace_function_decl(Gen, replace_name or name, new_type) + if replaced and replaced != existing: + Gen.functions[name] = replaced + return Gen.functions[name] + + def GetOrCreateStubFuncDecl( + self, + decl_name: str, + stub_func_type: Any, + Gen: Any, + *, + alias: str | None = None, + check_existing: bool = True, + ) -> Any: + """创建 stub 函数声明,可选注册别名。 + + check_existing=False 时跳过存在性检查(用于确定不存在的场景)。 + """ + if check_existing and decl_name in Gen.functions: + func_decl = Gen.functions[decl_name] + else: + func_decl = _ir.Function(Gen.module, stub_func_type, name=decl_name) + Gen.functions[decl_name] = func_decl + if alias and alias != decl_name: + if not check_existing or alias not in Gen.functions: + Gen.functions[alias] = func_decl + return func_decl + + StrictMode: bool = _config.mode == 'strict' \ No newline at end of file diff --git a/lib/core/Handles/HandlesBody.py b/lib/core/Handles/HandlesBody.py index 86b54d8..0232dbb 100644 --- a/lib/core/Handles/HandlesBody.py +++ b/lib/core/Handles/HandlesBody.py @@ -1,77 +1,77 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class BodyHandle(BaseHandle): - def __init__(self, translator: "Translator") -> None: - super().__init__(translator) - - def HandleBodyLlvm(self, Body: list[ast.stmt]) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - for Node in Body: - if Gen.builder and Gen.builder.block.is_terminated: - break - Gen._set_node_info(Node) - try: - if isinstance(Node, ast.Expr): - self.HandleExprLlvm(Node.value) - elif isinstance(Node, ast.Return): - self.Trans.ReturnHandler._HandleReturnLlvm(Node) - elif isinstance(Node, ast.Assign): - self.Trans.AssignHandler._HandleAssignLlvm(Node) - elif isinstance(Node, ast.AugAssign): - self.Trans.AugAssignHandler._HandleAugAssignLlvm(Node) - elif isinstance(Node, ast.AnnAssign): - self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(Node) - elif isinstance(Node, ast.If): - self.Trans.IfHandler._HandleIfLlvm(Node) - elif isinstance(Node, ast.For): - self.Trans.ForHandler._HandleForLlvm(Node) - elif isinstance(Node, ast.While): - self.Trans.WhileHandler._HandleWhileLlvm(Node) - elif isinstance(Node, ast.Break): - if Gen.loop_break_targets: - Gen.builder.branch(Gen.loop_break_targets[-1]) - elif isinstance(Node, ast.Continue): - if Gen.loop_continue_targets: - Gen.builder.branch(Gen.loop_continue_targets[-1]) - elif isinstance(Node, ast.With): - self.Trans.WithHandler._HandleWithLlvm(Node) - elif isinstance(Node, ast.ClassDef): - pass - elif getattr(ast, 'Match', None) and isinstance(Node, ast.Match): - self.Trans.MatchHandler._HandleMatchLlvm(Node) - elif isinstance(Node, ast.Try): - self.Trans.TryHandler._HandleTryLlvm(Node) - elif isinstance(Node, ast.Raise): - self.Trans.RaiseHandler._HandleRaiseLlvm(Node) - elif isinstance(Node, ast.Assert): - self.Trans.AssertHandler._HandleAssertLlvm(Node) - elif isinstance(Node, ast.Global): - self.Trans.ForHandler._HandleGlobalLlvm(Node) - elif isinstance(Node, ast.FunctionDef): - self.Trans.ForHandler._HandleNestedFunctionLlvm(Node) - elif isinstance(Node, ast.Nonlocal): - self.Trans.ForHandler._HandleNonlocalLlvm(Node) - elif isinstance(Node, ast.Delete): - self.Trans.DeleteHandler._HandleDeleteLlvm(Node) - except Exception as e: - lineno: int = getattr(Node, 'lineno', 0) - source_line: str | None = Gen._get_source_line(lineno) - src_file: str = Gen._current_source_file or '' - src_path: str = src_file if src_file else 'unknown' - line_info: str = "源代码 (%s, line %d)" % (src_path, lineno) - if source_line: - line_info += ":\n %d | %s" % (lineno, source_line) - self.Trans._ErrorStack.append((type(e).__name__, str(e), line_info)) - raise - if Gen.builder and not Gen.builder.block.is_terminated: - Gen._EmitTempFrees() - - def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None: +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import vast as ast +import llvmlite.ir as ir + + +class BodyHandle(BaseHandle): + def __init__(self, translator: "Translator") -> None: + super().__init__(translator) + + def HandleBodyLlvm(self, Body: list[ast.stmt]) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + for Node in Body: + if Gen.builder and Gen.builder.block.is_terminated: + break + Gen._set_node_info(Node) + try: + if isinstance(Node, ast.Expr): + self.HandleExprLlvm(Node.value) + elif isinstance(Node, ast.Return): + self.Trans.ReturnHandler._HandleReturnLlvm(Node) + elif isinstance(Node, ast.Assign): + self.Trans.AssignHandler._HandleAssignLlvm(Node) + elif isinstance(Node, ast.AugAssign): + self.Trans.AugAssignHandler._HandleAugAssignLlvm(Node) + elif isinstance(Node, ast.AnnAssign): + self.Trans.AnnAssignHandler._HandleAnnAssignLlvm(Node) + elif isinstance(Node, ast.If): + self.Trans.IfHandler._HandleIfLlvm(Node) + elif isinstance(Node, ast.For): + self.Trans.ForHandler._HandleForLlvm(Node) + elif isinstance(Node, ast.While): + self.Trans.WhileHandler._HandleWhileLlvm(Node) + elif isinstance(Node, ast.Break): + if Gen.loop_break_targets: + Gen.builder.branch(Gen.loop_break_targets[-1]) + elif isinstance(Node, ast.Continue): + if Gen.loop_continue_targets: + Gen.builder.branch(Gen.loop_continue_targets[-1]) + elif isinstance(Node, ast.With): + self.Trans.WithHandler._HandleWithLlvm(Node) + elif isinstance(Node, ast.ClassDef): + pass + elif getattr(ast, 'Match', None) and isinstance(Node, ast.Match): + self.Trans.MatchHandler._HandleMatchLlvm(Node) + elif isinstance(Node, ast.Try): + self.Trans.TryHandler._HandleTryLlvm(Node) + elif isinstance(Node, ast.Raise): + self.Trans.RaiseHandler._HandleRaiseLlvm(Node) + elif isinstance(Node, ast.Assert): + self.Trans.AssertHandler._HandleAssertLlvm(Node) + elif isinstance(Node, ast.Global): + self.Trans.ForHandler._HandleGlobalLlvm(Node) + elif isinstance(Node, ast.FunctionDef): + self.Trans.ForHandler._HandleNestedFunctionLlvm(Node) + elif isinstance(Node, ast.Nonlocal): + self.Trans.ForHandler._HandleNonlocalLlvm(Node) + elif isinstance(Node, ast.Delete): + self.Trans.DeleteHandler._HandleDeleteLlvm(Node) + except Exception as e: + lineno: int = getattr(Node, 'lineno', 0) + source_line: str | None = Gen._get_source_line(lineno) + src_file: str = Gen._current_source_file or '' + src_path: str = src_file if src_file else 'unknown' + line_info: str = "源代码 (%s, line %d)" % (src_path, lineno) + if source_line: + line_info += ":\n %d | %s" % (lineno, source_line) + self.Trans._ErrorStack.append((type(e).__name__, str(e), line_info)) + raise + if Gen.builder and not Gen.builder.block.is_terminated: + Gen._EmitTempFrees() + + def HandleExprLlvm(self, Node: ast.expr, VarType: ir.Type | None = None) -> ir.Value | None: return self.Trans.ExprHandler.HandleExprLlvm(Node, VarType) \ No newline at end of file diff --git a/lib/core/Handles/HandlesClassDef.py b/lib/core/Handles/HandlesClassDef.py index 3f061d6..2608592 100644 --- a/lib/core/Handles/HandlesClassDef.py +++ b/lib/core/Handles/HandlesClassDef.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin -import ast +import vast as ast import copy import llvmlite.ir as ir from lib.core.Exportable import EnumMember as ExportEnumMember @@ -247,125 +247,125 @@ class ClassHandle(BaseHandle): Gen._struct_sha1_map[spec_name] = self.Trans._module_sha1 return spec_name - def _resolve_base_kind(self, base_name: str, Gen: LlvmGeneratorMixin) -> str | None: - """解析基类名称的类型种类 - - 查询顺序: - 1. _t_type_symbols(from t import CEnum as en) - 2. t 模块属性(t.CEnum / t.CUnion / t.CStruct / t.REnum) - 3. 返回 None 表示不是已知标记基类 - - Returns: - 'enum' | 'union' | 'renum' | 'struct' | None - """ - # 1) 查 _t_type_symbols(别名导入) - symtab: object = self.Trans.SymbolTable - cls: type | None = symtab._t_type_symbols.get(base_name) - if cls is not None: - if issubclass(cls, (t.CEnum, t.REnum)): - return 'renum' if issubclass(cls, t.REnum) else 'enum' - if issubclass(cls, t.CUnion): - return 'union' - if issubclass(cls, t.CStruct): - return 'struct' - # CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记, - # 不应被编译为真实结构体。 - if issubclass(cls, t.CType): - return 'ctype_marker' - - # 2) 查 t 模块属性(直接引用 t.CEnum 等) - t_cls: type | None = getattr(t, base_name, None) - if isinstance(t_cls, type) and issubclass(t_cls, t.CType): - if issubclass(t_cls, (t.CEnum, t.REnum)): - return 'renum' if issubclass(t_cls, t.REnum) else 'enum' - if issubclass(t_cls, t.CUnion): - return 'union' - if issubclass(t_cls, t.CStruct): - return 'struct' - # CType 及其子类是"类型强转"标记,不编译为结构体。 - return 'ctype_marker' - - return None - - @staticmethod - def _is_classname_ctype_marker(class_name: str) -> bool: - """检查类名是否是 t.CType 的"类型强转"标记子类。 - - 只有 position 不含 BASE 的纯修饰符/标记类型(CPtr/CVolatile/CConst/ - CInline/CStatic/CExtern/CExport/CRegister/CAuto/_CTypedef/CTypeDefault 等) - 才应跳过编译。有 BASE position 的基本类型(CInt/CChar/CSizeT/CLong 等) - 有具体大小,应被正常编译。CType 基类本身无 bases,base 检测无法触发, - 需要直接按类名检查。 - - 注意:CTypeRegistry.GetClassByName 会跳过 CType 本身和 CTypeDefault, - 所以这里直接用 getattr(t, name) 检查 t 模块属性。 - - Returns: - True 如果 class_name 是 CType 标记子类名(应跳过编译) - """ - if not class_name: - return False - # 直接查 t 模块属性(CTypeRegistry._build 会跳过 CType/CTypeDefault/BigEndian/LittleEndian) - t_cls: type | None = getattr(t, class_name, None) - if not isinstance(t_cls, type) or not issubclass(t_cls, t.CType): - return False - if issubclass(t_cls, (t.CStruct, t.CEnum, t.REnum, t.CUnion)): - return False - # 基本类型(position 含 BASE 且 Size > 0)有具体大小,不应跳过 - # CVoid 虽含 BASE 但 Size=0,CType Size=None,仍需跳过 - if t.CType.BASE in t_cls.position: - try: - inst = t_cls() - size_val = getattr(inst, 'Size', None) - if size_val is not None and size_val > 0: - return False - except Exception: - pass - return True - - def _resolve_decorator_kind(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> str | None: - """从装饰器列表中解析结构体类型种类 - - 支持 @t.CStruct, @t.CUnion, @t.CEnum, @t.REnum - 也支持 from t import CStruct 等别名形式 - - Returns: - 'enum' | 'union' | 'renum' | 'struct' | None - """ - if not hasattr(Node, 'decorator_list') or not Node.decorator_list: - return None - symtab: object = self.Trans.SymbolTable - for decorator in Node.decorator_list: - attr_name: str | None = None - # @t.CStruct 形式 - if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name): - if IsTModule(decorator.value.id, symtab): - attr_name = decorator.attr - # @CStruct 形式 (from t import CStruct) - elif isinstance(decorator, ast.Name): - cls: type | None = getattr(t, decorator.id, None) - if cls is None and hasattr(symtab, '_t_type_symbols'): - cls = symtab._t_type_symbols.get(decorator.id) - if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType): - attr_name = cls.__name__ - if attr_name: - # 查 _t_type_symbols 和 t 模块属性以确定种类 - resolved_cls: type | None = None - if hasattr(symtab, '_t_type_symbols'): - resolved_cls = symtab._t_type_symbols.get(attr_name) - if resolved_cls is None: - resolved_cls = getattr(t, attr_name, None) - if resolved_cls is not None and isinstance(resolved_cls, type): - if issubclass(resolved_cls, t.REnum): - return 'renum' - if issubclass(resolved_cls, t.CEnum): - return 'enum' - if issubclass(resolved_cls, t.CUnion): - return 'union' - if issubclass(resolved_cls, t.CStruct): - return 'struct' - return None - + def _resolve_base_kind(self, base_name: str, Gen: LlvmGeneratorMixin) -> str | None: + """解析基类名称的类型种类 + + 查询顺序: + 1. _t_type_symbols(from t import CEnum as en) + 2. t 模块属性(t.CEnum / t.CUnion / t.CStruct / t.REnum) + 3. 返回 None 表示不是已知标记基类 + + Returns: + 'enum' | 'union' | 'renum' | 'struct' | None + """ + # 1) 查 _t_type_symbols(别名导入) + symtab: object = self.Trans.SymbolTable + cls: type | None = symtab._t_type_symbols.get(base_name) + if cls is not None: + if issubclass(cls, (t.CEnum, t.REnum)): + return 'renum' if issubclass(cls, t.REnum) else 'enum' + if issubclass(cls, t.CUnion): + return 'union' + if issubclass(cls, t.CStruct): + return 'struct' + # CType 及其子类(CChar/CInt/CVoid/CPtr 等)是"类型强转"标记, + # 不应被编译为真实结构体。 + if issubclass(cls, t.CType): + return 'ctype_marker' + + # 2) 查 t 模块属性(直接引用 t.CEnum 等) + t_cls: type | None = getattr(t, base_name, None) + if isinstance(t_cls, type) and issubclass(t_cls, t.CType): + if issubclass(t_cls, (t.CEnum, t.REnum)): + return 'renum' if issubclass(t_cls, t.REnum) else 'enum' + if issubclass(t_cls, t.CUnion): + return 'union' + if issubclass(t_cls, t.CStruct): + return 'struct' + # CType 及其子类是"类型强转"标记,不编译为结构体。 + return 'ctype_marker' + + return None + + @staticmethod + def _is_classname_ctype_marker(class_name: str) -> bool: + """检查类名是否是 t.CType 的"类型强转"标记子类。 + + 只有 position 不含 BASE 的纯修饰符/标记类型(CPtr/CVolatile/CConst/ + CInline/CStatic/CExtern/CExport/CRegister/CAuto/_CTypedef/CTypeDefault 等) + 才应跳过编译。有 BASE position 的基本类型(CInt/CChar/CSizeT/CLong 等) + 有具体大小,应被正常编译。CType 基类本身无 bases,base 检测无法触发, + 需要直接按类名检查。 + + 注意:CTypeRegistry.GetClassByName 会跳过 CType 本身和 CTypeDefault, + 所以这里直接用 getattr(t, name) 检查 t 模块属性。 + + Returns: + True 如果 class_name 是 CType 标记子类名(应跳过编译) + """ + if not class_name: + return False + # 直接查 t 模块属性(CTypeRegistry._build 会跳过 CType/CTypeDefault/BigEndian/LittleEndian) + t_cls: type | None = getattr(t, class_name, None) + if not isinstance(t_cls, type) or not issubclass(t_cls, t.CType): + return False + if issubclass(t_cls, (t.CStruct, t.CEnum, t.REnum, t.CUnion)): + return False + # 基本类型(position 含 BASE 且 Size > 0)有具体大小,不应跳过 + # CVoid 虽含 BASE 但 Size=0,CType Size=None,仍需跳过 + if t.CType.BASE in t_cls.position: + try: + inst = t_cls() + size_val = getattr(inst, 'Size', None) + if size_val is not None and size_val > 0: + return False + except Exception: + pass + return True + + def _resolve_decorator_kind(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> str | None: + """从装饰器列表中解析结构体类型种类 + + 支持 @t.CStruct, @t.CUnion, @t.CEnum, @t.REnum + 也支持 from t import CStruct 等别名形式 + + Returns: + 'enum' | 'union' | 'renum' | 'struct' | None + """ + if not hasattr(Node, 'decorator_list') or not Node.decorator_list: + return None + symtab: object = self.Trans.SymbolTable + for decorator in Node.decorator_list: + attr_name: str | None = None + # @t.CStruct 形式 + if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name): + if IsTModule(decorator.value.id, symtab): + attr_name = decorator.attr + # @CStruct 形式 (from t import CStruct) + elif isinstance(decorator, ast.Name): + cls: type | None = getattr(t, decorator.id, None) + if cls is None and hasattr(symtab, '_t_type_symbols'): + cls = symtab._t_type_symbols.get(decorator.id) + if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType): + attr_name = cls.__name__ + if attr_name: + # 查 _t_type_symbols 和 t 模块属性以确定种类 + resolved_cls: type | None = None + if hasattr(symtab, '_t_type_symbols'): + resolved_cls = symtab._t_type_symbols.get(attr_name) + if resolved_cls is None: + resolved_cls = getattr(t, attr_name, None) + if resolved_cls is not None and isinstance(resolved_cls, type): + if issubclass(resolved_cls, t.REnum): + return 'renum' + if issubclass(resolved_cls, t.CEnum): + return 'enum' + if issubclass(resolved_cls, t.CUnion): + return 'union' + if issubclass(resolved_cls, t.CStruct): + return 'struct' + return None + def _resolve_class_flags(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> tuple[bool, bool, str | None, bool]: """解析类的 Object/CVTable 标志和父类信息 @@ -467,8 +467,8 @@ class ClassHandle(BaseHandle): if IsCVTable: Gen.class_vtable.add(ClassName) # 沿继承链向上传播,将所有祖先类加入 vtable - visited: set[str] = {ClassName} - ancestor: str | None = ParentClassName + visited: set[str] = {ClassName} + ancestor: str | None = ParentClassName while ancestor and ancestor not in visited: visited.add(ancestor) Gen.class_vtable.add(ancestor) @@ -550,44 +550,44 @@ class ClassHandle(BaseHandle): if IsRenum: self._EmitREnumLlvm(Node, Gen) return - IsCpythonObject: bool - IsCVTable: bool - ParentClassName: str | None - IsNoVTable: bool - IsCpythonObject, IsCVTable, ParentClassName, IsNoVTable = self._resolve_class_flags(Node, Gen) - # 跟踪正在发射的类,防止递归特化时 _generate_structs 过早为空成员类设置 body - Gen._classes_in_progress.add(ClassName) - # 标记正在收集字段,阻止继承处理(_ResolveGenericSlice → _specialize_generic_class) - # 和 CollectAnnAssignMember 触发的嵌套 _generate_structs 用不完整 class_members 调用 set_body - Gen._collecting_members_set.add(ClassName) - if ClassName not in Gen.class_methods: - Gen.class_methods[ClassName] = [] - else: - # 防御性清除:移除导入阶段可能添加的构造函数(__new__/__init__/__before_init__)。 - # 构造函数不参与虚分派,放入 vtable 会导致子类与基类 vtable 大小不一致, - # 索引偏移破坏多态分派(如 Module 有 __new__/__init__ 使 vtable=7,而 AST 无它们 vtable=5, - # 调用方按 AST 布局取 append@idx4 实际取到 Module.dump@idx4)。 - Gen.class_methods[ClassName] = [ - m for m in Gen.class_methods[ClassName] - if m.split('.')[-1] not in ('__new__', '__init__', '__before_init__') - ] - # 当前文件定义的类是权威定义,覆盖之前导入阶段可能添加的外部声明。 - # 关键:如果本地类是 @t.NoVTable 但同名导入类有 vtable(名称冲突), - # 必须清除 vtable 状态,否则 _generate_structs 会错误添加 vtable 指针。 - if IsNoVTable: - Gen.class_vtable.discard(ClassName) - Gen._cross_module_vtable_classes.discard(ClassName) - Gen._cross_module_novtable.add(ClassName) - # 清除可能从导入 stub 加载的旧 struct body(含错误 vtable 指针), - # 让 _generate_structs 用本地 class_members 重新生成 - _old_st = Gen.structs.get(ClassName) - if isinstance(_old_st, ir.IdentifiedStructType) and _old_st.elements is not None: - _old_st._elements = None - _ih = getattr(Gen, '_import_handler_ref', None) - if _ih is not None: - _ck = (id(Gen), ClassName) - if _ck in _ih._struct_Load_cache: - del _ih._struct_Load_cache[_ck] + IsCpythonObject: bool + IsCVTable: bool + ParentClassName: str | None + IsNoVTable: bool + IsCpythonObject, IsCVTable, ParentClassName, IsNoVTable = self._resolve_class_flags(Node, Gen) + # 跟踪正在发射的类,防止递归特化时 _generate_structs 过早为空成员类设置 body + Gen._classes_in_progress.add(ClassName) + # 标记正在收集字段,阻止继承处理(_ResolveGenericSlice → _specialize_generic_class) + # 和 CollectAnnAssignMember 触发的嵌套 _generate_structs 用不完整 class_members 调用 set_body + Gen._collecting_members_set.add(ClassName) + if ClassName not in Gen.class_methods: + Gen.class_methods[ClassName] = [] + else: + # 防御性清除:移除导入阶段可能添加的构造函数(__new__/__init__/__before_init__)。 + # 构造函数不参与虚分派,放入 vtable 会导致子类与基类 vtable 大小不一致, + # 索引偏移破坏多态分派(如 Module 有 __new__/__init__ 使 vtable=7,而 AST 无它们 vtable=5, + # 调用方按 AST 布局取 append@idx4 实际取到 Module.dump@idx4)。 + Gen.class_methods[ClassName] = [ + m for m in Gen.class_methods[ClassName] + if m.split('.')[-1] not in ('__new__', '__init__', '__before_init__') + ] + # 当前文件定义的类是权威定义,覆盖之前导入阶段可能添加的外部声明。 + # 关键:如果本地类是 @t.NoVTable 但同名导入类有 vtable(名称冲突), + # 必须清除 vtable 状态,否则 _generate_structs 会错误添加 vtable 指针。 + if IsNoVTable: + Gen.class_vtable.discard(ClassName) + Gen._cross_module_vtable_classes.discard(ClassName) + Gen._cross_module_novtable.add(ClassName) + # 清除可能从导入 stub 加载的旧 struct body(含错误 vtable 指针), + # 让 _generate_structs 用本地 class_members 重新生成 + _old_st = Gen.structs.get(ClassName) + if isinstance(_old_st, ir.IdentifiedStructType) and _old_st.elements is not None: + _old_st._elements = None + _ih = getattr(Gen, '_import_handler_ref', None) + if _ih is not None: + _ck = (id(Gen), ClassName) + if _ck in _ih._struct_Load_cache: + del _ih._struct_Load_cache[_ck] Gen.class_members[ClassName] = [] Gen.class_member_defaults[ClassName] = {} Gen.class_member_signeds[ClassName] = {} @@ -707,13 +707,13 @@ class ClassHandle(BaseHandle): if method_name not in covered_names: new_methods.append(m) Gen.class_methods[ClassName] = new_methods - # 提取首个裸字符串字面量作为结构体 __doc__ docstring - if (Node.body and isinstance(Node.body[0], ast.Expr) - and isinstance(Node.body[0].value, ast.Constant) - and isinstance(Node.body[0].value.value, str)): - Gen._create_doc_global(ClassName, Node.body[0].value.value) - else: - Gen._create_doc_global(ClassName, None) + # 提取首个裸字符串字面量作为结构体 __doc__ docstring + if (Node.body and isinstance(Node.body[0], ast.Expr) + and isinstance(Node.body[0].value, ast.Constant) + and isinstance(Node.body[0].value.value, str)): + Gen._create_doc_global(ClassName, Node.body[0].value.value) + else: + Gen._create_doc_global(ClassName, None) # 解析 __provides__/__requires__/__require_must__ 编译期元数据 for item in Node.body: if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): @@ -1081,35 +1081,35 @@ class ClassHandle(BaseHandle): continue self._scan_node_for_self_assign(child, ClassName, existing_members, Gen) - def _EmitUnionLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> None: - ClassName: str = Node.name - union_member_types: list[ir.Type] = [] - for item in Node.body: - if isinstance(item, ast.ClassDef): - nested_class_name: str = item.name - nested_member_types: list[ir.Type] = [] - for nested_item in item.body: - parsed = self.CollectAnnAssignMember(nested_item, Gen) - if parsed: - nested_member_types.append(parsed[1]) - if nested_member_types: - nested_struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, f"{ClassName}_{nested_class_name}") - nested_struct_type.set_body(*nested_member_types) - Gen.structs[f"{ClassName}_{nested_class_name}"] = nested_struct_type - union_member_types.append(nested_struct_type) - nested_class_full_name: str = f"{ClassName}_{nested_class_name}" - if nested_class_full_name not in Gen.class_members: - Gen.class_members[nested_class_full_name] = [] - if nested_class_full_name not in Gen.class_member_signeds: - Gen.class_member_signeds[nested_class_full_name] = {} - for nested_item in item.body: - parsed = self.CollectAnnAssignMember(nested_item, Gen) - if parsed: - VarName, MemberType, TypeInfo = parsed - Gen.class_members[nested_class_full_name].append((VarName, MemberType)) - if TypeInfo and hasattr(TypeInfo.BaseType, 'IsSigned'): - Gen.class_member_signeds[nested_class_full_name][VarName] = TypeInfo.BaseType.IsSigned - else: + def _EmitUnionLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> None: + ClassName: str = Node.name + union_member_types: list[ir.Type] = [] + for item in Node.body: + if isinstance(item, ast.ClassDef): + nested_class_name: str = item.name + nested_member_types: list[ir.Type] = [] + for nested_item in item.body: + parsed = self.CollectAnnAssignMember(nested_item, Gen) + if parsed: + nested_member_types.append(parsed[1]) + if nested_member_types: + nested_struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(Gen.module, f"{ClassName}_{nested_class_name}") + nested_struct_type.set_body(*nested_member_types) + Gen.structs[f"{ClassName}_{nested_class_name}"] = nested_struct_type + union_member_types.append(nested_struct_type) + nested_class_full_name: str = f"{ClassName}_{nested_class_name}" + if nested_class_full_name not in Gen.class_members: + Gen.class_members[nested_class_full_name] = [] + if nested_class_full_name not in Gen.class_member_signeds: + Gen.class_member_signeds[nested_class_full_name] = {} + for nested_item in item.body: + parsed = self.CollectAnnAssignMember(nested_item, Gen) + if parsed: + VarName, MemberType, TypeInfo = parsed + Gen.class_members[nested_class_full_name].append((VarName, MemberType)) + if TypeInfo and hasattr(TypeInfo.BaseType, 'IsSigned'): + Gen.class_member_signeds[nested_class_full_name][VarName] = TypeInfo.BaseType.IsSigned + else: Gen.class_member_signeds[nested_class_full_name][VarName] = None if union_member_types: max_size: int = 0 diff --git a/lib/core/Handles/HandlesDelete.py b/lib/core/Handles/HandlesDelete.py index f4871d9..e462dcc 100644 --- a/lib/core/Handles/HandlesDelete.py +++ b/lib/core/Handles/HandlesDelete.py @@ -1,102 +1,102 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta -import ast -import llvmlite.ir as ir - - -class DeleteHandle(BaseHandle): - def _HandleDeleteLlvm(self, Node: ast.Delete) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - for target in Node.targets: - if isinstance(target, ast.Subscript): - ClassName: str | None = self.Trans.ExprHandler._get_var_class(target.value, Gen) - if ClassName and Gen._has_function(f'{ClassName}.__delitem__'): - 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(整数)的情况:联合类型 | t.CPtr 降级后可能被 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 isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - Gen.builder.call(Gen._get_function(f'{ClassName}.__delitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__delitem__") - elif isinstance(target, ast.Name): - ClassName: str | None = Gen.var_struct_class.get(target.id) - if ClassName and Gen._has_function(f'{ClassName}.__delete__'): - obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target) - if obj_val: - # 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 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 isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - Gen.builder.call(Gen._get_function(f'{ClassName}.__delete__'), [obj_val], name=f"call_{ClassName}.__delete__") - elif isinstance(target, ast.Attribute): - # 检查 property deleter - AttrName: str = target.attr - ClassName: str | None = None - obj_val_for_prop: ir.Value | None = None - - if isinstance(target.value, ast.Name) and target.value.id == 'self': - # del self.attr — 检查当前类的 property deleter - ClassName = self.Trans._CurrentCpythonObjectClass - if ClassName: - PropKey: str = f'{ClassName}.{AttrName}' - PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) - if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: - SelfVar: ir.Value | None = Gen._get_var_ptr('self') - if SelfVar: - SelfPtr: ir.Value = Gen._load(SelfVar, name="self") - DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del') - if DeleterFunc and SelfPtr: - Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}") - continue - else: - # del obj.attr — 检查 obj 类的 property deleter - ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen) - if ClassName: - PropKey: str = f'{ClassName}.{AttrName}' - PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) - if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: - obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value) - if obj_val: - DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del') - if DeleterFunc: - Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}") - continue - - # 原有的 __del__ 处理逻辑 - obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target) - if obj_val: - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.PointerType): - obj_val = Gen._load(obj_val, name="Load_del_ptr") - ClassName = None - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - for CN, ST in Gen.structs.items(): - if obj_val.type.pointee == ST: - ClassName = CN - break - elif isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - if isinstance(target.value, ast.Name) and target.value.id == 'self': - AttrName = target.attr - SelfClassName: str | None = self.Trans._CurrentCpythonObjectClass - if SelfClassName and SelfClassName in Gen.class_members: - for member_name, member_type in Gen.class_members[SelfClassName]: - if member_name == AttrName: - for CN in Gen.structs: - if CN == AttrName or Gen._has_function(f'{CN}.__del__'): - ClassName = CN - break - break - if not ClassName: - for CN, ST in Gen.structs.items(): - if Gen._has_function(f'{CN}.__del__'): - ClassName = CN - break - if ClassName and Gen._has_function(f'{ClassName}.__del__'): - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta +import vast as ast +import llvmlite.ir as ir + + +class DeleteHandle(BaseHandle): + def _HandleDeleteLlvm(self, Node: ast.Delete) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + for target in Node.targets: + if isinstance(target, ast.Subscript): + ClassName: str | None = self.Trans.ExprHandler._get_var_class(target.value, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__delitem__'): + 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(整数)的情况:联合类型 | t.CPtr 降级后可能被 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 isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + Gen.builder.call(Gen._get_function(f'{ClassName}.__delitem__'), [obj_val, idx_val], name=f"call_{ClassName}.__delitem__") + elif isinstance(target, ast.Name): + ClassName: str | None = Gen.var_struct_class.get(target.id) + if ClassName and Gen._has_function(f'{ClassName}.__delete__'): + obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target) + if obj_val: + # 处理 obj_val 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 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 isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + Gen.builder.call(Gen._get_function(f'{ClassName}.__delete__'), [obj_val], name=f"call_{ClassName}.__delete__") + elif isinstance(target, ast.Attribute): + # 检查 property deleter + AttrName: str = target.attr + ClassName: str | None = None + obj_val_for_prop: ir.Value | None = None + + if isinstance(target.value, ast.Name) and target.value.id == 'self': + # del self.attr — 检查当前类的 property deleter + ClassName = self.Trans._CurrentCpythonObjectClass + if ClassName: + PropKey: str = f'{ClassName}.{AttrName}' + PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) + if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: + SelfVar: ir.Value | None = Gen._get_var_ptr('self') + if SelfVar: + SelfPtr: ir.Value = Gen._load(SelfVar, name="self") + DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del') + if DeleterFunc and SelfPtr: + Gen.builder.call(DeleterFunc, [SelfPtr], name=f"prop_del_{PropKey}") + continue + else: + # del obj.attr — 检查 obj 类的 property deleter + ClassName = self.Trans.ExprHandler._get_var_class(target.value, Gen) + if ClassName: + PropKey: str = f'{ClassName}.{AttrName}' + PropInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(PropKey) + if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList: + obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target.value) + if obj_val: + DeleterFunc: ir.Function | None = Gen._get_function(PropKey + '$del') + if DeleterFunc: + Gen.builder.call(DeleterFunc, [obj_val], name=f"prop_del_{PropKey}") + continue + + # 原有的 __del__ 处理逻辑 + obj_val: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(target) + if obj_val: + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.PointerType): + obj_val = Gen._load(obj_val, name="Load_del_ptr") + ClassName = None + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + for CN, ST in Gen.structs.items(): + if obj_val.type.pointee == ST: + ClassName = CN + break + elif isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + if isinstance(target.value, ast.Name) and target.value.id == 'self': + AttrName = target.attr + SelfClassName: str | None = self.Trans._CurrentCpythonObjectClass + if SelfClassName and SelfClassName in Gen.class_members: + for member_name, member_type in Gen.class_members[SelfClassName]: + if member_name == AttrName: + for CN in Gen.structs: + if CN == AttrName or Gen._has_function(f'{CN}.__del__'): + ClassName = CN + break + break + if not ClassName: + for CN, ST in Gen.structs.items(): + if Gen._has_function(f'{CN}.__del__'): + ClassName = CN + break + if ClassName and Gen._has_function(f'{ClassName}.__del__'): + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") Gen.builder.call(Gen._get_function(f'{ClassName}.__del__'), [obj_val], name=f"call_{ClassName}.__del__") \ No newline at end of file diff --git a/lib/core/Handles/HandlesExpr.py b/lib/core/Handles/HandlesExpr.py index 6e3ea35..af12896 100644 --- a/lib/core/Handles/HandlesExpr.py +++ b/lib/core/Handles/HandlesExpr.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -import ast +import vast as ast import re import llvmlite.ir as ir from lib.core.Handles.HandlesBase import BaseHandle diff --git a/lib/core/Handles/HandlesExprAsm.py b/lib/core/Handles/HandlesExprAsm.py index 03d19e9..05c85db 100644 --- a/lib/core/Handles/HandlesExprAsm.py +++ b/lib/core/Handles/HandlesExprAsm.py @@ -1,6 +1,6 @@ from __future__ import annotations from typing import TYPE_CHECKING, Any -import ast +import vast as ast import re import llvmlite.ir as ir if TYPE_CHECKING: diff --git a/lib/core/Handles/HandlesExprAttr.py b/lib/core/Handles/HandlesExprAttr.py index 0322d6e..e0b0e6b 100644 --- a/lib/core/Handles/HandlesExprAttr.py +++ b/lib/core/Handles/HandlesExprAttr.py @@ -4,7 +4,7 @@ if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.LlvmCodeGenerator import LlvmCodeGenerator from lib.core.Handles.HandlesBase import BaseHandle, FuncMeta -import ast +import vast as ast import llvmlite.ir as ir diff --git a/lib/core/Handles/HandlesExprBuiltin.py b/lib/core/Handles/HandlesExprBuiltin.py index aaaf611..e1b3050 100644 --- a/lib/core/Handles/HandlesExprBuiltin.py +++ b/lib/core/Handles/HandlesExprBuiltin.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin -import ast +import vast as ast import llvmlite.ir as ir from lib.core.Handles.HandlesBase import BaseHandle from lib.core.VLogger import get_logger as _vlog diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index 9a041f4..5088b33 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -1,31 +1,31 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin -import ast -import os -import re -import llvmlite.ir as ir -from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta -from lib.core.VLogger import get_logger as _vlog -from lib.constants.config import mode as _config_mode -from lib.includes import t -from lib.includes.t import CTypeRegistry -from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp - - -def _safe_ptr_type(ty: ir.Type) -> ir.Type: - """LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*(对应 C 的 void* 语义)""" - if isinstance(ty, ir.PointerType): - cur: ir.Type = ty - while isinstance(cur, ir.PointerType): - if isinstance(cur.pointee, ir.VoidType): - return ir.IntType(8).as_pointer() - cur = cur.pointee - return ty - - +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator + from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin +import vast as ast +import os +import re +import llvmlite.ir as ir +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta +from lib.core.VLogger import get_logger as _vlog +from lib.constants.config import mode as _config_mode +from lib.includes import t +from lib.includes.t import CTypeRegistry +from lib.core.SymbolUtils import IsTModule, ExtractTypeNameFromBinOp + + +def _safe_ptr_type(ty: ir.Type) -> ir.Type: + """LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*(对应 C 的 void* 语义)""" + if isinstance(ty, ir.PointerType): + cur: ir.Type = ty + while isinstance(cur, ir.PointerType): + if isinstance(cur.pointee, ir.VoidType): + return ir.IntType(8).as_pointer() + cur = cur.pointee + return ty + + class ExprCallHandle(BaseHandle): def _append_eh_msg_out_arg(self, CallArgs: list[ir.Value], func: ir.Function | None, Gen: LlvmGeneratorMixin) -> None: if not func: @@ -929,15 +929,15 @@ class ExprCallHandle(BaseHandle): ArgVal = self.HandleExprLlvm(arg) if ArgVal: CallArgs.append(ArgVal) - if (ClassName not in Gen.class_vtable - and ClassName not in Gen._cross_module_vtable_classes - and class_sha1): - self._try_register_vtable_ondemand(ClassName, class_sha1, Gen) - # 跨模块多继承:确保 class_parents 可用(MRO 回退需要)。 - # 如 HandlesType 委托调用 Generator 的方法——Generator 定义在 - # 另一模块,class_parents 未随 import 填充,需从 vpi 按需加载。 - self._EnsureClassParentsLoaded(ClassName, Gen) - if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods and CallArgs and not is_static_call: + if (ClassName not in Gen.class_vtable + and ClassName not in Gen._cross_module_vtable_classes + and class_sha1): + self._try_register_vtable_ondemand(ClassName, class_sha1, Gen) + # 跨模块多继承:确保 class_parents 可用(MRO 回退需要)。 + # 如 HandlesType 委托调用 Generator 的方法——Generator 定义在 + # 另一模块,class_parents 未随 import 填充,需从 vpi 按需加载。 + self._EnsureClassParentsLoaded(ClassName, Gen) + if (ClassName in Gen.class_vtable or ClassName in Gen._cross_module_vtable_classes) and ClassName in Gen.class_methods and CallArgs and not is_static_call: methods = Gen.class_methods[ClassName] if class_sha1: FullMethodName = f'{class_sha1}.{ClassName}.{MethodName}' @@ -2407,125 +2407,125 @@ class ExprCallHandle(BaseHandle): # 失败时恢复 declare_only 标记,避免后续调用跳过补发 Gen._generic_class_specializations[spec_key] = (cached_name, True) - def _compute_field_byte_offset(self, Gen: LlvmGeneratorMixin, ClassName: str, field_name: str) -> int | None: - """计算字段在 struct 中的字节偏移(按 LLVM 布局含对齐)。 - - 遍历 struct elements 带对齐累加(与 _get_struct_size/_get_align 一致)。 - 有 vtable 的类 struct 首元素为 vtable 指针(i8*),class_members 不含它。 - 返回 None 表示无法计算(struct 未定义 / 字段不存在)。 - """ - st = Gen.structs.get(ClassName) - if not st or not isinstance(st, ir.IdentifiedStructType) or st.elements is None: - return None - members: list = Gen.class_members.get(ClassName, []) - has_vtable: bool = (ClassName in Gen.class_vtable - or ClassName in Gen._cross_module_vtable_classes) - base: int = 1 if has_vtable else 0 - idx: int | None = None - for i, (name, _) in enumerate(members): - if name == field_name: - idx = base + i - break - if idx is None or idx >= len(st.elements): - return None - # ============================================================ - # 修复(2026-08-13):class_members 与 struct.elements 数量不一致时对齐。 - # 根因链(NewAstTest ASTCtx 枚举丢失): - # DeclarationGenerator/收集路径生成的 class_members 可能漏部分 Mixin/自动 - # 字段(如 Generator 漏 GenericSpecDepth/GenericClassFiles/ISINSTANCE_CLASS_MAX - # 3 个,class_members=88 vs struct=91),导致 this_adjust 用 class_members - # 索引算错字节偏移(Generator 624 vs 真实 644)。StmtGenMixin 方法(find_enum/ - # register_enum/is_enum_class)字段访问错位 20 字节 → EnumTable 落在 - # ReexportSrcs 内存 → 与 reexport 数据冲突覆盖 → ASTCtx 等枚举丢失。 - # 修正:字段真实 struct 索引 = class_members 索引 + (struct 元素数 - members 数)。 - # 前提:遗漏字段位于目标字段之前(本 bug 场景成立:漏字段在 StmtGenMixin 前)。 - # ============================================================ - diff_elems: int = len(st.elements) - len(members) - if diff_elems > 0: - idx += diff_elems - if idx >= len(st.elements): - return None - offset: int = 0 - for i in range(idx): - et = st.elements[i] - align: int = Gen._get_align(et) - size: int = Gen._get_struct_size(et) - if align > 1: - offset = ((offset + align - 1) // align) * align - offset += size - align = Gen._get_align(st.elements[idx]) - if align > 1: - offset = ((offset + align - 1) // align) * align - return offset - - def _adjust_this_for_inherited_method(self, Gen: LlvmGeneratorMixin, ObjVal: ir.Value, - ClassName: str, method_anc: str | None) -> ir.Value: - """多继承 this 调整(与 TPV _translate_method_call 一致): - - 继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内 - GEP(self_B, [0, 1]),字节偏移为 B 布局中 b 的 offset 8)。父类字段区 - 在子类中的**字节偏移**可能不同(如 AB={i8*,a@8,b@12} 中 b 偏移 12), - self 需按字节差前移,使父类方法内二次 GEP 恰好落到子类字段。 - - 修复(2026-08-10):字段索引法在"父类与子类元素大小不同"时错位 - (GEP 索引按元素个数计,非字节等价)。改用字节偏移: - delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移 - delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节 - GEP 到父类字段区在子类中的等效基址,再 bitcast 成父类指针。 - """ - if method_anc is None or method_anc == ClassName: - return ObjVal - anc_members: list = Gen.class_members.get(method_anc, []) - if not anc_members: - return ObjVal - first_field_name: str | None = None - for _fn, _ft in anc_members: - if _fn == '__vtable__': - continue - first_field_name = _fn - break - if first_field_name is None: - return ObjVal - sub_off: int | None = self._compute_field_byte_offset(Gen, ClassName, first_field_name) - if sub_off is None: - return ObjVal - anc_off: int | None = self._compute_field_byte_offset(Gen, method_anc, first_field_name) - if anc_off is None: - return ObjVal - delta: int = sub_off - anc_off - if delta <= 0: - return ObjVal - if method_anc not in Gen.structs: - return ObjVal - obj_i8: ir.Value = Gen.builder.bitcast(ObjVal, ir.PointerType(ir.IntType(8)), - name=f"this_adjust_i8_{method_anc}") - adj: ir.Value = Gen.builder.gep(obj_i8, [ir.Constant(ir.IntType(64), delta)], - name=f"this_adjust_{method_anc}") - return Gen.builder.bitcast(adj, ir.PointerType(Gen.structs[method_anc]), - name=f"this_adjust_cast_{method_anc}") - - def _EnsureClassParentsLoaded(self, ClassName: str, Gen: LlvmGeneratorMixin) -> None: - """跨模块多继承:class_parents 缺失时从 vpi 按需加载继承信息。 - - 调用方(如 HandlesType 委托)引用的类定义在另一模块,其父类 - 信息未随 import 填充。_TryLoadClassMembersFromPyi 读取 .vpi 中 - 的 ClassDef 并经 _EmitExternalClassDeclLlvm 填充 class_parents, - 使 _get_mro_chain 能沿 MRO 回退到定义类(如 TypeGenMixin)。 - """ - if not ClassName: - return - if Gen.class_parents.get(ClassName): - return - sha1_cls = Gen.ModuleSha1Map.get(ClassName) - if not sha1_cls: - sha1_cls = getattr(Gen, '_struct_sha1_map', {}).get(ClassName) - if not sha1_cls: - return - try: - self.Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, f"{sha1_cls}.stub.ll", Gen) - except Exception: - pass - + def _compute_field_byte_offset(self, Gen: LlvmGeneratorMixin, ClassName: str, field_name: str) -> int | None: + """计算字段在 struct 中的字节偏移(按 LLVM 布局含对齐)。 + + 遍历 struct elements 带对齐累加(与 _get_struct_size/_get_align 一致)。 + 有 vtable 的类 struct 首元素为 vtable 指针(i8*),class_members 不含它。 + 返回 None 表示无法计算(struct 未定义 / 字段不存在)。 + """ + st = Gen.structs.get(ClassName) + if not st or not isinstance(st, ir.IdentifiedStructType) or st.elements is None: + return None + members: list = Gen.class_members.get(ClassName, []) + has_vtable: bool = (ClassName in Gen.class_vtable + or ClassName in Gen._cross_module_vtable_classes) + base: int = 1 if has_vtable else 0 + idx: int | None = None + for i, (name, _) in enumerate(members): + if name == field_name: + idx = base + i + break + if idx is None or idx >= len(st.elements): + return None + # ============================================================ + # 修复(2026-08-13):class_members 与 struct.elements 数量不一致时对齐。 + # 根因链(NewAstTest ASTCtx 枚举丢失): + # DeclarationGenerator/收集路径生成的 class_members 可能漏部分 Mixin/自动 + # 字段(如 Generator 漏 GenericSpecDepth/GenericClassFiles/ISINSTANCE_CLASS_MAX + # 3 个,class_members=88 vs struct=91),导致 this_adjust 用 class_members + # 索引算错字节偏移(Generator 624 vs 真实 644)。StmtGenMixin 方法(find_enum/ + # register_enum/is_enum_class)字段访问错位 20 字节 → EnumTable 落在 + # ReexportSrcs 内存 → 与 reexport 数据冲突覆盖 → ASTCtx 等枚举丢失。 + # 修正:字段真实 struct 索引 = class_members 索引 + (struct 元素数 - members 数)。 + # 前提:遗漏字段位于目标字段之前(本 bug 场景成立:漏字段在 StmtGenMixin 前)。 + # ============================================================ + diff_elems: int = len(st.elements) - len(members) + if diff_elems > 0: + idx += diff_elems + if idx >= len(st.elements): + return None + offset: int = 0 + for i in range(idx): + et = st.elements[i] + align: int = Gen._get_align(et) + size: int = Gen._get_struct_size(et) + if align > 1: + offset = ((offset + align - 1) // align) * align + offset += size + align = Gen._get_align(st.elements[idx]) + if align > 1: + offset = ((offset + align - 1) // align) * align + return offset + + def _adjust_this_for_inherited_method(self, Gen: LlvmGeneratorMixin, ObjVal: ir.Value, + ClassName: str, method_anc: str | None) -> ir.Value: + """多继承 this 调整(与 TPV _translate_method_call 一致): + + 继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内 + GEP(self_B, [0, 1]),字节偏移为 B 布局中 b 的 offset 8)。父类字段区 + 在子类中的**字节偏移**可能不同(如 AB={i8*,a@8,b@12} 中 b 偏移 12), + self 需按字节差前移,使父类方法内二次 GEP 恰好落到子类字段。 + + 修复(2026-08-10):字段索引法在"父类与子类元素大小不同"时错位 + (GEP 索引按元素个数计,非字节等价)。改用字节偏移: + delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移 + delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节 + GEP 到父类字段区在子类中的等效基址,再 bitcast 成父类指针。 + """ + if method_anc is None or method_anc == ClassName: + return ObjVal + anc_members: list = Gen.class_members.get(method_anc, []) + if not anc_members: + return ObjVal + first_field_name: str | None = None + for _fn, _ft in anc_members: + if _fn == '__vtable__': + continue + first_field_name = _fn + break + if first_field_name is None: + return ObjVal + sub_off: int | None = self._compute_field_byte_offset(Gen, ClassName, first_field_name) + if sub_off is None: + return ObjVal + anc_off: int | None = self._compute_field_byte_offset(Gen, method_anc, first_field_name) + if anc_off is None: + return ObjVal + delta: int = sub_off - anc_off + if delta <= 0: + return ObjVal + if method_anc not in Gen.structs: + return ObjVal + obj_i8: ir.Value = Gen.builder.bitcast(ObjVal, ir.PointerType(ir.IntType(8)), + name=f"this_adjust_i8_{method_anc}") + adj: ir.Value = Gen.builder.gep(obj_i8, [ir.Constant(ir.IntType(64), delta)], + name=f"this_adjust_{method_anc}") + return Gen.builder.bitcast(adj, ir.PointerType(Gen.structs[method_anc]), + name=f"this_adjust_cast_{method_anc}") + + def _EnsureClassParentsLoaded(self, ClassName: str, Gen: LlvmGeneratorMixin) -> None: + """跨模块多继承:class_parents 缺失时从 vpi 按需加载继承信息。 + + 调用方(如 HandlesType 委托)引用的类定义在另一模块,其父类 + 信息未随 import 填充。_TryLoadClassMembersFromPyi 读取 .vpi 中 + 的 ClassDef 并经 _EmitExternalClassDeclLlvm 填充 class_parents, + 使 _get_mro_chain 能沿 MRO 回退到定义类(如 TypeGenMixin)。 + """ + if not ClassName: + return + if Gen.class_parents.get(ClassName): + return + sha1_cls = Gen.ModuleSha1Map.get(ClassName) + if not sha1_cls: + sha1_cls = getattr(Gen, '_struct_sha1_map', {}).get(ClassName) + if not sha1_cls: + return + try: + self.Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, f"{sha1_cls}.stub.ll", Gen) + except Exception: + pass + def _HandleMethodCallLlvm(self, Node: ast.Call) -> ir.Value: Gen = self.Trans.LlvmGen MethodName = Node.func.attr diff --git a/lib/core/Handles/HandlesExprFormat.py b/lib/core/Handles/HandlesExprFormat.py index 02693cf..bbbb783 100644 --- a/lib/core/Handles/HandlesExprFormat.py +++ b/lib/core/Handles/HandlesExprFormat.py @@ -1,271 +1,271 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Any -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import re -import llvmlite.ir as ir - - -class ExprFormatHandle(BaseHandle): - def _HandleJoinedStrLlvm(self, Node: ast.JoinedStr) -> ir.Value: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - if not Gen or not Gen.builder: - return ir.Constant(ir.IntType(8).as_pointer(), None) - format_str: str = "" - cast_args: list[Any] = [] - for part in Node.values: - if isinstance(part, ast.Constant) and isinstance(part.value, str): - format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0') - elif isinstance(part, ast.FormattedValue): - fmt_class: str | None = self.Trans.ExprHandler._get_var_class(part.value, Gen) - if fmt_class and Gen._has_function(f'{fmt_class}.__str__'): - obj_val: Any = self.HandleExprLlvm(part.value) - if obj_val: - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - if fmt_class in Gen.structs: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}") - val: Any = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__") - Gen._RegisterTempPtr(val) - format_str += "%s" - cast_args.append(val) - else: - format_str += "%s" - cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) - continue - val = self.HandleExprLlvm(part.value) - if not val: - format_str += "%d" - cast_args.append(ir.Constant(ir.IntType(32), 0)) - continue - # 检查 format_spec(Python f-string 格式说明符) - if part.format_spec is not None: - c_fmt: str | None = self._parse_format_spec(part.format_spec, val) - if c_fmt is not None: - cast_val: Any = self._cast_value_for_format(val, c_fmt, Gen, part.value) - format_str += c_fmt - cast_args.append(cast_val) - continue - if isinstance(val.type, ir.PointerType): - pointee: ir.Type = val.type.pointee - if isinstance(pointee, ir.IntType) and pointee.width == 8: - format_str += "%s" - cast_args.append(val) - elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - int_val: Any = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int") - trunc_val: Any = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc") - format_str += "%d" - cast_args.append(trunc_val) - else: - Loaded: Any = Gen._load(val, name="fstr_deref") - if isinstance(Loaded.type, ir.IntType): - if Loaded.type.width == 8: - format_str += "%c" - ext: Any = Gen.builder.zext(Loaded, ir.IntType(32), name="fstr_char2int") - cast_args.append(ext) - else: - format_str += "%d" - cast_args.append(Loaded) - elif isinstance(Loaded.type, (ir.FloatType, ir.DoubleType)): - format_str += "%f" - cast_args.append(Loaded) - elif isinstance(Loaded.type, ir.PointerType): - format_str += "%s" - cast_args.append(Loaded) - else: - format_str += "%d" - cast_args.append(Loaded) - elif isinstance(val.type, ir.IntType): - if val.type.width == 8: - format_str += "%c" - ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int") - cast_args.append(ext) - elif val.type.width == 1: - zext: Any = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int") - format_str += "%d" - cast_args.append(zext) - else: - is_u: bool = Gen._check_node_unsigned(part.value) - format_str += "%u" if is_u else "%d" - cast_args.append(val) - elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): - format_str += "%f" - cast_args.append(val) - else: - format_str += "%d" - cast_args.append(val) - if not format_str: - return Gen.emit_constant("", 'string') - format_ptr: Any = Gen._create_string_global(format_str) - # 统一使用 snprintf 生成字符串,返回 i8* - # __str__ 方法内使用堆分配(返回值需持久化),其他场景使用栈分配(自动释放) - in_str_method: bool = bool(getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__')) - snprintf_type: ir.FunctionType = ir.FunctionType(ir.IntType(32), [ - ir.PointerType(ir.IntType(8)), - ir.IntType(64), - ir.PointerType(ir.IntType(8)) - ], var_arg=True) - snprintf_func: Any = Gen.get_or_declare_c_func('snprintf', snprintf_type) - null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) - # 第一遍:获取所需长度(NULL 缓冲,size=0) - len_val: ir.Value = Gen.builder.call(snprintf_func, [null_ptr, ir.Constant(ir.IntType(64), 0), format_ptr] + cast_args, name="fstr_len") - # 加 1 用于 null 终止符 - size_val: ir.Value = Gen.builder.add(len_val, ir.Constant(ir.IntType(32), 1), name="fstr_size") - size_ext: ir.Value = Gen.builder.zext(size_val, ir.IntType(64), name="fstr_size_ext") - if in_str_method: - # 堆分配(__str__ 返回值需跨函数生命周期) - malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) - malloc_func: Any = Gen._get_or_declare_func('malloc', malloc_type) - buf_ptr: ir.Value = Gen.builder.call(malloc_func, [size_ext], name="fstr_heap_buf") - Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf") - Gen._RegisterTempPtr(buf_ptr) - return buf_ptr - # 栈分配(局部使用,自动释放) - buf_ptr: ir.Value = Gen._alloca(ir.IntType(8), name="fstr_stack_buf", size=size_val) - Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf") - return buf_ptr - - def _parse_format_spec(self, format_spec_node: ast.AST, val: ir.Value) -> str | None: - """将 Python f-string format_spec 转换为 C printf 格式说明符。 - - 支持: d/x/X/o/c/f/s 及 [[fill]align][sign][#][0][width][.precision][type] 语法。 - 返回 None 表示无法解析,调用方应回退到类型推断。 - """ - if isinstance(format_spec_node, ast.JoinedStr): - parts: list[str] = [] - for v in format_spec_node.values: - if isinstance(v, ast.Constant) and isinstance(v.value, str): - parts.append(v.value) - else: - return None - spec_str: str = ''.join(parts) - elif isinstance(format_spec_node, ast.Constant) and isinstance(format_spec_node.value, str): - spec_str = format_spec_node.value - else: - return None - - if not spec_str: - return None - - m: Any = re.match(r'^(.?[<>=^])?([+\- ])?(#)?(0)?(\d+)?(,)?(\.\d+)?([bcdeEfFgGnosxX%])?$', spec_str) - if not m: - return None - - fill_align, sign, alt, zero, width, comma, precision, fmt_type = m.groups() - - c_flags: str = '' - if sign == '+': - c_flags += '+' - elif sign == ' ': - c_flags += ' ' - if alt: - c_flags += '#' - - if fill_align: - align_char: str = fill_align[-1] if len(fill_align) > 1 else fill_align[0] - if align_char in ('<', '^'): - c_flags += '-' - if zero: - c_flags += '0' - - c_width: str = width or '' - c_precision: str = precision or '' - - length_mod: str = '' - if isinstance(val.type, ir.IntType): - if val.type.width == 64: - length_mod = 'll' - elif val.type.width == 32: - length_mod = 'l' - elif val.type.width == 16: - length_mod = 'h' - elif val.type.width == 8: - length_mod = 'hh' - - c_specifier: str = '' - if fmt_type in ('d', 'n'): - c_specifier = f'{length_mod}d' - elif fmt_type == 'x': - c_specifier = f'{length_mod}x' - elif fmt_type == 'X': - c_specifier = f'{length_mod}X' - elif fmt_type == 'o': - c_specifier = f'{length_mod}o' - elif fmt_type == 'b': - return None - elif fmt_type == 'c': - c_specifier = 'c' - elif fmt_type in ('f', 'F'): - c_specifier = 'f' - elif fmt_type in ('e', 'E', 'g', 'G'): - c_specifier = fmt_type - elif fmt_type == 's': - c_specifier = 's' - elif fmt_type == '%': - c_specifier = 'f%%' - else: - if isinstance(val.type, ir.IntType): - if val.type.width == 8: - c_specifier = 'c' - elif val.type.width == 1: - c_specifier = 'd' - else: - c_specifier = f'{length_mod}d' - elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): - c_specifier = 'f' - elif isinstance(val.type, ir.PointerType): - c_specifier = 's' - else: - c_specifier = 'd' - - return f'%{c_flags}{c_width}{c_precision}{c_specifier}' - - def _cast_value_for_format(self, val: ir.Value, c_fmt: str, Gen: Any, arg_node: ast.AST) -> ir.Value: - """根据 C printf 格式说明符转换值类型。""" - fmt_type_char: str = '' - for ch in reversed(c_fmt): - if ch.isalpha() and ch not in ('l', 'h'): - fmt_type_char = ch - break - elif ch == '%': - break - - if fmt_type_char == 's': - if isinstance(val.type, ir.PointerType): - pointee: ir.Type = val.type.pointee - if isinstance(pointee, ir.IntType) and pointee.width == 8: - return val - if isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8: - return Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="fstr_arr2ptr") - return val - elif fmt_type_char == 'c': - if isinstance(val.type, ir.IntType) and val.type.width < 32: - return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_c") - return val - elif fmt_type_char in ('d', 'x', 'X', 'o', 'i'): - if isinstance(val.type, ir.IntType): - if val.type.width == 8: - is_u: bool = Gen._check_node_unsigned(arg_node) - if is_u: - return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i8") - return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i8") - elif val.type.width == 16: - is_u = Gen._check_node_unsigned(arg_node) - if is_u: - return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i16") - return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i16") - elif val.type.width == 1: - return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_bool") - return val - elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): - return Gen.builder.fptosi(val, ir.IntType(32), name="fstr_f2i") - return val - elif fmt_type_char in ('f', 'e', 'E', 'g', 'G'): - if isinstance(val.type, ir.FloatType): - return Gen.builder.fpext(val, ir.DoubleType(), name="fstr_fpext") - elif isinstance(val.type, ir.IntType): - return Gen.builder.sitofp(val, ir.DoubleType(), name="fstr_i2f") - return val +from __future__ import annotations +from typing import TYPE_CHECKING, Any +if TYPE_CHECKING: + from lib.core.translator import Translator + from lib.core.LlvmCodeGenerator import LlvmCodeGenerator +from lib.core.Handles.HandlesBase import BaseHandle +import vast as ast +import re +import llvmlite.ir as ir + + +class ExprFormatHandle(BaseHandle): + def _HandleJoinedStrLlvm(self, Node: ast.JoinedStr) -> ir.Value: + Gen: LlvmCodeGenerator = self.Trans.LlvmGen + if not Gen or not Gen.builder: + return ir.Constant(ir.IntType(8).as_pointer(), None) + format_str: str = "" + cast_args: list[Any] = [] + for part in Node.values: + if isinstance(part, ast.Constant) and isinstance(part.value, str): + format_str += part.value.replace('\\', '\\\\').replace('%', '%%').replace('\n', '\\n').replace('\t', '\\t').replace('\0', '\\0') + elif isinstance(part, ast.FormattedValue): + fmt_class: str | None = self.Trans.ExprHandler._get_var_class(part.value, Gen) + if fmt_class and Gen._has_function(f'{fmt_class}.__str__'): + obj_val: Any = self.HandleExprLlvm(part.value) + if obj_val: + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + if fmt_class in Gen.structs: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[fmt_class]), name=f"cast_{fmt_class}") + val: Any = Gen.builder.call(Gen._get_function(f'{fmt_class}.__str__'), [obj_val], name=f"call_{fmt_class}.__str__") + Gen._RegisterTempPtr(val) + format_str += "%s" + cast_args.append(val) + else: + format_str += "%s" + cast_args.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) + continue + val = self.HandleExprLlvm(part.value) + if not val: + format_str += "%d" + cast_args.append(ir.Constant(ir.IntType(32), 0)) + continue + # 检查 format_spec(Python f-string 格式说明符) + if part.format_spec is not None: + c_fmt: str | None = self._parse_format_spec(part.format_spec, val) + if c_fmt is not None: + cast_val: Any = self._cast_value_for_format(val, c_fmt, Gen, part.value) + format_str += c_fmt + cast_args.append(cast_val) + continue + if isinstance(val.type, ir.PointerType): + pointee: ir.Type = val.type.pointee + if isinstance(pointee, ir.IntType) and pointee.width == 8: + format_str += "%s" + cast_args.append(val) + elif isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + int_val: Any = Gen.builder.ptrtoint(val, ir.IntType(64), name="fstr_ptr2int") + trunc_val: Any = Gen.builder.trunc(int_val, ir.IntType(32), name="fstr_trunc") + format_str += "%d" + cast_args.append(trunc_val) + else: + Loaded: Any = Gen._load(val, name="fstr_deref") + if isinstance(Loaded.type, ir.IntType): + if Loaded.type.width == 8: + format_str += "%c" + ext: Any = Gen.builder.zext(Loaded, ir.IntType(32), name="fstr_char2int") + cast_args.append(ext) + else: + format_str += "%d" + cast_args.append(Loaded) + elif isinstance(Loaded.type, (ir.FloatType, ir.DoubleType)): + format_str += "%f" + cast_args.append(Loaded) + elif isinstance(Loaded.type, ir.PointerType): + format_str += "%s" + cast_args.append(Loaded) + else: + format_str += "%d" + cast_args.append(Loaded) + elif isinstance(val.type, ir.IntType): + if val.type.width == 8: + format_str += "%c" + ext = Gen.builder.zext(val, ir.IntType(32), name="fstr_char2int") + cast_args.append(ext) + elif val.type.width == 1: + zext: Any = Gen.builder.zext(val, ir.IntType(32), name="fstr_bool2int") + format_str += "%d" + cast_args.append(zext) + else: + is_u: bool = Gen._check_node_unsigned(part.value) + format_str += "%u" if is_u else "%d" + cast_args.append(val) + elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): + format_str += "%f" + cast_args.append(val) + else: + format_str += "%d" + cast_args.append(val) + if not format_str: + return Gen.emit_constant("", 'string') + format_ptr: Any = Gen._create_string_global(format_str) + # 统一使用 snprintf 生成字符串,返回 i8* + # __str__ 方法内使用堆分配(返回值需持久化),其他场景使用栈分配(自动释放) + in_str_method: bool = bool(getattr(Gen, 'func', None) and getattr(Gen.func, 'name', '').endswith('.__str__')) + snprintf_type: ir.FunctionType = ir.FunctionType(ir.IntType(32), [ + ir.PointerType(ir.IntType(8)), + ir.IntType(64), + ir.PointerType(ir.IntType(8)) + ], var_arg=True) + snprintf_func: Any = Gen.get_or_declare_c_func('snprintf', snprintf_type) + null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) + # 第一遍:获取所需长度(NULL 缓冲,size=0) + len_val: ir.Value = Gen.builder.call(snprintf_func, [null_ptr, ir.Constant(ir.IntType(64), 0), format_ptr] + cast_args, name="fstr_len") + # 加 1 用于 null 终止符 + size_val: ir.Value = Gen.builder.add(len_val, ir.Constant(ir.IntType(32), 1), name="fstr_size") + size_ext: ir.Value = Gen.builder.zext(size_val, ir.IntType(64), name="fstr_size_ext") + if in_str_method: + # 堆分配(__str__ 返回值需跨函数生命周期) + malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) + malloc_func: Any = Gen._get_or_declare_func('malloc', malloc_type) + buf_ptr: ir.Value = Gen.builder.call(malloc_func, [size_ext], name="fstr_heap_buf") + Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf") + Gen._RegisterTempPtr(buf_ptr) + return buf_ptr + # 栈分配(局部使用,自动释放) + buf_ptr: ir.Value = Gen._alloca(ir.IntType(8), name="fstr_stack_buf", size=size_val) + Gen.builder.call(snprintf_func, [buf_ptr, size_ext, format_ptr] + cast_args, name="fstr_snprintf") + return buf_ptr + + def _parse_format_spec(self, format_spec_node: ast.AST, val: ir.Value) -> str | None: + """将 Python f-string format_spec 转换为 C printf 格式说明符。 + + 支持: d/x/X/o/c/f/s 及 [[fill]align][sign][#][0][width][.precision][type] 语法。 + 返回 None 表示无法解析,调用方应回退到类型推断。 + """ + if isinstance(format_spec_node, ast.JoinedStr): + parts: list[str] = [] + for v in format_spec_node.values: + if isinstance(v, ast.Constant) and isinstance(v.value, str): + parts.append(v.value) + else: + return None + spec_str: str = ''.join(parts) + elif isinstance(format_spec_node, ast.Constant) and isinstance(format_spec_node.value, str): + spec_str = format_spec_node.value + else: + return None + + if not spec_str: + return None + + m: Any = re.match(r'^(.?[<>=^])?([+\- ])?(#)?(0)?(\d+)?(,)?(\.\d+)?([bcdeEfFgGnosxX%])?$', spec_str) + if not m: + return None + + fill_align, sign, alt, zero, width, comma, precision, fmt_type = m.groups() + + c_flags: str = '' + if sign == '+': + c_flags += '+' + elif sign == ' ': + c_flags += ' ' + if alt: + c_flags += '#' + + if fill_align: + align_char: str = fill_align[-1] if len(fill_align) > 1 else fill_align[0] + if align_char in ('<', '^'): + c_flags += '-' + if zero: + c_flags += '0' + + c_width: str = width or '' + c_precision: str = precision or '' + + length_mod: str = '' + if isinstance(val.type, ir.IntType): + if val.type.width == 64: + length_mod = 'll' + elif val.type.width == 32: + length_mod = 'l' + elif val.type.width == 16: + length_mod = 'h' + elif val.type.width == 8: + length_mod = 'hh' + + c_specifier: str = '' + if fmt_type in ('d', 'n'): + c_specifier = f'{length_mod}d' + elif fmt_type == 'x': + c_specifier = f'{length_mod}x' + elif fmt_type == 'X': + c_specifier = f'{length_mod}X' + elif fmt_type == 'o': + c_specifier = f'{length_mod}o' + elif fmt_type == 'b': + return None + elif fmt_type == 'c': + c_specifier = 'c' + elif fmt_type in ('f', 'F'): + c_specifier = 'f' + elif fmt_type in ('e', 'E', 'g', 'G'): + c_specifier = fmt_type + elif fmt_type == 's': + c_specifier = 's' + elif fmt_type == '%': + c_specifier = 'f%%' + else: + if isinstance(val.type, ir.IntType): + if val.type.width == 8: + c_specifier = 'c' + elif val.type.width == 1: + c_specifier = 'd' + else: + c_specifier = f'{length_mod}d' + elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): + c_specifier = 'f' + elif isinstance(val.type, ir.PointerType): + c_specifier = 's' + else: + c_specifier = 'd' + + return f'%{c_flags}{c_width}{c_precision}{c_specifier}' + + def _cast_value_for_format(self, val: ir.Value, c_fmt: str, Gen: Any, arg_node: ast.AST) -> ir.Value: + """根据 C printf 格式说明符转换值类型。""" + fmt_type_char: str = '' + for ch in reversed(c_fmt): + if ch.isalpha() and ch not in ('l', 'h'): + fmt_type_char = ch + break + elif ch == '%': + break + + if fmt_type_char == 's': + if isinstance(val.type, ir.PointerType): + pointee: ir.Type = val.type.pointee + if isinstance(pointee, ir.IntType) and pointee.width == 8: + return val + if isinstance(pointee, ir.ArrayType) and isinstance(pointee.element, ir.IntType) and pointee.element.width == 8: + return Gen.builder.gep(val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="fstr_arr2ptr") + return val + elif fmt_type_char == 'c': + if isinstance(val.type, ir.IntType) and val.type.width < 32: + return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_c") + return val + elif fmt_type_char in ('d', 'x', 'X', 'o', 'i'): + if isinstance(val.type, ir.IntType): + if val.type.width == 8: + is_u: bool = Gen._check_node_unsigned(arg_node) + if is_u: + return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i8") + return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i8") + elif val.type.width == 16: + is_u = Gen._check_node_unsigned(arg_node) + if is_u: + return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_i16") + return Gen.builder.sext(val, ir.IntType(32), name="fstr_sext_i16") + elif val.type.width == 1: + return Gen.builder.zext(val, ir.IntType(32), name="fstr_zext_bool") + return val + elif isinstance(val.type, (ir.FloatType, ir.DoubleType)): + return Gen.builder.fptosi(val, ir.IntType(32), name="fstr_f2i") + return val + elif fmt_type_char in ('f', 'e', 'E', 'g', 'G'): + if isinstance(val.type, ir.FloatType): + return Gen.builder.fpext(val, ir.DoubleType(), name="fstr_fpext") + elif isinstance(val.type, ir.IntType): + return Gen.builder.sitofp(val, ir.DoubleType(), name="fstr_i2f") + return val return val \ No newline at end of file diff --git a/lib/core/Handles/HandlesExprLambda.py b/lib/core/Handles/HandlesExprLambda.py index 7003785..db37c70 100644 --- a/lib/core/Handles/HandlesExprLambda.py +++ b/lib/core/Handles/HandlesExprLambda.py @@ -1,249 +1,249 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Any -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class ExprLambdaHandle(BaseHandle): - def _HandleLambdaLlvm(self, Node: ast.Lambda) -> ir.Value: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - if not getattr(Gen, '_lambda_counter', None): - Gen._lambda_counter = 0 - lambda_id: int = Gen._lambda_counter - Gen._lambda_counter += 1 - fn_name: str = f"lambda_fn_{lambda_id}" - captured_vars: list[tuple[str, Any]] = self._get_lambda_captured_vars(Node) - env_types: list[ir.Type] = [] - env_var_names: list[str] = [] - for var_name, var_val in captured_vars: - env_types.append(var_val.type) - env_var_names.append(var_name) - env_struct_type: ir.LiteralStructType = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([]) - ret_type: ir.Type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body) - param_types: list[ir.Type] = [ir.PointerType(env_struct_type)] - if Node.args: - for arg in Node.args.args: - param_types.append(ir.IntType(32)) - fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types) - fn: ir.Function = ir.Function(Gen.module, fn_type, name=fn_name) - Gen.functions[fn_name] = fn - entry_block: ir.Block = fn.append_basic_block(name=f"{fn_name}_entry") - prev_builder: Any = Gen.builder - prev_func: Any = Gen.func - prev_vars: dict[str, Any] = dict(Gen.variables) - Gen.builder = ir.IRBuilder(entry_block) - Gen.func = fn - Gen.variables = {} - for i, arg in enumerate(fn.args): - arg.name = f"arg_{i}" if i > 0 else "env" - if env_types: - for idx, var_name in enumerate(env_var_names): - env_ptr: Any = fn.args[0] - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - member_ptr: Any = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}") - Loaded: Any = Gen._load(member_ptr, name=f"Load_env_{var_name}") - temp_alloca: Any = Gen._alloca(Loaded.type, name=f"temp_{var_name}") - Gen._store(Loaded, temp_alloca) - Gen.variables[var_name] = temp_alloca - if Node.args: - for i, arg in enumerate(Node.args.args): - Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg) - Gen._store(fn.args[i + 1], Gen.variables[arg.arg]) - body_val: Any = self.HandleExprLlvm(Node.body) - if body_val: - if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType): - body_val = Gen._load(body_val, name="Load_lambda_ret") - if body_val.type != ret_type: - if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType): - if body_val.type.width < ret_type.width: - body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret") - elif body_val.type.width > ret_type.width: - body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret") - elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType): - body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret") - Gen.builder.ret(body_val) - else: - if isinstance(ret_type, ir.PointerType): - Gen.builder.ret(ir.Constant(ret_type, None)) - elif isinstance(ret_type, ir.IntType): - Gen.builder.ret(ir.Constant(ret_type, 0)) - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): - Gen.builder.ret(ir.Constant(ret_type, 0.0)) - elif isinstance(ret_type, ir.BaseStructType): - if ret_type.elements: - zero_val: ir.Constant = ir.Constant(ret_type, [ - ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) - else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) - else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) - else: - zero_val = ir.Constant(ret_type, None) - Gen.builder.ret(zero_val) - else: - Gen.builder.ret(ir.Constant(ret_type, 0)) - Gen.builder = prev_builder - Gen.func = prev_func - Gen.variables = prev_vars - closure_struct_type: ir.LiteralStructType = ir.LiteralStructType([ - ir.PointerType(ir.IntType(8)), - ir.PointerType(fn_type) - ]) - closure_ptr: Any = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}") - env_ptr: Any = Gen._alloca(env_struct_type, name=f"env_{lambda_id}") - if env_types: - for idx, (var_name, var_val) in enumerate(captured_vars): - zero = ir.Constant(ir.IntType(32), 0) - member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}") - Gen._store(var_val, member_ptr) - zero = ir.Constant(ir.IntType(32), 0) - env_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr") - env_i8_ptr: Any = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr") - Gen._store(env_i8_ptr, env_field_ptr) - fn_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr") - Gen._store(fn, fn_field_ptr) - return closure_ptr - - def _get_lambda_captured_vars(self, Node: ast.Lambda) -> list[tuple[str, ir.Value]]: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - captured: list[tuple[str, Any]] = [] - free_vars: list[str] = self._get_lambda_free_vars(Node) - for var_name in free_vars: - if var_name in Gen.variables: - var_ptr: Any = Gen.variables[var_name] - if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable): - Loaded: Any = Gen._load(var_ptr, name=f"capture_{var_name}") - captured.append((var_name, Loaded)) - return captured - - def _get_lambda_free_vars(self, Node: ast.Lambda) -> list[str]: - bound_vars: set[str] = set() - free_vars: set[str] = set() - # 收集 lambda body 中的 bound 和 free 变量 - self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars) - # lambda 参数也是 bound 的 - if Node.args: - for arg in Node.args.args: - bound_vars.add(arg.arg) - # free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量 - result: list[str] = list(free_vars - bound_vars) - return result - - def _HandleIfExpLlvm(self, Node: ast.IfExp) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - TestVal: Any = self.HandleExprLlvm(Node.test) - if not TestVal: - return None - if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1: - TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._ZeroConst(TestVal.type), name="ifexp_cond") - ThenBB: ir.Block = Gen.func.append_basic_block(name="ifexp.then") - ElseBB: ir.Block = Gen.func.append_basic_block(name="ifexp.else") - MergeBB: ir.Block = Gen.func.append_basic_block(name="ifexp.end") - Gen.builder.cbranch(TestVal, ThenBB, ElseBB) - # 先在 ThenBB 中生成 BodyVal - Gen.builder.position_at_start(ThenBB) - BodyVal: Any = self.HandleExprLlvm(Node.body) - if not BodyVal: - BodyVal = ir.Constant(ir.IntType(32), 0) - ThenEndBB: ir.Block = Gen.builder.block - # 在 ElseBB 中生成 OrelseVal - Gen.builder.position_at_start(ElseBB) - OrelseVal: Any = self.HandleExprLlvm(Node.orelse) - if not OrelseVal: - OrelseVal = ir.Constant(ir.IntType(32), 0) - ElseEndBB: ir.Block = Gen.builder.block - # 确定 phi 节点的目标类型 - result_type: ir.Type = BodyVal.type - if BodyVal.type != OrelseVal.type: - if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType): - result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type - elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType): - # 指针类型,使用 BodyVal 的类型 - result_type = BodyVal.type - elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType): - # BodyVal 是整数,OrelseVal 是指针(字符串字面量) - # 如果指针指向 i8,将指针转换为 i8(加载字符) - if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: - result_type = ir.IntType(8) - else: - result_type = OrelseVal.type - elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType): - # BodyVal 是指针(字符串字面量),OrelseVal 是整数 - # 如果指针指向 i8,将指针转换为 i8(加载字符) - if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8: - result_type = ir.IntType(8) - else: - result_type = BodyVal.type - else: - result_type = OrelseVal.type - # 在 ThenBB 末尾添加类型转换(如果需要)和分支 - if not ThenEndBB.is_terminated: - Gen.builder.position_at_end(ThenEndBB) - if BodyVal.type != result_type: - if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType): - if BodyVal.type.width < result_type.width: - BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext") - else: - BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc") - elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): - # 如果 result_type 是 i8*,说明 Else 分支是字符串字面量 - # 不应该将整数转换为指针,而应该保持整数类型 - # 这里将 result_type 改为 i8 - result_type = ir.IntType(8) - # 重新处理 Else 分支的类型转换 - elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): - # 指针转整数 - BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int") - Gen.builder.branch(MergeBB) - # 在 ElseBB 末尾添加类型转换(如果需要)和分支 - if not ElseEndBB.is_terminated: - Gen.builder.position_at_end(ElseEndBB) - if OrelseVal.type != result_type: - if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType): - if OrelseVal.type.width < result_type.width: - OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext") - else: - OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc") - elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): - # 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量 - # 不应该将整数转换为指针,而应该保持整数类型 - # 这里将 result_type 改为 i8 - result_type = ir.IntType(8) - # 重新处理 BodyVal 分支的类型转换(已经在上面处理过了) - elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): - # 如果指针指向 i8,加载字符值 - if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: - OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_Load_char") - else: - OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int") - Gen.builder.branch(MergeBB) - Gen.builder.position_at_start(MergeBB) - result_phi: Any = Gen.builder.phi(result_type, name="ifexp.result") - result_phi.add_incoming(BodyVal, ThenEndBB) - result_phi.add_incoming(OrelseVal, ElseEndBB) - return result_phi - - def _HandleNamedExprLlvm(self, Node: ast.NamedExpr) -> ir.Value: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - ValueVal: Any = self.HandleExprLlvm(Node.value) - if not ValueVal: - return None - TargetName: str = Node.target.id - if TargetName in Gen._reg_values: - del Gen._reg_values[TargetName] - if TargetName in Gen.variables and Gen.variables[TargetName] is not None: - VarPtr: Any = Gen.variables[TargetName] - if VarPtr.type.pointee == ValueVal.type: - Gen._store(ValueVal, VarPtr) - else: - NewVar: Any = Gen._alloca(ValueVal.type, name=TargetName) - Gen._store(ValueVal, NewVar) - Gen.variables[TargetName] = NewVar - else: - NewVar = Gen._alloca(ValueVal.type, name=TargetName) - Gen._store(ValueVal, NewVar) - Gen.variables[TargetName] = NewVar - Gen._reg_values[TargetName] = ValueVal +from __future__ import annotations +from typing import TYPE_CHECKING, Any +if TYPE_CHECKING: + from lib.core.translator import Translator + from lib.core.LlvmCodeGenerator import LlvmCodeGenerator +from lib.core.Handles.HandlesBase import BaseHandle +import vast as ast +import llvmlite.ir as ir + + +class ExprLambdaHandle(BaseHandle): + def _HandleLambdaLlvm(self, Node: ast.Lambda) -> ir.Value: + Gen: LlvmCodeGenerator = self.Trans.LlvmGen + if not getattr(Gen, '_lambda_counter', None): + Gen._lambda_counter = 0 + lambda_id: int = Gen._lambda_counter + Gen._lambda_counter += 1 + fn_name: str = f"lambda_fn_{lambda_id}" + captured_vars: list[tuple[str, Any]] = self._get_lambda_captured_vars(Node) + env_types: list[ir.Type] = [] + env_var_names: list[str] = [] + for var_name, var_val in captured_vars: + env_types.append(var_val.type) + env_var_names.append(var_name) + env_struct_type: ir.LiteralStructType = ir.LiteralStructType(env_types) if env_types else ir.LiteralStructType([]) + ret_type: ir.Type = self.Trans.ExprUtils._infer_expr_llvm_type_full(Node.body) + param_types: list[ir.Type] = [ir.PointerType(env_struct_type)] + if Node.args: + for arg in Node.args.args: + param_types.append(ir.IntType(32)) + fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types) + fn: ir.Function = ir.Function(Gen.module, fn_type, name=fn_name) + Gen.functions[fn_name] = fn + entry_block: ir.Block = fn.append_basic_block(name=f"{fn_name}_entry") + prev_builder: Any = Gen.builder + prev_func: Any = Gen.func + prev_vars: dict[str, Any] = dict(Gen.variables) + Gen.builder = ir.IRBuilder(entry_block) + Gen.func = fn + Gen.variables = {} + for i, arg in enumerate(fn.args): + arg.name = f"arg_{i}" if i > 0 else "env" + if env_types: + for idx, var_name in enumerate(env_var_names): + env_ptr: Any = fn.args[0] + zero: ir.Constant = ir.Constant(ir.IntType(32), 0) + member_ptr: Any = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"env_{var_name}") + Loaded: Any = Gen._load(member_ptr, name=f"Load_env_{var_name}") + temp_alloca: Any = Gen._alloca(Loaded.type, name=f"temp_{var_name}") + Gen._store(Loaded, temp_alloca) + Gen.variables[var_name] = temp_alloca + if Node.args: + for i, arg in enumerate(Node.args.args): + Gen.variables[arg.arg] = Gen._alloca(ir.IntType(32), name=arg.arg) + Gen._store(fn.args[i + 1], Gen.variables[arg.arg]) + body_val: Any = self.HandleExprLlvm(Node.body) + if body_val: + if isinstance(body_val.type, ir.PointerType) and not isinstance(ret_type, ir.PointerType): + body_val = Gen._load(body_val, name="Load_lambda_ret") + if body_val.type != ret_type: + if isinstance(body_val.type, ir.IntType) and isinstance(ret_type, ir.IntType): + if body_val.type.width < ret_type.width: + body_val = Gen.builder.zext(body_val, ret_type, name="zext_lambda_ret") + elif body_val.type.width > ret_type.width: + body_val = Gen.builder.trunc(body_val, ret_type, name="trunc_lambda_ret") + elif isinstance(body_val.type, ir.PointerType) and isinstance(ret_type, ir.PointerType): + body_val = Gen.builder.bitcast(body_val, ret_type, name="bitcast_lambda_ret") + Gen.builder.ret(body_val) + else: + if isinstance(ret_type, ir.PointerType): + Gen.builder.ret(ir.Constant(ret_type, None)) + elif isinstance(ret_type, ir.IntType): + Gen.builder.ret(ir.Constant(ret_type, 0)) + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): + Gen.builder.ret(ir.Constant(ret_type, 0.0)) + elif isinstance(ret_type, ir.BaseStructType): + if ret_type.elements: + zero_val: ir.Constant = ir.Constant(ret_type, [ + ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) + else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) + else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + zero_val = ir.Constant(ret_type, None) + Gen.builder.ret(zero_val) + else: + Gen.builder.ret(ir.Constant(ret_type, 0)) + Gen.builder = prev_builder + Gen.func = prev_func + Gen.variables = prev_vars + closure_struct_type: ir.LiteralStructType = ir.LiteralStructType([ + ir.PointerType(ir.IntType(8)), + ir.PointerType(fn_type) + ]) + closure_ptr: Any = Gen._alloca(closure_struct_type, name=f"closure_{lambda_id}") + env_ptr: Any = Gen._alloca(env_struct_type, name=f"env_{lambda_id}") + if env_types: + for idx, (var_name, var_val) in enumerate(captured_vars): + zero = ir.Constant(ir.IntType(32), 0) + member_ptr = Gen.builder.gep(env_ptr, [zero, ir.Constant(ir.IntType(32), idx)], name=f"store_env_{var_name}") + Gen._store(var_val, member_ptr) + zero = ir.Constant(ir.IntType(32), 0) + env_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, zero], name="closure_env_ptr") + env_i8_ptr: Any = Gen.builder.bitcast(env_ptr, ir.PointerType(ir.IntType(8)), name="env_i8_ptr") + Gen._store(env_i8_ptr, env_field_ptr) + fn_field_ptr: Any = Gen.builder.gep(closure_ptr, [zero, ir.Constant(ir.IntType(32), 1)], name="closure_fn_ptr") + Gen._store(fn, fn_field_ptr) + return closure_ptr + + def _get_lambda_captured_vars(self, Node: ast.Lambda) -> list[tuple[str, ir.Value]]: + Gen: LlvmCodeGenerator = self.Trans.LlvmGen + captured: list[tuple[str, Any]] = [] + free_vars: list[str] = self._get_lambda_free_vars(Node) + for var_name in free_vars: + if var_name in Gen.variables: + var_ptr: Any = Gen.variables[var_name] + if isinstance(var_ptr, ir.AllocaInstr) or isinstance(var_ptr, ir.GlobalVariable): + Loaded: Any = Gen._load(var_ptr, name=f"capture_{var_name}") + captured.append((var_name, Loaded)) + return captured + + def _get_lambda_free_vars(self, Node: ast.Lambda) -> list[str]: + bound_vars: set[str] = set() + free_vars: set[str] = set() + # 收集 lambda body 中的 bound 和 free 变量 + self.Trans.ExprUtils._collect_names(Node.body, bound_vars, free_vars) + # lambda 参数也是 bound 的 + if Node.args: + for arg in Node.args.args: + bound_vars.add(arg.arg) + # free 变量 = 在 body 中引用(Load)但不是参数也不是 body 内赋值的变量 + result: list[str] = list(free_vars - bound_vars) + return result + + def _HandleIfExpLlvm(self, Node: ast.IfExp) -> ir.Value | None: + Gen: LlvmCodeGenerator = self.Trans.LlvmGen + TestVal: Any = self.HandleExprLlvm(Node.test) + if not TestVal: + return None + if not isinstance(TestVal.type, ir.IntType) or TestVal.type.width != 1: + TestVal = Gen.builder.icmp_signed('!=', TestVal, Gen._ZeroConst(TestVal.type), name="ifexp_cond") + ThenBB: ir.Block = Gen.func.append_basic_block(name="ifexp.then") + ElseBB: ir.Block = Gen.func.append_basic_block(name="ifexp.else") + MergeBB: ir.Block = Gen.func.append_basic_block(name="ifexp.end") + Gen.builder.cbranch(TestVal, ThenBB, ElseBB) + # 先在 ThenBB 中生成 BodyVal + Gen.builder.position_at_start(ThenBB) + BodyVal: Any = self.HandleExprLlvm(Node.body) + if not BodyVal: + BodyVal = ir.Constant(ir.IntType(32), 0) + ThenEndBB: ir.Block = Gen.builder.block + # 在 ElseBB 中生成 OrelseVal + Gen.builder.position_at_start(ElseBB) + OrelseVal: Any = self.HandleExprLlvm(Node.orelse) + if not OrelseVal: + OrelseVal = ir.Constant(ir.IntType(32), 0) + ElseEndBB: ir.Block = Gen.builder.block + # 确定 phi 节点的目标类型 + result_type: ir.Type = BodyVal.type + if BodyVal.type != OrelseVal.type: + if isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.IntType): + result_type = BodyVal.type if BodyVal.type.width >= OrelseVal.type.width else OrelseVal.type + elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.PointerType): + # 指针类型,使用 BodyVal 的类型 + result_type = BodyVal.type + elif isinstance(BodyVal.type, ir.IntType) and isinstance(OrelseVal.type, ir.PointerType): + # BodyVal 是整数,OrelseVal 是指针(字符串字面量) + # 如果指针指向 i8,将指针转换为 i8(加载字符) + if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: + result_type = ir.IntType(8) + else: + result_type = OrelseVal.type + elif isinstance(BodyVal.type, ir.PointerType) and isinstance(OrelseVal.type, ir.IntType): + # BodyVal 是指针(字符串字面量),OrelseVal 是整数 + # 如果指针指向 i8,将指针转换为 i8(加载字符) + if isinstance(BodyVal.type.pointee, ir.IntType) and BodyVal.type.pointee.width == 8: + result_type = ir.IntType(8) + else: + result_type = BodyVal.type + else: + result_type = OrelseVal.type + # 在 ThenBB 末尾添加类型转换(如果需要)和分支 + if not ThenEndBB.is_terminated: + Gen.builder.position_at_end(ThenEndBB) + if BodyVal.type != result_type: + if isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.IntType): + if BodyVal.type.width < result_type.width: + BodyVal = Gen.builder.zext(BodyVal, result_type, name="ifexp_body_zext") + else: + BodyVal = Gen.builder.trunc(BodyVal, result_type, name="ifexp_body_trunc") + elif isinstance(BodyVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): + # 如果 result_type 是 i8*,说明 Else 分支是字符串字面量 + # 不应该将整数转换为指针,而应该保持整数类型 + # 这里将 result_type 改为 i8 + result_type = ir.IntType(8) + # 重新处理 Else 分支的类型转换 + elif isinstance(BodyVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): + # 指针转整数 + BodyVal = Gen.builder.ptrtoint(BodyVal, result_type, name="ifexp_body_ptr2int") + Gen.builder.branch(MergeBB) + # 在 ElseBB 末尾添加类型转换(如果需要)和分支 + if not ElseEndBB.is_terminated: + Gen.builder.position_at_end(ElseEndBB) + if OrelseVal.type != result_type: + if isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.IntType): + if OrelseVal.type.width < result_type.width: + OrelseVal = Gen.builder.zext(OrelseVal, result_type, name="ifexp_orelse_zext") + else: + OrelseVal = Gen.builder.trunc(OrelseVal, result_type, name="ifexp_orelse_trunc") + elif isinstance(OrelseVal.type, ir.IntType) and isinstance(result_type, ir.PointerType): + # 如果 result_type 是 i8*,说明 BodyVal 分支是字符串字面量 + # 不应该将整数转换为指针,而应该保持整数类型 + # 这里将 result_type 改为 i8 + result_type = ir.IntType(8) + # 重新处理 BodyVal 分支的类型转换(已经在上面处理过了) + elif isinstance(OrelseVal.type, ir.PointerType) and isinstance(result_type, ir.IntType): + # 如果指针指向 i8,加载字符值 + if isinstance(OrelseVal.type.pointee, ir.IntType) and OrelseVal.type.pointee.width == 8: + OrelseVal = Gen._load(OrelseVal, name="ifexp_orelse_Load_char") + else: + OrelseVal = Gen.builder.ptrtoint(OrelseVal, result_type, name="ifexp_orelse_ptr2int") + Gen.builder.branch(MergeBB) + Gen.builder.position_at_start(MergeBB) + result_phi: Any = Gen.builder.phi(result_type, name="ifexp.result") + result_phi.add_incoming(BodyVal, ThenEndBB) + result_phi.add_incoming(OrelseVal, ElseEndBB) + return result_phi + + def _HandleNamedExprLlvm(self, Node: ast.NamedExpr) -> ir.Value: + Gen: LlvmCodeGenerator = self.Trans.LlvmGen + ValueVal: Any = self.HandleExprLlvm(Node.value) + if not ValueVal: + return None + TargetName: str = Node.target.id + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + if TargetName in Gen.variables and Gen.variables[TargetName] is not None: + VarPtr: Any = Gen.variables[TargetName] + if VarPtr.type.pointee == ValueVal.type: + Gen._store(ValueVal, VarPtr) + else: + NewVar: Any = Gen._alloca(ValueVal.type, name=TargetName) + Gen._store(ValueVal, NewVar) + Gen.variables[TargetName] = NewVar + else: + NewVar = Gen._alloca(ValueVal.type, name=TargetName) + Gen._store(ValueVal, NewVar) + Gen.variables[TargetName] = NewVar + Gen._reg_values[TargetName] = ValueVal return ValueVal \ No newline at end of file diff --git a/lib/core/Handles/HandlesExprOps.py b/lib/core/Handles/HandlesExprOps.py index 5002b0b..df1f5ab 100644 --- a/lib/core/Handles/HandlesExprOps.py +++ b/lib/core/Handles/HandlesExprOps.py @@ -1,487 +1,487 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Any -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class ExprOpsHandle(BaseHandle): - def _HandleBinOpLlvm(self, Node: ast.BinOp, VarType: ir.Type | str | None = None) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - Gen._set_node_info(Node, "BinOp") - LeftVal: Any = self.HandleExprLlvm(Node.left, VarType) - if not LeftVal: - return None - RightVal: Any = self.HandleExprLlvm(Node.right, VarType) - if not RightVal: - return None - Op: str | None = self.Trans.ExprHandler.GetOpSymbol(Node.op) - if not Op: - return None - OP_OVERLOAD_MAP: dict[str, list[str]] = { - '+': ['__add__'], '-': ['__sub__'], '*': ['__mul__'], - '/': ['__truediv__', '__div__'], '//': ['__floordiv__'], '%': ['__mod__'], - '**': ['__pow__'], - '&': ['__and__'], '|': ['__or__'], '^': ['__xor__'], - '<<': ['__lshift__'], '>>': ['__rshift__'], - } - if Op in OP_OVERLOAD_MAP: - LeftClassName: str | None = None - if isinstance(LeftVal.type, ir.PointerType): - pointee: ir.Type = LeftVal.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - for CN, ST in Gen.structs.items(): - if pointee == ST: - LeftClassName = CN - break - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen) - if LeftClassName and LeftClassName in Gen.structs: - TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName]) - LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") - if LeftClassName is None and isinstance(Node.left, ast.Name): - LeftClassName = Gen.var_struct_class.get(Node.left.id) - if LeftClassName and LeftClassName in Gen.structs: - if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: - TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName]) - LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") - if LeftClassName: - op_names: list[str] = OP_OVERLOAD_MAP[Op] - for op_name in op_names: - result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal) - if result is not None: - return result - if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): - if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: - if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1: - CharVal: Any = Gen._load(LeftVal, name="Load_char_const") - CharAsInt: Any = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int") - result = Gen.builder.add(CharAsInt, RightVal, name="char_add") - TruncResult: Any = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char") - return TruncResult - is_unsigned: bool = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right) - if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): - if LeftVal.type.width < RightVal.type.width: - need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1 - if not need_zext and isinstance(RightVal, ir.Constant): - signed_max: int = (1 << (LeftVal.type.width - 1)) - 1 - try: - if RightVal.constant > signed_max: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left") - else: - LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left") - elif LeftVal.type.width > RightVal.type.width: - need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 or RightVal.type.width == 1 - if not need_zext and isinstance(LeftVal, ir.Constant): - signed_max = (1 << (RightVal.type.width - 1)) - 1 - try: - if LeftVal.constant > signed_max: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right") - else: - RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right") - elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): - if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType): - LeftVal = Gen._load(LeftVal, name="deref_ptr_binop") - if LeftVal.type.width < RightVal.type.width: - LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left") - elif LeftVal.type.width > RightVal.type.width: - RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref") - elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType): - if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType): - RightVal = Gen._load(RightVal, name="deref_ptr_binop_r") - if RightVal.type.width < LeftVal.type.width: - RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right") - elif RightVal.type.width > LeftVal.type.width: - LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref") - if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name): - vname: str = Node.left.id - if vname in Gen.var_signedness and Gen.var_signedness[vname]: - is_unsigned = True - result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned) - return result - - def _HandleBoolOpLlvm(self, Node: ast.BoolOp) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - - def _to_bool(val: Any, name: str) -> Any: - if isinstance(val.type, (ir.FloatType, ir.DoubleType)): - return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name) - if not isinstance(val.type, ir.IntType) or val.type.width != 1: - return Gen.builder.icmp_signed('!=', val, Gen._ZeroConst(val.type), name=name) - return val - - values: list[ast.expr] = Node.values - if len(values) < 2: - return self.HandleExprLlvm(values[0]) if values else None - if isinstance(Node.op, ast.And): - phi_incomings: list[tuple[ir.Constant, ir.Block]] = [] - end_bb: ir.Block = Gen.func.append_basic_block(name="and.end") - for idx in range(len(values) - 1): - val: Any = self.HandleExprLlvm(values[idx]) - if not val: - if not end_bb.is_terminated: - saved_block: ir.Block = Gen.builder.block - Gen.builder.position_at_start(end_bb) - Gen.builder.unreachable() - Gen.builder.position_at_end(saved_block) - return None - if not isinstance(val.type, ir.IntType) or val.type.width != 1: - val = _to_bool(val, f"andcond{idx}") - cur_bb: ir.Block = Gen.builder.block - next_bb: ir.Block = Gen.func.append_basic_block(name=f"and.rhs{idx}") - Gen.builder.cbranch(val, next_bb, end_bb) - phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb)) - Gen.builder.position_at_start(next_bb) - last_val: Any = self.HandleExprLlvm(values[-1]) - if not last_val: - last_val = ir.Constant(ir.IntType(1), 0) - if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1: - last_val = _to_bool(last_val, "andcond_last") - last_bb: ir.Block = Gen.builder.block - Gen.builder.branch(end_bb) - Gen.builder.position_at_start(end_bb) - result_phi: Any = Gen.builder.phi(ir.IntType(1), name="and.result") - for const_val, bb in phi_incomings: - result_phi.add_incoming(const_val, bb) - result_phi.add_incoming(last_val, last_bb) - return result_phi - elif isinstance(Node.op, ast.Or): - phi_incomings = [] - end_bb = Gen.func.append_basic_block(name="or.end") - for idx in range(len(values) - 1): - val = self.HandleExprLlvm(values[idx]) - if not val: - if not end_bb.is_terminated: - saved_block = Gen.builder.block - Gen.builder.position_at_start(end_bb) - Gen.builder.unreachable() - Gen.builder.position_at_end(saved_block) - return None - if not isinstance(val.type, ir.IntType) or val.type.width != 1: - val = _to_bool(val, f"orcond{idx}") - cur_bb = Gen.builder.block - next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}") - Gen.builder.cbranch(val, end_bb, next_bb) - phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb)) - Gen.builder.position_at_start(next_bb) - last_val = self.HandleExprLlvm(values[-1]) - if not last_val: - last_val = ir.Constant(ir.IntType(1), 1) - if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1: - last_val = _to_bool(last_val, "orcond_last") - last_bb = Gen.builder.block - Gen.builder.branch(end_bb) - Gen.builder.position_at_start(end_bb) - result_phi = Gen.builder.phi(ir.IntType(1), name="or.result") - for const_val, bb in phi_incomings: - result_phi.add_incoming(const_val, bb) - result_phi.add_incoming(last_val, last_bb) - return result_phi - return None - - def _HandleUnaryOpLlvm(self, Node: ast.UnaryOp) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - OperandVal: Any = self.HandleExprLlvm(Node.operand) - if not OperandVal: - return None - OpSymbol: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op) - if not OpSymbol: - return None - UNARY_OVERLOAD_MAP: dict[str, str] = { - '-': '__neg__', - '+': '__pos__', - '~': '__invert__', - } - if OpSymbol in UNARY_OVERLOAD_MAP: - ClassName: str | None = None - if isinstance(OperandVal.type, ir.PointerType): - pointee: ir.Type = OperandVal.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - for CN, ST in Gen.structs.items(): - if pointee == ST: - ClassName = CN - break - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen) - if ClassName and ClassName in Gen.structs: - TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[ClassName]) - OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}") - if ClassName is None and isinstance(Node.operand, ast.Name): - ClassName = Gen.var_struct_class.get(Node.operand.id) - if ClassName and ClassName in Gen.structs: - if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8: - TargetStructPtr = ir.PointerType(Gen.structs[ClassName]) - OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}") - if ClassName: - op_name: str = UNARY_OVERLOAD_MAP[OpSymbol] - result: Any = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen) - if result is not None: - return result - if OpSymbol == 'not': - if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1: - return Gen.builder.not_(OperandVal, name="not_result") - if isinstance(OperandVal.type, ir.PointerType): - null_val: ir.Constant = ir.Constant(OperandVal.type, None) - return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result") - zero: ir.Constant = ir.Constant(OperandVal.type, 0) - return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result") - elif OpSymbol == '~': - if isinstance(OperandVal.type, ir.IntType): - mask: int = (1 << OperandVal.type.width) - 1 - return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result") - return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result") - elif OpSymbol == '+': - return OperandVal - elif OpSymbol == '-': - if isinstance(OperandVal.type, ir.IntType): - return Gen.builder.neg(OperandVal, name="neg_result") - elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)): - return Gen.builder.fneg(OperandVal, name="fneg_result") - return None - - def _HandleCompareLlvm(self, Node: ast.Compare) -> ir.Value | None: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - LeftVal: Any = self.HandleExprLlvm(Node.left) - if not LeftVal: - return None - is_unsigned: bool = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False) - if len(Node.ops) == 1: - Op: ast.cmpop = Node.ops[0] - # in/not in: 调用 __contains__ - if isinstance(Op, (ast.In, ast.NotIn)): - RightVal: Any = self.HandleExprLlvm(Node.comparators[0]) - if RightVal: - ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.comparators[0], Gen) - if ClassName and Gen._has_function(f'{ClassName}.__contains__'): - # 处理 RightVal 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8 - if isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8: - RightVal = Gen.builder.inttoptr(RightVal, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}") - if isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8: - RightVal = Gen.builder.bitcast(RightVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - contains_func: ir.Function = Gen._get_function(f'{ClassName}.__contains__') - result: ir.Value = Gen.builder.call(contains_func, [RightVal, LeftVal], name=f"call_{ClassName}.__contains__") - # 归一化为 i1 - if isinstance(result.type, ir.IntType) and result.type.width > 1: - zero: ir.Constant = ir.Constant(result.type, 0) - result = Gen.builder.icmp_signed('!=', result, zero, name="contains_bool") - if isinstance(Op, ast.NotIn): - result = Gen.builder.not_(result, name="not_in_result") - return result - return ir.Constant(ir.IntType(1), 0) - ComparatorSymbol: str | None = self.Trans.ExprHandler.GetComparatorSymbol(Op) - if not ComparatorSymbol: - return None - RightVal: Any = self.HandleExprLlvm(Node.comparators[0]) - if not RightVal: - return None - # 比较运算符重载检测:当左侧是结构体指针时,尝试调用 __eq__/__ne__/__lt__/__le__/__gt__/__ge__ - CMP_OVERLOAD_MAP: dict[str, str] = { - '==': '__eq__', '!=': '__ne__', '<': '__lt__', - '<=': '__le__', '>': '__gt__', '>=': '__ge__', - } - if ComparatorSymbol in CMP_OVERLOAD_MAP: - LeftClassName: str | None = None - if isinstance(LeftVal.type, ir.PointerType): - pointee: ir.Type = LeftVal.type.pointee - if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - for CN, ST in Gen.structs.items(): - if pointee == ST: - LeftClassName = CN - break - elif isinstance(pointee, ir.IntType) and pointee.width == 8: - LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen) - if LeftClassName and LeftClassName in Gen.structs: - TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName]) - LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") - if LeftClassName is None and isinstance(Node.left, ast.Name): - LeftClassName = Gen.var_struct_class.get(Node.left.id) - if LeftClassName and LeftClassName in Gen.structs: - if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: - TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName]) - LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") - if LeftClassName: - op_name: str = CMP_OVERLOAD_MAP[ComparatorSymbol] - result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal) - if result is not None: - return result - if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant): - if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): - lv: int = LeftVal.constant - rv: int = RightVal.constant - lw: int = LeftVal.type.width - rw: int = RightVal.type.width - if lw < rw: - lv = lv if lv >= 0 else lv + (1 << lw) - elif rw < lw: - rv = rv if rv >= 0 else rv + (1 << rw) - if is_unsigned: - mask_l: int = (1 << max(lw, rw)) - 1 - lv = lv & mask_l - rv = rv & mask_l - cmp_map: dict[str, bool] = { - '==': lv == rv, '!=': lv != rv, - '<': lv < rv, '>': lv > rv, - '<=': lv <= rv, '>=': lv >= rv, - } - result: bool = cmp_map.get(ComparatorSymbol, False) - return ir.Constant(ir.IntType(1), 1 if result else 0) - # is / is not: 值类型(IntType)与 None(空指针常量)比较 - # 值类型(如 i8/i32)永远不可能为 None,因此: - # - 值类型 is None → 恒为 false (i1 0) - # - 值类型 is not None → 恒为 true (i1 1) - # 此检查必须在类型对齐之前,否则类型对齐会对 i8* null 执行 load(空指针解引用)导致崩溃 - if ComparatorSymbol in ('is', 'is not'): - LeftIsNullPtr: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None and isinstance(LeftVal.type, ir.PointerType) - RightIsNullPtr: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None and isinstance(RightVal.type, ir.PointerType) - LeftIsValueType: bool = isinstance(LeftVal.type, ir.IntType) - RightIsValueType: bool = isinstance(RightVal.type, ir.IntType) - if (LeftIsValueType and RightIsNullPtr) or (RightIsValueType and LeftIsNullPtr): - IsNotResult: int = 1 if ComparatorSymbol == 'is not' else 0 - return ir.Constant(ir.IntType(1), IsNotResult) - if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): - if LeftVal.type.width < RightVal.type.width: - # 如果宽类型常量值超出窄类型有符号范围,则必须用zext - # i8 类型默认使用 zext(系统编程中 i8 几乎总是无符号字节) - need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1 - if not need_zext and isinstance(RightVal, ir.Constant): - signed_max: int = (1 << (LeftVal.type.width - 1)) - 1 - try: - if RightVal.constant > signed_max or RightVal.constant < 0: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp") - else: - LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp") - elif LeftVal.type.width > RightVal.type.width: - need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 or RightVal.type.width == 1 - if not need_zext and isinstance(LeftVal, ir.Constant): - signed_max = (1 << (RightVal.type.width - 1)) - 1 - try: - if LeftVal.constant > signed_max or LeftVal.constant < 0: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp") - else: - RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp") - elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): - if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8: - LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp") - else: - if isinstance(RightVal, ir.Constant) and RightVal.constant == 0: - RightVal = ir.Constant(LeftVal.type, None) - else: - # 指针 vs 非零整数: 将指针转为整数走正常 ==(地址值比较) - LeftVal = Gen.builder.ptrtoint(LeftVal, RightVal.type, name="ptr2int_cmp") - elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType): - if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8: - RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp") - else: - if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0: - LeftVal = ir.Constant(RightVal.type, None) - else: - # 非零整数 vs 指针: 将指针转为整数走正常 ==(地址值比较) - RightVal = Gen.builder.ptrtoint(RightVal, LeftVal.type, name="ptr2int_cmp") - # is / is not: 地址比较(指针)或值比较(int) - if ComparatorSymbol in ('is', 'is not'): - if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType): - addr_cmp = Gen.builder.icmp_unsigned('==', LeftVal, RightVal, name="is_cmp") - if ComparatorSymbol == 'is not': - addr_cmp = Gen.builder.not_(addr_cmp, name="is_not_result") - return addr_cmp - if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): - val_cmp = Gen.builder.icmp_signed('==', LeftVal, RightVal, name="is_cmp") - if ComparatorSymbol == 'is not': - val_cmp = Gen.builder.not_(val_cmp, name="is_not_result") - return val_cmp - # == / !=: 指针间做地址比较(C-Like 语义,不隐式调用 strcmp) - # 如需字符串内容比较,应显式调用 string.strcmp() - if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType): - result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") - elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)): - if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType): - RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp") - elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType): - LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp") - result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") - elif is_unsigned: - result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") - else: - result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") - return result - EndBB: ir.Block = Gen.func.append_basic_block(name="cmp.end") - phi_incomings: list[tuple[ir.Value, ir.Block]] = [] - for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)): - ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op) - if not ComparatorSymbol: - continue - RightVal = self.HandleExprLlvm(Comparator) - if not RightVal: - continue - if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): - if LeftVal.type.width < RightVal.type.width: - need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1 - if not need_zext and isinstance(RightVal, ir.Constant): - signed_max = (1 << (LeftVal.type.width - 1)) - 1 - try: - if RightVal.constant > signed_max or RightVal.constant < 0: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}") - else: - LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}") - elif LeftVal.type.width > RightVal.type.width: - need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 or RightVal.type.width == 1 - if not need_zext and isinstance(LeftVal, ir.Constant): - signed_max = (1 << (RightVal.type.width - 1)) - 1 - try: - if LeftVal.constant > signed_max or LeftVal.constant < 0: - need_zext = True - except (TypeError, ValueError): - pass - if need_zext: - RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}") - else: - RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}") - if is_unsigned: - cmp_result: Any = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") - elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)): - if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType): - RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}") - elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType): - LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}") - cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") - else: - cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") - if i < len(Node.ops) - 1: - NextBB: ir.Block = Gen.func.append_basic_block(name=f"cmp.next.{i}") - cur_bb: ir.Block = Gen.builder.block - Gen.builder.cbranch(cmp_result, NextBB, EndBB) - phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb)) - Gen.builder.position_at_start(NextBB) - LeftVal = RightVal - else: - cur_bb = Gen.builder.block - Gen.builder.branch(EndBB) - phi_incomings.append((cmp_result, cur_bb)) - Gen.builder.position_at_start(EndBB) - final_result: Any = Gen.builder.phi(ir.IntType(1), name="final_cmp") - for val, bb in phi_incomings: - final_result.add_incoming(val, bb) +from __future__ import annotations +from typing import TYPE_CHECKING, Any +if TYPE_CHECKING: + from lib.core.translator import Translator + from lib.core.LlvmCodeGenerator import LlvmCodeGenerator +from lib.core.Handles.HandlesBase import BaseHandle +import vast as ast +import llvmlite.ir as ir + + +class ExprOpsHandle(BaseHandle): + def _HandleBinOpLlvm(self, Node: ast.BinOp, VarType: ir.Type | str | None = None) -> ir.Value | None: + Gen: LlvmCodeGenerator = self.Trans.LlvmGen + Gen._set_node_info(Node, "BinOp") + LeftVal: Any = self.HandleExprLlvm(Node.left, VarType) + if not LeftVal: + return None + RightVal: Any = self.HandleExprLlvm(Node.right, VarType) + if not RightVal: + return None + Op: str | None = self.Trans.ExprHandler.GetOpSymbol(Node.op) + if not Op: + return None + OP_OVERLOAD_MAP: dict[str, list[str]] = { + '+': ['__add__'], '-': ['__sub__'], '*': ['__mul__'], + '/': ['__truediv__', '__div__'], '//': ['__floordiv__'], '%': ['__mod__'], + '**': ['__pow__'], + '&': ['__and__'], '|': ['__or__'], '^': ['__xor__'], + '<<': ['__lshift__'], '>>': ['__rshift__'], + } + if Op in OP_OVERLOAD_MAP: + LeftClassName: str | None = None + if isinstance(LeftVal.type, ir.PointerType): + pointee: ir.Type = LeftVal.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + LeftClassName = CN + break + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen) + if LeftClassName and LeftClassName in Gen.structs: + TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName]) + LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") + if LeftClassName is None and isinstance(Node.left, ast.Name): + LeftClassName = Gen.var_struct_class.get(Node.left.id) + if LeftClassName and LeftClassName in Gen.structs: + if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: + TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName]) + LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") + if LeftClassName: + op_names: list[str] = OP_OVERLOAD_MAP[Op] + for op_name in op_names: + result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal) + if result is not None: + return result + if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): + if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: + if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1: + CharVal: Any = Gen._load(LeftVal, name="Load_char_const") + CharAsInt: Any = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int") + result = Gen.builder.add(CharAsInt, RightVal, name="char_add") + TruncResult: Any = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char") + return TruncResult + is_unsigned: bool = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right) + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + if LeftVal.type.width < RightVal.type.width: + need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1 + if not need_zext and isinstance(RightVal, ir.Constant): + signed_max: int = (1 << (LeftVal.type.width - 1)) - 1 + try: + if RightVal.constant > signed_max: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left") + else: + LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left") + elif LeftVal.type.width > RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 or RightVal.type.width == 1 + if not need_zext and isinstance(LeftVal, ir.Constant): + signed_max = (1 << (RightVal.type.width - 1)) - 1 + try: + if LeftVal.constant > signed_max: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right") + else: + RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right") + elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): + if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType): + LeftVal = Gen._load(LeftVal, name="deref_ptr_binop") + if LeftVal.type.width < RightVal.type.width: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left") + elif LeftVal.type.width > RightVal.type.width: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref") + elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType): + if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType): + RightVal = Gen._load(RightVal, name="deref_ptr_binop_r") + if RightVal.type.width < LeftVal.type.width: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right") + elif RightVal.type.width > LeftVal.type.width: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref") + if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name): + vname: str = Node.left.id + if vname in Gen.var_signedness and Gen.var_signedness[vname]: + is_unsigned = True + result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned) + return result + + def _HandleBoolOpLlvm(self, Node: ast.BoolOp) -> ir.Value | None: + Gen: LlvmCodeGenerator = self.Trans.LlvmGen + + def _to_bool(val: Any, name: str) -> Any: + if isinstance(val.type, (ir.FloatType, ir.DoubleType)): + return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name) + if not isinstance(val.type, ir.IntType) or val.type.width != 1: + return Gen.builder.icmp_signed('!=', val, Gen._ZeroConst(val.type), name=name) + return val + + values: list[ast.expr] = Node.values + if len(values) < 2: + return self.HandleExprLlvm(values[0]) if values else None + if isinstance(Node.op, ast.And): + phi_incomings: list[tuple[ir.Constant, ir.Block]] = [] + end_bb: ir.Block = Gen.func.append_basic_block(name="and.end") + for idx in range(len(values) - 1): + val: Any = self.HandleExprLlvm(values[idx]) + if not val: + if not end_bb.is_terminated: + saved_block: ir.Block = Gen.builder.block + Gen.builder.position_at_start(end_bb) + Gen.builder.unreachable() + Gen.builder.position_at_end(saved_block) + return None + if not isinstance(val.type, ir.IntType) or val.type.width != 1: + val = _to_bool(val, f"andcond{idx}") + cur_bb: ir.Block = Gen.builder.block + next_bb: ir.Block = Gen.func.append_basic_block(name=f"and.rhs{idx}") + Gen.builder.cbranch(val, next_bb, end_bb) + phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb)) + Gen.builder.position_at_start(next_bb) + last_val: Any = self.HandleExprLlvm(values[-1]) + if not last_val: + last_val = ir.Constant(ir.IntType(1), 0) + if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1: + last_val = _to_bool(last_val, "andcond_last") + last_bb: ir.Block = Gen.builder.block + Gen.builder.branch(end_bb) + Gen.builder.position_at_start(end_bb) + result_phi: Any = Gen.builder.phi(ir.IntType(1), name="and.result") + for const_val, bb in phi_incomings: + result_phi.add_incoming(const_val, bb) + result_phi.add_incoming(last_val, last_bb) + return result_phi + elif isinstance(Node.op, ast.Or): + phi_incomings = [] + end_bb = Gen.func.append_basic_block(name="or.end") + for idx in range(len(values) - 1): + val = self.HandleExprLlvm(values[idx]) + if not val: + if not end_bb.is_terminated: + saved_block = Gen.builder.block + Gen.builder.position_at_start(end_bb) + Gen.builder.unreachable() + Gen.builder.position_at_end(saved_block) + return None + if not isinstance(val.type, ir.IntType) or val.type.width != 1: + val = _to_bool(val, f"orcond{idx}") + cur_bb = Gen.builder.block + next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}") + Gen.builder.cbranch(val, end_bb, next_bb) + phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb)) + Gen.builder.position_at_start(next_bb) + last_val = self.HandleExprLlvm(values[-1]) + if not last_val: + last_val = ir.Constant(ir.IntType(1), 1) + if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1: + last_val = _to_bool(last_val, "orcond_last") + last_bb = Gen.builder.block + Gen.builder.branch(end_bb) + Gen.builder.position_at_start(end_bb) + result_phi = Gen.builder.phi(ir.IntType(1), name="or.result") + for const_val, bb in phi_incomings: + result_phi.add_incoming(const_val, bb) + result_phi.add_incoming(last_val, last_bb) + return result_phi + return None + + def _HandleUnaryOpLlvm(self, Node: ast.UnaryOp) -> ir.Value | None: + Gen: LlvmCodeGenerator = self.Trans.LlvmGen + OperandVal: Any = self.HandleExprLlvm(Node.operand) + if not OperandVal: + return None + OpSymbol: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op) + if not OpSymbol: + return None + UNARY_OVERLOAD_MAP: dict[str, str] = { + '-': '__neg__', + '+': '__pos__', + '~': '__invert__', + } + if OpSymbol in UNARY_OVERLOAD_MAP: + ClassName: str | None = None + if isinstance(OperandVal.type, ir.PointerType): + pointee: ir.Type = OperandVal.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + ClassName = CN + break + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen) + if ClassName and ClassName in Gen.structs: + TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[ClassName]) + OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}") + if ClassName is None and isinstance(Node.operand, ast.Name): + ClassName = Gen.var_struct_class.get(Node.operand.id) + if ClassName and ClassName in Gen.structs: + if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8: + TargetStructPtr = ir.PointerType(Gen.structs[ClassName]) + OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}") + if ClassName: + op_name: str = UNARY_OVERLOAD_MAP[OpSymbol] + result: Any = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen) + if result is not None: + return result + if OpSymbol == 'not': + if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1: + return Gen.builder.not_(OperandVal, name="not_result") + if isinstance(OperandVal.type, ir.PointerType): + null_val: ir.Constant = ir.Constant(OperandVal.type, None) + return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result") + zero: ir.Constant = ir.Constant(OperandVal.type, 0) + return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result") + elif OpSymbol == '~': + if isinstance(OperandVal.type, ir.IntType): + mask: int = (1 << OperandVal.type.width) - 1 + return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result") + return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result") + elif OpSymbol == '+': + return OperandVal + elif OpSymbol == '-': + if isinstance(OperandVal.type, ir.IntType): + return Gen.builder.neg(OperandVal, name="neg_result") + elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)): + return Gen.builder.fneg(OperandVal, name="fneg_result") + return None + + def _HandleCompareLlvm(self, Node: ast.Compare) -> ir.Value | None: + Gen: LlvmCodeGenerator = self.Trans.LlvmGen + LeftVal: Any = self.HandleExprLlvm(Node.left) + if not LeftVal: + return None + is_unsigned: bool = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False) + if len(Node.ops) == 1: + Op: ast.cmpop = Node.ops[0] + # in/not in: 调用 __contains__ + if isinstance(Op, (ast.In, ast.NotIn)): + RightVal: Any = self.HandleExprLlvm(Node.comparators[0]) + if RightVal: + ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.comparators[0], Gen) + if ClassName and Gen._has_function(f'{ClassName}.__contains__'): + # 处理 RightVal 为 i8(整数)的情况:联合类型 | t.CPtr 降级后可能被 load 为 i8 + if isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8: + RightVal = Gen.builder.inttoptr(RightVal, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}") + if isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8: + RightVal = Gen.builder.bitcast(RightVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + contains_func: ir.Function = Gen._get_function(f'{ClassName}.__contains__') + result: ir.Value = Gen.builder.call(contains_func, [RightVal, LeftVal], name=f"call_{ClassName}.__contains__") + # 归一化为 i1 + if isinstance(result.type, ir.IntType) and result.type.width > 1: + zero: ir.Constant = ir.Constant(result.type, 0) + result = Gen.builder.icmp_signed('!=', result, zero, name="contains_bool") + if isinstance(Op, ast.NotIn): + result = Gen.builder.not_(result, name="not_in_result") + return result + return ir.Constant(ir.IntType(1), 0) + ComparatorSymbol: str | None = self.Trans.ExprHandler.GetComparatorSymbol(Op) + if not ComparatorSymbol: + return None + RightVal: Any = self.HandleExprLlvm(Node.comparators[0]) + if not RightVal: + return None + # 比较运算符重载检测:当左侧是结构体指针时,尝试调用 __eq__/__ne__/__lt__/__le__/__gt__/__ge__ + CMP_OVERLOAD_MAP: dict[str, str] = { + '==': '__eq__', '!=': '__ne__', '<': '__lt__', + '<=': '__le__', '>': '__gt__', '>=': '__ge__', + } + if ComparatorSymbol in CMP_OVERLOAD_MAP: + LeftClassName: str | None = None + if isinstance(LeftVal.type, ir.PointerType): + pointee: ir.Type = LeftVal.type.pointee + if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + for CN, ST in Gen.structs.items(): + if pointee == ST: + LeftClassName = CN + break + elif isinstance(pointee, ir.IntType) and pointee.width == 8: + LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen) + if LeftClassName and LeftClassName in Gen.structs: + TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName]) + LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") + if LeftClassName is None and isinstance(Node.left, ast.Name): + LeftClassName = Gen.var_struct_class.get(Node.left.id) + if LeftClassName and LeftClassName in Gen.structs: + if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8: + TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName]) + LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}") + if LeftClassName: + op_name: str = CMP_OVERLOAD_MAP[ComparatorSymbol] + result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal) + if result is not None: + return result + if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant): + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + lv: int = LeftVal.constant + rv: int = RightVal.constant + lw: int = LeftVal.type.width + rw: int = RightVal.type.width + if lw < rw: + lv = lv if lv >= 0 else lv + (1 << lw) + elif rw < lw: + rv = rv if rv >= 0 else rv + (1 << rw) + if is_unsigned: + mask_l: int = (1 << max(lw, rw)) - 1 + lv = lv & mask_l + rv = rv & mask_l + cmp_map: dict[str, bool] = { + '==': lv == rv, '!=': lv != rv, + '<': lv < rv, '>': lv > rv, + '<=': lv <= rv, '>=': lv >= rv, + } + result: bool = cmp_map.get(ComparatorSymbol, False) + return ir.Constant(ir.IntType(1), 1 if result else 0) + # is / is not: 值类型(IntType)与 None(空指针常量)比较 + # 值类型(如 i8/i32)永远不可能为 None,因此: + # - 值类型 is None → 恒为 false (i1 0) + # - 值类型 is not None → 恒为 true (i1 1) + # 此检查必须在类型对齐之前,否则类型对齐会对 i8* null 执行 load(空指针解引用)导致崩溃 + if ComparatorSymbol in ('is', 'is not'): + LeftIsNullPtr: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None and isinstance(LeftVal.type, ir.PointerType) + RightIsNullPtr: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None and isinstance(RightVal.type, ir.PointerType) + LeftIsValueType: bool = isinstance(LeftVal.type, ir.IntType) + RightIsValueType: bool = isinstance(RightVal.type, ir.IntType) + if (LeftIsValueType and RightIsNullPtr) or (RightIsValueType and LeftIsNullPtr): + IsNotResult: int = 1 if ComparatorSymbol == 'is not' else 0 + return ir.Constant(ir.IntType(1), IsNotResult) + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + if LeftVal.type.width < RightVal.type.width: + # 如果宽类型常量值超出窄类型有符号范围,则必须用zext + # i8 类型默认使用 zext(系统编程中 i8 几乎总是无符号字节) + need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1 + if not need_zext and isinstance(RightVal, ir.Constant): + signed_max: int = (1 << (LeftVal.type.width - 1)) - 1 + try: + if RightVal.constant > signed_max or RightVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp") + else: + LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp") + elif LeftVal.type.width > RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 or RightVal.type.width == 1 + if not need_zext and isinstance(LeftVal, ir.Constant): + signed_max = (1 << (RightVal.type.width - 1)) - 1 + try: + if LeftVal.constant > signed_max or LeftVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp") + else: + RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp") + elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType): + if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8: + LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp") + else: + if isinstance(RightVal, ir.Constant) and RightVal.constant == 0: + RightVal = ir.Constant(LeftVal.type, None) + else: + # 指针 vs 非零整数: 将指针转为整数走正常 ==(地址值比较) + LeftVal = Gen.builder.ptrtoint(LeftVal, RightVal.type, name="ptr2int_cmp") + elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType): + if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8: + RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp") + else: + if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0: + LeftVal = ir.Constant(RightVal.type, None) + else: + # 非零整数 vs 指针: 将指针转为整数走正常 ==(地址值比较) + RightVal = Gen.builder.ptrtoint(RightVal, LeftVal.type, name="ptr2int_cmp") + # is / is not: 地址比较(指针)或值比较(int) + if ComparatorSymbol in ('is', 'is not'): + if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType): + addr_cmp = Gen.builder.icmp_unsigned('==', LeftVal, RightVal, name="is_cmp") + if ComparatorSymbol == 'is not': + addr_cmp = Gen.builder.not_(addr_cmp, name="is_not_result") + return addr_cmp + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + val_cmp = Gen.builder.icmp_signed('==', LeftVal, RightVal, name="is_cmp") + if ComparatorSymbol == 'is not': + val_cmp = Gen.builder.not_(val_cmp, name="is_not_result") + return val_cmp + # == / !=: 指针间做地址比较(C-Like 语义,不隐式调用 strcmp) + # 如需字符串内容比较,应显式调用 string.strcmp() + if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType): + result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)): + if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType): + RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp") + elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType): + LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp") + result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + elif is_unsigned: + result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + else: + result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult") + return result + EndBB: ir.Block = Gen.func.append_basic_block(name="cmp.end") + phi_incomings: list[tuple[ir.Value, ir.Block]] = [] + for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)): + ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op) + if not ComparatorSymbol: + continue + RightVal = self.HandleExprLlvm(Comparator) + if not RightVal: + continue + if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType): + if LeftVal.type.width < RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1 + if not need_zext and isinstance(RightVal, ir.Constant): + signed_max = (1 << (LeftVal.type.width - 1)) - 1 + try: + if RightVal.constant > signed_max or RightVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}") + else: + LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}") + elif LeftVal.type.width > RightVal.type.width: + need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 or RightVal.type.width == 1 + if not need_zext and isinstance(LeftVal, ir.Constant): + signed_max = (1 << (RightVal.type.width - 1)) - 1 + try: + if LeftVal.constant > signed_max or LeftVal.constant < 0: + need_zext = True + except (TypeError, ValueError): + pass + if need_zext: + RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}") + else: + RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}") + if is_unsigned: + cmp_result: Any = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") + elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)): + if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType): + RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}") + elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType): + LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}") + cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") + else: + cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}") + if i < len(Node.ops) - 1: + NextBB: ir.Block = Gen.func.append_basic_block(name=f"cmp.next.{i}") + cur_bb: ir.Block = Gen.builder.block + Gen.builder.cbranch(cmp_result, NextBB, EndBB) + phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb)) + Gen.builder.position_at_start(NextBB) + LeftVal = RightVal + else: + cur_bb = Gen.builder.block + Gen.builder.branch(EndBB) + phi_incomings.append((cmp_result, cur_bb)) + Gen.builder.position_at_start(EndBB) + final_result: Any = Gen.builder.phi(ir.IntType(1), name="final_cmp") + for val, bb in phi_incomings: + final_result.add_incoming(val, bb) return final_result \ No newline at end of file diff --git a/lib/core/Handles/HandlesExprUtils.py b/lib/core/Handles/HandlesExprUtils.py index 0464849..b2fd047 100644 --- a/lib/core/Handles/HandlesExprUtils.py +++ b/lib/core/Handles/HandlesExprUtils.py @@ -1,305 +1,305 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Any -if TYPE_CHECKING: - from lib.core.translator import Translator - from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -import ast -import llvmlite.ir as ir -from lib.core.SymbolUtils import IsTModule - - -class ExprUtils: - def __init__(self, translator: "Translator") -> None: - self.Trans: Translator = translator - - def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None: - OpMap: dict[type, str] = { - ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/', - ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&', - ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>', - ast.MatMult: '@', - } - return OpMap.get(type(Op), None) - - def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None: - OpMap: dict[type, str] = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'} - return OpMap.get(type(Op), None) - - def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None: - OpMap: dict[type, str] = { - ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=', - ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not', - ast.In: 'in', ast.NotIn: 'not in', - } - return OpMap.get(type(Op), None) - - def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None: - if isinstance(node, ast.Name): - VarName: str = node.id - return Gen.var_struct_class.get(VarName) - if isinstance(node, ast.Attribute): - AttrName: str = node.attr - # 从父对象的类成员类型推导(如 self._ht → ParsedArgs._ht → HashTable) - # 必须先查 BaseClass,避免字段名和变量名冲突导致错误分派 - # (如 old_args.args 匹配到函数参数 args 的 var_struct_class='AST') - BaseClass: str | None = self._get_var_class(node.value, Gen) - if not BaseClass and isinstance(node.value, ast.Name) and node.value.id == 'self': - BaseClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None) - if BaseClass and BaseClass in Gen.class_members: - for m_name, m_type in Gen.class_members[BaseClass]: - if m_name == AttrName: - if isinstance(m_type, ir.PointerType) and isinstance(m_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - found = Gen.find_struct_by_pointee(m_type.pointee) - if found: - return found[0] - # 联合类型(如 GSList[Param] | t.CPtr)降级为 i8* 时, - # 从 class_member_element_class 查找泛型特化类名 - element_class_map = getattr(Gen, 'class_member_element_class', {}) - element_class = element_class_map.get(BaseClass, {}).get(AttrName) - if element_class: - return element_class - break - # Fallback: 直接查找 var_struct_class(放在 BaseClass 查找之后, - # 避免字段名和变量名冲突导致错误分派) - cls: str | None = Gen.var_struct_class.get(AttrName) - if cls: - return cls - return None - return None - - def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None: - FullMethodName: str = f'{ClassName}.{op_name}' - if not Gen._has_function(FullMethodName): - FullMethodName = f'{ClassName}.{op_name}__' - if not Gen._has_function(FullMethodName): - # 多继承:沿 MRO 祖先链查找 dunder 方法(先声明父类优先,与 TPV 一致) - for anc in Gen._get_mro_chain(ClassName)[1:]: - anc_method: str = f'{anc}.{op_name}' - if Gen._has_function(anc_method): - FullMethodName = anc_method - break - anc_method_ss = f'{anc}.{op_name}__' - if Gen._has_function(anc_method_ss): - FullMethodName = anc_method_ss - break - if not Gen._has_function(FullMethodName): - # 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray')且 - # 无直接匹配方法时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本 - # (如 'ndarray[double]')。注解 'numpy.ndarray | t.CPtr' 未指定类型参数时, - # var_struct_class 仅记录裸模板名,但方法只在特化版本中定义。 - # 选择策略:优先选 obj_val.type.pointee 实际匹配的特化;否则选第一个有方法的特化。 - if '[' not in ClassName: - SpecClass: str | None = None - for CN in Gen.structs.keys(): - if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}'): - SpecClass = CN - break - if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}__'): - SpecClass = CN - break - if SpecClass: - FullMethodName = f'{SpecClass}.{op_name}' - if not Gen._has_function(FullMethodName): - FullMethodName = f'{SpecClass}.{op_name}__' - if Gen._has_function(FullMethodName): - func: Any = Gen._get_function(FullMethodName) - # 多继承 this 调整:运算符重载方法定义在"无 vtable 父类"且字段区偏移 > 0 时, - # 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。 - method_anc: str | None = None - _fm_short: str = FullMethodName.split('.')[-1] if '.' in FullMethodName else FullMethodName - if '.' in FullMethodName: - _fm_cls: str = FullMethodName.split('.')[0] - if _fm_cls != ClassName: - method_anc = _fm_cls - _call_self: Any = self.Trans.ExprCallHandle._adjust_this_for_inherited_method(Gen, obj_val, ClassName, method_anc) - call_args: list[Any] = [_call_self] - if other_val is not None: - call_args.append(other_val) - if len(func.ftype.args) == len(call_args): - for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)): - if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType): - if expected_type != actual_val.type: - if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}") - result: Any = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}") - return result - return None - - def _llvm_type_to_detailed_string(self, llvm_type: ir.Type, var_name: str = "") -> dict[str, Any]: - info: dict[str, Any] = { - 'name': "unknown", - 'size': 0, - 'signed': False, - 'ptr': False - } - if isinstance(llvm_type, ir.IntType): - info['size'] = llvm_type.width // 8 - info['signed'] = True - if llvm_type.width == 8: - info['name'] = "char" - elif llvm_type.width == 16: - info['name'] = "short" - elif llvm_type.width == 32: - info['name'] = "int" - elif llvm_type.width == 64: - info['name'] = "long long" - else: - info['name'] = f"int{llvm_type.width}" - elif isinstance(llvm_type, ir.DoubleType): - info['size'] = 8 - info['signed'] = True - info['name'] = "double" - elif isinstance(llvm_type, ir.FloatType): - info['size'] = 4 - info['signed'] = True - info['name'] = "float" - elif isinstance(llvm_type, ir.PointerType): - info['size'] = 8 - info['signed'] = False - info['ptr'] = True - pointee_info: dict[str, Any] = self._llvm_type_to_detailed_string(llvm_type.pointee) - info['name'] = f"{pointee_info['name']}*" - elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)): - size: int = 0 - for elem in llvm_type.elements: - elem_info: dict[str, Any] = self._llvm_type_to_detailed_string(elem) - size += elem_info['size'] - info['size'] = size - info['signed'] = False - if isinstance(llvm_type, ir.IdentifiedStructType): - info['name'] = llvm_type.name - else: - info['name'] = "struct" - elif isinstance(llvm_type, ir.ArrayType): - elem_info = self._llvm_type_to_detailed_string(llvm_type.element) - info['size'] = elem_info['size'] * llvm_type.count - info['signed'] = elem_info['signed'] - info['name'] = f"{elem_info['name']}[]" - elif isinstance(llvm_type, ir.VoidType): - info['size'] = 0 - info['signed'] = False - info['name'] = "void" - else: - info['size'] = 0 - info['signed'] = False - info['name'] = str(llvm_type) - return info - - def _infer_expr_llvm_type_full(self, node: ast.AST) -> ir.Type: - Gen: LlvmCodeGenerator = self.Trans.LlvmGen - if isinstance(node, ast.Constant): - if isinstance(node.value, bool): - return ir.IntType(32) - elif isinstance(node.value, int): - return ir.IntType(32) - elif isinstance(node.value, float): - return ir.DoubleType() - elif isinstance(node.value, str): - if getattr(node, 'kind', None) == 'u': - return ir.PointerType(ir.IntType(16)) - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - elif isinstance(node, ast.Name): - if node.id in Gen.variables: - var_ptr: Any = Gen.variables[node.id] - if isinstance(var_ptr.type, ir.PointerType): - return var_ptr.type.pointee - return var_ptr.type - if node.id in Gen._reg_values: - return Gen._reg_values[node.id].type - return ir.IntType(32) - elif isinstance(node, ast.Attribute): - attr_name: str = node.attr - AttrInfo: Any = self.Trans.SymbolTable.lookup(attr_name) - if AttrInfo and getattr(AttrInfo, 'IsEnumMember', None): - return ir.IntType(32) - return ir.IntType(32) - elif isinstance(node, ast.BinOp): - left_type: ir.Type = self._infer_expr_llvm_type_full(node.left) - right_type: ir.Type = self._infer_expr_llvm_type_full(node.right) - if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)): - return ir.DoubleType() - if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType): - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - elif isinstance(node, ast.UnaryOp): - return self._infer_expr_llvm_type_full(node.operand) - elif isinstance(node, ast.Subscript): - val_type: ir.Type = self._infer_expr_llvm_type_full(node.value) - if isinstance(val_type, ir.PointerType): - if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8: - return ir.IntType(8) - if isinstance(val_type.pointee, ir.ArrayType): - return ir.PointerType(val_type.pointee.element) - return val_type.pointee - if isinstance(val_type, ir.ArrayType): - return val_type.element - if isinstance(val_type, ir.IntType): - return ir.IntType(8) - return ir.IntType(32) - elif isinstance(node, ast.Call): - if isinstance(node.func, ast.Name): - func_name: str = node.func.id - if Gen._has_function(func_name): - fn: Any = Gen._get_function(func_name) - return fn.function_type.return_type - if func_name == 'len': - return ir.IntType(32) - if func_name == 'sizeof': - return ir.IntType(32) - if func_name == 'ord': - return ir.IntType(32) - if func_name == 'chr': - return ir.IntType(8) - if func_name == 'int': - return ir.IntType(32) - if func_name == 'float' or func_name == 'double': - return ir.DoubleType() - elif isinstance(node.func, ast.Attribute): - if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': - if node.func.attr == 'Deref': - return ir.IntType(64) - if isinstance(node.func.value, ast.Name) and IsTModule(node.func.value.id, self.Trans.SymbolTable): - if node.func.attr == 'CChar': - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - elif isinstance(node, ast.Compare): - return ir.IntType(1) - elif isinstance(node, ast.BoolOp): - return ir.IntType(1) - elif isinstance(node, ast.IfExp): - return self._infer_expr_llvm_type_full(node.body) - elif isinstance(node, ast.Attribute): - return ir.PointerType(ir.IntType(8)) - return ir.IntType(32) - - def _collect_names(self, node: ast.AST, bound: set[str], free: set[str] | None = None) -> None: - """收集 AST 节点中的绑定变量和自由变量 - - Args: - node: AST 节点 - bound: 集合,收集绑定变量(ast.Store 上下文) - free: 集合,收集自由变量(ast.Load 上下文),可为 None - """ - if free is None: - free = set() - if isinstance(node, ast.Name): - if isinstance(node.ctx, ast.Store): - bound.add(node.id) - elif isinstance(node.ctx, ast.Load): - free.add(node.id) - elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)): - # 这些节点有自己的作用域,不递归进入 - # 但需要收集参数名作为 bound - if hasattr(node, 'args') and node.args: - for arg in node.args.args: - bound.add(arg.arg) - elif getattr(node, '_fields', None): - for field in node._fields: - value: Any = getattr(node, field, None) - if isinstance(value, list): - for item in value: - if isinstance(item, (ast.stmt, ast.expr)): - self._collect_names(item, bound, free) - elif isinstance(value, (ast.stmt, ast.expr)): +from __future__ import annotations +from typing import TYPE_CHECKING, Any +if TYPE_CHECKING: + from lib.core.translator import Translator + from lib.core.LlvmCodeGenerator import LlvmCodeGenerator +import vast as ast +import llvmlite.ir as ir +from lib.core.SymbolUtils import IsTModule + + +class ExprUtils: + def __init__(self, translator: "Translator") -> None: + self.Trans: Translator = translator + + def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None: + OpMap: dict[type, str] = { + ast.Add: '+', ast.Sub: '-', ast.Mult: '*', ast.Div: '/', + ast.FloorDiv: '//', ast.Mod: '%', ast.Pow: '**', ast.BitAnd: '&', + ast.BitOr: '|', ast.BitXor: '^', ast.LShift: '<<', ast.RShift: '>>', + ast.MatMult: '@', + } + return OpMap.get(type(Op), None) + + def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None: + OpMap: dict[type, str] = {ast.Invert: '~', ast.Not: 'not', ast.UAdd: '+', ast.USub: '-'} + return OpMap.get(type(Op), None) + + def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None: + OpMap: dict[type, str] = { + ast.Eq: '==', ast.NotEq: '!=', ast.Lt: '<', ast.LtE: '<=', + ast.Gt: '>', ast.GtE: '>=', ast.Is: 'is', ast.IsNot: 'is not', + ast.In: 'in', ast.NotIn: 'not in', + } + return OpMap.get(type(Op), None) + + def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None: + if isinstance(node, ast.Name): + VarName: str = node.id + return Gen.var_struct_class.get(VarName) + if isinstance(node, ast.Attribute): + AttrName: str = node.attr + # 从父对象的类成员类型推导(如 self._ht → ParsedArgs._ht → HashTable) + # 必须先查 BaseClass,避免字段名和变量名冲突导致错误分派 + # (如 old_args.args 匹配到函数参数 args 的 var_struct_class='AST') + BaseClass: str | None = self._get_var_class(node.value, Gen) + if not BaseClass and isinstance(node.value, ast.Name) and node.value.id == 'self': + BaseClass = getattr(self.Trans, '_CurrentCpythonObjectClass', None) + if BaseClass and BaseClass in Gen.class_members: + for m_name, m_type in Gen.class_members[BaseClass]: + if m_name == AttrName: + if isinstance(m_type, ir.PointerType) and isinstance(m_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + found = Gen.find_struct_by_pointee(m_type.pointee) + if found: + return found[0] + # 联合类型(如 GSList[Param] | t.CPtr)降级为 i8* 时, + # 从 class_member_element_class 查找泛型特化类名 + element_class_map = getattr(Gen, 'class_member_element_class', {}) + element_class = element_class_map.get(BaseClass, {}).get(AttrName) + if element_class: + return element_class + break + # Fallback: 直接查找 var_struct_class(放在 BaseClass 查找之后, + # 避免字段名和变量名冲突导致错误分派) + cls: str | None = Gen.var_struct_class.get(AttrName) + if cls: + return cls + return None + return None + + def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None: + FullMethodName: str = f'{ClassName}.{op_name}' + if not Gen._has_function(FullMethodName): + FullMethodName = f'{ClassName}.{op_name}__' + if not Gen._has_function(FullMethodName): + # 多继承:沿 MRO 祖先链查找 dunder 方法(先声明父类优先,与 TPV 一致) + for anc in Gen._get_mro_chain(ClassName)[1:]: + anc_method: str = f'{anc}.{op_name}' + if Gen._has_function(anc_method): + FullMethodName = anc_method + break + anc_method_ss = f'{anc}.{op_name}__' + if Gen._has_function(anc_method_ss): + FullMethodName = anc_method_ss + break + if not Gen._has_function(FullMethodName): + # 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray')且 + # 无直接匹配方法时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本 + # (如 'ndarray[double]')。注解 'numpy.ndarray | t.CPtr' 未指定类型参数时, + # var_struct_class 仅记录裸模板名,但方法只在特化版本中定义。 + # 选择策略:优先选 obj_val.type.pointee 实际匹配的特化;否则选第一个有方法的特化。 + if '[' not in ClassName: + SpecClass: str | None = None + for CN in Gen.structs.keys(): + if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}'): + SpecClass = CN + break + if CN.startswith(f'{ClassName}[') and Gen._has_function(f'{CN}.{op_name}__'): + SpecClass = CN + break + if SpecClass: + FullMethodName = f'{SpecClass}.{op_name}' + if not Gen._has_function(FullMethodName): + FullMethodName = f'{SpecClass}.{op_name}__' + if Gen._has_function(FullMethodName): + func: Any = Gen._get_function(FullMethodName) + # 多继承 this 调整:运算符重载方法定义在"无 vtable 父类"且字段区偏移 > 0 时, + # 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。 + method_anc: str | None = None + _fm_short: str = FullMethodName.split('.')[-1] if '.' in FullMethodName else FullMethodName + if '.' in FullMethodName: + _fm_cls: str = FullMethodName.split('.')[0] + if _fm_cls != ClassName: + method_anc = _fm_cls + _call_self: Any = self.Trans.ExprCallHandle._adjust_this_for_inherited_method(Gen, obj_val, ClassName, method_anc) + call_args: list[Any] = [_call_self] + if other_val is not None: + call_args.append(other_val) + if len(func.ftype.args) == len(call_args): + for i, (expected_type, actual_val) in enumerate(zip(func.ftype.args, call_args)): + if isinstance(expected_type, ir.PointerType) and isinstance(actual_val.type, ir.PointerType): + if expected_type != actual_val.type: + if isinstance(expected_type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + call_args[i] = Gen.builder.bitcast(actual_val, expected_type, name=f"bitcast_arg_{i}") + result: Any = Gen.builder.call(func, call_args, name=f"call_{FullMethodName}") + return result + return None + + def _llvm_type_to_detailed_string(self, llvm_type: ir.Type, var_name: str = "") -> dict[str, Any]: + info: dict[str, Any] = { + 'name': "unknown", + 'size': 0, + 'signed': False, + 'ptr': False + } + if isinstance(llvm_type, ir.IntType): + info['size'] = llvm_type.width // 8 + info['signed'] = True + if llvm_type.width == 8: + info['name'] = "char" + elif llvm_type.width == 16: + info['name'] = "short" + elif llvm_type.width == 32: + info['name'] = "int" + elif llvm_type.width == 64: + info['name'] = "long long" + else: + info['name'] = f"int{llvm_type.width}" + elif isinstance(llvm_type, ir.DoubleType): + info['size'] = 8 + info['signed'] = True + info['name'] = "double" + elif isinstance(llvm_type, ir.FloatType): + info['size'] = 4 + info['signed'] = True + info['name'] = "float" + elif isinstance(llvm_type, ir.PointerType): + info['size'] = 8 + info['signed'] = False + info['ptr'] = True + pointee_info: dict[str, Any] = self._llvm_type_to_detailed_string(llvm_type.pointee) + info['name'] = f"{pointee_info['name']}*" + elif isinstance(llvm_type, (ir.LiteralStructType, ir.IdentifiedStructType)): + size: int = 0 + for elem in llvm_type.elements: + elem_info: dict[str, Any] = self._llvm_type_to_detailed_string(elem) + size += elem_info['size'] + info['size'] = size + info['signed'] = False + if isinstance(llvm_type, ir.IdentifiedStructType): + info['name'] = llvm_type.name + else: + info['name'] = "struct" + elif isinstance(llvm_type, ir.ArrayType): + elem_info = self._llvm_type_to_detailed_string(llvm_type.element) + info['size'] = elem_info['size'] * llvm_type.count + info['signed'] = elem_info['signed'] + info['name'] = f"{elem_info['name']}[]" + elif isinstance(llvm_type, ir.VoidType): + info['size'] = 0 + info['signed'] = False + info['name'] = "void" + else: + info['size'] = 0 + info['signed'] = False + info['name'] = str(llvm_type) + return info + + def _infer_expr_llvm_type_full(self, node: ast.AST) -> ir.Type: + Gen: LlvmCodeGenerator = self.Trans.LlvmGen + if isinstance(node, ast.Constant): + if isinstance(node.value, bool): + return ir.IntType(32) + elif isinstance(node.value, int): + return ir.IntType(32) + elif isinstance(node.value, float): + return ir.DoubleType() + elif isinstance(node.value, str): + if getattr(node, 'kind', None) == 'u': + return ir.PointerType(ir.IntType(16)) + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + elif isinstance(node, ast.Name): + if node.id in Gen.variables: + var_ptr: Any = Gen.variables[node.id] + if isinstance(var_ptr.type, ir.PointerType): + return var_ptr.type.pointee + return var_ptr.type + if node.id in Gen._reg_values: + return Gen._reg_values[node.id].type + return ir.IntType(32) + elif isinstance(node, ast.Attribute): + attr_name: str = node.attr + AttrInfo: Any = self.Trans.SymbolTable.lookup(attr_name) + if AttrInfo and getattr(AttrInfo, 'IsEnumMember', None): + return ir.IntType(32) + return ir.IntType(32) + elif isinstance(node, ast.BinOp): + left_type: ir.Type = self._infer_expr_llvm_type_full(node.left) + right_type: ir.Type = self._infer_expr_llvm_type_full(node.right) + if isinstance(left_type, (ir.FloatType, ir.DoubleType)) or isinstance(right_type, (ir.FloatType, ir.DoubleType)): + return ir.DoubleType() + if isinstance(left_type, ir.PointerType) or isinstance(right_type, ir.PointerType): + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + elif isinstance(node, ast.UnaryOp): + return self._infer_expr_llvm_type_full(node.operand) + elif isinstance(node, ast.Subscript): + val_type: ir.Type = self._infer_expr_llvm_type_full(node.value) + if isinstance(val_type, ir.PointerType): + if isinstance(val_type.pointee, ir.IntType) and val_type.pointee.width == 8: + return ir.IntType(8) + if isinstance(val_type.pointee, ir.ArrayType): + return ir.PointerType(val_type.pointee.element) + return val_type.pointee + if isinstance(val_type, ir.ArrayType): + return val_type.element + if isinstance(val_type, ir.IntType): + return ir.IntType(8) + return ir.IntType(32) + elif isinstance(node, ast.Call): + if isinstance(node.func, ast.Name): + func_name: str = node.func.id + if Gen._has_function(func_name): + fn: Any = Gen._get_function(func_name) + return fn.function_type.return_type + if func_name == 'len': + return ir.IntType(32) + if func_name == 'sizeof': + return ir.IntType(32) + if func_name == 'ord': + return ir.IntType(32) + if func_name == 'chr': + return ir.IntType(8) + if func_name == 'int': + return ir.IntType(32) + if func_name == 'float' or func_name == 'double': + return ir.DoubleType() + elif isinstance(node.func, ast.Attribute): + if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': + if node.func.attr == 'Deref': + return ir.IntType(64) + if isinstance(node.func.value, ast.Name) and IsTModule(node.func.value.id, self.Trans.SymbolTable): + if node.func.attr == 'CChar': + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + elif isinstance(node, ast.Compare): + return ir.IntType(1) + elif isinstance(node, ast.BoolOp): + return ir.IntType(1) + elif isinstance(node, ast.IfExp): + return self._infer_expr_llvm_type_full(node.body) + elif isinstance(node, ast.Attribute): + return ir.PointerType(ir.IntType(8)) + return ir.IntType(32) + + def _collect_names(self, node: ast.AST, bound: set[str], free: set[str] | None = None) -> None: + """收集 AST 节点中的绑定变量和自由变量 + + Args: + node: AST 节点 + bound: 集合,收集绑定变量(ast.Store 上下文) + free: 集合,收集自由变量(ast.Load 上下文),可为 None + """ + if free is None: + free = set() + if isinstance(node, ast.Name): + if isinstance(node.ctx, ast.Store): + bound.add(node.id) + elif isinstance(node.ctx, ast.Load): + free.add(node.id) + elif isinstance(node, (ast.Lambda, ast.FunctionDef, ast.AsyncFunctionDef)): + # 这些节点有自己的作用域,不递归进入 + # 但需要收集参数名作为 bound + if hasattr(node, 'args') and node.args: + for arg in node.args.args: + bound.add(arg.arg) + elif getattr(node, '_fields', None): + for field in node._fields: + value: Any = getattr(node, field, None) + if isinstance(value, list): + for item in value: + if isinstance(item, (ast.stmt, ast.expr)): + self._collect_names(item, bound, free) + elif isinstance(value, (ast.stmt, ast.expr)): self._collect_names(value, bound, free) \ No newline at end of file diff --git a/lib/core/Handles/HandlesFor.py b/lib/core/Handles/HandlesFor.py index 1b9aae4..cf2c7ec 100644 --- a/lib/core/Handles/HandlesFor.py +++ b/lib/core/Handles/HandlesFor.py @@ -1,1094 +1,1094 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -def _safe_ptr_type(ty: ir.Type) -> ir.Type: - """LLVM IR 中不允许 void* 指针,统一替换为 i8*(对应 C 的 void* 语义) - - 当 ty 是 Ptr(VoidType) / Ptr(Ptr(VoidType)) / 任何包含 VoidType 作为 pointee 的指针链, - 替换为 Ptr(i8)。非指针类型原样返回。 - """ - if isinstance(ty, ir.PointerType): - # 单级 / 多级 void 指针全部降级为 i8* - cur: ir.Type = ty - while isinstance(cur, ir.PointerType): - if isinstance(cur.pointee, ir.VoidType): - return ir.IntType(8).as_pointer() - cur = cur.pointee - return ty - - -class ForHandle(BaseHandle): - def _HandleForLlvm(self, Node: ast.For) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - Gen._set_node_info(Node, "For") - # zip() 内置:for a, b in zip(iter1, iter2): - if (isinstance(Node.iter, ast.Call) - and isinstance(Node.iter.func, ast.Name) - and Node.iter.func.id == 'zip' - and isinstance(Node.target, ast.Tuple)): - self._HandleForZipLlvm(Node) - return - # enumerate() 内置:for idx, val in enumerate(iterable): - if (isinstance(Node.iter, ast.Call) - and isinstance(Node.iter.func, ast.Name) - and Node.iter.func.id == 'enumerate' - and isinstance(Node.target, ast.Tuple) - and Node.iter.args): - self._HandleForEnumerateLlvm(Node) - return - if not isinstance(Node.target, ast.Name): - return - TargetName: str = Node.target.id - StartVal: ir.Value | None = None - EndVal: ir.Value | None = None - StepVal: ir.Value | None = None - IsRange: bool = False - CondOp: str = '<' - if isinstance(Node.iter, ast.Call): - CallFunc: ast.expr = Node.iter.func - if isinstance(CallFunc, ast.Name) and CallFunc.id == 'range': - IsRange = True - RangeArgs: list[ast.expr] = Node.iter.args - RangeEndArg: ast.expr | None = RangeArgs[1] if len(RangeArgs) >= 2 else RangeArgs[0] if len(RangeArgs) >= 1 else None - OptimizedEnd: bool = False - if len(RangeArgs) >= 2 and isinstance(RangeEndArg, ast.BinOp): - if isinstance(RangeEndArg.op, ast.Add): - if (isinstance(RangeEndArg.right, ast.Constant) and RangeEndArg.right.value == 1): - EndVal = self.HandleExprLlvm(RangeEndArg.left) - CondOp = '<=' - OptimizedEnd = True - elif (isinstance(RangeEndArg.left, ast.Constant) and RangeEndArg.left.value == 1): - EndVal = self.HandleExprLlvm(RangeEndArg.right) - CondOp = '<=' - OptimizedEnd = True - elif isinstance(RangeEndArg.op, ast.Sub): - if isinstance(RangeEndArg.right, ast.Constant) and RangeEndArg.right.value == 1: - EndVal = self.HandleExprLlvm(RangeEndArg.left) - CondOp = '<' - OptimizedEnd = True - if not OptimizedEnd: - if len(RangeArgs) == 1: - EndVal = self.HandleExprLlvm(RangeArgs[0]) - else: - EndVal = self.HandleExprLlvm(RangeEndArg) - if len(RangeArgs) == 1: - StartVal = ir.Constant(ir.IntType(32), 0) - elif len(RangeArgs) >= 2: - StartVal = self.HandleExprLlvm(RangeArgs[0]) - if len(RangeArgs) >= 3: - StepVal = self.HandleExprLlvm(RangeArgs[2]) - # Check if step is a negative constant — need to flip condition - step_arg: ast.expr = RangeArgs[2] - if isinstance(step_arg, ast.UnaryOp) and isinstance(step_arg.op, ast.USub): - if isinstance(step_arg.operand, ast.Constant) and isinstance(step_arg.operand.value, (int, float)): - if step_arg.operand.value > 0: - CondOp = '>' - elif isinstance(step_arg, ast.Constant) and isinstance(step_arg.value, (int, float)): - if step_arg.value < 0: - CondOp = '>' - if not EndVal: - return - if not isinstance(EndVal.type, ir.IntType): - if isinstance(EndVal.type, ir.PointerType) and isinstance(EndVal.type.pointee, ir.IntType): - EndVal = Gen._load(EndVal, name="Load_end") - else: - EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="end") - if StartVal and not isinstance(StartVal.type, ir.IntType): - if isinstance(StartVal.type, ir.PointerType) and isinstance(StartVal.type.pointee, ir.IntType): - StartVal = Gen._load(StartVal, name="Load_start") - else: - StartVal = Gen.builder.ptrtoint(StartVal, ir.IntType(64), name="start") - else: - StartVal = ir.Constant(ir.IntType(64), 0) - if not StartVal: - StartVal = ir.Constant(EndVal.type, 0) - if StepVal is None: - StepVal = ir.Constant(EndVal.type, 1) - if not IsRange: - # 检测 c.Addr(x) 模式:按原始变量类型迭代(for i64 in i64* 语义) - if (isinstance(Node.iter, ast.Call) - and isinstance(Node.iter.func, ast.Attribute) - and isinstance(Node.iter.func.value, ast.Name) - and Node.iter.func.value.id == 'c' - and Node.iter.func.attr == 'Addr' - and Node.iter.args): - AddrArg: ast.expr = Node.iter.args[0] - if isinstance(AddrArg, ast.Name) and AddrArg.id in Gen.variables: - _var_ptr: ir.Value | None = Gen.variables[AddrArg.id] - if _var_ptr is not None and isinstance(_var_ptr.type, ir.PointerType): - _pointee: ir.Type = _var_ptr.type.pointee - # 标量整数变量 - if isinstance(_pointee, ir.IntType): - if _pointee.width == 8: - self._HandleForStrLlvm(Node, _var_ptr) - return - self._HandleForPtrLlvm(Node, _var_ptr, _pointee) - return - # 数组变量:取元素类型 - if isinstance(_pointee, ir.ArrayType) and isinstance(_pointee.element, ir.IntType): - _elem_type: ir.IntType = _pointee.element - if _elem_type.width == 8: - self._HandleForStrLlvm(Node, _var_ptr) - return - _typed_ptr: ir.Value = Gen.builder.bitcast(_var_ptr, ir.PointerType(_elem_type), name="addr_arr_elem_cast") - self._HandleForPtrLlvm(Node, _typed_ptr, _elem_type) - return - IterClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.iter, Gen) - if not IterClassName and isinstance(Node.iter, ast.Call) and isinstance(Node.iter.func, ast.Name): - IterClassName = Node.iter.func.id - if IterClassName not in Gen.structs: - IterClassName = None - if IterClassName and Gen._has_function(f'{IterClassName}.__iter__') and Gen._has_function(f'{IterClassName}.__next__'): - self._HandleForIterLlvm(Node, IterClassName) - return - IterVal: ir.Value | None = self.HandleExprLlvm(Node.iter) - if not IterVal: - return - # 回退:通过 LLVM 类型查找结构体类名,检测 __iter__/__next__ - if not IterClassName and isinstance(IterVal.type, ir.PointerType): - _pointee: ir.Type = IterVal.type.pointee - if isinstance(_pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - _found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(_pointee) - if _found: - _cn: str = _found[0] - if not (Gen._has_function(f'{_cn}.__iter__') and Gen._has_function(f'{_cn}.__next__')): - # temp stub 可能不包含泛型特化方法,尝试从 output stub 按需加载 - self.Trans.ImportHandler._TryLoadFuncDeclsFromOutputStub(_cn, Gen) - if Gen._has_function(f'{_cn}.__iter__') and Gen._has_function(f'{_cn}.__next__'): - Gen._UnregisterTempPtr(IterVal) - self._HandleForIterLlvm(Node, _cn) - return - if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8: - self._HandleForStrLlvm(Node, IterVal) - return - if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.ArrayType): - self._HandleForListLlvm(Node, IterVal) - return - StartVal = ir.Constant(ir.IntType(32), 0) - EndVal = IterVal - if not isinstance(EndVal.type, ir.IntType): - EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="end") - StartVal = ir.Constant(ir.IntType(64), 0) - StepVal = ir.Constant(EndVal.type, 1) - CondOp = '<' - if TargetName in Gen._reg_values: - del Gen._reg_values[TargetName] - LoopVar: ir.AllocaInstr - if TargetName in Gen.variables and Gen.variables[TargetName] is not None: - LoopVar = Gen.variables[TargetName] - if isinstance(LoopVar.type, ir.PointerType) and isinstance(LoopVar.type.pointee, ir.IntType) and LoopVar.type.pointee == EndVal.type and isinstance(EndVal.type, ir.IntType) and StartVal.type == LoopVar.type.pointee and EndVal.type == StartVal.type: - Gen._store(StartVal, LoopVar) - else: - NewVar: ir.AllocaInstr = Gen._allocaEntry(EndVal.type, name=TargetName) - if StartVal.type != EndVal.type: - if isinstance(EndVal.type, ir.IntType) and isinstance(StartVal.type, ir.IntType): - if StartVal.type.width < EndVal.type.width: - StartVal = Gen.builder.zext(StartVal, EndVal.type, name="zext_loop_start") - elif StartVal.type.width > EndVal.type.width: - StartVal = Gen.builder.trunc(StartVal, EndVal.type, name="trunc_loop_start") - Gen._store(StartVal, NewVar) - Gen.variables[TargetName] = NewVar - LoopVar = NewVar - else: - LoopVar = Gen._allocaEntry(EndVal.type, name=TargetName) - Gen.variables[TargetName] = LoopVar - Gen._store(StartVal, LoopVar) - if StepVal and isinstance(StepVal.type, ir.IntType) and isinstance(EndVal.type, ir.IntType): - if StepVal.type.width < EndVal.type.width: - StepVal = Gen.builder.zext(StepVal, EndVal.type, name="zext_loop_step") - elif StepVal.type.width > EndVal.type.width: - StepVal = Gen.builder.trunc(StepVal, EndVal.type, name="trunc_loop_step") - Gen._record_var_signedness(TargetName, 'int') - CondBB: ir.Block = Gen.func.append_basic_block(name="for.cond") - BodyBB: ir.Block = Gen.func.append_basic_block(name="for.body") - StepBB: ir.Block = Gen.func.append_basic_block(name="for.step") - ElseBB: ir.Block | None = Gen.func.append_basic_block(name="for.else") if Node.orelse else None - AfterBB: ir.Block = Gen.func.append_basic_block(name="for.end") - Gen.loop_break_targets.append(AfterBB) - Gen.loop_continue_targets.append(StepBB) - Gen.builder.branch(CondBB) - Gen.builder.position_at_start(CondBB) - LoopVal: ir.Value = Gen._load(LoopVar, name=TargetName) - is_unsigned: bool = Gen._is_var_unsigned(TargetName) - Cond: ir.Value - if is_unsigned: - Cond = Gen.builder.icmp_unsigned(CondOp, LoopVal, EndVal, name="forcond") - else: - Cond = Gen.builder.icmp_signed(CondOp, LoopVal, EndVal, name="forcond") - Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB) - Gen.builder.position_at_start(BodyBB) - CachedLoopVal: ir.Value = Gen._load(LoopVar, name=TargetName) - Gen._reg_values[TargetName] = CachedLoopVal - self.HandleBodyLlvm(Node.body) - StepLoopVal: ir.Value = CachedLoopVal - if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is CachedLoopVal: - del Gen._reg_values[TargetName] - elif not Gen.builder.block.is_terminated: - # 死代码防御(2026-08-15):body 修改过循环变量时此处重新 load, - # 但该值实际未被使用(step 块 L237 会重新 load)。 - # 若 body 以 break/continue/return 终结,当前块已带 terminator, - # 再发射 load 会落在 terminator 之后 → opt 报 - # "expected instruction opcode" 非法 IR。 - StepLoopVal = Gen._load(LoopVar, name=TargetName) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(StepBB) - Gen.builder.position_at_start(StepBB) - StepLoopVal2: ir.Value = Gen._load(LoopVar, name=TargetName) - NextVal: ir.Value = Gen.builder.add(StepLoopVal2, StepVal, name="next") - Gen._store(NextVal, LoopVar) - Gen.builder.branch(CondBB) - Gen.loop_break_targets.pop() - Gen.loop_continue_targets.pop() - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - - def _HandleGlobalLlvm(self, Node: ast.Global) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - self._RegisterGlobalNames(Node.names, Gen, clear_reg_values=True) - - def _RegisterGlobalNames(self, names: list[str], Gen: "Translator.LlvmGen", clear_reg_values: bool = False) -> None: - for name in names: - Gen.global_vars.add(name) - if name in Gen.module.globals: - Gen.variables[name] = Gen.module.globals[name] - if clear_reg_values and name in Gen._reg_values: - del Gen._reg_values[name] - - def _HandleNonlocalLlvm(self, Node: ast.Nonlocal) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - for name in Node.names: - if name in Gen._reg_values and name not in Gen.variables: - OldVal: ir.Value = Gen._reg_values[name] - var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=name) - Gen._store(OldVal, var) - Gen.variables[name] = var - del Gen._reg_values[name] - - def _collect_implicit_nonlocal(self, Node: ast.FunctionDef, Gen: "Translator.LlvmGen") -> list[str]: - param_names: set[str] = set() - for arg in Node.args.args: - param_names.add(arg.arg) - local_names: set[str] = set() - for child in ast.walk(Node): - if isinstance(child, ast.Assign): - for target in child.targets: - if isinstance(target, ast.Name): - local_names.add(target.id) - elif isinstance(target, ast.Tuple): - for elt in target.elts: - if isinstance(elt, ast.Name): - local_names.add(elt.id) - elif isinstance(child, ast.AugAssign): - if isinstance(child.target, ast.Name): - local_names.add(child.target.id) - elif isinstance(child, ast.AnnAssign): - if isinstance(child.target, ast.Name): - local_names.add(child.target.id) - elif isinstance(child, ast.For): - if isinstance(child.target, ast.Name): - local_names.add(child.target.id) - read_names: set[str] = set() - for child in ast.walk(Node): - if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Load): - name: str = child.id - if name not in param_names and name not in local_names: - read_names.add(name) - implicit: list[str] = [] - for name in read_names: - if name in Gen.variables and Gen.variables[name] is not None: - implicit.append(name) - elif name in Gen._reg_values: - implicit.append(name) - for called_name in read_names: - if called_name in Gen.nonlocal_params: - for nv, _ in Gen.nonlocal_params[called_name]: - if nv not in param_names and nv not in local_names: - if nv not in read_names: - if nv in Gen.variables and Gen.variables[nv] is not None: - implicit.append(nv) - elif nv in Gen._reg_values: - implicit.append(nv) - return implicit - - def _collect_all_nonlocal_names(self, Node: ast.FunctionDef) -> set[str]: - """Recursively collect all nonlocal variable names from a function and its nested functions.""" - names: set[str] = set() - for stmt in Node.body: - if isinstance(stmt, ast.Nonlocal): - for name in stmt.names: - names.add(name) - elif isinstance(stmt, ast.FunctionDef): - # Recursively collect from nested functions - sub_names: set[str] = self._collect_all_nonlocal_names(stmt) - names.update(sub_names) - return names - - def _HandleNestedFunctionLlvm(self, Node: ast.FunctionDef) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - nonlocal_var_names: list[str] = [] - for stmt in Node.body: - if isinstance(stmt, ast.Nonlocal): - for name in stmt.names: - nonlocal_var_names.append(name) - # Pre-scan ALL nested functions recursively for their nonlocal needs (passthrough) - for stmt in Node.body: - if isinstance(stmt, ast.FunctionDef): - sub_nonlocal_names: set[str] = self._collect_all_nonlocal_names(stmt) - for name in sub_nonlocal_names: - if name not in nonlocal_var_names: - nonlocal_var_names.append(name) - implicit_names: list[str] = self._collect_implicit_nonlocal(Node, Gen) - for name in implicit_names: - if name not in nonlocal_var_names: - nonlocal_var_names.append(name) - # 堆分配 nonlocal 变量:避免外层函数返回后栈帧释放导致悬垂指针 - # 闭包返回模式(return nested_fn)要求捕获变量在堆上存活 - malloc_fn_type: ir.FunctionType = ir.FunctionType(ir.IntType(8).as_pointer(), [ir.IntType(64)]) - malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_fn_type) - for var_name in nonlocal_var_names: - if var_name in Gen.variables and Gen.variables[var_name] is not None: - old_var: ir.Value = Gen.variables[var_name] - if isinstance(old_var.type, ir.PointerType): - elem_type: ir.Type = old_var.type.pointee - # 计算元素大小(字节) - elem_size: int = 8 # 默认指针大小 - if isinstance(elem_type, ir.IntType): - elem_size = max(1, elem_type.width // 8) - elif isinstance(elem_type, ir.FloatType): - elem_size = 4 - elif isinstance(elem_type, ir.DoubleType): - elem_size = 8 - elif isinstance(elem_type, ir.PointerType): - elem_size = 8 - # malloc 堆存储 - heap_raw: ir.Value = Gen.builder.call(malloc_func, [ir.Constant(ir.IntType(64), elem_size)], name=f"heap_{var_name}") - heap_ptr: ir.Value = Gen.builder.bitcast(heap_raw, ir.PointerType(elem_type), name=f"heap_{var_name}_ptr") - # 复制栈值到堆 - old_val: ir.Value = Gen._load(old_var, name=f"load_old_{var_name}") - Gen._store(old_val, heap_ptr) - # 更新 Gen.variables 使外层和嵌套函数都使用堆指针 - Gen.variables[var_name] = heap_ptr - extra_params: list[tuple[str, ir.Type]] = [] - for var_name in nonlocal_var_names: - if var_name in Gen.variables and Gen.variables[var_name] is not None: - var: ir.Value = Gen.variables[var_name] - extra_params.append((var_name, _safe_ptr_type(var.type))) - elif var_name in Gen._reg_values: - OldVal: ir.Value = Gen._reg_values[var_name] - var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=var_name) - Gen._store(OldVal, var) - Gen.variables[var_name] = var - del Gen._reg_values[var_name] - extra_params.append((var_name, _safe_ptr_type(var.type))) - else: - # Search outer scope stack for the variable - found_var: ir.Value | None = None - for scope in reversed(Gen._variable_scope_stack): - if var_name in scope and scope[var_name] is not None: - found_var = scope[var_name] - break - if found_var is not None: - # Add to current scope so it can be passed to nested functions - Gen.variables[var_name] = found_var - extra_params.append((var_name, _safe_ptr_type(found_var.type))) - else: - var = Gen._allocaEntry(ir.IntType(32), name=var_name) - Gen.variables[var_name] = var - extra_params.append((var_name, _safe_ptr_type(var.type))) - if extra_params: - Gen.nonlocal_params[Node.name] = [(name, _safe_ptr_type(ptr_type)) for name, ptr_type in extra_params] - # Push current variables to scope stack before compiling nested function - Gen._variable_scope_stack.append(Gen.variables.copy()) - saved_builder: ir.IRBuilder = Gen.builder - saved_func: ir.Function = Gen.func - saved_variables: dict[str, ir.Value] = Gen.variables.copy() - saved_reg_values: dict[str, ir.Value] = Gen._reg_values.copy() - saved_global_vars: set[str] = Gen.global_vars.copy() - saved_var_signedness: dict[str, str] = Gen.var_signedness.copy() - saved_var_type_info: dict[str, dict[str, str]] = Gen.var_type_info.copy() - saved_var_type_assignments: dict[str, list[dict[str, str]]] = Gen.var_type_assignments.copy() - saved_CurrentCReturnTypes: object | None = getattr(self.Trans, 'CurrentCReturnTypes', None) - saved_CurrentCpythonObjectClass: str | None = getattr(self.Trans, '_CurrentCpythonObjectClass', None) - saved_VarScopes: int = len(self.Trans.VarScopes) - self.Trans.FunctionHandler._EmitFunctionLlvm(Node, Gen, extra_params=extra_params if extra_params else None) - Gen.builder = saved_builder - Gen.func = saved_func - Gen.variables = saved_variables - Gen._reg_values = saved_reg_values - Gen.global_vars = saved_global_vars - Gen.var_signedness = saved_var_signedness - Gen.var_type_info = saved_var_type_info - Gen.var_type_assignments = saved_var_type_assignments - self.Trans.CurrentCReturnTypes = saved_CurrentCReturnTypes - self.Trans._CurrentCpythonObjectClass = saved_CurrentCpythonObjectClass - while len(self.Trans.VarScopes) > saved_VarScopes: - self.Trans.VarScopes.pop() - # Pop scope stack - if Gen._variable_scope_stack: - Gen._variable_scope_stack.pop() - - def _HandleForListLlvm(self, Node: ast.For, ArrPtr: ir.Value) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if not isinstance(Node.target, ast.Name): - return - TargetName: str = Node.target.id - ElemType: ir.Type = ArrPtr.type.pointee.element - ArrayCount: int = ArrPtr.type.pointee.count - IdxVal: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=f"arr_idx") - Gen.builder.store(ir.Constant(ir.IntType(32), 0), IdxVal) - if TargetName in Gen._reg_values: - del Gen._reg_values[TargetName] - LoopVar: ir.AllocaInstr = Gen._allocaEntry(ElemType, name=TargetName) - Gen.variables[TargetName] = LoopVar - Gen._store(ir.Constant(ElemType, None), LoopVar) - CondBB: ir.Block = Gen.func.append_basic_block(name="arrfor.cond") - BodyBB: ir.Block = Gen.func.append_basic_block(name="arrfor.body") - StepBB: ir.Block = Gen.func.append_basic_block(name="arrfor.step") - ElseBB: ir.Block | None = Gen.func.append_basic_block(name="arrfor.else") if Node.orelse else None - AfterBB: ir.Block = Gen.func.append_basic_block(name="arrfor.end") - Gen.loop_break_targets.append(AfterBB) - Gen.loop_continue_targets.append(StepBB) - Gen.builder.branch(CondBB) - Gen.builder.position_at_start(CondBB) - CurIdx: ir.Value = Gen._load(IdxVal, name="cur_idx") - IsDone: ir.Value = Gen.builder.icmp_signed('<', CurIdx, ir.Constant(ir.IntType(32), ArrayCount), name="arr_in_bounds") - Gen.builder.cbranch(IsDone, BodyBB, ElseBB if ElseBB else AfterBB) - Gen.builder.position_at_start(BodyBB) - ElemPtr: ir.Value = Gen.builder.gep(ArrPtr, [ir.Constant(ir.IntType(32), 0), CurIdx], name="arr_elem_ptr") - ElemVal: ir.Value = Gen._load(ElemPtr, name="arr_elem_val") - Gen._store(ElemVal, LoopVar) - Gen._record_var_signedness(TargetName, 'ptr') - Gen._reg_values[TargetName] = ElemVal - self.HandleBodyLlvm(Node.body) - if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is ElemVal: - del Gen._reg_values[TargetName] - if not Gen.builder.block.is_terminated: - Gen.builder.branch(StepBB) - Gen.builder.position_at_start(StepBB) - CurIdx2: ir.Value = Gen._load(IdxVal, name="cur_idx2") - NextIdx: ir.Value = Gen.builder.add(CurIdx2, ir.Constant(ir.IntType(32), 1), name="next_idx") - Gen._store(NextIdx, IdxVal) - Gen.builder.branch(CondBB) - Gen.loop_break_targets.pop() - Gen.loop_continue_targets.pop() - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - - def _HandleForStrLlvm(self, Node: ast.For, StrVal: ir.Value) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if not isinstance(Node.target, ast.Name): - return - TargetName: str = Node.target.id - Gen._UnregisterTempPtr(StrVal) - PtrVal: ir.AllocaInstr = Gen.builder.alloca(ir.IntType(8).as_pointer(), name=f"str_ptr_copy") - Gen.builder.store(StrVal, PtrVal) - CharType: ir.IntType = ir.IntType(8) - if TargetName in Gen._reg_values: - del Gen._reg_values[TargetName] - LoopVar: ir.AllocaInstr = Gen._allocaEntry(CharType, name=TargetName) - Gen.variables[TargetName] = LoopVar - Gen._store(ir.Constant(CharType, 0), LoopVar) - CondBB: ir.Block = Gen.func.append_basic_block(name="strfor.cond") - BodyBB: ir.Block = Gen.func.append_basic_block(name="strfor.body") - StepBB: ir.Block = Gen.func.append_basic_block(name="strfor.step") - ElseBB: ir.Block | None = Gen.func.append_basic_block(name="strfor.else") if Node.orelse else None - AfterBB: ir.Block = Gen.func.append_basic_block(name="strfor.end") - Gen.loop_break_targets.append(AfterBB) - Gen.loop_continue_targets.append(StepBB) - Gen.builder.branch(CondBB) - Gen.builder.position_at_start(CondBB) - CurrentPtr: ir.Value = Gen._load(PtrVal, name="current_ptr") - RawChar: ir.Value = Gen._load(CurrentPtr, name="raw_char") - NullCond: ir.Value = Gen.builder.icmp_signed('==', RawChar, ir.Constant(CharType, 0), name="is_null") - Gen.builder.cbranch(NullCond, ElseBB if ElseBB else AfterBB, BodyBB) - Gen.builder.position_at_start(BodyBB) - Gen._store(RawChar, LoopVar) - Gen._record_var_signedness(TargetName, 'char') - Gen._reg_values[TargetName] = RawChar - self.HandleBodyLlvm(Node.body) - if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is RawChar: - del Gen._reg_values[TargetName] - if not Gen.builder.block.is_terminated: - Gen.builder.branch(StepBB) - Gen.builder.position_at_start(StepBB) - CurrentPtr2: ir.Value = Gen._load(PtrVal, name="current_ptr2") - NextPtr: ir.Value = Gen.builder.gep(CurrentPtr2, [ir.Constant(ir.IntType(32), 1)], name="next_ptr") - Gen._store(NextPtr, PtrVal) - Gen.builder.branch(CondBB) - Gen.loop_break_targets.pop() - Gen.loop_continue_targets.pop() - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - - def _HandleForPtrLlvm(self, Node: ast.For, PtrVal: ir.Value, ElemType: ir.IntType) -> None: - """通用指针迭代:按 ElemType 大小逐元素迭代,终止条件为元素值 == 0 - - 适用于 for i in c.Addr(u) where u: i32/i64 等非 i8 整数类型。 - """ - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if not isinstance(Node.target, ast.Name): - return - TargetName: str = Node.target.id - # 确保 PtrVal 是 ElemType* - TypedPtr: ir.Value = PtrVal - if isinstance(PtrVal.type, ir.PointerType) and PtrVal.type.pointee is not ElemType: - TypedPtr = Gen.builder.bitcast(PtrVal, ir.PointerType(ElemType), name="ptr_elem_cast") - Gen._UnregisterTempPtr(TypedPtr) - # 分配指针副本 - PtrCopy: ir.AllocaInstr = Gen.builder.alloca(ir.PointerType(ElemType), name="ptr_copy") - Gen.builder.store(TypedPtr, PtrCopy) - if TargetName in Gen._reg_values: - del Gen._reg_values[TargetName] - LoopVar: ir.AllocaInstr = Gen._allocaEntry(ElemType, name=TargetName) - Gen.variables[TargetName] = LoopVar - Gen._store(ir.Constant(ElemType, 0), LoopVar) - CondBB: ir.Block = Gen.func.append_basic_block(name="ptrfor.cond") - BodyBB: ir.Block = Gen.func.append_basic_block(name="ptrfor.body") - StepBB: ir.Block = Gen.func.append_basic_block(name="ptrfor.step") - ElseBB: ir.Block | None = Gen.func.append_basic_block(name="ptrfor.else") if Node.orelse else None - AfterBB: ir.Block = Gen.func.append_basic_block(name="ptrfor.end") - Gen.loop_break_targets.append(AfterBB) - Gen.loop_continue_targets.append(StepBB) - Gen.builder.branch(CondBB) - Gen.builder.position_at_start(CondBB) - CurrentPtr: ir.Value = Gen._load(PtrCopy, name="current_ptr") - RawElem: ir.Value = Gen._load(CurrentPtr, name="raw_elem") - NullCond: ir.Value = Gen.builder.icmp_signed('==', RawElem, ir.Constant(ElemType, 0), name="is_null") - Gen.builder.cbranch(NullCond, ElseBB if ElseBB else AfterBB, BodyBB) - Gen.builder.position_at_start(BodyBB) - Gen._store(RawElem, LoopVar) - Gen._record_var_signedness(TargetName, 'int') - Gen._reg_values[TargetName] = RawElem - self.HandleBodyLlvm(Node.body) - if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is RawElem: - del Gen._reg_values[TargetName] - if not Gen.builder.block.is_terminated: - Gen.builder.branch(StepBB) - Gen.builder.position_at_start(StepBB) - CurrentPtr2: ir.Value = Gen._load(PtrCopy, name="current_ptr2") - NextPtr: ir.Value = Gen.builder.gep(CurrentPtr2, [ir.Constant(ir.IntType(32), 1)], name="next_ptr") - Gen._store(NextPtr, PtrCopy) - Gen.builder.branch(CondBB) - Gen.loop_break_targets.pop() - Gen.loop_continue_targets.pop() - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - - def _HandleForIterLlvm(self, Node: ast.For, ClassName: str) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if not isinstance(Node.target, ast.Name): - return - TargetName: str = Node.target.id - IterVal: ir.Value | None = self.HandleExprLlvm(Node.iter) - if not IterVal: - return - Gen._UnregisterTempPtr(IterVal) - if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8: - IterVal = Gen.builder.bitcast(IterVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - IterCall: ir.Function = Gen._get_function(f'{ClassName}.__iter__') - IterResult: ir.Value = Gen.builder.call(IterCall, [IterVal], name=f"call_{ClassName}.__iter__") - Gen._UnregisterTempPtr(IterResult) - if isinstance(IterResult.type, ir.PointerType) and isinstance(IterResult.type.pointee, ir.IntType) and IterResult.type.pointee.width == 8: - IterResult = Gen.builder.bitcast(IterResult, ir.PointerType(Gen.structs[ClassName]), name=f"cast_iter_{ClassName}") - NextCall: ir.Function = Gen._get_function(f'{ClassName}.__next__') - StopFlagPtr: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(1), name="stop_iter_flag") - Gen.builder.store(ir.Constant(ir.IntType(1), 0), StopFlagPtr) - NextReturnType: ir.Type = NextCall.function_type.return_type - if TargetName in Gen._reg_values: - del Gen._reg_values[TargetName] - LoopVar: ir.AllocaInstr = Gen._allocaEntry(NextReturnType, name=TargetName) - Gen.variables[TargetName] = LoopVar - CondBB: ir.Block = Gen.func.append_basic_block(name="iter.cond") - BodyBB: ir.Block = Gen.func.append_basic_block(name="iter.body") - StepBB: ir.Block = Gen.func.append_basic_block(name="iter.step") - ElseBB: ir.Block | None = Gen.func.append_basic_block(name="iter.else") if Node.orelse else None - AfterBB: ir.Block = Gen.func.append_basic_block(name="iter.end") - Gen.loop_break_targets.append(AfterBB) - Gen.loop_continue_targets.append(StepBB) - Gen.builder.branch(CondBB) - Gen.builder.position_at_start(CondBB) - Gen.builder.store(ir.Constant(ir.IntType(1), 0), StopFlagPtr) - NextCallArgs: list[ir.Value] = [IterResult, StopFlagPtr] - if NextCall and len(NextCall.function_type.args) > len(NextCallArgs): - last_param_type: ir.Type = NextCall.function_type.args[-1] - if (isinstance(last_param_type, ir.PointerType) - and isinstance(last_param_type.pointee, ir.PointerType) - and isinstance(last_param_type.pointee.pointee, ir.IntType) - and last_param_type.pointee.pointee.width == 8): - null_msg: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null") - NextCallArgs.append(null_msg) - NextVal: ir.Value = Gen.builder.call(NextCall, NextCallArgs, name=f"call_{ClassName}.__next__") - StopFlag: ir.Value = Gen.builder.load(StopFlagPtr, name="stop_flag") - Cond: ir.Value = Gen.builder.icmp_signed('==', StopFlag, ir.Constant(ir.IntType(1), 0), name="iter_cond") - Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB) - Gen.builder.position_at_start(BodyBB) - Gen._store(NextVal, LoopVar) - Gen._reg_values[TargetName] = NextVal - self.HandleBodyLlvm(Node.body) - if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is NextVal: - del Gen._reg_values[TargetName] - if not Gen.builder.block.is_terminated: - Gen.builder.branch(StepBB) - Gen.builder.position_at_start(StepBB) - Gen.builder.branch(CondBB) - Gen.loop_break_targets.pop() - Gen.loop_continue_targets.pop() - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - - # ===== zip() 内置支持 ===== - - def _HandleForZipLlvm(self, Node: ast.For) -> None: - """for a, b in zip(iter1, iter2): — 多迭代器并行迭代 - - 兼容 range、__iter__/__next__、字符串、数组、指针等所有迭代类型。 - 任一迭代器停止则退出循环。 - """ - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if not isinstance(Node.target, ast.Tuple): - return - Targets: list[ast.Name] = [t for t in Node.target.elts if isinstance(t, ast.Name)] - ZipArgs: list[ast.expr] = Node.iter.args - if len(Targets) != len(ZipArgs) or len(Targets) < 2: - return - - # 为每个可迭代对象设置迭代状态 - IterInfos: list[dict] = [] - for i, arg in enumerate(ZipArgs): - target_name: str = Targets[i].id - info: dict | None = self._zip_setup_iter(arg, target_name, Gen) - if info is None: - return - IterInfos.append(info) - - CondBB: ir.Block = Gen.func.append_basic_block(name="zip.cond") - BodyBB: ir.Block = Gen.func.append_basic_block(name="zip.body") - StepBB: ir.Block = Gen.func.append_basic_block(name="zip.step") - ElseBB: ir.Block | None = Gen.func.append_basic_block(name="zip.else") if Node.orelse else None - AfterBB: ir.Block = Gen.func.append_basic_block(name="zip.end") - Gen.loop_break_targets.append(AfterBB) - Gen.loop_continue_targets.append(StepBB) - Gen.builder.branch(CondBB) - - # Cond 块:为每个迭代器获取下一个值和停止条件 - Gen.builder.position_at_start(CondBB) - AnyStopped: ir.Value | None = None - for info in IterInfos: - val: ir.Value - stopped: ir.Value - val, stopped = self._zip_get_next(info, Gen) - info['last_value'] = val - if AnyStopped is None: - AnyStopped = stopped - else: - AnyStopped = Gen.builder.or_(AnyStopped, stopped, name="zip_any_stop") - Gen.builder.cbranch(AnyStopped, ElseBB if ElseBB else AfterBB, BodyBB) - - # Body 块:赋值并执行循环体 - Gen.builder.position_at_start(BodyBB) - for info in IterInfos: - Gen._store(info['last_value'], info['loop_var']) - Gen._reg_values[info['target_name']] = info['last_value'] - self.HandleBodyLlvm(Node.body) - for info in IterInfos: - tn: str = info['target_name'] - if tn in Gen._reg_values and Gen._reg_values[tn] is info['last_value']: - del Gen._reg_values[tn] - if not Gen.builder.block.is_terminated: - Gen.builder.branch(StepBB) - - # Step 块:跳回 Cond(推进已在 Cond 中完成) - Gen.builder.position_at_start(StepBB) - Gen.builder.branch(CondBB) - Gen.loop_break_targets.pop() - Gen.loop_continue_targets.pop() - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - - def _zip_setup_iter(self, arg: ast.expr, target_name: str, Gen: "Translator.LlvmGen") -> dict | None: - """为 zip 参数设置迭代状态,返回包含迭代信息的 dict。""" - if target_name in Gen._reg_values: - del Gen._reg_values[target_name] - - # Case 1: range(n) / range(start, end) / range(start, end, step) - if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Name) and arg.func.id == 'range': - return self._zip_setup_range(arg, target_name, Gen) - - # Case 2: c.Addr(x) — 指针/数组迭代 - if (isinstance(arg, ast.Call) - and isinstance(arg.func, ast.Attribute) - and isinstance(arg.func.value, ast.Name) - and arg.func.value.id == 'c' - and arg.func.attr == 'Addr' - and arg.args): - AddrArg: ast.expr = arg.args[0] - if isinstance(AddrArg, ast.Name) and AddrArg.id in Gen.variables: - _var_ptr: ir.Value | None = Gen.variables[AddrArg.id] - if _var_ptr is not None and isinstance(_var_ptr.type, ir.PointerType): - _pointee: ir.Type = _var_ptr.type.pointee - if isinstance(_pointee, ir.IntType): - if _pointee.width == 8: - return self._zip_setup_str(_var_ptr, target_name, Gen) - return self._zip_setup_ptr(_var_ptr, target_name, _pointee, Gen) - if isinstance(_pointee, ir.ArrayType) and isinstance(_pointee.element, ir.IntType): - _elem_type: ir.IntType = _pointee.element - if _elem_type.width == 8: - return self._zip_setup_str(_var_ptr, target_name, Gen) - _typed_ptr: ir.Value = Gen.builder.bitcast(_var_ptr, ir.PointerType(_elem_type), name="zip_addr_cast") - return self._zip_setup_ptr(_typed_ptr, target_name, _elem_type, Gen) - - # Case 3: __iter__/__next__ 类迭代 - IterClassName: str | None = self.Trans.ExprHandler._get_var_class(arg, Gen) - if not IterClassName and isinstance(arg, ast.Call) and isinstance(arg.func, ast.Name): - IterClassName = arg.func.id - if IterClassName not in Gen.structs: - IterClassName = None - if IterClassName and Gen._has_function(f'{IterClassName}.__iter__') and Gen._has_function(f'{IterClassName}.__next__'): - return self._zip_setup_iter_class(arg, target_name, IterClassName, Gen) - - # Case 4-6: 求值表达式后按类型分发 - IterVal: ir.Value | None = self.HandleExprLlvm(arg) - if not IterVal: - return None - # 回退:通过 LLVM 类型查找结构体类名,检测 __iter__/__next__ - if not IterClassName and isinstance(IterVal.type, ir.PointerType): - _pointee: ir.Type = IterVal.type.pointee - if isinstance(_pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): - _found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(_pointee) - if _found: - _cn: str = _found[0] - if not (Gen._has_function(f'{_cn}.__iter__') and Gen._has_function(f'{_cn}.__next__')): - self.Trans.ImportHandler._TryLoadFuncDeclsFromOutputStub(_cn, Gen) - if Gen._has_function(f'{_cn}.__iter__') and Gen._has_function(f'{_cn}.__next__'): - Gen._UnregisterTempPtr(IterVal) - return self._zip_setup_iter_class_from_val(IterVal, target_name, _cn, Gen) - if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8: - return self._zip_setup_str(IterVal, target_name, Gen) - if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.ArrayType): - return self._zip_setup_array(IterVal, target_name, Gen) - # Case 6: 整数计数器 - return self._zip_setup_int(IterVal, target_name, Gen) - - def _zip_setup_range(self, arg: ast.Call, target_name: str, Gen: "Translator.LlvmGen") -> dict | None: - RangeArgs: list[ast.expr] = arg.args - if len(RangeArgs) == 1: - StartVal: ir.Value = ir.Constant(ir.IntType(32), 0) - EndVal: ir.Value = self.HandleExprLlvm(RangeArgs[0]) - StepVal: ir.Value = ir.Constant(ir.IntType(32), 1) - elif len(RangeArgs) == 2: - StartVal = self.HandleExprLlvm(RangeArgs[0]) - EndVal = self.HandleExprLlvm(RangeArgs[1]) - StepVal = ir.Constant(ir.IntType(32), 1) - elif len(RangeArgs) >= 3: - StartVal = self.HandleExprLlvm(RangeArgs[0]) - EndVal = self.HandleExprLlvm(RangeArgs[1]) - StepVal = self.HandleExprLlvm(RangeArgs[2]) - else: - return None - if not EndVal: - return None - if not isinstance(EndVal.type, ir.IntType): - if isinstance(EndVal.type, ir.PointerType) and isinstance(EndVal.type.pointee, ir.IntType): - EndVal = Gen._load(EndVal, name="zip_end") - else: - EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="zip_end") - if not isinstance(StartVal.type, ir.IntType): - StartVal = ir.Constant(EndVal.type, 0) - if isinstance(StartVal.type, ir.IntType) and isinstance(EndVal.type, ir.IntType): - if StartVal.type.width < EndVal.type.width: - StartVal = Gen.builder.zext(StartVal, EndVal.type, name="zip_start_zext") - elif StartVal.type.width > EndVal.type.width: - EndVal = Gen.builder.zext(EndVal, StartVal.type, name="zip_end_zext") - if isinstance(StepVal.type, ir.IntType) and isinstance(EndVal.type, ir.IntType): - if StepVal.type.width < EndVal.type.width: - StepVal = Gen.builder.zext(StepVal, EndVal.type, name="zip_step_zext") - IdxVar: ir.AllocaInstr = Gen._allocaEntry(EndVal.type, name=f"zip_{target_name}_idx") - Gen._store(StartVal, IdxVar) - LoopVar: ir.AllocaInstr = Gen._allocaEntry(EndVal.type, name=target_name) - Gen.variables[target_name] = LoopVar - Gen._store(StartVal, LoopVar) - Gen._record_var_signedness(target_name, 'int') - return { - 'iter_type': 'range', - 'target_name': target_name, - 'value_type': EndVal.type, - 'idx_var': IdxVar, - 'end_val': EndVal, - 'step_val': StepVal, - 'loop_var': LoopVar, - } - - def _zip_setup_iter_class(self, arg: ast.expr, target_name: str, ClassName: str, Gen: "Translator.LlvmGen") -> dict | None: - IterVal: ir.Value | None = self.HandleExprLlvm(arg) - if not IterVal: - return None - return self._zip_setup_iter_class_from_val(IterVal, target_name, ClassName, Gen) - - def _zip_setup_iter_class_from_val(self, IterVal: ir.Value, target_name: str, ClassName: str, Gen: "Translator.LlvmGen") -> dict | None: - Gen._UnregisterTempPtr(IterVal) - if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8: - IterVal = Gen.builder.bitcast(IterVal, ir.PointerType(Gen.structs[ClassName]), name=f"zip_cast_{ClassName}") - IterCall: ir.Function = Gen._get_function(f'{ClassName}.__iter__') - IterResult: ir.Value = Gen.builder.call(IterCall, [IterVal], name=f"zip_call_{ClassName}.__iter__") - Gen._UnregisterTempPtr(IterResult) - if isinstance(IterResult.type, ir.PointerType) and isinstance(IterResult.type.pointee, ir.IntType) and IterResult.type.pointee.width == 8: - IterResult = Gen.builder.bitcast(IterResult, ir.PointerType(Gen.structs[ClassName]), name=f"zip_cast_iter_{ClassName}") - NextCall: ir.Function = Gen._get_function(f'{ClassName}.__next__') - StopFlagPtr: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(1), name=f"zip_stop_{target_name}") - Gen.builder.store(ir.Constant(ir.IntType(1), 0), StopFlagPtr) - NextReturnType: ir.Type = NextCall.function_type.return_type - LoopVar: ir.AllocaInstr = Gen._allocaEntry(NextReturnType, name=target_name) - Gen.variables[target_name] = LoopVar - return { - 'iter_type': 'iter', - 'target_name': target_name, - 'value_type': NextReturnType, - 'iter_obj': IterResult, - 'next_call': NextCall, - 'stop_flag': StopFlagPtr, - 'loop_var': LoopVar, - } - - def _zip_setup_str(self, StrVal: ir.Value, target_name: str, Gen: "Translator.LlvmGen") -> dict: - Gen._UnregisterTempPtr(StrVal) - PtrVal: ir.AllocaInstr = Gen.builder.alloca(ir.IntType(8).as_pointer(), name=f"zip_{target_name}_ptr") - Gen.builder.store(StrVal, PtrVal) - CharType: ir.IntType = ir.IntType(8) - LoopVar: ir.AllocaInstr = Gen._allocaEntry(CharType, name=target_name) - Gen.variables[target_name] = LoopVar - Gen._store(ir.Constant(CharType, 0), LoopVar) - Gen._record_var_signedness(target_name, 'char') - return { - 'iter_type': 'str', - 'target_name': target_name, - 'value_type': CharType, - 'ptr_var': PtrVal, - 'loop_var': LoopVar, - } - - def _zip_setup_array(self, ArrPtr: ir.Value, target_name: str, Gen: "Translator.LlvmGen") -> dict: - ElemType: ir.Type = ArrPtr.type.pointee.element - ArrayCount: int = ArrPtr.type.pointee.count - IdxVar: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=f"zip_{target_name}_idx") - Gen.builder.store(ir.Constant(ir.IntType(32), 0), IdxVar) - LoopVar: ir.AllocaInstr = Gen._allocaEntry(ElemType, name=target_name) - Gen.variables[target_name] = LoopVar - Gen._store(ir.Constant(ElemType, None), LoopVar) - Gen._record_var_signedness(target_name, 'ptr') - return { - 'iter_type': 'array', - 'target_name': target_name, - 'value_type': ElemType, - 'arr_ptr': ArrPtr, - 'idx_var': IdxVar, - 'count_val': ir.Constant(ir.IntType(32), ArrayCount), - 'loop_var': LoopVar, - } - - def _zip_setup_ptr(self, PtrVal: ir.Value, target_name: str, ElemType: ir.IntType, Gen: "Translator.LlvmGen") -> dict: - TypedPtr: ir.Value = PtrVal - if isinstance(PtrVal.type, ir.PointerType) and PtrVal.type.pointee is not ElemType: - TypedPtr = Gen.builder.bitcast(PtrVal, ir.PointerType(ElemType), name="zip_ptr_cast") - Gen._UnregisterTempPtr(TypedPtr) - PtrCopy: ir.AllocaInstr = Gen.builder.alloca(ir.PointerType(ElemType), name=f"zip_{target_name}_ptr") - Gen.builder.store(TypedPtr, PtrCopy) - LoopVar: ir.AllocaInstr = Gen._allocaEntry(ElemType, name=target_name) - Gen.variables[target_name] = LoopVar - Gen._store(ir.Constant(ElemType, 0), LoopVar) - Gen._record_var_signedness(target_name, 'int') - return { - 'iter_type': 'ptr', - 'target_name': target_name, - 'value_type': ElemType, - 'ptr_var': PtrCopy, - 'loop_var': LoopVar, - } - - def _zip_setup_int(self, IterVal: ir.Value, target_name: str, Gen: "Translator.LlvmGen") -> dict: - EndVal: ir.Value = IterVal - if not isinstance(EndVal.type, ir.IntType): - EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="zip_int_end") - StartVal: ir.Value = ir.Constant(EndVal.type, 0) - StepVal: ir.Value = ir.Constant(EndVal.type, 1) - IdxVar: ir.AllocaInstr = Gen._allocaEntry(EndVal.type, name=f"zip_{target_name}_idx") - Gen._store(StartVal, IdxVar) - LoopVar: ir.AllocaInstr = Gen._allocaEntry(EndVal.type, name=target_name) - Gen.variables[target_name] = LoopVar - Gen._store(StartVal, LoopVar) - Gen._record_var_signedness(target_name, 'int') - return { - 'iter_type': 'range', - 'target_name': target_name, - 'value_type': EndVal.type, - 'idx_var': IdxVar, - 'end_val': EndVal, - 'step_val': StepVal, - 'loop_var': LoopVar, - } - - def _zip_get_next(self, info: dict, Gen: "Translator.LlvmGen") -> tuple[ir.Value, ir.Value]: - """生成获取下一个值和停止条件的 IR。返回 (value, stopped_cond)。""" - iter_type: str = info['iter_type'] - - if iter_type == 'range': - idx: ir.Value = Gen._load(info['idx_var'], name="zip_range_idx") - stopped: ir.Value = Gen.builder.icmp_signed('>=', idx, info['end_val'], name="zip_range_stop") - next_idx: ir.Value = Gen.builder.add(idx, info['step_val'], name="zip_range_next") - Gen._store(next_idx, info['idx_var']) - return idx, stopped - - if iter_type == 'iter': - Gen.builder.store(ir.Constant(ir.IntType(1), 0), info['stop_flag']) - args: list[ir.Value] = [info['iter_obj'], info['stop_flag']] - NextCall: ir.Function = info['next_call'] - if NextCall and len(NextCall.function_type.args) > len(args): - last_param_type: ir.Type = NextCall.function_type.args[-1] - if (isinstance(last_param_type, ir.PointerType) - and isinstance(last_param_type.pointee, ir.PointerType) - and isinstance(last_param_type.pointee.pointee, ir.IntType) - and last_param_type.pointee.pointee.width == 8): - null_msg: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="zip_eh_msg") - args.append(null_msg) - val: ir.Value = Gen.builder.call(NextCall, args, name="zip_iter_next") - stopped = Gen.builder.load(info['stop_flag'], name="zip_iter_stop") - return val, stopped - - if iter_type == 'str': - ptr: ir.Value = Gen._load(info['ptr_var'], name="zip_str_ptr") - val = Gen._load(ptr, name="zip_str_val") - stopped = Gen.builder.icmp_signed('==', val, ir.Constant(ir.IntType(8), 0), name="zip_str_stop") - next_ptr: ir.Value = Gen.builder.gep(ptr, [ir.Constant(ir.IntType(32), 1)], name="zip_str_next") - Gen._store(next_ptr, info['ptr_var']) - return val, stopped - - if iter_type == 'ptr': - ptr = Gen._load(info['ptr_var'], name="zip_ptr_cur") - val = Gen._load(ptr, name="zip_ptr_val") - elem_type: ir.IntType = info['value_type'] - stopped = Gen.builder.icmp_signed('==', val, ir.Constant(elem_type, 0), name="zip_ptr_stop") - next_ptr = Gen.builder.gep(ptr, [ir.Constant(ir.IntType(32), 1)], name="zip_ptr_next") - Gen._store(next_ptr, info['ptr_var']) - return val, stopped - - if iter_type == 'array': - idx = Gen._load(info['idx_var'], name="zip_arr_idx") - stopped = Gen.builder.icmp_signed('>=', idx, info['count_val'], name="zip_arr_stop") - elem_ptr: ir.Value = Gen.builder.gep(info['arr_ptr'], [ir.Constant(ir.IntType(32), 0), idx], name="zip_arr_elem") - val = Gen._load(elem_ptr, name="zip_arr_val") - next_idx = Gen.builder.add(idx, ir.Constant(ir.IntType(32), 1), name="zip_arr_next") - Gen._store(next_idx, info['idx_var']) - return val, stopped - - # 回退:立即停止 - return ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(1), 1) - - # ===== enumerate() 内置支持 ===== - - def _HandleForEnumerateLlvm(self, Node: ast.For) -> None: - """for idx, val in enumerate(iterable): — 带索引迭代 - - 等价于 zip(range(0, ∞), iterable),但无需 len()。 - idx 从 0 开始,每次迭代 +1。 - """ - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if not isinstance(Node.target, ast.Tuple): - return - Targets: list[ast.Name] = [t for t in Node.target.elts if isinstance(t, ast.Name)] - if len(Targets) != 2: - return - IdxTargetName: str = Targets[0].id - ValTargetName: str = Targets[1].id - IterArg: ast.expr = Node.iter.args[0] - - # 设置内部可迭代对象(复用 zip 基础设施) - if ValTargetName in Gen._reg_values: - del Gen._reg_values[ValTargetName] - if IdxTargetName in Gen._reg_values: - del Gen._reg_values[IdxTargetName] - IterInfo: dict | None = self._zip_setup_iter(IterArg, ValTargetName, Gen) - if IterInfo is None: - return - - # 索引计数器(i32,从 0 开始) - IdxType: ir.IntType = ir.IntType(32) - IdxVar: ir.AllocaInstr = Gen._allocaEntry(IdxType, name=f"enum_{IdxTargetName}") - Gen._store(ir.Constant(IdxType, 0), IdxVar) - IdxLoopVar: ir.AllocaInstr = Gen._allocaEntry(IdxType, name=IdxTargetName) - Gen.variables[IdxTargetName] = IdxLoopVar - Gen._store(ir.Constant(IdxType, 0), IdxLoopVar) - Gen._record_var_signedness(IdxTargetName, 'int') - - CondBB: ir.Block = Gen.func.append_basic_block(name="enum.cond") - BodyBB: ir.Block = Gen.func.append_basic_block(name="enum.body") - StepBB: ir.Block = Gen.func.append_basic_block(name="enum.step") - ElseBB: ir.Block | None = Gen.func.append_basic_block(name="enum.else") if Node.orelse else None - AfterBB: ir.Block = Gen.func.append_basic_block(name="enum.end") - Gen.loop_break_targets.append(AfterBB) - Gen.loop_continue_targets.append(StepBB) - Gen.builder.branch(CondBB) - - # Cond 块:获取下一个值和停止条件 - Gen.builder.position_at_start(CondBB) - CurIdx: ir.Value = Gen._load(IdxVar, name="enum_idx") - Val, Stopped = self._zip_get_next(IterInfo, Gen) - IterInfo['last_value'] = Val - Gen.builder.cbranch(Stopped, ElseBB if ElseBB else AfterBB, BodyBB) - - # Body 块:赋值并执行循环体 - Gen.builder.position_at_start(BodyBB) - Gen._store(CurIdx, IdxLoopVar) - Gen._store(Val, IterInfo['loop_var']) - Gen._reg_values[IdxTargetName] = CurIdx - Gen._reg_values[ValTargetName] = Val - self.HandleBodyLlvm(Node.body) - if IdxTargetName in Gen._reg_values and Gen._reg_values[IdxTargetName] is CurIdx: - del Gen._reg_values[IdxTargetName] - if ValTargetName in Gen._reg_values and Gen._reg_values[ValTargetName] is Val: - del Gen._reg_values[ValTargetName] - if not Gen.builder.block.is_terminated: - Gen.builder.branch(StepBB) - - # Step 块:索引 +1,跳回 Cond - Gen.builder.position_at_start(StepBB) - CurIdx2: ir.Value = Gen._load(IdxVar, name="enum_idx2") - NextIdx: ir.Value = Gen.builder.add(CurIdx2, ir.Constant(IdxType, 1), name="enum_next") - Gen._store(NextIdx, IdxVar) - Gen.builder.branch(CondBB) - Gen.loop_break_targets.pop() - Gen.loop_continue_targets.pop() - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import vast as ast +import llvmlite.ir as ir + + +def _safe_ptr_type(ty: ir.Type) -> ir.Type: + """LLVM IR 中不允许 void* 指针,统一替换为 i8*(对应 C 的 void* 语义) + + 当 ty 是 Ptr(VoidType) / Ptr(Ptr(VoidType)) / 任何包含 VoidType 作为 pointee 的指针链, + 替换为 Ptr(i8)。非指针类型原样返回。 + """ + if isinstance(ty, ir.PointerType): + # 单级 / 多级 void 指针全部降级为 i8* + cur: ir.Type = ty + while isinstance(cur, ir.PointerType): + if isinstance(cur.pointee, ir.VoidType): + return ir.IntType(8).as_pointer() + cur = cur.pointee + return ty + + +class ForHandle(BaseHandle): + def _HandleForLlvm(self, Node: ast.For) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + Gen._set_node_info(Node, "For") + # zip() 内置:for a, b in zip(iter1, iter2): + if (isinstance(Node.iter, ast.Call) + and isinstance(Node.iter.func, ast.Name) + and Node.iter.func.id == 'zip' + and isinstance(Node.target, ast.Tuple)): + self._HandleForZipLlvm(Node) + return + # enumerate() 内置:for idx, val in enumerate(iterable): + if (isinstance(Node.iter, ast.Call) + and isinstance(Node.iter.func, ast.Name) + and Node.iter.func.id == 'enumerate' + and isinstance(Node.target, ast.Tuple) + and Node.iter.args): + self._HandleForEnumerateLlvm(Node) + return + if not isinstance(Node.target, ast.Name): + return + TargetName: str = Node.target.id + StartVal: ir.Value | None = None + EndVal: ir.Value | None = None + StepVal: ir.Value | None = None + IsRange: bool = False + CondOp: str = '<' + if isinstance(Node.iter, ast.Call): + CallFunc: ast.expr = Node.iter.func + if isinstance(CallFunc, ast.Name) and CallFunc.id == 'range': + IsRange = True + RangeArgs: list[ast.expr] = Node.iter.args + RangeEndArg: ast.expr | None = RangeArgs[1] if len(RangeArgs) >= 2 else RangeArgs[0] if len(RangeArgs) >= 1 else None + OptimizedEnd: bool = False + if len(RangeArgs) >= 2 and isinstance(RangeEndArg, ast.BinOp): + if isinstance(RangeEndArg.op, ast.Add): + if (isinstance(RangeEndArg.right, ast.Constant) and RangeEndArg.right.value == 1): + EndVal = self.HandleExprLlvm(RangeEndArg.left) + CondOp = '<=' + OptimizedEnd = True + elif (isinstance(RangeEndArg.left, ast.Constant) and RangeEndArg.left.value == 1): + EndVal = self.HandleExprLlvm(RangeEndArg.right) + CondOp = '<=' + OptimizedEnd = True + elif isinstance(RangeEndArg.op, ast.Sub): + if isinstance(RangeEndArg.right, ast.Constant) and RangeEndArg.right.value == 1: + EndVal = self.HandleExprLlvm(RangeEndArg.left) + CondOp = '<' + OptimizedEnd = True + if not OptimizedEnd: + if len(RangeArgs) == 1: + EndVal = self.HandleExprLlvm(RangeArgs[0]) + else: + EndVal = self.HandleExprLlvm(RangeEndArg) + if len(RangeArgs) == 1: + StartVal = ir.Constant(ir.IntType(32), 0) + elif len(RangeArgs) >= 2: + StartVal = self.HandleExprLlvm(RangeArgs[0]) + if len(RangeArgs) >= 3: + StepVal = self.HandleExprLlvm(RangeArgs[2]) + # Check if step is a negative constant — need to flip condition + step_arg: ast.expr = RangeArgs[2] + if isinstance(step_arg, ast.UnaryOp) and isinstance(step_arg.op, ast.USub): + if isinstance(step_arg.operand, ast.Constant) and isinstance(step_arg.operand.value, (int, float)): + if step_arg.operand.value > 0: + CondOp = '>' + elif isinstance(step_arg, ast.Constant) and isinstance(step_arg.value, (int, float)): + if step_arg.value < 0: + CondOp = '>' + if not EndVal: + return + if not isinstance(EndVal.type, ir.IntType): + if isinstance(EndVal.type, ir.PointerType) and isinstance(EndVal.type.pointee, ir.IntType): + EndVal = Gen._load(EndVal, name="Load_end") + else: + EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="end") + if StartVal and not isinstance(StartVal.type, ir.IntType): + if isinstance(StartVal.type, ir.PointerType) and isinstance(StartVal.type.pointee, ir.IntType): + StartVal = Gen._load(StartVal, name="Load_start") + else: + StartVal = Gen.builder.ptrtoint(StartVal, ir.IntType(64), name="start") + else: + StartVal = ir.Constant(ir.IntType(64), 0) + if not StartVal: + StartVal = ir.Constant(EndVal.type, 0) + if StepVal is None: + StepVal = ir.Constant(EndVal.type, 1) + if not IsRange: + # 检测 c.Addr(x) 模式:按原始变量类型迭代(for i64 in i64* 语义) + if (isinstance(Node.iter, ast.Call) + and isinstance(Node.iter.func, ast.Attribute) + and isinstance(Node.iter.func.value, ast.Name) + and Node.iter.func.value.id == 'c' + and Node.iter.func.attr == 'Addr' + and Node.iter.args): + AddrArg: ast.expr = Node.iter.args[0] + if isinstance(AddrArg, ast.Name) and AddrArg.id in Gen.variables: + _var_ptr: ir.Value | None = Gen.variables[AddrArg.id] + if _var_ptr is not None and isinstance(_var_ptr.type, ir.PointerType): + _pointee: ir.Type = _var_ptr.type.pointee + # 标量整数变量 + if isinstance(_pointee, ir.IntType): + if _pointee.width == 8: + self._HandleForStrLlvm(Node, _var_ptr) + return + self._HandleForPtrLlvm(Node, _var_ptr, _pointee) + return + # 数组变量:取元素类型 + if isinstance(_pointee, ir.ArrayType) and isinstance(_pointee.element, ir.IntType): + _elem_type: ir.IntType = _pointee.element + if _elem_type.width == 8: + self._HandleForStrLlvm(Node, _var_ptr) + return + _typed_ptr: ir.Value = Gen.builder.bitcast(_var_ptr, ir.PointerType(_elem_type), name="addr_arr_elem_cast") + self._HandleForPtrLlvm(Node, _typed_ptr, _elem_type) + return + IterClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.iter, Gen) + if not IterClassName and isinstance(Node.iter, ast.Call) and isinstance(Node.iter.func, ast.Name): + IterClassName = Node.iter.func.id + if IterClassName not in Gen.structs: + IterClassName = None + if IterClassName and Gen._has_function(f'{IterClassName}.__iter__') and Gen._has_function(f'{IterClassName}.__next__'): + self._HandleForIterLlvm(Node, IterClassName) + return + IterVal: ir.Value | None = self.HandleExprLlvm(Node.iter) + if not IterVal: + return + # 回退:通过 LLVM 类型查找结构体类名,检测 __iter__/__next__ + if not IterClassName and isinstance(IterVal.type, ir.PointerType): + _pointee: ir.Type = IterVal.type.pointee + if isinstance(_pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + _found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(_pointee) + if _found: + _cn: str = _found[0] + if not (Gen._has_function(f'{_cn}.__iter__') and Gen._has_function(f'{_cn}.__next__')): + # temp stub 可能不包含泛型特化方法,尝试从 output stub 按需加载 + self.Trans.ImportHandler._TryLoadFuncDeclsFromOutputStub(_cn, Gen) + if Gen._has_function(f'{_cn}.__iter__') and Gen._has_function(f'{_cn}.__next__'): + Gen._UnregisterTempPtr(IterVal) + self._HandleForIterLlvm(Node, _cn) + return + if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8: + self._HandleForStrLlvm(Node, IterVal) + return + if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.ArrayType): + self._HandleForListLlvm(Node, IterVal) + return + StartVal = ir.Constant(ir.IntType(32), 0) + EndVal = IterVal + if not isinstance(EndVal.type, ir.IntType): + EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="end") + StartVal = ir.Constant(ir.IntType(64), 0) + StepVal = ir.Constant(EndVal.type, 1) + CondOp = '<' + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + LoopVar: ir.AllocaInstr + if TargetName in Gen.variables and Gen.variables[TargetName] is not None: + LoopVar = Gen.variables[TargetName] + if isinstance(LoopVar.type, ir.PointerType) and isinstance(LoopVar.type.pointee, ir.IntType) and LoopVar.type.pointee == EndVal.type and isinstance(EndVal.type, ir.IntType) and StartVal.type == LoopVar.type.pointee and EndVal.type == StartVal.type: + Gen._store(StartVal, LoopVar) + else: + NewVar: ir.AllocaInstr = Gen._allocaEntry(EndVal.type, name=TargetName) + if StartVal.type != EndVal.type: + if isinstance(EndVal.type, ir.IntType) and isinstance(StartVal.type, ir.IntType): + if StartVal.type.width < EndVal.type.width: + StartVal = Gen.builder.zext(StartVal, EndVal.type, name="zext_loop_start") + elif StartVal.type.width > EndVal.type.width: + StartVal = Gen.builder.trunc(StartVal, EndVal.type, name="trunc_loop_start") + Gen._store(StartVal, NewVar) + Gen.variables[TargetName] = NewVar + LoopVar = NewVar + else: + LoopVar = Gen._allocaEntry(EndVal.type, name=TargetName) + Gen.variables[TargetName] = LoopVar + Gen._store(StartVal, LoopVar) + if StepVal and isinstance(StepVal.type, ir.IntType) and isinstance(EndVal.type, ir.IntType): + if StepVal.type.width < EndVal.type.width: + StepVal = Gen.builder.zext(StepVal, EndVal.type, name="zext_loop_step") + elif StepVal.type.width > EndVal.type.width: + StepVal = Gen.builder.trunc(StepVal, EndVal.type, name="trunc_loop_step") + Gen._record_var_signedness(TargetName, 'int') + CondBB: ir.Block = Gen.func.append_basic_block(name="for.cond") + BodyBB: ir.Block = Gen.func.append_basic_block(name="for.body") + StepBB: ir.Block = Gen.func.append_basic_block(name="for.step") + ElseBB: ir.Block | None = Gen.func.append_basic_block(name="for.else") if Node.orelse else None + AfterBB: ir.Block = Gen.func.append_basic_block(name="for.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(StepBB) + Gen.builder.branch(CondBB) + Gen.builder.position_at_start(CondBB) + LoopVal: ir.Value = Gen._load(LoopVar, name=TargetName) + is_unsigned: bool = Gen._is_var_unsigned(TargetName) + Cond: ir.Value + if is_unsigned: + Cond = Gen.builder.icmp_unsigned(CondOp, LoopVal, EndVal, name="forcond") + else: + Cond = Gen.builder.icmp_signed(CondOp, LoopVal, EndVal, name="forcond") + Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB) + Gen.builder.position_at_start(BodyBB) + CachedLoopVal: ir.Value = Gen._load(LoopVar, name=TargetName) + Gen._reg_values[TargetName] = CachedLoopVal + self.HandleBodyLlvm(Node.body) + StepLoopVal: ir.Value = CachedLoopVal + if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is CachedLoopVal: + del Gen._reg_values[TargetName] + elif not Gen.builder.block.is_terminated: + # 死代码防御(2026-08-15):body 修改过循环变量时此处重新 load, + # 但该值实际未被使用(step 块 L237 会重新 load)。 + # 若 body 以 break/continue/return 终结,当前块已带 terminator, + # 再发射 load 会落在 terminator 之后 → opt 报 + # "expected instruction opcode" 非法 IR。 + StepLoopVal = Gen._load(LoopVar, name=TargetName) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(StepBB) + Gen.builder.position_at_start(StepBB) + StepLoopVal2: ir.Value = Gen._load(LoopVar, name=TargetName) + NextVal: ir.Value = Gen.builder.add(StepLoopVal2, StepVal, name="next") + Gen._store(NextVal, LoopVar) + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + def _HandleGlobalLlvm(self, Node: ast.Global) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + self._RegisterGlobalNames(Node.names, Gen, clear_reg_values=True) + + def _RegisterGlobalNames(self, names: list[str], Gen: "Translator.LlvmGen", clear_reg_values: bool = False) -> None: + for name in names: + Gen.global_vars.add(name) + if name in Gen.module.globals: + Gen.variables[name] = Gen.module.globals[name] + if clear_reg_values and name in Gen._reg_values: + del Gen._reg_values[name] + + def _HandleNonlocalLlvm(self, Node: ast.Nonlocal) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + for name in Node.names: + if name in Gen._reg_values and name not in Gen.variables: + OldVal: ir.Value = Gen._reg_values[name] + var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=name) + Gen._store(OldVal, var) + Gen.variables[name] = var + del Gen._reg_values[name] + + def _collect_implicit_nonlocal(self, Node: ast.FunctionDef, Gen: "Translator.LlvmGen") -> list[str]: + param_names: set[str] = set() + for arg in Node.args.args: + param_names.add(arg.arg) + local_names: set[str] = set() + for child in ast.walk(Node): + if isinstance(child, ast.Assign): + for target in child.targets: + if isinstance(target, ast.Name): + local_names.add(target.id) + elif isinstance(target, ast.Tuple): + for elt in target.elts: + if isinstance(elt, ast.Name): + local_names.add(elt.id) + elif isinstance(child, ast.AugAssign): + if isinstance(child.target, ast.Name): + local_names.add(child.target.id) + elif isinstance(child, ast.AnnAssign): + if isinstance(child.target, ast.Name): + local_names.add(child.target.id) + elif isinstance(child, ast.For): + if isinstance(child.target, ast.Name): + local_names.add(child.target.id) + read_names: set[str] = set() + for child in ast.walk(Node): + if isinstance(child, ast.Name) and isinstance(child.ctx, ast.Load): + name: str = child.id + if name not in param_names and name not in local_names: + read_names.add(name) + implicit: list[str] = [] + for name in read_names: + if name in Gen.variables and Gen.variables[name] is not None: + implicit.append(name) + elif name in Gen._reg_values: + implicit.append(name) + for called_name in read_names: + if called_name in Gen.nonlocal_params: + for nv, _ in Gen.nonlocal_params[called_name]: + if nv not in param_names and nv not in local_names: + if nv not in read_names: + if nv in Gen.variables and Gen.variables[nv] is not None: + implicit.append(nv) + elif nv in Gen._reg_values: + implicit.append(nv) + return implicit + + def _collect_all_nonlocal_names(self, Node: ast.FunctionDef) -> set[str]: + """Recursively collect all nonlocal variable names from a function and its nested functions.""" + names: set[str] = set() + for stmt in Node.body: + if isinstance(stmt, ast.Nonlocal): + for name in stmt.names: + names.add(name) + elif isinstance(stmt, ast.FunctionDef): + # Recursively collect from nested functions + sub_names: set[str] = self._collect_all_nonlocal_names(stmt) + names.update(sub_names) + return names + + def _HandleNestedFunctionLlvm(self, Node: ast.FunctionDef) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + nonlocal_var_names: list[str] = [] + for stmt in Node.body: + if isinstance(stmt, ast.Nonlocal): + for name in stmt.names: + nonlocal_var_names.append(name) + # Pre-scan ALL nested functions recursively for their nonlocal needs (passthrough) + for stmt in Node.body: + if isinstance(stmt, ast.FunctionDef): + sub_nonlocal_names: set[str] = self._collect_all_nonlocal_names(stmt) + for name in sub_nonlocal_names: + if name not in nonlocal_var_names: + nonlocal_var_names.append(name) + implicit_names: list[str] = self._collect_implicit_nonlocal(Node, Gen) + for name in implicit_names: + if name not in nonlocal_var_names: + nonlocal_var_names.append(name) + # 堆分配 nonlocal 变量:避免外层函数返回后栈帧释放导致悬垂指针 + # 闭包返回模式(return nested_fn)要求捕获变量在堆上存活 + malloc_fn_type: ir.FunctionType = ir.FunctionType(ir.IntType(8).as_pointer(), [ir.IntType(64)]) + malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_fn_type) + for var_name in nonlocal_var_names: + if var_name in Gen.variables and Gen.variables[var_name] is not None: + old_var: ir.Value = Gen.variables[var_name] + if isinstance(old_var.type, ir.PointerType): + elem_type: ir.Type = old_var.type.pointee + # 计算元素大小(字节) + elem_size: int = 8 # 默认指针大小 + if isinstance(elem_type, ir.IntType): + elem_size = max(1, elem_type.width // 8) + elif isinstance(elem_type, ir.FloatType): + elem_size = 4 + elif isinstance(elem_type, ir.DoubleType): + elem_size = 8 + elif isinstance(elem_type, ir.PointerType): + elem_size = 8 + # malloc 堆存储 + heap_raw: ir.Value = Gen.builder.call(malloc_func, [ir.Constant(ir.IntType(64), elem_size)], name=f"heap_{var_name}") + heap_ptr: ir.Value = Gen.builder.bitcast(heap_raw, ir.PointerType(elem_type), name=f"heap_{var_name}_ptr") + # 复制栈值到堆 + old_val: ir.Value = Gen._load(old_var, name=f"load_old_{var_name}") + Gen._store(old_val, heap_ptr) + # 更新 Gen.variables 使外层和嵌套函数都使用堆指针 + Gen.variables[var_name] = heap_ptr + extra_params: list[tuple[str, ir.Type]] = [] + for var_name in nonlocal_var_names: + if var_name in Gen.variables and Gen.variables[var_name] is not None: + var: ir.Value = Gen.variables[var_name] + extra_params.append((var_name, _safe_ptr_type(var.type))) + elif var_name in Gen._reg_values: + OldVal: ir.Value = Gen._reg_values[var_name] + var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=var_name) + Gen._store(OldVal, var) + Gen.variables[var_name] = var + del Gen._reg_values[var_name] + extra_params.append((var_name, _safe_ptr_type(var.type))) + else: + # Search outer scope stack for the variable + found_var: ir.Value | None = None + for scope in reversed(Gen._variable_scope_stack): + if var_name in scope and scope[var_name] is not None: + found_var = scope[var_name] + break + if found_var is not None: + # Add to current scope so it can be passed to nested functions + Gen.variables[var_name] = found_var + extra_params.append((var_name, _safe_ptr_type(found_var.type))) + else: + var = Gen._allocaEntry(ir.IntType(32), name=var_name) + Gen.variables[var_name] = var + extra_params.append((var_name, _safe_ptr_type(var.type))) + if extra_params: + Gen.nonlocal_params[Node.name] = [(name, _safe_ptr_type(ptr_type)) for name, ptr_type in extra_params] + # Push current variables to scope stack before compiling nested function + Gen._variable_scope_stack.append(Gen.variables.copy()) + saved_builder: ir.IRBuilder = Gen.builder + saved_func: ir.Function = Gen.func + saved_variables: dict[str, ir.Value] = Gen.variables.copy() + saved_reg_values: dict[str, ir.Value] = Gen._reg_values.copy() + saved_global_vars: set[str] = Gen.global_vars.copy() + saved_var_signedness: dict[str, str] = Gen.var_signedness.copy() + saved_var_type_info: dict[str, dict[str, str]] = Gen.var_type_info.copy() + saved_var_type_assignments: dict[str, list[dict[str, str]]] = Gen.var_type_assignments.copy() + saved_CurrentCReturnTypes: object | None = getattr(self.Trans, 'CurrentCReturnTypes', None) + saved_CurrentCpythonObjectClass: str | None = getattr(self.Trans, '_CurrentCpythonObjectClass', None) + saved_VarScopes: int = len(self.Trans.VarScopes) + self.Trans.FunctionHandler._EmitFunctionLlvm(Node, Gen, extra_params=extra_params if extra_params else None) + Gen.builder = saved_builder + Gen.func = saved_func + Gen.variables = saved_variables + Gen._reg_values = saved_reg_values + Gen.global_vars = saved_global_vars + Gen.var_signedness = saved_var_signedness + Gen.var_type_info = saved_var_type_info + Gen.var_type_assignments = saved_var_type_assignments + self.Trans.CurrentCReturnTypes = saved_CurrentCReturnTypes + self.Trans._CurrentCpythonObjectClass = saved_CurrentCpythonObjectClass + while len(self.Trans.VarScopes) > saved_VarScopes: + self.Trans.VarScopes.pop() + # Pop scope stack + if Gen._variable_scope_stack: + Gen._variable_scope_stack.pop() + + def _HandleForListLlvm(self, Node: ast.For, ArrPtr: ir.Value) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if not isinstance(Node.target, ast.Name): + return + TargetName: str = Node.target.id + ElemType: ir.Type = ArrPtr.type.pointee.element + ArrayCount: int = ArrPtr.type.pointee.count + IdxVal: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=f"arr_idx") + Gen.builder.store(ir.Constant(ir.IntType(32), 0), IdxVal) + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + LoopVar: ir.AllocaInstr = Gen._allocaEntry(ElemType, name=TargetName) + Gen.variables[TargetName] = LoopVar + Gen._store(ir.Constant(ElemType, None), LoopVar) + CondBB: ir.Block = Gen.func.append_basic_block(name="arrfor.cond") + BodyBB: ir.Block = Gen.func.append_basic_block(name="arrfor.body") + StepBB: ir.Block = Gen.func.append_basic_block(name="arrfor.step") + ElseBB: ir.Block | None = Gen.func.append_basic_block(name="arrfor.else") if Node.orelse else None + AfterBB: ir.Block = Gen.func.append_basic_block(name="arrfor.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(StepBB) + Gen.builder.branch(CondBB) + Gen.builder.position_at_start(CondBB) + CurIdx: ir.Value = Gen._load(IdxVal, name="cur_idx") + IsDone: ir.Value = Gen.builder.icmp_signed('<', CurIdx, ir.Constant(ir.IntType(32), ArrayCount), name="arr_in_bounds") + Gen.builder.cbranch(IsDone, BodyBB, ElseBB if ElseBB else AfterBB) + Gen.builder.position_at_start(BodyBB) + ElemPtr: ir.Value = Gen.builder.gep(ArrPtr, [ir.Constant(ir.IntType(32), 0), CurIdx], name="arr_elem_ptr") + ElemVal: ir.Value = Gen._load(ElemPtr, name="arr_elem_val") + Gen._store(ElemVal, LoopVar) + Gen._record_var_signedness(TargetName, 'ptr') + Gen._reg_values[TargetName] = ElemVal + self.HandleBodyLlvm(Node.body) + if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is ElemVal: + del Gen._reg_values[TargetName] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(StepBB) + Gen.builder.position_at_start(StepBB) + CurIdx2: ir.Value = Gen._load(IdxVal, name="cur_idx2") + NextIdx: ir.Value = Gen.builder.add(CurIdx2, ir.Constant(ir.IntType(32), 1), name="next_idx") + Gen._store(NextIdx, IdxVal) + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + def _HandleForStrLlvm(self, Node: ast.For, StrVal: ir.Value) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if not isinstance(Node.target, ast.Name): + return + TargetName: str = Node.target.id + Gen._UnregisterTempPtr(StrVal) + PtrVal: ir.AllocaInstr = Gen.builder.alloca(ir.IntType(8).as_pointer(), name=f"str_ptr_copy") + Gen.builder.store(StrVal, PtrVal) + CharType: ir.IntType = ir.IntType(8) + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + LoopVar: ir.AllocaInstr = Gen._allocaEntry(CharType, name=TargetName) + Gen.variables[TargetName] = LoopVar + Gen._store(ir.Constant(CharType, 0), LoopVar) + CondBB: ir.Block = Gen.func.append_basic_block(name="strfor.cond") + BodyBB: ir.Block = Gen.func.append_basic_block(name="strfor.body") + StepBB: ir.Block = Gen.func.append_basic_block(name="strfor.step") + ElseBB: ir.Block | None = Gen.func.append_basic_block(name="strfor.else") if Node.orelse else None + AfterBB: ir.Block = Gen.func.append_basic_block(name="strfor.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(StepBB) + Gen.builder.branch(CondBB) + Gen.builder.position_at_start(CondBB) + CurrentPtr: ir.Value = Gen._load(PtrVal, name="current_ptr") + RawChar: ir.Value = Gen._load(CurrentPtr, name="raw_char") + NullCond: ir.Value = Gen.builder.icmp_signed('==', RawChar, ir.Constant(CharType, 0), name="is_null") + Gen.builder.cbranch(NullCond, ElseBB if ElseBB else AfterBB, BodyBB) + Gen.builder.position_at_start(BodyBB) + Gen._store(RawChar, LoopVar) + Gen._record_var_signedness(TargetName, 'char') + Gen._reg_values[TargetName] = RawChar + self.HandleBodyLlvm(Node.body) + if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is RawChar: + del Gen._reg_values[TargetName] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(StepBB) + Gen.builder.position_at_start(StepBB) + CurrentPtr2: ir.Value = Gen._load(PtrVal, name="current_ptr2") + NextPtr: ir.Value = Gen.builder.gep(CurrentPtr2, [ir.Constant(ir.IntType(32), 1)], name="next_ptr") + Gen._store(NextPtr, PtrVal) + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + def _HandleForPtrLlvm(self, Node: ast.For, PtrVal: ir.Value, ElemType: ir.IntType) -> None: + """通用指针迭代:按 ElemType 大小逐元素迭代,终止条件为元素值 == 0 + + 适用于 for i in c.Addr(u) where u: i32/i64 等非 i8 整数类型。 + """ + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if not isinstance(Node.target, ast.Name): + return + TargetName: str = Node.target.id + # 确保 PtrVal 是 ElemType* + TypedPtr: ir.Value = PtrVal + if isinstance(PtrVal.type, ir.PointerType) and PtrVal.type.pointee is not ElemType: + TypedPtr = Gen.builder.bitcast(PtrVal, ir.PointerType(ElemType), name="ptr_elem_cast") + Gen._UnregisterTempPtr(TypedPtr) + # 分配指针副本 + PtrCopy: ir.AllocaInstr = Gen.builder.alloca(ir.PointerType(ElemType), name="ptr_copy") + Gen.builder.store(TypedPtr, PtrCopy) + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + LoopVar: ir.AllocaInstr = Gen._allocaEntry(ElemType, name=TargetName) + Gen.variables[TargetName] = LoopVar + Gen._store(ir.Constant(ElemType, 0), LoopVar) + CondBB: ir.Block = Gen.func.append_basic_block(name="ptrfor.cond") + BodyBB: ir.Block = Gen.func.append_basic_block(name="ptrfor.body") + StepBB: ir.Block = Gen.func.append_basic_block(name="ptrfor.step") + ElseBB: ir.Block | None = Gen.func.append_basic_block(name="ptrfor.else") if Node.orelse else None + AfterBB: ir.Block = Gen.func.append_basic_block(name="ptrfor.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(StepBB) + Gen.builder.branch(CondBB) + Gen.builder.position_at_start(CondBB) + CurrentPtr: ir.Value = Gen._load(PtrCopy, name="current_ptr") + RawElem: ir.Value = Gen._load(CurrentPtr, name="raw_elem") + NullCond: ir.Value = Gen.builder.icmp_signed('==', RawElem, ir.Constant(ElemType, 0), name="is_null") + Gen.builder.cbranch(NullCond, ElseBB if ElseBB else AfterBB, BodyBB) + Gen.builder.position_at_start(BodyBB) + Gen._store(RawElem, LoopVar) + Gen._record_var_signedness(TargetName, 'int') + Gen._reg_values[TargetName] = RawElem + self.HandleBodyLlvm(Node.body) + if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is RawElem: + del Gen._reg_values[TargetName] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(StepBB) + Gen.builder.position_at_start(StepBB) + CurrentPtr2: ir.Value = Gen._load(PtrCopy, name="current_ptr2") + NextPtr: ir.Value = Gen.builder.gep(CurrentPtr2, [ir.Constant(ir.IntType(32), 1)], name="next_ptr") + Gen._store(NextPtr, PtrCopy) + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + def _HandleForIterLlvm(self, Node: ast.For, ClassName: str) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if not isinstance(Node.target, ast.Name): + return + TargetName: str = Node.target.id + IterVal: ir.Value | None = self.HandleExprLlvm(Node.iter) + if not IterVal: + return + Gen._UnregisterTempPtr(IterVal) + if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8: + IterVal = Gen.builder.bitcast(IterVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + IterCall: ir.Function = Gen._get_function(f'{ClassName}.__iter__') + IterResult: ir.Value = Gen.builder.call(IterCall, [IterVal], name=f"call_{ClassName}.__iter__") + Gen._UnregisterTempPtr(IterResult) + if isinstance(IterResult.type, ir.PointerType) and isinstance(IterResult.type.pointee, ir.IntType) and IterResult.type.pointee.width == 8: + IterResult = Gen.builder.bitcast(IterResult, ir.PointerType(Gen.structs[ClassName]), name=f"cast_iter_{ClassName}") + NextCall: ir.Function = Gen._get_function(f'{ClassName}.__next__') + StopFlagPtr: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(1), name="stop_iter_flag") + Gen.builder.store(ir.Constant(ir.IntType(1), 0), StopFlagPtr) + NextReturnType: ir.Type = NextCall.function_type.return_type + if TargetName in Gen._reg_values: + del Gen._reg_values[TargetName] + LoopVar: ir.AllocaInstr = Gen._allocaEntry(NextReturnType, name=TargetName) + Gen.variables[TargetName] = LoopVar + CondBB: ir.Block = Gen.func.append_basic_block(name="iter.cond") + BodyBB: ir.Block = Gen.func.append_basic_block(name="iter.body") + StepBB: ir.Block = Gen.func.append_basic_block(name="iter.step") + ElseBB: ir.Block | None = Gen.func.append_basic_block(name="iter.else") if Node.orelse else None + AfterBB: ir.Block = Gen.func.append_basic_block(name="iter.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(StepBB) + Gen.builder.branch(CondBB) + Gen.builder.position_at_start(CondBB) + Gen.builder.store(ir.Constant(ir.IntType(1), 0), StopFlagPtr) + NextCallArgs: list[ir.Value] = [IterResult, StopFlagPtr] + if NextCall and len(NextCall.function_type.args) > len(NextCallArgs): + last_param_type: ir.Type = NextCall.function_type.args[-1] + if (isinstance(last_param_type, ir.PointerType) + and isinstance(last_param_type.pointee, ir.PointerType) + and isinstance(last_param_type.pointee.pointee, ir.IntType) + and last_param_type.pointee.pointee.width == 8): + null_msg: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_msg_out_null") + NextCallArgs.append(null_msg) + NextVal: ir.Value = Gen.builder.call(NextCall, NextCallArgs, name=f"call_{ClassName}.__next__") + StopFlag: ir.Value = Gen.builder.load(StopFlagPtr, name="stop_flag") + Cond: ir.Value = Gen.builder.icmp_signed('==', StopFlag, ir.Constant(ir.IntType(1), 0), name="iter_cond") + Gen.builder.cbranch(Cond, BodyBB, ElseBB if ElseBB else AfterBB) + Gen.builder.position_at_start(BodyBB) + Gen._store(NextVal, LoopVar) + Gen._reg_values[TargetName] = NextVal + self.HandleBodyLlvm(Node.body) + if TargetName in Gen._reg_values and Gen._reg_values[TargetName] is NextVal: + del Gen._reg_values[TargetName] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(StepBB) + Gen.builder.position_at_start(StepBB) + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + # ===== zip() 内置支持 ===== + + def _HandleForZipLlvm(self, Node: ast.For) -> None: + """for a, b in zip(iter1, iter2): — 多迭代器并行迭代 + + 兼容 range、__iter__/__next__、字符串、数组、指针等所有迭代类型。 + 任一迭代器停止则退出循环。 + """ + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if not isinstance(Node.target, ast.Tuple): + return + Targets: list[ast.Name] = [t for t in Node.target.elts if isinstance(t, ast.Name)] + ZipArgs: list[ast.expr] = Node.iter.args + if len(Targets) != len(ZipArgs) or len(Targets) < 2: + return + + # 为每个可迭代对象设置迭代状态 + IterInfos: list[dict] = [] + for i, arg in enumerate(ZipArgs): + target_name: str = Targets[i].id + info: dict | None = self._zip_setup_iter(arg, target_name, Gen) + if info is None: + return + IterInfos.append(info) + + CondBB: ir.Block = Gen.func.append_basic_block(name="zip.cond") + BodyBB: ir.Block = Gen.func.append_basic_block(name="zip.body") + StepBB: ir.Block = Gen.func.append_basic_block(name="zip.step") + ElseBB: ir.Block | None = Gen.func.append_basic_block(name="zip.else") if Node.orelse else None + AfterBB: ir.Block = Gen.func.append_basic_block(name="zip.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(StepBB) + Gen.builder.branch(CondBB) + + # Cond 块:为每个迭代器获取下一个值和停止条件 + Gen.builder.position_at_start(CondBB) + AnyStopped: ir.Value | None = None + for info in IterInfos: + val: ir.Value + stopped: ir.Value + val, stopped = self._zip_get_next(info, Gen) + info['last_value'] = val + if AnyStopped is None: + AnyStopped = stopped + else: + AnyStopped = Gen.builder.or_(AnyStopped, stopped, name="zip_any_stop") + Gen.builder.cbranch(AnyStopped, ElseBB if ElseBB else AfterBB, BodyBB) + + # Body 块:赋值并执行循环体 + Gen.builder.position_at_start(BodyBB) + for info in IterInfos: + Gen._store(info['last_value'], info['loop_var']) + Gen._reg_values[info['target_name']] = info['last_value'] + self.HandleBodyLlvm(Node.body) + for info in IterInfos: + tn: str = info['target_name'] + if tn in Gen._reg_values and Gen._reg_values[tn] is info['last_value']: + del Gen._reg_values[tn] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(StepBB) + + # Step 块:跳回 Cond(推进已在 Cond 中完成) + Gen.builder.position_at_start(StepBB) + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + def _zip_setup_iter(self, arg: ast.expr, target_name: str, Gen: "Translator.LlvmGen") -> dict | None: + """为 zip 参数设置迭代状态,返回包含迭代信息的 dict。""" + if target_name in Gen._reg_values: + del Gen._reg_values[target_name] + + # Case 1: range(n) / range(start, end) / range(start, end, step) + if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Name) and arg.func.id == 'range': + return self._zip_setup_range(arg, target_name, Gen) + + # Case 2: c.Addr(x) — 指针/数组迭代 + if (isinstance(arg, ast.Call) + and isinstance(arg.func, ast.Attribute) + and isinstance(arg.func.value, ast.Name) + and arg.func.value.id == 'c' + and arg.func.attr == 'Addr' + and arg.args): + AddrArg: ast.expr = arg.args[0] + if isinstance(AddrArg, ast.Name) and AddrArg.id in Gen.variables: + _var_ptr: ir.Value | None = Gen.variables[AddrArg.id] + if _var_ptr is not None and isinstance(_var_ptr.type, ir.PointerType): + _pointee: ir.Type = _var_ptr.type.pointee + if isinstance(_pointee, ir.IntType): + if _pointee.width == 8: + return self._zip_setup_str(_var_ptr, target_name, Gen) + return self._zip_setup_ptr(_var_ptr, target_name, _pointee, Gen) + if isinstance(_pointee, ir.ArrayType) and isinstance(_pointee.element, ir.IntType): + _elem_type: ir.IntType = _pointee.element + if _elem_type.width == 8: + return self._zip_setup_str(_var_ptr, target_name, Gen) + _typed_ptr: ir.Value = Gen.builder.bitcast(_var_ptr, ir.PointerType(_elem_type), name="zip_addr_cast") + return self._zip_setup_ptr(_typed_ptr, target_name, _elem_type, Gen) + + # Case 3: __iter__/__next__ 类迭代 + IterClassName: str | None = self.Trans.ExprHandler._get_var_class(arg, Gen) + if not IterClassName and isinstance(arg, ast.Call) and isinstance(arg.func, ast.Name): + IterClassName = arg.func.id + if IterClassName not in Gen.structs: + IterClassName = None + if IterClassName and Gen._has_function(f'{IterClassName}.__iter__') and Gen._has_function(f'{IterClassName}.__next__'): + return self._zip_setup_iter_class(arg, target_name, IterClassName, Gen) + + # Case 4-6: 求值表达式后按类型分发 + IterVal: ir.Value | None = self.HandleExprLlvm(arg) + if not IterVal: + return None + # 回退:通过 LLVM 类型查找结构体类名,检测 __iter__/__next__ + if not IterClassName and isinstance(IterVal.type, ir.PointerType): + _pointee: ir.Type = IterVal.type.pointee + if isinstance(_pointee, (ir.IdentifiedStructType, ir.LiteralStructType)): + _found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(_pointee) + if _found: + _cn: str = _found[0] + if not (Gen._has_function(f'{_cn}.__iter__') and Gen._has_function(f'{_cn}.__next__')): + self.Trans.ImportHandler._TryLoadFuncDeclsFromOutputStub(_cn, Gen) + if Gen._has_function(f'{_cn}.__iter__') and Gen._has_function(f'{_cn}.__next__'): + Gen._UnregisterTempPtr(IterVal) + return self._zip_setup_iter_class_from_val(IterVal, target_name, _cn, Gen) + if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8: + return self._zip_setup_str(IterVal, target_name, Gen) + if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.ArrayType): + return self._zip_setup_array(IterVal, target_name, Gen) + # Case 6: 整数计数器 + return self._zip_setup_int(IterVal, target_name, Gen) + + def _zip_setup_range(self, arg: ast.Call, target_name: str, Gen: "Translator.LlvmGen") -> dict | None: + RangeArgs: list[ast.expr] = arg.args + if len(RangeArgs) == 1: + StartVal: ir.Value = ir.Constant(ir.IntType(32), 0) + EndVal: ir.Value = self.HandleExprLlvm(RangeArgs[0]) + StepVal: ir.Value = ir.Constant(ir.IntType(32), 1) + elif len(RangeArgs) == 2: + StartVal = self.HandleExprLlvm(RangeArgs[0]) + EndVal = self.HandleExprLlvm(RangeArgs[1]) + StepVal = ir.Constant(ir.IntType(32), 1) + elif len(RangeArgs) >= 3: + StartVal = self.HandleExprLlvm(RangeArgs[0]) + EndVal = self.HandleExprLlvm(RangeArgs[1]) + StepVal = self.HandleExprLlvm(RangeArgs[2]) + else: + return None + if not EndVal: + return None + if not isinstance(EndVal.type, ir.IntType): + if isinstance(EndVal.type, ir.PointerType) and isinstance(EndVal.type.pointee, ir.IntType): + EndVal = Gen._load(EndVal, name="zip_end") + else: + EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="zip_end") + if not isinstance(StartVal.type, ir.IntType): + StartVal = ir.Constant(EndVal.type, 0) + if isinstance(StartVal.type, ir.IntType) and isinstance(EndVal.type, ir.IntType): + if StartVal.type.width < EndVal.type.width: + StartVal = Gen.builder.zext(StartVal, EndVal.type, name="zip_start_zext") + elif StartVal.type.width > EndVal.type.width: + EndVal = Gen.builder.zext(EndVal, StartVal.type, name="zip_end_zext") + if isinstance(StepVal.type, ir.IntType) and isinstance(EndVal.type, ir.IntType): + if StepVal.type.width < EndVal.type.width: + StepVal = Gen.builder.zext(StepVal, EndVal.type, name="zip_step_zext") + IdxVar: ir.AllocaInstr = Gen._allocaEntry(EndVal.type, name=f"zip_{target_name}_idx") + Gen._store(StartVal, IdxVar) + LoopVar: ir.AllocaInstr = Gen._allocaEntry(EndVal.type, name=target_name) + Gen.variables[target_name] = LoopVar + Gen._store(StartVal, LoopVar) + Gen._record_var_signedness(target_name, 'int') + return { + 'iter_type': 'range', + 'target_name': target_name, + 'value_type': EndVal.type, + 'idx_var': IdxVar, + 'end_val': EndVal, + 'step_val': StepVal, + 'loop_var': LoopVar, + } + + def _zip_setup_iter_class(self, arg: ast.expr, target_name: str, ClassName: str, Gen: "Translator.LlvmGen") -> dict | None: + IterVal: ir.Value | None = self.HandleExprLlvm(arg) + if not IterVal: + return None + return self._zip_setup_iter_class_from_val(IterVal, target_name, ClassName, Gen) + + def _zip_setup_iter_class_from_val(self, IterVal: ir.Value, target_name: str, ClassName: str, Gen: "Translator.LlvmGen") -> dict | None: + Gen._UnregisterTempPtr(IterVal) + if isinstance(IterVal.type, ir.PointerType) and isinstance(IterVal.type.pointee, ir.IntType) and IterVal.type.pointee.width == 8: + IterVal = Gen.builder.bitcast(IterVal, ir.PointerType(Gen.structs[ClassName]), name=f"zip_cast_{ClassName}") + IterCall: ir.Function = Gen._get_function(f'{ClassName}.__iter__') + IterResult: ir.Value = Gen.builder.call(IterCall, [IterVal], name=f"zip_call_{ClassName}.__iter__") + Gen._UnregisterTempPtr(IterResult) + if isinstance(IterResult.type, ir.PointerType) and isinstance(IterResult.type.pointee, ir.IntType) and IterResult.type.pointee.width == 8: + IterResult = Gen.builder.bitcast(IterResult, ir.PointerType(Gen.structs[ClassName]), name=f"zip_cast_iter_{ClassName}") + NextCall: ir.Function = Gen._get_function(f'{ClassName}.__next__') + StopFlagPtr: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(1), name=f"zip_stop_{target_name}") + Gen.builder.store(ir.Constant(ir.IntType(1), 0), StopFlagPtr) + NextReturnType: ir.Type = NextCall.function_type.return_type + LoopVar: ir.AllocaInstr = Gen._allocaEntry(NextReturnType, name=target_name) + Gen.variables[target_name] = LoopVar + return { + 'iter_type': 'iter', + 'target_name': target_name, + 'value_type': NextReturnType, + 'iter_obj': IterResult, + 'next_call': NextCall, + 'stop_flag': StopFlagPtr, + 'loop_var': LoopVar, + } + + def _zip_setup_str(self, StrVal: ir.Value, target_name: str, Gen: "Translator.LlvmGen") -> dict: + Gen._UnregisterTempPtr(StrVal) + PtrVal: ir.AllocaInstr = Gen.builder.alloca(ir.IntType(8).as_pointer(), name=f"zip_{target_name}_ptr") + Gen.builder.store(StrVal, PtrVal) + CharType: ir.IntType = ir.IntType(8) + LoopVar: ir.AllocaInstr = Gen._allocaEntry(CharType, name=target_name) + Gen.variables[target_name] = LoopVar + Gen._store(ir.Constant(CharType, 0), LoopVar) + Gen._record_var_signedness(target_name, 'char') + return { + 'iter_type': 'str', + 'target_name': target_name, + 'value_type': CharType, + 'ptr_var': PtrVal, + 'loop_var': LoopVar, + } + + def _zip_setup_array(self, ArrPtr: ir.Value, target_name: str, Gen: "Translator.LlvmGen") -> dict: + ElemType: ir.Type = ArrPtr.type.pointee.element + ArrayCount: int = ArrPtr.type.pointee.count + IdxVar: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name=f"zip_{target_name}_idx") + Gen.builder.store(ir.Constant(ir.IntType(32), 0), IdxVar) + LoopVar: ir.AllocaInstr = Gen._allocaEntry(ElemType, name=target_name) + Gen.variables[target_name] = LoopVar + Gen._store(ir.Constant(ElemType, None), LoopVar) + Gen._record_var_signedness(target_name, 'ptr') + return { + 'iter_type': 'array', + 'target_name': target_name, + 'value_type': ElemType, + 'arr_ptr': ArrPtr, + 'idx_var': IdxVar, + 'count_val': ir.Constant(ir.IntType(32), ArrayCount), + 'loop_var': LoopVar, + } + + def _zip_setup_ptr(self, PtrVal: ir.Value, target_name: str, ElemType: ir.IntType, Gen: "Translator.LlvmGen") -> dict: + TypedPtr: ir.Value = PtrVal + if isinstance(PtrVal.type, ir.PointerType) and PtrVal.type.pointee is not ElemType: + TypedPtr = Gen.builder.bitcast(PtrVal, ir.PointerType(ElemType), name="zip_ptr_cast") + Gen._UnregisterTempPtr(TypedPtr) + PtrCopy: ir.AllocaInstr = Gen.builder.alloca(ir.PointerType(ElemType), name=f"zip_{target_name}_ptr") + Gen.builder.store(TypedPtr, PtrCopy) + LoopVar: ir.AllocaInstr = Gen._allocaEntry(ElemType, name=target_name) + Gen.variables[target_name] = LoopVar + Gen._store(ir.Constant(ElemType, 0), LoopVar) + Gen._record_var_signedness(target_name, 'int') + return { + 'iter_type': 'ptr', + 'target_name': target_name, + 'value_type': ElemType, + 'ptr_var': PtrCopy, + 'loop_var': LoopVar, + } + + def _zip_setup_int(self, IterVal: ir.Value, target_name: str, Gen: "Translator.LlvmGen") -> dict: + EndVal: ir.Value = IterVal + if not isinstance(EndVal.type, ir.IntType): + EndVal = Gen.builder.ptrtoint(EndVal, ir.IntType(64), name="zip_int_end") + StartVal: ir.Value = ir.Constant(EndVal.type, 0) + StepVal: ir.Value = ir.Constant(EndVal.type, 1) + IdxVar: ir.AllocaInstr = Gen._allocaEntry(EndVal.type, name=f"zip_{target_name}_idx") + Gen._store(StartVal, IdxVar) + LoopVar: ir.AllocaInstr = Gen._allocaEntry(EndVal.type, name=target_name) + Gen.variables[target_name] = LoopVar + Gen._store(StartVal, LoopVar) + Gen._record_var_signedness(target_name, 'int') + return { + 'iter_type': 'range', + 'target_name': target_name, + 'value_type': EndVal.type, + 'idx_var': IdxVar, + 'end_val': EndVal, + 'step_val': StepVal, + 'loop_var': LoopVar, + } + + def _zip_get_next(self, info: dict, Gen: "Translator.LlvmGen") -> tuple[ir.Value, ir.Value]: + """生成获取下一个值和停止条件的 IR。返回 (value, stopped_cond)。""" + iter_type: str = info['iter_type'] + + if iter_type == 'range': + idx: ir.Value = Gen._load(info['idx_var'], name="zip_range_idx") + stopped: ir.Value = Gen.builder.icmp_signed('>=', idx, info['end_val'], name="zip_range_stop") + next_idx: ir.Value = Gen.builder.add(idx, info['step_val'], name="zip_range_next") + Gen._store(next_idx, info['idx_var']) + return idx, stopped + + if iter_type == 'iter': + Gen.builder.store(ir.Constant(ir.IntType(1), 0), info['stop_flag']) + args: list[ir.Value] = [info['iter_obj'], info['stop_flag']] + NextCall: ir.Function = info['next_call'] + if NextCall and len(NextCall.function_type.args) > len(args): + last_param_type: ir.Type = NextCall.function_type.args[-1] + if (isinstance(last_param_type, ir.PointerType) + and isinstance(last_param_type.pointee, ir.PointerType) + and isinstance(last_param_type.pointee.pointee, ir.IntType) + and last_param_type.pointee.pointee.width == 8): + null_msg: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="zip_eh_msg") + args.append(null_msg) + val: ir.Value = Gen.builder.call(NextCall, args, name="zip_iter_next") + stopped = Gen.builder.load(info['stop_flag'], name="zip_iter_stop") + return val, stopped + + if iter_type == 'str': + ptr: ir.Value = Gen._load(info['ptr_var'], name="zip_str_ptr") + val = Gen._load(ptr, name="zip_str_val") + stopped = Gen.builder.icmp_signed('==', val, ir.Constant(ir.IntType(8), 0), name="zip_str_stop") + next_ptr: ir.Value = Gen.builder.gep(ptr, [ir.Constant(ir.IntType(32), 1)], name="zip_str_next") + Gen._store(next_ptr, info['ptr_var']) + return val, stopped + + if iter_type == 'ptr': + ptr = Gen._load(info['ptr_var'], name="zip_ptr_cur") + val = Gen._load(ptr, name="zip_ptr_val") + elem_type: ir.IntType = info['value_type'] + stopped = Gen.builder.icmp_signed('==', val, ir.Constant(elem_type, 0), name="zip_ptr_stop") + next_ptr = Gen.builder.gep(ptr, [ir.Constant(ir.IntType(32), 1)], name="zip_ptr_next") + Gen._store(next_ptr, info['ptr_var']) + return val, stopped + + if iter_type == 'array': + idx = Gen._load(info['idx_var'], name="zip_arr_idx") + stopped = Gen.builder.icmp_signed('>=', idx, info['count_val'], name="zip_arr_stop") + elem_ptr: ir.Value = Gen.builder.gep(info['arr_ptr'], [ir.Constant(ir.IntType(32), 0), idx], name="zip_arr_elem") + val = Gen._load(elem_ptr, name="zip_arr_val") + next_idx = Gen.builder.add(idx, ir.Constant(ir.IntType(32), 1), name="zip_arr_next") + Gen._store(next_idx, info['idx_var']) + return val, stopped + + # 回退:立即停止 + return ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(1), 1) + + # ===== enumerate() 内置支持 ===== + + def _HandleForEnumerateLlvm(self, Node: ast.For) -> None: + """for idx, val in enumerate(iterable): — 带索引迭代 + + 等价于 zip(range(0, ∞), iterable),但无需 len()。 + idx 从 0 开始,每次迭代 +1。 + """ + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if not isinstance(Node.target, ast.Tuple): + return + Targets: list[ast.Name] = [t for t in Node.target.elts if isinstance(t, ast.Name)] + if len(Targets) != 2: + return + IdxTargetName: str = Targets[0].id + ValTargetName: str = Targets[1].id + IterArg: ast.expr = Node.iter.args[0] + + # 设置内部可迭代对象(复用 zip 基础设施) + if ValTargetName in Gen._reg_values: + del Gen._reg_values[ValTargetName] + if IdxTargetName in Gen._reg_values: + del Gen._reg_values[IdxTargetName] + IterInfo: dict | None = self._zip_setup_iter(IterArg, ValTargetName, Gen) + if IterInfo is None: + return + + # 索引计数器(i32,从 0 开始) + IdxType: ir.IntType = ir.IntType(32) + IdxVar: ir.AllocaInstr = Gen._allocaEntry(IdxType, name=f"enum_{IdxTargetName}") + Gen._store(ir.Constant(IdxType, 0), IdxVar) + IdxLoopVar: ir.AllocaInstr = Gen._allocaEntry(IdxType, name=IdxTargetName) + Gen.variables[IdxTargetName] = IdxLoopVar + Gen._store(ir.Constant(IdxType, 0), IdxLoopVar) + Gen._record_var_signedness(IdxTargetName, 'int') + + CondBB: ir.Block = Gen.func.append_basic_block(name="enum.cond") + BodyBB: ir.Block = Gen.func.append_basic_block(name="enum.body") + StepBB: ir.Block = Gen.func.append_basic_block(name="enum.step") + ElseBB: ir.Block | None = Gen.func.append_basic_block(name="enum.else") if Node.orelse else None + AfterBB: ir.Block = Gen.func.append_basic_block(name="enum.end") + Gen.loop_break_targets.append(AfterBB) + Gen.loop_continue_targets.append(StepBB) + Gen.builder.branch(CondBB) + + # Cond 块:获取下一个值和停止条件 + Gen.builder.position_at_start(CondBB) + CurIdx: ir.Value = Gen._load(IdxVar, name="enum_idx") + Val, Stopped = self._zip_get_next(IterInfo, Gen) + IterInfo['last_value'] = Val + Gen.builder.cbranch(Stopped, ElseBB if ElseBB else AfterBB, BodyBB) + + # Body 块:赋值并执行循环体 + Gen.builder.position_at_start(BodyBB) + Gen._store(CurIdx, IdxLoopVar) + Gen._store(Val, IterInfo['loop_var']) + Gen._reg_values[IdxTargetName] = CurIdx + Gen._reg_values[ValTargetName] = Val + self.HandleBodyLlvm(Node.body) + if IdxTargetName in Gen._reg_values and Gen._reg_values[IdxTargetName] is CurIdx: + del Gen._reg_values[IdxTargetName] + if ValTargetName in Gen._reg_values and Gen._reg_values[ValTargetName] is Val: + del Gen._reg_values[ValTargetName] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(StepBB) + + # Step 块:索引 +1,跳回 Cond + Gen.builder.position_at_start(StepBB) + CurIdx2: ir.Value = Gen._load(IdxVar, name="enum_idx2") + NextIdx: ir.Value = Gen.builder.add(CurIdx2, ir.Constant(IdxType, 1), name="enum_next") + Gen._store(NextIdx, IdxVar) + Gen.builder.branch(CondBB) + Gen.loop_break_targets.pop() + Gen.loop_continue_targets.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) Gen.builder.position_at_start(AfterBB) \ No newline at end of file diff --git a/lib/core/Handles/HandlesFunctions.py b/lib/core/Handles/HandlesFunctions.py index 2f4127a..42de018 100644 --- a/lib/core/Handles/HandlesFunctions.py +++ b/lib/core/Handles/HandlesFunctions.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.LlvmCodeGenerator import LlvmCodeGenerator -import ast +import vast as ast import copy import traceback import llvmlite.ir as ir @@ -1757,8 +1757,8 @@ class FunctionHandle(BaseHandle): Gen.builder.store(last_param_ptr, last_param_alloc) Gen.emit_va_start(va_list_ptr) Gen._variadic_info['va_start_called'] = True - # 用 _direct_values 注册,Name 解析时直接返回 va_list 指针(i8*), - # 不走 variables 的 load 路径(否则会把 i8* 当 char* 加载一个字节) + # 用 _direct_values 注册,Name 解析时直接返回 va_list 指针(i8*), + # 不走 variables 的 load 路径(否则会把 i8* 当 char* 加载一个字节) Gen._direct_values[vararg_name] = va_list_ptr # @t.TLS 一次性初始化检查:首次调用执行函数体,后续调用直接返回 if is_tls_func: @@ -1790,18 +1790,18 @@ class FunctionHandle(BaseHandle): Gen.builder.ret(ir.Constant(ActualReturnType, None)) Gen.builder.position_at_end(cont_bb) Gen.builder.store(ir.Constant(ir.IntType(1), 1), flag_global) - _saved_class_name = getattr(Gen, '_current_class_name', None) - Gen._current_class_name = ClassName - # 提取首个裸字符串字面量作为 __doc__ docstring,并跳过该节点避免生成死代码 - func_body: list[ast.stmt] = Node.body - doc_symbol: str = f"{ClassName}.{Node.name}" if ClassName else Node.name - if (func_body and isinstance(func_body[0], ast.Expr) - and isinstance(func_body[0].value, ast.Constant) - and isinstance(func_body[0].value.value, str)): - Gen._create_doc_global(doc_symbol, func_body[0].value.value) - func_body = func_body[1:] - else: - Gen._create_doc_global(doc_symbol, None) + _saved_class_name = getattr(Gen, '_current_class_name', None) + Gen._current_class_name = ClassName + # 提取首个裸字符串字面量作为 __doc__ docstring,并跳过该节点避免生成死代码 + func_body: list[ast.stmt] = Node.body + doc_symbol: str = f"{ClassName}.{Node.name}" if ClassName else Node.name + if (func_body and isinstance(func_body[0], ast.Expr) + and isinstance(func_body[0].value, ast.Constant) + and isinstance(func_body[0].value.value, str)): + Gen._create_doc_global(doc_symbol, func_body[0].value.value) + func_body = func_body[1:] + else: + Gen._create_doc_global(doc_symbol, None) try: self.Trans.BodyHandler.HandleBodyLlvm(func_body) except Exception as _body_exc: diff --git a/lib/core/Handles/HandlesIf.py b/lib/core/Handles/HandlesIf.py index f3f577e..42d4a3c 100644 --- a/lib/core/Handles/HandlesIf.py +++ b/lib/core/Handles/HandlesIf.py @@ -1,214 +1,214 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -import ast -import llvmlite.ir as ir -from lib.core.Handles.HandlesBase import BaseHandle -from lib.core.ConstEvaluator import ConstEvaluator, EvalContext - - -class IfHandle(BaseHandle): - def _get_attr_full_name(self, node: ast.expr) -> str | None: - if isinstance(node, ast.Attribute): - parts: list[str] = [] - cur: ast.expr = node - while isinstance(cur, ast.Attribute): - parts.append(cur.attr) - cur = cur.value - if isinstance(cur, ast.Name): - parts.append(cur.id) - parts.reverse() - return '.'.join(parts) - return None - - def _is_cif_call(self, node: ast.expr) -> bool: - if isinstance(node, ast.Call): - if isinstance(node.func, ast.Attribute): - if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': - return node.func.attr in ('CIf', 'CIfdef', 'CIfndef') - if isinstance(node.func, ast.Name): - return node.func.id in ('CIf', 'CIfdef', 'CIfndef') - return False - - def _resolve_macro_name(self, arg: ast.expr) -> str | None: - if isinstance(arg, ast.Name): - return arg.id - if isinstance(arg, ast.Constant) and isinstance(arg.value, str): - return arg.value - if isinstance(arg, ast.Attribute): - full_name: str | None = self._get_attr_full_name(arg) - if full_name: - return full_name - return None - - def _evaluate_cif_condition(self, node: ast.Call) -> int | None: - if not isinstance(node, ast.Call): - return None - args: list[ast.expr] = node.args - if not args: - return 0 - kind: str | None = None - if isinstance(node.func, ast.Attribute): - kind = node.func.attr - elif isinstance(node.func, ast.Name): - kind = node.func.id - else: - return None - if kind == 'CIfdef': - name: str | None = self._resolve_macro_name(args[0]) - if name is None: - return 0 - return 1 if self._is_macro_defined(name) else 0 - elif kind == 'CIfndef': - name: str | None = self._resolve_macro_name(args[0]) - if name is None: - return 1 - return 0 if self._is_macro_defined(name) else 1 - elif kind == 'CIf': - return self._eval_const_expr(args[0]) - return None - - def _is_macro_defined(self, name: str) -> bool: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if hasattr(Gen, '_define_constants') and name in Gen._define_constants: - return True - if self.Trans.SymbolTable.is_define(name): - return True - platform_macros: dict[str, int] = self._get_platform_macros() - return name in platform_macros - - def _get_macro_value(self, name: str) -> int | float | None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if hasattr(Gen, '_define_constants') and name in Gen._define_constants: - val: int | float | None = Gen._define_constants[name] - # 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 覆盖 - try: - if hasattr(Gen, 'module') and name in Gen.module.globals: - _gv: Any = Gen.module.globals[name] - if getattr(_gv, 'initializer', None) is not None: - _iv: Any = _gv.initializer - if hasattr(_iv, 'constant') and isinstance(_iv.constant, (int, float)): - val = _iv.constant - except Exception: - pass - if isinstance(val, (int, float)): - return val - info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(name) - if info: - if info.IsDefine: - val: int | float | None = info.DefineValue - if isinstance(val, (int, float)): - return val - platform_macros: dict[str, int] = self._get_platform_macros() - if name in platform_macros: - return platform_macros[name] - return None - - def _get_platform_macros(self) -> dict[str, int]: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - macros: dict[str, int] = {} - pi: dict[str, object] = Gen._platform_info - ptr_size: int = getattr(Gen, 'ptr_size', 8) - # 根据目标平台设置宏(从三元组推导) - if pi.get('is_windows'): - macros['_WIN32'] = 1 - if not pi.get('is_32bit'): - macros['_WIN64'] = 1 - macros['WIN64'] = 1 - macros['WIN32'] = 1 - if pi.get('is_linux'): - macros['__linux__'] = 1 - if pi.get('is_macos'): - macros['__APPLE__'] = 1 - macros['__MACH__'] = 1 - if pi.get('is_x86_64'): - macros['__x86_64__'] = 1 - macros['__x86_64'] = 1 - macros['_M_X64'] = 1 - elif pi.get('is_arm64'): - macros['__aarch64__'] = 1 - macros['_M_ARM64'] = 1 - if not pi.get('is_32bit') and pi.get('is_linux'): - macros['__LP64__'] = 1 - elif pi.get('is_32bit'): - macros['_ILP32'] = 1 - macros['SIZEOF_VOID_P'] = ptr_size - macros['__SIZEOF_POINTER__'] = ptr_size - macros['NDEBUG'] = 0 - return macros - - def _eval_const_expr(self, node: ast.expr) -> int | None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans) - result: int | float | bool | None = ConstEvaluator.eval_full(node, ctx) - if result is None: - # 保留 CIf 嵌套调用处理(HandlesIf 特有逻辑) - if isinstance(node, ast.Call) and self._is_cif_call(node): - return self._evaluate_cif_condition(node) - return None - # HandlesIf 需要 bool/float → int 转换(#if 条件编译语义) - if isinstance(result, bool): - return 1 if result else 0 - if isinstance(result, float): - return 1 if result != 0.0 else 0 - return result - - def _HandleIfLlvm(self, Node: ast.If) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if self._is_cif_call(Node.test): - compile_time_val: int | None = self._evaluate_cif_condition(Node.test) - if compile_time_val is not None: - if compile_time_val: - self.Trans.BodyHandler.HandleBodyLlvm(Node.body) - elif Node.orelse: - if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If): - self._HandleIfLlvm(Node.orelse[0]) - else: - self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) - return - Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test) - if not Cond: - return - is_const: bool = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1 - if is_const: - if Cond.constant: - self.Trans.BodyHandler.HandleBodyLlvm(Node.body) - elif Node.orelse: - if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If): - self._HandleIfLlvm(Node.orelse[0]) - else: - self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) - return - if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1: - ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.test, Gen) - if ClassName and Gen._has_function(f'{ClassName}.__bool__'): - obj_val: ir.Value = Cond - if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: - obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") - Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__") - if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1: - Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="bool_result") - else: - if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)): - Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond") - else: - Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="ifcond") - ThenBB: ir.Block = Gen.func.append_basic_block(name="then") - ElseBB: ir.Block | None = Gen.func.append_basic_block(name="else") if Node.orelse else None - MergeBB: ir.Block = Gen.func.append_basic_block(name="endif") - if not Gen.builder.block.is_terminated: - Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB) - Gen.builder.position_at_start(ThenBB) - self.Trans.BodyHandler.HandleBodyLlvm(Node.body) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(MergeBB) - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(MergeBB) - if not MergeBB.is_terminated: - Gen.builder.position_at_start(MergeBB) - else: +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +import vast as ast +import llvmlite.ir as ir +from lib.core.Handles.HandlesBase import BaseHandle +from lib.core.ConstEvaluator import ConstEvaluator, EvalContext + + +class IfHandle(BaseHandle): + def _get_attr_full_name(self, node: ast.expr) -> str | None: + if isinstance(node, ast.Attribute): + parts: list[str] = [] + cur: ast.expr = node + while isinstance(cur, ast.Attribute): + parts.append(cur.attr) + cur = cur.value + if isinstance(cur, ast.Name): + parts.append(cur.id) + parts.reverse() + return '.'.join(parts) + return None + + def _is_cif_call(self, node: ast.expr) -> bool: + if isinstance(node, ast.Call): + if isinstance(node.func, ast.Attribute): + if isinstance(node.func.value, ast.Name) and node.func.value.id == 'c': + return node.func.attr in ('CIf', 'CIfdef', 'CIfndef') + if isinstance(node.func, ast.Name): + return node.func.id in ('CIf', 'CIfdef', 'CIfndef') + return False + + def _resolve_macro_name(self, arg: ast.expr) -> str | None: + if isinstance(arg, ast.Name): + return arg.id + if isinstance(arg, ast.Constant) and isinstance(arg.value, str): + return arg.value + if isinstance(arg, ast.Attribute): + full_name: str | None = self._get_attr_full_name(arg) + if full_name: + return full_name + return None + + def _evaluate_cif_condition(self, node: ast.Call) -> int | None: + if not isinstance(node, ast.Call): + return None + args: list[ast.expr] = node.args + if not args: + return 0 + kind: str | None = None + if isinstance(node.func, ast.Attribute): + kind = node.func.attr + elif isinstance(node.func, ast.Name): + kind = node.func.id + else: + return None + if kind == 'CIfdef': + name: str | None = self._resolve_macro_name(args[0]) + if name is None: + return 0 + return 1 if self._is_macro_defined(name) else 0 + elif kind == 'CIfndef': + name: str | None = self._resolve_macro_name(args[0]) + if name is None: + return 1 + return 0 if self._is_macro_defined(name) else 1 + elif kind == 'CIf': + return self._eval_const_expr(args[0]) + return None + + def _is_macro_defined(self, name: str) -> bool: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if hasattr(Gen, '_define_constants') and name in Gen._define_constants: + return True + if self.Trans.SymbolTable.is_define(name): + return True + platform_macros: dict[str, int] = self._get_platform_macros() + return name in platform_macros + + def _get_macro_value(self, name: str) -> int | float | None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if hasattr(Gen, '_define_constants') and name in Gen._define_constants: + val: int | float | None = Gen._define_constants[name] + # 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 覆盖 + try: + if hasattr(Gen, 'module') and name in Gen.module.globals: + _gv: Any = Gen.module.globals[name] + if getattr(_gv, 'initializer', None) is not None: + _iv: Any = _gv.initializer + if hasattr(_iv, 'constant') and isinstance(_iv.constant, (int, float)): + val = _iv.constant + except Exception: + pass + if isinstance(val, (int, float)): + return val + info: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(name) + if info: + if info.IsDefine: + val: int | float | None = info.DefineValue + if isinstance(val, (int, float)): + return val + platform_macros: dict[str, int] = self._get_platform_macros() + if name in platform_macros: + return platform_macros[name] + return None + + def _get_platform_macros(self) -> dict[str, int]: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + macros: dict[str, int] = {} + pi: dict[str, object] = Gen._platform_info + ptr_size: int = getattr(Gen, 'ptr_size', 8) + # 根据目标平台设置宏(从三元组推导) + if pi.get('is_windows'): + macros['_WIN32'] = 1 + if not pi.get('is_32bit'): + macros['_WIN64'] = 1 + macros['WIN64'] = 1 + macros['WIN32'] = 1 + if pi.get('is_linux'): + macros['__linux__'] = 1 + if pi.get('is_macos'): + macros['__APPLE__'] = 1 + macros['__MACH__'] = 1 + if pi.get('is_x86_64'): + macros['__x86_64__'] = 1 + macros['__x86_64'] = 1 + macros['_M_X64'] = 1 + elif pi.get('is_arm64'): + macros['__aarch64__'] = 1 + macros['_M_ARM64'] = 1 + if not pi.get('is_32bit') and pi.get('is_linux'): + macros['__LP64__'] = 1 + elif pi.get('is_32bit'): + macros['_ILP32'] = 1 + macros['SIZEOF_VOID_P'] = ptr_size + macros['__SIZEOF_POINTER__'] = ptr_size + macros['NDEBUG'] = 0 + return macros + + def _eval_const_expr(self, node: ast.expr) -> int | None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + ctx: EvalContext = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable, translator=self.Trans) + result: int | float | bool | None = ConstEvaluator.eval_full(node, ctx) + if result is None: + # 保留 CIf 嵌套调用处理(HandlesIf 特有逻辑) + if isinstance(node, ast.Call) and self._is_cif_call(node): + return self._evaluate_cif_condition(node) + return None + # HandlesIf 需要 bool/float → int 转换(#if 条件编译语义) + if isinstance(result, bool): + return 1 if result else 0 + if isinstance(result, float): + return 1 if result != 0.0 else 0 + return result + + def _HandleIfLlvm(self, Node: ast.If) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if self._is_cif_call(Node.test): + compile_time_val: int | None = self._evaluate_cif_condition(Node.test) + if compile_time_val is not None: + if compile_time_val: + self.Trans.BodyHandler.HandleBodyLlvm(Node.body) + elif Node.orelse: + if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If): + self._HandleIfLlvm(Node.orelse[0]) + else: + self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) + return + Cond: ir.Value | None = self.Trans.ExprHandler.HandleExprLlvm(Node.test) + if not Cond: + return + is_const: bool = isinstance(Cond, ir.Constant) and isinstance(Cond.type, ir.IntType) and Cond.type.width == 1 + if is_const: + if Cond.constant: + self.Trans.BodyHandler.HandleBodyLlvm(Node.body) + elif Node.orelse: + if isinstance(Node.orelse, list) and len(Node.orelse) == 1 and isinstance(Node.orelse[0], ast.If): + self._HandleIfLlvm(Node.orelse[0]) + else: + self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) + return + if not isinstance(Cond.type, ir.IntType) or Cond.type.width != 1: + ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.test, Gen) + if ClassName and Gen._has_function(f'{ClassName}.__bool__'): + obj_val: ir.Value = Cond + if isinstance(obj_val.type, ir.PointerType) and isinstance(obj_val.type.pointee, ir.IntType) and obj_val.type.pointee.width == 8: + obj_val = Gen.builder.bitcast(obj_val, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}") + Cond = Gen.builder.call(Gen._get_function(f'{ClassName}.__bool__'), [obj_val], name=f"call_{ClassName}.__bool__") + if isinstance(Cond.type, ir.IntType) and Cond.type.width != 1: + Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="bool_result") + else: + if isinstance(Cond.type, (ir.FloatType, ir.DoubleType)): + Cond = Gen.builder.fcmp_ordered('!=', Cond, ir.Constant(Cond.type, 0.0), name="ifcond") + else: + Cond = Gen.builder.icmp_signed('!=', Cond, Gen._ZeroConst(Cond.type), name="ifcond") + ThenBB: ir.Block = Gen.func.append_basic_block(name="then") + ElseBB: ir.Block | None = Gen.func.append_basic_block(name="else") if Node.orelse else None + MergeBB: ir.Block = Gen.func.append_basic_block(name="endif") + if not Gen.builder.block.is_terminated: + Gen.builder.cbranch(Cond, ThenBB, ElseBB if ElseBB else MergeBB) + Gen.builder.position_at_start(ThenBB) + self.Trans.BodyHandler.HandleBodyLlvm(Node.body) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(MergeBB) + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.Trans.BodyHandler.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(MergeBB) + if not MergeBB.is_terminated: + Gen.builder.position_at_start(MergeBB) + else: Gen.builder.position_at_end(MergeBB) \ No newline at end of file diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index 38eecc9..b341a0a 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -3,7 +3,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin -import ast +import vast as ast import inspect import os import re @@ -381,7 +381,7 @@ class ImportHandle(BaseHandle): # 治本修复:使用 file_module_name(源模块名)而非 module_name(可能是别名/类名)。 # 这样 _EmitExternalClassDeclLlvm 内的 ModuleSha1Map 查找才能命中, # _EmitExternalFuncDeclLlvm 才能拿到正确的 source_module_name → 正确的 struct sha1。 - # 注意:actual_module_name 保持原值(可能为 None),不回退到 module_name(可能是别名) + # 注意:actual_module_name 保持原值(可能为 None),不回退到 module_name(可能是别名) self._EmitExternalClassDeclLlvm(node, Gen, module_name=file_module_name, actual_module_name=actual_module_name) elif isinstance(node, ast.ImportFrom): if node.level > 0: diff --git a/lib/core/Handles/HandlesMatch.py b/lib/core/Handles/HandlesMatch.py index 5c9b482..a14e343 100644 --- a/lib/core/Handles/HandlesMatch.py +++ b/lib/core/Handles/HandlesMatch.py @@ -1,420 +1,420 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class MatchHandle(BaseHandle): - def _HandleMatchLlvm(self, Node: ast.Match) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject) - if not SubjectVal: - return - - IsRenumMatch: bool = False - RenumName: str | None = None - SubjectPtr: ir.Value | None = None - if isinstance(Node.subject, ast.Name): - VarName: str = Node.subject.id - TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName) - if TypeInfo and TypeInfo.IsRenum: - IsRenumMatch = True - RenumName = TypeInfo.Name - SubjectPtr = Gen._Load_var(VarName) - - if not IsRenumMatch: - for case in Node.cases: - if isinstance(case.pattern, ast.MatchClass): - cls_node: ast.expr = case.pattern.cls - VariantName: str | None = None - QualifiedName: str | None = None - if isinstance(cls_node, ast.Name): - VariantName = cls_node.id - elif isinstance(cls_node, ast.Attribute): - VariantName = cls_node.attr - # Extract enum name for qualified lookup to avoid collision - # with same-name factory functions (e.g. def Ptr vs LLVMType.Ptr) - if isinstance(cls_node.value, ast.Attribute): - QualifiedName = f"{cls_node.value.attr}.{VariantName}" - elif isinstance(cls_node.value, ast.Name): - QualifiedName = f"{cls_node.value.id}.{VariantName}" - if VariantName: - # Try qualified name first (e.g., "LLVMType.Ptr") to avoid - # collision with same-name functions (e.g., def Ptr(...)) - SymInfo: "SymbolTable.SymbolInfo" = None - if QualifiedName: - SymInfo = self.Trans.SymbolTable.lookup(QualifiedName) - if not (SymInfo and SymInfo.IsEnumMember): - SymInfo = self.Trans.SymbolTable.lookup(VariantName) - if SymInfo and SymInfo.IsEnumMember and SymInfo.EnumName: - EnumName: str = SymInfo.EnumName - EnumInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(EnumName) - if EnumInfo and EnumInfo.IsRenum: - IsRenumMatch = True - RenumName = EnumName - if SubjectPtr is None: - SubjectPtr = self.HandleExprLlvm(Node.subject) - break - - if IsRenumMatch and SubjectPtr: - self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr) - return - - if not isinstance(SubjectVal.type, ir.IntType): - try: - SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj") - SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32") - except Exception: # 回退:ptrtoint 失败时直接返回 - return - SwitchIntType: ir.IntType = SubjectVal.type - DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default") - AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end") - CaseBBs: list[ir.Block] = [] - CaseValues: list[ir.Value] = [] - HasDefault: bool = False - HasNoBreak: list[bool] = [] - for i, case in enumerate(Node.cases): - pattern: ast.pattern = case.pattern - if isinstance(pattern, ast.MatchValue): - Val: ir.Value | None = self.HandleExprLlvm(pattern.value) - if Val: - CaseVal: ir.Value - if isinstance(Val.type, ir.IntType): - if Val.type != SwitchIntType: - if Val.type.width > SwitchIntType.width: - CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) - else: - CaseVal = ir.Constant(SwitchIntType, Val.constant) - else: - CaseVal = Val - else: - try: - CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}") - except Exception: # 回退:ptrtoint 失败时设默认值 0 - CaseVal = ir.Constant(SwitchIntType, 0) - CaseValues.append(CaseVal) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - elif isinstance(pattern, ast.MatchOr): - for j, SubPattern in enumerate(pattern.patterns): - if isinstance(SubPattern, ast.MatchValue): - Val: ir.Value | None = self.HandleExprLlvm(SubPattern.value) - if Val: - CaseVal: ir.Value - if isinstance(Val.type, ir.IntType): - if Val.type != SwitchIntType: - if Val.type.width > SwitchIntType.width: - CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) - else: - CaseVal = ir.Constant(SwitchIntType, Val.constant) - else: - CaseVal = Val - else: - try: - CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}") - except Exception: # 回退:ptrtoint 失败时设默认值 0 - CaseVal = ir.Constant(SwitchIntType, 0) - CaseValues.append(CaseVal) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}")) - elif isinstance(pattern, ast.MatchSingleton): - if pattern.value is None: - CaseValues.append(ir.Constant(SwitchIntType, 0)) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - HasDefault = True - CaseBBs.append(DefaultBB) - elif isinstance(pattern, ast.MatchSequence): - HasDefault = True - CaseBBs.append(DefaultBB) - elif isinstance(pattern, ast.MatchClass): - # 兜底处理:REnum 检测失败但 case 是 MatchClass(REnum 变体模式) - # 尝试从变体名查找 tag 值,按整数值处理 - cls_node_mc: ast.expr = pattern.cls - VariantName_mc: str | None = None - QualifiedName_mc: str | None = None - if isinstance(cls_node_mc, ast.Name): - VariantName_mc = cls_node_mc.id - elif isinstance(cls_node_mc, ast.Attribute): - VariantName_mc = cls_node_mc.attr - if isinstance(cls_node_mc.value, ast.Attribute): - QualifiedName_mc = f"{cls_node_mc.value.attr}.{VariantName_mc}" - elif isinstance(cls_node_mc.value, ast.Name): - QualifiedName_mc = f"{cls_node_mc.value.id}.{VariantName_mc}" - TagValue_mc: int | None = None - SymInfo_mc: "SymbolTable.SymbolInfo" = None - if QualifiedName_mc: - SymInfo_mc = self.Trans.SymbolTable.lookup(QualifiedName_mc) - if not (SymInfo_mc and SymInfo_mc.IsEnumMember): - SymInfo_mc = self.Trans.SymbolTable.lookup(VariantName_mc) - if SymInfo_mc and SymInfo_mc.IsEnumMember: - TagValue_mc = SymInfo_mc.value - if TagValue_mc is not None: - CaseValues.append(ir.Constant(SwitchIntType, TagValue_mc)) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{VariantName_mc}")) - else: - # 变体名未找到,跳过此 case(fast-fail 已在外层处理) - pass - def _HasNoBreak(stmts: list[ast.stmt]) -> bool: - for stmt in stmts: - if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): - if isinstance(stmt.value.func, ast.Attribute): - if (isinstance(stmt.value.func.value, ast.Name) and - stmt.value.func.value.id == 'c' and - stmt.value.func.attr == 'NoBreak'): - return True - if getattr(stmt, 'body', None) and isinstance(stmt.body, list): - if _HasNoBreak(stmt.body): - return True - if getattr(stmt, 'orelse', None): - if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): - return True - return False - HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) - if not HasDefault: - CaseBBs.append(DefaultBB) - SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] - switch_instr: ir.SwitchInstr = Gen.builder.switch(SubjectVal, DefaultBB) - for val, bb in SwitchCases: - switch_instr.add_case(val, bb) - CaseIdx: int = 0 - for i, case in enumerate(Node.cases): - pattern: ast.pattern = case.pattern - if isinstance(pattern, ast.MatchOr): - NumSubCases: int = len(pattern.patterns) - for j in range(NumSubCases): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchSequence): - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchClass): - # 兜底处理:MatchClass 在非 REnum 路径的 case body 生成 - # case 收集阶段已创建 CaseBB,此处生成 body - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - if not HasDefault: - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) - elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - - def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType): - SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj") - # Bug fix: HandleExprLlvm 可能对 REnum 字段执行了 load,返回值而非指针。 - # 情况1: SubjectPtr 不是指针类型(如 IntType)→ alloca REnum 结构体 + store - # 情况2: SubjectPtr 是指针但 pointee 不是结构体(如 i32* 指向 __tag)→ bitcast - NeedAlloca: bool = not isinstance(SubjectPtr.type, ir.PointerType) - NeedBitcast: bool = (isinstance(SubjectPtr.type, ir.PointerType) and - not isinstance(SubjectPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))) - if NeedAlloca or NeedBitcast: - RenumStructType: Any = Gen.structs.get(RenumName) - if RenumStructType is None: - # 跨模块编译时 REnum 结构体可能尚未在 Gen.structs 中注册 - # (如 import llvmlite 后 LLVMType 仅在符号表,Gen.structs 无条目)。 - # 使用 _get_or_create_struct 按需创建(可能为 opaque)。 - RenumStructType = Gen._get_or_create_struct(RenumName) - if NeedAlloca: - AllocaPtr: ir.Value = Gen._allocaEntry(RenumStructType, name="match_subj_alloca") - CastedPtr: ir.Value = Gen.builder.bitcast(AllocaPtr, ir.PointerType(SubjectPtr.type), name="match_subj_cast") - Gen._store(SubjectPtr, CastedPtr) - SubjectPtr = AllocaPtr - else: - SubjectPtr = Gen.builder.bitcast(SubjectPtr, ir.PointerType(RenumStructType), name="match_subj_recast") - # REnum 布局为 { i32 __tag, },tag 在偏移 0。 - # 使用 bitcast 到 i32* 替代 gep [0,0],兼容 opaque 结构体 - # (跨模块编译时 REnum 结构体可能未 set_body,gep 会失败)。 - tag_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, ir.PointerType(ir.IntType(32)), name="match_tag_ptr") - TagVal: ir.Value = Gen._load(tag_ptr, name="match_tag_val") - DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default") - AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end") - CaseBBs: list[ir.Block] = [] - CaseValues: list[ir.Value] = [] - CaseBindings: list[list[tuple[str, str, ir.Type, int]]] = [] - HasDefault: bool = False - HasNoBreak: list[bool] = [] - for i, case in enumerate(Node.cases): - pattern: ast.pattern = case.pattern - bindings: list[tuple[str, str, ir.Type, int]] = [] - if isinstance(pattern, ast.MatchClass): - cls_node: ast.expr = pattern.cls - VariantName: str | None = None - QualifiedName: str | None = None - if isinstance(cls_node, ast.Name): - VariantName = cls_node.id - elif isinstance(cls_node, ast.Attribute): - VariantName = cls_node.attr - if isinstance(cls_node.value, ast.Attribute): - QualifiedName = f"{cls_node.value.attr}.{VariantName}" - elif isinstance(cls_node.value, ast.Name): - QualifiedName = f"{cls_node.value.id}.{VariantName}" - if VariantName: - TagValue: int | None = None - SymInfo: "SymbolTable.SymbolInfo" = None - if QualifiedName: - SymInfo = self.Trans.SymbolTable.lookup(QualifiedName) - if not (SymInfo and SymInfo.IsEnumMember): - SymInfo = self.Trans.SymbolTable.lookup(VariantName) - if SymInfo and SymInfo.IsEnumMember: - TagValue = SymInfo.value - if TagValue is not None: - CaseValues.append(ir.Constant(ir.IntType(32), TagValue)) - CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}") - CaseBBs.append(CaseBB) - NestedStructName: str = f"{RenumName}_{VariantName}" - if NestedStructName in Gen.structs: - members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, []) - payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag'] - for j, sub_pat in enumerate(pattern.patterns): - if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members): - bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j)) - CaseBindings.append(bindings) - else: - CaseValues.append(ir.Constant(ir.IntType(32), 0)) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - CaseBindings.append([]) - elif isinstance(pattern, ast.MatchValue): - Val: ir.Value | None = self.HandleExprLlvm(pattern.value) - if Val: - CaseVal: ir.Value - if isinstance(Val.type, ir.IntType): - CaseVal = Val - else: - try: - CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}") - except Exception: # 回退:ptrtoint 失败时设默认值 0 - CaseVal = ir.Constant(ir.IntType(32), 0) - CaseValues.append(CaseVal) - CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) - CaseBindings.append([]) - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - HasDefault = True - CaseBBs.append(DefaultBB) - CaseBindings.append([]) - elif isinstance(pattern, ast.MatchSequence): - HasDefault = True - CaseBBs.append(DefaultBB) - CaseBindings.append([]) - def _HasNoBreak(stmts: list[ast.stmt]) -> bool: - for stmt in stmts: - if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): - if isinstance(stmt.value.func, ast.Attribute): - if (isinstance(stmt.value.func.value, ast.Name) and - stmt.value.func.value.id == 'c' and - stmt.value.func.attr == 'NoBreak'): - return True - if getattr(stmt, 'body', None) and isinstance(stmt.body, list): - if _HasNoBreak(stmt.body): - return True - if getattr(stmt, 'orelse', None): - if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): - return True - return False - HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) - if not HasDefault: - CaseBBs.append(DefaultBB) - SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] - switch_instr: ir.SwitchInstr = Gen.builder.switch(TagVal, DefaultBB) - for val, bb in SwitchCases: - switch_instr.add_case(val, bb) - CaseIdx: int = 0 - for i, case in enumerate(Node.cases): - pattern: ast.pattern = case.pattern - if isinstance(pattern, ast.MatchClass): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - bindings: list[tuple[str, str, ir.Type, int]] = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else [] - cls_node: ast.expr = pattern.cls - VariantName: str | None = None - if isinstance(cls_node, ast.Name): - VariantName = cls_node.id - elif isinstance(cls_node, ast.Attribute): - VariantName = cls_node.attr - if VariantName: - NestedStructName: str = f"{RenumName}_{VariantName}" - if NestedStructName in Gen.structs: - NestedStructType: ir.Type = Gen.structs[NestedStructName] - NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType) - variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}") - for bind_name, member_name, member_type, member_idx in bindings: - elem_ptr: ir.Value = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}") - # REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与 - # 结构体字段类型不一致。bitcast 到成员类型以确保后续 load 得到正确类型。 - if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type: - elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast") - Gen.variables[bind_name] = elem_ptr - self.HandleBodyLlvm(case.body) - for bind_name, _, _, _ in bindings: - if bind_name in Gen.variables: - del Gen.variables[bind_name] - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchValue): - if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: - Gen.builder.position_at_start(CaseBBs[CaseIdx]) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchAs): - if pattern.pattern is None: - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - elif isinstance(pattern, ast.MatchSequence): - Gen.builder.position_at_start(DefaultBB) - self.HandleBodyLlvm(case.body) - if not Gen.builder.block.is_terminated: - if not HasNoBreak[i]: - Gen.builder.branch(AfterBB) - CaseIdx += 1 - if not HasDefault: - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) - elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): - Gen.builder.position_at_start(DefaultBB) - Gen.builder.branch(AfterBB) +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import vast as ast +import llvmlite.ir as ir + + +class MatchHandle(BaseHandle): + def _HandleMatchLlvm(self, Node: ast.Match) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + SubjectVal: ir.Value | None = self.HandleExprLlvm(Node.subject) + if not SubjectVal: + return + + IsRenumMatch: bool = False + RenumName: str | None = None + SubjectPtr: ir.Value | None = None + if isinstance(Node.subject, ast.Name): + VarName: str = Node.subject.id + TypeInfo: "SymbolTable.SymbolInfo | None" = self.Trans.SymbolTable.lookup(VarName) + if TypeInfo and TypeInfo.IsRenum: + IsRenumMatch = True + RenumName = TypeInfo.Name + SubjectPtr = Gen._Load_var(VarName) + + if not IsRenumMatch: + for case in Node.cases: + if isinstance(case.pattern, ast.MatchClass): + cls_node: ast.expr = case.pattern.cls + VariantName: str | None = None + QualifiedName: str | None = None + if isinstance(cls_node, ast.Name): + VariantName = cls_node.id + elif isinstance(cls_node, ast.Attribute): + VariantName = cls_node.attr + # Extract enum name for qualified lookup to avoid collision + # with same-name factory functions (e.g. def Ptr vs LLVMType.Ptr) + if isinstance(cls_node.value, ast.Attribute): + QualifiedName = f"{cls_node.value.attr}.{VariantName}" + elif isinstance(cls_node.value, ast.Name): + QualifiedName = f"{cls_node.value.id}.{VariantName}" + if VariantName: + # Try qualified name first (e.g., "LLVMType.Ptr") to avoid + # collision with same-name functions (e.g., def Ptr(...)) + SymInfo: "SymbolTable.SymbolInfo" = None + if QualifiedName: + SymInfo = self.Trans.SymbolTable.lookup(QualifiedName) + if not (SymInfo and SymInfo.IsEnumMember): + SymInfo = self.Trans.SymbolTable.lookup(VariantName) + if SymInfo and SymInfo.IsEnumMember and SymInfo.EnumName: + EnumName: str = SymInfo.EnumName + EnumInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(EnumName) + if EnumInfo and EnumInfo.IsRenum: + IsRenumMatch = True + RenumName = EnumName + if SubjectPtr is None: + SubjectPtr = self.HandleExprLlvm(Node.subject) + break + + if IsRenumMatch and SubjectPtr: + self._HandleRenumMatchLlvm(Node, RenumName, SubjectPtr) + return + + if not isinstance(SubjectVal.type, ir.IntType): + try: + SubjectVal = Gen.builder.ptrtoint(SubjectVal, ir.IntType(64), name="match_subj") + SubjectVal = Gen.builder.trunc(SubjectVal, ir.IntType(32), name="match_subj_i32") + except Exception: # 回退:ptrtoint 失败时直接返回 + return + SwitchIntType: ir.IntType = SubjectVal.type + DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default") + AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end") + CaseBBs: list[ir.Block] = [] + CaseValues: list[ir.Value] = [] + HasDefault: bool = False + HasNoBreak: list[bool] = [] + for i, case in enumerate(Node.cases): + pattern: ast.pattern = case.pattern + if isinstance(pattern, ast.MatchValue): + Val: ir.Value | None = self.HandleExprLlvm(pattern.value) + if Val: + CaseVal: ir.Value + if isinstance(Val.type, ir.IntType): + if Val.type != SwitchIntType: + if Val.type.width > SwitchIntType.width: + CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) + else: + CaseVal = ir.Constant(SwitchIntType, Val.constant) + else: + CaseVal = Val + else: + try: + CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}") + except Exception: # 回退:ptrtoint 失败时设默认值 0 + CaseVal = ir.Constant(SwitchIntType, 0) + CaseValues.append(CaseVal) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + elif isinstance(pattern, ast.MatchOr): + for j, SubPattern in enumerate(pattern.patterns): + if isinstance(SubPattern, ast.MatchValue): + Val: ir.Value | None = self.HandleExprLlvm(SubPattern.value) + if Val: + CaseVal: ir.Value + if isinstance(Val.type, ir.IntType): + if Val.type != SwitchIntType: + if Val.type.width > SwitchIntType.width: + CaseVal = ir.Constant(SwitchIntType, Val.constant & ((1 << SwitchIntType.width) - 1)) + else: + CaseVal = ir.Constant(SwitchIntType, Val.constant) + else: + CaseVal = Val + else: + try: + CaseVal = Gen.builder.ptrtoint(Val, SwitchIntType, name=f"case_val_{i}_{j}") + except Exception: # 回退:ptrtoint 失败时设默认值 0 + CaseVal = ir.Constant(SwitchIntType, 0) + CaseValues.append(CaseVal) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}_{j}")) + elif isinstance(pattern, ast.MatchSingleton): + if pattern.value is None: + CaseValues.append(ir.Constant(SwitchIntType, 0)) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + HasDefault = True + CaseBBs.append(DefaultBB) + elif isinstance(pattern, ast.MatchSequence): + HasDefault = True + CaseBBs.append(DefaultBB) + elif isinstance(pattern, ast.MatchClass): + # 兜底处理:REnum 检测失败但 case 是 MatchClass(REnum 变体模式) + # 尝试从变体名查找 tag 值,按整数值处理 + cls_node_mc: ast.expr = pattern.cls + VariantName_mc: str | None = None + QualifiedName_mc: str | None = None + if isinstance(cls_node_mc, ast.Name): + VariantName_mc = cls_node_mc.id + elif isinstance(cls_node_mc, ast.Attribute): + VariantName_mc = cls_node_mc.attr + if isinstance(cls_node_mc.value, ast.Attribute): + QualifiedName_mc = f"{cls_node_mc.value.attr}.{VariantName_mc}" + elif isinstance(cls_node_mc.value, ast.Name): + QualifiedName_mc = f"{cls_node_mc.value.id}.{VariantName_mc}" + TagValue_mc: int | None = None + SymInfo_mc: "SymbolTable.SymbolInfo" = None + if QualifiedName_mc: + SymInfo_mc = self.Trans.SymbolTable.lookup(QualifiedName_mc) + if not (SymInfo_mc and SymInfo_mc.IsEnumMember): + SymInfo_mc = self.Trans.SymbolTable.lookup(VariantName_mc) + if SymInfo_mc and SymInfo_mc.IsEnumMember: + TagValue_mc = SymInfo_mc.value + if TagValue_mc is not None: + CaseValues.append(ir.Constant(SwitchIntType, TagValue_mc)) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{VariantName_mc}")) + else: + # 变体名未找到,跳过此 case(fast-fail 已在外层处理) + pass + def _HasNoBreak(stmts: list[ast.stmt]) -> bool: + for stmt in stmts: + if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): + if isinstance(stmt.value.func, ast.Attribute): + if (isinstance(stmt.value.func.value, ast.Name) and + stmt.value.func.value.id == 'c' and + stmt.value.func.attr == 'NoBreak'): + return True + if getattr(stmt, 'body', None) and isinstance(stmt.body, list): + if _HasNoBreak(stmt.body): + return True + if getattr(stmt, 'orelse', None): + if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): + return True + return False + HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) + if not HasDefault: + CaseBBs.append(DefaultBB) + SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] + switch_instr: ir.SwitchInstr = Gen.builder.switch(SubjectVal, DefaultBB) + for val, bb in SwitchCases: + switch_instr.add_case(val, bb) + CaseIdx: int = 0 + for i, case in enumerate(Node.cases): + pattern: ast.pattern = case.pattern + if isinstance(pattern, ast.MatchOr): + NumSubCases: int = len(pattern.patterns) + for j in range(NumSubCases): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, (ast.MatchValue, ast.MatchSingleton)): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchSequence): + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchClass): + # 兜底处理:MatchClass 在非 REnum 路径的 case body 生成 + # case 收集阶段已创建 CaseBB,此处生成 body + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + if not HasDefault: + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) + elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + + def _HandleRenumMatchLlvm(self, Node: ast.Match, RenumName: str, SubjectPtr: ir.Value) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if isinstance(SubjectPtr.type, ir.PointerType) and isinstance(SubjectPtr.type.pointee, ir.PointerType): + SubjectPtr = Gen._load(SubjectPtr, name="Load_match_subj") + # Bug fix: HandleExprLlvm 可能对 REnum 字段执行了 load,返回值而非指针。 + # 情况1: SubjectPtr 不是指针类型(如 IntType)→ alloca REnum 结构体 + store + # 情况2: SubjectPtr 是指针但 pointee 不是结构体(如 i32* 指向 __tag)→ bitcast + NeedAlloca: bool = not isinstance(SubjectPtr.type, ir.PointerType) + NeedBitcast: bool = (isinstance(SubjectPtr.type, ir.PointerType) and + not isinstance(SubjectPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType))) + if NeedAlloca or NeedBitcast: + RenumStructType: Any = Gen.structs.get(RenumName) + if RenumStructType is None: + # 跨模块编译时 REnum 结构体可能尚未在 Gen.structs 中注册 + # (如 import llvmlite 后 LLVMType 仅在符号表,Gen.structs 无条目)。 + # 使用 _get_or_create_struct 按需创建(可能为 opaque)。 + RenumStructType = Gen._get_or_create_struct(RenumName) + if NeedAlloca: + AllocaPtr: ir.Value = Gen._allocaEntry(RenumStructType, name="match_subj_alloca") + CastedPtr: ir.Value = Gen.builder.bitcast(AllocaPtr, ir.PointerType(SubjectPtr.type), name="match_subj_cast") + Gen._store(SubjectPtr, CastedPtr) + SubjectPtr = AllocaPtr + else: + SubjectPtr = Gen.builder.bitcast(SubjectPtr, ir.PointerType(RenumStructType), name="match_subj_recast") + # REnum 布局为 { i32 __tag, },tag 在偏移 0。 + # 使用 bitcast 到 i32* 替代 gep [0,0],兼容 opaque 结构体 + # (跨模块编译时 REnum 结构体可能未 set_body,gep 会失败)。 + tag_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, ir.PointerType(ir.IntType(32)), name="match_tag_ptr") + TagVal: ir.Value = Gen._load(tag_ptr, name="match_tag_val") + DefaultBB: ir.Block = Gen.func.append_basic_block(name="match.default") + AfterBB: ir.Block = Gen.func.append_basic_block(name="match.end") + CaseBBs: list[ir.Block] = [] + CaseValues: list[ir.Value] = [] + CaseBindings: list[list[tuple[str, str, ir.Type, int]]] = [] + HasDefault: bool = False + HasNoBreak: list[bool] = [] + for i, case in enumerate(Node.cases): + pattern: ast.pattern = case.pattern + bindings: list[tuple[str, str, ir.Type, int]] = [] + if isinstance(pattern, ast.MatchClass): + cls_node: ast.expr = pattern.cls + VariantName: str | None = None + QualifiedName: str | None = None + if isinstance(cls_node, ast.Name): + VariantName = cls_node.id + elif isinstance(cls_node, ast.Attribute): + VariantName = cls_node.attr + if isinstance(cls_node.value, ast.Attribute): + QualifiedName = f"{cls_node.value.attr}.{VariantName}" + elif isinstance(cls_node.value, ast.Name): + QualifiedName = f"{cls_node.value.id}.{VariantName}" + if VariantName: + TagValue: int | None = None + SymInfo: "SymbolTable.SymbolInfo" = None + if QualifiedName: + SymInfo = self.Trans.SymbolTable.lookup(QualifiedName) + if not (SymInfo and SymInfo.IsEnumMember): + SymInfo = self.Trans.SymbolTable.lookup(VariantName) + if SymInfo and SymInfo.IsEnumMember: + TagValue = SymInfo.value + if TagValue is not None: + CaseValues.append(ir.Constant(ir.IntType(32), TagValue)) + CaseBB: ir.Block = Gen.func.append_basic_block(name=f"match.case_{VariantName}") + CaseBBs.append(CaseBB) + NestedStructName: str = f"{RenumName}_{VariantName}" + if NestedStructName in Gen.structs: + members: list[tuple[str, ir.Type]] = Gen.class_members.get(NestedStructName, []) + payLoad_members: list[tuple[str, ir.Type]] = [(n, t) for n, t in members if n != '__tag'] + for j, sub_pat in enumerate(pattern.patterns): + if isinstance(sub_pat, ast.MatchAs) and sub_pat.name and j < len(payLoad_members): + bindings.append((sub_pat.name, payLoad_members[j][0], payLoad_members[j][1], j)) + CaseBindings.append(bindings) + else: + CaseValues.append(ir.Constant(ir.IntType(32), 0)) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + CaseBindings.append([]) + elif isinstance(pattern, ast.MatchValue): + Val: ir.Value | None = self.HandleExprLlvm(pattern.value) + if Val: + CaseVal: ir.Value + if isinstance(Val.type, ir.IntType): + CaseVal = Val + else: + try: + CaseVal = Gen.builder.ptrtoint(Val, ir.IntType(32), name=f"case_val_{i}") + except Exception: # 回退:ptrtoint 失败时设默认值 0 + CaseVal = ir.Constant(ir.IntType(32), 0) + CaseValues.append(CaseVal) + CaseBBs.append(Gen.func.append_basic_block(name=f"match.case_{i}")) + CaseBindings.append([]) + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + HasDefault = True + CaseBBs.append(DefaultBB) + CaseBindings.append([]) + elif isinstance(pattern, ast.MatchSequence): + HasDefault = True + CaseBBs.append(DefaultBB) + CaseBindings.append([]) + def _HasNoBreak(stmts: list[ast.stmt]) -> bool: + for stmt in stmts: + if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Call): + if isinstance(stmt.value.func, ast.Attribute): + if (isinstance(stmt.value.func.value, ast.Name) and + stmt.value.func.value.id == 'c' and + stmt.value.func.attr == 'NoBreak'): + return True + if getattr(stmt, 'body', None) and isinstance(stmt.body, list): + if _HasNoBreak(stmt.body): + return True + if getattr(stmt, 'orelse', None): + if isinstance(stmt.orelse, list) and _HasNoBreak(stmt.orelse): + return True + return False + HasNoBreak.append(_HasNoBreak(case.body) if case.body else False) + if not HasDefault: + CaseBBs.append(DefaultBB) + SwitchCases: list[tuple[ir.Value, ir.Block]] = [(val, bb) for val, bb in zip(CaseValues, CaseBBs) if bb != DefaultBB] + switch_instr: ir.SwitchInstr = Gen.builder.switch(TagVal, DefaultBB) + for val, bb in SwitchCases: + switch_instr.add_case(val, bb) + CaseIdx: int = 0 + for i, case in enumerate(Node.cases): + pattern: ast.pattern = case.pattern + if isinstance(pattern, ast.MatchClass): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + bindings: list[tuple[str, str, ir.Type, int]] = CaseBindings[CaseIdx] if CaseIdx < len(CaseBindings) else [] + cls_node: ast.expr = pattern.cls + VariantName: str | None = None + if isinstance(cls_node, ast.Name): + VariantName = cls_node.id + elif isinstance(cls_node, ast.Attribute): + VariantName = cls_node.attr + if VariantName: + NestedStructName: str = f"{RenumName}_{VariantName}" + if NestedStructName in Gen.structs: + NestedStructType: ir.Type = Gen.structs[NestedStructName] + NestedStructPtrType: ir.PointerType = ir.PointerType(NestedStructType) + variant_ptr: ir.Value = Gen.builder.bitcast(SubjectPtr, NestedStructPtrType, name=f"match_cast_{VariantName}") + for bind_name, member_name, member_type, member_idx in bindings: + elem_ptr: ir.Value = Gen.builder.gep(variant_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), member_idx + 1)], name=f"match_{bind_name}") + # REnum 嵌套结构体共享 max_variant_struct 布局,成员类型可能与 + # 结构体字段类型不一致。bitcast 到成员类型以确保后续 load 得到正确类型。 + if isinstance(elem_ptr.type, ir.PointerType) and elem_ptr.type.pointee != member_type: + elem_ptr = Gen.builder.bitcast(elem_ptr, ir.PointerType(member_type), name=f"match_{bind_name}_cast") + Gen.variables[bind_name] = elem_ptr + self.HandleBodyLlvm(case.body) + for bind_name, _, _, _ in bindings: + if bind_name in Gen.variables: + del Gen.variables[bind_name] + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchValue): + if CaseIdx < len(CaseBBs) and CaseBBs[CaseIdx] != DefaultBB: + Gen.builder.position_at_start(CaseBBs[CaseIdx]) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchAs): + if pattern.pattern is None: + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + elif isinstance(pattern, ast.MatchSequence): + Gen.builder.position_at_start(DefaultBB) + self.HandleBodyLlvm(case.body) + if not Gen.builder.block.is_terminated: + if not HasNoBreak[i]: + Gen.builder.branch(AfterBB) + CaseIdx += 1 + if not HasDefault: + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) + elif not any(isinstance(c.pattern, ast.MatchAs) and c.pattern.pattern is None for c in Node.cases) and not any(isinstance(c.pattern, ast.MatchSequence) for c in Node.cases): + Gen.builder.position_at_start(DefaultBB) + Gen.builder.branch(AfterBB) Gen.builder.position_at_start(AfterBB) \ No newline at end of file diff --git a/lib/core/Handles/HandlesRaise.py b/lib/core/Handles/HandlesRaise.py index 9802e92..0c0203a 100644 --- a/lib/core/Handles/HandlesRaise.py +++ b/lib/core/Handles/HandlesRaise.py @@ -1,155 +1,155 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -import ast -import llvmlite.ir as ir -from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP -from lib.constants.config import mode as _config_mode - - -class RaiseHandle(BaseHandle): - def _get_exception_code(self, ExcName: str) -> int: - if ExcName in EXCEPTION_CODE_MAP: - return EXCEPTION_CODE_MAP[ExcName] - if ExcName in self.Trans.exception_registry: - return self.Trans.exception_registry[ExcName] - return 1 - - def _HandleRaiseLlvm(self, Node: ast.Raise) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - exc_val: ir.Constant = ir.Constant(ir.IntType(32), 1) - exc_msg: ir.Value | None = None - IsStopIteration: bool = False - if Node.exc: - if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int): - exc_val = ir.Constant(ir.IntType(32), Node.exc.value) - elif isinstance(Node.exc, ast.Name): - ExcName: str = Node.exc.id - if ExcName == 'StopIteration': - IsStopIteration = True - exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) - elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name): - ExcName: str = Node.exc.func.id - if ExcName == 'StopIteration': - IsStopIteration = True - exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) - if Node.exc.args: - first_arg: ast.expr = Node.exc.args[0] - if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): - exc_msg = self.HandleExprLlvm(first_arg) - elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)): - arg_val: ir.Value | None = self.HandleExprLlvm(first_arg) - if arg_val: - if isinstance(arg_val.type, ir.PointerType): - if self._is_char_pointer(arg_val): - exc_msg = arg_val - else: - try: - exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast") - except Exception as _e: - if _config_mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - else: - try: - exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr") - except Exception as _e: - if _config_mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - else: - val: ir.Value | None = self.HandleExprLlvm(Node.exc) - if val: - if isinstance(val.type, ir.IntType): - if val.type.width != 32: - try: - val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc") - except Exception: # 回退:trunc 失败时设默认值 1 - val = ir.Constant(ir.IntType(32), 1) - exc_val = val - else: - try: - val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int") - exc_val = val - except Exception as _e: - if _config_mode == "strict": - self.Trans.LogWarning(f"异常被忽略: {_e}") - if IsStopIteration: - if Gen._stop_iter_flag_param is not None: - Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param) - if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType(): - ret_type: ir.Type = Gen.func.type.pointee.return_type - if isinstance(ret_type, ir.PointerType): - Gen.builder.ret(ir.Constant(ret_type, None)) - elif isinstance(ret_type, ir.IntType): - Gen.builder.ret(ir.Constant(ret_type, 0)) - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): - Gen.builder.ret(ir.Constant(ret_type, 0.0)) - elif isinstance(ret_type, ir.BaseStructType): - if ret_type.elements: - zero_val: ir.Constant = ir.Constant(ret_type, [ - ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) - else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) - else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) - else: - zero_val = ir.Constant(ret_type, None) - Gen.builder.ret(zero_val) - else: - Gen.builder.ret(ir.Constant(ret_type, 0)) - else: - Gen.builder.ret_void() - return - if Gen.eh_except_block_stack: - ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0] - EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1] - exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2] - eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3] - Gen._store(exc_val, exception_code) - if exc_msg: - Gen._store(exc_msg, eh_message) - else: - null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) - Gen._store(null_ptr, eh_message) - if Gen.func and ExceptBB and ExceptBB.function is Gen.func: - Gen.builder.branch(ExceptBB) - else: - eh_msg_arg: ir.Argument | None = None - eh_code_arg: ir.Argument | None = None - if Gen.func: - for arg in Gen.func.args: - if arg.name == '__eh_msg_out__': - eh_msg_arg = arg - elif arg.name == '__eh_code_out__': - eh_code_arg = arg - if eh_msg_arg is not None: - if exc_msg: - Gen.builder.store(exc_msg, eh_msg_arg) - else: - null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) - Gen.builder.store(null_ptr, eh_msg_arg) - if eh_code_arg is not None: - Gen.builder.store(exc_val, eh_code_arg) - if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): - Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) - else: - Gen.builder.ret_void() - else: - eh_msg_arg: ir.Argument | None = None - eh_code_arg: ir.Argument | None = None - if Gen.func: - for arg in Gen.func.args: - if arg.name == '__eh_msg_out__': - eh_msg_arg = arg - elif arg.name == '__eh_code_out__': - eh_code_arg = arg - if eh_msg_arg is not None: - if exc_msg: - Gen.builder.store(exc_msg, eh_msg_arg) - else: - null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) - Gen.builder.store(null_ptr, eh_msg_arg) - if eh_code_arg is not None: - Gen.builder.store(exc_val, eh_code_arg) - if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): - Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) - else: +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +import vast as ast +import llvmlite.ir as ir +from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP +from lib.constants.config import mode as _config_mode + + +class RaiseHandle(BaseHandle): + def _get_exception_code(self, ExcName: str) -> int: + if ExcName in EXCEPTION_CODE_MAP: + return EXCEPTION_CODE_MAP[ExcName] + if ExcName in self.Trans.exception_registry: + return self.Trans.exception_registry[ExcName] + return 1 + + def _HandleRaiseLlvm(self, Node: ast.Raise) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + exc_val: ir.Constant = ir.Constant(ir.IntType(32), 1) + exc_msg: ir.Value | None = None + IsStopIteration: bool = False + if Node.exc: + if isinstance(Node.exc, ast.Constant) and isinstance(Node.exc.value, int): + exc_val = ir.Constant(ir.IntType(32), Node.exc.value) + elif isinstance(Node.exc, ast.Name): + ExcName: str = Node.exc.id + if ExcName == 'StopIteration': + IsStopIteration = True + exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) + elif isinstance(Node.exc, ast.Call) and isinstance(Node.exc.func, ast.Name): + ExcName: str = Node.exc.func.id + if ExcName == 'StopIteration': + IsStopIteration = True + exc_val = ir.Constant(ir.IntType(32), self._get_exception_code(ExcName)) + if Node.exc.args: + first_arg: ast.expr = Node.exc.args[0] + if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str): + exc_msg = self.HandleExprLlvm(first_arg) + elif isinstance(first_arg, (ast.Name, ast.Call, ast.Attribute)): + arg_val: ir.Value | None = self.HandleExprLlvm(first_arg) + if arg_val: + if isinstance(arg_val.type, ir.PointerType): + if self._is_char_pointer(arg_val): + exc_msg = arg_val + else: + try: + exc_msg = Gen.builder.bitcast(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_cast") + except Exception as _e: + if _config_mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + else: + try: + exc_msg = Gen.builder.inttoptr(arg_val, ir.PointerType(ir.IntType(8)), name="exc_msg_ptr") + except Exception as _e: + if _config_mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + else: + val: ir.Value | None = self.HandleExprLlvm(Node.exc) + if val: + if isinstance(val.type, ir.IntType): + if val.type.width != 32: + try: + val = Gen.builder.trunc(val, ir.IntType(32), name="exc_trunc") + except Exception: # 回退:trunc 失败时设默认值 1 + val = ir.Constant(ir.IntType(32), 1) + exc_val = val + else: + try: + val = Gen.builder.ptrtoint(val, ir.IntType(32), name="exc_ptr2int") + exc_val = val + except Exception as _e: + if _config_mode == "strict": + self.Trans.LogWarning(f"异常被忽略: {_e}") + if IsStopIteration: + if Gen._stop_iter_flag_param is not None: + Gen.builder.store(ir.Constant(ir.IntType(1), 1), Gen._stop_iter_flag_param) + if Gen.func and Gen.func.type.pointee.return_type != ir.VoidType(): + ret_type: ir.Type = Gen.func.type.pointee.return_type + if isinstance(ret_type, ir.PointerType): + Gen.builder.ret(ir.Constant(ret_type, None)) + elif isinstance(ret_type, ir.IntType): + Gen.builder.ret(ir.Constant(ret_type, 0)) + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): + Gen.builder.ret(ir.Constant(ret_type, 0.0)) + elif isinstance(ret_type, ir.BaseStructType): + if ret_type.elements: + zero_val: ir.Constant = ir.Constant(ret_type, [ + ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) + else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) + else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + zero_val = ir.Constant(ret_type, None) + Gen.builder.ret(zero_val) + else: + Gen.builder.ret(ir.Constant(ret_type, 0)) + else: + Gen.builder.ret_void() + return + if Gen.eh_except_block_stack: + ExceptBB: ir.Block = Gen.eh_except_block_stack[-1][0] + EndBB: ir.Block | None = Gen.eh_except_block_stack[-1][1] + exception_code: ir.AllocaInstr = Gen.eh_except_block_stack[-1][2] + eh_message: ir.AllocaInstr = Gen.eh_except_block_stack[-1][3] + Gen._store(exc_val, exception_code) + if exc_msg: + Gen._store(exc_msg, eh_message) + else: + null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) + Gen._store(null_ptr, eh_message) + if Gen.func and ExceptBB and ExceptBB.function is Gen.func: + Gen.builder.branch(ExceptBB) + else: + eh_msg_arg: ir.Argument | None = None + eh_code_arg: ir.Argument | None = None + if Gen.func: + for arg in Gen.func.args: + if arg.name == '__eh_msg_out__': + eh_msg_arg = arg + elif arg.name == '__eh_code_out__': + eh_code_arg = arg + if eh_msg_arg is not None: + if exc_msg: + Gen.builder.store(exc_msg, eh_msg_arg) + else: + null_ptr = ir.Constant(ir.PointerType(ir.IntType(8)), None) + Gen.builder.store(null_ptr, eh_msg_arg) + if eh_code_arg is not None: + Gen.builder.store(exc_val, eh_code_arg) + if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): + Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) + else: + Gen.builder.ret_void() + else: + eh_msg_arg: ir.Argument | None = None + eh_code_arg: ir.Argument | None = None + if Gen.func: + for arg in Gen.func.args: + if arg.name == '__eh_msg_out__': + eh_msg_arg = arg + elif arg.name == '__eh_code_out__': + eh_code_arg = arg + if eh_msg_arg is not None: + if exc_msg: + Gen.builder.store(exc_msg, eh_msg_arg) + else: + null_ptr: ir.Constant = ir.Constant(ir.PointerType(ir.IntType(8)), None) + Gen.builder.store(null_ptr, eh_msg_arg) + if eh_code_arg is not None: + Gen.builder.store(exc_val, eh_code_arg) + if Gen.func and Gen.func.type.pointee.return_type == ir.IntType(32): + Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) + else: Gen.builder.ret_void() \ No newline at end of file diff --git a/lib/core/Handles/HandlesReturn.py b/lib/core/Handles/HandlesReturn.py index d7c6560..d043f8a 100644 --- a/lib/core/Handles/HandlesReturn.py +++ b/lib/core/Handles/HandlesReturn.py @@ -1,228 +1,228 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo -import ast -import llvmlite.ir as ir - - -def _safe_ptr_type(ty: ir.Type) -> ir.Type: - """LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*""" - if isinstance(ty, ir.PointerType): - cur: ir.Type = ty - while isinstance(cur, ir.PointerType): - if isinstance(cur.pointee, ir.VoidType): - return ir.IntType(8).as_pointer() - cur = cur.pointee - return ty - - -class ReturnHandle(BaseHandle): - def _find_active_finally(self, Gen: "Translator.LlvmGen") -> tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None: - for item in reversed(Gen.eh_finally_stack): - if item is not None and item[0] is not None: - return item - return None - - def _HandleReturnLlvm(self, Node: ast.Return) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - # 闭包返回检测:当返回值是带 nonlocal 参数的嵌套函数时,创建闭包结构体 - # 闭包结构体 {i8* env, i8* fn} 在堆上分配,env 指向 nonlocal 变量的堆存储 - if Node.value and isinstance(Node.value, ast.Name): - ret_name: str = Node.value.id - if ret_name in Gen.nonlocal_params and ret_name in Gen.functions: - nested_fn: ir.Function = Gen.functions[ret_name] - nonlocal_params: list[tuple[str, ir.Type]] = Gen.nonlocal_params[ret_name] - fn_return_type: ir.Type = nested_fn.function_type.return_type - nonlocal_types: list[ir.Type] = [_safe_ptr_type(t) for _, t in nonlocal_params] - # 构建 env:收集所有 nonlocal 变量指针 - env_ptrs: list[ir.Value] = [] - for var_name, _ in nonlocal_params: - vp: ir.Value | None = Gen.variables.get(var_name) - if vp is not None: - env_ptrs.append(vp) - if env_ptrs: - # env 值:单个指针直接用,多个指针打包成结构体 - i8_ptr_type: ir.PointerType = ir.IntType(8).as_pointer() - if len(env_ptrs) == 1: - env_val: ir.Value = Gen.builder.bitcast(env_ptrs[0], i8_ptr_type, name="closure_env") - else: - env_struct_type: ir.LiteralStructType = ir.LiteralStructType([p.type for p in env_ptrs]) - env_size: int = len(env_ptrs) * 8 - malloc_type: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)]) - malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_type) - env_raw: ir.Value = Gen.builder.call(malloc_func, [ir.Constant(ir.IntType(64), env_size)], name="env_struct_raw") - env_struct_ptr: ir.Value = Gen.builder.bitcast(env_raw, ir.PointerType(env_struct_type), name="env_struct_ptr") - for i, ptr in enumerate(env_ptrs): - gep: ir.Value = Gen.builder.gep(env_struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"env_field_{i}") - Gen._store(ptr, gep) - env_val = Gen.builder.bitcast(env_struct_ptr, i8_ptr_type, name="closure_env") - # fn 指针 - fn_ptr: ir.Value = Gen.builder.bitcast(nested_fn, i8_ptr_type, name="closure_fn") - # 创建闭包结构体 {i8* env, i8* fn} - closure_type: ir.LiteralStructType = ir.LiteralStructType([i8_ptr_type, i8_ptr_type]) - malloc_type2: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)]) - malloc_func2: ir.Function = Gen._get_or_declare_func('malloc', malloc_type2) - closure_raw: ir.Value = Gen.builder.call(malloc_func2, [ir.Constant(ir.IntType(64), 16)], name="closure_raw") - closure_ptr: ir.Value = Gen.builder.bitcast(closure_raw, ir.PointerType(closure_type), name="closure_ptr") - # 填充闭包结构体 - env_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="closure_env_slot") - Gen._store(env_val, env_gep) - fn_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name="closure_fn_slot") - Gen._store(fn_ptr, fn_gep) - # 记录闭包返回类型 - current_name: str = Gen.func.name if Gen.func else '' - short_name: str = current_name.split('.', 1)[1] if '.' in current_name else current_name - Gen._closure_return_types[short_name] = (fn_return_type, nonlocal_types) - # 返回闭包结构体指针(bitcast 到 i8*) - closure_ret: ir.Value = Gen.builder.bitcast(closure_ptr, i8_ptr_type, name="closure_ret") - Gen.emit_return(closure_ret) - return - active_finally: tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None = self._find_active_finally(Gen) - if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes and Node.value: - return_values: list[ast.expr] = [] - if isinstance(Node.value, ast.Tuple): - return_values = Node.value.elts - else: - return_values = [Node.value] - if len(return_values) == len(self.Trans.CurrentCReturnTypes): - llvm_vals: list[ir.Value] = [] - expected_types: list[ir.Type] = [] - for i, val in enumerate(return_values): - ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(self.Trans.CurrentCReturnTypes[i], self.Trans.SymbolTable) - IsRetPtr: bool = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False - if (isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.IsStr) or (isinstance(self.Trans.CurrentCReturnTypes[i], ast.Name) and self.Trans.CurrentCReturnTypes[i].id == 'str'): - IsRetPtr = True - ExpectedType: ir.Type = ReturnTypeInfo.ToLLVM(Gen) if ReturnTypeInfo and ReturnTypeInfo.BaseType else Gen._CType2LLVM('int', IsRetPtr) - expected_types.append(ExpectedType) - Val: ir.Value | None = self.HandleExprLlvm(val) - if Val is None: - if isinstance(ExpectedType, ir.PointerType): - Val = ir.Constant(ExpectedType, None) - elif isinstance(ExpectedType, ir.IntType): - Val = ir.Constant(ExpectedType, 0) - else: - Val = ir.Constant(ExpectedType, ir.Undefined) - else: - if Val.type != ExpectedType: - if isinstance(ExpectedType, ir.IntType) and isinstance(Val.type, ir.IntType): - if Val.type.width < ExpectedType.width: - Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}") - elif Val.type.width > ExpectedType.width: - Val = Gen.builder.trunc(Val, ExpectedType, name=f"trunc_ret_{i}") - elif isinstance(ExpectedType, ir.PointerType) and isinstance(Val.type, ir.PointerType): - Val = Gen.builder.bitcast(Val, ExpectedType, name=f"cast_ret_{i}") - llvm_vals.append(Val) - if llvm_vals: - struct_type: ir.LiteralStructType = ir.LiteralStructType(expected_types) - result: ir.Value = ir.Constant(struct_type, ir.Undefined) - for i, val in enumerate(llvm_vals): - result = Gen.builder.insert_value(result, val, i, name=f"ret_field_{i}") - if active_finally: - FinallyBB: ir.Block = active_finally[0] - pending_ret_flag: ir.AllocaInstr = active_finally[1] - pending_ret_val: ir.AllocaInstr | None = active_finally[2] - if pending_ret_val: - Gen._store(result, pending_ret_val) - Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) - Gen.builder.branch(FinallyBB) - else: - Gen.emit_return(result) - return - if Node.value: - Val: ir.Value | None = self.HandleExprLlvm(Node.value) - if Val: - ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None - if isinstance(ret_type, ir.IdentifiedStructType) and isinstance(Val, ir.Constant) and isinstance(Val.type, ir.PointerType) and Val.constant is None: - if ret_type.elements: - zero_val: ir.Constant = ir.Constant(ret_type, [ - ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) - else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) - else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) - else: - zero_val = ir.Constant(ret_type, None) - if active_finally: - FinallyBB: ir.Block = active_finally[0] - pending_ret_flag: ir.AllocaInstr = active_finally[1] - pending_ret_val: ir.AllocaInstr | None = active_finally[2] - if pending_ret_val: - Gen._store(zero_val, pending_ret_val) - Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) - Gen.builder.branch(FinallyBB) - else: - Gen.emit_return(zero_val) - return - if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes: - struct_type: ir.Type = Gen.func.ftype.return_type - if isinstance(struct_type, ir.LiteralStructType): - result: ir.Value = ir.Constant(struct_type, ir.Undefined) - if isinstance(Val.type, ir.PointerType) and len(struct_type.elements) > 0 and isinstance(struct_type.elements[0], ir.PointerType): - result = Gen.builder.insert_value(result, Val, 0, name="ret_field_0") - for j in range(1, len(struct_type.elements)): - elem_type: ir.Type = struct_type.elements[j] - zero_val: ir.Constant = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None) - result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}") - else: - for j, elem_type in enumerate(struct_type.elements): - if j == 0: - if Val.type == elem_type: - result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}") - elif isinstance(elem_type, ir.IntType) and isinstance(Val.type, ir.IntType): - if Val.type.width < elem_type.width: - Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}") - elif Val.type.width > elem_type.width: - Val = Gen.builder.trunc(Val, elem_type, name=f"trunc_ret_{j}") - result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}") - else: - zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None) - result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}") - else: - zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None) - result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}") - if active_finally: - FinallyBB: ir.Block = active_finally[0] - pending_ret_flag: ir.AllocaInstr = active_finally[1] - pending_ret_val: ir.AllocaInstr | None = active_finally[2] - if pending_ret_val: - Gen._store(result, pending_ret_val) - Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) - Gen.builder.branch(FinallyBB) - else: - Gen.emit_return(result) - return - if active_finally: - FinallyBB: ir.Block = active_finally[0] - pending_ret_flag: ir.AllocaInstr = active_finally[1] - pending_ret_val: ir.AllocaInstr | None = active_finally[2] - if pending_ret_val: - Gen._store(Val, pending_ret_val) - Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) - Gen.builder.branch(FinallyBB) - else: - Gen.emit_return(Val) - else: - if active_finally: - FinallyBB: ir.Block = active_finally[0] - pending_ret_flag: ir.AllocaInstr = active_finally[1] - pending_ret_val: ir.AllocaInstr | None = active_finally[2] - Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) - Gen.builder.branch(FinallyBB) - else: - ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None - if isinstance(ret_type, ir.IntType): - Gen.builder.ret(ir.Constant(ret_type, 0)) - elif isinstance(ret_type, ir.PointerType): - Gen.builder.ret(ir.Constant(ret_type, None)) - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): - Gen.builder.ret(ir.Constant(ret_type, 0.0)) - elif isinstance(ret_type, ir.BaseStructType): - if ret_type.elements: - zero_val: ir.Constant = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) - else: - zero_val = ir.Constant(ret_type, None) - Gen.builder.ret(zero_val) - elif isinstance(ret_type, ir.ArrayType): - Gen.builder.ret(ir.Constant(ret_type, None)) - else: +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo +import vast as ast +import llvmlite.ir as ir + + +def _safe_ptr_type(ty: ir.Type) -> ir.Type: + """LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*""" + if isinstance(ty, ir.PointerType): + cur: ir.Type = ty + while isinstance(cur, ir.PointerType): + if isinstance(cur.pointee, ir.VoidType): + return ir.IntType(8).as_pointer() + cur = cur.pointee + return ty + + +class ReturnHandle(BaseHandle): + def _find_active_finally(self, Gen: "Translator.LlvmGen") -> tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None: + for item in reversed(Gen.eh_finally_stack): + if item is not None and item[0] is not None: + return item + return None + + def _HandleReturnLlvm(self, Node: ast.Return) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + # 闭包返回检测:当返回值是带 nonlocal 参数的嵌套函数时,创建闭包结构体 + # 闭包结构体 {i8* env, i8* fn} 在堆上分配,env 指向 nonlocal 变量的堆存储 + if Node.value and isinstance(Node.value, ast.Name): + ret_name: str = Node.value.id + if ret_name in Gen.nonlocal_params and ret_name in Gen.functions: + nested_fn: ir.Function = Gen.functions[ret_name] + nonlocal_params: list[tuple[str, ir.Type]] = Gen.nonlocal_params[ret_name] + fn_return_type: ir.Type = nested_fn.function_type.return_type + nonlocal_types: list[ir.Type] = [_safe_ptr_type(t) for _, t in nonlocal_params] + # 构建 env:收集所有 nonlocal 变量指针 + env_ptrs: list[ir.Value] = [] + for var_name, _ in nonlocal_params: + vp: ir.Value | None = Gen.variables.get(var_name) + if vp is not None: + env_ptrs.append(vp) + if env_ptrs: + # env 值:单个指针直接用,多个指针打包成结构体 + i8_ptr_type: ir.PointerType = ir.IntType(8).as_pointer() + if len(env_ptrs) == 1: + env_val: ir.Value = Gen.builder.bitcast(env_ptrs[0], i8_ptr_type, name="closure_env") + else: + env_struct_type: ir.LiteralStructType = ir.LiteralStructType([p.type for p in env_ptrs]) + env_size: int = len(env_ptrs) * 8 + malloc_type: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)]) + malloc_func: ir.Function = Gen._get_or_declare_func('malloc', malloc_type) + env_raw: ir.Value = Gen.builder.call(malloc_func, [ir.Constant(ir.IntType(64), env_size)], name="env_struct_raw") + env_struct_ptr: ir.Value = Gen.builder.bitcast(env_raw, ir.PointerType(env_struct_type), name="env_struct_ptr") + for i, ptr in enumerate(env_ptrs): + gep: ir.Value = Gen.builder.gep(env_struct_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), i)], name=f"env_field_{i}") + Gen._store(ptr, gep) + env_val = Gen.builder.bitcast(env_struct_ptr, i8_ptr_type, name="closure_env") + # fn 指针 + fn_ptr: ir.Value = Gen.builder.bitcast(nested_fn, i8_ptr_type, name="closure_fn") + # 创建闭包结构体 {i8* env, i8* fn} + closure_type: ir.LiteralStructType = ir.LiteralStructType([i8_ptr_type, i8_ptr_type]) + malloc_type2: ir.FunctionType = ir.FunctionType(i8_ptr_type, [ir.IntType(64)]) + malloc_func2: ir.Function = Gen._get_or_declare_func('malloc', malloc_type2) + closure_raw: ir.Value = Gen.builder.call(malloc_func2, [ir.Constant(ir.IntType(64), 16)], name="closure_raw") + closure_ptr: ir.Value = Gen.builder.bitcast(closure_raw, ir.PointerType(closure_type), name="closure_ptr") + # 填充闭包结构体 + env_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name="closure_env_slot") + Gen._store(env_val, env_gep) + fn_gep: ir.Value = Gen.builder.gep(closure_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 1)], name="closure_fn_slot") + Gen._store(fn_ptr, fn_gep) + # 记录闭包返回类型 + current_name: str = Gen.func.name if Gen.func else '' + short_name: str = current_name.split('.', 1)[1] if '.' in current_name else current_name + Gen._closure_return_types[short_name] = (fn_return_type, nonlocal_types) + # 返回闭包结构体指针(bitcast 到 i8*) + closure_ret: ir.Value = Gen.builder.bitcast(closure_ptr, i8_ptr_type, name="closure_ret") + Gen.emit_return(closure_ret) + return + active_finally: tuple[ir.Block, ir.AllocaInstr, ir.AllocaInstr | None] | None = self._find_active_finally(Gen) + if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes and Node.value: + return_values: list[ast.expr] = [] + if isinstance(Node.value, ast.Tuple): + return_values = Node.value.elts + else: + return_values = [Node.value] + if len(return_values) == len(self.Trans.CurrentCReturnTypes): + llvm_vals: list[ir.Value] = [] + expected_types: list[ir.Type] = [] + for i, val in enumerate(return_values): + ReturnTypeInfo: CTypeInfo | None = CTypeInfo.FromNode(self.Trans.CurrentCReturnTypes[i], self.Trans.SymbolTable) + IsRetPtr: bool = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False + if (isinstance(ReturnTypeInfo, CTypeInfo) and ReturnTypeInfo.IsStr) or (isinstance(self.Trans.CurrentCReturnTypes[i], ast.Name) and self.Trans.CurrentCReturnTypes[i].id == 'str'): + IsRetPtr = True + ExpectedType: ir.Type = ReturnTypeInfo.ToLLVM(Gen) if ReturnTypeInfo and ReturnTypeInfo.BaseType else Gen._CType2LLVM('int', IsRetPtr) + expected_types.append(ExpectedType) + Val: ir.Value | None = self.HandleExprLlvm(val) + if Val is None: + if isinstance(ExpectedType, ir.PointerType): + Val = ir.Constant(ExpectedType, None) + elif isinstance(ExpectedType, ir.IntType): + Val = ir.Constant(ExpectedType, 0) + else: + Val = ir.Constant(ExpectedType, ir.Undefined) + else: + if Val.type != ExpectedType: + if isinstance(ExpectedType, ir.IntType) and isinstance(Val.type, ir.IntType): + if Val.type.width < ExpectedType.width: + Val = Gen.builder.zext(Val, ExpectedType, name=f"zext_ret_{i}") + elif Val.type.width > ExpectedType.width: + Val = Gen.builder.trunc(Val, ExpectedType, name=f"trunc_ret_{i}") + elif isinstance(ExpectedType, ir.PointerType) and isinstance(Val.type, ir.PointerType): + Val = Gen.builder.bitcast(Val, ExpectedType, name=f"cast_ret_{i}") + llvm_vals.append(Val) + if llvm_vals: + struct_type: ir.LiteralStructType = ir.LiteralStructType(expected_types) + result: ir.Value = ir.Constant(struct_type, ir.Undefined) + for i, val in enumerate(llvm_vals): + result = Gen.builder.insert_value(result, val, i, name=f"ret_field_{i}") + if active_finally: + FinallyBB: ir.Block = active_finally[0] + pending_ret_flag: ir.AllocaInstr = active_finally[1] + pending_ret_val: ir.AllocaInstr | None = active_finally[2] + if pending_ret_val: + Gen._store(result, pending_ret_val) + Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) + Gen.builder.branch(FinallyBB) + else: + Gen.emit_return(result) + return + if Node.value: + Val: ir.Value | None = self.HandleExprLlvm(Node.value) + if Val: + ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None + if isinstance(ret_type, ir.IdentifiedStructType) and isinstance(Val, ir.Constant) and isinstance(Val.type, ir.PointerType) and Val.constant is None: + if ret_type.elements: + zero_val: ir.Constant = ir.Constant(ret_type, [ + ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) + else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) + else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + zero_val = ir.Constant(ret_type, None) + if active_finally: + FinallyBB: ir.Block = active_finally[0] + pending_ret_flag: ir.AllocaInstr = active_finally[1] + pending_ret_val: ir.AllocaInstr | None = active_finally[2] + if pending_ret_val: + Gen._store(zero_val, pending_ret_val) + Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) + Gen.builder.branch(FinallyBB) + else: + Gen.emit_return(zero_val) + return + if getattr(self.Trans, 'CurrentCReturnTypes', None) and self.Trans.CurrentCReturnTypes: + struct_type: ir.Type = Gen.func.ftype.return_type + if isinstance(struct_type, ir.LiteralStructType): + result: ir.Value = ir.Constant(struct_type, ir.Undefined) + if isinstance(Val.type, ir.PointerType) and len(struct_type.elements) > 0 and isinstance(struct_type.elements[0], ir.PointerType): + result = Gen.builder.insert_value(result, Val, 0, name="ret_field_0") + for j in range(1, len(struct_type.elements)): + elem_type: ir.Type = struct_type.elements[j] + zero_val: ir.Constant = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None) + result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}") + else: + for j, elem_type in enumerate(struct_type.elements): + if j == 0: + if Val.type == elem_type: + result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}") + elif isinstance(elem_type, ir.IntType) and isinstance(Val.type, ir.IntType): + if Val.type.width < elem_type.width: + Val = Gen.builder.zext(Val, elem_type, name=f"zext_ret_{j}") + elif Val.type.width > elem_type.width: + Val = Gen.builder.trunc(Val, elem_type, name=f"trunc_ret_{j}") + result = Gen.builder.insert_value(result, Val, j, name=f"ret_field_{j}") + else: + zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None) + result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}") + else: + zero_val = ir.Constant(elem_type, 0 if isinstance(elem_type, ir.IntType) else None) + result = Gen.builder.insert_value(result, zero_val, j, name=f"ret_field_{j}") + if active_finally: + FinallyBB: ir.Block = active_finally[0] + pending_ret_flag: ir.AllocaInstr = active_finally[1] + pending_ret_val: ir.AllocaInstr | None = active_finally[2] + if pending_ret_val: + Gen._store(result, pending_ret_val) + Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) + Gen.builder.branch(FinallyBB) + else: + Gen.emit_return(result) + return + if active_finally: + FinallyBB: ir.Block = active_finally[0] + pending_ret_flag: ir.AllocaInstr = active_finally[1] + pending_ret_val: ir.AllocaInstr | None = active_finally[2] + if pending_ret_val: + Gen._store(Val, pending_ret_val) + Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) + Gen.builder.branch(FinallyBB) + else: + Gen.emit_return(Val) + else: + if active_finally: + FinallyBB: ir.Block = active_finally[0] + pending_ret_flag: ir.AllocaInstr = active_finally[1] + pending_ret_val: ir.AllocaInstr | None = active_finally[2] + Gen._store(ir.Constant(ir.IntType(32), 1), pending_ret_flag) + Gen.builder.branch(FinallyBB) + else: + ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None + if isinstance(ret_type, ir.IntType): + Gen.builder.ret(ir.Constant(ret_type, 0)) + elif isinstance(ret_type, ir.PointerType): + Gen.builder.ret(ir.Constant(ret_type, None)) + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): + Gen.builder.ret(ir.Constant(ret_type, 0.0)) + elif isinstance(ret_type, ir.BaseStructType): + if ret_type.elements: + zero_val: ir.Constant = ir.Constant(ret_type, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + zero_val = ir.Constant(ret_type, None) + Gen.builder.ret(zero_val) + elif isinstance(ret_type, ir.ArrayType): + Gen.builder.ret(ir.Constant(ret_type, None)) + else: Gen.emit_return() \ No newline at end of file diff --git a/lib/core/Handles/HandlesSpecialCall.py b/lib/core/Handles/HandlesSpecialCall.py index 61ea1de..46f4c46 100644 --- a/lib/core/Handles/HandlesSpecialCall.py +++ b/lib/core/Handles/HandlesSpecialCall.py @@ -1,6 +1,6 @@ from __future__ import annotations from typing import TYPE_CHECKING -import ast +import vast as ast import llvmlite.ir as ir if TYPE_CHECKING: from lib.core.translator import Translator diff --git a/lib/core/Handles/HandlesTry.py b/lib/core/Handles/HandlesTry.py index 1fd04e7..d57fb12 100644 --- a/lib/core/Handles/HandlesTry.py +++ b/lib/core/Handles/HandlesTry.py @@ -1,214 +1,214 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP -import ast -import llvmlite.ir as ir - - -class TryHandle(BaseHandle): - def _get_exception_type_code(self, type_node: ast.expr) -> int: - if isinstance(type_node, ast.Name): - name: str = type_node.id - if name in EXCEPTION_CODE_MAP: - return EXCEPTION_CODE_MAP[name] - if name in self.Trans.exception_registry: - return self.Trans.exception_registry[name] - return 1 - if isinstance(type_node, ast.Attribute): - name: str = type_node.attr - if name in EXCEPTION_CODE_MAP: - return EXCEPTION_CODE_MAP[name] - if name in self.Trans.exception_registry: - return self.Trans.exception_registry[name] - return 1 - if isinstance(type_node, ast.Tuple): - for elt in type_node.elts: - code: int = self._get_exception_type_code(elt) - if code != 1: - return code - return 1 - return 1 - - def _get_exception_name(self, type_node: ast.expr) -> str | None: - if isinstance(type_node, ast.Name): - return type_node.id - if isinstance(type_node, ast.Attribute): - return type_node.attr - return None - - def _get_all_match_codes(self, type_node: ast.expr) -> list[int]: - name: str | None = self._get_exception_name(type_node) - if name is None: - return [self._get_exception_type_code(type_node)] - if name not in self.Trans.exception_registry: - return [self._get_exception_type_code(type_node)] - codes: list[int] = [self.Trans.exception_registry[name]] - self._collect_descendant_codes(name, codes) - return codes - - def _collect_descendant_codes(self, parent_name: str, codes: list[int]) -> None: - for child_name, parent in self.Trans.exception_parents.items(): - if parent == parent_name: - child_code: int | None = self.Trans.exception_registry.get(child_name) - if child_code is not None and child_code not in codes: - codes.append(child_code) - self._collect_descendant_codes(child_name, codes) - - def _HandleTryLlvm(self, Node: ast.Try) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - if not Gen.func: - return - exception_code: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="eh_code") - eh_message: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_message") - Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) - Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message) - HasFinally: bool = bool(Node.finalbody) - if HasFinally: - Gen.eh_finally_stack.append((None, None, None)) - else: - Gen.eh_finally_stack.append(None) - DispatchBB: ir.Block = Gen.func.append_basic_block(name="try.dispatch") - AfterBB: ir.Block = Gen.func.append_basic_block(name="try.after") - except_blocks: list[tuple[ir.Block, list[int], ast.ExceptHandler]] = [] - for i, handler in enumerate(Node.handlers): - ExcTypeCodes: list[int] = [1] - if handler.type: - ExcTypeCodes = self._get_all_match_codes(handler.type) - ExceptBB: ir.Block = Gen.func.append_basic_block(name=f"try.except_{i}") - Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message)) - except_blocks.append((ExceptBB, ExcTypeCodes, handler)) - TryBB: ir.Block = Gen.func.append_basic_block(name="try.body") - ElseBB: ir.Block | None = None - if Node.orelse: - ElseBB = Gen.func.append_basic_block(name="try.else") - Gen.builder.branch(TryBB) - Gen.builder.position_at_start(TryBB) - self.HandleBodyLlvm(Node.body) - if not Gen.builder.block.is_terminated: - Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) - if ElseBB: - Gen.builder.branch(ElseBB) - else: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(DispatchBB) - eh_code_val: ir.Value = Gen._load(exception_code, name="Load_eh_code") - next_check_bb: ir.Block | None = None - handler_var_map: dict[int, tuple[str, ir.AllocaInstr, ir.Value | None]] = {} - UnhandledBB: ir.Block = Gen.func.append_basic_block(name="try.unhandled") - for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): - MatchBB: ir.Block = Gen.func.append_basic_block(name=f"try.match_{i}") - if i > 0 and next_check_bb is not None: - Gen.builder.position_at_start(next_check_bb) - eh_code_val = Gen._load(exception_code, name=f"Load_eh_code_{i}") - if handler.type is None: - Gen.builder.branch(MatchBB) - else: - match_cond: ir.Value | None = None - for code in ExcTypeCodes: - is_code_match: ir.Value = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}") - if match_cond is None: - match_cond = is_code_match - else: - match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}") - if i < len(except_blocks) - 1: - next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}") - else: - next_check_bb = UnhandledBB - Gen.builder.cbranch(match_cond, MatchBB, next_check_bb) - Gen.builder.position_at_start(MatchBB) - if handler.name: - var_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name=handler.name) - eh_msg_val: ir.Value = Gen._load(eh_message, name=f"Load_eh_msg_{handler.name}") - Gen._store(eh_msg_val, var_alloca) - handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name)) - Gen.builder.branch(ExceptBB) - Gen.builder.position_at_start(UnhandledBB) - eh_msg_out_arg: ir.Argument | None = None - eh_code_out_arg: ir.Argument | None = None - if Gen.func and len(Gen.func.args) > 0: - for arg in Gen.func.args: - if arg.name == '__eh_msg_out__': - eh_msg_out_arg = arg - elif arg.name == '__eh_code_out__': - eh_code_out_arg = arg - if eh_msg_out_arg is not None and eh_code_out_arg is not None: - eh_msg_val: ir.Value = Gen._load(eh_message, name="Load_eh_msg_propagate") - eh_code_val_prop: ir.Value = Gen._load(exception_code, name="Load_eh_code_propagate") - Gen._store(eh_msg_val, eh_msg_out_arg) - Gen._store(eh_code_val_prop, eh_code_out_arg) - ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None - if isinstance(ret_type, ir.IdentifiedStructType): - if ret_type.elements: - zero_val: ir.Constant = ir.Constant(ret_type, [ - ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) - else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) - else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) - else: - zero_val = ir.Constant(ret_type, None) - Gen.builder.ret(zero_val) - elif isinstance(ret_type, ir.PointerType): - Gen.builder.ret(ir.Constant(ret_type, None)) - elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): - Gen.builder.ret(ir.Constant(ret_type, 0.0)) - elif isinstance(ret_type, ir.IntType): - Gen.builder.ret(ir.Constant(ret_type, 1)) - elif isinstance(ret_type, ir.VoidType): - Gen.builder.ret_void() - else: - Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) - else: - Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) - Gen.builder.branch(AfterBB) - for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): - Gen.builder.position_at_start(ExceptBB) - old_var: ir.Value | None = None - if idx in handler_var_map: - hname: str = handler_var_map[idx][0] - var_alloca: ir.AllocaInstr = handler_var_map[idx][1] - old_var = handler_var_map[idx][2] - Gen.variables[hname] = var_alloca - self.HandleBodyLlvm(handler.body) - if idx in handler_var_map: - hname = handler_var_map[idx][0] - old_var = handler_var_map[idx][2] - if old_var is not None: - Gen.variables[hname] = old_var - elif hname in Gen.variables: - del Gen.variables[hname] - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.eh_except_block_stack.pop() - if ElseBB: - Gen.builder.position_at_start(ElseBB) - self.HandleBodyLlvm(Node.orelse) - if not Gen.builder.block.is_terminated: - Gen.builder.branch(AfterBB) - Gen.builder.position_at_start(AfterBB) - if HasFinally: - Gen.eh_finally_stack.pop() - if Node.finalbody: - FinallyBB: ir.Block = Gen.func.append_basic_block(name="try.finally") - pending_ret_flag: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="pending_ret_flag") - pending_ret_val: ir.AllocaInstr | None = Gen._allocaEntry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None - Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val)) - Gen.builder.branch(FinallyBB) - Gen.builder.position_at_start(FinallyBB) - Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag) - self.HandleBodyLlvm(Node.finalbody) - if Gen.eh_finally_stack: - _, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1] - Gen.eh_finally_stack.pop() - ret_flag_val: ir.Value = Gen._load(pending_ret_flag, name="Load_ret_flag") - ret_flag_is_set: ir.Value = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag") - RetBB: ir.Block = Gen.func.append_basic_block(name="finally.ret") - ContinueBB: ir.Block = Gen.func.append_basic_block(name="try.continue") - Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB) - Gen.builder.position_at_start(RetBB) - if pending_ret_val: - ret_val: ir.Value = Gen._load(pending_ret_val, name="Load_ret_val") - Gen.builder.ret(ret_val) - else: - Gen.builder.ret_void() +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle, EXCEPTION_CODE_MAP +import vast as ast +import llvmlite.ir as ir + + +class TryHandle(BaseHandle): + def _get_exception_type_code(self, type_node: ast.expr) -> int: + if isinstance(type_node, ast.Name): + name: str = type_node.id + if name in EXCEPTION_CODE_MAP: + return EXCEPTION_CODE_MAP[name] + if name in self.Trans.exception_registry: + return self.Trans.exception_registry[name] + return 1 + if isinstance(type_node, ast.Attribute): + name: str = type_node.attr + if name in EXCEPTION_CODE_MAP: + return EXCEPTION_CODE_MAP[name] + if name in self.Trans.exception_registry: + return self.Trans.exception_registry[name] + return 1 + if isinstance(type_node, ast.Tuple): + for elt in type_node.elts: + code: int = self._get_exception_type_code(elt) + if code != 1: + return code + return 1 + return 1 + + def _get_exception_name(self, type_node: ast.expr) -> str | None: + if isinstance(type_node, ast.Name): + return type_node.id + if isinstance(type_node, ast.Attribute): + return type_node.attr + return None + + def _get_all_match_codes(self, type_node: ast.expr) -> list[int]: + name: str | None = self._get_exception_name(type_node) + if name is None: + return [self._get_exception_type_code(type_node)] + if name not in self.Trans.exception_registry: + return [self._get_exception_type_code(type_node)] + codes: list[int] = [self.Trans.exception_registry[name]] + self._collect_descendant_codes(name, codes) + return codes + + def _collect_descendant_codes(self, parent_name: str, codes: list[int]) -> None: + for child_name, parent in self.Trans.exception_parents.items(): + if parent == parent_name: + child_code: int | None = self.Trans.exception_registry.get(child_name) + if child_code is not None and child_code not in codes: + codes.append(child_code) + self._collect_descendant_codes(child_name, codes) + + def _HandleTryLlvm(self, Node: ast.Try) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + if not Gen.func: + return + exception_code: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="eh_code") + eh_message: ir.AllocaInstr = Gen._allocaEntry(ir.PointerType(ir.IntType(8)), name="eh_message") + Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) + Gen._store(ir.Constant(ir.PointerType(ir.IntType(8)), None), eh_message) + HasFinally: bool = bool(Node.finalbody) + if HasFinally: + Gen.eh_finally_stack.append((None, None, None)) + else: + Gen.eh_finally_stack.append(None) + DispatchBB: ir.Block = Gen.func.append_basic_block(name="try.dispatch") + AfterBB: ir.Block = Gen.func.append_basic_block(name="try.after") + except_blocks: list[tuple[ir.Block, list[int], ast.ExceptHandler]] = [] + for i, handler in enumerate(Node.handlers): + ExcTypeCodes: list[int] = [1] + if handler.type: + ExcTypeCodes = self._get_all_match_codes(handler.type) + ExceptBB: ir.Block = Gen.func.append_basic_block(name=f"try.except_{i}") + Gen.eh_except_block_stack.append((DispatchBB, None, exception_code, eh_message)) + except_blocks.append((ExceptBB, ExcTypeCodes, handler)) + TryBB: ir.Block = Gen.func.append_basic_block(name="try.body") + ElseBB: ir.Block | None = None + if Node.orelse: + ElseBB = Gen.func.append_basic_block(name="try.else") + Gen.builder.branch(TryBB) + Gen.builder.position_at_start(TryBB) + self.HandleBodyLlvm(Node.body) + if not Gen.builder.block.is_terminated: + Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) + if ElseBB: + Gen.builder.branch(ElseBB) + else: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(DispatchBB) + eh_code_val: ir.Value = Gen._load(exception_code, name="Load_eh_code") + next_check_bb: ir.Block | None = None + handler_var_map: dict[int, tuple[str, ir.AllocaInstr, ir.Value | None]] = {} + UnhandledBB: ir.Block = Gen.func.append_basic_block(name="try.unhandled") + for i, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): + MatchBB: ir.Block = Gen.func.append_basic_block(name=f"try.match_{i}") + if i > 0 and next_check_bb is not None: + Gen.builder.position_at_start(next_check_bb) + eh_code_val = Gen._load(exception_code, name=f"Load_eh_code_{i}") + if handler.type is None: + Gen.builder.branch(MatchBB) + else: + match_cond: ir.Value | None = None + for code in ExcTypeCodes: + is_code_match: ir.Value = Gen.builder.icmp_signed('==', eh_code_val, ir.Constant(ir.IntType(32), code), name=f"eh_match_{i}_c{code}") + if match_cond is None: + match_cond = is_code_match + else: + match_cond = Gen.builder.or_(match_cond, is_code_match, name=f"eh_match_any_{i}") + if i < len(except_blocks) - 1: + next_check_bb = Gen.func.append_basic_block(name=f"try.check_{i}") + else: + next_check_bb = UnhandledBB + Gen.builder.cbranch(match_cond, MatchBB, next_check_bb) + Gen.builder.position_at_start(MatchBB) + if handler.name: + var_alloca: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(8).as_pointer(), name=handler.name) + eh_msg_val: ir.Value = Gen._load(eh_message, name=f"Load_eh_msg_{handler.name}") + Gen._store(eh_msg_val, var_alloca) + handler_var_map[i] = (handler.name, var_alloca, Gen.variables.get(handler.name)) + Gen.builder.branch(ExceptBB) + Gen.builder.position_at_start(UnhandledBB) + eh_msg_out_arg: ir.Argument | None = None + eh_code_out_arg: ir.Argument | None = None + if Gen.func and len(Gen.func.args) > 0: + for arg in Gen.func.args: + if arg.name == '__eh_msg_out__': + eh_msg_out_arg = arg + elif arg.name == '__eh_code_out__': + eh_code_out_arg = arg + if eh_msg_out_arg is not None and eh_code_out_arg is not None: + eh_msg_val: ir.Value = Gen._load(eh_message, name="Load_eh_msg_propagate") + eh_code_val_prop: ir.Value = Gen._load(exception_code, name="Load_eh_code_propagate") + Gen._store(eh_msg_val, eh_msg_out_arg) + Gen._store(eh_code_val_prop, eh_code_out_arg) + ret_type: ir.Type | None = getattr(Gen.func, 'ftype', None) and Gen.func.ftype.return_type if getattr(Gen, 'func', None) else None + if isinstance(ret_type, ir.IdentifiedStructType): + if ret_type.elements: + zero_val: ir.Constant = ir.Constant(ret_type, [ + ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) + else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) + else ir.Constant(et, ir.Undefined) for et in ret_type.elements]) + else: + zero_val = ir.Constant(ret_type, None) + Gen.builder.ret(zero_val) + elif isinstance(ret_type, ir.PointerType): + Gen.builder.ret(ir.Constant(ret_type, None)) + elif isinstance(ret_type, (ir.FloatType, ir.DoubleType)): + Gen.builder.ret(ir.Constant(ret_type, 0.0)) + elif isinstance(ret_type, ir.IntType): + Gen.builder.ret(ir.Constant(ret_type, 1)) + elif isinstance(ret_type, ir.VoidType): + Gen.builder.ret_void() + else: + Gen.builder.ret(ir.Constant(ir.IntType(32), 1)) + else: + Gen._store(ir.Constant(ir.IntType(32), 0), exception_code) + Gen.builder.branch(AfterBB) + for idx, (ExceptBB, ExcTypeCodes, handler) in enumerate(except_blocks): + Gen.builder.position_at_start(ExceptBB) + old_var: ir.Value | None = None + if idx in handler_var_map: + hname: str = handler_var_map[idx][0] + var_alloca: ir.AllocaInstr = handler_var_map[idx][1] + old_var = handler_var_map[idx][2] + Gen.variables[hname] = var_alloca + self.HandleBodyLlvm(handler.body) + if idx in handler_var_map: + hname = handler_var_map[idx][0] + old_var = handler_var_map[idx][2] + if old_var is not None: + Gen.variables[hname] = old_var + elif hname in Gen.variables: + del Gen.variables[hname] + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.eh_except_block_stack.pop() + if ElseBB: + Gen.builder.position_at_start(ElseBB) + self.HandleBodyLlvm(Node.orelse) + if not Gen.builder.block.is_terminated: + Gen.builder.branch(AfterBB) + Gen.builder.position_at_start(AfterBB) + if HasFinally: + Gen.eh_finally_stack.pop() + if Node.finalbody: + FinallyBB: ir.Block = Gen.func.append_basic_block(name="try.finally") + pending_ret_flag: ir.AllocaInstr = Gen._allocaEntry(ir.IntType(32), name="pending_ret_flag") + pending_ret_val: ir.AllocaInstr | None = Gen._allocaEntry(ir.IntType(32), name="pending_ret_val") if Gen.func.type.pointee.return_type == ir.IntType(32) else None + Gen.eh_finally_stack.append((FinallyBB, pending_ret_flag, pending_ret_val)) + Gen.builder.branch(FinallyBB) + Gen.builder.position_at_start(FinallyBB) + Gen._store(ir.Constant(ir.IntType(32), 0), pending_ret_flag) + self.HandleBodyLlvm(Node.finalbody) + if Gen.eh_finally_stack: + _, pending_ret_flag, pending_ret_val = Gen.eh_finally_stack[-1] + Gen.eh_finally_stack.pop() + ret_flag_val: ir.Value = Gen._load(pending_ret_flag, name="Load_ret_flag") + ret_flag_is_set: ir.Value = Gen.builder.icmp_signed('!=', ret_flag_val, ir.Constant(ir.IntType(32), 0), name="check_ret_flag") + RetBB: ir.Block = Gen.func.append_basic_block(name="finally.ret") + ContinueBB: ir.Block = Gen.func.append_basic_block(name="try.continue") + Gen.builder.cbranch(ret_flag_is_set, RetBB, ContinueBB) + Gen.builder.position_at_start(RetBB) + if pending_ret_val: + ret_val: ir.Value = Gen._load(pending_ret_val, name="Load_ret_val") + Gen.builder.ret(ret_val) + else: + Gen.builder.ret_void() Gen.builder.position_at_start(ContinueBB) \ No newline at end of file diff --git a/lib/core/Handles/HandlesTypeMerge.py b/lib/core/Handles/HandlesTypeMerge.py index 9c98043..4fe6357 100644 --- a/lib/core/Handles/HandlesTypeMerge.py +++ b/lib/core/Handles/HandlesTypeMerge.py @@ -7,7 +7,7 @@ from lib.core.Handles.HandlesBase import BaseHandle, CTypeHelper, CTypeInfo from lib.core.SymbolUtils import IsTModule, IsListAnnotation from lib.includes import t import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes) -import ast +import vast as ast class HandlesTypeMerge(BaseHandle): diff --git a/lib/core/Handles/HandlesWith.py b/lib/core/Handles/HandlesWith.py index 6591250..4b37d10 100644 --- a/lib/core/Handles/HandlesWith.py +++ b/lib/core/Handles/HandlesWith.py @@ -1,212 +1,212 @@ -from __future__ import annotations -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.translator import Translator -from lib.core.Handles.HandlesBase import BaseHandle -import ast -import llvmlite.ir as ir - - -class WithHandle(BaseHandle): - def _ResolveInheritedMethod(self, ClassName: str, MethodName: str, Gen: "Translator.LlvmGen") -> tuple[str | None, "ir.Function | None"]: - """沿继承链查找方法,返回 (定义方法的类名, 函数对象) - - 当子类未覆写 __enter__/__exit__ 等方法时,沿 Gen.class_parent 链查找父类实现。 - _generate_inherited_method_wrappers 只为 class_methods[ClassName] 中的方法生成包装, - 不包括父类独有方法,因此 with 语句需要单独处理继承查找。 - """ - # 先检查子类自身:必须有函数体(define)才算真方法。 - # 子类继承方法的 stub declare(如 MemPool.__enter__,Phase1 生成的继承 - # 包装声明)无函数体且 TPC 不生成对应定义,直接调用会链接 undefined, - # 必须跳过并沿 MRO 找父类实现。 - FullName: str = f'{ClassName}.{MethodName}' - func = Gen._find_function(FullName) if hasattr(Gen, '_find_function') else Gen.functions.get(FullName) - if func and len(list(func.blocks)) > 0: - return (ClassName, func) - # 沿 MRO 继承链查找(多继承:先声明父类优先)。 - # 祖先的 stub declare(无函数体)是真实定义的声明(定义在其模块 obj 中), - # 可直接调用——与 _HandleMethodCallLlvm 的 MRO 回退语义一致。 - for anc in Gen._get_mro_chain(ClassName)[1:]: - parent_full: str = f'{anc}.{MethodName}' - parent_func = Gen._find_function(parent_full) if hasattr(Gen, '_find_function') else Gen.functions.get(parent_full) - if parent_func: - return (anc, parent_func) - return (None, None) - - def _HandleWithLlvm(self, Node: ast.With) -> None: - Gen: "Translator.LlvmGen" = self.Trans.LlvmGen - for item in Node.items: - context_expr: ast.expr = item.context_expr - asname: str | None = None - target: ast.expr | None = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None))) - if target and isinstance(target, ast.Name): - asname = target.id - ClassName: str | None = None - if isinstance(context_expr, ast.Call): - if isinstance(context_expr.func, ast.Name): - ClassName = context_expr.func.id - elif isinstance(context_expr.func, ast.Attribute): - ClassName = context_expr.func.attr - if ClassName and ClassName not in Gen.structs: - SymInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(ClassName) - if SymInfo: - if SymInfo.IsStruct or SymInfo.IsRenum: - pass - else: - ClassName = None - else: - ClassName = None - elif isinstance(context_expr, ast.Name): - VarName: str = context_expr.id - if VarName in Gen.var_struct_class: - ClassName = Gen.var_struct_class[VarName] - ctx_val: ir.Value | None = self.HandleExprLlvm(context_expr) - if not ctx_val: - continue - original_ctx_val: ir.Value = ctx_val - if ClassName and isinstance(ctx_val.type, ir.PointerType): - pointee: ir.Type = ctx_val.type.pointee - if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee) - if found: - CN: str = found[0] - ST: ir.Type = found[1] - ClassName = CN - StructPtrType: ir.PointerType | None = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None - if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName): - ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx") - ctx_alloca: ir.AllocaInstr = Gen._allocaEntry(ctx_val.type, name="__with_ctx") - Gen._store(ctx_val, ctx_alloca) - Gen._UnregisterTempPtr(ctx_val) - if ClassName: - Gen.var_struct_class['__with_ctx'] = ClassName - Gen._var_to_heap_ptr['__with_ctx'] = ctx_val - original_asname_heap_ptr: ir.Value | None = Gen._var_to_heap_ptr.get(asname) if asname else None - ctx_is_var_ref: bool = isinstance(context_expr, ast.Name) - enter_result: ir.Value | None = None - if ClassName: - # 沿继承链查找 __enter__(子类可能未覆写,使用父类实现) - enter_class, enter_func = self._ResolveInheritedMethod(ClassName, '__enter__', Gen) - if enter_func is not None: - ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx") - # 父类方法需要 self 为父类指针类型,bitcast 子类指针。 - # bitcast 目标用 enter_func 签名参数类型(args[0] 本身即 - # MemManager* 指针),避免 Gen.structs 查找返回 opaque/异 - # sha1 占位对象导致 llvmlite 类型不匹配。 - if enter_class != ClassName: - parent_ptr_type: ir.Type = enter_func.function_type.args[0] - if ctx_Loaded.type != parent_ptr_type: - ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_enter_self") - enter_call: ir.CallInstr = Gen.builder.call(enter_func, [ctx_Loaded], name="call_enter") - enter_result = enter_call - if isinstance(enter_call.type, ir.PointerType): - pointee: ir.Type = enter_call.type.pointee - if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - enter_result = Gen._load(enter_call, name="enter_deref") - elif self._is_char_pointer(enter_call) and StructPtrType: - enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter") - if asname and enter_result: - if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): - found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(enter_result.type.pointee) - if found: - CN: str = found[0] - ST: ir.Type = found[1] - Gen.var_struct_class[asname] = CN - Gen._var_to_heap_ptr[asname] = enter_result - Gen._register_local_heap_ptr(enter_result, VarName=asname) - if asname in Gen._reg_values: - OldVal: ir.Value = Gen._reg_values[asname] - var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=asname) - Gen._store(OldVal, var) - Gen.variables[asname] = var - del Gen._reg_values[asname] - if asname in Gen.variables and Gen.variables[asname] is not None: - VarPtr: ir.Value = Gen.variables[asname] - if VarPtr.type.pointee == enter_result.type: - Gen._store(enter_result, VarPtr) - elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): - CastedVal: ir.Value = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}") - Gen._store(CastedVal, VarPtr) - else: - NewVar: ir.AllocaInstr = Gen._alloca(enter_result.type, name=asname) - Gen._store(enter_result, NewVar) - Gen.variables[asname] = NewVar - else: - Gen._reg_values[asname] = enter_result - Gen.variables[asname] = None - # 如果类有 __provides__,自动生成 push 代码 - if ClassName and ClassName in Gen.class_provides: - # 编译期检查: with provider 栈深度是否超过 _MAX_PROVIDER_DEPTH (32) - # _with_provides_stack 只反映当前嵌套路径,顺序执行的 with 会在退出时弹栈 - current_depth: int = sum(len(pl) for pl in Gen._with_provides_stack) - new_fields: int = len(Gen.class_provides[ClassName]) - if current_depth + new_fields > 32: - raise SyntaxError( - f"[TransPyC] with provider stack overflow at line {Node.lineno}: " - f"current depth {current_depth} + new {new_fields} fields > max 32. " - f"Class '{ClassName}' provides too many fields or with nesting too deep." - ) - # 编译期压栈:记录当前 with 上下文提供的字段名,供 __require_must__ 静态检查 - Gen._with_provides_stack.append(Gen.class_provides[ClassName]) - ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx") - ctx_i8: ir.Value = ctx_Loaded - if isinstance(ctx_Loaded.type, ir.PointerType) and ctx_Loaded.type != ir.PointerType(ir.IntType(8)): - ctx_i8 = Gen.builder.bitcast(ctx_Loaded, ir.PointerType(ir.IntType(8)), name="ctx_push_i8") - for field_name in Gen.class_provides[ClassName]: - field_str: ir.Value = Gen._create_string_global(field_name) - push_func = Gen.functions.get('_push_provider') - if push_func: - Gen.builder.call(push_func, [field_str, ctx_i8], name="call_push_provider") - self.Trans.VarScopes.append({}) - if asname: - self.Trans.VarScopes[-1][asname] = True - self.HandleBodyLlvm(Node.body) - if self.Trans.VarScopes: - self.Trans.VarScopes.pop() - # 如果类有 __provides__,自动生成 pop 代码 - if ClassName and ClassName in Gen.class_provides: - for _ in Gen.class_provides[ClassName]: - pop_func = Gen.functions.get('_pop_provider') - if pop_func: - Gen.builder.call(pop_func, [], name="call_pop_provider") - # 编译期弹栈 - if Gen._with_provides_stack: - Gen._with_provides_stack.pop() - if ClassName: - # 沿继承链查找 __exit__(子类可能未覆写,使用父类实现) - exit_class, exit_func = self._ResolveInheritedMethod(ClassName, '__exit__', Gen) - if exit_func is not None: - ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx") - # 父类方法需要 self 为父类指针类型,bitcast 子类指针(同上) - if exit_class != ClassName: - parent_ptr_type: ir.Type = exit_func.function_type.args[0] - if ctx_Loaded.type != parent_ptr_type: - ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_exit_self") - Gen.builder.call(exit_func, [ctx_Loaded], name="call_exit") - Gen._unregister_local_heap_ptr(original_ctx_val) - if ctx_val is not original_ctx_val: - Gen._unregister_local_heap_ptr(ctx_val) - if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val: - Gen._unregister_local_heap_ptr(original_asname_heap_ptr) - if '__with_ctx' in Gen._var_to_heap_ptr: - del Gen._var_to_heap_ptr['__with_ctx'] - if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): - ctx_int: ir.Value = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int") - enter_int: ir.Value = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int") - same_ptr: ir.Value = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check") - with_free_bb: ir.Block = Gen.func.append_basic_block("with_free_ctx") - with_skip_bb: ir.Block = Gen.func.append_basic_block("with_skip_free") - Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb) - Gen.builder.position_at_start(with_free_bb) - raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") - free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) - Gen.builder.call(free_func, [raw]) - Gen.builder.branch(with_skip_bb) - Gen.builder.position_at_start(with_skip_bb) - Gen._unregister_local_heap_ptr(enter_result) - Gen._unregister_local_heap_ptr(original_ctx_val) - elif isinstance(ctx_val.type, ir.PointerType): - raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") - free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) - Gen.builder.call(free_func, [raw]) +from __future__ import annotations +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.translator import Translator +from lib.core.Handles.HandlesBase import BaseHandle +import vast as ast +import llvmlite.ir as ir + + +class WithHandle(BaseHandle): + def _ResolveInheritedMethod(self, ClassName: str, MethodName: str, Gen: "Translator.LlvmGen") -> tuple[str | None, "ir.Function | None"]: + """沿继承链查找方法,返回 (定义方法的类名, 函数对象) + + 当子类未覆写 __enter__/__exit__ 等方法时,沿 Gen.class_parent 链查找父类实现。 + _generate_inherited_method_wrappers 只为 class_methods[ClassName] 中的方法生成包装, + 不包括父类独有方法,因此 with 语句需要单独处理继承查找。 + """ + # 先检查子类自身:必须有函数体(define)才算真方法。 + # 子类继承方法的 stub declare(如 MemPool.__enter__,Phase1 生成的继承 + # 包装声明)无函数体且 TPC 不生成对应定义,直接调用会链接 undefined, + # 必须跳过并沿 MRO 找父类实现。 + FullName: str = f'{ClassName}.{MethodName}' + func = Gen._find_function(FullName) if hasattr(Gen, '_find_function') else Gen.functions.get(FullName) + if func and len(list(func.blocks)) > 0: + return (ClassName, func) + # 沿 MRO 继承链查找(多继承:先声明父类优先)。 + # 祖先的 stub declare(无函数体)是真实定义的声明(定义在其模块 obj 中), + # 可直接调用——与 _HandleMethodCallLlvm 的 MRO 回退语义一致。 + for anc in Gen._get_mro_chain(ClassName)[1:]: + parent_full: str = f'{anc}.{MethodName}' + parent_func = Gen._find_function(parent_full) if hasattr(Gen, '_find_function') else Gen.functions.get(parent_full) + if parent_func: + return (anc, parent_func) + return (None, None) + + def _HandleWithLlvm(self, Node: ast.With) -> None: + Gen: "Translator.LlvmGen" = self.Trans.LlvmGen + for item in Node.items: + context_expr: ast.expr = item.context_expr + asname: str | None = None + target: ast.expr | None = getattr(item, 'optional_vars', getattr(item, 'target', getattr(item, 'asname', None))) + if target and isinstance(target, ast.Name): + asname = target.id + ClassName: str | None = None + if isinstance(context_expr, ast.Call): + if isinstance(context_expr.func, ast.Name): + ClassName = context_expr.func.id + elif isinstance(context_expr.func, ast.Attribute): + ClassName = context_expr.func.attr + if ClassName and ClassName not in Gen.structs: + SymInfo: "SymbolTable.SymbolInfo" = self.Trans.SymbolTable.lookup(ClassName) + if SymInfo: + if SymInfo.IsStruct or SymInfo.IsRenum: + pass + else: + ClassName = None + else: + ClassName = None + elif isinstance(context_expr, ast.Name): + VarName: str = context_expr.id + if VarName in Gen.var_struct_class: + ClassName = Gen.var_struct_class[VarName] + ctx_val: ir.Value | None = self.HandleExprLlvm(context_expr) + if not ctx_val: + continue + original_ctx_val: ir.Value = ctx_val + if ClassName and isinstance(ctx_val.type, ir.PointerType): + pointee: ir.Type = ctx_val.type.pointee + if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(pointee) + if found: + CN: str = found[0] + ST: ir.Type = found[1] + ClassName = CN + StructPtrType: ir.PointerType | None = ir.PointerType(Gen.structs[ClassName]) if ClassName and ClassName in Gen.structs else None + if StructPtrType and isinstance(ctx_val.type, ir.PointerType) and ctx_val.type.pointee != Gen.structs.get(ClassName): + ctx_val = Gen.builder.bitcast(ctx_val, StructPtrType, name="cast_with_ctx") + ctx_alloca: ir.AllocaInstr = Gen._allocaEntry(ctx_val.type, name="__with_ctx") + Gen._store(ctx_val, ctx_alloca) + Gen._UnregisterTempPtr(ctx_val) + if ClassName: + Gen.var_struct_class['__with_ctx'] = ClassName + Gen._var_to_heap_ptr['__with_ctx'] = ctx_val + original_asname_heap_ptr: ir.Value | None = Gen._var_to_heap_ptr.get(asname) if asname else None + ctx_is_var_ref: bool = isinstance(context_expr, ast.Name) + enter_result: ir.Value | None = None + if ClassName: + # 沿继承链查找 __enter__(子类可能未覆写,使用父类实现) + enter_class, enter_func = self._ResolveInheritedMethod(ClassName, '__enter__', Gen) + if enter_func is not None: + ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx") + # 父类方法需要 self 为父类指针类型,bitcast 子类指针。 + # bitcast 目标用 enter_func 签名参数类型(args[0] 本身即 + # MemManager* 指针),避免 Gen.structs 查找返回 opaque/异 + # sha1 占位对象导致 llvmlite 类型不匹配。 + if enter_class != ClassName: + parent_ptr_type: ir.Type = enter_func.function_type.args[0] + if ctx_Loaded.type != parent_ptr_type: + ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_enter_self") + enter_call: ir.CallInstr = Gen.builder.call(enter_func, [ctx_Loaded], name="call_enter") + enter_result = enter_call + if isinstance(enter_call.type, ir.PointerType): + pointee: ir.Type = enter_call.type.pointee + if isinstance(pointee, ir.PointerType) and isinstance(pointee.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + enter_result = Gen._load(enter_call, name="enter_deref") + elif self._is_char_pointer(enter_call) and StructPtrType: + enter_result = Gen.builder.bitcast(enter_call, StructPtrType, name="cast_enter") + if asname and enter_result: + if isinstance(enter_result.type, ir.PointerType) and isinstance(enter_result.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): + found: tuple[str, ir.Type] | None = Gen.find_struct_by_pointee(enter_result.type.pointee) + if found: + CN: str = found[0] + ST: ir.Type = found[1] + Gen.var_struct_class[asname] = CN + Gen._var_to_heap_ptr[asname] = enter_result + Gen._register_local_heap_ptr(enter_result, VarName=asname) + if asname in Gen._reg_values: + OldVal: ir.Value = Gen._reg_values[asname] + var: ir.AllocaInstr = Gen._allocaEntry(OldVal.type, name=asname) + Gen._store(OldVal, var) + Gen.variables[asname] = var + del Gen._reg_values[asname] + if asname in Gen.variables and Gen.variables[asname] is not None: + VarPtr: ir.Value = Gen.variables[asname] + if VarPtr.type.pointee == enter_result.type: + Gen._store(enter_result, VarPtr) + elif isinstance(VarPtr.type.pointee, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): + CastedVal: ir.Value = Gen.builder.bitcast(enter_result, VarPtr.type.pointee, name=f"cast_{asname}") + Gen._store(CastedVal, VarPtr) + else: + NewVar: ir.AllocaInstr = Gen._alloca(enter_result.type, name=asname) + Gen._store(enter_result, NewVar) + Gen.variables[asname] = NewVar + else: + Gen._reg_values[asname] = enter_result + Gen.variables[asname] = None + # 如果类有 __provides__,自动生成 push 代码 + if ClassName and ClassName in Gen.class_provides: + # 编译期检查: with provider 栈深度是否超过 _MAX_PROVIDER_DEPTH (32) + # _with_provides_stack 只反映当前嵌套路径,顺序执行的 with 会在退出时弹栈 + current_depth: int = sum(len(pl) for pl in Gen._with_provides_stack) + new_fields: int = len(Gen.class_provides[ClassName]) + if current_depth + new_fields > 32: + raise SyntaxError( + f"[TransPyC] with provider stack overflow at line {Node.lineno}: " + f"current depth {current_depth} + new {new_fields} fields > max 32. " + f"Class '{ClassName}' provides too many fields or with nesting too deep." + ) + # 编译期压栈:记录当前 with 上下文提供的字段名,供 __require_must__ 静态检查 + Gen._with_provides_stack.append(Gen.class_provides[ClassName]) + ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx") + ctx_i8: ir.Value = ctx_Loaded + if isinstance(ctx_Loaded.type, ir.PointerType) and ctx_Loaded.type != ir.PointerType(ir.IntType(8)): + ctx_i8 = Gen.builder.bitcast(ctx_Loaded, ir.PointerType(ir.IntType(8)), name="ctx_push_i8") + for field_name in Gen.class_provides[ClassName]: + field_str: ir.Value = Gen._create_string_global(field_name) + push_func = Gen.functions.get('_push_provider') + if push_func: + Gen.builder.call(push_func, [field_str, ctx_i8], name="call_push_provider") + self.Trans.VarScopes.append({}) + if asname: + self.Trans.VarScopes[-1][asname] = True + self.HandleBodyLlvm(Node.body) + if self.Trans.VarScopes: + self.Trans.VarScopes.pop() + # 如果类有 __provides__,自动生成 pop 代码 + if ClassName and ClassName in Gen.class_provides: + for _ in Gen.class_provides[ClassName]: + pop_func = Gen.functions.get('_pop_provider') + if pop_func: + Gen.builder.call(pop_func, [], name="call_pop_provider") + # 编译期弹栈 + if Gen._with_provides_stack: + Gen._with_provides_stack.pop() + if ClassName: + # 沿继承链查找 __exit__(子类可能未覆写,使用父类实现) + exit_class, exit_func = self._ResolveInheritedMethod(ClassName, '__exit__', Gen) + if exit_func is not None: + ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx") + # 父类方法需要 self 为父类指针类型,bitcast 子类指针(同上) + if exit_class != ClassName: + parent_ptr_type: ir.Type = exit_func.function_type.args[0] + if ctx_Loaded.type != parent_ptr_type: + ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_exit_self") + Gen.builder.call(exit_func, [ctx_Loaded], name="call_exit") + Gen._unregister_local_heap_ptr(original_ctx_val) + if ctx_val is not original_ctx_val: + Gen._unregister_local_heap_ptr(ctx_val) + if ctx_is_var_ref and original_asname_heap_ptr and original_asname_heap_ptr is not original_ctx_val and original_asname_heap_ptr is not ctx_val: + Gen._unregister_local_heap_ptr(original_asname_heap_ptr) + if '__with_ctx' in Gen._var_to_heap_ptr: + del Gen._var_to_heap_ptr['__with_ctx'] + if asname and enter_result is not None and isinstance(ctx_val.type, ir.PointerType) and isinstance(enter_result.type, ir.PointerType): + ctx_int: ir.Value = Gen.builder.ptrtoint(ctx_val, ir.IntType(64), name="ctx_int") + enter_int: ir.Value = Gen.builder.ptrtoint(enter_result, ir.IntType(64), name="enter_int") + same_ptr: ir.Value = Gen.builder.icmp_unsigned('==', ctx_int, enter_int, name="same_ptr_check") + with_free_bb: ir.Block = Gen.func.append_basic_block("with_free_ctx") + with_skip_bb: ir.Block = Gen.func.append_basic_block("with_skip_free") + Gen.builder.cbranch(same_ptr, with_skip_bb, with_free_bb) + Gen.builder.position_at_start(with_free_bb) + raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") + free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) + Gen.builder.call(free_func, [raw]) + Gen.builder.branch(with_skip_bb) + Gen.builder.position_at_start(with_skip_bb) + Gen._unregister_local_heap_ptr(enter_result) + Gen._unregister_local_heap_ptr(original_ctx_val) + elif isinstance(ctx_val.type, ir.PointerType): + raw: ir.Value = Gen.builder.bitcast(ctx_val, ir.PointerType(ir.IntType(8)), name="with_free_cast") + free_func: ir.Function = Gen.get_or_declare_c_func('free', ir.FunctionType(ir.VoidType(), [ir.PointerType(ir.IntType(8))])) + Gen.builder.call(free_func, [raw]) Gen._unregister_local_heap_ptr(original_ctx_val) \ No newline at end of file diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index c012f3f..3a172e4 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -1,843 +1,843 @@ -from __future__ import annotations -from typing import Any -import ast -import os -import llvmlite.ir as ir -from lib.includes import t as _t -from lib.includes.t import CTypeRegistry -from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, BuiltinTypeMap - - -class VaArgInstruction(ir.Instruction): - def descr(self, buf: list[str]) -> None: - ptr: ir.Value = self.operands[0] - buf.append("va_arg {0} {1}, {2}\n".format( - ptr.type, ptr.get_reference(), self.type)) - - -class BaseGenMixin: - - @staticmethod - def _parse_triple(triple: str | None) -> dict[str, bool | int]: - """解析目标三元组,返回平台信息字典""" - info: dict[str, bool | int] = { - 'is_windows': False, 'is_linux': False, 'is_macos': False, - 'is_x86_64': False, 'is_arm64': False, 'is_32bit': False, - 'ptr_size': 8, 'long_size': 8, 'wchar_t_size': 32, - } - if not triple: - return info - triple_lower: str = triple.lower() - # 检测操作系统 - if 'windows' in triple_lower or 'win32' in triple_lower or 'mingw' in triple_lower or 'msvc' in triple_lower or 'cygwin' in triple_lower: - info['is_windows'] = True - # Windows LLP64: long = 32 位, wchar_t = 16 位 - info['long_size'] = 32 - info['wchar_t_size'] = 16 - elif 'linux' in triple_lower: - info['is_linux'] = True - elif 'darwin' in triple_lower or 'macos' in triple_lower or 'apple' in triple_lower: - info['is_macos'] = True - # 检测架构 - if 'x86_64' in triple_lower or 'amd64' in triple_lower or 'x64' in triple_lower: - info['is_x86_64'] = True - elif 'aarch64' in triple_lower or 'arm64' in triple_lower: - info['is_arm64'] = True - elif 'i386' in triple_lower or 'i686' in triple_lower or 'arm' in triple_lower: - info['is_32bit'] = True - info['ptr_size'] = 4 - info['long_size'] = 32 - if info['is_windows']: - info['wchar_t_size'] = 16 - else: - info['wchar_t_size'] = 32 - return info - - def __init__(self, triple: str | None = None, datalayout: str | None = None) -> None: - self.module: ir.Module = ir.Module(name="transpyc_module") - if triple: - self.module.triple = triple - else: - self.module.triple = "x86_64-none-elf" - if datalayout: - self.module.data_layout = datalayout - else: - self.module.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" - - # 解析目标平台信息 - self._platform_info: dict[str, bool | int] = self._parse_triple(self.module.triple) - self.ptr_size: int = self._platform_info['ptr_size'] - # 根据目标平台配置 t 模块中的平台相关类型大小 - _t.configure_platform(self.module.triple) - self.builder: ir.IRBuilder | None = None - self.func: ir.Function | None = None - self.functions: dict[str, ir.Function] = {} - self.variables: dict[str, ir.Value | None] = {} - self._direct_values: dict[str, ir.Value] = {} - self._reg_values: dict[str, ir.Value] = {} - self.var_signedness: dict[str, bool] = {} - self._unsigned_results: set[int] = {} - self.string_const_counter: int = 0 - self.Vtables: dict[str, ir.GlobalVariable] = {} - self.class_methods: dict[str, list[str]] = {} - self.class_members: dict[str, list[tuple[str, ir.Type]]] = {} - self.class_member_defaults: dict[str, dict[str, Any]] = {} - self.class_member_signeds: dict[str, dict[str, bool]] = {} - self.class_member_bitfields: dict[str, dict[str, int]] = {} - self.class_member_byteorders: dict[str, dict[str, str]] = {} - self.local_var_byteorders: dict[str, str] = {} - self.class_member_element_class: dict[str, dict[str, str]] = {} - self.class_member_bitoffsets: dict[str, dict[str, int]] = {} - self.structs: dict[str, ir.IdentifiedStructType] = {} - self.typedef_int_widths: dict[str, int] = {} # typedef名称 -> 底层整数位宽 (如 'UINT' -> 32, 'BYTE' -> 8) - self._cross_module_vtable_classes: set[str] = set() - self._cross_module_novtable: set[str] = set() - self.class_vtable: set[str] = set() - self._class_graph: dict[str, Any] = {} - self.class_parent: dict[str, str] = {} - # 多继承:父类名数组(声明顺序)。class_parent 兼容保留为第一个父类。 - self.class_parents: dict[str, list[str]] = {} - # Store member annotations for deferred type resolution (cross-module class references) - self.class_member_annotations: dict[str, dict[str, Any]] = {} - self.loop_break_targets: list[ir.Block] = [] - self.loop_continue_targets: list[ir.Block] = [] - self.eh_jmp_buf_stack: list[ir.Value] = [] - self.eh_except_block_stack: list[ir.Block] = [] - self.eh_finally_stack: list[Any] = [] - self.global_vars: set[str] = set() - self.nonlocal_params: dict[str, Any] = {} - self._variable_scope_stack: list[dict[str, Any]] = [] # Stack of outer scope variables for nested function nonlocal lookup - self.var_struct_class: dict[str, str] = {} - self.var_ptr_element: dict[str, bool] = {} - # 全局变量的指针元素标志(持久,不受函数重置影响) - # 用于全局变量 _argv: bytes | t.CPtr 等,使 _argv[index] 使用 8 字节指针步长 - self.global_var_ptr_element: dict[str, bool] = {} - self.class_provides: dict[str, list[str]] = {} - self.class_requires: dict[str, list[str]] = {} - self.class_require_must: dict[str, list[str]] = {} - # 编译期 with 上下文栈:记录当前嵌套 with 链中所有可用的 provides 字段名 - # 用于 __require_must__ 的纯编译期静态可达性检查 - self._with_provides_stack: list[list[str]] = [] - # 函数参数自动取地址模式: func_name -> [None, None, 'need', 'always', ...] - # 'need': t.CNeedPtr — 仅对非指针值取地址 - # 'always': t.CAutoPtr — 无条件取地址 - self._auto_addr_params: dict[str, list[str | None]] = {} - self.global_struct_class: dict[str, str] = {} - self.var_type_info: dict[str, Any] = {} - self.var_const_flags: dict[str, bool] = {} - self._current_source_file: str | None = None - self._current_source_lines: list[str] = [] - self._ns_cache: dict[str, str] = {} - self._type_cache: dict[tuple[str, bool], ir.Type] = {} - self._typedef_cache: dict[str, Any] = {} - self._func_sig_cache: dict[str, Any] = {} - self.var_type_assignments: dict[str, Any] = {} - self._temp_struct_ptrs: list[ir.Value] = [] - self._stop_iter_flag_param: ir.Value | None = None - self._local_heap_ptrs: list[tuple[ir.Value, str, str | None]] = [] - self._var_to_heap_ptr: dict[str, ir.Value] = {} - self.known_return_types: dict[str, ir.Type] = {} - self._current_lineno: int = 0 - self._current_node_info: str = "" - self.module_sha1: str | None = None - self.ModuleSha1Map: dict[str, str] = {} - self._temp_dir: str | None = None - self._export_funcs: set[str] = set() - self._export_extern_funcs: dict[str, str] = {} - self._current_module_func_names: set[str] = set() - # __doc__ 魔法字符串注册表:symbol_name -> docstring 文本(None 表示空/优化剥离) - self._doc_strings: dict[str, str | None] = {} - self.class_packed: set[str] = set() - self._define_constants: dict[str, int] = {} - # 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射 - self._struct_sha1_map: dict[str, str] = {} - self.SymbolTable: Any = None - self._Trans: Any = None - self.class_sha1_map: dict[str, str] = {} - # 以下属性原先懒注入,此处显式初始化以消除 hasattr/getattr 动态反射 - self._import_handler_ref: Any = None - self._classes_in_progress: set[str] = set() - # 字段收集期间添加当前类名,阻止 CollectAnnAssignMember 触发的嵌套 - # _generate_structs 用不完整 class_members 调用 set_body(set_body 只能调用一次) - # 用集合而非单值,因为嵌套特化类 _EmitClassLlvm 会清除单值,导致外层类被错误设置 body - self._collecting_members_set: set[str] = set() - self._last_var_name: str | None = None - self._variadic_info: dict | None = None - self._vtable_copy_counter: int = 0 - self._decorated_funcs: dict = {} - self._current_tree: Any = None - self._DefineConstants: dict = {} - self._all_define_constants: dict = {} - # 闭包追踪:记录返回闭包的函数和变量 - # _closure_return_types: func_name -> (fn_return_type, nonlocal_arg_types) - self._closure_return_types: dict[str, tuple[Any, list[Any]]] = {} - # _closure_var_types: var_name -> (fn_return_type, nonlocal_arg_types) - self._closure_var_types: dict[str, tuple[Any, list[Any]]] = {} - pi: dict[str, bool | int] = self._platform_info - # 根据目标平台设置宏(声明式,从三元组推导) - if pi['is_windows']: - self._define_constants['_WIN32'] = 1 - if not pi['is_32bit']: - self._define_constants['_WIN64'] = 1 - self._define_constants['WIN64'] = 1 - self._define_constants['WIN32'] = 1 - if pi['is_linux']: - self._define_constants['__linux__'] = 1 - if pi['is_macos']: - self._define_constants['__APPLE__'] = 1 - self._define_constants['__MACH__'] = 1 - if pi['is_x86_64']: - self._define_constants['__x86_64__'] = 1 - self._define_constants['__x86_64'] = 1 - self._define_constants['_M_X64'] = 1 - elif pi['is_arm64']: - self._define_constants['__aarch64__'] = 1 - self._define_constants['_M_ARM64'] = 1 - if not pi['is_32bit'] and pi['is_linux']: - self._define_constants['__LP64__'] = 1 - elif pi['is_32bit']: - self._define_constants['_ILP32'] = 1 - self._define_constants['SIZEOF_VOID_P'] = pi['ptr_size'] - self._define_constants['__SIZEOF_POINTER__'] = pi['ptr_size'] - - def find_struct_by_pointee(self, pointee: ir.Type) -> tuple[str, ir.IdentifiedStructType] | None: - """根据 pointee 类型查找匹配的结构体,返回 (class_name, struct_type) 或 None""" - for class_name, struct_type in self.structs.items(): - if pointee == struct_type: - return (class_name, struct_type) - return None - - @staticmethod - def _extract_short_name(name: str) -> str: - """从结构体类型名中提取短名(去掉 sha1 前缀)。 - 如 "6bc91356c652f8ca.Function" → "Function" - 如 "Function" → "Function"(无 sha1 前缀时原样返回) - """ - if '.' in name: - prefix: str = name.split('.', 1)[0] - if len(prefix) == 16 and all(c in '0123456789abcdef' for c in prefix): - return name.split('.', 1)[1] - return name - - @staticmethod - def _extract_struct_sha1(st: ir.IdentifiedStructType) -> str: - """从 IdentifiedStructType 的 name 中提取 sha1 前缀(16 位十六进制)。 - 返回空字符串表示无 sha1 前缀。用于同名类冲突检测。 - """ - if not isinstance(st, ir.IdentifiedStructType): - return '' - try: - name: str = st.name - except (AssertionError, AttributeError): - return '' - if '.' in name: - prefix: str = name.split('.', 1)[0] - if len(prefix) == 16 and all(c in '0123456789abcdef' for c in prefix): - return prefix - return '' - - def _get_or_create_struct(self, name: str, source_sha1: str | None = None, packed: bool = False) -> ir.IdentifiedStructType: - clean_name: str = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_') - # 如果名称包含模块前缀(如 "a9fa0f6200c09e65.zbit_writer"), - # 先尝试用短名称(如 "zbit_writer")查找已注册的 struct, - # 避免为同一 struct 创建多个不同的类型对象导致跨模块引用类型不一致 - if '.' in clean_name and clean_name not in self.structs: - parts: list[str] = clean_name.split('.', 1) - if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]): - short_name: str = parts[1] - if short_name in self.structs: - existing_short: ir.IdentifiedStructType = self.structs[short_name] - # 治本修复:同名类 sha1 冲突检测。 - # 当请求的 sha1 前缀与现有 struct 的 sha1 前缀不一致时 - # (如 stmts.py:Module 与 __module.py:Module 同名冲突), - # 不能复用已有 struct(set_body 已锁定为错误布局), - # 需创建独立 struct 并以 sha1 前缀全名存储。 - _existing_sha1: str = self._extract_struct_sha1(existing_short) - if _existing_sha1 and _existing_sha1 != parts[0]: - if clean_name in self.structs: - return self.structs[clean_name] - st_new: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=clean_name, packed=packed) - self.structs[clean_name] = st_new - return st_new - return existing_short - # 优先解析 typedef 整数类型(如 INT/UINT/BYTE),避免将其注册为 opaque struct。 - # 必须在 `if clean_name in self.structs` 缓存检查之前执行, - # 否则首次调用(SymbolTable 未就绪时)会将 typedef 名缓存为 opaque struct, - # 后续调用即使 SymbolTable 就绪也只会返回缓存的错误类型。 - # 此修复同时解决两个问题: - # 1. alloca unsized type:变量声明 `argc: INT = 6` 不再生成 `alloca %"...INT"` - # 2. 下标访问:FindStructNameInAnnotation 不再匹配 typedef 名(因不在 Gen.structs) - td_width: int | None = self._resolve_typedef_int_width(clean_name) - if td_width is not None: - if td_width > 0: - self.typedef_int_widths[clean_name] = td_width - return ir.IntType(td_width) - # td_width == 0: 特殊 typedef 名称(str/bytes/list 等),返回 i8 - self.typedef_int_widths[clean_name] = 0 - return ir.IntType(8) - if clean_name in self.structs: - existing: ir.IdentifiedStructType = self.structs[clean_name] - # 治本修复:同名类 sha1 冲突检测(短名调用路径)。 - # 当 source_sha1 与现有 struct 的 sha1 前缀不一致时(跨模块同名类冲突), - # 不能复用已有 struct(set_body 已锁定为错误布局), - # 需创建独立 struct 并以 sha1 前缀全名存储,不覆盖短名条目。 - if source_sha1: - _existing_sha1: str = self._extract_struct_sha1(existing) - if _existing_sha1 and _existing_sha1 != source_sha1: - full_key: str = f"{source_sha1}.{clean_name}" - if full_key in self.structs: - st_full: ir.IdentifiedStructType = self.structs[full_key] - if packed and isinstance(st_full, ir.IdentifiedStructType) and not st_full.packed: - st_full.packed = True - return st_full - ns_name: str = f"{source_sha1}.{clean_name}" - st_new: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed) - self.structs[full_key] = st_new - return st_new - 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'}: - return ir.IntType(8) - # typing.Any 是"任意类型"标记,应解析为 i8*(通用指针), - # 而非创建为 opaque 结构体(否则包含 Any 字段的结构体会变成 unsized)。 - if clean_name == 'Any': - return ir.IntType(8).as_pointer() - # t.CType 的基本类型子类(CInt/CChar/CSizeT/CLong/CFloat/CDouble 等, - # position 含 BASE 且 Size>0)有具体 LLVM 类型,应直接返回对应的 - # ir.IntType/ir.FloatType/ir.DoubleType,而非创建结构体。 - # _is_ctype_marker_name 对这些类型返回 False(不跳过),需要在此处拦截。 - _basic_llvm_type: ir.Type | None = self._try_resolve_ctype_basic(clean_name) - if _basic_llvm_type is not None: - return _basic_llvm_type - # t.CType 及其子类是"类型强转"标记,不应被编译为真实结构体。 - # 动态检查 t 模块中所有 CType 子类名(排除 CStruct/CEnum/CUnion/REnum 子类, - # 因为用户定义的结构体类继承自它们,需要被创建为结构体)。 - if self._is_ctype_marker_name(clean_name): - return ir.IntType(8) - if self.SymbolTable: - Entry: _CTypeInfo | None = self.SymbolTable.lookup(clean_name) - if Entry and Entry.IsTypedef: - resolved_str: str = self._resolve_typedef(clean_name) - if resolved_str != clean_name: - return self._type_str_to_llvm(resolved_str) - if Entry.BaseType: - if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0: - resolved: str = self._resolve_ctype_to_str(Entry) - if resolved: - return self._type_str_to_llvm(resolved) - if Entry and Entry.IsRenum: - if clean_name in self.structs: - return self.structs[clean_name] - # REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32), - # 需要继续到下方正常结构体创建路径,创建 opaque 结构体。 - # 这对自引用 REnum(如 LLVMType 包含 LLVMType*)至关重要: - # _parse_llvm_type 先通过此路径创建 opaque 结构体,_TryLoadStructFromStub 再 set_body。 - elif Entry and Entry.IsEnum and clean_name not in self.class_methods: - return ir.IntType(32) - # 治本修复:当 clean_name 是已注册的类(在 class_methods 或 class_members 中)时, - # 不应走 IsExceptionClass/IsFunction/IsVariable 分支返回非结构体类型。 - # 否则 _get_or_create_struct 返回指针类型(如 _TypedPointerType)而非 IdentifiedStructType, - # 导致 _TryLoadStructFromStub 的 set_body 被跳过(isinstance 检查失败), - # struct 保持不完整字段数,引发跨模块 GEP 越界崩溃。 - _is_class_name: bool = clean_name in self.class_methods or clean_name in self.class_members - if Entry and Entry.IsExceptionClass and not _is_class_name: - return ir.IntType(32) - if Entry and Entry.IsFunction and not _is_class_name: - return ir.PointerType(ir.IntType(8)) - if Entry and Entry.IsVariable and not _is_class_name: - return ir.PointerType(ir.IntType(8)) - if Entry and Entry.BaseType: - if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum): - return ir.IntType(32) - if Entry.BaseType is _t.CEnum: - return ir.IntType(32) - ns_name: str - if source_sha1: - ns_name = f"{source_sha1}.{clean_name}" - elif clean_name in self._struct_sha1_map: - ns_name = f"{self._struct_sha1_map[clean_name]}.{clean_name}" - else: - ns_name = self._mangle_name(clean_name) - st: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed) - self.structs[clean_name] = st - # 尝试解析 typedef 的底层整数位宽 - width: int | None = self._resolve_typedef_int_width(clean_name) - if width is not None: - self.typedef_int_widths[clean_name] = width - return st - - def _resolve_typedef_int_width(self, name: str) -> int | None: - """解析 typedef 名称的底层整数位宽 - - 通过 CTypeRegistry 和 BuiltinTypeMap 动态解析, - 替代硬编码的 TYPEDEF_NAMES 映射表。 - 返回 int 位宽或 None(无法解析)。 - """ - # 1. 先查 BuiltinTypeMap(覆盖 BYTEPTR 等指针别名) - bm: Any = BuiltinTypeMap.Get(name) - if bm: - ctype_cls: Any - ptr_count: int - ctype_cls, ptr_count = bm - if ptr_count > 0: - return None # 指针类型,不是整数 typedef - llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls) - if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): - return int(llvm_str[1:]) - - # 2. 再查 SymbolTable(用户定义的 typedef) - if self.SymbolTable: - Entry: _CTypeInfo | None = self.SymbolTable.lookup(name) - if Entry and Entry.IsTypedef: - if Entry.BaseType: - if not isinstance(Entry.BaseType, (_t._CTypedef,)) and Entry.PtrCount == 0: - llvm_str: str = CTypeRegistry.CTypeToLLVM(type(Entry.BaseType) if isinstance(Entry.BaseType, _t.CType) else Entry.BaseType) - if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): - return int(llvm_str[1:]) - if Entry.OriginalType: - if isinstance(Entry.OriginalType, _CTypeInfo) and Entry.OriginalType.BaseType: - if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and Entry.OriginalType.PtrCount == 0: - llvm_str: str = CTypeRegistry.CTypeToLLVM(type(Entry.OriginalType.BaseType) if isinstance(Entry.OriginalType.BaseType, _t.CType) else Entry.OriginalType.BaseType) - if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): - return int(llvm_str[1:]) - elif isinstance(Entry.OriginalType, str): - # OriginalType 是类型名字符串(如 'CInt', 'CUnsignedInt'), - # 通过 CTypeRegistry 解析为整数位宽 - cls: Any = CTypeRegistry.GetClassByName(Entry.OriginalType) - if cls: - llvm_str: str = CTypeRegistry.CTypeToLLVM(cls) - if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): - return int(llvm_str[1:]) - - # 3. 尝试 CTypeRegistry 直接按名称查找 - ctype_cls: Any = CTypeRegistry.GetClassByName(name) - if ctype_cls: - llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls) - if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): - return int(llvm_str[1:]) - - # 4. 特殊名称(非整数类型,但需要标记为 typedef 以跳过 opaque 定义) - # 注意:如果 name 已注册为 struct(用户定义了同名 class,如 includes/_dict.py 中的 dict), - # 则不应视为 typedef,应返回 None 让调用方走 struct 创建路径。 - # 解决时序问题:_parse_llvm_declare 从 stub.ll 解析时 dict 可能尚未注册到 Gen.structs, - # 但 SymbolTable 在 .pyi 解析阶段已就绪,可通过 is_struct 检查区分 class 和 typedef。 - _SPECIAL_TYPEDEFS: set[str] = { - 'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', - 'CStruct', 'enum', 'REnum', 'renum', - 'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', 'type', 'CArray', - } - if name in _SPECIAL_TYPEDEFS: - if name in self.structs: - return None # 已注册为 struct,不视为 typedef - if self.SymbolTable is not None: - try: - if self.SymbolTable.is_struct(name): - return None # SymbolTable 中标记为 struct,不视为 typedef - except Exception: - pass - return 0 # 标记为 typedef,但位宽为 0(非整数) - - # t.CType 及其子类是"类型强转"标记,不应被创建为结构体。 - # 动态检查 t 模块中所有 CType 子类名(排除 CStruct/CEnum/CUnion/REnum 子类)。 - # 返回 0 标记为 typedef,使 _get_or_create_struct 走 typedef 路径返回 i8。 - if self._is_ctype_marker_name(name): - return 0 - - return None - - @staticmethod - def _is_ctype_marker_name(name: str) -> bool: - """检查名称是否是 t.CType 的"类型强转"标记子类名。 - - 只有 position 不含 BASE 的纯修饰符/标记类型(CPtr/CVolatile/CConst/ - CInline/CStatic/CExtern/CExport/CRegister/CAuto/_CTypedef/CTypeDefault 等) - 才应该跳过结构体创建。有 BASE position 的基本类型(CInt/CChar/CSizeT/ - CLong/CFloat/CDouble 等)有具体大小,应被正常解析为对应宽度的整数/浮点。 - - CStruct/CEnum/CUnion/REnum 的用户子类是合法结构体,需要被创建。 - - 注意:CTypeRegistry.GetClassByName 会跳过 CType 本身和 CTypeDefault, - 所以这里直接用 getattr(t, name) 检查 t 模块属性。 - - Returns: - True 如果 name 是 CType 标记子类名(应跳过结构体创建) - """ - if not name: - return False - # 去除可能的 SHA1 前缀(如 "abc123.CPtr" -> "CPtr") - short_name: str = name.split('.')[-1] if '.' in name else name - # 直接查 t 模块属性(CTypeRegistry._build 会跳过 CType/CTypeDefault/BigEndian/LittleEndian) - t_cls: Any = getattr(_t, short_name, None) - if not isinstance(t_cls, type) or not issubclass(t_cls, _t.CType): - return False - # 排除 CStruct/CEnum/CUnion/REnum 子类(它们是命名类型的基类, - # 用户定义的结构体继承自它们,需要被创建为结构体) - if issubclass(t_cls, (_t.CStruct, _t.CEnum, _t.REnum, _t.CUnion)): - return False - # 基本类型(position 含 BASE 且 Size > 0)有具体大小,不应跳过 - # (CInt→i32, CChar→i8, CSizeT→i64, CLong→i64, CFloat→f32 等) - # CVoid 虽含 BASE 但 Size=0,CType Size=None,仍需跳过 - if _t.CType.BASE in t_cls.position: - # 检查实例的 Size(类属性可能未设置,用实例获取) - try: - inst = t_cls() - size_val = getattr(inst, 'Size', None) - if size_val is not None and size_val > 0: - return False - except Exception: - pass - return True - - def _try_resolve_ctype_basic(self, name: str) -> ir.Type | None: - """尝试将 t.CType 的基本类型子类名解析为对应的 LLVM 基本类型。 - - 仅对 t 模块内的 CType 基本类型子类(CInt/CChar/CSizeT/CLong/CFloat/ - CDouble 等,即 position 含 BASE 且 Size>0)生效,返回对应的 - ir.IntType/ir.FloatType/ir.DoubleType。 - - CStruct/CEnum/CUnion/REnum 子类不在此处理(用户自定义结构体需要被 - 创建为结构体)。CVoid/CType/CPtr 等无 Size 或 Size=0 的类型也不在此 - 处理(应通过 _is_ctype_marker_name 跳过结构体创建)。 - - Returns: - 对应的 ir.Type,或 None 表示不是基本类型,需要继续走结构体创建路径。 - """ - if not name: - return None - short_name: str = name.split('.')[-1] if '.' in name else name - cls: Any = getattr(_t, short_name, None) - if not isinstance(cls, type) or not issubclass(cls, _t.CType): - return None - if issubclass(cls, (_t.CStruct, _t.CEnum, _t.REnum, _t.CUnion)): - return None - if _t.CType.BASE not in getattr(cls, 'position', frozenset()): - return None - try: - inst = cls() - size_val = getattr(inst, 'Size', None) - if size_val is None or size_val <= 0: - return None - except Exception: - return None - llvm_str: str | None = CTypeRegistry.NameToLLVM(short_name) - if not llvm_str: - return None - return self._type_str_to_llvm(llvm_str) - - def _set_node_info(self, node: ast.AST, extra_info: str = "") -> None: - if hasattr(node, 'lineno'): - self._current_lineno = node.lineno - else: - self._current_lineno = 0 - if hasattr(node, 'col_offset'): - self._current_node_info = f"line {self._current_lineno}, col {node.col_offset}" - else: - self._current_node_info = f"line {self._current_lineno}" - if extra_info: - self._current_node_info += f" ({extra_info})" - - def _set_source_info(self, filepath: str) -> None: - self._current_source_file = filepath - try: - with open(filepath, 'r', encoding='utf-8') as f: - self._current_source_lines = f.readlines() - except Exception: # 文件读取失败时回退为空行列表 - self._current_source_lines = [] - - def _skip_mangle(self, name: str) -> bool: - skip_prefixes: tuple[str, ...] = ('llvm.', 'str_const_', 'printf', 'memset_pattern') - if any(name.startswith(p) for p in skip_prefixes): - return True - if '.' in name: - parts: list[str] = name.split('.', 1) - if len(parts[0]) >= 8 and all(c in '0123456789abcdef' for c in parts[0]): - return True - return False - - def _mangle_name(self, name: str) -> str: - if self._skip_mangle(name): - return name - if name in self._export_funcs: - return name - if self.module_sha1: - return f"{self.module_sha1}.{name}" - return name - - def _find_function(self, name: str) -> ir.Function | None: - if name in self.functions: - return self.functions[name] - g: Any = self.module.globals.get(name) - if g and isinstance(g, ir.Function): - self.functions[name] = g - return g - mangled: str = self._mangle_func_name(name) - if mangled != name: - if mangled in self.functions: - self.functions[name] = self.functions[mangled] - return self.functions[mangled] - g = self.module.globals.get(mangled) - if g and isinstance(g, ir.Function): - self.functions[mangled] = g - self.functions[name] = g - return g - for sha1 in self.ModuleSha1Map.values(): - prefixed: str = f"{sha1}.{name}" - if prefixed in self.functions: - self.functions[name] = self.functions[prefixed] - return self.functions[prefixed] - g = self.module.globals.get(prefixed) - if g and isinstance(g, ir.Function): - self.functions[prefixed] = g - self.functions[name] = g - return g - return None - - def _has_function(self, name: str) -> bool: - return self._find_function(name) is not None - - def _get_mro_chain(self, ClassName: str) -> list[str]: - """MRO 线性化类名列表(深度优先 + 声明顺序 + 去重,含自身)。 - - 顺序: 自身 → 父类1 及祖先 → 父类2 及祖先(先声明父类优先,菱形去重)。 - 与 TPV HandlesStruct.get_mro_chain 的语义一致。 - """ - chain: list[str] = [] - visited: set[str] = set() - stack: list[str] = [ClassName] - parents_map: dict[str, list[str]] = getattr(self, 'class_parents', {}) - while stack: - cur: str = stack.pop() - if not cur or cur in visited: - continue - visited.add(cur) - chain.append(cur) - parents: list[str] = parents_map.get(cur, []) - # 父类逆序压栈,保证声明顺序弹出(先访问父类1 的整条链) - for p in reversed(parents): - if p and p not in visited: - stack.append(p) - return chain - - def _get_parent_classes(self, ClassName: str) -> list[str]: - """获取类的所有父类名(声明顺序),兼容旧 class_parent 单链。""" - parents_map: dict[str, list[str]] = getattr(self, 'class_parents', {}) - parents: list[str] = parents_map.get(ClassName) - if parents: - return parents - p: str | None = self.class_parent.get(ClassName) - if p: - return [p] - return [] - - def _get_or_declare_function(self, mangled_name: str, func_type: ir.FunctionType) -> ir.Function: - # DDEBUG: 检测 mangled_name 含双点(不应到达这里) - if '..' in mangled_name: - import sys - sys.stderr.write(f"[DDEBUG] _get_or_declare_function DOUBLE-DOT mangled_name='{mangled_name}'\n") - import traceback - traceback.print_stack(file=sys.stderr, limit=10) - sys.stderr.flush() - sys.exit(1) - g = self.module.globals.get(mangled_name) - if g and isinstance(g, ir.Function): - return g - return ir.Function(self.module, func_type, name=mangled_name) - - def _get_function(self, name: str) -> ir.Function | None: - func: ir.Function | None = self._find_function(name) - return func - - def _mangle_func_name(self, name: str, module_name: str | None = None) -> str: - # DDEBUG: 检测即将产生双点的情况,立即打印并终止 - if name.startswith('.') or (module_name and module_name.endswith('.') and len(module_name) > 0): - import sys - sys.stderr.write(f"[DDEBUG] _mangle_func_name LEADING-DOT name='{name}' module_name='{module_name}'\n") - import traceback - traceback.print_stack(file=sys.stderr, limit=8) - sys.stderr.flush() - sys.exit(1) - if name in self._export_funcs and not module_name: - return name - if name in self._export_extern_funcs: - target_sha1: str = self._export_extern_funcs[name] - if module_name: - # 显式带 module_name 调用(如 stdlib.system):即使当前模块定义了同名函数, - # 也应按模块匹配 extern,返回裸名。snprintf 之所以工作而 system 不工作, - # 就是因为 os._win32 定义了自己的 system 包装,导致旧逻辑跳过了 extern 匹配。 - if module_name == target_sha1: - return name - if module_name in self.ModuleSha1Map and self.ModuleSha1Map[module_name] == target_sha1: - return name - init_name: str = f"{module_name}.__init__" - if init_name in self.ModuleSha1Map and self.ModuleSha1Map[init_name] == target_sha1: - return name - # 兜底:module_name 不在 ModuleSha1Map 中或 sha1 不匹配, - # 但函数在 _export_extern_funcs 中(C extern 不应混淆), - # 仅当当前模块未定义同名函数时才返回裸名。 - if name not in self._current_module_func_names: - return name - elif name not in self._current_module_func_names: - # 无 module_name 调用(如 from stdlib import system; system()): - # 仅当当前模块未定义同名函数时才返回 extern 裸名, - # 否则让本地定义走正常 mangle 路径(本地 def 遮蔽 import 语义)。 - return name - # main 函数作为程序入口点,永远不混淆 - if name == 'main': - return name - # Try class_sha1_map first for class methods (e.g., 'md5.__init__' -> class 'md5') - class_sha1_map: dict[str, str] = self.class_sha1_map - if class_sha1_map: - if '.' in name: - base_class: str = name.split('.')[0] - if base_class in class_sha1_map: - sha1: str = class_sha1_map[base_class] - return f"{sha1}.{name}" - elif name in class_sha1_map: - sha1: str = class_sha1_map[name] - return f"{sha1}.{name}" - # If module_name is already a SHA1 hash (16 hex chars), use it directly - if module_name and len(module_name) == 16 and all(c in '0123456789abcdef' for c in module_name): - return f"{module_name}.{name}" - if module_name and module_name in self.ModuleSha1Map: - sha1: str = self.ModuleSha1Map[module_name] - return f"{sha1}.{name}" - # Try parent package name (e.g., 'hashlib' -> 'hashlib.__init__') - if module_name: - init_name: str = f"{module_name}.__init__" - if init_name in self.ModuleSha1Map: - sha1: str = self.ModuleSha1Map[init_name] - return f"{sha1}.{name}" - if self._skip_mangle(name): - return name - if self.module_sha1: - result = f"{self.module_sha1}.{name}" - else: - result = name - # DDEBUG: 检测返回结果中是否含双点 - if '..' in result: - import sys - sys.stderr.write(f"[DDEBUG] _mangle_func_name RESULT-DOUBLE-DOT name='{name}' module_name='{module_name}' result='{result}'\n") - import traceback - traceback.print_stack(file=sys.stderr, limit=10) - sys.stderr.flush() - sys.exit(1) - return result - - def _get_source_line(self, lineno: int) -> str | None: - if 0 < lineno <= len(self._current_source_lines): - return self._current_source_lines[lineno - 1].rstrip('\r\n') - return None - - def _get_node_info(self) -> str: - info: str = "" - if self._current_node_info: - info = f" [{self._current_node_info}]" - if self._current_source_file: - info += f" in {self._current_source_file}" - lineno: int = self._current_lineno - if lineno > 0: - info += f", line {lineno}:" - source_line: str | None = self._get_source_line(lineno) - if source_line: - info += f"\n → {source_line}" - return info - - # ========== 统一工具方法 ========== - - def _create_string_global(self, s: str, name: str | None = None) -> ir.Constant: - """创建字符串全局变量并返回 i8* 指针。 - - 统一字符串全局变量创建模式:编码为 utf-8 + '\\x00' 终止符, - 创建 internal linkage 的 GlobalVariable,返回 i8* 指针常量。 - """ - str_val: str = s + '\x00' - str_bytes: bytes = str_val.encode('utf-8') - arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes)) - gv_name: str = name or f"str_const_{self.string_const_counter}" - self.string_const_counter += 1 - gv: ir.GlobalVariable = ir.GlobalVariable(self.module, arr_type, name=gv_name) - gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) - gv.linkage = 'internal' - return ir.Constant(ir.PointerType(ir.IntType(8)), gv.get_reference()) - - def _create_doc_global(self, symbol_name: str, docstring: str | None) -> None: - """为符号创建 __doc__ 全局常量。 - - - docstring 为 None 或空字符串时,不创建常量(访问时内联空指针) - - slice_level != 0(优化开启)时,内容视为空 - - 非空时创建 internal linkage、global_constant=True 的只读字符串常量 - - 常量名格式:{module_sha1}.{symbol_name}.__doc__ - """ - slice_level: int = getattr(self._Trans, 'SliceLevel', 3) - if slice_level != 0: - docstring = None - if docstring is None or docstring == '': - self._doc_strings[symbol_name] = None - return - self._doc_strings[symbol_name] = docstring - mangled: str = self._mangle_name(f"{symbol_name}.__doc__") - self._create_string_global(docstring, name=mangled) - gv: ir.GlobalVariable | None = self.module.globals.get(mangled) - if gv is not None: - gv.global_constant = True - - def _get_doc_ptr(self, symbol_name: str) -> ir.Value | None: - """获取符号 __doc__ 的 i8* 指针。 - - - 若符号未注册 __doc__,返回 None(调用方回退到其他解析) - - 若 __doc__ 为空(无 docstring 或优化剥离),返回 i8* null 内联空指针 - - 若 __doc__ 非空,返回指向字符串全局常量的 i8* 指针 - - 跨模块 docstring(在 _doc_strings 中有文本但 module.globals 无对应常量)首次访问时创建本地 internal linkage 只读副本 - """ - if symbol_name not in self._doc_strings: - return None - docstring: str | None = self._doc_strings[symbol_name] - if docstring is None or docstring == '': - return ir.Constant(ir.PointerType(ir.IntType(8)), None) - mangled: str = self._mangle_name(f"{symbol_name}.__doc__") - gv: ir.GlobalVariable | None = self.module.globals.get(mangled) - if gv is None: - # 跨模块 docstring:创建本地 internal linkage 只读字符串常量副本 - self._create_string_global(docstring, name=mangled) - gv = self.module.globals.get(mangled) - if gv is None: - return ir.Constant(ir.PointerType(ir.IntType(8)), None) - gv.global_constant = True - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - return self.builder.gep(gv, [zero, zero], name=f"{symbol_name}_doc_ptr") - - def _apply_bswap_if_big(self, val: ir.Value, byte_order: str, name: str) -> ir.Value: - """大端字节序时对整数应用 bswap,否则原值返回。 - - 仅对 16/32/64 位整数生效,统一 bswap 逻辑。 - """ - if byte_order == 'big' and isinstance(val.type, ir.IntType) and val.type.width in (16, 32, 64): - return self.builder.bswap(val, name=name) - return val - - def _zero_value_for_type(self, llvm_type: ir.Type) -> ir.Constant | None: - """为指定 LLVM 类型生成零值常量。 - - 合并原 HandlesAssign._zero_value 与 StructGen._zero_value_for_type 的逻辑。 - 返回 ir.Constant 或 None(无法生成零值的类型,如 opaque struct)。 - """ - if isinstance(llvm_type, ir.IntType): - return ir.Constant(llvm_type, 0) - elif isinstance(llvm_type, (ir.FloatType, ir.DoubleType)): - return ir.Constant(llvm_type, 0.0) - elif isinstance(llvm_type, ir.PointerType): - return ir.Constant(llvm_type, None) - elif isinstance(llvm_type, ir.ArrayType): - elem_zv: ir.Constant | None = self._zero_value_for_type(llvm_type.element) - if elem_zv is None: - return None - return ir.Constant(llvm_type, [elem_zv] * llvm_type.count) - elif isinstance(llvm_type, ir.BaseStructType): - if llvm_type.elements is not None and len(llvm_type.elements) > 0: - elem_zvs: list[ir.Constant | None] = [self._zero_value_for_type(m) for m in llvm_type.elements] - if any(zv is None for zv in elem_zvs): - return None - return ir.Constant(llvm_type, elem_zvs) - return None +from __future__ import annotations +from typing import Any +import vast as ast +import os +import llvmlite.ir as ir +from lib.includes import t as _t +from lib.includes.t import CTypeRegistry +from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, BuiltinTypeMap + + +class VaArgInstruction(ir.Instruction): + def descr(self, buf: list[str]) -> None: + ptr: ir.Value = self.operands[0] + buf.append("va_arg {0} {1}, {2}\n".format( + ptr.type, ptr.get_reference(), self.type)) + + +class BaseGenMixin: + + @staticmethod + def _parse_triple(triple: str | None) -> dict[str, bool | int]: + """解析目标三元组,返回平台信息字典""" + info: dict[str, bool | int] = { + 'is_windows': False, 'is_linux': False, 'is_macos': False, + 'is_x86_64': False, 'is_arm64': False, 'is_32bit': False, + 'ptr_size': 8, 'long_size': 8, 'wchar_t_size': 32, + } + if not triple: + return info + triple_lower: str = triple.lower() + # 检测操作系统 + if 'windows' in triple_lower or 'win32' in triple_lower or 'mingw' in triple_lower or 'msvc' in triple_lower or 'cygwin' in triple_lower: + info['is_windows'] = True + # Windows LLP64: long = 32 位, wchar_t = 16 位 + info['long_size'] = 32 + info['wchar_t_size'] = 16 + elif 'linux' in triple_lower: + info['is_linux'] = True + elif 'darwin' in triple_lower or 'macos' in triple_lower or 'apple' in triple_lower: + info['is_macos'] = True + # 检测架构 + if 'x86_64' in triple_lower or 'amd64' in triple_lower or 'x64' in triple_lower: + info['is_x86_64'] = True + elif 'aarch64' in triple_lower or 'arm64' in triple_lower: + info['is_arm64'] = True + elif 'i386' in triple_lower or 'i686' in triple_lower or 'arm' in triple_lower: + info['is_32bit'] = True + info['ptr_size'] = 4 + info['long_size'] = 32 + if info['is_windows']: + info['wchar_t_size'] = 16 + else: + info['wchar_t_size'] = 32 + return info + + def __init__(self, triple: str | None = None, datalayout: str | None = None) -> None: + self.module: ir.Module = ir.Module(name="transpyc_module") + if triple: + self.module.triple = triple + else: + self.module.triple = "x86_64-none-elf" + if datalayout: + self.module.data_layout = datalayout + else: + self.module.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + + # 解析目标平台信息 + self._platform_info: dict[str, bool | int] = self._parse_triple(self.module.triple) + self.ptr_size: int = self._platform_info['ptr_size'] + # 根据目标平台配置 t 模块中的平台相关类型大小 + _t.configure_platform(self.module.triple) + self.builder: ir.IRBuilder | None = None + self.func: ir.Function | None = None + self.functions: dict[str, ir.Function] = {} + self.variables: dict[str, ir.Value | None] = {} + self._direct_values: dict[str, ir.Value] = {} + self._reg_values: dict[str, ir.Value] = {} + self.var_signedness: dict[str, bool] = {} + self._unsigned_results: set[int] = {} + self.string_const_counter: int = 0 + self.Vtables: dict[str, ir.GlobalVariable] = {} + self.class_methods: dict[str, list[str]] = {} + self.class_members: dict[str, list[tuple[str, ir.Type]]] = {} + self.class_member_defaults: dict[str, dict[str, Any]] = {} + self.class_member_signeds: dict[str, dict[str, bool]] = {} + self.class_member_bitfields: dict[str, dict[str, int]] = {} + self.class_member_byteorders: dict[str, dict[str, str]] = {} + self.local_var_byteorders: dict[str, str] = {} + self.class_member_element_class: dict[str, dict[str, str]] = {} + self.class_member_bitoffsets: dict[str, dict[str, int]] = {} + self.structs: dict[str, ir.IdentifiedStructType] = {} + self.typedef_int_widths: dict[str, int] = {} # typedef名称 -> 底层整数位宽 (如 'UINT' -> 32, 'BYTE' -> 8) + self._cross_module_vtable_classes: set[str] = set() + self._cross_module_novtable: set[str] = set() + self.class_vtable: set[str] = set() + self._class_graph: dict[str, Any] = {} + self.class_parent: dict[str, str] = {} + # 多继承:父类名数组(声明顺序)。class_parent 兼容保留为第一个父类。 + self.class_parents: dict[str, list[str]] = {} + # Store member annotations for deferred type resolution (cross-module class references) + self.class_member_annotations: dict[str, dict[str, Any]] = {} + self.loop_break_targets: list[ir.Block] = [] + self.loop_continue_targets: list[ir.Block] = [] + self.eh_jmp_buf_stack: list[ir.Value] = [] + self.eh_except_block_stack: list[ir.Block] = [] + self.eh_finally_stack: list[Any] = [] + self.global_vars: set[str] = set() + self.nonlocal_params: dict[str, Any] = {} + self._variable_scope_stack: list[dict[str, Any]] = [] # Stack of outer scope variables for nested function nonlocal lookup + self.var_struct_class: dict[str, str] = {} + self.var_ptr_element: dict[str, bool] = {} + # 全局变量的指针元素标志(持久,不受函数重置影响) + # 用于全局变量 _argv: bytes | t.CPtr 等,使 _argv[index] 使用 8 字节指针步长 + self.global_var_ptr_element: dict[str, bool] = {} + self.class_provides: dict[str, list[str]] = {} + self.class_requires: dict[str, list[str]] = {} + self.class_require_must: dict[str, list[str]] = {} + # 编译期 with 上下文栈:记录当前嵌套 with 链中所有可用的 provides 字段名 + # 用于 __require_must__ 的纯编译期静态可达性检查 + self._with_provides_stack: list[list[str]] = [] + # 函数参数自动取地址模式: func_name -> [None, None, 'need', 'always', ...] + # 'need': t.CNeedPtr — 仅对非指针值取地址 + # 'always': t.CAutoPtr — 无条件取地址 + self._auto_addr_params: dict[str, list[str | None]] = {} + self.global_struct_class: dict[str, str] = {} + self.var_type_info: dict[str, Any] = {} + self.var_const_flags: dict[str, bool] = {} + self._current_source_file: str | None = None + self._current_source_lines: list[str] = [] + self._ns_cache: dict[str, str] = {} + self._type_cache: dict[tuple[str, bool], ir.Type] = {} + self._typedef_cache: dict[str, Any] = {} + self._func_sig_cache: dict[str, Any] = {} + self.var_type_assignments: dict[str, Any] = {} + self._temp_struct_ptrs: list[ir.Value] = [] + self._stop_iter_flag_param: ir.Value | None = None + self._local_heap_ptrs: list[tuple[ir.Value, str, str | None]] = [] + self._var_to_heap_ptr: dict[str, ir.Value] = {} + self.known_return_types: dict[str, ir.Type] = {} + self._current_lineno: int = 0 + self._current_node_info: str = "" + self.module_sha1: str | None = None + self.ModuleSha1Map: dict[str, str] = {} + self._temp_dir: str | None = None + self._export_funcs: set[str] = set() + self._export_extern_funcs: dict[str, str] = {} + self._current_module_func_names: set[str] = set() + # __doc__ 魔法字符串注册表:symbol_name -> docstring 文本(None 表示空/优化剥离) + self._doc_strings: dict[str, str | None] = {} + self.class_packed: set[str] = set() + self._define_constants: dict[str, int] = {} + # 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射 + self._struct_sha1_map: dict[str, str] = {} + self.SymbolTable: Any = None + self._Trans: Any = None + self.class_sha1_map: dict[str, str] = {} + # 以下属性原先懒注入,此处显式初始化以消除 hasattr/getattr 动态反射 + self._import_handler_ref: Any = None + self._classes_in_progress: set[str] = set() + # 字段收集期间添加当前类名,阻止 CollectAnnAssignMember 触发的嵌套 + # _generate_structs 用不完整 class_members 调用 set_body(set_body 只能调用一次) + # 用集合而非单值,因为嵌套特化类 _EmitClassLlvm 会清除单值,导致外层类被错误设置 body + self._collecting_members_set: set[str] = set() + self._last_var_name: str | None = None + self._variadic_info: dict | None = None + self._vtable_copy_counter: int = 0 + self._decorated_funcs: dict = {} + self._current_tree: Any = None + self._DefineConstants: dict = {} + self._all_define_constants: dict = {} + # 闭包追踪:记录返回闭包的函数和变量 + # _closure_return_types: func_name -> (fn_return_type, nonlocal_arg_types) + self._closure_return_types: dict[str, tuple[Any, list[Any]]] = {} + # _closure_var_types: var_name -> (fn_return_type, nonlocal_arg_types) + self._closure_var_types: dict[str, tuple[Any, list[Any]]] = {} + pi: dict[str, bool | int] = self._platform_info + # 根据目标平台设置宏(声明式,从三元组推导) + if pi['is_windows']: + self._define_constants['_WIN32'] = 1 + if not pi['is_32bit']: + self._define_constants['_WIN64'] = 1 + self._define_constants['WIN64'] = 1 + self._define_constants['WIN32'] = 1 + if pi['is_linux']: + self._define_constants['__linux__'] = 1 + if pi['is_macos']: + self._define_constants['__APPLE__'] = 1 + self._define_constants['__MACH__'] = 1 + if pi['is_x86_64']: + self._define_constants['__x86_64__'] = 1 + self._define_constants['__x86_64'] = 1 + self._define_constants['_M_X64'] = 1 + elif pi['is_arm64']: + self._define_constants['__aarch64__'] = 1 + self._define_constants['_M_ARM64'] = 1 + if not pi['is_32bit'] and pi['is_linux']: + self._define_constants['__LP64__'] = 1 + elif pi['is_32bit']: + self._define_constants['_ILP32'] = 1 + self._define_constants['SIZEOF_VOID_P'] = pi['ptr_size'] + self._define_constants['__SIZEOF_POINTER__'] = pi['ptr_size'] + + def find_struct_by_pointee(self, pointee: ir.Type) -> tuple[str, ir.IdentifiedStructType] | None: + """根据 pointee 类型查找匹配的结构体,返回 (class_name, struct_type) 或 None""" + for class_name, struct_type in self.structs.items(): + if pointee == struct_type: + return (class_name, struct_type) + return None + + @staticmethod + def _extract_short_name(name: str) -> str: + """从结构体类型名中提取短名(去掉 sha1 前缀)。 + 如 "6bc91356c652f8ca.Function" → "Function" + 如 "Function" → "Function"(无 sha1 前缀时原样返回) + """ + if '.' in name: + prefix: str = name.split('.', 1)[0] + if len(prefix) == 16 and all(c in '0123456789abcdef' for c in prefix): + return name.split('.', 1)[1] + return name + + @staticmethod + def _extract_struct_sha1(st: ir.IdentifiedStructType) -> str: + """从 IdentifiedStructType 的 name 中提取 sha1 前缀(16 位十六进制)。 + 返回空字符串表示无 sha1 前缀。用于同名类冲突检测。 + """ + if not isinstance(st, ir.IdentifiedStructType): + return '' + try: + name: str = st.name + except (AssertionError, AttributeError): + return '' + if '.' in name: + prefix: str = name.split('.', 1)[0] + if len(prefix) == 16 and all(c in '0123456789abcdef' for c in prefix): + return prefix + return '' + + def _get_or_create_struct(self, name: str, source_sha1: str | None = None, packed: bool = False) -> ir.IdentifiedStructType: + clean_name: str = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_') + # 如果名称包含模块前缀(如 "a9fa0f6200c09e65.zbit_writer"), + # 先尝试用短名称(如 "zbit_writer")查找已注册的 struct, + # 避免为同一 struct 创建多个不同的类型对象导致跨模块引用类型不一致 + if '.' in clean_name and clean_name not in self.structs: + parts: list[str] = clean_name.split('.', 1) + if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]): + short_name: str = parts[1] + if short_name in self.structs: + existing_short: ir.IdentifiedStructType = self.structs[short_name] + # 治本修复:同名类 sha1 冲突检测。 + # 当请求的 sha1 前缀与现有 struct 的 sha1 前缀不一致时 + # (如 stmts.py:Module 与 __module.py:Module 同名冲突), + # 不能复用已有 struct(set_body 已锁定为错误布局), + # 需创建独立 struct 并以 sha1 前缀全名存储。 + _existing_sha1: str = self._extract_struct_sha1(existing_short) + if _existing_sha1 and _existing_sha1 != parts[0]: + if clean_name in self.structs: + return self.structs[clean_name] + st_new: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=clean_name, packed=packed) + self.structs[clean_name] = st_new + return st_new + return existing_short + # 优先解析 typedef 整数类型(如 INT/UINT/BYTE),避免将其注册为 opaque struct。 + # 必须在 `if clean_name in self.structs` 缓存检查之前执行, + # 否则首次调用(SymbolTable 未就绪时)会将 typedef 名缓存为 opaque struct, + # 后续调用即使 SymbolTable 就绪也只会返回缓存的错误类型。 + # 此修复同时解决两个问题: + # 1. alloca unsized type:变量声明 `argc: INT = 6` 不再生成 `alloca %"...INT"` + # 2. 下标访问:FindStructNameInAnnotation 不再匹配 typedef 名(因不在 Gen.structs) + td_width: int | None = self._resolve_typedef_int_width(clean_name) + if td_width is not None: + if td_width > 0: + self.typedef_int_widths[clean_name] = td_width + return ir.IntType(td_width) + # td_width == 0: 特殊 typedef 名称(str/bytes/list 等),返回 i8 + self.typedef_int_widths[clean_name] = 0 + return ir.IntType(8) + if clean_name in self.structs: + existing: ir.IdentifiedStructType = self.structs[clean_name] + # 治本修复:同名类 sha1 冲突检测(短名调用路径)。 + # 当 source_sha1 与现有 struct 的 sha1 前缀不一致时(跨模块同名类冲突), + # 不能复用已有 struct(set_body 已锁定为错误布局), + # 需创建独立 struct 并以 sha1 前缀全名存储,不覆盖短名条目。 + if source_sha1: + _existing_sha1: str = self._extract_struct_sha1(existing) + if _existing_sha1 and _existing_sha1 != source_sha1: + full_key: str = f"{source_sha1}.{clean_name}" + if full_key in self.structs: + st_full: ir.IdentifiedStructType = self.structs[full_key] + if packed and isinstance(st_full, ir.IdentifiedStructType) and not st_full.packed: + st_full.packed = True + return st_full + ns_name: str = f"{source_sha1}.{clean_name}" + st_new: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed) + self.structs[full_key] = st_new + return st_new + 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'}: + return ir.IntType(8) + # typing.Any 是"任意类型"标记,应解析为 i8*(通用指针), + # 而非创建为 opaque 结构体(否则包含 Any 字段的结构体会变成 unsized)。 + if clean_name == 'Any': + return ir.IntType(8).as_pointer() + # t.CType 的基本类型子类(CInt/CChar/CSizeT/CLong/CFloat/CDouble 等, + # position 含 BASE 且 Size>0)有具体 LLVM 类型,应直接返回对应的 + # ir.IntType/ir.FloatType/ir.DoubleType,而非创建结构体。 + # _is_ctype_marker_name 对这些类型返回 False(不跳过),需要在此处拦截。 + _basic_llvm_type: ir.Type | None = self._try_resolve_ctype_basic(clean_name) + if _basic_llvm_type is not None: + return _basic_llvm_type + # t.CType 及其子类是"类型强转"标记,不应被编译为真实结构体。 + # 动态检查 t 模块中所有 CType 子类名(排除 CStruct/CEnum/CUnion/REnum 子类, + # 因为用户定义的结构体类继承自它们,需要被创建为结构体)。 + if self._is_ctype_marker_name(clean_name): + return ir.IntType(8) + if self.SymbolTable: + Entry: _CTypeInfo | None = self.SymbolTable.lookup(clean_name) + if Entry and Entry.IsTypedef: + resolved_str: str = self._resolve_typedef(clean_name) + if resolved_str != clean_name: + return self._type_str_to_llvm(resolved_str) + if Entry.BaseType: + if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0: + resolved: str = self._resolve_ctype_to_str(Entry) + if resolved: + return self._type_str_to_llvm(resolved) + if Entry and Entry.IsRenum: + if clean_name in self.structs: + return self.structs[clean_name] + # REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32), + # 需要继续到下方正常结构体创建路径,创建 opaque 结构体。 + # 这对自引用 REnum(如 LLVMType 包含 LLVMType*)至关重要: + # _parse_llvm_type 先通过此路径创建 opaque 结构体,_TryLoadStructFromStub 再 set_body。 + elif Entry and Entry.IsEnum and clean_name not in self.class_methods: + return ir.IntType(32) + # 治本修复:当 clean_name 是已注册的类(在 class_methods 或 class_members 中)时, + # 不应走 IsExceptionClass/IsFunction/IsVariable 分支返回非结构体类型。 + # 否则 _get_or_create_struct 返回指针类型(如 _TypedPointerType)而非 IdentifiedStructType, + # 导致 _TryLoadStructFromStub 的 set_body 被跳过(isinstance 检查失败), + # struct 保持不完整字段数,引发跨模块 GEP 越界崩溃。 + _is_class_name: bool = clean_name in self.class_methods or clean_name in self.class_members + if Entry and Entry.IsExceptionClass and not _is_class_name: + return ir.IntType(32) + if Entry and Entry.IsFunction and not _is_class_name: + return ir.PointerType(ir.IntType(8)) + if Entry and Entry.IsVariable and not _is_class_name: + return ir.PointerType(ir.IntType(8)) + if Entry and Entry.BaseType: + if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum): + return ir.IntType(32) + if Entry.BaseType is _t.CEnum: + return ir.IntType(32) + ns_name: str + if source_sha1: + ns_name = f"{source_sha1}.{clean_name}" + elif clean_name in self._struct_sha1_map: + ns_name = f"{self._struct_sha1_map[clean_name]}.{clean_name}" + else: + ns_name = self._mangle_name(clean_name) + st: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed) + self.structs[clean_name] = st + # 尝试解析 typedef 的底层整数位宽 + width: int | None = self._resolve_typedef_int_width(clean_name) + if width is not None: + self.typedef_int_widths[clean_name] = width + return st + + def _resolve_typedef_int_width(self, name: str) -> int | None: + """解析 typedef 名称的底层整数位宽 + + 通过 CTypeRegistry 和 BuiltinTypeMap 动态解析, + 替代硬编码的 TYPEDEF_NAMES 映射表。 + 返回 int 位宽或 None(无法解析)。 + """ + # 1. 先查 BuiltinTypeMap(覆盖 BYTEPTR 等指针别名) + bm: Any = BuiltinTypeMap.Get(name) + if bm: + ctype_cls: Any + ptr_count: int + ctype_cls, ptr_count = bm + if ptr_count > 0: + return None # 指针类型,不是整数 typedef + llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls) + if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): + return int(llvm_str[1:]) + + # 2. 再查 SymbolTable(用户定义的 typedef) + if self.SymbolTable: + Entry: _CTypeInfo | None = self.SymbolTable.lookup(name) + if Entry and Entry.IsTypedef: + if Entry.BaseType: + if not isinstance(Entry.BaseType, (_t._CTypedef,)) and Entry.PtrCount == 0: + llvm_str: str = CTypeRegistry.CTypeToLLVM(type(Entry.BaseType) if isinstance(Entry.BaseType, _t.CType) else Entry.BaseType) + if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): + return int(llvm_str[1:]) + if Entry.OriginalType: + if isinstance(Entry.OriginalType, _CTypeInfo) and Entry.OriginalType.BaseType: + if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and Entry.OriginalType.PtrCount == 0: + llvm_str: str = CTypeRegistry.CTypeToLLVM(type(Entry.OriginalType.BaseType) if isinstance(Entry.OriginalType.BaseType, _t.CType) else Entry.OriginalType.BaseType) + if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): + return int(llvm_str[1:]) + elif isinstance(Entry.OriginalType, str): + # OriginalType 是类型名字符串(如 'CInt', 'CUnsignedInt'), + # 通过 CTypeRegistry 解析为整数位宽 + cls: Any = CTypeRegistry.GetClassByName(Entry.OriginalType) + if cls: + llvm_str: str = CTypeRegistry.CTypeToLLVM(cls) + if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): + return int(llvm_str[1:]) + + # 3. 尝试 CTypeRegistry 直接按名称查找 + ctype_cls: Any = CTypeRegistry.GetClassByName(name) + if ctype_cls: + llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls) + if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit(): + return int(llvm_str[1:]) + + # 4. 特殊名称(非整数类型,但需要标记为 typedef 以跳过 opaque 定义) + # 注意:如果 name 已注册为 struct(用户定义了同名 class,如 includes/_dict.py 中的 dict), + # 则不应视为 typedef,应返回 None 让调用方走 struct 创建路径。 + # 解决时序问题:_parse_llvm_declare 从 stub.ll 解析时 dict 可能尚未注册到 Gen.structs, + # 但 SymbolTable 在 .pyi 解析阶段已就绪,可通过 is_struct 检查区分 class 和 typedef。 + _SPECIAL_TYPEDEFS: set[str] = { + 'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', + 'CStruct', 'enum', 'REnum', 'renum', + 'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', 'type', 'CArray', + } + if name in _SPECIAL_TYPEDEFS: + if name in self.structs: + return None # 已注册为 struct,不视为 typedef + if self.SymbolTable is not None: + try: + if self.SymbolTable.is_struct(name): + return None # SymbolTable 中标记为 struct,不视为 typedef + except Exception: + pass + return 0 # 标记为 typedef,但位宽为 0(非整数) + + # t.CType 及其子类是"类型强转"标记,不应被创建为结构体。 + # 动态检查 t 模块中所有 CType 子类名(排除 CStruct/CEnum/CUnion/REnum 子类)。 + # 返回 0 标记为 typedef,使 _get_or_create_struct 走 typedef 路径返回 i8。 + if self._is_ctype_marker_name(name): + return 0 + + return None + + @staticmethod + def _is_ctype_marker_name(name: str) -> bool: + """检查名称是否是 t.CType 的"类型强转"标记子类名。 + + 只有 position 不含 BASE 的纯修饰符/标记类型(CPtr/CVolatile/CConst/ + CInline/CStatic/CExtern/CExport/CRegister/CAuto/_CTypedef/CTypeDefault 等) + 才应该跳过结构体创建。有 BASE position 的基本类型(CInt/CChar/CSizeT/ + CLong/CFloat/CDouble 等)有具体大小,应被正常解析为对应宽度的整数/浮点。 + + CStruct/CEnum/CUnion/REnum 的用户子类是合法结构体,需要被创建。 + + 注意:CTypeRegistry.GetClassByName 会跳过 CType 本身和 CTypeDefault, + 所以这里直接用 getattr(t, name) 检查 t 模块属性。 + + Returns: + True 如果 name 是 CType 标记子类名(应跳过结构体创建) + """ + if not name: + return False + # 去除可能的 SHA1 前缀(如 "abc123.CPtr" -> "CPtr") + short_name: str = name.split('.')[-1] if '.' in name else name + # 直接查 t 模块属性(CTypeRegistry._build 会跳过 CType/CTypeDefault/BigEndian/LittleEndian) + t_cls: Any = getattr(_t, short_name, None) + if not isinstance(t_cls, type) or not issubclass(t_cls, _t.CType): + return False + # 排除 CStruct/CEnum/CUnion/REnum 子类(它们是命名类型的基类, + # 用户定义的结构体继承自它们,需要被创建为结构体) + if issubclass(t_cls, (_t.CStruct, _t.CEnum, _t.REnum, _t.CUnion)): + return False + # 基本类型(position 含 BASE 且 Size > 0)有具体大小,不应跳过 + # (CInt→i32, CChar→i8, CSizeT→i64, CLong→i64, CFloat→f32 等) + # CVoid 虽含 BASE 但 Size=0,CType Size=None,仍需跳过 + if _t.CType.BASE in t_cls.position: + # 检查实例的 Size(类属性可能未设置,用实例获取) + try: + inst = t_cls() + size_val = getattr(inst, 'Size', None) + if size_val is not None and size_val > 0: + return False + except Exception: + pass + return True + + def _try_resolve_ctype_basic(self, name: str) -> ir.Type | None: + """尝试将 t.CType 的基本类型子类名解析为对应的 LLVM 基本类型。 + + 仅对 t 模块内的 CType 基本类型子类(CInt/CChar/CSizeT/CLong/CFloat/ + CDouble 等,即 position 含 BASE 且 Size>0)生效,返回对应的 + ir.IntType/ir.FloatType/ir.DoubleType。 + + CStruct/CEnum/CUnion/REnum 子类不在此处理(用户自定义结构体需要被 + 创建为结构体)。CVoid/CType/CPtr 等无 Size 或 Size=0 的类型也不在此 + 处理(应通过 _is_ctype_marker_name 跳过结构体创建)。 + + Returns: + 对应的 ir.Type,或 None 表示不是基本类型,需要继续走结构体创建路径。 + """ + if not name: + return None + short_name: str = name.split('.')[-1] if '.' in name else name + cls: Any = getattr(_t, short_name, None) + if not isinstance(cls, type) or not issubclass(cls, _t.CType): + return None + if issubclass(cls, (_t.CStruct, _t.CEnum, _t.REnum, _t.CUnion)): + return None + if _t.CType.BASE not in getattr(cls, 'position', frozenset()): + return None + try: + inst = cls() + size_val = getattr(inst, 'Size', None) + if size_val is None or size_val <= 0: + return None + except Exception: + return None + llvm_str: str | None = CTypeRegistry.NameToLLVM(short_name) + if not llvm_str: + return None + return self._type_str_to_llvm(llvm_str) + + def _set_node_info(self, node: ast.AST, extra_info: str = "") -> None: + if hasattr(node, 'lineno'): + self._current_lineno = node.lineno + else: + self._current_lineno = 0 + if hasattr(node, 'col_offset'): + self._current_node_info = f"line {self._current_lineno}, col {node.col_offset}" + else: + self._current_node_info = f"line {self._current_lineno}" + if extra_info: + self._current_node_info += f" ({extra_info})" + + def _set_source_info(self, filepath: str) -> None: + self._current_source_file = filepath + try: + with open(filepath, 'r', encoding='utf-8') as f: + self._current_source_lines = f.readlines() + except Exception: # 文件读取失败时回退为空行列表 + self._current_source_lines = [] + + def _skip_mangle(self, name: str) -> bool: + skip_prefixes: tuple[str, ...] = ('llvm.', 'str_const_', 'printf', 'memset_pattern') + if any(name.startswith(p) for p in skip_prefixes): + return True + if '.' in name: + parts: list[str] = name.split('.', 1) + if len(parts[0]) >= 8 and all(c in '0123456789abcdef' for c in parts[0]): + return True + return False + + def _mangle_name(self, name: str) -> str: + if self._skip_mangle(name): + return name + if name in self._export_funcs: + return name + if self.module_sha1: + return f"{self.module_sha1}.{name}" + return name + + def _find_function(self, name: str) -> ir.Function | None: + if name in self.functions: + return self.functions[name] + g: Any = self.module.globals.get(name) + if g and isinstance(g, ir.Function): + self.functions[name] = g + return g + mangled: str = self._mangle_func_name(name) + if mangled != name: + if mangled in self.functions: + self.functions[name] = self.functions[mangled] + return self.functions[mangled] + g = self.module.globals.get(mangled) + if g and isinstance(g, ir.Function): + self.functions[mangled] = g + self.functions[name] = g + return g + for sha1 in self.ModuleSha1Map.values(): + prefixed: str = f"{sha1}.{name}" + if prefixed in self.functions: + self.functions[name] = self.functions[prefixed] + return self.functions[prefixed] + g = self.module.globals.get(prefixed) + if g and isinstance(g, ir.Function): + self.functions[prefixed] = g + self.functions[name] = g + return g + return None + + def _has_function(self, name: str) -> bool: + return self._find_function(name) is not None + + def _get_mro_chain(self, ClassName: str) -> list[str]: + """MRO 线性化类名列表(深度优先 + 声明顺序 + 去重,含自身)。 + + 顺序: 自身 → 父类1 及祖先 → 父类2 及祖先(先声明父类优先,菱形去重)。 + 与 TPV HandlesStruct.get_mro_chain 的语义一致。 + """ + chain: list[str] = [] + visited: set[str] = set() + stack: list[str] = [ClassName] + parents_map: dict[str, list[str]] = getattr(self, 'class_parents', {}) + while stack: + cur: str = stack.pop() + if not cur or cur in visited: + continue + visited.add(cur) + chain.append(cur) + parents: list[str] = parents_map.get(cur, []) + # 父类逆序压栈,保证声明顺序弹出(先访问父类1 的整条链) + for p in reversed(parents): + if p and p not in visited: + stack.append(p) + return chain + + def _get_parent_classes(self, ClassName: str) -> list[str]: + """获取类的所有父类名(声明顺序),兼容旧 class_parent 单链。""" + parents_map: dict[str, list[str]] = getattr(self, 'class_parents', {}) + parents: list[str] = parents_map.get(ClassName) + if parents: + return parents + p: str | None = self.class_parent.get(ClassName) + if p: + return [p] + return [] + + def _get_or_declare_function(self, mangled_name: str, func_type: ir.FunctionType) -> ir.Function: + # DDEBUG: 检测 mangled_name 含双点(不应到达这里) + if '..' in mangled_name: + import sys + sys.stderr.write(f"[DDEBUG] _get_or_declare_function DOUBLE-DOT mangled_name='{mangled_name}'\n") + import traceback + traceback.print_stack(file=sys.stderr, limit=10) + sys.stderr.flush() + sys.exit(1) + g = self.module.globals.get(mangled_name) + if g and isinstance(g, ir.Function): + return g + return ir.Function(self.module, func_type, name=mangled_name) + + def _get_function(self, name: str) -> ir.Function | None: + func: ir.Function | None = self._find_function(name) + return func + + def _mangle_func_name(self, name: str, module_name: str | None = None) -> str: + # DDEBUG: 检测即将产生双点的情况,立即打印并终止 + if name.startswith('.') or (module_name and module_name.endswith('.') and len(module_name) > 0): + import sys + sys.stderr.write(f"[DDEBUG] _mangle_func_name LEADING-DOT name='{name}' module_name='{module_name}'\n") + import traceback + traceback.print_stack(file=sys.stderr, limit=8) + sys.stderr.flush() + sys.exit(1) + if name in self._export_funcs and not module_name: + return name + if name in self._export_extern_funcs: + target_sha1: str = self._export_extern_funcs[name] + if module_name: + # 显式带 module_name 调用(如 stdlib.system):即使当前模块定义了同名函数, + # 也应按模块匹配 extern,返回裸名。snprintf 之所以工作而 system 不工作, + # 就是因为 os._win32 定义了自己的 system 包装,导致旧逻辑跳过了 extern 匹配。 + if module_name == target_sha1: + return name + if module_name in self.ModuleSha1Map and self.ModuleSha1Map[module_name] == target_sha1: + return name + init_name: str = f"{module_name}.__init__" + if init_name in self.ModuleSha1Map and self.ModuleSha1Map[init_name] == target_sha1: + return name + # 兜底:module_name 不在 ModuleSha1Map 中或 sha1 不匹配, + # 但函数在 _export_extern_funcs 中(C extern 不应混淆), + # 仅当当前模块未定义同名函数时才返回裸名。 + if name not in self._current_module_func_names: + return name + elif name not in self._current_module_func_names: + # 无 module_name 调用(如 from stdlib import system; system()): + # 仅当当前模块未定义同名函数时才返回 extern 裸名, + # 否则让本地定义走正常 mangle 路径(本地 def 遮蔽 import 语义)。 + return name + # main 函数作为程序入口点,永远不混淆 + if name == 'main': + return name + # Try class_sha1_map first for class methods (e.g., 'md5.__init__' -> class 'md5') + class_sha1_map: dict[str, str] = self.class_sha1_map + if class_sha1_map: + if '.' in name: + base_class: str = name.split('.')[0] + if base_class in class_sha1_map: + sha1: str = class_sha1_map[base_class] + return f"{sha1}.{name}" + elif name in class_sha1_map: + sha1: str = class_sha1_map[name] + return f"{sha1}.{name}" + # If module_name is already a SHA1 hash (16 hex chars), use it directly + if module_name and len(module_name) == 16 and all(c in '0123456789abcdef' for c in module_name): + return f"{module_name}.{name}" + if module_name and module_name in self.ModuleSha1Map: + sha1: str = self.ModuleSha1Map[module_name] + return f"{sha1}.{name}" + # Try parent package name (e.g., 'hashlib' -> 'hashlib.__init__') + if module_name: + init_name: str = f"{module_name}.__init__" + if init_name in self.ModuleSha1Map: + sha1: str = self.ModuleSha1Map[init_name] + return f"{sha1}.{name}" + if self._skip_mangle(name): + return name + if self.module_sha1: + result = f"{self.module_sha1}.{name}" + else: + result = name + # DDEBUG: 检测返回结果中是否含双点 + if '..' in result: + import sys + sys.stderr.write(f"[DDEBUG] _mangle_func_name RESULT-DOUBLE-DOT name='{name}' module_name='{module_name}' result='{result}'\n") + import traceback + traceback.print_stack(file=sys.stderr, limit=10) + sys.stderr.flush() + sys.exit(1) + return result + + def _get_source_line(self, lineno: int) -> str | None: + if 0 < lineno <= len(self._current_source_lines): + return self._current_source_lines[lineno - 1].rstrip('\r\n') + return None + + def _get_node_info(self) -> str: + info: str = "" + if self._current_node_info: + info = f" [{self._current_node_info}]" + if self._current_source_file: + info += f" in {self._current_source_file}" + lineno: int = self._current_lineno + if lineno > 0: + info += f", line {lineno}:" + source_line: str | None = self._get_source_line(lineno) + if source_line: + info += f"\n → {source_line}" + return info + + # ========== 统一工具方法 ========== + + def _create_string_global(self, s: str, name: str | None = None) -> ir.Constant: + """创建字符串全局变量并返回 i8* 指针。 + + 统一字符串全局变量创建模式:编码为 utf-8 + '\\x00' 终止符, + 创建 internal linkage 的 GlobalVariable,返回 i8* 指针常量。 + """ + str_val: str = s + '\x00' + str_bytes: bytes = str_val.encode('utf-8') + arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes)) + gv_name: str = name or f"str_const_{self.string_const_counter}" + self.string_const_counter += 1 + gv: ir.GlobalVariable = ir.GlobalVariable(self.module, arr_type, name=gv_name) + gv.initializer = ir.Constant(arr_type, bytearray(str_bytes)) + gv.linkage = 'internal' + return ir.Constant(ir.PointerType(ir.IntType(8)), gv.get_reference()) + + def _create_doc_global(self, symbol_name: str, docstring: str | None) -> None: + """为符号创建 __doc__ 全局常量。 + + - docstring 为 None 或空字符串时,不创建常量(访问时内联空指针) + - slice_level != 0(优化开启)时,内容视为空 + - 非空时创建 internal linkage、global_constant=True 的只读字符串常量 + - 常量名格式:{module_sha1}.{symbol_name}.__doc__ + """ + slice_level: int = getattr(self._Trans, 'SliceLevel', 3) + if slice_level != 0: + docstring = None + if docstring is None or docstring == '': + self._doc_strings[symbol_name] = None + return + self._doc_strings[symbol_name] = docstring + mangled: str = self._mangle_name(f"{symbol_name}.__doc__") + self._create_string_global(docstring, name=mangled) + gv: ir.GlobalVariable | None = self.module.globals.get(mangled) + if gv is not None: + gv.global_constant = True + + def _get_doc_ptr(self, symbol_name: str) -> ir.Value | None: + """获取符号 __doc__ 的 i8* 指针。 + + - 若符号未注册 __doc__,返回 None(调用方回退到其他解析) + - 若 __doc__ 为空(无 docstring 或优化剥离),返回 i8* null 内联空指针 + - 若 __doc__ 非空,返回指向字符串全局常量的 i8* 指针 + - 跨模块 docstring(在 _doc_strings 中有文本但 module.globals 无对应常量)首次访问时创建本地 internal linkage 只读副本 + """ + if symbol_name not in self._doc_strings: + return None + docstring: str | None = self._doc_strings[symbol_name] + if docstring is None or docstring == '': + return ir.Constant(ir.PointerType(ir.IntType(8)), None) + mangled: str = self._mangle_name(f"{symbol_name}.__doc__") + gv: ir.GlobalVariable | None = self.module.globals.get(mangled) + if gv is None: + # 跨模块 docstring:创建本地 internal linkage 只读字符串常量副本 + self._create_string_global(docstring, name=mangled) + gv = self.module.globals.get(mangled) + if gv is None: + return ir.Constant(ir.PointerType(ir.IntType(8)), None) + gv.global_constant = True + zero: ir.Constant = ir.Constant(ir.IntType(32), 0) + return self.builder.gep(gv, [zero, zero], name=f"{symbol_name}_doc_ptr") + + def _apply_bswap_if_big(self, val: ir.Value, byte_order: str, name: str) -> ir.Value: + """大端字节序时对整数应用 bswap,否则原值返回。 + + 仅对 16/32/64 位整数生效,统一 bswap 逻辑。 + """ + if byte_order == 'big' and isinstance(val.type, ir.IntType) and val.type.width in (16, 32, 64): + return self.builder.bswap(val, name=name) + return val + + def _zero_value_for_type(self, llvm_type: ir.Type) -> ir.Constant | None: + """为指定 LLVM 类型生成零值常量。 + + 合并原 HandlesAssign._zero_value 与 StructGen._zero_value_for_type 的逻辑。 + 返回 ir.Constant 或 None(无法生成零值的类型,如 opaque struct)。 + """ + if isinstance(llvm_type, ir.IntType): + return ir.Constant(llvm_type, 0) + elif isinstance(llvm_type, (ir.FloatType, ir.DoubleType)): + return ir.Constant(llvm_type, 0.0) + elif isinstance(llvm_type, ir.PointerType): + return ir.Constant(llvm_type, None) + elif isinstance(llvm_type, ir.ArrayType): + elem_zv: ir.Constant | None = self._zero_value_for_type(llvm_type.element) + if elem_zv is None: + return None + return ir.Constant(llvm_type, [elem_zv] * llvm_type.count) + elif isinstance(llvm_type, ir.BaseStructType): + if llvm_type.elements is not None and len(llvm_type.elements) > 0: + elem_zvs: list[ir.Constant | None] = [self._zero_value_for_type(m) for m in llvm_type.elements] + if any(zv is None for zv in elem_zvs): + return None + return ir.Constant(llvm_type, elem_zvs) + return None return None \ No newline at end of file diff --git a/lib/core/LLVMCG/FuncGen.py b/lib/core/LLVMCG/FuncGen.py index bc9532f..2a120da 100644 --- a/lib/core/LLVMCG/FuncGen.py +++ b/lib/core/LLVMCG/FuncGen.py @@ -1,558 +1,558 @@ -from __future__ import annotations -from typing import Any -import ast -import os -import re -import llvmlite.ir as ir -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.core.VLogger import get_logger as _vlog -from lib.constants.config import mode as _config_mode - - -class FuncGenMixin: - - def setup_from_symbol_table(self, SymbolTable: Any) -> None: - self.SymbolTable: Any = SymbolTable - for name, info in SymbolTable.items(): - if isinstance(info, CTypeInfo): - # CTypeInfo 对象:struct/union 由 StructGen 处理,此处只处理 dict 格式 - continue - if not isinstance(info, dict): - if hasattr(info, 'get'): - info = dict(info) if hasattr(info, '__iter__') else {} - else: - continue - TypeKind: str = info.get('type', '') - if TypeKind == 'struct': - ClassName: str = name - self.class_methods[ClassName] = [] - self.class_members[ClassName] = [] - members: dict[str, Any] = info.get('members', {}) - if members: - for MemberName, MemberInfo in members.items(): - if isinstance(MemberInfo, dict): - MemberType: ir.Type = self._type_str_to_llvm(MemberInfo.get('type', 'int'), MemberInfo.get('IsPtr', False)) - self.class_members[ClassName].append((MemberName, MemberType)) - elif isinstance(MemberInfo, CTypeInfo): - MemberType: ir.Type = self._ctype_to_llvm(MemberInfo) - if MemberType is None: - MemberType = self._type_str_to_llvm(MemberInfo.ToString(), MemberInfo.IsPtr) - self.class_members[ClassName].append((MemberName, MemberType)) - self._generate_structs() - self._create_Vtable_globals() - - def register_method(self, ClassName: str, MethodName: str) -> None: - if ClassName not in self.class_methods: - self.class_methods[ClassName] = [] - if ClassName not in self.class_members: - self.class_members[ClassName] = [] - self._generate_structs() - self._create_Vtable_globals() - # 构造函数(__new__/__init__/__before_init__)不放入 vtable, - # 避免子类与基类 vtable 大小不一致导致虚分派索引偏移 - _short_name: str = MethodName.split('.')[-1] if '.' in MethodName else MethodName - if _short_name in ('__new__', '__init__', '__before_init__'): - return - if MethodName not in self.class_methods[ClassName]: - self.class_methods[ClassName].append(MethodName) - - def _apply_auto_addr(self, func_name: str, args: list[ir.Value]) -> list[ir.Value]: - """对函数参数应用自动取地址逻辑(t.CNeedPtr / t.CAutoPtr)。 - - 在调用前对标记为 auto-addr 的参数自动取地址: - - 'need' (t.CNeedPtr): 仅对非指针值取地址(alloca + store + get pointer) - - 'always' (t.CAutoPtr): 无条件取地址 - """ - modes: list[str | None] | None = self._auto_addr_params.get(func_name) - if not modes: - return args - new_args: list[ir.Value] = list(args) - for i, mode in enumerate(modes): - if i >= len(new_args) or mode is None: - continue - arg: ir.Value = new_args[i] - is_ptr: bool = isinstance(arg.type, ir.PointerType) - if mode == 'always' or (mode == 'need' and not is_ptr): - # alloca + store + get pointer - slot: ir.Value = self.builder.alloca(arg.type) - self.builder.store(arg, slot) - new_args[i] = slot - return new_args - - def _adjust_args(self, args: list[ir.Value], func: ir.Function) -> list[ir.Value]: - adjusted: list[ir.Value] = [] - for i, (arg, param) in enumerate(zip(args, func.args)): - if arg.type != param.type: - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): - # C 语言中数组参数退化为指针,不做 load 而是退化为元素指针 - if isinstance(param.type, ir.ArrayType): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") - adjusted.append(elem_ptr) - else: - adjusted.append(self._load(arg, name=f"Load_arg_{i}")) - continue - try: - if isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): - if isinstance(param.type.pointee, ir.IntType) and param.type.pointee.width == 8 and arg.type.width == 8: - # 当参数是 i8(字符值)而函数期望 i8*(字符串指针)时 - # 为字符值分配内存,创建 null-terminated 字符串 - tmp: ir.AllocaInstr = self._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"char2str_arg_{i}") - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - char_ptr: ir.Value = self.builder.gep(tmp, [zero, zero], name=f"char2str_ptr_{i}") - self._store(arg, char_ptr) - null_ptr: ir.Value = self.builder.gep(tmp, [zero, ir.Constant(ir.IntType(32), 1)], name=f"char2str_null_{i}") - self._store(ir.Constant(ir.IntType(8), 0), null_ptr) - adjusted.append(char_ptr) - else: - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): - # 当参数是指针而函数期望整数时,使用 ptrtoint - adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) - else: - if arg.type.width < 32: - arg = self.builder.zext(arg, ir.IntType(32), name=f"zext_arg_{i}") - adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): - # 当参数是指针而函数期望整数时,使用 ptrtoint - adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType): - if isinstance(arg.type.pointee, ir.PointerType) and isinstance(param.type.pointee, ir.IntType): - Loaded: ir.Value = self._load(arg, name=f"Load_arg_{i}") - adjusted.append(Loaded) - elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, (ir.IntType, ir.FloatType, ir.DoubleType)): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") - if elem_ptr.type != param.type: - adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) - else: - adjusted.append(elem_ptr) - elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, ir.PointerType): - zero: ir.Constant = ir.Constant(ir.IntType(32), 0) - elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") - if elem_ptr.type != param.type: - adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) - else: - adjusted.append(elem_ptr) - else: - adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) - else: - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): - adjusted.append(self._load(arg, name=f"Load_arg_{i}")) - elif isinstance(arg.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - tmp: ir.AllocaInstr = self._alloca(param.type, name=f"temp_arg_{i}") - Loaded: ir.Value = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") - Loaded_val: ir.Value = self._load(Loaded, name=f"Load_arg_{i}") - self._store(Loaded_val, tmp) - adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}")) - else: - tmp: ir.AllocaInstr = self._alloca(param.type, name=f"temp_arg_{i}") - cast_ptr: ir.Value = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") - Loaded_val: ir.Value = self._load(cast_ptr, name=f"Load_arg_{i}") - self._store(Loaded_val, tmp) - adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: - adjusted.append(self._load(arg, name=f"Load_arg_{i}")) - elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: - tmp: ir.AllocaInstr = self._alloca(arg.type, name=f"temp_arg_{i}") - self._store(arg, tmp) - adjusted.append(tmp) - elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.IntType): - if arg.type.width < param.type.width: - # 整数扩展:使用 sext(符号扩展)以正确处理负数 - adjusted.append(self.builder.sext(arg, param.type, name=f"sext_arg_{i}")) - else: - adjusted.append(self.builder.trunc(arg, param.type, name=f"trunc_arg_{i}")) - elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): - if isinstance(arg.type, ir.DoubleType) and isinstance(param.type, ir.FloatType): - adjusted.append(self.builder.fptrunc(arg, param.type, name=f"fptrunc_arg_{i}")) - elif isinstance(arg.type, ir.FloatType) and isinstance(param.type, ir.DoubleType): - adjusted.append(self.builder.fpext(arg, param.type, name=f"fpext_arg_{i}")) - else: - adjusted.append(arg) - elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, ir.IntType): - adjusted.append(self.builder.fptosi(arg, param.type, name=f"fptosi_arg_{i}")) - elif isinstance(arg.type, ir.IntType) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): - adjusted.append(self.builder.sitofp(arg, param.type, name=f"sitofp_arg_{i}")) - elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): - # 整数转指针:inttoptr - if arg.type.width < 64: - i64_val: ir.Value = self.builder.sext(arg, ir.IntType(64), name=f"sext_arg_{i}") - adjusted.append(self.builder.inttoptr(i64_val, param.type, name=f"inttoptr_arg_{i}")) - else: - adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): - # 指针转整数:ptrtoint - i64_val: ir.Value = self.builder.ptrtoint(arg, ir.IntType(64), name=f"ptrtoint_arg_{i}") - if i64_val.type.width > param.type.width: - adjusted.append(self.builder.trunc(i64_val, param.type, name=f"trunc_arg_{i}")) - elif i64_val.type.width < param.type.width: - adjusted.append(self.builder.sext(i64_val, param.type, name=f"sext_arg_{i}")) - else: - adjusted.append(i64_val) - else: - adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) - except Exception: # 参数类型调整失败时使用简化回退逻辑 - if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): - if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): - adjusted.append(self._load(arg, name=f"Load_arg_{i}")) - else: - adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) - elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: - adjusted.append(self._load(arg, name=f"Load_arg_{i}")) - elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: - tmp: ir.AllocaInstr = self._alloca(arg.type, name=f"temp_arg_{i}") - self._store(arg, tmp) - adjusted.append(tmp) - elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType): - # 任意指针到指针的类型转换(如 struct* -> i8*) - adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) - else: - adjusted.append(arg) - else: - adjusted.append(arg) - while len(adjusted) < len(func.args): - missing_idx: int = len(adjusted) - param: ir.Argument = func.args[missing_idx] - param_type: ir.Type = param.type if hasattr(param, 'type') else param - if isinstance(param_type, ir.PointerType): - adjusted.append(ir.Constant(param_type, None)) - elif isinstance(param_type, ir.IntType): - adjusted.append(ir.Constant(param_type, 0)) - elif isinstance(param_type, (ir.FloatType, ir.DoubleType)): - adjusted.append(ir.Constant(param_type, 0.0)) - else: - adjusted.append(ir.Constant(ir.IntType(32), 0)) - if func.type.pointee.var_arg: - for i in range(len(func.args), len(args)): - arg: ir.Value = args[i] - adjusted.append(arg) - return adjusted - - def _get_member_offset(self, field_name: str, ClassName: str | None = None) -> int | None: - # 治本修复:同名类 sha1 冲突检测。 - # 当 class_sha1_map[ClassName] 的 sha1 与 Gen.structs[ClassName] 的 sha1 不一致时, - # class_members[ClassName] 可能存储了错误模块的同名类成员。 - # 此处检测冲突,加载正确模块的 class_members 并以 sha1 前缀全名缓存。 - _ResolvedClass: str = ClassName if ClassName else '' - if ClassName: - # 统一短名解析(治本修复 2026-08-10):struct/class_members/class_vtable/ - # class_parent 均以短名注册(跨模块加载 HandlesImports L1604),而调用方 - # 可能传入带 sha1 前缀的全名(如 "f47f88ae6545965a.Import"),导致下方 - # 查表全部 miss 返回 None → _gep_and_Load_member 静默返回 None → - # AnnAssign InitValue 为 None → 变量 alloca 未初始化 → 运行期读垃圾指针。 - ClassName = self._extract_short_name(ClassName) - _ResolvedClass = ClassName - _ClassSha1Map: dict[str, str] = getattr(self, 'class_sha1_map', {}) - _ExpectedSha1: str | None = _ClassSha1Map.get(ClassName) - if _ExpectedSha1: - _ExistingStruct = self.structs.get(ClassName) - if isinstance(_ExistingStruct, ir.IdentifiedStructType): - _ExistingSha1: str = self._extract_struct_sha1(_ExistingStruct) - if _ExistingSha1 and _ExistingSha1 != _ExpectedSha1: - # sha1 冲突:使用全名查找 class_members - _FullKey: str = f"{_ExpectedSha1}.{ClassName}" - if _FullKey in self.class_members and self.class_members[_FullKey]: - _ResolvedClass = _FullKey - else: - # 从正确 stub 加载 class_members - if self._Trans and hasattr(self._Trans, 'ImportHandler'): - _StubName: str = f"{_ExpectedSha1}.stub.ll" - # 临时保存旧值,清除短名条目以绕过 guard,加载后恢复 - _OldMembers = self.class_members.get(ClassName) - self.class_members[ClassName] = [] - try: - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, _StubName, self) - except Exception: - pass - _NewMembers = self.class_members.get(ClassName) - if _NewMembers: - self.class_members[_FullKey] = _NewMembers - _ResolvedClass = _FullKey - # 恢复旧值(避免影响其他代码对短名的依赖) - if _OldMembers: - self.class_members[ClassName] = _OldMembers - else: - self.class_members.pop(ClassName, None) - has_vtable: bool = ClassName and (ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes) - base: int = 1 if has_vtable else 0 - if ClassName and ClassName in self.structs: - struct_type: ir.IdentifiedStructType = self.structs[ClassName] - if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: - if ClassName in self.class_members: - expected_fields: int = len(self.class_members[ClassName]) - actual_elements: int = len(struct_type.elements) - if base > 0 and actual_elements == expected_fields: - base = 0 - elif base == 0 and actual_elements == expected_fields + 1: - # 跨模块类可能未被检测为 CVTable(如 Name 继承 AST@t.CVTable), - # 但实际 struct 首元素是 vtable ptr → 需 base=1。 - # 但若类有继承(class_parent 有值),多出的 1 可能是继承字段而非 vtable, - # 需检查 struct 首元素类型:i8*/i8** 为 vtable,其他为继承字段。 - _first_elem = struct_type.elements[0] if actual_elements > 0 else None - _has_parent = self.class_parent.get(ClassName) is not None - _is_vtable_ptr = (isinstance(_first_elem, ir.PointerType) and - isinstance(_first_elem.pointee, ir.IntType) and _first_elem.pointee.width == 8) - if not _has_parent or _is_vtable_ptr: - base = 1 - if ClassName and ClassName not in self.class_members and self._Trans and hasattr(self._Trans, 'ImportHandler'): - # 跨模块 class_members 懒加载:struct 已从 stub 加载但 class_members - # 可能尚未从 .vpi 填充(vpi/stub 就绪时序不一致),主动按类 sha1 加载。 - _Sha1sForLoad: dict[str, str] = getattr(self, 'class_sha1_map', {}) - for _mod_name_lz, _mod_sha1_lz in _Sha1sForLoad.items(): - try: - self._Trans.ImportHandler._TryLoadClassMembersFromPyi( - ClassName, f"{_mod_sha1_lz}.stub.ll", self) - except Exception: - continue - if ClassName in self.class_members and len(self.class_members[ClassName]) > 0: - break - if _ResolvedClass and _ResolvedClass in self.class_members: - for i, (name, _) in enumerate(self.class_members[_ResolvedClass]): - if name == field_name: - return base + i - # 继承链回退:当字段不在当前类的 class_members 中时(常见于跨模块导入 - # 父类未加载,字段被填充为 __inherited_N 占位名),沿 class_parent 链向上查找。 - # 子类 struct 布局为 [vtable?] + [基类字段...] + [子类字段...], - # 基类字段在子类 struct 中的起始偏移即为 base(子类), - # 因此祖先 class_members 中的索引 i 对应子类 struct 中的偏移 base + i。 - if ClassName and field_name: - _parent: str | None = self.class_parent.get(ClassName) - _visited: set = {ClassName} if ClassName else set() - while _parent and _parent not in _visited: - _visited.add(_parent) - # 跳过 __inherited_N 占位条目,只在真实字段名中查找 - if _parent in self.class_members: - _members: list = self.class_members[_parent] - _has_placeholder: bool = any(n.startswith('__inherited_') for n, _ in _members) - if not _has_placeholder: - for i, (name, _) in enumerate(_members): - if name == field_name: - return base + i - # 父类 class_members 未加载或含占位条目,尝试从 stub 加载真实字段 - if self._Trans and hasattr(self._Trans, 'ImportHandler'): - sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {}) - for mod_name, mod_sha1 in sha1_map.items(): - stub_name: str = f"{mod_sha1}.stub.ll" - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(_parent, stub_name, self) - if _parent in self.class_members and not any(n.startswith('__inherited_') for n, _ in self.class_members[_parent]): - for i, (name, _) in enumerate(self.class_members[_parent]): - if name == field_name: - return base + i - break - _parent = self.class_parent.get(_parent) - short_name: str | None = ClassName.split('.')[-1] if ClassName and '.' in ClassName else None - if short_name and short_name in self.class_members: - for i, (name, _) in enumerate(self.class_members[short_name]): - if name == field_name: - return base + i - if ClassName and field_name: - if ClassName not in self.class_members or field_name not in [n for n, _ in self.class_members.get(ClassName, [])]: - if self._Trans and hasattr(self._Trans, 'ImportHandler'): - sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {}) - for mod_name, mod_sha1 in sha1_map.items(): - stub_name: str = f"{mod_sha1}.stub.ll" - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, stub_name, self) - if ClassName in self.class_members and len(self.class_members[ClassName]) > 0: - for i, (name, _) in enumerate(self.class_members[ClassName]): - if name == field_name: - return base + i - break - if short_name: - for mod_name, mod_sha1 in sha1_map.items(): - stub_name: str = f"{mod_sha1}.stub.ll" - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_name, stub_name, self) - if short_name in self.class_members and len(self.class_members[short_name]) > 0: - for i, (name, _) in enumerate(self.class_members[short_name]): - if name == field_name: - return base + i - break - if ClassName and field_name: - for cn_key in self.class_members: - if cn_key == ClassName or cn_key.endswith(f'.{ClassName}') or (short_name and (cn_key == short_name or cn_key.endswith(f'.{short_name}'))): - for i, (name, _) in enumerate(self.class_members[cn_key]): - if name == field_name: - return base + i - # REnum 变体搜索: ClassName 是 REnum(如 MetaType),成员注册在变体结构 - # (MetaType_Var, MetaType_Concrete, MetaType_App)中。变体与 REnum 主结构 - # 共享 max_variant_struct 布局,偏移一致(__tag 在偏移 0,字段从偏移 1 开始) - if ClassName and field_name: - variant_prefix: str = f"{ClassName}_" - for cn_key in self.class_members: - if cn_key.startswith(variant_prefix): - for i, (name, _) in enumerate(self.class_members[cn_key]): - if name == field_name: - return i - if short_name: - variant_prefix = f"{short_name}_" - for cn_key in self.class_members: - if cn_key.startswith(variant_prefix): - for i, (name, _) in enumerate(self.class_members[cn_key]): - if name == field_name: - return i - if ClassName and ClassName in self.structs: - struct_type: ir.IdentifiedStructType = self.structs[ClassName] - if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: - for cn_key, members in self.class_members.items(): - if cn_key == short_name or (short_name and cn_key.endswith(f'.{short_name}')): - for i, (name, _) in enumerate(members): - if name == field_name and i < len(struct_type.elements): - return i - break - else: - if short_name: - for cn_key, members in self.class_members.items(): - sn: str = cn_key.split('.')[-1] if '.' in cn_key else cn_key - if sn == short_name: - for i, (name, _) in enumerate(members): - if name == field_name and i < len(struct_type.elements): - return i - break - if ClassName and field_name and ClassName not in self.class_members: - if self._Trans and hasattr(self._Trans, 'ImportHandler'): - for temp_dir_candidate in [getattr(self, '_temp_dir', None)]: - if temp_dir_candidate and os.path.isdir(temp_dir_candidate): - for pyi_file in os.listdir(temp_dir_candidate): - if pyi_file.endswith('.vpi') or pyi_file.endswith('.pyi'): - stub_name: str = pyi_file.replace('.vpi', '.stub.ll').replace('.pyi', '.stub.ll') - short_cn: str = short_name if short_name else ClassName - self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_cn, stub_name, self) - if short_cn in self.class_members and len(self.class_members[short_cn]) > 0: - for i, (name, _) in enumerate(self.class_members[short_cn]): - if name == field_name: - return base + i - break - if ClassName and ClassName in self.structs and (ClassName not in self.class_members or len(self.class_members.get(ClassName, [])) == 0): - struct_type: ir.IdentifiedStructType = self.structs[ClassName] - if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None: - if self._Trans and hasattr(self._Trans, 'ClassHandler'): - class_handler: Any = self._Trans.ClassHandler - if self._current_tree: - for node in ast.iter_child_nodes(self._current_tree): - if isinstance(node, ast.ClassDef) and (node.name == ClassName or node.name == short_name): - if node.name not in self.class_members: - self.class_members[node.name] = [] - if len(self.class_members[node.name]) == 0: - class_handler._PreRegisterClassMembers(node, self) - if ClassName in self.class_members: - for i, (name, _) in enumerate(self.class_members[ClassName]): - if name == field_name: - return base + i - if short_name and short_name in self.class_members: - for i, (name, _) in enumerate(self.class_members[short_name]): - if name == field_name: - return base + i - break - # 最后回退:当继承链回退失败但 struct body 已加载时, - # 从 struct elements 数和 class_members 数推断继承字段偏移。 - # 继承字段在 struct 开头(base 之后),此 fallback 仅适用于单继承字段的情况 - # (如 GSListNode[T] 的 Next 字段)。子类 struct 布局: - # [vtable?] + [基类字段...] + [子类字段...] - # 当 class_members 只含子类自身字段、基类 class_members 未加载时, - # 继承字段数 = struct_elements - class_members_count, - # 若该值 == 1,则所查字段(如 Next)的偏移 = base + 0。 - if ClassName and field_name: - _st_final = self.structs.get(ClassName) - if isinstance(_st_final, ir.IdentifiedStructType) and _st_final.elements is not None: - _num_elements_final: int = len(_st_final.elements) - _members_final: list = self.class_members.get(ClassName, []) - _num_members_final: int = len(_members_final) - if _num_elements_final > _num_members_final: - _num_inherited_final: int = _num_elements_final - _num_members_final - if _num_inherited_final == 1: - # 单继承字段,偏移 = base(vtable 之后第一个位置) - return base + 0 - # fast-fail(治本修复 2026-08-10):字段未找到不再静默返回 None。 - # 静默 None 会让调用方(_gep_and_Load_member L26-27)直接 return None, - # AnnAssign InitValue 变 None → 变量 alloca 未初始化 → 运行期读垃圾指针 - # (如 HandlesImports.HandleImport 的 imp.names → 0xffffffffffffffff 崩溃)。 - # 抛出编译错误,暴露 class_members/struct 的真实状态便于定位根因。 - _members_diag: list = self.class_members.get(ClassName, []) if ClassName else [] - _struct_diag: str = 'not-registered' - if ClassName and ClassName in self.structs: - _st_diag = self.structs[ClassName] - if isinstance(_st_diag, ir.IdentifiedStructType): - _struct_diag = f"{len(_st_diag.elements)} elems" if _st_diag.elements is not None else 'opaque' - _member_names_diag: list = [n for n, _ in _members_diag][:16] - raise KeyError( - f"[fast-fail] 属性 '{field_name}' 在类 '{ClassName}' 中找不到" - f"(class_members={len(_members_diag)} 个: {_member_names_diag}, struct={_struct_diag})" - ) - - def _resolve_class_for_var(self, var_name: str) -> str | None: - for ClassName in self.class_methods: - if var_name == ClassName or var_name.startswith(f"__with_{ClassName}_"): - return ClassName - if var_name in self.variables: - var: ir.Value = self.variables[var_name] - if isinstance(var.type, ir.PointerType): - for ClassName, struct_type in self.structs.items(): - if var.type.pointee == struct_type: - return ClassName - if isinstance(var.type.pointee, ir.PointerType) and var.type.pointee.pointee == struct_type: - return ClassName - return None - - def _infer_return_type(self, FuncName: str) -> ir.Type: - if FuncName in self.functions: - return self.functions[FuncName].type.pointee.return_type - # 也尝试混淆后的名称 - mangled: str = self._mangle_func_name(FuncName) - if mangled != FuncName and mangled in self.functions: - return self.functions[mangled].type.pointee.return_type - if FuncName in self.known_return_types: - return self.known_return_types[FuncName] - if mangled != FuncName and mangled in self.known_return_types: - return self.known_return_types[mangled] - for ClassName, methods in self.class_methods.items(): - for method in methods: - if FuncName == method: - return ir.VoidType() - if self._import_handler_ref: - try: - # 先用原始名称查找,再用混淆名称查找 - stub_func_type: Any = self._import_handler_ref._LookupStubFuncType(FuncName, self) - if stub_func_type is None and mangled != FuncName: - stub_func_type = self._import_handler_ref._LookupStubFuncType(mangled, self) - if stub_func_type and hasattr(stub_func_type, 'return_type'): - return stub_func_type.return_type - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"查找桩函数返回类型失败: {_e}", "Exception") - return ir.IntType(32) - - def _get_or_declare_func(self, name: str, func_type: ir.FunctionType) -> ir.Function: - for fname, fobj in self.functions.items(): - if fname == name: - return fobj - if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): - return fobj - func_decl: ir.Function = ir.Function(self.module, func_type, name=name) - self.functions[name] = func_decl - return func_decl - - def get_or_declare_c_func(self, name: str, fallback_type: ir.FunctionType | None = None) -> ir.Function | None: - if name in self.functions: - return self.functions[name] - for fname, fobj in self.functions.items(): - if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): - return fobj - stub_func_type: ir.FunctionType | None = None - if self._import_handler_ref: - try: - stub_func_type = self._import_handler_ref._LookupStubFuncType(name, self) - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"查找桩函数类型失败: {_e}", "Exception") - if stub_func_type: - func_decl: ir.Function = ir.Function(self.module, stub_func_type, name=name) - self.functions[name] = func_decl - return func_decl - if fallback_type is not None: - func_decl: ir.Function = ir.Function(self.module, fallback_type, name=name) - self.functions[name] = func_decl - return func_decl +from __future__ import annotations +from typing import Any +import vast as ast +import os +import re +import llvmlite.ir as ir +from lib.core.Handles.HandlesBase import CTypeInfo +from lib.core.VLogger import get_logger as _vlog +from lib.constants.config import mode as _config_mode + + +class FuncGenMixin: + + def setup_from_symbol_table(self, SymbolTable: Any) -> None: + self.SymbolTable: Any = SymbolTable + for name, info in SymbolTable.items(): + if isinstance(info, CTypeInfo): + # CTypeInfo 对象:struct/union 由 StructGen 处理,此处只处理 dict 格式 + continue + if not isinstance(info, dict): + if hasattr(info, 'get'): + info = dict(info) if hasattr(info, '__iter__') else {} + else: + continue + TypeKind: str = info.get('type', '') + if TypeKind == 'struct': + ClassName: str = name + self.class_methods[ClassName] = [] + self.class_members[ClassName] = [] + members: dict[str, Any] = info.get('members', {}) + if members: + for MemberName, MemberInfo in members.items(): + if isinstance(MemberInfo, dict): + MemberType: ir.Type = self._type_str_to_llvm(MemberInfo.get('type', 'int'), MemberInfo.get('IsPtr', False)) + self.class_members[ClassName].append((MemberName, MemberType)) + elif isinstance(MemberInfo, CTypeInfo): + MemberType: ir.Type = self._ctype_to_llvm(MemberInfo) + if MemberType is None: + MemberType = self._type_str_to_llvm(MemberInfo.ToString(), MemberInfo.IsPtr) + self.class_members[ClassName].append((MemberName, MemberType)) + self._generate_structs() + self._create_Vtable_globals() + + def register_method(self, ClassName: str, MethodName: str) -> None: + if ClassName not in self.class_methods: + self.class_methods[ClassName] = [] + if ClassName not in self.class_members: + self.class_members[ClassName] = [] + self._generate_structs() + self._create_Vtable_globals() + # 构造函数(__new__/__init__/__before_init__)不放入 vtable, + # 避免子类与基类 vtable 大小不一致导致虚分派索引偏移 + _short_name: str = MethodName.split('.')[-1] if '.' in MethodName else MethodName + if _short_name in ('__new__', '__init__', '__before_init__'): + return + if MethodName not in self.class_methods[ClassName]: + self.class_methods[ClassName].append(MethodName) + + def _apply_auto_addr(self, func_name: str, args: list[ir.Value]) -> list[ir.Value]: + """对函数参数应用自动取地址逻辑(t.CNeedPtr / t.CAutoPtr)。 + + 在调用前对标记为 auto-addr 的参数自动取地址: + - 'need' (t.CNeedPtr): 仅对非指针值取地址(alloca + store + get pointer) + - 'always' (t.CAutoPtr): 无条件取地址 + """ + modes: list[str | None] | None = self._auto_addr_params.get(func_name) + if not modes: + return args + new_args: list[ir.Value] = list(args) + for i, mode in enumerate(modes): + if i >= len(new_args) or mode is None: + continue + arg: ir.Value = new_args[i] + is_ptr: bool = isinstance(arg.type, ir.PointerType) + if mode == 'always' or (mode == 'need' and not is_ptr): + # alloca + store + get pointer + slot: ir.Value = self.builder.alloca(arg.type) + self.builder.store(arg, slot) + new_args[i] = slot + return new_args + + def _adjust_args(self, args: list[ir.Value], func: ir.Function) -> list[ir.Value]: + adjusted: list[ir.Value] = [] + for i, (arg, param) in enumerate(zip(args, func.args)): + if arg.type != param.type: + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): + # C 语言中数组参数退化为指针,不做 load 而是退化为元素指针 + if isinstance(param.type, ir.ArrayType): + zero: ir.Constant = ir.Constant(ir.IntType(32), 0) + elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") + adjusted.append(elem_ptr) + else: + adjusted.append(self._load(arg, name=f"Load_arg_{i}")) + continue + try: + if isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): + if isinstance(param.type.pointee, ir.IntType) and param.type.pointee.width == 8 and arg.type.width == 8: + # 当参数是 i8(字符值)而函数期望 i8*(字符串指针)时 + # 为字符值分配内存,创建 null-terminated 字符串 + tmp: ir.AllocaInstr = self._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"char2str_arg_{i}") + zero: ir.Constant = ir.Constant(ir.IntType(32), 0) + char_ptr: ir.Value = self.builder.gep(tmp, [zero, zero], name=f"char2str_ptr_{i}") + self._store(arg, char_ptr) + null_ptr: ir.Value = self.builder.gep(tmp, [zero, ir.Constant(ir.IntType(32), 1)], name=f"char2str_null_{i}") + self._store(ir.Constant(ir.IntType(8), 0), null_ptr) + adjusted.append(char_ptr) + else: + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): + # 当参数是指针而函数期望整数时,使用 ptrtoint + adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) + else: + if arg.type.width < 32: + arg = self.builder.zext(arg, ir.IntType(32), name=f"zext_arg_{i}") + adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): + # 当参数是指针而函数期望整数时,使用 ptrtoint + adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType): + if isinstance(arg.type.pointee, ir.PointerType) and isinstance(param.type.pointee, ir.IntType): + Loaded: ir.Value = self._load(arg, name=f"Load_arg_{i}") + adjusted.append(Loaded) + elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, (ir.IntType, ir.FloatType, ir.DoubleType)): + zero: ir.Constant = ir.Constant(ir.IntType(32), 0) + elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") + if elem_ptr.type != param.type: + adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) + else: + adjusted.append(elem_ptr) + elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, ir.PointerType): + zero: ir.Constant = ir.Constant(ir.IntType(32), 0) + elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}") + if elem_ptr.type != param.type: + adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}")) + else: + adjusted.append(elem_ptr) + else: + adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) + else: + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): + adjusted.append(self._load(arg, name=f"Load_arg_{i}")) + elif isinstance(arg.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + tmp: ir.AllocaInstr = self._alloca(param.type, name=f"temp_arg_{i}") + Loaded: ir.Value = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") + Loaded_val: ir.Value = self._load(Loaded, name=f"Load_arg_{i}") + self._store(Loaded_val, tmp) + adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}")) + else: + tmp: ir.AllocaInstr = self._alloca(param.type, name=f"temp_arg_{i}") + cast_ptr: ir.Value = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}") + Loaded_val: ir.Value = self._load(cast_ptr, name=f"Load_arg_{i}") + self._store(Loaded_val, tmp) + adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: + adjusted.append(self._load(arg, name=f"Load_arg_{i}")) + elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: + tmp: ir.AllocaInstr = self._alloca(arg.type, name=f"temp_arg_{i}") + self._store(arg, tmp) + adjusted.append(tmp) + elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.IntType): + if arg.type.width < param.type.width: + # 整数扩展:使用 sext(符号扩展)以正确处理负数 + adjusted.append(self.builder.sext(arg, param.type, name=f"sext_arg_{i}")) + else: + adjusted.append(self.builder.trunc(arg, param.type, name=f"trunc_arg_{i}")) + elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): + if isinstance(arg.type, ir.DoubleType) and isinstance(param.type, ir.FloatType): + adjusted.append(self.builder.fptrunc(arg, param.type, name=f"fptrunc_arg_{i}")) + elif isinstance(arg.type, ir.FloatType) and isinstance(param.type, ir.DoubleType): + adjusted.append(self.builder.fpext(arg, param.type, name=f"fpext_arg_{i}")) + else: + adjusted.append(arg) + elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, ir.IntType): + adjusted.append(self.builder.fptosi(arg, param.type, name=f"fptosi_arg_{i}")) + elif isinstance(arg.type, ir.IntType) and isinstance(param.type, (ir.FloatType, ir.DoubleType)): + adjusted.append(self.builder.sitofp(arg, param.type, name=f"sitofp_arg_{i}")) + elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType): + # 整数转指针:inttoptr + if arg.type.width < 64: + i64_val: ir.Value = self.builder.sext(arg, ir.IntType(64), name=f"sext_arg_{i}") + adjusted.append(self.builder.inttoptr(i64_val, param.type, name=f"inttoptr_arg_{i}")) + else: + adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType): + # 指针转整数:ptrtoint + i64_val: ir.Value = self.builder.ptrtoint(arg, ir.IntType(64), name=f"ptrtoint_arg_{i}") + if i64_val.type.width > param.type.width: + adjusted.append(self.builder.trunc(i64_val, param.type, name=f"trunc_arg_{i}")) + elif i64_val.type.width < param.type.width: + adjusted.append(self.builder.sext(i64_val, param.type, name=f"sext_arg_{i}")) + else: + adjusted.append(i64_val) + else: + adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) + except Exception: # 参数类型调整失败时使用简化回退逻辑 + if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)): + if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name): + adjusted.append(self._load(arg, name=f"Load_arg_{i}")) + else: + adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) + elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type: + adjusted.append(self._load(arg, name=f"Load_arg_{i}")) + elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type: + tmp: ir.AllocaInstr = self._alloca(arg.type, name=f"temp_arg_{i}") + self._store(arg, tmp) + adjusted.append(tmp) + elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType): + # 任意指针到指针的类型转换(如 struct* -> i8*) + adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}")) + else: + adjusted.append(arg) + else: + adjusted.append(arg) + while len(adjusted) < len(func.args): + missing_idx: int = len(adjusted) + param: ir.Argument = func.args[missing_idx] + param_type: ir.Type = param.type if hasattr(param, 'type') else param + if isinstance(param_type, ir.PointerType): + adjusted.append(ir.Constant(param_type, None)) + elif isinstance(param_type, ir.IntType): + adjusted.append(ir.Constant(param_type, 0)) + elif isinstance(param_type, (ir.FloatType, ir.DoubleType)): + adjusted.append(ir.Constant(param_type, 0.0)) + else: + adjusted.append(ir.Constant(ir.IntType(32), 0)) + if func.type.pointee.var_arg: + for i in range(len(func.args), len(args)): + arg: ir.Value = args[i] + adjusted.append(arg) + return adjusted + + def _get_member_offset(self, field_name: str, ClassName: str | None = None) -> int | None: + # 治本修复:同名类 sha1 冲突检测。 + # 当 class_sha1_map[ClassName] 的 sha1 与 Gen.structs[ClassName] 的 sha1 不一致时, + # class_members[ClassName] 可能存储了错误模块的同名类成员。 + # 此处检测冲突,加载正确模块的 class_members 并以 sha1 前缀全名缓存。 + _ResolvedClass: str = ClassName if ClassName else '' + if ClassName: + # 统一短名解析(治本修复 2026-08-10):struct/class_members/class_vtable/ + # class_parent 均以短名注册(跨模块加载 HandlesImports L1604),而调用方 + # 可能传入带 sha1 前缀的全名(如 "f47f88ae6545965a.Import"),导致下方 + # 查表全部 miss 返回 None → _gep_and_Load_member 静默返回 None → + # AnnAssign InitValue 为 None → 变量 alloca 未初始化 → 运行期读垃圾指针。 + ClassName = self._extract_short_name(ClassName) + _ResolvedClass = ClassName + _ClassSha1Map: dict[str, str] = getattr(self, 'class_sha1_map', {}) + _ExpectedSha1: str | None = _ClassSha1Map.get(ClassName) + if _ExpectedSha1: + _ExistingStruct = self.structs.get(ClassName) + if isinstance(_ExistingStruct, ir.IdentifiedStructType): + _ExistingSha1: str = self._extract_struct_sha1(_ExistingStruct) + if _ExistingSha1 and _ExistingSha1 != _ExpectedSha1: + # sha1 冲突:使用全名查找 class_members + _FullKey: str = f"{_ExpectedSha1}.{ClassName}" + if _FullKey in self.class_members and self.class_members[_FullKey]: + _ResolvedClass = _FullKey + else: + # 从正确 stub 加载 class_members + if self._Trans and hasattr(self._Trans, 'ImportHandler'): + _StubName: str = f"{_ExpectedSha1}.stub.ll" + # 临时保存旧值,清除短名条目以绕过 guard,加载后恢复 + _OldMembers = self.class_members.get(ClassName) + self.class_members[ClassName] = [] + try: + self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, _StubName, self) + except Exception: + pass + _NewMembers = self.class_members.get(ClassName) + if _NewMembers: + self.class_members[_FullKey] = _NewMembers + _ResolvedClass = _FullKey + # 恢复旧值(避免影响其他代码对短名的依赖) + if _OldMembers: + self.class_members[ClassName] = _OldMembers + else: + self.class_members.pop(ClassName, None) + has_vtable: bool = ClassName and (ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes) + base: int = 1 if has_vtable else 0 + if ClassName and ClassName in self.structs: + struct_type: ir.IdentifiedStructType = self.structs[ClassName] + if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: + if ClassName in self.class_members: + expected_fields: int = len(self.class_members[ClassName]) + actual_elements: int = len(struct_type.elements) + if base > 0 and actual_elements == expected_fields: + base = 0 + elif base == 0 and actual_elements == expected_fields + 1: + # 跨模块类可能未被检测为 CVTable(如 Name 继承 AST@t.CVTable), + # 但实际 struct 首元素是 vtable ptr → 需 base=1。 + # 但若类有继承(class_parent 有值),多出的 1 可能是继承字段而非 vtable, + # 需检查 struct 首元素类型:i8*/i8** 为 vtable,其他为继承字段。 + _first_elem = struct_type.elements[0] if actual_elements > 0 else None + _has_parent = self.class_parent.get(ClassName) is not None + _is_vtable_ptr = (isinstance(_first_elem, ir.PointerType) and + isinstance(_first_elem.pointee, ir.IntType) and _first_elem.pointee.width == 8) + if not _has_parent or _is_vtable_ptr: + base = 1 + if ClassName and ClassName not in self.class_members and self._Trans and hasattr(self._Trans, 'ImportHandler'): + # 跨模块 class_members 懒加载:struct 已从 stub 加载但 class_members + # 可能尚未从 .vpi 填充(vpi/stub 就绪时序不一致),主动按类 sha1 加载。 + _Sha1sForLoad: dict[str, str] = getattr(self, 'class_sha1_map', {}) + for _mod_name_lz, _mod_sha1_lz in _Sha1sForLoad.items(): + try: + self._Trans.ImportHandler._TryLoadClassMembersFromPyi( + ClassName, f"{_mod_sha1_lz}.stub.ll", self) + except Exception: + continue + if ClassName in self.class_members and len(self.class_members[ClassName]) > 0: + break + if _ResolvedClass and _ResolvedClass in self.class_members: + for i, (name, _) in enumerate(self.class_members[_ResolvedClass]): + if name == field_name: + return base + i + # 继承链回退:当字段不在当前类的 class_members 中时(常见于跨模块导入 + # 父类未加载,字段被填充为 __inherited_N 占位名),沿 class_parent 链向上查找。 + # 子类 struct 布局为 [vtable?] + [基类字段...] + [子类字段...], + # 基类字段在子类 struct 中的起始偏移即为 base(子类), + # 因此祖先 class_members 中的索引 i 对应子类 struct 中的偏移 base + i。 + if ClassName and field_name: + _parent: str | None = self.class_parent.get(ClassName) + _visited: set = {ClassName} if ClassName else set() + while _parent and _parent not in _visited: + _visited.add(_parent) + # 跳过 __inherited_N 占位条目,只在真实字段名中查找 + if _parent in self.class_members: + _members: list = self.class_members[_parent] + _has_placeholder: bool = any(n.startswith('__inherited_') for n, _ in _members) + if not _has_placeholder: + for i, (name, _) in enumerate(_members): + if name == field_name: + return base + i + # 父类 class_members 未加载或含占位条目,尝试从 stub 加载真实字段 + if self._Trans and hasattr(self._Trans, 'ImportHandler'): + sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {}) + for mod_name, mod_sha1 in sha1_map.items(): + stub_name: str = f"{mod_sha1}.stub.ll" + self._Trans.ImportHandler._TryLoadClassMembersFromPyi(_parent, stub_name, self) + if _parent in self.class_members and not any(n.startswith('__inherited_') for n, _ in self.class_members[_parent]): + for i, (name, _) in enumerate(self.class_members[_parent]): + if name == field_name: + return base + i + break + _parent = self.class_parent.get(_parent) + short_name: str | None = ClassName.split('.')[-1] if ClassName and '.' in ClassName else None + if short_name and short_name in self.class_members: + for i, (name, _) in enumerate(self.class_members[short_name]): + if name == field_name: + return base + i + if ClassName and field_name: + if ClassName not in self.class_members or field_name not in [n for n, _ in self.class_members.get(ClassName, [])]: + if self._Trans and hasattr(self._Trans, 'ImportHandler'): + sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {}) + for mod_name, mod_sha1 in sha1_map.items(): + stub_name: str = f"{mod_sha1}.stub.ll" + self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, stub_name, self) + if ClassName in self.class_members and len(self.class_members[ClassName]) > 0: + for i, (name, _) in enumerate(self.class_members[ClassName]): + if name == field_name: + return base + i + break + if short_name: + for mod_name, mod_sha1 in sha1_map.items(): + stub_name: str = f"{mod_sha1}.stub.ll" + self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_name, stub_name, self) + if short_name in self.class_members and len(self.class_members[short_name]) > 0: + for i, (name, _) in enumerate(self.class_members[short_name]): + if name == field_name: + return base + i + break + if ClassName and field_name: + for cn_key in self.class_members: + if cn_key == ClassName or cn_key.endswith(f'.{ClassName}') or (short_name and (cn_key == short_name or cn_key.endswith(f'.{short_name}'))): + for i, (name, _) in enumerate(self.class_members[cn_key]): + if name == field_name: + return base + i + # REnum 变体搜索: ClassName 是 REnum(如 MetaType),成员注册在变体结构 + # (MetaType_Var, MetaType_Concrete, MetaType_App)中。变体与 REnum 主结构 + # 共享 max_variant_struct 布局,偏移一致(__tag 在偏移 0,字段从偏移 1 开始) + if ClassName and field_name: + variant_prefix: str = f"{ClassName}_" + for cn_key in self.class_members: + if cn_key.startswith(variant_prefix): + for i, (name, _) in enumerate(self.class_members[cn_key]): + if name == field_name: + return i + if short_name: + variant_prefix = f"{short_name}_" + for cn_key in self.class_members: + if cn_key.startswith(variant_prefix): + for i, (name, _) in enumerate(self.class_members[cn_key]): + if name == field_name: + return i + if ClassName and ClassName in self.structs: + struct_type: ir.IdentifiedStructType = self.structs[ClassName] + if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0: + for cn_key, members in self.class_members.items(): + if cn_key == short_name or (short_name and cn_key.endswith(f'.{short_name}')): + for i, (name, _) in enumerate(members): + if name == field_name and i < len(struct_type.elements): + return i + break + else: + if short_name: + for cn_key, members in self.class_members.items(): + sn: str = cn_key.split('.')[-1] if '.' in cn_key else cn_key + if sn == short_name: + for i, (name, _) in enumerate(members): + if name == field_name and i < len(struct_type.elements): + return i + break + if ClassName and field_name and ClassName not in self.class_members: + if self._Trans and hasattr(self._Trans, 'ImportHandler'): + for temp_dir_candidate in [getattr(self, '_temp_dir', None)]: + if temp_dir_candidate and os.path.isdir(temp_dir_candidate): + for pyi_file in os.listdir(temp_dir_candidate): + if pyi_file.endswith('.vpi') or pyi_file.endswith('.pyi'): + stub_name: str = pyi_file.replace('.vpi', '.stub.ll').replace('.pyi', '.stub.ll') + short_cn: str = short_name if short_name else ClassName + self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_cn, stub_name, self) + if short_cn in self.class_members and len(self.class_members[short_cn]) > 0: + for i, (name, _) in enumerate(self.class_members[short_cn]): + if name == field_name: + return base + i + break + if ClassName and ClassName in self.structs and (ClassName not in self.class_members or len(self.class_members.get(ClassName, [])) == 0): + struct_type: ir.IdentifiedStructType = self.structs[ClassName] + if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None: + if self._Trans and hasattr(self._Trans, 'ClassHandler'): + class_handler: Any = self._Trans.ClassHandler + if self._current_tree: + for node in ast.iter_child_nodes(self._current_tree): + if isinstance(node, ast.ClassDef) and (node.name == ClassName or node.name == short_name): + if node.name not in self.class_members: + self.class_members[node.name] = [] + if len(self.class_members[node.name]) == 0: + class_handler._PreRegisterClassMembers(node, self) + if ClassName in self.class_members: + for i, (name, _) in enumerate(self.class_members[ClassName]): + if name == field_name: + return base + i + if short_name and short_name in self.class_members: + for i, (name, _) in enumerate(self.class_members[short_name]): + if name == field_name: + return base + i + break + # 最后回退:当继承链回退失败但 struct body 已加载时, + # 从 struct elements 数和 class_members 数推断继承字段偏移。 + # 继承字段在 struct 开头(base 之后),此 fallback 仅适用于单继承字段的情况 + # (如 GSListNode[T] 的 Next 字段)。子类 struct 布局: + # [vtable?] + [基类字段...] + [子类字段...] + # 当 class_members 只含子类自身字段、基类 class_members 未加载时, + # 继承字段数 = struct_elements - class_members_count, + # 若该值 == 1,则所查字段(如 Next)的偏移 = base + 0。 + if ClassName and field_name: + _st_final = self.structs.get(ClassName) + if isinstance(_st_final, ir.IdentifiedStructType) and _st_final.elements is not None: + _num_elements_final: int = len(_st_final.elements) + _members_final: list = self.class_members.get(ClassName, []) + _num_members_final: int = len(_members_final) + if _num_elements_final > _num_members_final: + _num_inherited_final: int = _num_elements_final - _num_members_final + if _num_inherited_final == 1: + # 单继承字段,偏移 = base(vtable 之后第一个位置) + return base + 0 + # fast-fail(治本修复 2026-08-10):字段未找到不再静默返回 None。 + # 静默 None 会让调用方(_gep_and_Load_member L26-27)直接 return None, + # AnnAssign InitValue 变 None → 变量 alloca 未初始化 → 运行期读垃圾指针 + # (如 HandlesImports.HandleImport 的 imp.names → 0xffffffffffffffff 崩溃)。 + # 抛出编译错误,暴露 class_members/struct 的真实状态便于定位根因。 + _members_diag: list = self.class_members.get(ClassName, []) if ClassName else [] + _struct_diag: str = 'not-registered' + if ClassName and ClassName in self.structs: + _st_diag = self.structs[ClassName] + if isinstance(_st_diag, ir.IdentifiedStructType): + _struct_diag = f"{len(_st_diag.elements)} elems" if _st_diag.elements is not None else 'opaque' + _member_names_diag: list = [n for n, _ in _members_diag][:16] + raise KeyError( + f"[fast-fail] 属性 '{field_name}' 在类 '{ClassName}' 中找不到" + f"(class_members={len(_members_diag)} 个: {_member_names_diag}, struct={_struct_diag})" + ) + + def _resolve_class_for_var(self, var_name: str) -> str | None: + for ClassName in self.class_methods: + if var_name == ClassName or var_name.startswith(f"__with_{ClassName}_"): + return ClassName + if var_name in self.variables: + var: ir.Value = self.variables[var_name] + if isinstance(var.type, ir.PointerType): + for ClassName, struct_type in self.structs.items(): + if var.type.pointee == struct_type: + return ClassName + if isinstance(var.type.pointee, ir.PointerType) and var.type.pointee.pointee == struct_type: + return ClassName + return None + + def _infer_return_type(self, FuncName: str) -> ir.Type: + if FuncName in self.functions: + return self.functions[FuncName].type.pointee.return_type + # 也尝试混淆后的名称 + mangled: str = self._mangle_func_name(FuncName) + if mangled != FuncName and mangled in self.functions: + return self.functions[mangled].type.pointee.return_type + if FuncName in self.known_return_types: + return self.known_return_types[FuncName] + if mangled != FuncName and mangled in self.known_return_types: + return self.known_return_types[mangled] + for ClassName, methods in self.class_methods.items(): + for method in methods: + if FuncName == method: + return ir.VoidType() + if self._import_handler_ref: + try: + # 先用原始名称查找,再用混淆名称查找 + stub_func_type: Any = self._import_handler_ref._LookupStubFuncType(FuncName, self) + if stub_func_type is None and mangled != FuncName: + stub_func_type = self._import_handler_ref._LookupStubFuncType(mangled, self) + if stub_func_type and hasattr(stub_func_type, 'return_type'): + return stub_func_type.return_type + except Exception as _e: + if _config_mode == "strict": + raise + _vlog().warning(f"查找桩函数返回类型失败: {_e}", "Exception") + return ir.IntType(32) + + def _get_or_declare_func(self, name: str, func_type: ir.FunctionType) -> ir.Function: + for fname, fobj in self.functions.items(): + if fname == name: + return fobj + if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): + return fobj + func_decl: ir.Function = ir.Function(self.module, func_type, name=name) + self.functions[name] = func_decl + return func_decl + + def get_or_declare_c_func(self, name: str, fallback_type: ir.FunctionType | None = None) -> ir.Function | None: + if name in self.functions: + return self.functions[name] + for fname, fobj in self.functions.items(): + if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname): + return fobj + stub_func_type: ir.FunctionType | None = None + if self._import_handler_ref: + try: + stub_func_type = self._import_handler_ref._LookupStubFuncType(name, self) + except Exception as _e: + if _config_mode == "strict": + raise + _vlog().warning(f"查找桩函数类型失败: {_e}", "Exception") + if stub_func_type: + func_decl: ir.Function = ir.Function(self.module, stub_func_type, name=name) + self.functions[name] = func_decl + return func_decl + if fallback_type is not None: + func_decl: ir.Function = ir.Function(self.module, fallback_type, name=name) + self.functions[name] = func_decl + return func_decl return None \ No newline at end of file diff --git a/lib/core/LLVMCG/StructGen.py b/lib/core/LLVMCG/StructGen.py index 1582a9a..9de4ac4 100644 --- a/lib/core/LLVMCG/StructGen.py +++ b/lib/core/LLVMCG/StructGen.py @@ -1,651 +1,651 @@ -from __future__ import annotations -from typing import Any -import re -import ast -import llvmlite.ir as ir -from llvmlite.ir.values import _Undefined -from lib.includes import t as _t - - -class StructGenMixin: - - def _get_align(self, llvm_type: ir.Type) -> int: - if isinstance(llvm_type, ir.IntType): - return max(1, llvm_type.width // 8) - if isinstance(llvm_type, ir.FloatType): - return 4 - if isinstance(llvm_type, ir.DoubleType): - return 8 - if isinstance(llvm_type, ir.PointerType): - return self.ptr_size - if isinstance(llvm_type, ir.ArrayType): - return self._get_align(llvm_type.element) - if isinstance(llvm_type, ir.LiteralStructType): - return max((self._get_align(f) for f in llvm_type.elements), default=1) - if isinstance(llvm_type, ir.IdentifiedStructType): - if llvm_type.elements is None or len(llvm_type.elements) == 0: - return self.ptr_size # opaque struct, assume pointer alignment - return max((self._get_align(f) for f in llvm_type.elements), default=1) - if isinstance(llvm_type, ir.VoidType): - return 0 - return 4 - - def _resolve_opaque_struct(self, llvm_type: ir.Type) -> ir.Type: - """尝试从 Gen.structs 中查找已解析的同名 struct,解决跨模块 struct 类型对象不一致的问题""" - if not isinstance(llvm_type, ir.IdentifiedStructType): - return llvm_type - if llvm_type.elements is not None and len(llvm_type.elements) > 0: - return llvm_type - # opaque struct,尝试通过名称在 Gen.structs 中查找已解析的版本 - st_name: str - try: - st_name = llvm_type.name - except Exception: - return llvm_type - if not st_name: - return llvm_type - # 提取短名称 - short_name: str = st_name - if '.' in st_name: - short_name = st_name.split('.', 1)[1] - # 尝试短名称查找 - if short_name in self.structs: - resolved: ir.IdentifiedStructType = self.structs[short_name] - if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: - return resolved - # 尝试全名查找 - if st_name in self.structs: - resolved: ir.IdentifiedStructType = self.structs[st_name] - if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: - return resolved - # 尝试通过导入处理器从 stub 文件加载 struct 定义 - import_handler: Any = self._import_handler_ref - if import_handler is not None: - try: - import_handler._TryLoadStructFromStub(short_name, self) - except Exception: - pass - # 加载后再次查找 - if short_name in self.structs: - resolved = self.structs[short_name] - if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: - return resolved - if st_name in self.structs: - resolved = self.structs[st_name] - if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: - return resolved - return llvm_type - - def _get_struct_size(self, llvm_type: ir.Type) -> int: - if isinstance(llvm_type, ir.IntType): - return max(1, llvm_type.width // 8) - if isinstance(llvm_type, ir.FloatType): - return 4 - if isinstance(llvm_type, ir.DoubleType): - return 8 - if isinstance(llvm_type, ir.PointerType): - return self.ptr_size - if isinstance(llvm_type, ir.ArrayType): - return self._get_struct_size(llvm_type.element) * llvm_type.count - if isinstance(llvm_type, ir.LiteralStructType): - total: int = 0 - max_align: int = 1 - for f in llvm_type.fields: - fa: int = self._get_align(f) - fs: int = self._get_struct_size(f) - max_align = max(max_align, fa) - if fa > 1: - total = (total + fa - 1) // fa * fa - total += fs - if max_align > 1: - total = (total + max_align - 1) // max_align * max_align - return total - if isinstance(llvm_type, ir.IdentifiedStructType): - # 尝试解析 opaque struct 为已注册的版本 - llvm_type = self._resolve_opaque_struct(llvm_type) - if llvm_type.elements is None or len(llvm_type.elements) == 0: - return self.ptr_size # opaque struct, assume pointer size - total: int = 0 - max_align: int = 1 - for f in llvm_type.elements: - fa: int = self._get_align(f) - fs: int = self._get_struct_size(f) - max_align = max(max_align, fa) - if fa > 1: - total = (total + fa - 1) // fa * fa - total += fs - if max_align > 1: - total = (total + max_align - 1) // max_align * max_align - return total - return 4 - - @staticmethod - def _strip_unnecessary_quotes(ir_str: str) -> str: - def _unquote(m: re.Match) -> str: - prefix: str = m.group(1) - name: str = m.group(2) - if '.' in name: - return m.group(0) - if re.match(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$', name): - return prefix + name - return m.group(0) - return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str) - - def finalize(self) -> str: - self._set_Vtable_initializers() - self._fix_global_var_init() - ir_text: str - try: - ir_text = str(self.module) - except TypeError as e: - for func in self.module.functions: - for block in func.blocks: - for instr in block.instructions: - try: - str(instr) - except TypeError as te: - pass - raise - ir_text = self._strip_unnecessary_quotes(ir_text) - struct_defs: list[str] = [] - struct_names: set[str] = set() - for ClassName, struct_type in self.structs.items(): - if isinstance(struct_type, ir.IdentifiedStructType): - sname: str = struct_type.name - sname_ir: str - if sname[0].isdigit() or '.' in sname or not sname.replace('_', '').replace('.', '').isalnum(): - sname_ir = f'%"{sname}"' - else: - sname_ir = f'%{sname}' - if struct_type.elements is None or len(struct_type.elements) == 0: - if ClassName not in self.typedef_int_widths: - struct_names.add(sname) - struct_defs.append(f'{sname_ir} = type opaque') - continue - elems: str = ', '.join(str(e) for e in struct_type.elements) - if struct_type.packed: - struct_defs.append(f'{sname_ir} = type <{{ {elems} }}>') - else: - struct_defs.append(f'{sname_ir} = type {{ {elems} }}') - struct_names.add(sname) - if struct_defs: - lines: list[str] = ir_text.split('\n') - filtered: list[str] = [] - for line in lines: - stripped: str = line.strip() - skip: bool = False - for name in struct_names: - patterns: list[str] - if name[0].isdigit() or '.' in name or not name.replace('_', '').replace('.', '').isalnum(): - patterns = [f'%"{name}" = type', f'%"{name}"=type', f'%{name} = type', f'%{name}=type'] - else: - patterns = [f'%{name} = type', f'%{name}= type', f'%{name}=type'] - for p in patterns: - if stripped.startswith(p): - skip = True - break - if skip: - break - if not skip: - filtered.append(line) - ir_text = '\n'.join(filtered) - header_end: int = ir_text.find('\ndefine') - if header_end == -1: - header_end = ir_text.find('\ndeclare') - if header_end == -1: - header_end = ir_text.find('\n@') - if header_end == -1: - header_end = len(ir_text) - insert_pos: int = ir_text.rfind('\n', 0, header_end) - if insert_pos == -1: - insert_pos = header_end - struct_block: str = '\n'.join(struct_defs) + '\n' - ir_text = ir_text[:insert_pos + 1] + struct_block + ir_text[insert_pos + 1:] - for name in struct_names: - if name[0].isdigit() or '.' in name: - ir_text = re.sub( - r'%' + re.escape(name) + r'(?=[^a-zA-Z0-9_$\.]|$)', - r'%"' + name + r'"', - ir_text - ) - - return ir_text - - def _generate_structs(self) -> None: - all_classes: set[str] = set(self.class_methods.keys()) | set(self.class_members.keys()) - - preserved_structs: dict[str, ir.IdentifiedStructType] = {} - for name, st in self.structs.items(): - if name not in all_classes: - preserved_structs[name] = st - elif isinstance(st, ir.IdentifiedStructType): - preserved_structs[name] = st - - self.structs.clear() - - for name, st in preserved_structs.items(): - self.structs[name] = st - - # Step 1: 先为所有类创建空的 struct,确保后面可以正确引用 - all_classes = set(self.class_methods.keys()) | set(self.class_members.keys()) - for ClassName in all_classes: - is_packed: bool = ClassName in self.class_packed - if self.SymbolTable: - Entry = self.SymbolTable.lookup(ClassName) - if Entry and Entry.IsExceptionClass: - continue - # 注意:类名可能与 CEnum 成员名冲突(如 ASTKind.Module 枚举成员与 Module 类同名) - # 如果 ClassName 在 class_methods 中,表明是 _EmitClassLlvm 显式处理的常规类, - # 不应被 IsEnum/IsTypedef 检查跳过 - if Entry and Entry.IsEnum and ClassName not in self.class_methods: - if not Entry.IsRenum: - continue - if Entry and Entry.IsTypedef and ClassName not in self.class_methods: - if Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)): - if not isinstance(Entry.BaseType, (_t._CTypedef,)): - continue - if ClassName in self.structs: - if is_packed: - self.structs[ClassName].packed = True - continue - # 修复跨模块类型定义冲突:如果类是从其他模块导入的(已在 class_sha1_map 注册), - # 必须使用导入的 source_sha1 作为前缀,而非本地模块的 sha1。 - # 否则会创建缺少基类字段(如 GSListNode.Next)的本地类型定义, - # 导致字段索引错位 → 访问违规崩溃。 - _imported_sha1: str = self.class_sha1_map.get(ClassName, '') - if _imported_sha1: - mangled_name: str = f"{_imported_sha1}.{ClassName}" - else: - mangled_name: str = self._mangle_name(ClassName) - struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, mangled_name, packed=is_packed) - self.structs[ClassName] = struct_type - - # Step 2: 解析跨模块的成员类型 - for ClassName, annotations in self.class_member_annotations.items(): - if ClassName not in self.class_members: - continue - for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): - if member_name in annotations: - annotation: Any = annotations[member_name] - ResolvedType: ir.Type | None = None - - if isinstance(annotation, ast.Attribute): - 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] - - if ResolvedType: - self.class_members[ClassName][i] = (member_name, ResolvedType) - - struct_name_map: dict[str, ir.IdentifiedStructType] = {} - for struct_name, struct in self.structs.items(): - try: - struct_name_map[struct.name] = struct - except AssertionError: - struct_name_map[struct_name] = struct - orig: Any = getattr(struct, '_original_name', None) - if orig: - struct_name_map[orig] = struct - - # Step 3: 更新成员类型,确保使用正确的 mangled struct 引用 - for ClassName in all_classes: - if ClassName not in self.class_members: - continue - for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): - if isinstance(member_type, ir.PointerType): - pointee: ir.Type = member_type.pointee - if isinstance(pointee, ir.IdentifiedStructType): - pname: str | None - try: - pname = pointee.name - except AssertionError: - pname = None - struct: ir.IdentifiedStructType | None = struct_name_map.get(pname) if pname else None - if struct is None: - orig: Any = getattr(pointee, '_original_name', None) - struct = struct_name_map.get(orig) if orig else None - if struct is not None: - self.class_members[ClassName][i] = (member_name, ir.PointerType(struct)) - else: - raw_name: str = pname or '' - if raw_name.startswith('struct.'): - raw_name = raw_name[7:] - new_struct: ir.IdentifiedStructType = self._get_or_create_struct(raw_name) - self.class_members[ClassName][i] = (member_name, ir.PointerType(new_struct)) - elif isinstance(member_type, ir.IdentifiedStructType): - mname: str | None - try: - mname = member_type.name - except AssertionError: - mname = None - struct: ir.IdentifiedStructType | None = struct_name_map.get(mname) if mname else None - if struct is None: - orig: Any = getattr(member_type, '_original_name', None) - struct = struct_name_map.get(orig) if orig else None - if struct is not None: - self.class_members[ClassName][i] = (member_name, struct) - else: - raw_name: str = mname or '' - if raw_name.startswith('struct.'): - raw_name = raw_name[7:] - new_struct: ir.IdentifiedStructType = self._get_or_create_struct(raw_name) - self.class_members[ClassName][i] = (member_name, new_struct) - - # Step 4: 创建最终的 structs 并设置正确的成员类型 - for ClassName in all_classes: - if self.SymbolTable: - Entry = self.SymbolTable.lookup(ClassName) - if Entry and Entry.IsExceptionClass: - continue - # 注意:类名可能与 CEnum 成员名冲突(如 ASTKind.Constant 枚举成员与 Constant 类同名) - # 如果 ClassName 在 class_methods 中,表明是 _EmitClassLlvm 显式处理的常规类, - # 不应被 IsEnum 检查跳过(与 Step 1 的守卫保持一致) - if Entry and Entry.IsEnum and ClassName not in self.class_methods: - if not Entry.IsRenum: - continue - existing_st: ir.IdentifiedStructType | None = self.structs.get(ClassName) - if isinstance(existing_st, ir.IdentifiedStructType) and existing_st.elements is not None and len(existing_st.elements) > 0: - # 治本修复:检查 struct body 是否不完整(元素数少于 class_members + vtable 预期)。 - # 常见于跨模块继承:子类 struct 在父类 class_members 加载前从 stub 生成, - # stub 中的定义可能不完整或类型不正确(如 GSList* 代替 AST*、i8* 代替 i32)。 - # 此处检测到不完整后清除 _elements 和 stub 缓存,让后续代码重新从 stub 加载。 - _has_vtable_precheck: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes - if not _has_vtable_precheck: - _p_pre: str | None = self.class_parent.get(ClassName) - while _p_pre: - if _p_pre in self.class_vtable or _p_pre in self._cross_module_vtable_classes: - _has_vtable_precheck = True - break - _p_pre = self.class_parent.get(_p_pre) - _expected_count_pre: int = len(self.class_members.get(ClassName, [])) + (1 if _has_vtable_precheck else 0) - # has_vtable 时,首字段必须是 i8*(vtable 指针)。 - # 若首字段非指针(如 i8 占位符),struct body 不完整,需清除重新加载。 - _vtable_first_ok: bool = True - if _has_vtable_precheck and len(existing_st.elements) > 0: - _vtable_first_ok = isinstance(existing_st.elements[0], ir.PointerType) - # 检测 T* 占位类型(未特化的泛型类型参数)。 - # 当 struct 包含 T* 字段时(如 BasicBlock 继承 GSListNode[BasicBlock] 但 stub 未特化), - # 说明 stub 使用了未特化的基类,需清除重新生成。 - _has_t_placeholder_pre: bool = False - for _elem_pre in existing_st.elements: - if isinstance(_elem_pre, ir.PointerType) and isinstance(_elem_pre.pointee, ir.IdentifiedStructType): - _pname_pre: str = _elem_pre.pointee.name - _short_pre: str = _pname_pre.rsplit('.', 1)[-1] if '.' in _pname_pre else _pname_pre - if _short_pre == 'T': - _has_t_placeholder_pre = True - break - if len(existing_st.elements) >= _expected_count_pre and _vtable_first_ok and not _has_t_placeholder_pre: - if ClassName in self.class_packed and not existing_st.packed: - existing_st.packed = True - continue - # struct body 不完整,清除 _elements 和 stub 缓存以便重新加载 - existing_st._elements = None - # 同时清除 sha1 全名 key 的 _elements: - # self.structs 中可能同时存在 'Value'(短名) 和 'f9e36e2cd6fa659f.Value'(sha1全名) 两个 key, - # _TryLoadStructFromStub 调用 _get_or_create_struct 时会返回 sha1全名 key 的 struct。 - # 若只清除短名 key 的 _elements,sha1全名 key 的 struct 仍保持错误 body(is_opaque=False), - # 导致 _TryLoadStructFromStub 跳过 set_body,struct 保持不完整字段数。 - _imported_sha1_pre: str = self.class_sha1_map.get(ClassName, '') - if _imported_sha1_pre: - _full_key_pre: str = f"{_imported_sha1_pre}.{ClassName}" - _full_st_pre: ir.IdentifiedStructType | None = self.structs.get(_full_key_pre) - if _full_st_pre is not None and isinstance(_full_st_pre, ir.IdentifiedStructType): - _full_st_pre._elements = None - _import_handler_pre: Any = self._import_handler_ref - if _import_handler_pre is not None: - _cache_key_pre: tuple = (id(self), ClassName) - if _cache_key_pre in _import_handler_pre._struct_Load_cache: - del _import_handler_pre._struct_Load_cache[_cache_key_pre] - # 同时清除 sha1全名 key 的 stub 缓存 - if _imported_sha1_pre: - _cache_key_full_pre: tuple = (id(self), f"{_imported_sha1_pre}.{ClassName}") - if _cache_key_full_pre in _import_handler_pre._struct_Load_cache: - del _import_handler_pre._struct_Load_cache[_cache_key_full_pre] - has_vtable: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes - if not has_vtable: - p: str | None = self.class_parent.get(ClassName) - while p: - if p in self.class_vtable or p in self._cross_module_vtable_classes: - has_vtable = True - self.class_vtable.add(ClassName) - break - p = self.class_parent.get(p) - has_bitfield: bool = ClassName in self.class_member_bitfields and any( - self.class_member_bitfields[ClassName].get(name, 0) > 0 - for name, _ in self.class_members.get(ClassName, []) - ) - all_members: list[tuple[str, ir.Type]] = self.class_members.get(ClassName, []) - # 跳过正在发射中且成员尚未填充的类(递归特化时避免过早设置空 body) - if not all_members and not has_vtable and ClassName in self._classes_in_progress: - continue - # 字段收集期间触发的嵌套 _generate_structs:class_members 可能不完整, - # set_body 只能调用一次,跳过等字段收集完成后再设置 body - if ClassName in self._collecting_members_set: - continue - all_bitfield: bool = all( - self.class_member_bitfields.get(ClassName, {}).get(name, 0) > 0 - for name, _ in all_members - ) if all_members else False - - mangled_name: str = self._mangle_name(ClassName) - - member_types: list[ir.Type] - if has_bitfield and all_bitfield: - total_bits: int = sum(self.class_member_bitfields.get(ClassName, {}).get(name, 0) - for name, _ in all_members) - storage_type: ir.IntType - if total_bits <= 8: - storage_type = ir.IntType(8) - elif total_bits <= 16: - storage_type = ir.IntType(16) - elif total_bits <= 32: - storage_type = ir.IntType(32) - else: - storage_type = ir.IntType(64) - member_types = [storage_type] - bitfield_offsets: dict[str, int] = {} - current_bit_offset: int = 0 - for name, _ in all_members: - bit_width: int = self.class_member_bitfields.get(ClassName, {}).get(name, 0) - bitfield_offsets[name] = current_bit_offset - current_bit_offset += bit_width - self.class_member_bitoffsets[ClassName] = bitfield_offsets - else: - member_types = [] - if has_vtable: - member_types.append(ir.PointerType(ir.IntType(8))) - if ClassName in self.class_members: - for _, member_type in self.class_members[ClassName]: - if member_type is None: - member_type = ir.IntType(32) - member_types.append(member_type) - else: - if has_vtable: - # has_vtable 但 class_members 为空(跨模块导入类): - # 保持 member_types 为空([i8*] 占位会导致 stub 加载跳过, - # 因为 set_body 后 is_opaque=False)。让 struct 保持 opaque, - # 由 _TryLoadStructFromStub 设置完整 body。 - member_types = [] - else: - # 无 vtable 且 class_members 为空:常见于 register_method 早期 - # 调用 _generate_structs(此时 class_members[ClassName]=[] 但尚未 - # 填充实际字段)。保持 opaque,避免 set_body(*[i8]) 永久损坏 struct - # (llvmlite 的 set_body 只能调用一次)。后续 _generate_structs 调用 - # 会从 class_members 或 stub 设置正确 body。 - member_types = [] - - # 获取之前创建的 struct 并设置成员 - struct_type: ir.IdentifiedStructType = self.structs[ClassName] - if ClassName in self.class_packed: - struct_type.packed = True - # 只在未设置 body 时设置,避免重复定义错误 - if struct_type.elements is None: - # 跨模块 struct 的 class_members 可能不完整(当前模块只解析了部分字段), - # 优先从 stub.ll 加载完整定义。set_body 只能对 opaque struct 调用一次, - # 若用不完整 class_members 设置 body,后续无法修正,会导致 GEP 越界。 - # 但本地定义的类(_classes_in_progress)不从 stub 加载,因为 stub 可能 - # 来自同名导入类,其 vtable 状态与本地定义不同(@t.NoVTable 冲突) - import_handler: Any = self._import_handler_ref - if import_handler is not None and ClassName not in self._classes_in_progress: - try: - # 传入 source_sha1 确保从正确的 stub 文件加载完整定义 - _src_sha1: str = self.class_sha1_map.get(ClassName, '') - import_handler._TryLoadStructFromStub(ClassName, self, source_sha1=_src_sha1 or None) - except Exception: - pass - struct_type = self.structs.get(ClassName, struct_type) - # 检测 stub body 中的 T* 占位类型(未特化的泛型类型参数)。 - # 若 stub 使用了未特化的基类(如 GSListNode 而非 GSListNode[BasicBlock]), - # 清除 _elements 让 set_body 用正确的 class_members 重新设置。 - if struct_type.elements is not None and member_types: - _has_t_placeholder_post: bool = False - for _elem_post in struct_type.elements: - if isinstance(_elem_post, ir.PointerType) and isinstance(_elem_post.pointee, ir.IdentifiedStructType): - _pname_post: str = _elem_post.pointee.name - _short_post: str = _pname_post.rsplit('.', 1)[-1] if '.' in _pname_post else _pname_post - if _short_post == 'T': - _has_t_placeholder_post = True - break - if _has_t_placeholder_post: - struct_type._elements = None - if struct_type.elements is None: - # 防御性检查:member_types 为空时不调用 set_body。 - # set_body(*[]) 会设置 elements=() 使 is_opaque=False, - # 后续无法再次 set_body(llvmlite 限制),导致跨模块类型永久损坏。 - # 根因:register_method 在 class_members[ClassName]=[] 时立即调用 - # _generate_structs,此时 member_types 为空。保持 opaque 状态, - # 让后续 _TryLoadStructFromStub 能正确设置 body。 - if member_types: - struct_type.set_body(*member_types) - - def _create_Vtable_globals(self) -> None: - for ClassName, methods in self.class_methods.items(): - if ClassName in self.Vtables: - continue - if not methods: - continue - if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes: - continue - # 跳过正在发射中的类:它们的方法列表可能还不完整(如继承方法已添加但自有方法未添加), - # 此时创建 vtable 会导致大小不匹配。这些类的 vtable 会在其 _EmitClassLlvm 完成后 - # 由 _create_vtable_for_class 显式创建,或在模块级 _create_Vtable_globals 调用中创建。 - if ClassName in self._classes_in_progress: - continue - # 跨模块虚表过滤:_precollect_vtable_state 会将所有 includes 的有方法类同时加入 - # _shared_class_vtable 和 _shared_cross_module_vtable,导致 class_vtable 与 - # _cross_module_vtable_classes 内容相同,无法用以区分本模块类与跨模块类。 - # _generate_structs 会为所有 class_methods 的类创建空 struct type,导致 self.structs - # 也包含所有类。过滤条件是 self.functions:只考虑本模块定义的函数(define,有函数体), - # 跳过跨模块的 declare(无函数体)。跨模块类的 declare 通过 HandlesImports 加入 - # self.functions(短名如 "MemManager.alloc"),但其 is_declaration=True。 - # 若只存在 declare 而无 define,说明本模块未定义该类,虚表应由定义模块创建。 - # vtable linkage='internal',跨模块调用通过对象的 vtable 指针(首字段)完成分派, - # 不依赖本模块的 vtable 全局变量。 - has_local_method: bool = False - prefix: str = f"{ClassName}." - for func_name, func_obj in self.functions.items(): - if func_name.startswith(prefix): - # 跳过跨模块的 declare(无函数体),只考虑本模块定义的函数 - if not getattr(func_obj, 'is_declaration', False): - has_local_method = True - break - if not has_local_method: - continue - VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) - Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=self._mangle_name(f"{ClassName}_Vtable")) - Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) - # 保持默认 linkage(空字符串,带 initializer 自动打印为外部强定义 - # global,llvmlite descr 规则:initializer 非空时 linkage 归一为空)。 - # 2026-08-10:跨模块 isinstance 需引用 sha1.Class_Vtable 符号, - # vtable 名含模块 sha1 前缀全局唯一,外部可见不会冲突。 - self.Vtables[ClassName] = Vtable - - def _create_vtable_for_class(self, ClassName: str) -> None: - """为单个类创建 vtable(用于 _EmitClassLlvm 中当前类的方法已全部注册后)。""" - methods: list = self.class_methods.get(ClassName, []) - if not methods: - return - if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes: - return - _vtable_name: str = self._mangle_name(f"{ClassName}_Vtable") - # 如果虚表已在导入阶段创建(方法列表不完整,缺少继承方法),删除旧虚表 - if ClassName in self.Vtables: - _old_vtable = self.Vtables[ClassName] - _old_name = _old_vtable.name - if _old_name in self.module.globals: - del self.module.globals[_old_name] - # llvmlite 的 NameScope._useset 追踪所有已使用的名字, - # del module.globals[name] 不会从 _useset 移除, - # 导致再次创建同名 GlobalVariable 时 scope.register() 报 DuplicatedNameError - self.module.scope._useset.discard(_old_name) - del self.Vtables[ClassName] - # 防御性:如果全局变量已存在但不在 Vtables 字典中,也删除 - if _vtable_name in self.module.globals: - del self.module.globals[_vtable_name] - self.module.scope._useset.discard(_vtable_name) - VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) - Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=_vtable_name) - Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) - # 默认 linkage(外部强定义),跨模块 isinstance 引用(与 _create_Vtable_globals 一致) - self.Vtables[ClassName] = Vtable - - def _fix_global_var_init(self) -> None: - for gv_name, gv in list(self.module.globals.items()): - if not isinstance(gv, ir.GlobalVariable): - continue - if gv.linkage in ('external', 'extern_weak'): - continue - needs_fix: bool = False - if gv.initializer is None: - needs_fix = True - elif hasattr(gv.initializer, 'constant') and isinstance(gv.initializer.constant, _Undefined): - needs_fix = True - elif isinstance(gv.initializer, ir.Constant): - if isinstance(gv.initializer.constant, list): - if any(hasattr(c, 'constant') and isinstance(c.constant, _Undefined) for c in gv.initializer.constant): - needs_fix = True - if not needs_fix: - continue - gv.initializer = ir.Constant(gv.value_type, None) - if gv_name.startswith('str_const_') or gv_name.endswith('_Vtable') or gv_name.endswith('_str'): - gv.linkage = 'internal' - - def _set_Vtable_initializers(self) -> None: - for ClassName, methods in self.class_methods.items(): - if ClassName not in self.Vtables: - continue - if not methods: - continue - struct_type: ir.IdentifiedStructType | None = self.structs.get(ClassName) - if struct_type is None: - continue - Vtable: ir.GlobalVariable = self.Vtables[ClassName] - Vtable_entries: list[ir.Constant] = [] - for MethodName in methods: - short_name: str = MethodName.split('.')[-1] if '.' in MethodName else MethodName - # 多继承:vtable 槽直接用完整方法名(实际定义类.方法,如 B.get_b) - func: ir.Function | None = None - if MethodName in self.functions: - func = self.functions[MethodName] - if func is None: - full_MethodName: str = f"{ClassName}.{short_name}" - if full_MethodName in self.functions: - func = self.functions[full_MethodName] - if func is None: - # 沿 MRO 祖先链查找定义类(先声明父类优先) - for anc in self._get_mro_chain(ClassName)[1:]: - parent_full: str = f"{anc}.{short_name}" - if parent_full in self.functions: - func = self.functions[parent_full] - break - if func is None: - Vtable_entries.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) - continue - Vtable_entries.append(func.bitcast(ir.PointerType(ir.IntType(8)))) +from __future__ import annotations +from typing import Any +import re +import vast as ast +import llvmlite.ir as ir +from llvmlite.ir.values import _Undefined +from lib.includes import t as _t + + +class StructGenMixin: + + def _get_align(self, llvm_type: ir.Type) -> int: + if isinstance(llvm_type, ir.IntType): + return max(1, llvm_type.width // 8) + if isinstance(llvm_type, ir.FloatType): + return 4 + if isinstance(llvm_type, ir.DoubleType): + return 8 + if isinstance(llvm_type, ir.PointerType): + return self.ptr_size + if isinstance(llvm_type, ir.ArrayType): + return self._get_align(llvm_type.element) + if isinstance(llvm_type, ir.LiteralStructType): + return max((self._get_align(f) for f in llvm_type.elements), default=1) + if isinstance(llvm_type, ir.IdentifiedStructType): + if llvm_type.elements is None or len(llvm_type.elements) == 0: + return self.ptr_size # opaque struct, assume pointer alignment + return max((self._get_align(f) for f in llvm_type.elements), default=1) + if isinstance(llvm_type, ir.VoidType): + return 0 + return 4 + + def _resolve_opaque_struct(self, llvm_type: ir.Type) -> ir.Type: + """尝试从 Gen.structs 中查找已解析的同名 struct,解决跨模块 struct 类型对象不一致的问题""" + if not isinstance(llvm_type, ir.IdentifiedStructType): + return llvm_type + if llvm_type.elements is not None and len(llvm_type.elements) > 0: + return llvm_type + # opaque struct,尝试通过名称在 Gen.structs 中查找已解析的版本 + st_name: str + try: + st_name = llvm_type.name + except Exception: + return llvm_type + if not st_name: + return llvm_type + # 提取短名称 + short_name: str = st_name + if '.' in st_name: + short_name = st_name.split('.', 1)[1] + # 尝试短名称查找 + if short_name in self.structs: + resolved: ir.IdentifiedStructType = self.structs[short_name] + if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: + return resolved + # 尝试全名查找 + if st_name in self.structs: + resolved: ir.IdentifiedStructType = self.structs[st_name] + if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: + return resolved + # 尝试通过导入处理器从 stub 文件加载 struct 定义 + import_handler: Any = self._import_handler_ref + if import_handler is not None: + try: + import_handler._TryLoadStructFromStub(short_name, self) + except Exception: + pass + # 加载后再次查找 + if short_name in self.structs: + resolved = self.structs[short_name] + if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: + return resolved + if st_name in self.structs: + resolved = self.structs[st_name] + if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0: + return resolved + return llvm_type + + def _get_struct_size(self, llvm_type: ir.Type) -> int: + if isinstance(llvm_type, ir.IntType): + return max(1, llvm_type.width // 8) + if isinstance(llvm_type, ir.FloatType): + return 4 + if isinstance(llvm_type, ir.DoubleType): + return 8 + if isinstance(llvm_type, ir.PointerType): + return self.ptr_size + if isinstance(llvm_type, ir.ArrayType): + return self._get_struct_size(llvm_type.element) * llvm_type.count + if isinstance(llvm_type, ir.LiteralStructType): + total: int = 0 + max_align: int = 1 + for f in llvm_type.fields: + fa: int = self._get_align(f) + fs: int = self._get_struct_size(f) + max_align = max(max_align, fa) + if fa > 1: + total = (total + fa - 1) // fa * fa + total += fs + if max_align > 1: + total = (total + max_align - 1) // max_align * max_align + return total + if isinstance(llvm_type, ir.IdentifiedStructType): + # 尝试解析 opaque struct 为已注册的版本 + llvm_type = self._resolve_opaque_struct(llvm_type) + if llvm_type.elements is None or len(llvm_type.elements) == 0: + return self.ptr_size # opaque struct, assume pointer size + total: int = 0 + max_align: int = 1 + for f in llvm_type.elements: + fa: int = self._get_align(f) + fs: int = self._get_struct_size(f) + max_align = max(max_align, fa) + if fa > 1: + total = (total + fa - 1) // fa * fa + total += fs + if max_align > 1: + total = (total + max_align - 1) // max_align * max_align + return total + return 4 + + @staticmethod + def _strip_unnecessary_quotes(ir_str: str) -> str: + def _unquote(m: re.Match) -> str: + prefix: str = m.group(1) + name: str = m.group(2) + if '.' in name: + return m.group(0) + if re.match(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$', name): + return prefix + name + return m.group(0) + return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str) + + def finalize(self) -> str: + self._set_Vtable_initializers() + self._fix_global_var_init() + ir_text: str + try: + ir_text = str(self.module) + except TypeError as e: + for func in self.module.functions: + for block in func.blocks: + for instr in block.instructions: + try: + str(instr) + except TypeError as te: + pass + raise + ir_text = self._strip_unnecessary_quotes(ir_text) + struct_defs: list[str] = [] + struct_names: set[str] = set() + for ClassName, struct_type in self.structs.items(): + if isinstance(struct_type, ir.IdentifiedStructType): + sname: str = struct_type.name + sname_ir: str + if sname[0].isdigit() or '.' in sname or not sname.replace('_', '').replace('.', '').isalnum(): + sname_ir = f'%"{sname}"' + else: + sname_ir = f'%{sname}' + if struct_type.elements is None or len(struct_type.elements) == 0: + if ClassName not in self.typedef_int_widths: + struct_names.add(sname) + struct_defs.append(f'{sname_ir} = type opaque') + continue + elems: str = ', '.join(str(e) for e in struct_type.elements) + if struct_type.packed: + struct_defs.append(f'{sname_ir} = type <{{ {elems} }}>') + else: + struct_defs.append(f'{sname_ir} = type {{ {elems} }}') + struct_names.add(sname) + if struct_defs: + lines: list[str] = ir_text.split('\n') + filtered: list[str] = [] + for line in lines: + stripped: str = line.strip() + skip: bool = False + for name in struct_names: + patterns: list[str] + if name[0].isdigit() or '.' in name or not name.replace('_', '').replace('.', '').isalnum(): + patterns = [f'%"{name}" = type', f'%"{name}"=type', f'%{name} = type', f'%{name}=type'] + else: + patterns = [f'%{name} = type', f'%{name}= type', f'%{name}=type'] + for p in patterns: + if stripped.startswith(p): + skip = True + break + if skip: + break + if not skip: + filtered.append(line) + ir_text = '\n'.join(filtered) + header_end: int = ir_text.find('\ndefine') + if header_end == -1: + header_end = ir_text.find('\ndeclare') + if header_end == -1: + header_end = ir_text.find('\n@') + if header_end == -1: + header_end = len(ir_text) + insert_pos: int = ir_text.rfind('\n', 0, header_end) + if insert_pos == -1: + insert_pos = header_end + struct_block: str = '\n'.join(struct_defs) + '\n' + ir_text = ir_text[:insert_pos + 1] + struct_block + ir_text[insert_pos + 1:] + for name in struct_names: + if name[0].isdigit() or '.' in name: + ir_text = re.sub( + r'%' + re.escape(name) + r'(?=[^a-zA-Z0-9_$\.]|$)', + r'%"' + name + r'"', + ir_text + ) + + return ir_text + + def _generate_structs(self) -> None: + all_classes: set[str] = set(self.class_methods.keys()) | set(self.class_members.keys()) + + preserved_structs: dict[str, ir.IdentifiedStructType] = {} + for name, st in self.structs.items(): + if name not in all_classes: + preserved_structs[name] = st + elif isinstance(st, ir.IdentifiedStructType): + preserved_structs[name] = st + + self.structs.clear() + + for name, st in preserved_structs.items(): + self.structs[name] = st + + # Step 1: 先为所有类创建空的 struct,确保后面可以正确引用 + all_classes = set(self.class_methods.keys()) | set(self.class_members.keys()) + for ClassName in all_classes: + is_packed: bool = ClassName in self.class_packed + if self.SymbolTable: + Entry = self.SymbolTable.lookup(ClassName) + if Entry and Entry.IsExceptionClass: + continue + # 注意:类名可能与 CEnum 成员名冲突(如 ASTKind.Module 枚举成员与 Module 类同名) + # 如果 ClassName 在 class_methods 中,表明是 _EmitClassLlvm 显式处理的常规类, + # 不应被 IsEnum/IsTypedef 检查跳过 + if Entry and Entry.IsEnum and ClassName not in self.class_methods: + if not Entry.IsRenum: + continue + if Entry and Entry.IsTypedef and ClassName not in self.class_methods: + if Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)): + if not isinstance(Entry.BaseType, (_t._CTypedef,)): + continue + if ClassName in self.structs: + if is_packed: + self.structs[ClassName].packed = True + continue + # 修复跨模块类型定义冲突:如果类是从其他模块导入的(已在 class_sha1_map 注册), + # 必须使用导入的 source_sha1 作为前缀,而非本地模块的 sha1。 + # 否则会创建缺少基类字段(如 GSListNode.Next)的本地类型定义, + # 导致字段索引错位 → 访问违规崩溃。 + _imported_sha1: str = self.class_sha1_map.get(ClassName, '') + if _imported_sha1: + mangled_name: str = f"{_imported_sha1}.{ClassName}" + else: + mangled_name: str = self._mangle_name(ClassName) + struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, mangled_name, packed=is_packed) + self.structs[ClassName] = struct_type + + # Step 2: 解析跨模块的成员类型 + for ClassName, annotations in self.class_member_annotations.items(): + if ClassName not in self.class_members: + continue + for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): + if member_name in annotations: + annotation: Any = annotations[member_name] + ResolvedType: ir.Type | None = None + + if isinstance(annotation, ast.Attribute): + 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] + + if ResolvedType: + self.class_members[ClassName][i] = (member_name, ResolvedType) + + struct_name_map: dict[str, ir.IdentifiedStructType] = {} + for struct_name, struct in self.structs.items(): + try: + struct_name_map[struct.name] = struct + except AssertionError: + struct_name_map[struct_name] = struct + orig: Any = getattr(struct, '_original_name', None) + if orig: + struct_name_map[orig] = struct + + # Step 3: 更新成员类型,确保使用正确的 mangled struct 引用 + for ClassName in all_classes: + if ClassName not in self.class_members: + continue + for i, (member_name, member_type) in enumerate(self.class_members[ClassName]): + if isinstance(member_type, ir.PointerType): + pointee: ir.Type = member_type.pointee + if isinstance(pointee, ir.IdentifiedStructType): + pname: str | None + try: + pname = pointee.name + except AssertionError: + pname = None + struct: ir.IdentifiedStructType | None = struct_name_map.get(pname) if pname else None + if struct is None: + orig: Any = getattr(pointee, '_original_name', None) + struct = struct_name_map.get(orig) if orig else None + if struct is not None: + self.class_members[ClassName][i] = (member_name, ir.PointerType(struct)) + else: + raw_name: str = pname or '' + if raw_name.startswith('struct.'): + raw_name = raw_name[7:] + new_struct: ir.IdentifiedStructType = self._get_or_create_struct(raw_name) + self.class_members[ClassName][i] = (member_name, ir.PointerType(new_struct)) + elif isinstance(member_type, ir.IdentifiedStructType): + mname: str | None + try: + mname = member_type.name + except AssertionError: + mname = None + struct: ir.IdentifiedStructType | None = struct_name_map.get(mname) if mname else None + if struct is None: + orig: Any = getattr(member_type, '_original_name', None) + struct = struct_name_map.get(orig) if orig else None + if struct is not None: + self.class_members[ClassName][i] = (member_name, struct) + else: + raw_name: str = mname or '' + if raw_name.startswith('struct.'): + raw_name = raw_name[7:] + new_struct: ir.IdentifiedStructType = self._get_or_create_struct(raw_name) + self.class_members[ClassName][i] = (member_name, new_struct) + + # Step 4: 创建最终的 structs 并设置正确的成员类型 + for ClassName in all_classes: + if self.SymbolTable: + Entry = self.SymbolTable.lookup(ClassName) + if Entry and Entry.IsExceptionClass: + continue + # 注意:类名可能与 CEnum 成员名冲突(如 ASTKind.Constant 枚举成员与 Constant 类同名) + # 如果 ClassName 在 class_methods 中,表明是 _EmitClassLlvm 显式处理的常规类, + # 不应被 IsEnum 检查跳过(与 Step 1 的守卫保持一致) + if Entry and Entry.IsEnum and ClassName not in self.class_methods: + if not Entry.IsRenum: + continue + existing_st: ir.IdentifiedStructType | None = self.structs.get(ClassName) + if isinstance(existing_st, ir.IdentifiedStructType) and existing_st.elements is not None and len(existing_st.elements) > 0: + # 治本修复:检查 struct body 是否不完整(元素数少于 class_members + vtable 预期)。 + # 常见于跨模块继承:子类 struct 在父类 class_members 加载前从 stub 生成, + # stub 中的定义可能不完整或类型不正确(如 GSList* 代替 AST*、i8* 代替 i32)。 + # 此处检测到不完整后清除 _elements 和 stub 缓存,让后续代码重新从 stub 加载。 + _has_vtable_precheck: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes + if not _has_vtable_precheck: + _p_pre: str | None = self.class_parent.get(ClassName) + while _p_pre: + if _p_pre in self.class_vtable or _p_pre in self._cross_module_vtable_classes: + _has_vtable_precheck = True + break + _p_pre = self.class_parent.get(_p_pre) + _expected_count_pre: int = len(self.class_members.get(ClassName, [])) + (1 if _has_vtable_precheck else 0) + # has_vtable 时,首字段必须是 i8*(vtable 指针)。 + # 若首字段非指针(如 i8 占位符),struct body 不完整,需清除重新加载。 + _vtable_first_ok: bool = True + if _has_vtable_precheck and len(existing_st.elements) > 0: + _vtable_first_ok = isinstance(existing_st.elements[0], ir.PointerType) + # 检测 T* 占位类型(未特化的泛型类型参数)。 + # 当 struct 包含 T* 字段时(如 BasicBlock 继承 GSListNode[BasicBlock] 但 stub 未特化), + # 说明 stub 使用了未特化的基类,需清除重新生成。 + _has_t_placeholder_pre: bool = False + for _elem_pre in existing_st.elements: + if isinstance(_elem_pre, ir.PointerType) and isinstance(_elem_pre.pointee, ir.IdentifiedStructType): + _pname_pre: str = _elem_pre.pointee.name + _short_pre: str = _pname_pre.rsplit('.', 1)[-1] if '.' in _pname_pre else _pname_pre + if _short_pre == 'T': + _has_t_placeholder_pre = True + break + if len(existing_st.elements) >= _expected_count_pre and _vtable_first_ok and not _has_t_placeholder_pre: + if ClassName in self.class_packed and not existing_st.packed: + existing_st.packed = True + continue + # struct body 不完整,清除 _elements 和 stub 缓存以便重新加载 + existing_st._elements = None + # 同时清除 sha1 全名 key 的 _elements: + # self.structs 中可能同时存在 'Value'(短名) 和 'f9e36e2cd6fa659f.Value'(sha1全名) 两个 key, + # _TryLoadStructFromStub 调用 _get_or_create_struct 时会返回 sha1全名 key 的 struct。 + # 若只清除短名 key 的 _elements,sha1全名 key 的 struct 仍保持错误 body(is_opaque=False), + # 导致 _TryLoadStructFromStub 跳过 set_body,struct 保持不完整字段数。 + _imported_sha1_pre: str = self.class_sha1_map.get(ClassName, '') + if _imported_sha1_pre: + _full_key_pre: str = f"{_imported_sha1_pre}.{ClassName}" + _full_st_pre: ir.IdentifiedStructType | None = self.structs.get(_full_key_pre) + if _full_st_pre is not None and isinstance(_full_st_pre, ir.IdentifiedStructType): + _full_st_pre._elements = None + _import_handler_pre: Any = self._import_handler_ref + if _import_handler_pre is not None: + _cache_key_pre: tuple = (id(self), ClassName) + if _cache_key_pre in _import_handler_pre._struct_Load_cache: + del _import_handler_pre._struct_Load_cache[_cache_key_pre] + # 同时清除 sha1全名 key 的 stub 缓存 + if _imported_sha1_pre: + _cache_key_full_pre: tuple = (id(self), f"{_imported_sha1_pre}.{ClassName}") + if _cache_key_full_pre in _import_handler_pre._struct_Load_cache: + del _import_handler_pre._struct_Load_cache[_cache_key_full_pre] + has_vtable: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes + if not has_vtable: + p: str | None = self.class_parent.get(ClassName) + while p: + if p in self.class_vtable or p in self._cross_module_vtable_classes: + has_vtable = True + self.class_vtable.add(ClassName) + break + p = self.class_parent.get(p) + has_bitfield: bool = ClassName in self.class_member_bitfields and any( + self.class_member_bitfields[ClassName].get(name, 0) > 0 + for name, _ in self.class_members.get(ClassName, []) + ) + all_members: list[tuple[str, ir.Type]] = self.class_members.get(ClassName, []) + # 跳过正在发射中且成员尚未填充的类(递归特化时避免过早设置空 body) + if not all_members and not has_vtable and ClassName in self._classes_in_progress: + continue + # 字段收集期间触发的嵌套 _generate_structs:class_members 可能不完整, + # set_body 只能调用一次,跳过等字段收集完成后再设置 body + if ClassName in self._collecting_members_set: + continue + all_bitfield: bool = all( + self.class_member_bitfields.get(ClassName, {}).get(name, 0) > 0 + for name, _ in all_members + ) if all_members else False + + mangled_name: str = self._mangle_name(ClassName) + + member_types: list[ir.Type] + if has_bitfield and all_bitfield: + total_bits: int = sum(self.class_member_bitfields.get(ClassName, {}).get(name, 0) + for name, _ in all_members) + storage_type: ir.IntType + if total_bits <= 8: + storage_type = ir.IntType(8) + elif total_bits <= 16: + storage_type = ir.IntType(16) + elif total_bits <= 32: + storage_type = ir.IntType(32) + else: + storage_type = ir.IntType(64) + member_types = [storage_type] + bitfield_offsets: dict[str, int] = {} + current_bit_offset: int = 0 + for name, _ in all_members: + bit_width: int = self.class_member_bitfields.get(ClassName, {}).get(name, 0) + bitfield_offsets[name] = current_bit_offset + current_bit_offset += bit_width + self.class_member_bitoffsets[ClassName] = bitfield_offsets + else: + member_types = [] + if has_vtable: + member_types.append(ir.PointerType(ir.IntType(8))) + if ClassName in self.class_members: + for _, member_type in self.class_members[ClassName]: + if member_type is None: + member_type = ir.IntType(32) + member_types.append(member_type) + else: + if has_vtable: + # has_vtable 但 class_members 为空(跨模块导入类): + # 保持 member_types 为空([i8*] 占位会导致 stub 加载跳过, + # 因为 set_body 后 is_opaque=False)。让 struct 保持 opaque, + # 由 _TryLoadStructFromStub 设置完整 body。 + member_types = [] + else: + # 无 vtable 且 class_members 为空:常见于 register_method 早期 + # 调用 _generate_structs(此时 class_members[ClassName]=[] 但尚未 + # 填充实际字段)。保持 opaque,避免 set_body(*[i8]) 永久损坏 struct + # (llvmlite 的 set_body 只能调用一次)。后续 _generate_structs 调用 + # 会从 class_members 或 stub 设置正确 body。 + member_types = [] + + # 获取之前创建的 struct 并设置成员 + struct_type: ir.IdentifiedStructType = self.structs[ClassName] + if ClassName in self.class_packed: + struct_type.packed = True + # 只在未设置 body 时设置,避免重复定义错误 + if struct_type.elements is None: + # 跨模块 struct 的 class_members 可能不完整(当前模块只解析了部分字段), + # 优先从 stub.ll 加载完整定义。set_body 只能对 opaque struct 调用一次, + # 若用不完整 class_members 设置 body,后续无法修正,会导致 GEP 越界。 + # 但本地定义的类(_classes_in_progress)不从 stub 加载,因为 stub 可能 + # 来自同名导入类,其 vtable 状态与本地定义不同(@t.NoVTable 冲突) + import_handler: Any = self._import_handler_ref + if import_handler is not None and ClassName not in self._classes_in_progress: + try: + # 传入 source_sha1 确保从正确的 stub 文件加载完整定义 + _src_sha1: str = self.class_sha1_map.get(ClassName, '') + import_handler._TryLoadStructFromStub(ClassName, self, source_sha1=_src_sha1 or None) + except Exception: + pass + struct_type = self.structs.get(ClassName, struct_type) + # 检测 stub body 中的 T* 占位类型(未特化的泛型类型参数)。 + # 若 stub 使用了未特化的基类(如 GSListNode 而非 GSListNode[BasicBlock]), + # 清除 _elements 让 set_body 用正确的 class_members 重新设置。 + if struct_type.elements is not None and member_types: + _has_t_placeholder_post: bool = False + for _elem_post in struct_type.elements: + if isinstance(_elem_post, ir.PointerType) and isinstance(_elem_post.pointee, ir.IdentifiedStructType): + _pname_post: str = _elem_post.pointee.name + _short_post: str = _pname_post.rsplit('.', 1)[-1] if '.' in _pname_post else _pname_post + if _short_post == 'T': + _has_t_placeholder_post = True + break + if _has_t_placeholder_post: + struct_type._elements = None + if struct_type.elements is None: + # 防御性检查:member_types 为空时不调用 set_body。 + # set_body(*[]) 会设置 elements=() 使 is_opaque=False, + # 后续无法再次 set_body(llvmlite 限制),导致跨模块类型永久损坏。 + # 根因:register_method 在 class_members[ClassName]=[] 时立即调用 + # _generate_structs,此时 member_types 为空。保持 opaque 状态, + # 让后续 _TryLoadStructFromStub 能正确设置 body。 + if member_types: + struct_type.set_body(*member_types) + + def _create_Vtable_globals(self) -> None: + for ClassName, methods in self.class_methods.items(): + if ClassName in self.Vtables: + continue + if not methods: + continue + if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes: + continue + # 跳过正在发射中的类:它们的方法列表可能还不完整(如继承方法已添加但自有方法未添加), + # 此时创建 vtable 会导致大小不匹配。这些类的 vtable 会在其 _EmitClassLlvm 完成后 + # 由 _create_vtable_for_class 显式创建,或在模块级 _create_Vtable_globals 调用中创建。 + if ClassName in self._classes_in_progress: + continue + # 跨模块虚表过滤:_precollect_vtable_state 会将所有 includes 的有方法类同时加入 + # _shared_class_vtable 和 _shared_cross_module_vtable,导致 class_vtable 与 + # _cross_module_vtable_classes 内容相同,无法用以区分本模块类与跨模块类。 + # _generate_structs 会为所有 class_methods 的类创建空 struct type,导致 self.structs + # 也包含所有类。过滤条件是 self.functions:只考虑本模块定义的函数(define,有函数体), + # 跳过跨模块的 declare(无函数体)。跨模块类的 declare 通过 HandlesImports 加入 + # self.functions(短名如 "MemManager.alloc"),但其 is_declaration=True。 + # 若只存在 declare 而无 define,说明本模块未定义该类,虚表应由定义模块创建。 + # vtable linkage='internal',跨模块调用通过对象的 vtable 指针(首字段)完成分派, + # 不依赖本模块的 vtable 全局变量。 + has_local_method: bool = False + prefix: str = f"{ClassName}." + for func_name, func_obj in self.functions.items(): + if func_name.startswith(prefix): + # 跳过跨模块的 declare(无函数体),只考虑本模块定义的函数 + if not getattr(func_obj, 'is_declaration', False): + has_local_method = True + break + if not has_local_method: + continue + VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) + Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=self._mangle_name(f"{ClassName}_Vtable")) + Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) + # 保持默认 linkage(空字符串,带 initializer 自动打印为外部强定义 + # global,llvmlite descr 规则:initializer 非空时 linkage 归一为空)。 + # 2026-08-10:跨模块 isinstance 需引用 sha1.Class_Vtable 符号, + # vtable 名含模块 sha1 前缀全局唯一,外部可见不会冲突。 + self.Vtables[ClassName] = Vtable + + def _create_vtable_for_class(self, ClassName: str) -> None: + """为单个类创建 vtable(用于 _EmitClassLlvm 中当前类的方法已全部注册后)。""" + methods: list = self.class_methods.get(ClassName, []) + if not methods: + return + if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes: + return + _vtable_name: str = self._mangle_name(f"{ClassName}_Vtable") + # 如果虚表已在导入阶段创建(方法列表不完整,缺少继承方法),删除旧虚表 + if ClassName in self.Vtables: + _old_vtable = self.Vtables[ClassName] + _old_name = _old_vtable.name + if _old_name in self.module.globals: + del self.module.globals[_old_name] + # llvmlite 的 NameScope._useset 追踪所有已使用的名字, + # del module.globals[name] 不会从 _useset 移除, + # 导致再次创建同名 GlobalVariable 时 scope.register() 报 DuplicatedNameError + self.module.scope._useset.discard(_old_name) + del self.Vtables[ClassName] + # 防御性:如果全局变量已存在但不在 Vtables 字典中,也删除 + if _vtable_name in self.module.globals: + del self.module.globals[_vtable_name] + self.module.scope._useset.discard(_vtable_name) + VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) + Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=_vtable_name) + Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods)) + # 默认 linkage(外部强定义),跨模块 isinstance 引用(与 _create_Vtable_globals 一致) + self.Vtables[ClassName] = Vtable + + def _fix_global_var_init(self) -> None: + for gv_name, gv in list(self.module.globals.items()): + if not isinstance(gv, ir.GlobalVariable): + continue + if gv.linkage in ('external', 'extern_weak'): + continue + needs_fix: bool = False + if gv.initializer is None: + needs_fix = True + elif hasattr(gv.initializer, 'constant') and isinstance(gv.initializer.constant, _Undefined): + needs_fix = True + elif isinstance(gv.initializer, ir.Constant): + if isinstance(gv.initializer.constant, list): + if any(hasattr(c, 'constant') and isinstance(c.constant, _Undefined) for c in gv.initializer.constant): + needs_fix = True + if not needs_fix: + continue + gv.initializer = ir.Constant(gv.value_type, None) + if gv_name.startswith('str_const_') or gv_name.endswith('_Vtable') or gv_name.endswith('_str'): + gv.linkage = 'internal' + + def _set_Vtable_initializers(self) -> None: + for ClassName, methods in self.class_methods.items(): + if ClassName not in self.Vtables: + continue + if not methods: + continue + struct_type: ir.IdentifiedStructType | None = self.structs.get(ClassName) + if struct_type is None: + continue + Vtable: ir.GlobalVariable = self.Vtables[ClassName] + Vtable_entries: list[ir.Constant] = [] + for MethodName in methods: + short_name: str = MethodName.split('.')[-1] if '.' in MethodName else MethodName + # 多继承:vtable 槽直接用完整方法名(实际定义类.方法,如 B.get_b) + func: ir.Function | None = None + if MethodName in self.functions: + func = self.functions[MethodName] + if func is None: + full_MethodName: str = f"{ClassName}.{short_name}" + if full_MethodName in self.functions: + func = self.functions[full_MethodName] + if func is None: + # 沿 MRO 祖先链查找定义类(先声明父类优先) + for anc in self._get_mro_chain(ClassName)[1:]: + parent_full: str = f"{anc}.{short_name}" + if parent_full in self.functions: + func = self.functions[parent_full] + break + if func is None: + Vtable_entries.append(ir.Constant(ir.PointerType(ir.IntType(8)), None)) + continue + Vtable_entries.append(func.bitcast(ir.PointerType(ir.IntType(8)))) Vtable.initializer = ir.Constant(Vtable.type.pointee, Vtable_entries) \ No newline at end of file diff --git a/lib/core/LLVMCG/TypeConvert.py b/lib/core/LLVMCG/TypeConvert.py index f32d5b9..2b03c36 100644 --- a/lib/core/LLVMCG/TypeConvert.py +++ b/lib/core/LLVMCG/TypeConvert.py @@ -1,767 +1,767 @@ -from __future__ import annotations -from typing import Any -import ast -import re -import logging -import llvmlite.ir as ir -from lib.includes import t as _t -from lib.includes.t import CTypeRegistry -from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, BuiltinTypeMap -from lib.constants.config import mode as _config_mode -from lib.core.VLogger import get_logger as _vlog -from lib.core.SymbolUtils import IsTModule - - -class TypeConvertMixin: - - # 限定符前缀映射表:(前缀字符串, 去除长度) - # 这些限定符(const/volatile/static/extern/register/inline/export/CAuto 等) - # 仅影响 C 语义,对 LLVM IR 类型本身无影响,统一去除后递归解析内部类型。 - _QUALIFIER_PREFIXES: tuple[tuple[str, int], ...] = ( - ('const ', 6), ('volatile ', 9), ('const_', 6), ('volatile_', 9), - ('static ', 7), ('extern ', 7), ('register ', 9), ('inline ', 7), - ('export ', 7), - ('CStatic ', 8), ('CExtern ', 8), ('CRegister ', 10), - ('CInline ', 8), ('CAuto ', 6), - ) - - def _ctype_to_llvm(self, type_info: _CTypeInfo | str | None) -> ir.Type: - if type_info is None: - return ir.IntType(32) - - if isinstance(type_info, str): - return self._type_str_to_llvm(type_info) - - if not isinstance(type_info, _CTypeInfo): - return ir.IntType(32) - - if type_info.IsFuncPtr: - ret_type: ir.Type = self._ctype_to_llvm(type_info.FuncPtrReturn) if type_info.FuncPtrReturn else ir.VoidType() - param_types: list[ir.Type] = [] - if type_info.FuncPtrParams: - for _name, param_info in type_info.FuncPtrParams: - if isinstance(param_info, _CTypeInfo): - param_types.append(self._ctype_to_llvm(param_info)) - else: - param_types.append(ir.IntType(32)) - fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types) - return ir.PointerType(fn_type) - - if type_info.IsState and type_info.PtrCount == 0 and not type_info.IsTypedef: - if type_info.BaseType is None or (isinstance(type_info.BaseType, type) and issubclass(type_info.BaseType, _t.CVoid)) or isinstance(type_info.BaseType, _t.CVoid): - return ir.VoidType() - - if type_info.IsTypedef and type_info.Name: - resolved: ir.Type | None = self._resolve_typedef_ctype(type_info) - if resolved is not None: - return resolved - - # REnum 类型:通过 Name 查找或创建结构体(BaseType 可能为 None) - # 这对 BinOp `LLVMType | t.CPtr` 合并后的 CTypeInfo 至关重要 - if type_info.IsRenum and type_info.Name: - if type_info.Name in self.structs: - base: ir.Type = self.structs[type_info.Name] - else: - base = self._get_or_create_struct(type_info.Name) - result: ir.Type = base - for _ in range(type_info.PtrCount): - result = ir.PointerType(result) - return result - - BaseType: ir.Type = self._base_ctype_to_llvm(type_info.BaseType, type_info) - - result: ir.Type = BaseType - for _ in range(type_info.PtrCount): - if isinstance(result, ir.VoidType): - result = ir.IntType(8).as_pointer() - else: - result = ir.PointerType(result) - - for dim in reversed(type_info.ArrayDims): - try: - dim_val: int = int(dim) - if dim_val > 0: - result = ir.ArrayType(result, dim_val) - except (ValueError, TypeError): - pass - - return result - - def _resolve_typedef_ctype(self, type_info: _CTypeInfo) -> ir.Type | None: - name: str = type_info.Name - if not name or not self.SymbolTable: - return None - - entry: Any = self.SymbolTable.lookup(name) - if not entry or not isinstance(entry, _CTypeInfo): - return None - - if entry.BaseType and (not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0): - resolved: Any = entry.Copy() - resolved.IsTypedef = False - if type_info.PtrCount > resolved.PtrCount: - resolved.PtrCount = type_info.PtrCount - return self._ctype_to_llvm(resolved) - - if entry.OriginalType: - if isinstance(entry.OriginalType, _CTypeInfo): - resolved: Any = entry.OriginalType.Copy() - resolved.IsTypedef = False - if type_info.PtrCount > resolved.PtrCount: - resolved.PtrCount = type_info.PtrCount - return self._ctype_to_llvm(resolved) - elif isinstance(entry.OriginalType, str): - resolved: Any = _CTypeInfo.FromTypeName(entry.OriginalType) - if resolved and resolved.BaseType: - resolved.IsTypedef = False - if type_info.PtrCount > resolved.PtrCount: - resolved.PtrCount = type_info.PtrCount - return self._ctype_to_llvm(resolved) - - return None - - def _base_ctype_to_llvm(self, BaseType: Any, type_info: _CTypeInfo | None = None) -> ir.Type: - if BaseType is None: - return ir.VoidType() - - if isinstance(BaseType, (tuple, list)): - elem_types: list[ir.Type] = [self._base_ctype_to_llvm(bt, type_info) for bt in BaseType] - return ir.LiteralStructType(elem_types) if elem_types else ir.IntType(32) - - if isinstance(BaseType, type) and issubclass(BaseType, _t.CType): - BaseType = BaseType() - - if isinstance(BaseType, _t.CVoid): - return ir.VoidType() - - if isinstance(BaseType, _t.CStruct): - struct_name: str = getattr(BaseType, 'name', '') or (type_info.Name if type_info else '') - if struct_name and struct_name in self.structs: - return self.structs[struct_name] - if struct_name: - return self._get_or_create_struct(struct_name) - return ir.LiteralStructType([]) - - if isinstance(BaseType, (_t.CEnum, _t.REnum)): - enum_name: str = type_info.Name if type_info else '' - if enum_name and enum_name in self.structs: - return self.structs[enum_name] - return ir.IntType(32) - - if isinstance(BaseType, _t.CUnion): - union_name: str = type_info.Name if type_info else '' - if union_name and union_name in self.structs: - return self.structs[union_name] - if union_name: - return self._get_or_create_struct(union_name) - return ir.IntType(32) - - if isinstance(BaseType, _t._CTypedef): - typedef_name: str = getattr(BaseType, 'value', '') or (type_info.Name if type_info else '') - if typedef_name and self.SymbolTable: - entry: Any = self.SymbolTable.lookup(typedef_name) - if entry and isinstance(entry, _CTypeInfo) and entry.BaseType: - if not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0: - return self._base_ctype_to_llvm(entry.BaseType, entry) - return ir.IntType(32) - - if isinstance(BaseType, _t.CDefine): - # Use 64-bit type if the define value exceeds 32-bit range - if type_info and isinstance(type_info.DefineValue, int): - if type_info.DefineValue < 0 or type_info.DefineValue > 0xFFFFFFFF: - return ir.IntType(64) - return ir.IntType(32) - - if isinstance(BaseType, _t.CPass): - return ir.VoidType() - - llvm_str: str = CTypeRegistry.CTypeToLLVM(type(BaseType)) - return self._llvm_str_to_ir(llvm_str) - - def _get_source_sha1_from_type_str(self, type_str: str) -> str | None: - """从类型字符串中提取模块名,返回对应的源模块 SHA1。 - 用于跨模块类型引用(如 memhub.MemBuddy),确保用源模块的 SHA1 创建 struct。 - """ - if not type_str or '.' not in type_str: - return None - # 去除指针标记和空格 - clean: str = type_str.replace('*', '').strip() - if '.' not in clean: - return None - # 提取模块名(最后一个 '.' 之前的部分) - parts: list[str] = clean.rsplit('.', 1) - if len(parts) < 2: - return None - module_name: str = parts[0] - # 跳过 t/c 等内建模块 - if module_name in {'t', 'c'}: - return None - # 从 ModuleSha1Map 查找 SHA1(支持完整路径名和短名) - sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {}) - source_sha1: str | None = sha1_map.get(module_name) - if not source_sha1 and '.' in module_name: - source_sha1 = sha1_map.get(module_name.split('.')[-1]) - 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'}: - return type_name - if type_name == 'Callable': - return 'Callable' - visited: set[str] = set() - current: str = type_name - while current not in visited: - visited.add(current) - if self.SymbolTable: - Entry: _CTypeInfo | None = self.SymbolTable.lookup(current) - if isinstance(Entry, dict) and Entry.get('type') == 'typedef': - OriginalType: str = Entry.get('OriginalType', '') - if OriginalType: - current = OriginalType - continue - elif Entry and Entry.IsTypedef: - if Entry.OriginalType: - if isinstance(Entry.OriginalType, _CTypeInfo): - if Entry.OriginalType.IsFuncPtr: - return 'Callable' - return Entry.OriginalType.ToString() if Entry.OriginalType.BaseType else current - elif isinstance(Entry.OriginalType, str): - current = Entry.OriginalType - continue - if Entry.BaseType: - if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0: - resolved: str = self._resolve_ctype_to_str(Entry) - if resolved and resolved != current: - current = resolved - continue - bm: Any = BuiltinTypeMap.Get(current) - if bm: - base_cls: Any = bm[0] - try: - instance: Any = base_cls() - cname: str = type(instance).__name__ - if cname: - current = cname + ' *' * bm[1] - continue - except Exception as _e: - if _config_mode == "strict": - logging.warning(f"异常被忽略: {_e}") - pass - bm: Any = BuiltinTypeMap.Get(current) - if bm and bm[1] > 0: - base_cls: Any = bm[0] - try: - instance: Any = base_cls() - cname: str = type(instance).__name__ - if cname: - current = cname + ' *' * bm[1] - continue - except Exception as _e: - if _config_mode == "strict": - logging.warning(f"异常被忽略: {_e}") - pass - break - return current - - def _resolve_ctype_to_str(self, type_info: _CTypeInfo) -> str: - parts: list[str] = [] - base: Any = type_info.BaseType - if base is None or base is _t.CVoid or isinstance(base, _t.CVoid): - parts.append('void') - elif isinstance(base, _t._CTypedef) or base is _t._CTypedef: - return '' - elif isinstance(base, _t.CStruct) or base is _t.CStruct: - parts.append(f'struct {getattr(base, "name", "")}') - elif isinstance(base, _t.CEnum) or base is _t.CEnum: - parts.append(f'enum {getattr(base, "name", "")}') - else: - cname: str = '' - if isinstance(base, type) and issubclass(base, _t.CType): - cname = base.__name__ - elif isinstance(base, _t.CType): - cname = type(base).__name__ - if cname: - parts.append(cname) - else: - return '' - if type_info.PtrCount > 0: - parts.append('*' * type_info.PtrCount) - return ' '.join(parts) - - def _type_str_to_llvm(self, type_str: str, IsPtr: bool = False) -> ir.Type: - type_str = type_str.strip() - cache_key: tuple[str, bool] = (type_str, IsPtr) - cached: ir.Type | None = self._type_cache.get(cache_key) - if cached is not None: - return cached - result: ir.Type = self._type_str_to_llvm_impl(type_str, IsPtr) - if result is not None: - if isinstance(result, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): - self._type_cache[cache_key] = result - elif isinstance(result, ir.PointerType) and isinstance(result.pointee, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): - self._type_cache[cache_key] = result - elif isinstance(result, ir.ArrayType) and not isinstance(result.element, (ir.IdentifiedStructType, ir.LiteralStructType)): - self._type_cache[cache_key] = result - return result - - _CType2LLVM = _type_str_to_llvm - - def _type_str_to_llvm_impl(self, type_str: str, IsPtr: bool = False) -> ir.Type: - array_dims: list[int] = [] - dim_match: list[str] = re.findall(r'\[(\d+)\]', type_str) - if dim_match: - array_dims = [int(d) for d in dim_match] - type_str = re.sub(r'\s*\[\d+\]', '', type_str).strip() - result: ir.Type = self._type_str_to_llvm_base(type_str, IsPtr) - for dim in reversed(array_dims): - result = ir.ArrayType(result, dim) - return result - - def _type_str_to_llvm_base(self, type_str: str, IsPtr: bool = False) -> ir.Type: - ptr_depth: int = 0 - while type_str.endswith('*'): - ptr_depth += 1 - type_str = type_str[:-1].strip() - if ptr_depth > 0: - IsPtr = True - if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: - result: ir.Type - if IsPtr: - result = ir.IntType(8).as_pointer() - for _ in range(ptr_depth - 1): - result = ir.PointerType(result) - return result - return ir.IntType(32) - if type_str in {'const', 'volatile'}: - return ir.IntType(8) - if type_str == 'Callable': - return ir.IntType(8).as_pointer() - for _q_prefix, _q_offset in self._QUALIFIER_PREFIXES: - if type_str.startswith(_q_prefix): - return self._type_str_to_llvm(type_str[_q_offset:].strip(), IsPtr) - resolved: str = self._resolve_typedef(type_str) - if resolved != type_str: - if '*' in resolved: - IsPtr = False - return self._type_str_to_llvm(resolved, IsPtr) - if type_str.endswith('*'): - BaseType: str = type_str[:-1].strip() - base_llvm: ir.Type | None = self._basic_type_to_llvm(BaseType) - if base_llvm is not None and isinstance(base_llvm, ir.VoidType): - result: ir.Type = ir.IntType(8).as_pointer() - for _ in range(ptr_depth): - result = ir.PointerType(result) - return result - if base_llvm is not None and not isinstance(base_llvm, ir.VoidType): - if isinstance(base_llvm, ir.PointerType): - return base_llvm - return ir.PointerType(base_llvm) - if BaseType in self.structs: - return ir.PointerType(self.structs[BaseType]) - if BaseType.startswith('struct '): - stripped: str = BaseType[7:].strip() - if stripped in self.structs: - return ir.PointerType(self.structs[stripped]) - if '.' in BaseType: - LastPart: str = BaseType.split('.')[-1] - if LastPart in self.structs: - return ir.PointerType(self.structs[LastPart]) - _src_sha1: str | None = self._get_source_sha1_from_type_str(BaseType) - placeholder: ir.IdentifiedStructType = self._get_or_create_struct(LastPart, source_sha1=_src_sha1) - return ir.PointerType(placeholder) - if base_llvm is not None and isinstance(base_llvm, ir.VoidType): - return ir.PointerType(ir.IntType(8)) - if type_str.startswith('{') and type_str.endswith('}'): - inner: str = type_str[1:-1].strip() - elem_strs: list[str] = [] - depth: int = 0 - current: str = '' - for ch in inner: - if ch == ',' and depth == 0: - elem_strs.append(current.strip()) - current = '' - else: - if ch == '{': - depth += 1 - elif ch == '}': - depth -= 1 - current += ch - if current.strip(): - elem_strs.append(current.strip()) - elem_types: list[ir.Type] = [] - for es in elem_strs: - et: ir.Type = self._type_str_to_llvm(es, '*' in es) - if isinstance(et, ir.VoidType): - et = ir.IntType(8).as_pointer() - elem_types.append(et) - 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'}: - 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'}: - 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: - if IsPtr and not isinstance(basic_stripped, ir.VoidType): - return ir.PointerType(basic_stripped) - return basic_stripped - if self.SymbolTable: - _Entry: _CTypeInfo | None = self.SymbolTable.lookup(type_str) - if _Entry and _Entry.IsTypedef: - resolved_str: str = self._resolve_typedef(type_str) - if resolved_str != type_str: - return self._type_str_to_llvm(resolved_str, IsPtr) - if _Entry.BaseType: - if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or _Entry.PtrCount > 0: - resolved: str = self._resolve_ctype_to_str(_Entry) - if resolved: - return self._type_str_to_llvm(resolved, IsPtr) - if _Entry and _Entry.IsRenum: - if type_str in self.structs: - if IsPtr: - return ir.PointerType(self.structs[type_str]) - return self.structs[type_str] - # REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32), - # 需要通过 _get_or_create_struct 创建 opaque 结构体(自引用安全)。 - _renum_sha1: str | None = self._get_source_sha1_from_type_str(type_str) - opaque: ir.Type = self._get_or_create_struct(type_str, source_sha1=_renum_sha1) - if IsPtr: - return ir.PointerType(opaque) - return opaque - if _Entry and _Entry.IsStruct: - # 结构体类型(来自 _InsertClassSymbol):必须返回结构体类型而非 i32, - # 否则 (ast.Import | t.CPtr) 联合转换会得到 i32* 导致字段访问 GEP 偏移错误 - if type_str in self.structs: - if IsPtr: - return ir.PointerType(self.structs[type_str]) - return self.structs[type_str] - # 结构体尚未创建时,通过 _get_or_create_struct 创建 opaque 结构体 - # (_TryLoadStructFromStub 会在后续阶段填充字段) - _struct_sha1: str | None = self._get_source_sha1_from_type_str(type_str) - opaque_struct: ir.IdentifiedStructType = self._get_or_create_struct(type_str, source_sha1=_struct_sha1) - if IsPtr: - return ir.PointerType(opaque_struct) - return opaque_struct - if _Entry and _Entry.IsEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if _Entry and _Entry.IsExceptionClass: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if _Entry and _Entry.IsFunction: - return ir.PointerType(ir.IntType(8)) - if _Entry and _Entry.BaseType: - if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - for ClassName in self.structs: - if type_str == ClassName: - if IsPtr: - return ir.PointerType(self.structs[ClassName]) - return self.structs[ClassName] - if '.' in type_str and not type_str.startswith('%'): - LastPart: str = type_str.split('.')[-1] - basic_last: ir.Type | None = self._basic_type_to_llvm(LastPart) - if basic_last is not None: - if IsPtr and not isinstance(basic_last, ir.VoidType): - return ir.PointerType(basic_last) - return basic_last - if self.SymbolTable: - _Entry: _CTypeInfo | None = self.SymbolTable.lookup(LastPart) - if _Entry and _Entry.IsTypedef: - resolved_str: str = self._resolve_typedef(LastPart) - if resolved_str != LastPart: - return self._type_str_to_llvm(resolved_str, IsPtr) - if _Entry.BaseType: - if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or _Entry.PtrCount > 0: - resolved: str = self._resolve_ctype_to_str(_Entry) - if resolved: - return self._type_str_to_llvm(resolved, IsPtr) - if _Entry and _Entry.IsRenum: - if LastPart in self.structs: - if IsPtr: - return ir.PointerType(self.structs[LastPart]) - return self.structs[LastPart] - # REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32)。 - _lp_sha1: str | None = self._get_source_sha1_from_type_str(type_str) - opaque_lp: ir.Type = self._get_or_create_struct(LastPart, source_sha1=_lp_sha1) - if IsPtr: - return ir.PointerType(opaque_lp) - return opaque_lp - if _Entry and _Entry.IsEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if _Entry and _Entry.IsExceptionClass: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if _Entry and _Entry.IsFunction: - return ir.PointerType(ir.IntType(8)) - if _Entry and _Entry.BaseType: - if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: - return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) - if LastPart in self.structs: - if IsPtr: - return ir.PointerType(self.structs[LastPart]) - return self.structs[LastPart] - _lp_sha1_2: str | None = self._get_source_sha1_from_type_str(type_str) - placeholder: ir.IdentifiedStructType = self._get_or_create_struct(LastPart, source_sha1=_lp_sha1_2) - if IsPtr: - return ir.PointerType(placeholder) - return placeholder - if type_str.startswith('struct '): - stripped: str = type_str[7:].strip().replace(' *', '').replace('*', '') - if stripped in self.structs: - if IsPtr: - return ir.PointerType(self.structs[stripped]) - return self.structs[stripped] - basic_match: ir.Type | None = self._basic_type_to_llvm(stripped) - if basic_match is not None: - if IsPtr and not isinstance(basic_match, ir.VoidType): - return ir.PointerType(basic_match) - return basic_match - _stripped_sha1: str | None = self._get_source_sha1_from_type_str(stripped) - placeholder: ir.IdentifiedStructType = self._get_or_create_struct(stripped, source_sha1=_stripped_sha1) - if IsPtr: - return ir.PointerType(placeholder) - return placeholder - if type_str.startswith('%struct.'): - stripped: str = type_str[8:].strip().replace(' *', '').replace('*', '') - if stripped in self.structs: - if IsPtr: - return ir.PointerType(self.structs[stripped]) - return self.structs[stripped] - basic_match: ir.Type | None = self._basic_type_to_llvm(stripped) - if basic_match is not None: - if IsPtr and not isinstance(basic_match, ir.VoidType): - return ir.PointerType(basic_match) - return basic_match - _stripped_sha1_2: str | None = self._get_source_sha1_from_type_str(stripped) - placeholder: ir.IdentifiedStructType = self._get_or_create_struct(stripped, source_sha1=_stripped_sha1_2) - if IsPtr: - return ir.PointerType(placeholder) - return placeholder - if type_str.startswith('union '): - stripped: str = type_str[6:].strip() - basic_match: ir.Type | None = self._basic_type_to_llvm(stripped) - if basic_match is not None: - if IsPtr and not isinstance(basic_match, ir.VoidType): - return ir.PointerType(basic_match) - return basic_match - if type_str.endswith('*'): - pointee: ir.Type = self._type_str_to_llvm(type_str[:-1].strip()) - if isinstance(pointee, ir.VoidType): - return ir.PointerType(ir.IntType(8)) - return ir.PointerType(pointee) - result: ir.Type | None = self._basic_type_to_llvm(type_str) - if result is None: - # 未知类型:可能是跨模块结构体(如 'Import' 来自 ast 模块)。 - # 尝试通过 _get_or_create_struct 创建/查找结构体, - # 该方法内部会检查 typedef/enum 等并返回正确类型。 - # 必须在 fallback 到 i32 之前执行,否则 (ast.Import | t.CPtr) 联合转换 - # 会得到 i32* 导致字段访问 GEP 偏移错误(AccessViolation 崩溃)。 - _cand_sha1: str | None = self._get_source_sha1_from_type_str(type_str) - candidate: ir.Type = self._get_or_create_struct(type_str, source_sha1=_cand_sha1) - if isinstance(candidate, ir.IdentifiedStructType): - result = candidate - else: - result = ir.IntType(32) - if IsPtr: - if isinstance(result, ir.VoidType): - result = ir.PointerType(ir.IntType(8)) - elif isinstance(result, ir.PointerType): - pass - else: - result = ir.PointerType(result) - for _ in range(ptr_depth - 1): - result = ir.PointerType(result) - return result - - def _llvm_str_to_ir(self, llvm_str: str) -> ir.Type | None: - _LLVM_IR_TYPES: dict[str, ir.Type] = { - 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), - 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), - 'i128': ir.IntType(128), 'float': ir.FloatType(), 'double': ir.DoubleType(), - 'half': ir.IntType(16), 'fp128': ir.IntType(128), - } - return _LLVM_IR_TYPES.get(llvm_str) - - def _basic_type_to_llvm(self, type_str: str) -> ir.Type | None: - _LLVM_IR_TYPES: dict[str, ir.Type] = { - 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), - 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), - 'i128': ir.IntType(128), 'f32': ir.FloatType(), 'f64': ir.DoubleType(), - 'half': ir.IntType(16), 'fp128': ir.IntType(128), - } - if type_str in _LLVM_IR_TYPES: - return _LLVM_IR_TYPES[type_str] - resolved: Any = CTypeRegistry.ResolveName(type_str) - if resolved is not None: - ctype_cls: Any - ptr_level: int - ctype_cls, ptr_level = resolved - llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls) - if llvm_str: - # CTypeToLLVM 对 CPtr 等指针类型已返回含 * 的串(如 'i8*'), - # 此时 ptr_level 已内含在 llvm_str 中,直接解析即可 - if '*' in llvm_str: - return self._type_str_to_llvm(llvm_str) - base: ir.Type | None = self._llvm_str_to_ir(llvm_str) - if base is not None: - for _ in range(ptr_level): - if isinstance(base, ir.VoidType): - base = ir.IntType(8).as_pointer() - else: - base = ir.PointerType(base) - return base - if type_str == '*': - return ir.IntType(8) - if type_str in ('const_', 'const'): - return ir.IntType(8) - return None - - def _is_type_unsigned(self, type_str: str) -> bool: - s: str = type_str.strip() - if s.endswith('*'): - return True - if s.startswith('unsigned'): - return True - resolved: Any = CTypeRegistry.ResolveName(s) - if resolved is not None: - ctype_cls: Any - _: int - ctype_cls, _ = resolved - try: - inst: Any = ctype_cls() - if getattr(inst, 'IsSigned', None) is False: - return True - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"判断类型符号性失败: {_e}", "Exception") - return False - - def _record_var_signedness(self, name: str, type_str_or_bool: str | bool) -> None: - if isinstance(type_str_or_bool, bool): - self.var_signedness[name] = type_str_or_bool - else: - self.var_signedness[name] = self._is_type_unsigned(type_str_or_bool) - - def _is_var_unsigned(self, name: str) -> bool: - return self.var_signedness.get(name, False) - - def _check_node_unsigned(self, node: ast.AST) -> bool: - if isinstance(node, ast.Name): - return self._is_var_unsigned(node.id) - if isinstance(node, ast.BinOp): - return self._check_node_unsigned(node.left) or self._check_node_unsigned(node.right) - if isinstance(node, ast.UnaryOp): - return self._check_node_unsigned(node.operand) - if isinstance(node, ast.Call): - return self._check_call_unsigned(node) - if isinstance(node, ast.Subscript): - return self._check_node_unsigned(node.value) - if isinstance(node, ast.Attribute): - # 检查是否为结构体字段,并查询其符号性 - field_signed: bool | None = self._check_attribute_signedness(node) - if field_signed is not None: - return not field_signed # IsSigned=False 表示无符号 → 返回 True - return self._check_node_unsigned(node.value) - return False - - def _check_call_unsigned(self, node: ast.Call) -> bool: - """推断函数调用返回值的无符号性。 - - 修复:原代码对所有 Call 节点返回 False,导致函数调用返回值 - 直接参与 >>/% 等运算时丢失无符号性,退化成 ashr/srem。 - - 规则(用户确认): - - a = b 赋值时,若 a 无显式类型注解,则自动推导为 b 的类型(含符号性) - - 若 a 有显式有符号类型,b 无符号,则相当于将 b 强转为 a 的有符号类型 - - 此处仅推断 b(调用本身)的符号性,赋值时的强转由赋值逻辑处理 - """ - func_node: ast.AST = node.func - func_name: str = '' - - if isinstance(func_node, ast.Name): - # 直接调用: rdrand64() - func_name = func_node.id - elif isinstance(func_node, ast.Attribute): - # t.CUInt64T(x) 等类型转换调用 - if hasattr(func_node.value, 'id') and IsTModule(func_node.value.id, self.SymbolTable): - if self._is_type_unsigned(func_node.attr): - return True - # module.func() 形式的调用 - try: - func_name = f"{func_node.value.id}.{func_node.attr}" - except AttributeError: - return False - else: - return False - - if not func_name or not self.SymbolTable: - return False - - try: - sym_info: Any = self.SymbolTable.lookup(func_name) - except Exception: - return False - - if sym_info and isinstance(sym_info, _CTypeInfo): - if sym_info.IsFunction or sym_info.IsFuncPtr: - ret_info: Any = sym_info.FuncPtrReturn - if ret_info and isinstance(ret_info, _CTypeInfo): - # 指针类型视为无符号 - if ret_info.PtrCount > 0: - return True - # 检查返回类型的 IsUInt 属性(IsSigned is False) - if ret_info.IsUInt: - return True - elif sym_info.IsTypedef: - # 修复:typedef 强转调用(如 ULONGLONG(0x11))需要解析底层类型的无符号性 - # IsUInt 对组合类型(CType | CType 产生的 list)会失败,需多策略回退 - if sym_info.IsUInt: - return True - # 策略1:直接检查 BaseType(可能是组合类型,如 ULONGLONG = CUnsignedLong | CLong) - bt: Any = sym_info.BaseType - if isinstance(bt, (tuple, list)): - for elem in bt: - if isinstance(elem, _t.CType) and getattr(elem, 'IsSigned', None) is False: - return True - elif isinstance(bt, _t.CType) and getattr(bt, 'IsSigned', None) is False: - return True - # 策略2:通过 OriginalType 解析 - if sym_info.OriginalType: - ot: Any = sym_info.OriginalType - if isinstance(ot, str): - if self._is_type_unsigned(ot): - return True - elif isinstance(ot, _CTypeInfo): - if ot.IsUInt: - return True - elif isinstance(ot, (tuple, list)): - for elem in ot: - if isinstance(elem, _t.CType) and getattr(elem, 'IsSigned', None) is False: - return True - # 策略3:通过 _resolve_typedef 解析为字符串后判断 - resolved_str: str = self._resolve_typedef(func_name) - if resolved_str and self._is_type_unsigned(resolved_str): - return True - return False - - def _check_attribute_signedness(self, node: ast.Attribute) -> bool | None: - """检查 Attribute 节点是否引用具有已知符号性的结构体字段。 - - Returns: - True: 字段是有符号类型 - False: 字段是无符号类型 - None: 无法确定(非结构体字段或符号性未知) - """ - if not isinstance(node.value, ast.Name): - return None - var_name: str = node.value.id - field_name: str = node.attr - class_name: str | None = self._resolve_class_for_var(var_name) - if not class_name: - return None - signed_dict: dict[str, bool] = self.class_member_signeds.get(class_name, {}) - if field_name in signed_dict: - return signed_dict[field_name] +from __future__ import annotations +from typing import Any +import vast as ast +import re +import logging +import llvmlite.ir as ir +from lib.includes import t as _t +from lib.includes.t import CTypeRegistry +from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, BuiltinTypeMap +from lib.constants.config import mode as _config_mode +from lib.core.VLogger import get_logger as _vlog +from lib.core.SymbolUtils import IsTModule + + +class TypeConvertMixin: + + # 限定符前缀映射表:(前缀字符串, 去除长度) + # 这些限定符(const/volatile/static/extern/register/inline/export/CAuto 等) + # 仅影响 C 语义,对 LLVM IR 类型本身无影响,统一去除后递归解析内部类型。 + _QUALIFIER_PREFIXES: tuple[tuple[str, int], ...] = ( + ('const ', 6), ('volatile ', 9), ('const_', 6), ('volatile_', 9), + ('static ', 7), ('extern ', 7), ('register ', 9), ('inline ', 7), + ('export ', 7), + ('CStatic ', 8), ('CExtern ', 8), ('CRegister ', 10), + ('CInline ', 8), ('CAuto ', 6), + ) + + def _ctype_to_llvm(self, type_info: _CTypeInfo | str | None) -> ir.Type: + if type_info is None: + return ir.IntType(32) + + if isinstance(type_info, str): + return self._type_str_to_llvm(type_info) + + if not isinstance(type_info, _CTypeInfo): + return ir.IntType(32) + + if type_info.IsFuncPtr: + ret_type: ir.Type = self._ctype_to_llvm(type_info.FuncPtrReturn) if type_info.FuncPtrReturn else ir.VoidType() + param_types: list[ir.Type] = [] + if type_info.FuncPtrParams: + for _name, param_info in type_info.FuncPtrParams: + if isinstance(param_info, _CTypeInfo): + param_types.append(self._ctype_to_llvm(param_info)) + else: + param_types.append(ir.IntType(32)) + fn_type: ir.FunctionType = ir.FunctionType(ret_type, param_types) + return ir.PointerType(fn_type) + + if type_info.IsState and type_info.PtrCount == 0 and not type_info.IsTypedef: + if type_info.BaseType is None or (isinstance(type_info.BaseType, type) and issubclass(type_info.BaseType, _t.CVoid)) or isinstance(type_info.BaseType, _t.CVoid): + return ir.VoidType() + + if type_info.IsTypedef and type_info.Name: + resolved: ir.Type | None = self._resolve_typedef_ctype(type_info) + if resolved is not None: + return resolved + + # REnum 类型:通过 Name 查找或创建结构体(BaseType 可能为 None) + # 这对 BinOp `LLVMType | t.CPtr` 合并后的 CTypeInfo 至关重要 + if type_info.IsRenum and type_info.Name: + if type_info.Name in self.structs: + base: ir.Type = self.structs[type_info.Name] + else: + base = self._get_or_create_struct(type_info.Name) + result: ir.Type = base + for _ in range(type_info.PtrCount): + result = ir.PointerType(result) + return result + + BaseType: ir.Type = self._base_ctype_to_llvm(type_info.BaseType, type_info) + + result: ir.Type = BaseType + for _ in range(type_info.PtrCount): + if isinstance(result, ir.VoidType): + result = ir.IntType(8).as_pointer() + else: + result = ir.PointerType(result) + + for dim in reversed(type_info.ArrayDims): + try: + dim_val: int = int(dim) + if dim_val > 0: + result = ir.ArrayType(result, dim_val) + except (ValueError, TypeError): + pass + + return result + + def _resolve_typedef_ctype(self, type_info: _CTypeInfo) -> ir.Type | None: + name: str = type_info.Name + if not name or not self.SymbolTable: + return None + + entry: Any = self.SymbolTable.lookup(name) + if not entry or not isinstance(entry, _CTypeInfo): + return None + + if entry.BaseType and (not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0): + resolved: Any = entry.Copy() + resolved.IsTypedef = False + if type_info.PtrCount > resolved.PtrCount: + resolved.PtrCount = type_info.PtrCount + return self._ctype_to_llvm(resolved) + + if entry.OriginalType: + if isinstance(entry.OriginalType, _CTypeInfo): + resolved: Any = entry.OriginalType.Copy() + resolved.IsTypedef = False + if type_info.PtrCount > resolved.PtrCount: + resolved.PtrCount = type_info.PtrCount + return self._ctype_to_llvm(resolved) + elif isinstance(entry.OriginalType, str): + resolved: Any = _CTypeInfo.FromTypeName(entry.OriginalType) + if resolved and resolved.BaseType: + resolved.IsTypedef = False + if type_info.PtrCount > resolved.PtrCount: + resolved.PtrCount = type_info.PtrCount + return self._ctype_to_llvm(resolved) + + return None + + def _base_ctype_to_llvm(self, BaseType: Any, type_info: _CTypeInfo | None = None) -> ir.Type: + if BaseType is None: + return ir.VoidType() + + if isinstance(BaseType, (tuple, list)): + elem_types: list[ir.Type] = [self._base_ctype_to_llvm(bt, type_info) for bt in BaseType] + return ir.LiteralStructType(elem_types) if elem_types else ir.IntType(32) + + if isinstance(BaseType, type) and issubclass(BaseType, _t.CType): + BaseType = BaseType() + + if isinstance(BaseType, _t.CVoid): + return ir.VoidType() + + if isinstance(BaseType, _t.CStruct): + struct_name: str = getattr(BaseType, 'name', '') or (type_info.Name if type_info else '') + if struct_name and struct_name in self.structs: + return self.structs[struct_name] + if struct_name: + return self._get_or_create_struct(struct_name) + return ir.LiteralStructType([]) + + if isinstance(BaseType, (_t.CEnum, _t.REnum)): + enum_name: str = type_info.Name if type_info else '' + if enum_name and enum_name in self.structs: + return self.structs[enum_name] + return ir.IntType(32) + + if isinstance(BaseType, _t.CUnion): + union_name: str = type_info.Name if type_info else '' + if union_name and union_name in self.structs: + return self.structs[union_name] + if union_name: + return self._get_or_create_struct(union_name) + return ir.IntType(32) + + if isinstance(BaseType, _t._CTypedef): + typedef_name: str = getattr(BaseType, 'value', '') or (type_info.Name if type_info else '') + if typedef_name and self.SymbolTable: + entry: Any = self.SymbolTable.lookup(typedef_name) + if entry and isinstance(entry, _CTypeInfo) and entry.BaseType: + if not isinstance(entry.BaseType, _t._CTypedef) or entry.PtrCount > 0: + return self._base_ctype_to_llvm(entry.BaseType, entry) + return ir.IntType(32) + + if isinstance(BaseType, _t.CDefine): + # Use 64-bit type if the define value exceeds 32-bit range + if type_info and isinstance(type_info.DefineValue, int): + if type_info.DefineValue < 0 or type_info.DefineValue > 0xFFFFFFFF: + return ir.IntType(64) + return ir.IntType(32) + + if isinstance(BaseType, _t.CPass): + return ir.VoidType() + + llvm_str: str = CTypeRegistry.CTypeToLLVM(type(BaseType)) + return self._llvm_str_to_ir(llvm_str) + + def _get_source_sha1_from_type_str(self, type_str: str) -> str | None: + """从类型字符串中提取模块名,返回对应的源模块 SHA1。 + 用于跨模块类型引用(如 memhub.MemBuddy),确保用源模块的 SHA1 创建 struct。 + """ + if not type_str or '.' not in type_str: + return None + # 去除指针标记和空格 + clean: str = type_str.replace('*', '').strip() + if '.' not in clean: + return None + # 提取模块名(最后一个 '.' 之前的部分) + parts: list[str] = clean.rsplit('.', 1) + if len(parts) < 2: + return None + module_name: str = parts[0] + # 跳过 t/c 等内建模块 + if module_name in {'t', 'c'}: + return None + # 从 ModuleSha1Map 查找 SHA1(支持完整路径名和短名) + sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {}) + source_sha1: str | None = sha1_map.get(module_name) + if not source_sha1 and '.' in module_name: + source_sha1 = sha1_map.get(module_name.split('.')[-1]) + 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'}: + return type_name + if type_name == 'Callable': + return 'Callable' + visited: set[str] = set() + current: str = type_name + while current not in visited: + visited.add(current) + if self.SymbolTable: + Entry: _CTypeInfo | None = self.SymbolTable.lookup(current) + if isinstance(Entry, dict) and Entry.get('type') == 'typedef': + OriginalType: str = Entry.get('OriginalType', '') + if OriginalType: + current = OriginalType + continue + elif Entry and Entry.IsTypedef: + if Entry.OriginalType: + if isinstance(Entry.OriginalType, _CTypeInfo): + if Entry.OriginalType.IsFuncPtr: + return 'Callable' + return Entry.OriginalType.ToString() if Entry.OriginalType.BaseType else current + elif isinstance(Entry.OriginalType, str): + current = Entry.OriginalType + continue + if Entry.BaseType: + if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0: + resolved: str = self._resolve_ctype_to_str(Entry) + if resolved and resolved != current: + current = resolved + continue + bm: Any = BuiltinTypeMap.Get(current) + if bm: + base_cls: Any = bm[0] + try: + instance: Any = base_cls() + cname: str = type(instance).__name__ + if cname: + current = cname + ' *' * bm[1] + continue + except Exception as _e: + if _config_mode == "strict": + logging.warning(f"异常被忽略: {_e}") + pass + bm: Any = BuiltinTypeMap.Get(current) + if bm and bm[1] > 0: + base_cls: Any = bm[0] + try: + instance: Any = base_cls() + cname: str = type(instance).__name__ + if cname: + current = cname + ' *' * bm[1] + continue + except Exception as _e: + if _config_mode == "strict": + logging.warning(f"异常被忽略: {_e}") + pass + break + return current + + def _resolve_ctype_to_str(self, type_info: _CTypeInfo) -> str: + parts: list[str] = [] + base: Any = type_info.BaseType + if base is None or base is _t.CVoid or isinstance(base, _t.CVoid): + parts.append('void') + elif isinstance(base, _t._CTypedef) or base is _t._CTypedef: + return '' + elif isinstance(base, _t.CStruct) or base is _t.CStruct: + parts.append(f'struct {getattr(base, "name", "")}') + elif isinstance(base, _t.CEnum) or base is _t.CEnum: + parts.append(f'enum {getattr(base, "name", "")}') + else: + cname: str = '' + if isinstance(base, type) and issubclass(base, _t.CType): + cname = base.__name__ + elif isinstance(base, _t.CType): + cname = type(base).__name__ + if cname: + parts.append(cname) + else: + return '' + if type_info.PtrCount > 0: + parts.append('*' * type_info.PtrCount) + return ' '.join(parts) + + def _type_str_to_llvm(self, type_str: str, IsPtr: bool = False) -> ir.Type: + type_str = type_str.strip() + cache_key: tuple[str, bool] = (type_str, IsPtr) + cached: ir.Type | None = self._type_cache.get(cache_key) + if cached is not None: + return cached + result: ir.Type = self._type_str_to_llvm_impl(type_str, IsPtr) + if result is not None: + if isinstance(result, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): + self._type_cache[cache_key] = result + elif isinstance(result, ir.PointerType) and isinstance(result.pointee, (ir.IntType, ir.FloatType, ir.DoubleType, ir.VoidType)): + self._type_cache[cache_key] = result + elif isinstance(result, ir.ArrayType) and not isinstance(result.element, (ir.IdentifiedStructType, ir.LiteralStructType)): + self._type_cache[cache_key] = result + return result + + _CType2LLVM = _type_str_to_llvm + + def _type_str_to_llvm_impl(self, type_str: str, IsPtr: bool = False) -> ir.Type: + array_dims: list[int] = [] + dim_match: list[str] = re.findall(r'\[(\d+)\]', type_str) + if dim_match: + array_dims = [int(d) for d in dim_match] + type_str = re.sub(r'\s*\[\d+\]', '', type_str).strip() + result: ir.Type = self._type_str_to_llvm_base(type_str, IsPtr) + for dim in reversed(array_dims): + result = ir.ArrayType(result, dim) + return result + + def _type_str_to_llvm_base(self, type_str: str, IsPtr: bool = False) -> ir.Type: + ptr_depth: int = 0 + while type_str.endswith('*'): + ptr_depth += 1 + type_str = type_str[:-1].strip() + if ptr_depth > 0: + IsPtr = True + if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}: + result: ir.Type + if IsPtr: + result = ir.IntType(8).as_pointer() + for _ in range(ptr_depth - 1): + result = ir.PointerType(result) + return result + return ir.IntType(32) + if type_str in {'const', 'volatile'}: + return ir.IntType(8) + if type_str == 'Callable': + return ir.IntType(8).as_pointer() + for _q_prefix, _q_offset in self._QUALIFIER_PREFIXES: + if type_str.startswith(_q_prefix): + return self._type_str_to_llvm(type_str[_q_offset:].strip(), IsPtr) + resolved: str = self._resolve_typedef(type_str) + if resolved != type_str: + if '*' in resolved: + IsPtr = False + return self._type_str_to_llvm(resolved, IsPtr) + if type_str.endswith('*'): + BaseType: str = type_str[:-1].strip() + base_llvm: ir.Type | None = self._basic_type_to_llvm(BaseType) + if base_llvm is not None and isinstance(base_llvm, ir.VoidType): + result: ir.Type = ir.IntType(8).as_pointer() + for _ in range(ptr_depth): + result = ir.PointerType(result) + return result + if base_llvm is not None and not isinstance(base_llvm, ir.VoidType): + if isinstance(base_llvm, ir.PointerType): + return base_llvm + return ir.PointerType(base_llvm) + if BaseType in self.structs: + return ir.PointerType(self.structs[BaseType]) + if BaseType.startswith('struct '): + stripped: str = BaseType[7:].strip() + if stripped in self.structs: + return ir.PointerType(self.structs[stripped]) + if '.' in BaseType: + LastPart: str = BaseType.split('.')[-1] + if LastPart in self.structs: + return ir.PointerType(self.structs[LastPart]) + _src_sha1: str | None = self._get_source_sha1_from_type_str(BaseType) + placeholder: ir.IdentifiedStructType = self._get_or_create_struct(LastPart, source_sha1=_src_sha1) + return ir.PointerType(placeholder) + if base_llvm is not None and isinstance(base_llvm, ir.VoidType): + return ir.PointerType(ir.IntType(8)) + if type_str.startswith('{') and type_str.endswith('}'): + inner: str = type_str[1:-1].strip() + elem_strs: list[str] = [] + depth: int = 0 + current: str = '' + for ch in inner: + if ch == ',' and depth == 0: + elem_strs.append(current.strip()) + current = '' + else: + if ch == '{': + depth += 1 + elif ch == '}': + depth -= 1 + current += ch + if current.strip(): + elem_strs.append(current.strip()) + elem_types: list[ir.Type] = [] + for es in elem_strs: + et: ir.Type = self._type_str_to_llvm(es, '*' in es) + if isinstance(et, ir.VoidType): + et = ir.IntType(8).as_pointer() + elem_types.append(et) + 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'}: + 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'}: + 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: + if IsPtr and not isinstance(basic_stripped, ir.VoidType): + return ir.PointerType(basic_stripped) + return basic_stripped + if self.SymbolTable: + _Entry: _CTypeInfo | None = self.SymbolTable.lookup(type_str) + if _Entry and _Entry.IsTypedef: + resolved_str: str = self._resolve_typedef(type_str) + if resolved_str != type_str: + return self._type_str_to_llvm(resolved_str, IsPtr) + if _Entry.BaseType: + if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or _Entry.PtrCount > 0: + resolved: str = self._resolve_ctype_to_str(_Entry) + if resolved: + return self._type_str_to_llvm(resolved, IsPtr) + if _Entry and _Entry.IsRenum: + if type_str in self.structs: + if IsPtr: + return ir.PointerType(self.structs[type_str]) + return self.structs[type_str] + # REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32), + # 需要通过 _get_or_create_struct 创建 opaque 结构体(自引用安全)。 + _renum_sha1: str | None = self._get_source_sha1_from_type_str(type_str) + opaque: ir.Type = self._get_or_create_struct(type_str, source_sha1=_renum_sha1) + if IsPtr: + return ir.PointerType(opaque) + return opaque + if _Entry and _Entry.IsStruct: + # 结构体类型(来自 _InsertClassSymbol):必须返回结构体类型而非 i32, + # 否则 (ast.Import | t.CPtr) 联合转换会得到 i32* 导致字段访问 GEP 偏移错误 + if type_str in self.structs: + if IsPtr: + return ir.PointerType(self.structs[type_str]) + return self.structs[type_str] + # 结构体尚未创建时,通过 _get_or_create_struct 创建 opaque 结构体 + # (_TryLoadStructFromStub 会在后续阶段填充字段) + _struct_sha1: str | None = self._get_source_sha1_from_type_str(type_str) + opaque_struct: ir.IdentifiedStructType = self._get_or_create_struct(type_str, source_sha1=_struct_sha1) + if IsPtr: + return ir.PointerType(opaque_struct) + return opaque_struct + if _Entry and _Entry.IsEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if _Entry and _Entry.IsExceptionClass: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if _Entry and _Entry.IsFunction: + return ir.PointerType(ir.IntType(8)) + if _Entry and _Entry.BaseType: + if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + for ClassName in self.structs: + if type_str == ClassName: + if IsPtr: + return ir.PointerType(self.structs[ClassName]) + return self.structs[ClassName] + if '.' in type_str and not type_str.startswith('%'): + LastPart: str = type_str.split('.')[-1] + basic_last: ir.Type | None = self._basic_type_to_llvm(LastPart) + if basic_last is not None: + if IsPtr and not isinstance(basic_last, ir.VoidType): + return ir.PointerType(basic_last) + return basic_last + if self.SymbolTable: + _Entry: _CTypeInfo | None = self.SymbolTable.lookup(LastPart) + if _Entry and _Entry.IsTypedef: + resolved_str: str = self._resolve_typedef(LastPart) + if resolved_str != LastPart: + return self._type_str_to_llvm(resolved_str, IsPtr) + if _Entry.BaseType: + if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or _Entry.PtrCount > 0: + resolved: str = self._resolve_ctype_to_str(_Entry) + if resolved: + return self._type_str_to_llvm(resolved, IsPtr) + if _Entry and _Entry.IsRenum: + if LastPart in self.structs: + if IsPtr: + return ir.PointerType(self.structs[LastPart]) + return self.structs[LastPart] + # REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32)。 + _lp_sha1: str | None = self._get_source_sha1_from_type_str(type_str) + opaque_lp: ir.Type = self._get_or_create_struct(LastPart, source_sha1=_lp_sha1) + if IsPtr: + return ir.PointerType(opaque_lp) + return opaque_lp + if _Entry and _Entry.IsEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if _Entry and _Entry.IsExceptionClass: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if _Entry and _Entry.IsFunction: + return ir.PointerType(ir.IntType(8)) + if _Entry and _Entry.BaseType: + if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum: + return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32)) + if LastPart in self.structs: + if IsPtr: + return ir.PointerType(self.structs[LastPart]) + return self.structs[LastPart] + _lp_sha1_2: str | None = self._get_source_sha1_from_type_str(type_str) + placeholder: ir.IdentifiedStructType = self._get_or_create_struct(LastPart, source_sha1=_lp_sha1_2) + if IsPtr: + return ir.PointerType(placeholder) + return placeholder + if type_str.startswith('struct '): + stripped: str = type_str[7:].strip().replace(' *', '').replace('*', '') + if stripped in self.structs: + if IsPtr: + return ir.PointerType(self.structs[stripped]) + return self.structs[stripped] + basic_match: ir.Type | None = self._basic_type_to_llvm(stripped) + if basic_match is not None: + if IsPtr and not isinstance(basic_match, ir.VoidType): + return ir.PointerType(basic_match) + return basic_match + _stripped_sha1: str | None = self._get_source_sha1_from_type_str(stripped) + placeholder: ir.IdentifiedStructType = self._get_or_create_struct(stripped, source_sha1=_stripped_sha1) + if IsPtr: + return ir.PointerType(placeholder) + return placeholder + if type_str.startswith('%struct.'): + stripped: str = type_str[8:].strip().replace(' *', '').replace('*', '') + if stripped in self.structs: + if IsPtr: + return ir.PointerType(self.structs[stripped]) + return self.structs[stripped] + basic_match: ir.Type | None = self._basic_type_to_llvm(stripped) + if basic_match is not None: + if IsPtr and not isinstance(basic_match, ir.VoidType): + return ir.PointerType(basic_match) + return basic_match + _stripped_sha1_2: str | None = self._get_source_sha1_from_type_str(stripped) + placeholder: ir.IdentifiedStructType = self._get_or_create_struct(stripped, source_sha1=_stripped_sha1_2) + if IsPtr: + return ir.PointerType(placeholder) + return placeholder + if type_str.startswith('union '): + stripped: str = type_str[6:].strip() + basic_match: ir.Type | None = self._basic_type_to_llvm(stripped) + if basic_match is not None: + if IsPtr and not isinstance(basic_match, ir.VoidType): + return ir.PointerType(basic_match) + return basic_match + if type_str.endswith('*'): + pointee: ir.Type = self._type_str_to_llvm(type_str[:-1].strip()) + if isinstance(pointee, ir.VoidType): + return ir.PointerType(ir.IntType(8)) + return ir.PointerType(pointee) + result: ir.Type | None = self._basic_type_to_llvm(type_str) + if result is None: + # 未知类型:可能是跨模块结构体(如 'Import' 来自 ast 模块)。 + # 尝试通过 _get_or_create_struct 创建/查找结构体, + # 该方法内部会检查 typedef/enum 等并返回正确类型。 + # 必须在 fallback 到 i32 之前执行,否则 (ast.Import | t.CPtr) 联合转换 + # 会得到 i32* 导致字段访问 GEP 偏移错误(AccessViolation 崩溃)。 + _cand_sha1: str | None = self._get_source_sha1_from_type_str(type_str) + candidate: ir.Type = self._get_or_create_struct(type_str, source_sha1=_cand_sha1) + if isinstance(candidate, ir.IdentifiedStructType): + result = candidate + else: + result = ir.IntType(32) + if IsPtr: + if isinstance(result, ir.VoidType): + result = ir.PointerType(ir.IntType(8)) + elif isinstance(result, ir.PointerType): + pass + else: + result = ir.PointerType(result) + for _ in range(ptr_depth - 1): + result = ir.PointerType(result) + return result + + def _llvm_str_to_ir(self, llvm_str: str) -> ir.Type | None: + _LLVM_IR_TYPES: dict[str, ir.Type] = { + 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), + 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), + 'i128': ir.IntType(128), 'float': ir.FloatType(), 'double': ir.DoubleType(), + 'half': ir.IntType(16), 'fp128': ir.IntType(128), + } + return _LLVM_IR_TYPES.get(llvm_str) + + def _basic_type_to_llvm(self, type_str: str) -> ir.Type | None: + _LLVM_IR_TYPES: dict[str, ir.Type] = { + 'void': ir.VoidType(), 'i1': ir.IntType(1), 'i8': ir.IntType(8), + 'i16': ir.IntType(16), 'i32': ir.IntType(32), 'i64': ir.IntType(64), + 'i128': ir.IntType(128), 'f32': ir.FloatType(), 'f64': ir.DoubleType(), + 'half': ir.IntType(16), 'fp128': ir.IntType(128), + } + if type_str in _LLVM_IR_TYPES: + return _LLVM_IR_TYPES[type_str] + resolved: Any = CTypeRegistry.ResolveName(type_str) + if resolved is not None: + ctype_cls: Any + ptr_level: int + ctype_cls, ptr_level = resolved + llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls) + if llvm_str: + # CTypeToLLVM 对 CPtr 等指针类型已返回含 * 的串(如 'i8*'), + # 此时 ptr_level 已内含在 llvm_str 中,直接解析即可 + if '*' in llvm_str: + return self._type_str_to_llvm(llvm_str) + base: ir.Type | None = self._llvm_str_to_ir(llvm_str) + if base is not None: + for _ in range(ptr_level): + if isinstance(base, ir.VoidType): + base = ir.IntType(8).as_pointer() + else: + base = ir.PointerType(base) + return base + if type_str == '*': + return ir.IntType(8) + if type_str in ('const_', 'const'): + return ir.IntType(8) + return None + + def _is_type_unsigned(self, type_str: str) -> bool: + s: str = type_str.strip() + if s.endswith('*'): + return True + if s.startswith('unsigned'): + return True + resolved: Any = CTypeRegistry.ResolveName(s) + if resolved is not None: + ctype_cls: Any + _: int + ctype_cls, _ = resolved + try: + inst: Any = ctype_cls() + if getattr(inst, 'IsSigned', None) is False: + return True + except Exception as _e: + if _config_mode == "strict": + raise + _vlog().warning(f"判断类型符号性失败: {_e}", "Exception") + return False + + def _record_var_signedness(self, name: str, type_str_or_bool: str | bool) -> None: + if isinstance(type_str_or_bool, bool): + self.var_signedness[name] = type_str_or_bool + else: + self.var_signedness[name] = self._is_type_unsigned(type_str_or_bool) + + def _is_var_unsigned(self, name: str) -> bool: + return self.var_signedness.get(name, False) + + def _check_node_unsigned(self, node: ast.AST) -> bool: + if isinstance(node, ast.Name): + return self._is_var_unsigned(node.id) + if isinstance(node, ast.BinOp): + return self._check_node_unsigned(node.left) or self._check_node_unsigned(node.right) + if isinstance(node, ast.UnaryOp): + return self._check_node_unsigned(node.operand) + if isinstance(node, ast.Call): + return self._check_call_unsigned(node) + if isinstance(node, ast.Subscript): + return self._check_node_unsigned(node.value) + if isinstance(node, ast.Attribute): + # 检查是否为结构体字段,并查询其符号性 + field_signed: bool | None = self._check_attribute_signedness(node) + if field_signed is not None: + return not field_signed # IsSigned=False 表示无符号 → 返回 True + return self._check_node_unsigned(node.value) + return False + + def _check_call_unsigned(self, node: ast.Call) -> bool: + """推断函数调用返回值的无符号性。 + + 修复:原代码对所有 Call 节点返回 False,导致函数调用返回值 + 直接参与 >>/% 等运算时丢失无符号性,退化成 ashr/srem。 + + 规则(用户确认): + - a = b 赋值时,若 a 无显式类型注解,则自动推导为 b 的类型(含符号性) + - 若 a 有显式有符号类型,b 无符号,则相当于将 b 强转为 a 的有符号类型 + - 此处仅推断 b(调用本身)的符号性,赋值时的强转由赋值逻辑处理 + """ + func_node: ast.AST = node.func + func_name: str = '' + + if isinstance(func_node, ast.Name): + # 直接调用: rdrand64() + func_name = func_node.id + elif isinstance(func_node, ast.Attribute): + # t.CUInt64T(x) 等类型转换调用 + if hasattr(func_node.value, 'id') and IsTModule(func_node.value.id, self.SymbolTable): + if self._is_type_unsigned(func_node.attr): + return True + # module.func() 形式的调用 + try: + func_name = f"{func_node.value.id}.{func_node.attr}" + except AttributeError: + return False + else: + return False + + if not func_name or not self.SymbolTable: + return False + + try: + sym_info: Any = self.SymbolTable.lookup(func_name) + except Exception: + return False + + if sym_info and isinstance(sym_info, _CTypeInfo): + if sym_info.IsFunction or sym_info.IsFuncPtr: + ret_info: Any = sym_info.FuncPtrReturn + if ret_info and isinstance(ret_info, _CTypeInfo): + # 指针类型视为无符号 + if ret_info.PtrCount > 0: + return True + # 检查返回类型的 IsUInt 属性(IsSigned is False) + if ret_info.IsUInt: + return True + elif sym_info.IsTypedef: + # 修复:typedef 强转调用(如 ULONGLONG(0x11))需要解析底层类型的无符号性 + # IsUInt 对组合类型(CType | CType 产生的 list)会失败,需多策略回退 + if sym_info.IsUInt: + return True + # 策略1:直接检查 BaseType(可能是组合类型,如 ULONGLONG = CUnsignedLong | CLong) + bt: Any = sym_info.BaseType + if isinstance(bt, (tuple, list)): + for elem in bt: + if isinstance(elem, _t.CType) and getattr(elem, 'IsSigned', None) is False: + return True + elif isinstance(bt, _t.CType) and getattr(bt, 'IsSigned', None) is False: + return True + # 策略2:通过 OriginalType 解析 + if sym_info.OriginalType: + ot: Any = sym_info.OriginalType + if isinstance(ot, str): + if self._is_type_unsigned(ot): + return True + elif isinstance(ot, _CTypeInfo): + if ot.IsUInt: + return True + elif isinstance(ot, (tuple, list)): + for elem in ot: + if isinstance(elem, _t.CType) and getattr(elem, 'IsSigned', None) is False: + return True + # 策略3:通过 _resolve_typedef 解析为字符串后判断 + resolved_str: str = self._resolve_typedef(func_name) + if resolved_str and self._is_type_unsigned(resolved_str): + return True + return False + + def _check_attribute_signedness(self, node: ast.Attribute) -> bool | None: + """检查 Attribute 节点是否引用具有已知符号性的结构体字段。 + + Returns: + True: 字段是有符号类型 + False: 字段是无符号类型 + None: 无法确定(非结构体字段或符号性未知) + """ + if not isinstance(node.value, ast.Name): + return None + var_name: str = node.value.id + field_name: str = node.attr + class_name: str | None = self._resolve_class_for_var(var_name) + if not class_name: + return None + signed_dict: dict[str, bool] = self.class_member_signeds.get(class_name, {}) + if field_name in signed_dict: + return signed_dict[field_name] return None \ No newline at end of file diff --git a/lib/core/LLVMTypeMapper.py b/lib/core/LLVMTypeMapper.py index 0e8cbe9..30edccf 100644 --- a/lib/core/LLVMTypeMapper.py +++ b/lib/core/LLVMTypeMapper.py @@ -1,301 +1,301 @@ -"""LLVMTypeMapper — AST 注解节点到 LLVM IR 类型字符串的映射器 - -从 SymbolTable 中提取的类型解析逻辑,职责单一: -将 Python AST 注解节点翻译为 LLVM IR 类型字符串(如 'i32', 'i8*', '{ i32, i8* }')。 - -原 SymbolTable 上的 4 个方法: - - _GetLLVMTypeStr → LLVMTypeMapper.get_llvm_type_str - - _GetFuncRetTypeStr → LLVMTypeMapper.get_func_ret_type_str - - _GetFuncParamTypeStr → LLVMTypeMapper.get_func_param_type_str - - _ResolveTypedefValueType → LLVMTypeMapper.resolve_typedef_value_type -""" -from __future__ import annotations - -import ast -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from lib.core.SymbolTable import SymbolTable - -from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap -from lib.core.SymbolUtils import IsTModule, IsListAnnotation -from lib.includes import t as _t -from lib.includes.t import CTypeRegistry - - -class LLVMTypeMapper: - """AST 注解节点 → LLVM IR 类型字符串 映射器""" - - def __init__(self, symtab: SymbolTable): - self._symtab = symtab - - # ================================================================== - # 公共 API - # ================================================================== - - def get_llvm_type_str(self, node: ast.AST | None) -> str: - """将 AST 注解节点转换为 LLVM IR 类型字符串""" - if node is None: - self._symtab.diagnostics.warn('', 0, "类型注解为 None,回退到 i32") - return 'i32' - if isinstance(node, ast.Name): - return self._resolve_name(node) - elif isinstance(node, ast.Attribute): - return self._resolve_attribute(node) - elif isinstance(node, ast.Subscript): - return self._resolve_subscript(node) - elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - return self._resolve_bitor(node) - elif isinstance(node, ast.Constant): - if isinstance(node.value, bool): - return 'i8' - return 'i32' - elif isinstance(node, ast.Call): - return self._resolve_call(node) - self._symtab.diagnostics.warn('', 0, f"无法解析类型节点 {type(node).__name__},回退到 i32") - return 'i32' - - def get_func_ret_type_str(self, returns_node: ast.AST | None) -> str: - """提取函数返回类型的 LLVM 字符串""" - if returns_node is None: - return 'i32' - if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr): - left_str: str = self.get_llvm_type_str(returns_node.left) - right_str: str = self.get_llvm_type_str(returns_node.right) - if right_str and right_str.endswith('*'): - return right_str - if left_str and left_str.endswith('*'): - return left_str - if left_str and left_str not in ('i32', 'void', 'i64'): - return left_str - if right_str and right_str not in ('i32', 'void', 'i64'): - return right_str - return left_str - result: str = self.get_llvm_type_str(returns_node) - return result if result else 'i32' - - def get_func_param_type_str(self, annotation_node: ast.AST | None) -> str: - """提取函数参数类型的 LLVM 字符串""" - if annotation_node is None: - return 'i8*' - if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): - left_str: str = self.get_llvm_type_str(annotation_node.left) - right_str: str = self.get_llvm_type_str(annotation_node.right) - if right_str and right_str.endswith('*'): - return right_str - if left_str and left_str.endswith('*'): - return left_str - if right_str and right_str not in ('i32', 'void', 'i64'): - return right_str - if left_str and left_str not in ('i32', 'void', 'i64'): - return left_str - return right_str if right_str else left_str - result: str = self.get_llvm_type_str(annotation_node) - return result if result else 'i8*' - - def resolve_typedef_value_type(self, node: ast.AST | None) -> str: - """解析 typedef 值表达式的 C 类型字符串""" - if node is None: - return '' - if isinstance(node, ast.Name): - if node.id in self._symtab: - Entry: CTypeInfo = self._symtab[node.id] - if Entry.IsTypedef and Entry.OriginalType: - return Entry.OriginalType - return '' - if isinstance(node, ast.Attribute): - if isinstance(node.value, ast.Name) and IsTModule(node.value.id): - # 直接判断属性名是否为 CPtr(消除对 CName=='*' 的依赖) - if node.attr == 'CPtr': - return 'ptr' - CName: str | None = CTypeHelper.GetCName(node.attr) - if CName == 'CPtr': - return 'ptr' - if CName: - return CName - return '' - if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - left_str: str = self.resolve_typedef_value_type(node.left) - right_str: str = self.resolve_typedef_value_type(node.right) - if right_str == 'ptr' or (right_str and right_str.endswith('*')): - base: str = left_str if left_str and left_str != 'ptr' else '' - return base + ' *' if base else 'void *' - if left_str == 'ptr' or (left_str and left_str.endswith('*')): - base: str = right_str if right_str and right_str != 'ptr' else '' - return base + ' *' if base else 'void *' - if right_str and right_str not in ('ptr', 'void', 'i32', 'i64'): - return right_str - if left_str and left_str not in ('ptr', 'void', 'i32', 'i64'): - return left_str - return left_str if left_str else right_str - return '' - - # ================================================================== - # 内部解析方法 - # ================================================================== - - def _ctype_to_llvm_str(self, info: CTypeInfo) -> str: - """从 CTypeInfo 的 BaseType+PtrCount 生成归一化的 LLVM 类型字符串。 - - void* 在 LLVM IR 中归一化为 i8*;struct/enum/union 等非基础类型返回空字符串。 - """ - if not info or not info.BaseType: - return '' - base_type = info.BaseType - base_llvm: str = '' - if isinstance(base_type, type) and issubclass(base_type, _t.CType): - base_llvm = CTypeRegistry.CTypeToLLVM(base_type) - elif isinstance(base_type, _t.CType): - base_llvm = CTypeRegistry.CTypeToLLVM(type(base_type)) - if not base_llvm: - return '' - if info.PtrCount > 0: - if base_llvm == 'void': - return 'i8*' - return base_llvm + '*' * info.PtrCount - return base_llvm - - def _ctype_str_to_llvm(self, type_str: str) -> str: - """将 C 类型名字符串(如 'CUnsignedInt *')转换为 LLVM 类型字符串(如 'i32*') - - 支持: - - C 类名:'CUnsignedInt' → 'i32','CChar' → 'i8' - - 指针:'CUnsignedInt *' → 'i32*','void *' → 'i8*' - - 已是 LLVM 类型:'i32' → 'i32','i8*' → 'i8*' - 无法识别返回空字符串。 - """ - s: str = type_str.strip() - ptr_count: int = 0 - while s.endswith('*'): - ptr_count += 1 - s = s[:-1].strip() - base_llvm: str = '' - if s in ('void', 'CVoid'): - base_llvm = 'void' - else: - base_llvm = CTypeRegistry.NameToLLVM(s) - if not base_llvm and s in ('i8', 'i16', 'i32', 'i64', 'float', 'double', 'half', 'fp128', 'void'): - base_llvm = s - if not base_llvm: - return '' - if ptr_count > 0: - if base_llvm == 'void': - return 'i8*' - return base_llvm + '*' * ptr_count - return base_llvm - - def _resolve_name(self, node: ast.Name) -> str: - """解析 ast.Name 节点""" - id_map: dict[str, str] = { - 'str': 'i8*', 'int': 'i32', 'bool': 'i8', - 'float': 'double', 'None': 'void', - 'UINT8PTR': 'i8*', 'INT8PTR': 'i8*', 'BYTEPTR': 'i8*', - 'UINT16PTR': 'i16*', 'INT16PTR': 'i16*', - 'UINT32PTR': 'i32*', 'INT32PTR': 'i32*', - 'UINT64PTR': 'i64*', 'INT64PTR': 'i64*', - } - if node.id in id_map: - return id_map[node.id] - # 通过 BuiltinTypeMap 解析 VOIDPTR、INTPTR 等指针别名 - builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(node.id) - if builtin_entry: - TypeClass: type - base_ptr: int - TypeClass, base_ptr = builtin_entry - base_llvm: str = CTypeRegistry.CTypeToLLVM(TypeClass) - if base_ptr > 0: - if base_llvm == 'void': - return 'i8*' - return base_llvm + '*' * base_ptr - return base_llvm if base_llvm else 'i32' - # 查找 SymbolTable 中的 typedef - if node.id in self._symtab: - entry: CTypeInfo = self._symtab[node.id] - if entry and entry.IsTypedef: - # 优先用 OriginalType 解析 - if entry.OriginalType: - if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr: - return 'i8*' - elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType: - # 用 CTypeRegistry 生成归一化 LLVM 字符串(void*→i8*),struct/enum 回退 ToString() - resolved: str = self._ctype_to_llvm_str(entry.OriginalType) - if resolved: - return resolved - return entry.OriginalType.ToString() - elif isinstance(entry.OriginalType, str): - # 字符串形式的 OriginalType(如 'CUnsignedInt *')需转换为 LLVM 类型字符串 - llvm_str: str = self._ctype_str_to_llvm(entry.OriginalType) - if llvm_str: - return llvm_str - # OriginalType 为空或字符串无法转换时,回退到 BaseType - if entry.BaseType and (not isinstance(entry.BaseType, (_t._CTypedef,)) or entry.PtrCount > 0): - resolved = self._ctype_to_llvm_str(entry) - if resolved: - return resolved - self._symtab.diagnostics.warn('', 0, f"无法解析 Name 类型 '{node.id}',回退到 i32") - return 'i32' - - def _resolve_attribute(self, node: ast.Attribute) -> str: - """解析 ast.Attribute 节点""" - attr_name: str = node.attr if hasattr(node, 'attr') else '' - 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: - return f'%struct.{attr_name}*' - if attr_name and attr_name not in CTypeRegistry._name_to_class: - return f'%struct.{attr_name}*' - self._symtab.diagnostics.warn('', 0, f"无法解析 Attribute 类型 '{attr_name}',回退到 i32") - return 'i32' - - def _resolve_subscript(self, node: ast.Subscript) -> str: - """解析 ast.Subscript 节点""" - if isinstance(node.value, ast.Name) and node.value.id == 'tuple': - slice_node: ast.AST = node.slice - elem_types: list[str] = [] - if isinstance(slice_node, ast.Tuple): - elt: ast.AST - for elt in slice_node.elts: - elem_types.append(self.get_llvm_type_str(elt)) - else: - elem_types.append(self.get_llvm_type_str(slice_node)) - if elem_types: - return '{ ' + ', '.join(elem_types) + ' }' - if IsListAnnotation(node): - slice_node: ast.AST = node.slice - elem_type: str - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1: - elem_type = self.get_llvm_type_str(slice_node.elts[0]) - else: - elem_type = self.get_llvm_type_str(slice_node) - return elem_type + '*' - self._symtab.diagnostics.warn('', 0, "无法解析 Subscript 类型,回退到 i32") - return 'i32' - - def _resolve_bitor(self, node: ast.BinOp) -> str: - """解析 ast.BinOp(BitOr) 节点""" - left: str = self.get_llvm_type_str(node.left) - right: str = self.get_llvm_type_str(node.right) - if right and right.endswith('*'): - return right - if left and left.endswith('*'): - return left - if left and left not in ('i32', 'void', 'i64'): - return left - if right and right not in ('i32', 'void', 'i64'): - return right - return left if left else right - - def _resolve_call(self, node: ast.Call) -> str: - """解析 ast.Call 节点""" - if isinstance(node.func, ast.Attribute): - if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id): - return self.get_llvm_type_str(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr)) - self._symtab.diagnostics.warn('', 0, "无法解析 Call 类型,回退到 i32") - return 'i32' +"""LLVMTypeMapper — AST 注解节点到 LLVM IR 类型字符串的映射器 + +从 SymbolTable 中提取的类型解析逻辑,职责单一: +将 Python AST 注解节点翻译为 LLVM IR 类型字符串(如 'i32', 'i8*', '{ i32, i8* }')。 + +原 SymbolTable 上的 4 个方法: + - _GetLLVMTypeStr → LLVMTypeMapper.get_llvm_type_str + - _GetFuncRetTypeStr → LLVMTypeMapper.get_func_ret_type_str + - _GetFuncParamTypeStr → LLVMTypeMapper.get_func_param_type_str + - _ResolveTypedefValueType → LLVMTypeMapper.resolve_typedef_value_type +""" +from __future__ import annotations + +import vast as ast +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from lib.core.SymbolTable import SymbolTable + +from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper, BuiltinTypeMap +from lib.core.SymbolUtils import IsTModule, IsListAnnotation +from lib.includes import t as _t +from lib.includes.t import CTypeRegistry + + +class LLVMTypeMapper: + """AST 注解节点 → LLVM IR 类型字符串 映射器""" + + def __init__(self, symtab: SymbolTable): + self._symtab = symtab + + # ================================================================== + # 公共 API + # ================================================================== + + def get_llvm_type_str(self, node: ast.AST | None) -> str: + """将 AST 注解节点转换为 LLVM IR 类型字符串""" + if node is None: + self._symtab.diagnostics.warn('', 0, "类型注解为 None,回退到 i32") + return 'i32' + if isinstance(node, ast.Name): + return self._resolve_name(node) + elif isinstance(node, ast.Attribute): + return self._resolve_attribute(node) + elif isinstance(node, ast.Subscript): + return self._resolve_subscript(node) + elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + return self._resolve_bitor(node) + elif isinstance(node, ast.Constant): + if isinstance(node.value, bool): + return 'i8' + return 'i32' + elif isinstance(node, ast.Call): + return self._resolve_call(node) + self._symtab.diagnostics.warn('', 0, f"无法解析类型节点 {type(node).__name__},回退到 i32") + return 'i32' + + def get_func_ret_type_str(self, returns_node: ast.AST | None) -> str: + """提取函数返回类型的 LLVM 字符串""" + if returns_node is None: + return 'i32' + if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr): + left_str: str = self.get_llvm_type_str(returns_node.left) + right_str: str = self.get_llvm_type_str(returns_node.right) + if right_str and right_str.endswith('*'): + return right_str + if left_str and left_str.endswith('*'): + return left_str + if left_str and left_str not in ('i32', 'void', 'i64'): + return left_str + if right_str and right_str not in ('i32', 'void', 'i64'): + return right_str + return left_str + result: str = self.get_llvm_type_str(returns_node) + return result if result else 'i32' + + def get_func_param_type_str(self, annotation_node: ast.AST | None) -> str: + """提取函数参数类型的 LLVM 字符串""" + if annotation_node is None: + return 'i8*' + if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): + left_str: str = self.get_llvm_type_str(annotation_node.left) + right_str: str = self.get_llvm_type_str(annotation_node.right) + if right_str and right_str.endswith('*'): + return right_str + if left_str and left_str.endswith('*'): + return left_str + if right_str and right_str not in ('i32', 'void', 'i64'): + return right_str + if left_str and left_str not in ('i32', 'void', 'i64'): + return left_str + return right_str if right_str else left_str + result: str = self.get_llvm_type_str(annotation_node) + return result if result else 'i8*' + + def resolve_typedef_value_type(self, node: ast.AST | None) -> str: + """解析 typedef 值表达式的 C 类型字符串""" + if node is None: + return '' + if isinstance(node, ast.Name): + if node.id in self._symtab: + Entry: CTypeInfo = self._symtab[node.id] + if Entry.IsTypedef and Entry.OriginalType: + return Entry.OriginalType + return '' + if isinstance(node, ast.Attribute): + if isinstance(node.value, ast.Name) and IsTModule(node.value.id): + # 直接判断属性名是否为 CPtr(消除对 CName=='*' 的依赖) + if node.attr == 'CPtr': + return 'ptr' + CName: str | None = CTypeHelper.GetCName(node.attr) + if CName == 'CPtr': + return 'ptr' + if CName: + return CName + return '' + if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + left_str: str = self.resolve_typedef_value_type(node.left) + right_str: str = self.resolve_typedef_value_type(node.right) + if right_str == 'ptr' or (right_str and right_str.endswith('*')): + base: str = left_str if left_str and left_str != 'ptr' else '' + return base + ' *' if base else 'void *' + if left_str == 'ptr' or (left_str and left_str.endswith('*')): + base: str = right_str if right_str and right_str != 'ptr' else '' + return base + ' *' if base else 'void *' + if right_str and right_str not in ('ptr', 'void', 'i32', 'i64'): + return right_str + if left_str and left_str not in ('ptr', 'void', 'i32', 'i64'): + return left_str + return left_str if left_str else right_str + return '' + + # ================================================================== + # 内部解析方法 + # ================================================================== + + def _ctype_to_llvm_str(self, info: CTypeInfo) -> str: + """从 CTypeInfo 的 BaseType+PtrCount 生成归一化的 LLVM 类型字符串。 + + void* 在 LLVM IR 中归一化为 i8*;struct/enum/union 等非基础类型返回空字符串。 + """ + if not info or not info.BaseType: + return '' + base_type = info.BaseType + base_llvm: str = '' + if isinstance(base_type, type) and issubclass(base_type, _t.CType): + base_llvm = CTypeRegistry.CTypeToLLVM(base_type) + elif isinstance(base_type, _t.CType): + base_llvm = CTypeRegistry.CTypeToLLVM(type(base_type)) + if not base_llvm: + return '' + if info.PtrCount > 0: + if base_llvm == 'void': + return 'i8*' + return base_llvm + '*' * info.PtrCount + return base_llvm + + def _ctype_str_to_llvm(self, type_str: str) -> str: + """将 C 类型名字符串(如 'CUnsignedInt *')转换为 LLVM 类型字符串(如 'i32*') + + 支持: + - C 类名:'CUnsignedInt' → 'i32','CChar' → 'i8' + - 指针:'CUnsignedInt *' → 'i32*','void *' → 'i8*' + - 已是 LLVM 类型:'i32' → 'i32','i8*' → 'i8*' + 无法识别返回空字符串。 + """ + s: str = type_str.strip() + ptr_count: int = 0 + while s.endswith('*'): + ptr_count += 1 + s = s[:-1].strip() + base_llvm: str = '' + if s in ('void', 'CVoid'): + base_llvm = 'void' + else: + base_llvm = CTypeRegistry.NameToLLVM(s) + if not base_llvm and s in ('i8', 'i16', 'i32', 'i64', 'float', 'double', 'half', 'fp128', 'void'): + base_llvm = s + if not base_llvm: + return '' + if ptr_count > 0: + if base_llvm == 'void': + return 'i8*' + return base_llvm + '*' * ptr_count + return base_llvm + + def _resolve_name(self, node: ast.Name) -> str: + """解析 ast.Name 节点""" + id_map: dict[str, str] = { + 'str': 'i8*', 'int': 'i32', 'bool': 'i8', + 'float': 'double', 'None': 'void', + 'UINT8PTR': 'i8*', 'INT8PTR': 'i8*', 'BYTEPTR': 'i8*', + 'UINT16PTR': 'i16*', 'INT16PTR': 'i16*', + 'UINT32PTR': 'i32*', 'INT32PTR': 'i32*', + 'UINT64PTR': 'i64*', 'INT64PTR': 'i64*', + } + if node.id in id_map: + return id_map[node.id] + # 通过 BuiltinTypeMap 解析 VOIDPTR、INTPTR 等指针别名 + builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(node.id) + if builtin_entry: + TypeClass: type + base_ptr: int + TypeClass, base_ptr = builtin_entry + base_llvm: str = CTypeRegistry.CTypeToLLVM(TypeClass) + if base_ptr > 0: + if base_llvm == 'void': + return 'i8*' + return base_llvm + '*' * base_ptr + return base_llvm if base_llvm else 'i32' + # 查找 SymbolTable 中的 typedef + if node.id in self._symtab: + entry: CTypeInfo = self._symtab[node.id] + if entry and entry.IsTypedef: + # 优先用 OriginalType 解析 + if entry.OriginalType: + if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr: + return 'i8*' + elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType: + # 用 CTypeRegistry 生成归一化 LLVM 字符串(void*→i8*),struct/enum 回退 ToString() + resolved: str = self._ctype_to_llvm_str(entry.OriginalType) + if resolved: + return resolved + return entry.OriginalType.ToString() + elif isinstance(entry.OriginalType, str): + # 字符串形式的 OriginalType(如 'CUnsignedInt *')需转换为 LLVM 类型字符串 + llvm_str: str = self._ctype_str_to_llvm(entry.OriginalType) + if llvm_str: + return llvm_str + # OriginalType 为空或字符串无法转换时,回退到 BaseType + if entry.BaseType and (not isinstance(entry.BaseType, (_t._CTypedef,)) or entry.PtrCount > 0): + resolved = self._ctype_to_llvm_str(entry) + if resolved: + return resolved + self._symtab.diagnostics.warn('', 0, f"无法解析 Name 类型 '{node.id}',回退到 i32") + return 'i32' + + def _resolve_attribute(self, node: ast.Attribute) -> str: + """解析 ast.Attribute 节点""" + attr_name: str = node.attr if hasattr(node, 'attr') else '' + 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: + return f'%struct.{attr_name}*' + if attr_name and attr_name not in CTypeRegistry._name_to_class: + return f'%struct.{attr_name}*' + self._symtab.diagnostics.warn('', 0, f"无法解析 Attribute 类型 '{attr_name}',回退到 i32") + return 'i32' + + def _resolve_subscript(self, node: ast.Subscript) -> str: + """解析 ast.Subscript 节点""" + if isinstance(node.value, ast.Name) and node.value.id == 'tuple': + slice_node: ast.AST = node.slice + elem_types: list[str] = [] + if isinstance(slice_node, ast.Tuple): + elt: ast.AST + for elt in slice_node.elts: + elem_types.append(self.get_llvm_type_str(elt)) + else: + elem_types.append(self.get_llvm_type_str(slice_node)) + if elem_types: + return '{ ' + ', '.join(elem_types) + ' }' + if IsListAnnotation(node): + slice_node: ast.AST = node.slice + elem_type: str + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1: + elem_type = self.get_llvm_type_str(slice_node.elts[0]) + else: + elem_type = self.get_llvm_type_str(slice_node) + return elem_type + '*' + self._symtab.diagnostics.warn('', 0, "无法解析 Subscript 类型,回退到 i32") + return 'i32' + + def _resolve_bitor(self, node: ast.BinOp) -> str: + """解析 ast.BinOp(BitOr) 节点""" + left: str = self.get_llvm_type_str(node.left) + right: str = self.get_llvm_type_str(node.right) + if right and right.endswith('*'): + return right + if left and left.endswith('*'): + return left + if left and left not in ('i32', 'void', 'i64'): + return left + if right and right not in ('i32', 'void', 'i64'): + return right + return left if left else right + + def _resolve_call(self, node: ast.Call) -> str: + """解析 ast.Call 节点""" + if isinstance(node.func, ast.Attribute): + if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id): + return self.get_llvm_type_str(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr)) + self._symtab.diagnostics.warn('', 0, "无法解析 Call 类型,回退到 i32") + return 'i32' diff --git a/lib/core/SymbolData.py b/lib/core/SymbolData.py index c422de0..62276f1 100644 --- a/lib/core/SymbolData.py +++ b/lib/core/SymbolData.py @@ -1,85 +1,85 @@ -"""符号表处理的数据结构:四阶段管线中传递的中间数据""" -from __future__ import annotations -from dataclasses import dataclass, field -from typing import Dict, List, Optional, Tuple, TYPE_CHECKING -import ast - -if TYPE_CHECKING: - from lib.core.Handles.HandlesBase import CTypeInfo - - -@dataclass -class ClassSymbolData: - """从 AST 提取的类符号数据""" - name: str - type_kind: str # 'struct', 'union', 'enum', 'exception' - lineno: int - members: Dict[str, CTypeInfo] - is_cpython_object: bool = False - is_packed: bool = False - enum_members: List[Tuple[str, int, int]] = field(default_factory=list) # (name, value, lineno) - - -@dataclass -class TypedefSymbolData: - """Typedef 符号数据(含原始注解和解析结果)""" - name: str - lineno: int - # 原始注解数据(由 Extractor 设置,Resolver 使用) - annotation: ast.expr | None = None - value: ast.expr | int | str | float | None = None - has_cdefine: bool = False - has_postdef: bool = False - has_ctypedef: bool = False - # 解析结果(由 Resolver 设置,Inserter 使用) - original_type_kind: Optional[str] = None - original_class: type | None = None - members: Optional[Dict] = None - - -@dataclass -class FuncSymbolData: - """函数符号数据(含原始注解和解析结果)""" - name: str - lineno: int - # 原始数据(由 Extractor 设置) - returns_node: ast.expr | None = None - params: List = field(default_factory=list) # [(name, annotation_node), ...] - is_variadic: bool = False - is_inline: bool = False - # 解析结果(由 Resolver 设置) - ret_type: str | None = None - param_types: List = field(default_factory=list) # [str, ...] - # 解析结果(CTypeInfo,保留符号性,由 Resolver 设置) - ret_ctype: Optional[CTypeInfo] = None - - -@dataclass -class DefineSymbolData: - """Define 符号数据(含原始值和解析结果)""" - name: str - lineno: int - # 原始数据(由 Extractor 设置) - value_node: ast.expr | None = None - # 解析结果(由 Resolver 设置) - value: int | str | float | None = None - - -@dataclass -class AnonymousTypeData: - """匿名类型数据""" - name: str - is_union: bool - members: Dict[str, CTypeInfo] - lineno: int - - -@dataclass -class ModuleSymbols: - """从模块提取的完整符号数据,在四阶段管线中传递""" - file_path: str - classes: List[ClassSymbolData] = field(default_factory=list) - typedefs: List[TypedefSymbolData] = field(default_factory=list) - functions: List[FuncSymbolData] = field(default_factory=list) - defines: List[DefineSymbolData] = field(default_factory=list) - anonymous_types: Dict[str, AnonymousTypeData] = field(default_factory=dict) +"""符号表处理的数据结构:四阶段管线中传递的中间数据""" +from __future__ import annotations +from dataclasses import dataclass, field +from typing import Dict, List, Optional, Tuple, TYPE_CHECKING +import vast as ast + +if TYPE_CHECKING: + from lib.core.Handles.HandlesBase import CTypeInfo + + +@dataclass +class ClassSymbolData: + """从 AST 提取的类符号数据""" + name: str + type_kind: str # 'struct', 'union', 'enum', 'exception' + lineno: int + members: Dict[str, CTypeInfo] + is_cpython_object: bool = False + is_packed: bool = False + enum_members: List[Tuple[str, int, int]] = field(default_factory=list) # (name, value, lineno) + + +@dataclass +class TypedefSymbolData: + """Typedef 符号数据(含原始注解和解析结果)""" + name: str + lineno: int + # 原始注解数据(由 Extractor 设置,Resolver 使用) + annotation: ast.expr | None = None + value: ast.expr | int | str | float | None = None + has_cdefine: bool = False + has_postdef: bool = False + has_ctypedef: bool = False + # 解析结果(由 Resolver 设置,Inserter 使用) + original_type_kind: Optional[str] = None + original_class: type | None = None + members: Optional[Dict] = None + + +@dataclass +class FuncSymbolData: + """函数符号数据(含原始注解和解析结果)""" + name: str + lineno: int + # 原始数据(由 Extractor 设置) + returns_node: ast.expr | None = None + params: List = field(default_factory=list) # [(name, annotation_node), ...] + is_variadic: bool = False + is_inline: bool = False + # 解析结果(由 Resolver 设置) + ret_type: str | None = None + param_types: List = field(default_factory=list) # [str, ...] + # 解析结果(CTypeInfo,保留符号性,由 Resolver 设置) + ret_ctype: Optional[CTypeInfo] = None + + +@dataclass +class DefineSymbolData: + """Define 符号数据(含原始值和解析结果)""" + name: str + lineno: int + # 原始数据(由 Extractor 设置) + value_node: ast.expr | None = None + # 解析结果(由 Resolver 设置) + value: int | str | float | None = None + + +@dataclass +class AnonymousTypeData: + """匿名类型数据""" + name: str + is_union: bool + members: Dict[str, CTypeInfo] + lineno: int + + +@dataclass +class ModuleSymbols: + """从模块提取的完整符号数据,在四阶段管线中传递""" + file_path: str + classes: List[ClassSymbolData] = field(default_factory=list) + typedefs: List[TypedefSymbolData] = field(default_factory=list) + functions: List[FuncSymbolData] = field(default_factory=list) + defines: List[DefineSymbolData] = field(default_factory=list) + anonymous_types: Dict[str, AnonymousTypeData] = field(default_factory=dict) diff --git a/lib/core/SymbolExtractor.py b/lib/core/SymbolExtractor.py index f3fba6a..b69b6c6 100644 --- a/lib/core/SymbolExtractor.py +++ b/lib/core/SymbolExtractor.py @@ -1,307 +1,307 @@ -"""Pass 1: ASTSymbolExtractor — 从 AST 提取原始符号信息""" -from __future__ import annotations -import ast -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.SymbolTable import SymbolTable - -from lib.core.SymbolData import ( - ModuleSymbols, ClassSymbolData, TypedefSymbolData, - FuncSymbolData, DefineSymbolData, AnonymousTypeData -) -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.core.SymbolUtils import AnnotationContainsTType, CheckAnnotationHasCInline, IsTModule, AnnotationContainsName -from lib.includes import t - - -class ASTSymbolExtractor: - """从 Python 源文件的 AST 中提取所有符号信息""" - - def __init__(self, symbol_table: SymbolTable) -> None: - self._symtab: SymbolTable = symbol_table - - def extract(self, file_path: str) -> ModuleSymbols: - """提取文件中的所有符号信息""" - with open(file_path, 'r', encoding='utf-8') as f: - code: str = f.read() - tree: ast.Module = ast.parse(code) - - result: ModuleSymbols = ModuleSymbols(file_path=file_path) - - # 第一步:收集所有类的成员和匿名类型 - class_members: dict[str, dict[str, CTypeInfo]] = {} - for node in tree.body: - if isinstance(node, ast.ClassDef): - members: dict[str, CTypeInfo] = {} - self._collect_members(node, members, result.anonymous_types) - class_members[node.name] = members - - # 第二步:从每个顶层节点提取符号信息 - for node in tree.body: - if isinstance(node, ast.ClassDef): - members_info: dict[str, CTypeInfo] = class_members.get(node.name, {}) - result.classes.append(self._extract_class(node, members_info)) - elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): - self._extract_ann_assign(node, result) - elif isinstance(node, ast.FunctionDef): - result.functions.append(self._extract_function(node)) - - return result - - # ------------------------------------------------------------------ - # 成员收集(递归处理嵌套匿名类) - # ------------------------------------------------------------------ - - def _collect_members(self, class_node: ast.ClassDef, members: dict[str, CTypeInfo], anonymous_types: dict[str, AnonymousTypeData], prefix: str = '') -> None: - """递归收集类成员,包括嵌套匿名类型""" - for item in class_node.body: - if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): - member_name: str = item.target.id - full_name: str = f'{prefix}{member_name}' if prefix else member_name - member_type: CTypeInfo | None = CTypeInfo.FromNode(item.annotation, self._symtab) - if member_type is None: - member_type = CTypeInfo() - member_type.BaseType = t.CInt() - is_ptr: bool = member_type.IsPtr - if isinstance(item.annotation, ast.BinOp): - if AnnotationContainsName(item.annotation, 'CPtr'): - is_ptr = True - members[full_name] = member_type.Copy() - - elif isinstance(item, ast.ClassDef): - is_anonymous: bool = any( - any(AnnotationContainsTType(base, 'Anonymous') for base in item.bases) - ) if item.bases else False - - if is_anonymous: - is_union: bool = any( - any(AnnotationContainsTType(base, 'CUnion') for base in item.bases) - ) - # 也检查装饰器形式 @t.CUnion - if not is_union and hasattr(item, 'decorator_list') and item.decorator_list: - for deco in item.decorator_list: - if isinstance(deco, ast.Attribute) and hasattr(deco.value, 'id') and IsTModule(deco.value.id, self._symtab) and deco.attr == 'CUnion': - is_union = True - break - elif isinstance(deco, ast.Name): - cls2: type | None = getattr(t, deco.id, None) - if cls2 is None and hasattr(self._symtab, '_t_type_symbols'): - cls2 = self._symtab._t_type_symbols.get(deco.id) - if cls2 is not None and isinstance(cls2, type) and issubclass(cls2, t.CUnion): - is_union = True - break - - nested_name: str = f'{prefix}{item.name}' if prefix else item.name - members[nested_name] = CTypeInfo() - members[nested_name].BaseType = f'union {item.name}' if is_union else f'struct {item.name}' - members[nested_name].PtrCount = 0 - members[nested_name].ArrayDims = [] - - new_prefix: str = f'{prefix}{item.name}.' if prefix else f'{item.name}.' - self._collect_members(item, members, anonymous_types, new_prefix) - - anonymous_members: dict[str, CTypeInfo] = {} - for full_name, member_info in members.items(): - if full_name.startswith(f"{nested_name}."): - member_name: str = full_name[len(nested_name) + 1:] - anonymous_members[member_name] = member_info - - if item.name not in anonymous_types: - anonymous_types[item.name] = AnonymousTypeData( - name=item.name, - is_union=is_union, - members=anonymous_members, - lineno=item.lineno - ) - - # ------------------------------------------------------------------ - # 类符号提取 - # ------------------------------------------------------------------ - - def _extract_class(self, node: ast.ClassDef, members_info: dict[str, CTypeInfo]) -> ClassSymbolData: - """从 ClassDef 节点提取类符号数据""" - type_kind: str = 'struct' - is_cpython_object: bool = False - is_packed: bool = False - - # 检查装饰器 - if hasattr(node, 'decorator_list') and node.decorator_list: - for decorator in node.decorator_list: - if isinstance(decorator, ast.Attribute): - if (hasattr(decorator.value, 'id') and - IsTModule(decorator.value.id, self._symtab)): - if decorator.attr == 'Object': - is_cpython_object = True - elif decorator.attr == 'CUnion': - type_kind = 'union' - elif decorator.attr == 'CEnum': - type_kind = 'enum' - elif decorator.attr == 'REnum': - type_kind = 'renum' - elif decorator.attr == 'CStruct': - type_kind = 'struct' - elif isinstance(decorator, ast.Name): - # from t import CStruct / CUnion / CEnum / REnum - cls: type | None = getattr(t, decorator.id, None) - if cls is None and hasattr(self._symtab, '_t_type_symbols'): - cls = self._symtab._t_type_symbols.get(decorator.id) - if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType): - if issubclass(cls, t.CUnion): - type_kind = 'union' - elif issubclass(cls, t.REnum): - type_kind = 'renum' - elif issubclass(cls, t.CEnum): - type_kind = 'enum' - elif issubclass(cls, t.CStruct): - type_kind = 'struct' - elif decorator.id == 'Object': - is_cpython_object = True - elif isinstance(decorator, ast.Call): - if isinstance(decorator.func, ast.Attribute): - if hasattr(decorator.func.value, 'id') and decorator.func.value.id == 'c' and decorator.func.attr == 'Attribute': - for arg in decorator.args: - if isinstance(arg, ast.Attribute): - if isinstance(arg.value, ast.Attribute): - if hasattr(arg.value.value, 'id') and IsTModule(arg.value.value.id, self._symtab) and arg.value.attr == 'attr' and arg.attr == 'packed': - is_packed = True - - # 检查基类 - for base in node.bases: - if AnnotationContainsTType(base, 'CUnion'): - type_kind = 'union' - break - elif AnnotationContainsTType(base, 'CEnum'): - type_kind = 'enum' - break - elif AnnotationContainsTType(base, 'REnum'): - type_kind = 'renum' - break - elif AnnotationContainsTType(base, 'CStruct'): - type_kind = 'struct' - break - elif AnnotationContainsTType(base, 'Object'): - is_cpython_object = True - type_kind = 'struct' - break - elif isinstance(base, ast.Name) and base.id == 'Exception': - type_kind = 'exception' - break - elif isinstance(base, ast.Name): - base_entry: CTypeInfo | None = self._symtab.get(base.id) - if base_entry and base_entry.IsExceptionClass: - type_kind = 'exception' - break - - # 提取枚举成员 - enum_members: list[tuple[str, int, int]] = [] - if type_kind == 'enum': - next_enum_value: int = 0 - for item in node.body: - if isinstance(item, ast.Assign): - if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name): - member_name: str = item.targets[0].id - if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): - next_enum_value = item.value.value + 1 - else: - next_enum_value += 1 - enum_members.append((member_name, next_enum_value - 1, item.lineno)) - elif isinstance(item, ast.AnnAssign): - if isinstance(item.target, ast.Name): - member_name: str = item.target.id - if item.value: - if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): - next_enum_value = item.value.value + 1 - else: - next_enum_value += 1 - else: - next_enum_value += 1 - enum_members.append((member_name, next_enum_value - 1, item.lineno)) - - # REnum 变体提取(嵌套 ClassDef + Assign 显式值) - # 与 HandlesClassDef._EmitREnumLlvm 的 tag 分配逻辑对齐: - # - 先收集 Assign 显式值 - # - ClassDef 变体从 max(explicit)+1 开始顺序编号 - # - Assign 无显式值时用独立计数器 variant_index - if type_kind == 'renum': - explicit_values: dict[str, int] = {} - for item in node.body: - if isinstance(item, ast.Assign): - for target in item.targets: - if isinstance(target, ast.Name): - if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): - explicit_values[target.id] = item.value.value - next_class_tag: int = max(explicit_values.values()) + 1 if explicit_values else 0 - variant_index: int = 0 - for item in node.body: - if isinstance(item, ast.ClassDef): - variant_name_r: str = item.name - tag: int = next_class_tag - next_class_tag += 1 - enum_members.append((variant_name_r, tag, item.lineno)) - elif isinstance(item, ast.Assign): - for target in item.targets: - if isinstance(target, ast.Name): - var_name: str = target.id - if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): - value: int = item.value.value - else: - value = variant_index - variant_index += 1 - enum_members.append((var_name, value, item.lineno)) - - return ClassSymbolData( - name=node.name, - type_kind=type_kind, - lineno=node.lineno, - members=members_info, - is_cpython_object=is_cpython_object, - is_packed=is_packed, - enum_members=enum_members, - ) - - # ------------------------------------------------------------------ - # AnnAssign 提取(typedef / define) - # ------------------------------------------------------------------ - - def _extract_ann_assign(self, node: ast.AnnAssign, result: ModuleSymbols) -> None: - """从 AnnAssign 节点提取 typedef 或 define 数据""" - var_name: str = node.target.id - has_cdefine: bool = AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False - has_postdef: bool = AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False - has_ctypedef: bool = AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False - - if has_cdefine: - result.defines.append(DefineSymbolData( - name=var_name, - lineno=node.lineno, - value_node=node.value, - )) - else: - result.typedefs.append(TypedefSymbolData( - name=var_name, - lineno=node.lineno, - annotation=node.annotation, - value=node.value, - has_cdefine=has_cdefine, - has_postdef=has_postdef, - has_ctypedef=has_ctypedef, - )) - - # ------------------------------------------------------------------ - # 函数提取 - # ------------------------------------------------------------------ - - def _extract_function(self, node: ast.FunctionDef) -> FuncSymbolData: - """从 FunctionDef 节点提取函数符号数据""" - params: list[tuple[str, ast.AST | None]] = [(arg.arg, arg.annotation) for arg in node.args.args] - is_variadic: bool = node.args.vararg is not None - is_inline: bool = CheckAnnotationHasCInline(node.returns) - - return FuncSymbolData( - name=node.name, - lineno=node.lineno, - returns_node=node.returns, - params=params, - is_variadic=is_variadic, - is_inline=is_inline, - ) +"""Pass 1: ASTSymbolExtractor — 从 AST 提取原始符号信息""" +from __future__ import annotations +import vast as ast +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.SymbolTable import SymbolTable + +from lib.core.SymbolData import ( + ModuleSymbols, ClassSymbolData, TypedefSymbolData, + FuncSymbolData, DefineSymbolData, AnonymousTypeData +) +from lib.core.Handles.HandlesBase import CTypeInfo +from lib.core.SymbolUtils import AnnotationContainsTType, CheckAnnotationHasCInline, IsTModule, AnnotationContainsName +from lib.includes import t + + +class ASTSymbolExtractor: + """从 Python 源文件的 AST 中提取所有符号信息""" + + def __init__(self, symbol_table: SymbolTable) -> None: + self._symtab: SymbolTable = symbol_table + + def extract(self, file_path: str) -> ModuleSymbols: + """提取文件中的所有符号信息""" + with open(file_path, 'r', encoding='utf-8') as f: + code: str = f.read() + tree: ast.Module = ast.parse(code) + + result: ModuleSymbols = ModuleSymbols(file_path=file_path) + + # 第一步:收集所有类的成员和匿名类型 + class_members: dict[str, dict[str, CTypeInfo]] = {} + for node in tree.body: + if isinstance(node, ast.ClassDef): + members: dict[str, CTypeInfo] = {} + self._collect_members(node, members, result.anonymous_types) + class_members[node.name] = members + + # 第二步:从每个顶层节点提取符号信息 + for node in tree.body: + if isinstance(node, ast.ClassDef): + members_info: dict[str, CTypeInfo] = class_members.get(node.name, {}) + result.classes.append(self._extract_class(node, members_info)) + elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name): + self._extract_ann_assign(node, result) + elif isinstance(node, ast.FunctionDef): + result.functions.append(self._extract_function(node)) + + return result + + # ------------------------------------------------------------------ + # 成员收集(递归处理嵌套匿名类) + # ------------------------------------------------------------------ + + def _collect_members(self, class_node: ast.ClassDef, members: dict[str, CTypeInfo], anonymous_types: dict[str, AnonymousTypeData], prefix: str = '') -> None: + """递归收集类成员,包括嵌套匿名类型""" + for item in class_node.body: + if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name): + member_name: str = item.target.id + full_name: str = f'{prefix}{member_name}' if prefix else member_name + member_type: CTypeInfo | None = CTypeInfo.FromNode(item.annotation, self._symtab) + if member_type is None: + member_type = CTypeInfo() + member_type.BaseType = t.CInt() + is_ptr: bool = member_type.IsPtr + if isinstance(item.annotation, ast.BinOp): + if AnnotationContainsName(item.annotation, 'CPtr'): + is_ptr = True + members[full_name] = member_type.Copy() + + elif isinstance(item, ast.ClassDef): + is_anonymous: bool = any( + any(AnnotationContainsTType(base, 'Anonymous') for base in item.bases) + ) if item.bases else False + + if is_anonymous: + is_union: bool = any( + any(AnnotationContainsTType(base, 'CUnion') for base in item.bases) + ) + # 也检查装饰器形式 @t.CUnion + if not is_union and hasattr(item, 'decorator_list') and item.decorator_list: + for deco in item.decorator_list: + if isinstance(deco, ast.Attribute) and hasattr(deco.value, 'id') and IsTModule(deco.value.id, self._symtab) and deco.attr == 'CUnion': + is_union = True + break + elif isinstance(deco, ast.Name): + cls2: type | None = getattr(t, deco.id, None) + if cls2 is None and hasattr(self._symtab, '_t_type_symbols'): + cls2 = self._symtab._t_type_symbols.get(deco.id) + if cls2 is not None and isinstance(cls2, type) and issubclass(cls2, t.CUnion): + is_union = True + break + + nested_name: str = f'{prefix}{item.name}' if prefix else item.name + members[nested_name] = CTypeInfo() + members[nested_name].BaseType = f'union {item.name}' if is_union else f'struct {item.name}' + members[nested_name].PtrCount = 0 + members[nested_name].ArrayDims = [] + + new_prefix: str = f'{prefix}{item.name}.' if prefix else f'{item.name}.' + self._collect_members(item, members, anonymous_types, new_prefix) + + anonymous_members: dict[str, CTypeInfo] = {} + for full_name, member_info in members.items(): + if full_name.startswith(f"{nested_name}."): + member_name: str = full_name[len(nested_name) + 1:] + anonymous_members[member_name] = member_info + + if item.name not in anonymous_types: + anonymous_types[item.name] = AnonymousTypeData( + name=item.name, + is_union=is_union, + members=anonymous_members, + lineno=item.lineno + ) + + # ------------------------------------------------------------------ + # 类符号提取 + # ------------------------------------------------------------------ + + def _extract_class(self, node: ast.ClassDef, members_info: dict[str, CTypeInfo]) -> ClassSymbolData: + """从 ClassDef 节点提取类符号数据""" + type_kind: str = 'struct' + is_cpython_object: bool = False + is_packed: bool = False + + # 检查装饰器 + if hasattr(node, 'decorator_list') and node.decorator_list: + for decorator in node.decorator_list: + if isinstance(decorator, ast.Attribute): + if (hasattr(decorator.value, 'id') and + IsTModule(decorator.value.id, self._symtab)): + if decorator.attr == 'Object': + is_cpython_object = True + elif decorator.attr == 'CUnion': + type_kind = 'union' + elif decorator.attr == 'CEnum': + type_kind = 'enum' + elif decorator.attr == 'REnum': + type_kind = 'renum' + elif decorator.attr == 'CStruct': + type_kind = 'struct' + elif isinstance(decorator, ast.Name): + # from t import CStruct / CUnion / CEnum / REnum + cls: type | None = getattr(t, decorator.id, None) + if cls is None and hasattr(self._symtab, '_t_type_symbols'): + cls = self._symtab._t_type_symbols.get(decorator.id) + if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType): + if issubclass(cls, t.CUnion): + type_kind = 'union' + elif issubclass(cls, t.REnum): + type_kind = 'renum' + elif issubclass(cls, t.CEnum): + type_kind = 'enum' + elif issubclass(cls, t.CStruct): + type_kind = 'struct' + elif decorator.id == 'Object': + is_cpython_object = True + elif isinstance(decorator, ast.Call): + if isinstance(decorator.func, ast.Attribute): + if hasattr(decorator.func.value, 'id') and decorator.func.value.id == 'c' and decorator.func.attr == 'Attribute': + for arg in decorator.args: + if isinstance(arg, ast.Attribute): + if isinstance(arg.value, ast.Attribute): + if hasattr(arg.value.value, 'id') and IsTModule(arg.value.value.id, self._symtab) and arg.value.attr == 'attr' and arg.attr == 'packed': + is_packed = True + + # 检查基类 + for base in node.bases: + if AnnotationContainsTType(base, 'CUnion'): + type_kind = 'union' + break + elif AnnotationContainsTType(base, 'CEnum'): + type_kind = 'enum' + break + elif AnnotationContainsTType(base, 'REnum'): + type_kind = 'renum' + break + elif AnnotationContainsTType(base, 'CStruct'): + type_kind = 'struct' + break + elif AnnotationContainsTType(base, 'Object'): + is_cpython_object = True + type_kind = 'struct' + break + elif isinstance(base, ast.Name) and base.id == 'Exception': + type_kind = 'exception' + break + elif isinstance(base, ast.Name): + base_entry: CTypeInfo | None = self._symtab.get(base.id) + if base_entry and base_entry.IsExceptionClass: + type_kind = 'exception' + break + + # 提取枚举成员 + enum_members: list[tuple[str, int, int]] = [] + if type_kind == 'enum': + next_enum_value: int = 0 + for item in node.body: + if isinstance(item, ast.Assign): + if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name): + member_name: str = item.targets[0].id + if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): + next_enum_value = item.value.value + 1 + else: + next_enum_value += 1 + enum_members.append((member_name, next_enum_value - 1, item.lineno)) + elif isinstance(item, ast.AnnAssign): + if isinstance(item.target, ast.Name): + member_name: str = item.target.id + if item.value: + if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): + next_enum_value = item.value.value + 1 + else: + next_enum_value += 1 + else: + next_enum_value += 1 + enum_members.append((member_name, next_enum_value - 1, item.lineno)) + + # REnum 变体提取(嵌套 ClassDef + Assign 显式值) + # 与 HandlesClassDef._EmitREnumLlvm 的 tag 分配逻辑对齐: + # - 先收集 Assign 显式值 + # - ClassDef 变体从 max(explicit)+1 开始顺序编号 + # - Assign 无显式值时用独立计数器 variant_index + if type_kind == 'renum': + explicit_values: dict[str, int] = {} + for item in node.body: + if isinstance(item, ast.Assign): + for target in item.targets: + if isinstance(target, ast.Name): + if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): + explicit_values[target.id] = item.value.value + next_class_tag: int = max(explicit_values.values()) + 1 if explicit_values else 0 + variant_index: int = 0 + for item in node.body: + if isinstance(item, ast.ClassDef): + variant_name_r: str = item.name + tag: int = next_class_tag + next_class_tag += 1 + enum_members.append((variant_name_r, tag, item.lineno)) + elif isinstance(item, ast.Assign): + for target in item.targets: + if isinstance(target, ast.Name): + var_name: str = target.id + if item.value and isinstance(item.value, ast.Constant) and isinstance(item.value.value, int): + value: int = item.value.value + else: + value = variant_index + variant_index += 1 + enum_members.append((var_name, value, item.lineno)) + + return ClassSymbolData( + name=node.name, + type_kind=type_kind, + lineno=node.lineno, + members=members_info, + is_cpython_object=is_cpython_object, + is_packed=is_packed, + enum_members=enum_members, + ) + + # ------------------------------------------------------------------ + # AnnAssign 提取(typedef / define) + # ------------------------------------------------------------------ + + def _extract_ann_assign(self, node: ast.AnnAssign, result: ModuleSymbols) -> None: + """从 AnnAssign 节点提取 typedef 或 define 数据""" + var_name: str = node.target.id + has_cdefine: bool = AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False + has_postdef: bool = AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False + has_ctypedef: bool = AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False + + if has_cdefine: + result.defines.append(DefineSymbolData( + name=var_name, + lineno=node.lineno, + value_node=node.value, + )) + else: + result.typedefs.append(TypedefSymbolData( + name=var_name, + lineno=node.lineno, + annotation=node.annotation, + value=node.value, + has_cdefine=has_cdefine, + has_postdef=has_postdef, + has_ctypedef=has_ctypedef, + )) + + # ------------------------------------------------------------------ + # 函数提取 + # ------------------------------------------------------------------ + + def _extract_function(self, node: ast.FunctionDef) -> FuncSymbolData: + """从 FunctionDef 节点提取函数符号数据""" + params: list[tuple[str, ast.AST | None]] = [(arg.arg, arg.annotation) for arg in node.args.args] + is_variadic: bool = node.args.vararg is not None + is_inline: bool = CheckAnnotationHasCInline(node.returns) + + return FuncSymbolData( + name=node.name, + lineno=node.lineno, + returns_node=node.returns, + params=params, + is_variadic=is_variadic, + is_inline=is_inline, + ) diff --git a/lib/core/SymbolTable.py b/lib/core/SymbolTable.py index 9646b54..34da36a 100644 --- a/lib/core/SymbolTable.py +++ b/lib/core/SymbolTable.py @@ -1,531 +1,531 @@ -from __future__ import annotations -from typing import TYPE_CHECKING, Any, Iterator -if TYPE_CHECKING: - from lib.core.translator import Translator - -import ast -import traceback - -from lib.core.Handles.HandlesBase import CTypeInfo -from lib.includes import t -from lib.core.VLogger import get_logger as _vlog -from lib.core.DiagnosticCollector import DiagnosticCollector -from lib.core.LLVMTypeMapper import LLVMTypeMapper -from lib.core.SymbolExtractor import ASTSymbolExtractor -from lib.core.SymbolTypeResolver import TypeResolver -from lib.core.SymbolInserter import SymbolInserter -from lib.core.SymbolReexporter import PackageReexporter -from lib.core.ConstEvaluator import ConstEvaluator -from lib.core.SymbolData import ModuleSymbols - -# 从 SymbolUtils 重导出,保持向后兼容 -from lib.core.SymbolUtils import CheckAnnotationHasCInline as _CheckAnnotationHasCInline - - -class SymbolTable: - def __init__(self, translator: Translator) -> None: - self.translator: Translator = translator - self._symbols: dict[str, CTypeInfo] = {} - self._namespaces: dict[str, dict[str, CTypeInfo]] = {} # 模块名 -> 符号字典 - self._t_type_symbols: dict[str, type] = {} # 别名 -> t.CType 子类 (from t import CEnum as en) - self.diagnostics: DiagnosticCollector = DiagnosticCollector() - self._type_mapper: LLVMTypeMapper = LLVMTypeMapper(self) - self.import_aliases: dict[str, str] = {} # 别名 -> 模块路径 - - def __getstate__(self) -> dict: - """pickle 序列化:排除不可序列化的字段(translator/_type_mapper/diagnostics)""" - state: dict = self.__dict__.copy() - state.pop('translator', None) - state.pop('_type_mapper', None) - state.pop('diagnostics', None) - return state - - def __setstate__(self, state: dict) -> None: - """pickle 反序列化:重建可序列化的字段,translator 由调用方后续设置""" - self.__dict__.update(state) - self.translator = None # 由调用方赋值 - self.diagnostics = DiagnosticCollector() - self._type_mapper = LLVMTypeMapper(self) - - def clear(self) -> None: - self._symbols.clear() - self._namespaces.clear() - self._t_type_symbols.clear() - self.import_aliases.clear() - - def get(self, name: str, default: CTypeInfo | None = None) -> CTypeInfo | None: - return self._symbols.get(name, default) - - def set(self, name: str, value: CTypeInfo | dict[str, Any]) -> None: - if isinstance(value, CTypeInfo): - self._symbols[name] = value - else: - # 兼容旧代码传入 dict 的情况 - info: CTypeInfo = self._CTypeInfoFromDict(name, value) - self._symbols[name] = info - - def update(self, symbols: dict[str, CTypeInfo | dict[str, Any]]) -> None: - for name, value in symbols.items(): - self.set(name, value) - - def keys(self) -> Iterator[str]: - return iter(self._symbols.keys()) - - def values(self) -> Iterator[CTypeInfo]: - return iter(self._symbols.values()) - - def items(self) -> Iterator[tuple[str, CTypeInfo]]: - return iter(self._symbols.items()) - - def pop(self, name: str, *args: Any) -> CTypeInfo: - return self._symbols.pop(name, *args) - - def __getitem__(self, name: str) -> CTypeInfo: - if name in self._symbols: - return self._symbols[name] - raise KeyError(name) - - def __setitem__(self, name: str, value: CTypeInfo | dict[str, Any]) -> None: - self.set(name, value) - - def __delitem__(self, name: str) -> None: - del self._symbols[name] - - def __contains__(self, name: str) -> bool: - return name in self._symbols - - def __len__(self) -> int: - return len(self._symbols) - - def __iter__(self) -> Iterator[str]: - return iter(self._symbols) - - # ================================================================== - # 服务接口 — 语义化的符号查询与操作方法 - # ================================================================== - - def lookup(self, name: str) -> CTypeInfo | None: - """查找符号,支持别名解析和 dotted name - - 解析顺序: - 1. 直接匹配 _symbols - 2. 如果包含 '.',解析第一个段为别名后查找剩余路径 - 3. 查 _t_type_symbols(t/c 类型别名,返回模拟 CTypeInfo) - """ - if name in self._symbols: - return self._symbols[name] - - if '.' not in name: - return self._lookup_t_type(name) - - # dotted name: 尝试解析第一个段为别名 - parts: list[str] = name.split('.', 1) - first: str = parts[0] - rest: str = parts[1] - - # 1) 别名解析:import X as Y → Y.Symbol → X.Symbol - resolved: str | None = self.import_aliases.get(first) - if resolved: - alias_name: str = f"{resolved}.{rest}" - if alias_name in self._symbols: - return self._symbols[alias_name] - - # 2) 纯路径查找:module.ClassName - # (已在 line 100 检查过,此处为兜底,保留注释说明路径查找语义) - - return None - - def _lookup_t_type(self, name: str) -> CTypeInfo | None: - """在 _t_type_symbols 中查找 t/c 类型别名,返回模拟 CTypeInfo""" - cls: type | None = self._t_type_symbols.get(name) - if cls is None: - return None - info: CTypeInfo = CTypeInfo() - info.Name = name - info.BaseType = cls() - if issubclass(cls, (t.CEnum, t.REnum)): - info.IsEnum = True - elif issubclass(cls, t.CUnion): - info.IsUnion = True - elif issubclass(cls, t.CStruct): - info.IsStruct = True - return info - - def register_namespace(self, module_name: str) -> None: - """注册一个模块命名空间""" - if module_name not in self._namespaces: - self._namespaces[module_name] = {} - - def has(self, name: str) -> bool: - """检查符号是否存在(替代 `name in SymbolTable`)""" - return name in self._symbols - - def is_struct(self, name: str) -> bool: - """检查名称是否为结构体""" - entry: CTypeInfo | None = self._symbols.get(name) - return entry is not None and (entry.IsStruct or entry.IsCpythonObject) - - def is_define(self, name: str) -> bool: - """检查名称是否为常量定义""" - entry: CTypeInfo | None = self._symbols.get(name) - return entry is not None and entry.IsDefine - - def insert(self, name: str, info: CTypeInfo) -> None: - """插入符号(替代 `SymbolTable[name] = info`)""" - self._symbols[name] = info - - def resolve_alias(self, module_path: str) -> str: - """解析 import 别名,无别名返回原路径""" - return self.import_aliases.get(module_path, module_path) - - def ToDict(self) -> dict[str, Any]: - """序列化为字典格式,BaseType 使用可重建的 dict 格式 - - 返回的 dict 包含: - - 符号条目:{name: {attrs}}(与旧格式兼容) - - '__namespaces__': {namespace: [symbol_names]} 命名空间索引 - - '__import_aliases__': {alias: module_path} 导入别名 - """ - result: dict[str, Any] = {} - for name, info in self._symbols.items(): - entry: dict[str, Any] = {'name': name} - if info.BaseType: - entry['BaseType'] = self._SerializeBaseType(info.BaseType) - if info.PtrCount: - entry['PtrCount'] = info.PtrCount - if info.IsTypedef: - entry['IsTypedef'] = True - if info.IsStruct: - entry['IsStruct'] = True - if info.IsEnum: - entry['IsEnum'] = True - if info.IsUnion: - entry['IsUnion'] = True - if info.IsFunction: - entry['IsFunction'] = True - if info.IsVariable: - entry['IsVariable'] = True - if info.IsDefine: - entry['IsDefine'] = True - if info.OriginalType: - entry['OriginalType'] = str(info.OriginalType) - if info.Lineno: - entry['lineno'] = info.Lineno - if info.file: - entry['file'] = info.file - if info.Members: - entry['members'] = info.Members - extra: dict[str, Any] = info._sm._extra - if extra: - entry.update(extra) - result[name] = entry - - # 序列化命名空间信息 - if self._namespaces: - result['__namespaces__'] = { - ns: list(symbols.keys()) for ns, symbols in self._namespaces.items() - } - if self.import_aliases: - result['__import_aliases__'] = dict(self.import_aliases) - if self._t_type_symbols: - result['__t_type_symbols__'] = { - name: cls.__name__ for name, cls in self._t_type_symbols.items() - } - - return result - - @staticmethod - def _SerializeBaseType(base_type: t.CType | tuple | list | str | None) -> dict | str: - """将 BaseType 序列化为可重建的格式""" - if isinstance(base_type, t.CType): - return {'class': type(base_type).__name__} - if isinstance(base_type, (tuple, list)): - return {'classes': [type(b).__name__ for b in base_type if isinstance(b, t.CType)]} - return str(base_type) - - @staticmethod - def _DeserializeBaseType(data: Any) -> Any: - """从序列化格式恢复 BaseType""" - if isinstance(data, dict): - if 'class' in data: - cls: type | None = getattr(t, data['class'], None) - if cls and isinstance(cls, type) and issubclass(cls, t.CType): - return cls() - elif 'classes' in data: - types: list[t.CType] = [] - for cname in data['classes']: - cls: type | None = getattr(t, cname, None) - if cls and isinstance(cls, type) and issubclass(cls, t.CType): - types.append(cls()) - if types: - return tuple(types) - elif isinstance(data, str): - cls: type | None = getattr(t, data, None) - if cls and isinstance(cls, type) and issubclass(cls, t.CType): - return cls() - return None - - def FromDict(self, symbols: dict[str, Any]) -> None: - """从字典格式反序列化(兼容带/不带命名空间信息的两种格式)""" - self._symbols.clear() - self._namespaces.clear() - self.import_aliases.clear() - self._t_type_symbols.clear() - - _SPECIAL_KEYS: frozenset[str] = frozenset({'__namespaces__', '__import_aliases__', '__t_type_symbols__'}) - - for name, attrs in symbols.items(): - if name in _SPECIAL_KEYS: - continue - if isinstance(attrs, dict): - info: CTypeInfo = self._CTypeInfoFromDict(name, attrs) - self._symbols[name] = info - elif isinstance(attrs, CTypeInfo): - self._symbols[name] = attrs - - # 恢复命名空间信息 - ns_data: dict[str, list[str]] | None = symbols.get('__namespaces__') - if ns_data: - for ns, sym_names in ns_data.items(): - self._namespaces[ns] = {} - for sym_name in sym_names: - if sym_name in self._symbols: - self._namespaces[ns][sym_name] = self._symbols[sym_name] - aliases_data: dict[str, str] | None = symbols.get('__import_aliases__') - if aliases_data: - self.import_aliases.update(aliases_data) - - # 恢复 t 类型别名 - t_type_data: dict[str, str] | None = symbols.get('__t_type_symbols__') - if t_type_data: - for name, cls_name in t_type_data.items(): - cls: type | None = getattr(t, cls_name, None) - if cls and isinstance(cls, type) and issubclass(cls, t.CType): - self._t_type_symbols[name] = cls - - def _CTypeInfoFromDict(self, name: str, attrs: dict[str, Any]) -> CTypeInfo: - """从旧 dict 格式创建 CTypeInfo(兼容旧代码)""" - info: CTypeInfo = CTypeInfo() - info.Name = name - node_type: str = attrs.get('type', '') - - if node_type == 'struct' or attrs.get('IsStruct'): - info.IsStruct = True - elif node_type == 'enum' or attrs.get('IsEnum'): - info.IsEnum = True - elif node_type == 'union' or attrs.get('IsUnion'): - info.IsUnion = True - elif node_type == 'typedef' or attrs.get('IsTypedef'): - info.IsTypedef = True - elif node_type == 'function' or attrs.get('IsFunction'): - info.IsFunction = True - elif node_type == 'variable' or attrs.get('IsVariable'): - info.IsVariable = True - elif node_type == 'define' or attrs.get('IsDefine'): - info.IsDefine = True - elif node_type == 'enum_member' or attrs.get('IsEnumMember'): - info.IsEnumMember = True - - if 'PtrCount' in attrs: - info.PtrCount = attrs['PtrCount'] - if 'OriginalType' in attrs: - info.OriginalType = attrs['OriginalType'] - if 'lineno' in attrs: - info.Lineno = attrs['lineno'] - if 'file' in attrs: - info.file = attrs['file'] - if 'members' in attrs: - info.Members = attrs['members'] - if 'IsPtr' in attrs: - info.IsPtr = attrs['IsPtr'] - if 'dims' in attrs: - info.ArrayDims = attrs['dims'] - if 'IsCpythonObject' in attrs: - info.IsCpythonObject = attrs['IsCpythonObject'] - if 'IsAnonymous' in attrs: - info.IsAnonymous = attrs['IsAnonymous'] - if 'IsPacked' in attrs: - info.IsPacked = attrs['IsPacked'] - if 'EnumName' in attrs: - info.EnumName = attrs['EnumName'] - if 'DefineValue' in attrs: - info.DefineValue = attrs['DefineValue'] - if 'BaseType' in attrs: - info.BaseType = self._DeserializeBaseType(attrs['BaseType']) - if 'name' in attrs and attrs['name'] != name: - info.Name = attrs['name'] - - # 其他属性存入 _extra - skip_keys: frozenset[str] = frozenset({'type', 'name', 'PtrCount', 'OriginalType', 'lineno', 'file', - 'members', 'IsPtr', 'dims', 'IsCpythonObject', 'IsAnonymous', - 'IsPacked', 'EnumName', 'DefineValue', 'BaseType', - 'IsStruct', 'IsEnum', 'IsUnion', 'IsTypedef', - 'IsFunction', 'IsVariable', 'IsDefine', 'IsEnumMember'}) - for key, value in attrs.items(): - if key not in skip_keys: - info.set(key, value) - - return info - - # ================================================================== - # 模块符号加载:四阶段管线 - # ================================================================== - - def LoadModuleSymbols(self, FullModulePath: str, asname: str, lineno: int = 0) -> list[str]: - return self._LoadSymbolsFromFile(FullModulePath, asname, lineno) - - def _LoadSymbolsFromFile(self, FilePath: str, namespace_prefix: str | list[str], lineno: int = 0) -> list[str]: - try: - # 提取模块名作为命名空间 - module_name: str = namespace_prefix[0] if isinstance(namespace_prefix, list) else namespace_prefix - - # Pass 1: 从 AST 提取原始符号信息 - extractor: ASTSymbolExtractor = ASTSymbolExtractor(self) - module_symbols: ModuleSymbols = extractor.extract(FilePath) - - # Pass 2: 解析类型信息(typedef、函数签名、define 值) - resolver: TypeResolver = TypeResolver(self) - resolver.resolve(module_symbols) - - # Pass 3: 插入符号到主命名空间(无前缀) - inserter: SymbolInserter = SymbolInserter(self) - inserter.set_namespace(module_name) - loaded: list[str] = inserter.insert(module_symbols) - - # Pass 4: 重新导出到命名空间前缀下 - prefixes: list[str] = [namespace_prefix] if isinstance(namespace_prefix, str) else namespace_prefix - reexporter: PackageReexporter = PackageReexporter(self) - reexporter.set_namespace(module_name) - loaded.extend(reexporter.reexport(module_symbols, prefixes, lineno)) - - return loaded - - except Exception as e: - _vlog().error(traceback.format_exc()) - self.diagnostics.error(FilePath, lineno, f"加载模块失败: {e}") - return [] - - # ================================================================== - # 类型解析辅助方法(委托到 LLVMTypeMapper) - # ================================================================== - - @staticmethod - def _CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool: - return _CheckAnnotationHasCInline(annotation_node) - - # ================================================================== - # 符号插入方法(供 SymbolInserter / PackageReexporter 调用) - # ================================================================== - - def _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict[str, CTypeInfo], IsCpythonObject: bool, IsPacked: bool = False) -> None: - info: CTypeInfo = CTypeInfo() - info.Lineno = lineno - info.file = FilePath - info.Members = members if members else {} - - if TypeKind == 'struct': - info.IsStruct = True - elif TypeKind == 'union': - info.IsUnion = True - elif TypeKind == 'enum': - info.IsEnum = True - elif TypeKind == 'renum': - info.IsStruct = True - info.IsRenum = True - info.IsEnum = True - elif TypeKind == 'exception': - info.IsStruct = True - info.IsExceptionClass = True - - if IsCpythonObject: - info.IsCpythonObject = True - if IsPacked: - info.IsPacked = True - - self._symbols[FullName] = info - - def _InsertEnumMemberSymbol(self, FullName: str, EnumName: str, lineno: int, FilePath: str, value: int | None = None) -> None: - info: CTypeInfo = CTypeInfo() - info.IsEnumMember = True - info.EnumName = EnumName - info.Lineno = lineno - info.file = FilePath - if value is not None: - info.value = value - self._symbols[FullName] = info - - def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass: CTypeInfo | str | None, lineno: int, FilePath: str, members: dict[str, CTypeInfo] | None = None) -> None: - info: CTypeInfo = CTypeInfo() - info.IsTypedef = True - info.Name = FullName - info.Lineno = lineno - info.file = FilePath - if members: - info.Members = members - - if isinstance(OriginalClass, CTypeInfo): - info.OriginalType = OriginalClass - elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass): - OriginalType: str = OriginalClass - if OriginalType == 'CVoid *': - OriginalType = 'void *' - info.OriginalType = OriginalType - elif OriginalType_kind == 'typedef' and OriginalClass == 'void': - info.OriginalType = 'void *' - elif OriginalType_kind == 'typedef' and OriginalClass: - info.OriginalType = OriginalClass - elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str): - info.OriginalType = f'{OriginalType_kind} {OriginalClass}' - else: - info.OriginalType = OriginalClass - - self._symbols[FullName] = info - - def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str) -> None: - info: CTypeInfo = CTypeInfo() - info.IsModuleAlias = True - info.Lineno = lineno - info.file = FilePath - self._symbols[name] = info - - def _InsertFuncSymbol(self, FullName: str, RetType: str | CTypeInfo | None, ParamTypes: list[str], lineno: int, FilePath: str, IsVariadic: bool = False, IsInline: bool = False) -> None: - info: CTypeInfo = CTypeInfo() - info.IsFunction = True - if isinstance(RetType, str): - info.FuncPtrReturn = CTypeInfo.FromTypeName(RetType) if RetType else CTypeInfo.VoidTypeInfo() - elif isinstance(RetType, CTypeInfo): - info.FuncPtrReturn = RetType - else: - info.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - info.FuncPtrParams = [(f'arg{i}', pt) for i, pt in enumerate(ParamTypes)] - info.IsVariadic = IsVariadic - info.IsInline = IsInline - if IsInline: - info.Storage = t.CInline() - info.Lineno = lineno - info.file = FilePath - self._symbols[FullName] = info - - def _InsertDefineSymbol(self, FullName: str, DefineValue: int | str | float | bool | None, lineno: int, FilePath: str) -> None: - info: CTypeInfo = CTypeInfo() - info.IsDefine = True - info.DefineValue = DefineValue - info.Lineno = lineno - info.file = FilePath - self._symbols[FullName] = info - - def _eval_const_expr(self, node: ast.AST) -> int | float | str | None: - """计算常量表达式的值(委托到 ConstEvaluator)""" - return ConstEvaluator.eval_with_symtab(node, self) - - def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict[str, CTypeInfo], lineno: int, FilePath: str) -> None: - info: CTypeInfo = CTypeInfo() - if IsUnion: - info.IsUnion = True - else: - info.IsStruct = True - info.IsAnonymous = True - info.Members = members if members else {} - info.Lineno = lineno - info.file = FilePath - self._symbols[FullName] = info +from __future__ import annotations +from typing import TYPE_CHECKING, Any, Iterator +if TYPE_CHECKING: + from lib.core.translator import Translator + +import vast as ast +import traceback + +from lib.core.Handles.HandlesBase import CTypeInfo +from lib.includes import t +from lib.core.VLogger import get_logger as _vlog +from lib.core.DiagnosticCollector import DiagnosticCollector +from lib.core.LLVMTypeMapper import LLVMTypeMapper +from lib.core.SymbolExtractor import ASTSymbolExtractor +from lib.core.SymbolTypeResolver import TypeResolver +from lib.core.SymbolInserter import SymbolInserter +from lib.core.SymbolReexporter import PackageReexporter +from lib.core.ConstEvaluator import ConstEvaluator +from lib.core.SymbolData import ModuleSymbols + +# 从 SymbolUtils 重导出,保持向后兼容 +from lib.core.SymbolUtils import CheckAnnotationHasCInline as _CheckAnnotationHasCInline + + +class SymbolTable: + def __init__(self, translator: Translator) -> None: + self.translator: Translator = translator + self._symbols: dict[str, CTypeInfo] = {} + self._namespaces: dict[str, dict[str, CTypeInfo]] = {} # 模块名 -> 符号字典 + self._t_type_symbols: dict[str, type] = {} # 别名 -> t.CType 子类 (from t import CEnum as en) + self.diagnostics: DiagnosticCollector = DiagnosticCollector() + self._type_mapper: LLVMTypeMapper = LLVMTypeMapper(self) + self.import_aliases: dict[str, str] = {} # 别名 -> 模块路径 + + def __getstate__(self) -> dict: + """pickle 序列化:排除不可序列化的字段(translator/_type_mapper/diagnostics)""" + state: dict = self.__dict__.copy() + state.pop('translator', None) + state.pop('_type_mapper', None) + state.pop('diagnostics', None) + return state + + def __setstate__(self, state: dict) -> None: + """pickle 反序列化:重建可序列化的字段,translator 由调用方后续设置""" + self.__dict__.update(state) + self.translator = None # 由调用方赋值 + self.diagnostics = DiagnosticCollector() + self._type_mapper = LLVMTypeMapper(self) + + def clear(self) -> None: + self._symbols.clear() + self._namespaces.clear() + self._t_type_symbols.clear() + self.import_aliases.clear() + + def get(self, name: str, default: CTypeInfo | None = None) -> CTypeInfo | None: + return self._symbols.get(name, default) + + def set(self, name: str, value: CTypeInfo | dict[str, Any]) -> None: + if isinstance(value, CTypeInfo): + self._symbols[name] = value + else: + # 兼容旧代码传入 dict 的情况 + info: CTypeInfo = self._CTypeInfoFromDict(name, value) + self._symbols[name] = info + + def update(self, symbols: dict[str, CTypeInfo | dict[str, Any]]) -> None: + for name, value in symbols.items(): + self.set(name, value) + + def keys(self) -> Iterator[str]: + return iter(self._symbols.keys()) + + def values(self) -> Iterator[CTypeInfo]: + return iter(self._symbols.values()) + + def items(self) -> Iterator[tuple[str, CTypeInfo]]: + return iter(self._symbols.items()) + + def pop(self, name: str, *args: Any) -> CTypeInfo: + return self._symbols.pop(name, *args) + + def __getitem__(self, name: str) -> CTypeInfo: + if name in self._symbols: + return self._symbols[name] + raise KeyError(name) + + def __setitem__(self, name: str, value: CTypeInfo | dict[str, Any]) -> None: + self.set(name, value) + + def __delitem__(self, name: str) -> None: + del self._symbols[name] + + def __contains__(self, name: str) -> bool: + return name in self._symbols + + def __len__(self) -> int: + return len(self._symbols) + + def __iter__(self) -> Iterator[str]: + return iter(self._symbols) + + # ================================================================== + # 服务接口 — 语义化的符号查询与操作方法 + # ================================================================== + + def lookup(self, name: str) -> CTypeInfo | None: + """查找符号,支持别名解析和 dotted name + + 解析顺序: + 1. 直接匹配 _symbols + 2. 如果包含 '.',解析第一个段为别名后查找剩余路径 + 3. 查 _t_type_symbols(t/c 类型别名,返回模拟 CTypeInfo) + """ + if name in self._symbols: + return self._symbols[name] + + if '.' not in name: + return self._lookup_t_type(name) + + # dotted name: 尝试解析第一个段为别名 + parts: list[str] = name.split('.', 1) + first: str = parts[0] + rest: str = parts[1] + + # 1) 别名解析:import X as Y → Y.Symbol → X.Symbol + resolved: str | None = self.import_aliases.get(first) + if resolved: + alias_name: str = f"{resolved}.{rest}" + if alias_name in self._symbols: + return self._symbols[alias_name] + + # 2) 纯路径查找:module.ClassName + # (已在 line 100 检查过,此处为兜底,保留注释说明路径查找语义) + + return None + + def _lookup_t_type(self, name: str) -> CTypeInfo | None: + """在 _t_type_symbols 中查找 t/c 类型别名,返回模拟 CTypeInfo""" + cls: type | None = self._t_type_symbols.get(name) + if cls is None: + return None + info: CTypeInfo = CTypeInfo() + info.Name = name + info.BaseType = cls() + if issubclass(cls, (t.CEnum, t.REnum)): + info.IsEnum = True + elif issubclass(cls, t.CUnion): + info.IsUnion = True + elif issubclass(cls, t.CStruct): + info.IsStruct = True + return info + + def register_namespace(self, module_name: str) -> None: + """注册一个模块命名空间""" + if module_name not in self._namespaces: + self._namespaces[module_name] = {} + + def has(self, name: str) -> bool: + """检查符号是否存在(替代 `name in SymbolTable`)""" + return name in self._symbols + + def is_struct(self, name: str) -> bool: + """检查名称是否为结构体""" + entry: CTypeInfo | None = self._symbols.get(name) + return entry is not None and (entry.IsStruct or entry.IsCpythonObject) + + def is_define(self, name: str) -> bool: + """检查名称是否为常量定义""" + entry: CTypeInfo | None = self._symbols.get(name) + return entry is not None and entry.IsDefine + + def insert(self, name: str, info: CTypeInfo) -> None: + """插入符号(替代 `SymbolTable[name] = info`)""" + self._symbols[name] = info + + def resolve_alias(self, module_path: str) -> str: + """解析 import 别名,无别名返回原路径""" + return self.import_aliases.get(module_path, module_path) + + def ToDict(self) -> dict[str, Any]: + """序列化为字典格式,BaseType 使用可重建的 dict 格式 + + 返回的 dict 包含: + - 符号条目:{name: {attrs}}(与旧格式兼容) + - '__namespaces__': {namespace: [symbol_names]} 命名空间索引 + - '__import_aliases__': {alias: module_path} 导入别名 + """ + result: dict[str, Any] = {} + for name, info in self._symbols.items(): + entry: dict[str, Any] = {'name': name} + if info.BaseType: + entry['BaseType'] = self._SerializeBaseType(info.BaseType) + if info.PtrCount: + entry['PtrCount'] = info.PtrCount + if info.IsTypedef: + entry['IsTypedef'] = True + if info.IsStruct: + entry['IsStruct'] = True + if info.IsEnum: + entry['IsEnum'] = True + if info.IsUnion: + entry['IsUnion'] = True + if info.IsFunction: + entry['IsFunction'] = True + if info.IsVariable: + entry['IsVariable'] = True + if info.IsDefine: + entry['IsDefine'] = True + if info.OriginalType: + entry['OriginalType'] = str(info.OriginalType) + if info.Lineno: + entry['lineno'] = info.Lineno + if info.file: + entry['file'] = info.file + if info.Members: + entry['members'] = info.Members + extra: dict[str, Any] = info._sm._extra + if extra: + entry.update(extra) + result[name] = entry + + # 序列化命名空间信息 + if self._namespaces: + result['__namespaces__'] = { + ns: list(symbols.keys()) for ns, symbols in self._namespaces.items() + } + if self.import_aliases: + result['__import_aliases__'] = dict(self.import_aliases) + if self._t_type_symbols: + result['__t_type_symbols__'] = { + name: cls.__name__ for name, cls in self._t_type_symbols.items() + } + + return result + + @staticmethod + def _SerializeBaseType(base_type: t.CType | tuple | list | str | None) -> dict | str: + """将 BaseType 序列化为可重建的格式""" + if isinstance(base_type, t.CType): + return {'class': type(base_type).__name__} + if isinstance(base_type, (tuple, list)): + return {'classes': [type(b).__name__ for b in base_type if isinstance(b, t.CType)]} + return str(base_type) + + @staticmethod + def _DeserializeBaseType(data: Any) -> Any: + """从序列化格式恢复 BaseType""" + if isinstance(data, dict): + if 'class' in data: + cls: type | None = getattr(t, data['class'], None) + if cls and isinstance(cls, type) and issubclass(cls, t.CType): + return cls() + elif 'classes' in data: + types: list[t.CType] = [] + for cname in data['classes']: + cls: type | None = getattr(t, cname, None) + if cls and isinstance(cls, type) and issubclass(cls, t.CType): + types.append(cls()) + if types: + return tuple(types) + elif isinstance(data, str): + cls: type | None = getattr(t, data, None) + if cls and isinstance(cls, type) and issubclass(cls, t.CType): + return cls() + return None + + def FromDict(self, symbols: dict[str, Any]) -> None: + """从字典格式反序列化(兼容带/不带命名空间信息的两种格式)""" + self._symbols.clear() + self._namespaces.clear() + self.import_aliases.clear() + self._t_type_symbols.clear() + + _SPECIAL_KEYS: frozenset[str] = frozenset({'__namespaces__', '__import_aliases__', '__t_type_symbols__'}) + + for name, attrs in symbols.items(): + if name in _SPECIAL_KEYS: + continue + if isinstance(attrs, dict): + info: CTypeInfo = self._CTypeInfoFromDict(name, attrs) + self._symbols[name] = info + elif isinstance(attrs, CTypeInfo): + self._symbols[name] = attrs + + # 恢复命名空间信息 + ns_data: dict[str, list[str]] | None = symbols.get('__namespaces__') + if ns_data: + for ns, sym_names in ns_data.items(): + self._namespaces[ns] = {} + for sym_name in sym_names: + if sym_name in self._symbols: + self._namespaces[ns][sym_name] = self._symbols[sym_name] + aliases_data: dict[str, str] | None = symbols.get('__import_aliases__') + if aliases_data: + self.import_aliases.update(aliases_data) + + # 恢复 t 类型别名 + t_type_data: dict[str, str] | None = symbols.get('__t_type_symbols__') + if t_type_data: + for name, cls_name in t_type_data.items(): + cls: type | None = getattr(t, cls_name, None) + if cls and isinstance(cls, type) and issubclass(cls, t.CType): + self._t_type_symbols[name] = cls + + def _CTypeInfoFromDict(self, name: str, attrs: dict[str, Any]) -> CTypeInfo: + """从旧 dict 格式创建 CTypeInfo(兼容旧代码)""" + info: CTypeInfo = CTypeInfo() + info.Name = name + node_type: str = attrs.get('type', '') + + if node_type == 'struct' or attrs.get('IsStruct'): + info.IsStruct = True + elif node_type == 'enum' or attrs.get('IsEnum'): + info.IsEnum = True + elif node_type == 'union' or attrs.get('IsUnion'): + info.IsUnion = True + elif node_type == 'typedef' or attrs.get('IsTypedef'): + info.IsTypedef = True + elif node_type == 'function' or attrs.get('IsFunction'): + info.IsFunction = True + elif node_type == 'variable' or attrs.get('IsVariable'): + info.IsVariable = True + elif node_type == 'define' or attrs.get('IsDefine'): + info.IsDefine = True + elif node_type == 'enum_member' or attrs.get('IsEnumMember'): + info.IsEnumMember = True + + if 'PtrCount' in attrs: + info.PtrCount = attrs['PtrCount'] + if 'OriginalType' in attrs: + info.OriginalType = attrs['OriginalType'] + if 'lineno' in attrs: + info.Lineno = attrs['lineno'] + if 'file' in attrs: + info.file = attrs['file'] + if 'members' in attrs: + info.Members = attrs['members'] + if 'IsPtr' in attrs: + info.IsPtr = attrs['IsPtr'] + if 'dims' in attrs: + info.ArrayDims = attrs['dims'] + if 'IsCpythonObject' in attrs: + info.IsCpythonObject = attrs['IsCpythonObject'] + if 'IsAnonymous' in attrs: + info.IsAnonymous = attrs['IsAnonymous'] + if 'IsPacked' in attrs: + info.IsPacked = attrs['IsPacked'] + if 'EnumName' in attrs: + info.EnumName = attrs['EnumName'] + if 'DefineValue' in attrs: + info.DefineValue = attrs['DefineValue'] + if 'BaseType' in attrs: + info.BaseType = self._DeserializeBaseType(attrs['BaseType']) + if 'name' in attrs and attrs['name'] != name: + info.Name = attrs['name'] + + # 其他属性存入 _extra + skip_keys: frozenset[str] = frozenset({'type', 'name', 'PtrCount', 'OriginalType', 'lineno', 'file', + 'members', 'IsPtr', 'dims', 'IsCpythonObject', 'IsAnonymous', + 'IsPacked', 'EnumName', 'DefineValue', 'BaseType', + 'IsStruct', 'IsEnum', 'IsUnion', 'IsTypedef', + 'IsFunction', 'IsVariable', 'IsDefine', 'IsEnumMember'}) + for key, value in attrs.items(): + if key not in skip_keys: + info.set(key, value) + + return info + + # ================================================================== + # 模块符号加载:四阶段管线 + # ================================================================== + + def LoadModuleSymbols(self, FullModulePath: str, asname: str, lineno: int = 0) -> list[str]: + return self._LoadSymbolsFromFile(FullModulePath, asname, lineno) + + def _LoadSymbolsFromFile(self, FilePath: str, namespace_prefix: str | list[str], lineno: int = 0) -> list[str]: + try: + # 提取模块名作为命名空间 + module_name: str = namespace_prefix[0] if isinstance(namespace_prefix, list) else namespace_prefix + + # Pass 1: 从 AST 提取原始符号信息 + extractor: ASTSymbolExtractor = ASTSymbolExtractor(self) + module_symbols: ModuleSymbols = extractor.extract(FilePath) + + # Pass 2: 解析类型信息(typedef、函数签名、define 值) + resolver: TypeResolver = TypeResolver(self) + resolver.resolve(module_symbols) + + # Pass 3: 插入符号到主命名空间(无前缀) + inserter: SymbolInserter = SymbolInserter(self) + inserter.set_namespace(module_name) + loaded: list[str] = inserter.insert(module_symbols) + + # Pass 4: 重新导出到命名空间前缀下 + prefixes: list[str] = [namespace_prefix] if isinstance(namespace_prefix, str) else namespace_prefix + reexporter: PackageReexporter = PackageReexporter(self) + reexporter.set_namespace(module_name) + loaded.extend(reexporter.reexport(module_symbols, prefixes, lineno)) + + return loaded + + except Exception as e: + _vlog().error(traceback.format_exc()) + self.diagnostics.error(FilePath, lineno, f"加载模块失败: {e}") + return [] + + # ================================================================== + # 类型解析辅助方法(委托到 LLVMTypeMapper) + # ================================================================== + + @staticmethod + def _CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool: + return _CheckAnnotationHasCInline(annotation_node) + + # ================================================================== + # 符号插入方法(供 SymbolInserter / PackageReexporter 调用) + # ================================================================== + + def _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict[str, CTypeInfo], IsCpythonObject: bool, IsPacked: bool = False) -> None: + info: CTypeInfo = CTypeInfo() + info.Lineno = lineno + info.file = FilePath + info.Members = members if members else {} + + if TypeKind == 'struct': + info.IsStruct = True + elif TypeKind == 'union': + info.IsUnion = True + elif TypeKind == 'enum': + info.IsEnum = True + elif TypeKind == 'renum': + info.IsStruct = True + info.IsRenum = True + info.IsEnum = True + elif TypeKind == 'exception': + info.IsStruct = True + info.IsExceptionClass = True + + if IsCpythonObject: + info.IsCpythonObject = True + if IsPacked: + info.IsPacked = True + + self._symbols[FullName] = info + + def _InsertEnumMemberSymbol(self, FullName: str, EnumName: str, lineno: int, FilePath: str, value: int | None = None) -> None: + info: CTypeInfo = CTypeInfo() + info.IsEnumMember = True + info.EnumName = EnumName + info.Lineno = lineno + info.file = FilePath + if value is not None: + info.value = value + self._symbols[FullName] = info + + def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass: CTypeInfo | str | None, lineno: int, FilePath: str, members: dict[str, CTypeInfo] | None = None) -> None: + info: CTypeInfo = CTypeInfo() + info.IsTypedef = True + info.Name = FullName + info.Lineno = lineno + info.file = FilePath + if members: + info.Members = members + + if isinstance(OriginalClass, CTypeInfo): + info.OriginalType = OriginalClass + elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass): + OriginalType: str = OriginalClass + if OriginalType == 'CVoid *': + OriginalType = 'void *' + info.OriginalType = OriginalType + elif OriginalType_kind == 'typedef' and OriginalClass == 'void': + info.OriginalType = 'void *' + elif OriginalType_kind == 'typedef' and OriginalClass: + info.OriginalType = OriginalClass + elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str): + info.OriginalType = f'{OriginalType_kind} {OriginalClass}' + else: + info.OriginalType = OriginalClass + + self._symbols[FullName] = info + + def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str) -> None: + info: CTypeInfo = CTypeInfo() + info.IsModuleAlias = True + info.Lineno = lineno + info.file = FilePath + self._symbols[name] = info + + def _InsertFuncSymbol(self, FullName: str, RetType: str | CTypeInfo | None, ParamTypes: list[str], lineno: int, FilePath: str, IsVariadic: bool = False, IsInline: bool = False) -> None: + info: CTypeInfo = CTypeInfo() + info.IsFunction = True + if isinstance(RetType, str): + info.FuncPtrReturn = CTypeInfo.FromTypeName(RetType) if RetType else CTypeInfo.VoidTypeInfo() + elif isinstance(RetType, CTypeInfo): + info.FuncPtrReturn = RetType + else: + info.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + info.FuncPtrParams = [(f'arg{i}', pt) for i, pt in enumerate(ParamTypes)] + info.IsVariadic = IsVariadic + info.IsInline = IsInline + if IsInline: + info.Storage = t.CInline() + info.Lineno = lineno + info.file = FilePath + self._symbols[FullName] = info + + def _InsertDefineSymbol(self, FullName: str, DefineValue: int | str | float | bool | None, lineno: int, FilePath: str) -> None: + info: CTypeInfo = CTypeInfo() + info.IsDefine = True + info.DefineValue = DefineValue + info.Lineno = lineno + info.file = FilePath + self._symbols[FullName] = info + + def _eval_const_expr(self, node: ast.AST) -> int | float | str | None: + """计算常量表达式的值(委托到 ConstEvaluator)""" + return ConstEvaluator.eval_with_symtab(node, self) + + def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict[str, CTypeInfo], lineno: int, FilePath: str) -> None: + info: CTypeInfo = CTypeInfo() + if IsUnion: + info.IsUnion = True + else: + info.IsStruct = True + info.IsAnonymous = True + info.Members = members if members else {} + info.Lineno = lineno + info.file = FilePath + self._symbols[FullName] = info diff --git a/lib/core/SymbolTypeResolver.py b/lib/core/SymbolTypeResolver.py index deb567c..6ed87c1 100644 --- a/lib/core/SymbolTypeResolver.py +++ b/lib/core/SymbolTypeResolver.py @@ -1,272 +1,272 @@ -"""Pass 2: TypeResolver — 解析 typedef 类型、函数签名、define 值""" -from __future__ import annotations -import ast -from typing import TYPE_CHECKING -if TYPE_CHECKING: - from lib.core.SymbolTable import SymbolTable - -from lib.core.SymbolData import ( - ModuleSymbols, TypedefSymbolData, FuncSymbolData, DefineSymbolData -) -from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper -from lib.core.LLVMTypeMapper import LLVMTypeMapper -from lib.core.SymbolUtils import IsTModule -from lib.includes import t - - -class TypeResolver: - """解析从 AST 提取的原始符号中的类型信息""" - - def __init__(self, symbol_table: SymbolTable): - self._symtab = symbol_table - self._type_mapper = LLVMTypeMapper(symbol_table) - # 本模块内已解析的 typedef: name → original_class(供同模块 typedef 间引用解析) - self._resolved_typedefs: dict[str, str | None] = {} - - def resolve(self, module_symbols: ModuleSymbols) -> ModuleSymbols: - """解析所有类型信息,就地更新 ModuleSymbols""" - # 构建 class_members 查找表(typedef Postdefinition 需要) - class_members: dict[str, dict[str, CTypeInfo]] = {cls.name: cls.members for cls in module_symbols.classes} - - # 解析 typedef(按顺序记录,供后续 typedef 引用同模块已解析的 typedef) - td: TypedefSymbolData - for td in module_symbols.typedefs: - self._resolve_typedef(td, class_members) - self._resolved_typedefs[td.name] = td.original_class - - # 解析函数签名 - func: FuncSymbolData - for func in module_symbols.functions: - self._resolve_function(func) - - # 解析 define 值 - define: DefineSymbolData - for define in module_symbols.defines: - self._resolve_define(define) - - return module_symbols - - # ------------------------------------------------------------------ - # Typedef 解析 - # ------------------------------------------------------------------ - - def _resolve_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]): - """解析单个 typedef 的类型信息""" - is_postdef_with_typedef: bool = td.has_postdef and td.has_ctypedef - - if is_postdef_with_typedef: - self._resolve_postdef_typedef(td, class_members) - elif td.has_ctypedef: - self._resolve_ctypedef_typedef(td) - else: - # 无特殊注解的 typedef - td.original_type_kind = None - td.original_class = None - - def _resolve_postdef_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]): - """解析 Postdefinition + CTypedef 组合注解""" - original_class: str | None = self._find_postdef_arg(td.annotation) - if original_class and original_class in class_members: - members_info: dict[str, CTypeInfo] = class_members[original_class] - original_type_kind: str = 'struct' - if original_class in self._symtab: - orig_type_info: CTypeInfo = self._symtab[original_class] - if orig_type_info.type_cls in (t.CStruct, t.CEnum, t.CUnion): - if orig_type_info.type_cls is t.CStruct: - original_type_kind = 'struct' - elif orig_type_info.type_cls is t.CEnum: - original_type_kind = 'enum' - elif orig_type_info.type_cls is t.CUnion: - original_type_kind = 'union' - td.original_type_kind = original_type_kind - td.original_class = original_class - td.members = members_info - else: - td.original_type_kind = None - td.original_class = None - - 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'}) - - if base_type_name == 'Callable': - original_type: CTypeInfo = CTypeInfo() - original_type.IsFuncPtr = True - original_type.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - original_type.FuncPtrParams = [] - td.original_type_kind = 'typedef' - td.original_class = original_type - elif base_type_name and base_type_name not in _TYPE_QUALIFIERS: - cname: str | None = CTypeHelper.GetCName(base_type_name) - if cname: - td.original_class = cname - else: - td.original_class = base_type_name - td.original_type_kind = 'typedef' - else: - # 尝试从值表达式解析 - self._resolve_typedef_from_value(td) - - def _resolve_typedef_from_value(self, td: TypedefSymbolData): - """从值表达式解析 typedef 类型 - - BinOp(如 UINT | t.CPtr)优先于 _find_base_type 处理, - 因为 _find_base_type 是静态方法无法解析 Name 引用(如 UINT)。 - """ - if not td.value: - td.original_type_kind = None - td.original_class = None - return - - # 优先处理 BinOp(_find_base_type 无法解析 Name 引用) - if isinstance(td.value, ast.BinOp) and isinstance(td.value.op, ast.BitOr): - left_type: str = self._resolve_type_expr(td.value.left) - right_type: str = self._resolve_type_expr(td.value.right) - is_ptr_type: bool = right_type == 'ptr' or left_type == 'ptr' - if is_ptr_type: - base_name: str = left_type if left_type != 'ptr' else (right_type if right_type != 'ptr' else '') - original_type: str = (base_name + ' *') if base_name else 'void *' - td.original_class = original_type - td.original_type_kind = 'typedef' - elif left_type: - td.original_class = left_type - td.original_type_kind = 'typedef' - elif right_type: - td.original_class = right_type - td.original_type_kind = 'typedef' - else: - td.original_type_kind = None - td.original_class = None - return - - # 非 BinOp:使用 _find_base_type - value_base_type: str | None = self._find_base_type(td.value) - _PTR_MODIFIERS: frozenset[str] = frozenset({'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'}) - - if value_base_type and value_base_type not in _PTR_MODIFIERS: - cname: str | None = CTypeHelper.GetCName(value_base_type) - if cname: - td.original_class = cname - else: - td.original_class = value_base_type - td.original_type_kind = 'typedef' - return - - if isinstance(td.value, ast.Name): - ref_name: str = td.value.id - # 先查本模块已解析的 typedef - if ref_name in self._resolved_typedefs: - ref_class: str | None = self._resolved_typedefs[ref_name] - if ref_class: - td.original_class = ref_class - td.original_type_kind = 'typedef' - return - # 再查 symtab(跨模块) - if ref_name in self._symtab: - ref_info: CTypeInfo = self._symtab[ref_name] - if ref_info and ref_info.IsTypedef and ref_info.OriginalType: - td.original_class = ref_info.OriginalType - td.original_type_kind = 'typedef' - return - - td.original_type_kind = None - td.original_class = None - - def _resolve_type_expr(self, node: ast.AST) -> str: - """解析类型表达式为 C 类型名字符串,优先查本模块已解析的 typedef - - 解决同模块 typedef 间引用(如 UINTPTR = UINT | t.CPtr 中的 UINT) - 在 TypeResolver 阶段尚未插入 symtab 的问题。 - """ - if isinstance(node, ast.Name): - if node.id in self._resolved_typedefs: - return self._resolved_typedefs[node.id] or '' - return self._type_mapper.resolve_typedef_value_type(node) - - # ------------------------------------------------------------------ - # 函数签名解析 - # ------------------------------------------------------------------ - - def _resolve_function(self, func: FuncSymbolData): - """解析函数的返回类型和参数类型""" - func.ret_type = self._type_mapper.get_func_ret_type_str(func.returns_node) - # 同时解析为 CTypeInfo,保留符号性(LLVM 类型字符串 'i64' 不区分有无符号) - if func.returns_node is not None: - try: - func.ret_ctype = CTypeInfo.FromNode(func.returns_node, self._symtab) - except Exception: - func.ret_ctype = None - func.param_types = [] - _arg_name: str - annotation: ast.expr | None - for _arg_name, annotation in func.params: - if annotation: - func.param_types.append(self._type_mapper.get_func_param_type_str(annotation)) - else: - func.param_types.append('i8*') - - # ------------------------------------------------------------------ - # Define 值解析 - # ------------------------------------------------------------------ - - def _resolve_define(self, define: DefineSymbolData): - """解析 define 常量值""" - if define.value_node: - define.value = self._symtab._eval_const_expr(define.value_node) - - # ------------------------------------------------------------------ - # 静态工具方法(原 _LoadSymbolsFromFile 中的闭包) - # ------------------------------------------------------------------ - - @staticmethod - def _find_base_type(node: ast.AST | None) -> str | None: - """从注解 AST 节点中查找基础类型名称""" - if isinstance(node, ast.Attribute): - if hasattr(node.value, 'id') and IsTModule(node.value.id): - if node.attr == 'CPtr': - return 'ptr' - return node.attr - elif isinstance(node, ast.Subscript): - if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and IsTModule(node.value.value.id) and node.value.attr == 'Callable': - return 'Callable' - elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - left_result: str | None = TypeResolver._find_base_type(node.left) - if left_result == 'ptr': - right_result: str | None = TypeResolver._find_base_type(node.right) - return (right_result if right_result and right_result != 'ptr' else 'void') + ' *' - if left_result == 'Callable': - return 'Callable' - right_result: str | None = TypeResolver._find_base_type(node.right) - if right_result == 'ptr': - return (left_result if left_result and left_result != 'ptr' else 'void') + ' *' - if right_result == 'Callable': - return 'Callable' - # 类型拼接语义:CLong | CLong → CLongLong, CUnsignedLong | CLong → CUnsignedLongLong - long_types: frozenset[str] = frozenset({'CLong', 'CUnsignedLong'}) - if left_result in long_types and right_result in long_types: - if left_result == 'CUnsignedLong' or right_result == 'CUnsignedLong': - return 'CUnsignedLongLong' - return 'CLongLong' - if left_result: - return left_result - if right_result: - return right_result - return None - - @staticmethod - def _find_postdef_arg(node: ast.AST | None) -> str | None: - """从注解 AST 节点中查找 Postdefinition 参数""" - if isinstance(node, ast.Call): - if isinstance(node.func, ast.Attribute): - if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id) and node.func.attr == 'Postdefinition': - if node.args and isinstance(node.args[0], ast.Name): - return node.args[0].id - elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): - left_result: str | None = TypeResolver._find_postdef_arg(node.left) - if left_result: - return left_result - right_result: str | None = TypeResolver._find_postdef_arg(node.right) - if right_result: - return right_result - return None +"""Pass 2: TypeResolver — 解析 typedef 类型、函数签名、define 值""" +from __future__ import annotations +import vast as ast +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from lib.core.SymbolTable import SymbolTable + +from lib.core.SymbolData import ( + ModuleSymbols, TypedefSymbolData, FuncSymbolData, DefineSymbolData +) +from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper +from lib.core.LLVMTypeMapper import LLVMTypeMapper +from lib.core.SymbolUtils import IsTModule +from lib.includes import t + + +class TypeResolver: + """解析从 AST 提取的原始符号中的类型信息""" + + def __init__(self, symbol_table: SymbolTable): + self._symtab = symbol_table + self._type_mapper = LLVMTypeMapper(symbol_table) + # 本模块内已解析的 typedef: name → original_class(供同模块 typedef 间引用解析) + self._resolved_typedefs: dict[str, str | None] = {} + + def resolve(self, module_symbols: ModuleSymbols) -> ModuleSymbols: + """解析所有类型信息,就地更新 ModuleSymbols""" + # 构建 class_members 查找表(typedef Postdefinition 需要) + class_members: dict[str, dict[str, CTypeInfo]] = {cls.name: cls.members for cls in module_symbols.classes} + + # 解析 typedef(按顺序记录,供后续 typedef 引用同模块已解析的 typedef) + td: TypedefSymbolData + for td in module_symbols.typedefs: + self._resolve_typedef(td, class_members) + self._resolved_typedefs[td.name] = td.original_class + + # 解析函数签名 + func: FuncSymbolData + for func in module_symbols.functions: + self._resolve_function(func) + + # 解析 define 值 + define: DefineSymbolData + for define in module_symbols.defines: + self._resolve_define(define) + + return module_symbols + + # ------------------------------------------------------------------ + # Typedef 解析 + # ------------------------------------------------------------------ + + def _resolve_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]): + """解析单个 typedef 的类型信息""" + is_postdef_with_typedef: bool = td.has_postdef and td.has_ctypedef + + if is_postdef_with_typedef: + self._resolve_postdef_typedef(td, class_members) + elif td.has_ctypedef: + self._resolve_ctypedef_typedef(td) + else: + # 无特殊注解的 typedef + td.original_type_kind = None + td.original_class = None + + def _resolve_postdef_typedef(self, td: TypedefSymbolData, class_members: dict[str, dict[str, CTypeInfo]]): + """解析 Postdefinition + CTypedef 组合注解""" + original_class: str | None = self._find_postdef_arg(td.annotation) + if original_class and original_class in class_members: + members_info: dict[str, CTypeInfo] = class_members[original_class] + original_type_kind: str = 'struct' + if original_class in self._symtab: + orig_type_info: CTypeInfo = self._symtab[original_class] + if orig_type_info.type_cls in (t.CStruct, t.CEnum, t.CUnion): + if orig_type_info.type_cls is t.CStruct: + original_type_kind = 'struct' + elif orig_type_info.type_cls is t.CEnum: + original_type_kind = 'enum' + elif orig_type_info.type_cls is t.CUnion: + original_type_kind = 'union' + td.original_type_kind = original_type_kind + td.original_class = original_class + td.members = members_info + else: + td.original_type_kind = None + td.original_class = None + + 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'}) + + if base_type_name == 'Callable': + original_type: CTypeInfo = CTypeInfo() + original_type.IsFuncPtr = True + original_type.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + original_type.FuncPtrParams = [] + td.original_type_kind = 'typedef' + td.original_class = original_type + elif base_type_name and base_type_name not in _TYPE_QUALIFIERS: + cname: str | None = CTypeHelper.GetCName(base_type_name) + if cname: + td.original_class = cname + else: + td.original_class = base_type_name + td.original_type_kind = 'typedef' + else: + # 尝试从值表达式解析 + self._resolve_typedef_from_value(td) + + def _resolve_typedef_from_value(self, td: TypedefSymbolData): + """从值表达式解析 typedef 类型 + + BinOp(如 UINT | t.CPtr)优先于 _find_base_type 处理, + 因为 _find_base_type 是静态方法无法解析 Name 引用(如 UINT)。 + """ + if not td.value: + td.original_type_kind = None + td.original_class = None + return + + # 优先处理 BinOp(_find_base_type 无法解析 Name 引用) + if isinstance(td.value, ast.BinOp) and isinstance(td.value.op, ast.BitOr): + left_type: str = self._resolve_type_expr(td.value.left) + right_type: str = self._resolve_type_expr(td.value.right) + is_ptr_type: bool = right_type == 'ptr' or left_type == 'ptr' + if is_ptr_type: + base_name: str = left_type if left_type != 'ptr' else (right_type if right_type != 'ptr' else '') + original_type: str = (base_name + ' *') if base_name else 'void *' + td.original_class = original_type + td.original_type_kind = 'typedef' + elif left_type: + td.original_class = left_type + td.original_type_kind = 'typedef' + elif right_type: + td.original_class = right_type + td.original_type_kind = 'typedef' + else: + td.original_type_kind = None + td.original_class = None + return + + # 非 BinOp:使用 _find_base_type + value_base_type: str | None = self._find_base_type(td.value) + _PTR_MODIFIERS: frozenset[str] = frozenset({'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'}) + + if value_base_type and value_base_type not in _PTR_MODIFIERS: + cname: str | None = CTypeHelper.GetCName(value_base_type) + if cname: + td.original_class = cname + else: + td.original_class = value_base_type + td.original_type_kind = 'typedef' + return + + if isinstance(td.value, ast.Name): + ref_name: str = td.value.id + # 先查本模块已解析的 typedef + if ref_name in self._resolved_typedefs: + ref_class: str | None = self._resolved_typedefs[ref_name] + if ref_class: + td.original_class = ref_class + td.original_type_kind = 'typedef' + return + # 再查 symtab(跨模块) + if ref_name in self._symtab: + ref_info: CTypeInfo = self._symtab[ref_name] + if ref_info and ref_info.IsTypedef and ref_info.OriginalType: + td.original_class = ref_info.OriginalType + td.original_type_kind = 'typedef' + return + + td.original_type_kind = None + td.original_class = None + + def _resolve_type_expr(self, node: ast.AST) -> str: + """解析类型表达式为 C 类型名字符串,优先查本模块已解析的 typedef + + 解决同模块 typedef 间引用(如 UINTPTR = UINT | t.CPtr 中的 UINT) + 在 TypeResolver 阶段尚未插入 symtab 的问题。 + """ + if isinstance(node, ast.Name): + if node.id in self._resolved_typedefs: + return self._resolved_typedefs[node.id] or '' + return self._type_mapper.resolve_typedef_value_type(node) + + # ------------------------------------------------------------------ + # 函数签名解析 + # ------------------------------------------------------------------ + + def _resolve_function(self, func: FuncSymbolData): + """解析函数的返回类型和参数类型""" + func.ret_type = self._type_mapper.get_func_ret_type_str(func.returns_node) + # 同时解析为 CTypeInfo,保留符号性(LLVM 类型字符串 'i64' 不区分有无符号) + if func.returns_node is not None: + try: + func.ret_ctype = CTypeInfo.FromNode(func.returns_node, self._symtab) + except Exception: + func.ret_ctype = None + func.param_types = [] + _arg_name: str + annotation: ast.expr | None + for _arg_name, annotation in func.params: + if annotation: + func.param_types.append(self._type_mapper.get_func_param_type_str(annotation)) + else: + func.param_types.append('i8*') + + # ------------------------------------------------------------------ + # Define 值解析 + # ------------------------------------------------------------------ + + def _resolve_define(self, define: DefineSymbolData): + """解析 define 常量值""" + if define.value_node: + define.value = self._symtab._eval_const_expr(define.value_node) + + # ------------------------------------------------------------------ + # 静态工具方法(原 _LoadSymbolsFromFile 中的闭包) + # ------------------------------------------------------------------ + + @staticmethod + def _find_base_type(node: ast.AST | None) -> str | None: + """从注解 AST 节点中查找基础类型名称""" + if isinstance(node, ast.Attribute): + if hasattr(node.value, 'id') and IsTModule(node.value.id): + if node.attr == 'CPtr': + return 'ptr' + return node.attr + elif isinstance(node, ast.Subscript): + if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and IsTModule(node.value.value.id) and node.value.attr == 'Callable': + return 'Callable' + elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + left_result: str | None = TypeResolver._find_base_type(node.left) + if left_result == 'ptr': + right_result: str | None = TypeResolver._find_base_type(node.right) + return (right_result if right_result and right_result != 'ptr' else 'void') + ' *' + if left_result == 'Callable': + return 'Callable' + right_result: str | None = TypeResolver._find_base_type(node.right) + if right_result == 'ptr': + return (left_result if left_result and left_result != 'ptr' else 'void') + ' *' + if right_result == 'Callable': + return 'Callable' + # 类型拼接语义:CLong | CLong → CLongLong, CUnsignedLong | CLong → CUnsignedLongLong + long_types: frozenset[str] = frozenset({'CLong', 'CUnsignedLong'}) + if left_result in long_types and right_result in long_types: + if left_result == 'CUnsignedLong' or right_result == 'CUnsignedLong': + return 'CUnsignedLongLong' + return 'CLongLong' + if left_result: + return left_result + if right_result: + return right_result + return None + + @staticmethod + def _find_postdef_arg(node: ast.AST | None) -> str | None: + """从注解 AST 节点中查找 Postdefinition 参数""" + if isinstance(node, ast.Call): + if isinstance(node.func, ast.Attribute): + if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id) and node.func.attr == 'Postdefinition': + if node.args and isinstance(node.args[0], ast.Name): + return node.args[0].id + elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): + left_result: str | None = TypeResolver._find_postdef_arg(node.left) + if left_result: + return left_result + right_result: str | None = TypeResolver._find_postdef_arg(node.right) + if right_result: + return right_result + return None diff --git a/lib/core/SymbolUtils.py b/lib/core/SymbolUtils.py index 24a2d90..58370fc 100644 --- a/lib/core/SymbolUtils.py +++ b/lib/core/SymbolUtils.py @@ -1,233 +1,233 @@ -"""共享工具函数:符号表处理中使用的 AST 分析工具""" -from __future__ import annotations -import ast -import re -from lib.includes import t - -_T_MODULE_NAMES: frozenset[str] = frozenset({'t', t.__name__}) - -# Viper 软关键字 fn/fun/func/function 是 def 的别名(行首 + 空白 + 标识符才算函数定义, -# 变量名/调用/注解中的 fn 不受影响)。展开为 def 后行号不变,供 ast.parse 使用。 -_SOFT_KEYWORD_RE: re.Pattern[str] = re.compile( - r'^(\s*)(function|func|fun|fn)(\s+)(?=[A-Za-z_])', re.MULTILINE -) - - -def ExpandSoftKeywords(Code: str) -> str: - """将 Viper 软关键字 fn/fun/func/function 展开为 def(函数定义行)。 - - 仅在"行首缩进 + 关键字 + 空白 + 标识符"的函数定义形态匹配, - 变量名(fn = 5)、调用(fn(x))、注解(x: fn)与字符串内容不受影响。 - 展开为 def 与关键字等宽或更短,行号不变,AST 行号映射保持有效。 - """ - if not Code: - return Code - return _SOFT_KEYWORD_RE.sub(lambda m: f'{m.group(1)}def{m.group(3)}', Code) - - -def IsTModule(module_id: str, symtable: object | None = None) -> bool: - """检查模块标识符是否指向 t 类型模块(支持别名如 import t as tt)""" - if module_id in _T_MODULE_NAMES: - return True - if symtable is not None and hasattr(symtable, 'import_aliases'): - resolved: str = symtable.import_aliases.get(module_id, module_id) - if resolved in _T_MODULE_NAMES: - return True - return False - - -def IsTModulePath(module_path: str) -> bool: - """检查模块路径是否指向 t 类型模块""" - if module_path in _T_MODULE_NAMES: - return True - if module_path: - t_name: str - for t_name in _T_MODULE_NAMES: - if module_path == t_name or module_path.startswith(t_name + '.'): - return True - return False - - -def AnnotationContainsTType(node: ast.AST, TypeName: str) -> bool: - """检测 AST 节点中是否包含指定名称的 t 模块类型""" - if isinstance(node, ast.Attribute): - if (hasattr(node.value, 'id') and IsTModule(node.value.id) and - node.attr == TypeName): - return True - elif isinstance(node, ast.BinOp): - return AnnotationContainsTType(node.left, TypeName) or AnnotationContainsTType(node.right, TypeName) - elif isinstance(node, ast.Call): - if AnnotationContainsTType(node.func, TypeName): - return True - for arg in node.args: - if AnnotationContainsTType(arg, TypeName): - return True - elif isinstance(node, ast.Subscript): - if AnnotationContainsTType(node.value, TypeName): - return True - if AnnotationContainsTType(node.slice, TypeName): - return True - return False - - -def IsListAnnotation(annotation: ast.expr) -> bool: - """检查注解是否为栈上固定数组类型(t.CArray[...] 或 list[type, count])""" - if not isinstance(annotation, ast.Subscript): - return False - value = annotation.value - # t.CArray[...] - if (isinstance(value, ast.Attribute) - and isinstance(value.value, ast.Name) - and value.value.id == 't' - and value.attr == 'CArray'): - return True - # list[type, count] — 仅匹配双参数 Tuple 切片(固定数组), - # 单参数 list[type] 不匹配(走泛型类 list[T] 路径) - if (isinstance(value, ast.Name) - and value.id == 'list' - and isinstance(annotation.slice, ast.Tuple) - and len(annotation.slice.elts) == 2): - return True - return False - - -def ExtractListFromBinOp(annotation: ast.expr) -> ast.Subscript | None: - """从 BinOp(BitOr) 注解中提取 list[...] 部分,如 list[i32] | t.CPtr""" - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - for side in (annotation.left, annotation.right): - if IsListAnnotation(side): - return side - return None - - -class ListAnnotationParseResult: - """list[...] 注解解析结果。 - - is_pointer=True 表示单参数 list[type] → 指针模式; - is_pointer=False 表示 Tuple(2) 模式 list[type, count]。 - """ - __slots__ = ('elem_type_node', 'count_node', 'is_pointer') - - def __init__(self, elem_type_node: ast.expr, count_node: ast.expr | None, is_pointer: bool) -> None: - self.elem_type_node: ast.expr = elem_type_node - self.count_node: ast.expr | None = count_node - self.is_pointer: bool = is_pointer - - -def ParseListAnnotation(annotation: ast.expr) -> ListAnnotationParseResult | None: - """解析 list[...] 注解,统一处理 list[type, count] / list[type] / BinOp(BitOr) 形式。 - - 自动处理 BinOp(BitOr) 包裹(如 list[i32, N] | t.CPtr)。 - 返回 None 表示不是 list 注解。 - """ - list_node: ast.expr = annotation - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - extracted: ast.Subscript | None = ExtractListFromBinOp(annotation) - if extracted is None: - return None - list_node = extracted - if not IsListAnnotation(list_node): - return None - slice_node: ast.AST = list_node.slice - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: - return ListAnnotationParseResult(slice_node.elts[0], slice_node.elts[1], is_pointer=False) - # 单参数 list[type] → 指针模式 - return ListAnnotationParseResult(slice_node, None, is_pointer=True) - - -def CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool: - """检测注解节点中是否包含 CInline""" - if annotation_node is None: - return False - if isinstance(annotation_node, ast.Attribute): - if hasattr(annotation_node.value, 'id') and IsTModule(annotation_node.value.id) and annotation_node.attr == 'CInline': - return True - if isinstance(annotation_node, ast.Name): - if annotation_node.id == 'CInline': - return True - if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): - return CheckAnnotationHasCInline(annotation_node.left) or CheckAnnotationHasCInline(annotation_node.right) - return False - - -def ExtractTypeNameFromBinOp(annotation: ast.expr) -> str | None: - """从 BinOp(BitOr) 注解左侧提取类型名(如 TypeA | TypeB → TypeA)。 - - 返回 Name.id 或 Attribute.attr,非 BinOp 返回 None。 - """ - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - left: ast.expr = annotation.left - if isinstance(left, ast.Name): - return left.id - if isinstance(left, ast.Attribute): - return left.attr - return None - - -def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str | None: - """递归在注解中查找结构体名(支持 BinOp(BitOr) 递归)。 - - 检查 Name.id、Constant.str、Attribute.attr 是否在 struct_names 中。 - 支持泛型特化类型(如 GSList[Param]),构造特化名后检查是否在 struct_names 中。 - """ - if isinstance(node, ast.Name) and node.id in struct_names: - return node.id - if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in struct_names: - return node.value - if isinstance(node, ast.Attribute) and node.attr in struct_names: - return node.attr - if isinstance(node, ast.Subscript): - base_name: str | None = None - if isinstance(node.value, ast.Name): - base_name = node.value.id - elif isinstance(node.value, ast.Attribute): - base_name = node.value.attr - if base_name: - slice_node: ast.AST = node.slice - if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index): - slice_node = slice_node.value - type_args: list[str] = [] - if isinstance(slice_node, ast.Name): - type_args.append(slice_node.id) - elif isinstance(slice_node, ast.Attribute): - type_args.append(slice_node.attr) - elif isinstance(slice_node, ast.Tuple): - for elt in slice_node.elts: - if isinstance(elt, ast.Name): - type_args.append(elt.id) - elif isinstance(elt, ast.Attribute): - type_args.append(elt.attr) - if type_args: - spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args) - if spec_name in struct_names: - return spec_name - 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) - if result: - return result - return FindStructNameInAnnotation(node.right, struct_names) - return None - - -def AnnotationContainsName(annotation: ast.AST, name: str) -> bool: - """检查注解中是否包含指定名称(支持 BinOp(BitOr) 递归)。 - - 同时检查 Attribute.attr 和 Name.id,比 ast.dump 字符串匹配更精确。 - """ - if isinstance(annotation, ast.Attribute): - return annotation.attr == name - if isinstance(annotation, ast.Name): - return annotation.id == name - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - return AnnotationContainsName(annotation.left, name) or AnnotationContainsName(annotation.right, name) - return False - - -def IsCPtrNode(node: ast.AST) -> bool: - """检查节点是否为 t.CPtr 属性引用。""" - return (isinstance(node, ast.Attribute) - and isinstance(node.value, ast.Name) - and node.value.id == 't' - and node.attr == 'CPtr') +"""共享工具函数:符号表处理中使用的 AST 分析工具""" +from __future__ import annotations +import vast as ast +import re +from lib.includes import t + +_T_MODULE_NAMES: frozenset[str] = frozenset({'t', t.__name__}) + +# Viper 软关键字 fn/fun/func/function 是 def 的别名(行首 + 空白 + 标识符才算函数定义, +# 变量名/调用/注解中的 fn 不受影响)。展开为 def 后行号不变,供 ast.parse 使用。 +_SOFT_KEYWORD_RE: re.Pattern[str] = re.compile( + r'^(\s*)(function|func|fun|fn)(\s+)(?=[A-Za-z_])', re.MULTILINE +) + + +def ExpandSoftKeywords(Code: str) -> str: + """将 Viper 软关键字 fn/fun/func/function 展开为 def(函数定义行)。 + + 仅在"行首缩进 + 关键字 + 空白 + 标识符"的函数定义形态匹配, + 变量名(fn = 5)、调用(fn(x))、注解(x: fn)与字符串内容不受影响。 + 展开为 def 与关键字等宽或更短,行号不变,AST 行号映射保持有效。 + """ + if not Code: + return Code + return _SOFT_KEYWORD_RE.sub(lambda m: f'{m.group(1)}def{m.group(3)}', Code) + + +def IsTModule(module_id: str, symtable: object | None = None) -> bool: + """检查模块标识符是否指向 t 类型模块(支持别名如 import t as tt)""" + if module_id in _T_MODULE_NAMES: + return True + if symtable is not None and hasattr(symtable, 'import_aliases'): + resolved: str = symtable.import_aliases.get(module_id, module_id) + if resolved in _T_MODULE_NAMES: + return True + return False + + +def IsTModulePath(module_path: str) -> bool: + """检查模块路径是否指向 t 类型模块""" + if module_path in _T_MODULE_NAMES: + return True + if module_path: + t_name: str + for t_name in _T_MODULE_NAMES: + if module_path == t_name or module_path.startswith(t_name + '.'): + return True + return False + + +def AnnotationContainsTType(node: ast.AST, TypeName: str) -> bool: + """检测 AST 节点中是否包含指定名称的 t 模块类型""" + if isinstance(node, ast.Attribute): + if (hasattr(node.value, 'id') and IsTModule(node.value.id) and + node.attr == TypeName): + return True + elif isinstance(node, ast.BinOp): + return AnnotationContainsTType(node.left, TypeName) or AnnotationContainsTType(node.right, TypeName) + elif isinstance(node, ast.Call): + if AnnotationContainsTType(node.func, TypeName): + return True + for arg in node.args: + if AnnotationContainsTType(arg, TypeName): + return True + elif isinstance(node, ast.Subscript): + if AnnotationContainsTType(node.value, TypeName): + return True + if AnnotationContainsTType(node.slice, TypeName): + return True + return False + + +def IsListAnnotation(annotation: ast.expr) -> bool: + """检查注解是否为栈上固定数组类型(t.CArray[...] 或 list[type, count])""" + if not isinstance(annotation, ast.Subscript): + return False + value = annotation.value + # t.CArray[...] + if (isinstance(value, ast.Attribute) + and isinstance(value.value, ast.Name) + and value.value.id == 't' + and value.attr == 'CArray'): + return True + # list[type, count] — 仅匹配双参数 Tuple 切片(固定数组), + # 单参数 list[type] 不匹配(走泛型类 list[T] 路径) + if (isinstance(value, ast.Name) + and value.id == 'list' + and isinstance(annotation.slice, ast.Tuple) + and len(annotation.slice.elts) == 2): + return True + return False + + +def ExtractListFromBinOp(annotation: ast.expr) -> ast.Subscript | None: + """从 BinOp(BitOr) 注解中提取 list[...] 部分,如 list[i32] | t.CPtr""" + if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + for side in (annotation.left, annotation.right): + if IsListAnnotation(side): + return side + return None + + +class ListAnnotationParseResult: + """list[...] 注解解析结果。 + + is_pointer=True 表示单参数 list[type] → 指针模式; + is_pointer=False 表示 Tuple(2) 模式 list[type, count]。 + """ + __slots__ = ('elem_type_node', 'count_node', 'is_pointer') + + def __init__(self, elem_type_node: ast.expr, count_node: ast.expr | None, is_pointer: bool) -> None: + self.elem_type_node: ast.expr = elem_type_node + self.count_node: ast.expr | None = count_node + self.is_pointer: bool = is_pointer + + +def ParseListAnnotation(annotation: ast.expr) -> ListAnnotationParseResult | None: + """解析 list[...] 注解,统一处理 list[type, count] / list[type] / BinOp(BitOr) 形式。 + + 自动处理 BinOp(BitOr) 包裹(如 list[i32, N] | t.CPtr)。 + 返回 None 表示不是 list 注解。 + """ + list_node: ast.expr = annotation + if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + extracted: ast.Subscript | None = ExtractListFromBinOp(annotation) + if extracted is None: + return None + list_node = extracted + if not IsListAnnotation(list_node): + return None + slice_node: ast.AST = list_node.slice + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + return ListAnnotationParseResult(slice_node.elts[0], slice_node.elts[1], is_pointer=False) + # 单参数 list[type] → 指针模式 + return ListAnnotationParseResult(slice_node, None, is_pointer=True) + + +def CheckAnnotationHasCInline(annotation_node: ast.AST | None) -> bool: + """检测注解节点中是否包含 CInline""" + if annotation_node is None: + return False + if isinstance(annotation_node, ast.Attribute): + if hasattr(annotation_node.value, 'id') and IsTModule(annotation_node.value.id) and annotation_node.attr == 'CInline': + return True + if isinstance(annotation_node, ast.Name): + if annotation_node.id == 'CInline': + return True + if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr): + return CheckAnnotationHasCInline(annotation_node.left) or CheckAnnotationHasCInline(annotation_node.right) + return False + + +def ExtractTypeNameFromBinOp(annotation: ast.expr) -> str | None: + """从 BinOp(BitOr) 注解左侧提取类型名(如 TypeA | TypeB → TypeA)。 + + 返回 Name.id 或 Attribute.attr,非 BinOp 返回 None。 + """ + if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + left: ast.expr = annotation.left + if isinstance(left, ast.Name): + return left.id + if isinstance(left, ast.Attribute): + return left.attr + return None + + +def FindStructNameInAnnotation(node: ast.AST, struct_names: dict | set) -> str | None: + """递归在注解中查找结构体名(支持 BinOp(BitOr) 递归)。 + + 检查 Name.id、Constant.str、Attribute.attr 是否在 struct_names 中。 + 支持泛型特化类型(如 GSList[Param]),构造特化名后检查是否在 struct_names 中。 + """ + if isinstance(node, ast.Name) and node.id in struct_names: + return node.id + if isinstance(node, ast.Constant) and isinstance(node.value, str) and node.value in struct_names: + return node.value + if isinstance(node, ast.Attribute) and node.attr in struct_names: + return node.attr + if isinstance(node, ast.Subscript): + base_name: str | None = None + if isinstance(node.value, ast.Name): + base_name = node.value.id + elif isinstance(node.value, ast.Attribute): + base_name = node.value.attr + if base_name: + slice_node: ast.AST = node.slice + if hasattr(ast, 'Index') and isinstance(slice_node, ast.Index): + slice_node = slice_node.value + type_args: list[str] = [] + if isinstance(slice_node, ast.Name): + type_args.append(slice_node.id) + elif isinstance(slice_node, ast.Attribute): + type_args.append(slice_node.attr) + elif isinstance(slice_node, ast.Tuple): + for elt in slice_node.elts: + if isinstance(elt, ast.Name): + type_args.append(elt.id) + elif isinstance(elt, ast.Attribute): + type_args.append(elt.attr) + if type_args: + spec_name: str = base_name + ''.join(f'[{arg}]' for arg in type_args) + if spec_name in struct_names: + return spec_name + 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) + if result: + return result + return FindStructNameInAnnotation(node.right, struct_names) + return None + + +def AnnotationContainsName(annotation: ast.AST, name: str) -> bool: + """检查注解中是否包含指定名称(支持 BinOp(BitOr) 递归)。 + + 同时检查 Attribute.attr 和 Name.id,比 ast.dump 字符串匹配更精确。 + """ + if isinstance(annotation, ast.Attribute): + return annotation.attr == name + if isinstance(annotation, ast.Name): + return annotation.id == name + if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + return AnnotationContainsName(annotation.left, name) or AnnotationContainsName(annotation.right, name) + return False + + +def IsCPtrNode(node: ast.AST) -> bool: + """检查节点是否为 t.CPtr 属性引用。""" + return (isinstance(node, ast.Attribute) + and isinstance(node.value, ast.Name) + and node.value.id == 't' + and node.attr == 'CPtr') diff --git a/lib/core/Translator/AnnotationLoader.py b/lib/core/Translator/AnnotationLoader.py index 24a6d25..e1ffdfa 100644 --- a/lib/core/Translator/AnnotationLoader.py +++ b/lib/core/Translator/AnnotationLoader.py @@ -1,6 +1,6 @@ from __future__ import annotations -import ast +import vast as ast import os import importlib import types diff --git a/lib/core/Translator/BaseTranslator.py b/lib/core/Translator/BaseTranslator.py index 03f8537..fce641b 100644 --- a/lib/core/Translator/BaseTranslator.py +++ b/lib/core/Translator/BaseTranslator.py @@ -1,6 +1,6 @@ from __future__ import annotations -import ast +import vast as ast from typing import Any, Callable, Dict, TYPE_CHECKING from lib.core.Exportable import Exportable @@ -25,9 +25,9 @@ from lib.core.Handles.HandlesBase import CTypeInfo from lib.core.SymbolTable import SymbolTable from lib.core.SymbolNode import SymbolNode from lib.constants.config import mode as _ConfigMode -from lib.core.VLogger import get_logger as _vlog - - +from lib.core.VLogger import get_logger as _vlog + + def _StrictLog(logger: Callable[[str], None], msg: str) -> None: """在 strict 模式下记录异常日志""" if _ConfigMode == "strict": @@ -66,14 +66,14 @@ class BaseTranslatorMixin: self.InClass: bool = False # 是否正在处理 class 定义 self._UserTypeModules: dict = {} self._source_module_sig_files: dict = {} - self._global_function_default_args: dict = {} + self._global_function_default_args: dict = {} self._global_function_param_names: dict = {} self.exception_registry: dict = {} self.exception_parents: dict = {} - self._next_exception_code: int = 100 - # 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射 - self.config: Any = None - self._ImportedModules: set[str] | None = None + self._next_exception_code: int = 100 + # 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射 + self.config: Any = None + self._ImportedModules: set[str] | None = None self._t_c_imported_names: dict = {} # 导出表 diff --git a/lib/core/Translator/ConstEval.py b/lib/core/Translator/ConstEval.py index 8785365..ae75f85 100644 --- a/lib/core/Translator/ConstEval.py +++ b/lib/core/Translator/ConstEval.py @@ -1,6 +1,6 @@ from __future__ import annotations -import ast +import vast as ast from typing import TYPE_CHECKING import llvmlite.ir as ir diff --git a/lib/core/Translator/LlvmGenerator.py b/lib/core/Translator/LlvmGenerator.py index 9b3658d..d68605f 100644 --- a/lib/core/Translator/LlvmGenerator.py +++ b/lib/core/Translator/LlvmGenerator.py @@ -1,6 +1,6 @@ from __future__ import annotations -import ast +import vast as ast import re import llvmlite.ir as ir diff --git a/lib/core/Translator/PythonParser.py b/lib/core/Translator/PythonParser.py index bfe4e49..87be9f8 100644 --- a/lib/core/Translator/PythonParser.py +++ b/lib/core/Translator/PythonParser.py @@ -1,6 +1,6 @@ from __future__ import annotations -import ast +import vast as ast import json import struct diff --git a/lib/core/TypeAnnotationResolver.py b/lib/core/TypeAnnotationResolver.py index 10b4084..480ab7d 100644 --- a/lib/core/TypeAnnotationResolver.py +++ b/lib/core/TypeAnnotationResolver.py @@ -1,762 +1,762 @@ -from __future__ import annotations -import ast -import warnings -from typing import TYPE_CHECKING - -from lib.core.Handles.HandlesBase import CTypeInfo, BuiltinTypeMap, CTypeHelper -from lib.core.ConstEvaluator import ConstEvaluator -from lib.core.SymbolUtils import IsTModule, IsTModulePath, IsListAnnotation -from lib.includes import t -from lib.constants.config import mode as _config_mode - -if TYPE_CHECKING: - from lib.core.SymbolTable import SymbolTable - - -class TypeAnnotationResolver: - """从 AST 节点解析类型注解,独立于 CTypeInfo 数据模型。""" - - @staticmethod - def from_type_name(TypeName: str) -> CTypeInfo: - """从简单类型名构造 CTypeInfo(不经过 FromStr 字符串解析)""" - # Handle pointer types like 'CUInt32T *', 'void *', etc. - ptr_count: int = 0 - base_name: str = TypeName - while base_name.endswith(' *') or base_name.endswith('*'): - ptr_count += 1 - base_name = base_name.rstrip(' *').rstrip() - - entry: tuple[type, int] | None = BuiltinTypeMap.Get(base_name) - if entry: - TypeClass: type - base_ptr: int - TypeClass, base_ptr = entry - info: CTypeInfo = CTypeInfo() - info.BaseType = TypeClass - info.PtrCount = base_ptr + ptr_count - return info - # Handle LLVM primitive type names (e.g., 'i64', 'double' from generic type inference) - llvm_map: dict = CTypeInfo._get_llvm_primitive_map() - llvm_entry: tuple[type, int] | None = llvm_map.get(base_name) - if llvm_entry: - TypeClass: type - base_ptr: int - TypeClass, base_ptr = llvm_entry - info: CTypeInfo = CTypeInfo() - info.BaseType = TypeClass - info.PtrCount = base_ptr + ptr_count - return info - # Fallback with pointer count - info: CTypeInfo = CTypeInfo.CreateFromTypeName(TypeName) - if ptr_count > 0: - info.PtrCount = ptr_count - return info - - @staticmethod - def try_eval_const_expr(node: ast.AST, SymbolTable: SymbolTable) -> int | float | str | None: - return ConstEvaluator.eval_with_symtab(node, SymbolTable) - - @staticmethod - def from_node(Node: ast.AST, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """从 AST 节点解析 CTypeInfo - - Args: - Node: AST 节点(如 ast.Name, ast.Attribute 等) - SymbolTable: 符号表字典 - """ - if isinstance(Node, ast.Constant): - return TypeAnnotationResolver._from_node_constant(Node, SymbolTable) - if isinstance(Node, ast.Name): - return TypeAnnotationResolver._from_node_name(Node, SymbolTable) - if isinstance(Node, ast.Call): - return TypeAnnotationResolver._from_node_call(Node, SymbolTable) - if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr): - return TypeAnnotationResolver._from_node_binop(Node, SymbolTable) - if isinstance(Node, ast.Subscript): - return TypeAnnotationResolver._from_node_subscript(Node, SymbolTable) - if isinstance(Node, ast.Attribute): - return TypeAnnotationResolver._from_node_attribute(Node, SymbolTable) - return CTypeInfo() - - @staticmethod - def _from_node_constant(Node: ast.AST, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.Constant 节点""" - TypeName: str = Node.value - return TypeAnnotationResolver.from_type_name(TypeName) - - @staticmethod - def _from_node_name(Node: ast.Name, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.Name 节点""" - TypeName: str = Node.id - TypeObj: type | None = CTypeHelper.GetTModuleCType(TypeName) - if TypeObj is None: - TypeObj = getattr(t, TypeName, None) - if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType) and TypeObj is not t.CType: - if TypeObj == t.CPtr: - Result: CTypeInfo = CTypeInfo() - Result.PtrCount = 1 - Result.BaseType = t.CVoid() - return Result - if TypeObj == t.State: - Result: CTypeInfo = CTypeInfo() - Result.IsState = True - Result.BaseType = t.CVoid() - return Result - Inst: t.CType = TypeObj() - Result: CTypeInfo = CTypeInfo() - Result.Name = type(Inst).__name__ - # 存储类修饰符(CExtern, CExport, CInline, CThreadLocal 等): - # position 含 STORAGE_CLASS 且不含 BASE → 纯修饰符,无实际类型 - if t.CType.STORAGE_CLASS in TypeObj.position and t.CType.BASE not in TypeObj.position: - Result.BaseType = t.CVoid() - Result.Storage = Inst - return Result - # 类型限定符(CConst, CVolatile 等) - if t.CType.TYPE_QUALIFIER in TypeObj.position and t.CType.BASE not in TypeObj.position: - Result.BaseType = t.CVoid() - if TypeObj == t.CConst: - Result.DataConst = True - elif TypeObj == t.CVolatile: - Result.DataVolatile = True - return Result - Result.BaseType = TypeObj - if hasattr(Inst, 'IsSigned'): - Result.IsSigned = Inst.IsSigned - return Result - # 检查 BuiltinTypeMap(覆盖 VOIDPTR, BYTEPTR 等指针别名) - builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(TypeName) - if builtin_entry: - TypeClass: type - base_ptr: int - TypeClass, base_ptr = builtin_entry - Result: CTypeInfo = CTypeInfo() - Result.BaseType = TypeClass - Result.PtrCount = base_ptr - return Result - if TypeName in SymbolTable: - Entry: CTypeInfo | dict = SymbolTable[TypeName] - if Entry: - if isinstance(Entry, CTypeInfo): - if Entry.IsTypedef: - if Entry.BaseType and (not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0): - Result = Entry.Copy() - Result.IsTypedef = True - Result.Name = TypeName - return Result - if Entry.OriginalType: - if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr: - Result = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else [] - Result.IsTypedef = True - Result.Name = TypeName - return Result - elif isinstance(Entry.OriginalType, CTypeInfo): - Resolved = Entry.OriginalType.Copy() - elif isinstance(Entry.OriginalType, str) and Entry.OriginalType == 'Callable': - Result = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = [] - Result.IsTypedef = True - Result.Name = TypeName - return Result - elif isinstance(Entry.OriginalType, str): - Resolved = TypeAnnotationResolver.from_type_name(Entry.OriginalType) - else: - Resolved = Entry.OriginalType - Resolved.IsTypedef = True - Resolved.Name = TypeName - return Resolved - TypeEntry = BuiltinTypeMap.Get(TypeName) - if TypeEntry: - Result = CTypeInfo() - Result.BaseType = TypeEntry[0]() - Result.PtrCount = TypeEntry[1] - Result.IsTypedef = True - Result.Name = TypeName - return Result - return Entry - if Entry.IsEnum: - Result = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsEnum = True - Result.Name = TypeName - return Result - if Entry.IsExceptionClass: - Result = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsExceptionClass = True - Result.Name = TypeName - return Result - if Entry.BaseType is None and (Entry.IsStruct or Entry.Name): - Entry.BaseType = t.CStruct(name=TypeName) - Entry.IsStruct = True - return Entry - elif isinstance(Entry, dict): - if Entry.get('type') == 'typedef': - OriginalType = Entry.get('OriginalType', '') - if OriginalType: - if OriginalType == 'Callable': - Result = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = [] - Result.IsTypedef = True - Result.Name = TypeName - return Result - Resolved = TypeAnnotationResolver.from_type_name(OriginalType) - Resolved.IsTypedef = True - Resolved.Name = TypeName - return Resolved - TypeEntry = BuiltinTypeMap.Get(TypeName) - if TypeEntry: - Result = CTypeInfo() - Result.BaseType = TypeEntry[0]() - Result.PtrCount = TypeEntry[1] - Result.IsTypedef = True - Result.Name = TypeName - return Result - Result = CTypeInfo() - Result.BaseType = t._CTypedef(TypeName) - Result.IsTypedef = True - Result.Name = TypeName - return Result - # 检查 t 类型别名(from t import CInt as myint) - if hasattr(SymbolTable, '_t_type_symbols'): - t_cls = SymbolTable._t_type_symbols.get(TypeName) - if t_cls is not None: - Result = CTypeInfo() - Result.BaseType = t_cls - return Result - # 特殊处理 str 类型,它应该是 char*(指针) - if TypeName in ('str', 'bytes'): - Result = CTypeInfo() - Result.BaseType = t.CChar() - Result.PtrCount = 1 - return Result - return TypeAnnotationResolver.from_type_name(TypeName) - - @staticmethod - def _from_node_call(Node: ast.Call, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.Call 节点""" - if isinstance(Node.func, ast.Name) and Node.func.id == 'callable': - Result: CTypeInfo = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = [] - try: - if len(Node.args) > 0: - RetInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.args[0], SymbolTable) - if RetInfo: - Result.FuncPtrReturn = RetInfo - kw: ast.keyword - for kw in Node.keywords: - ParamInfo: CTypeInfo = TypeAnnotationResolver.from_node(kw.value, SymbolTable) - if ParamInfo: - Result.FuncPtrParams.append((kw.arg or '', ParamInfo)) - except Exception as _e: - if _config_mode == "strict": - warnings.warn(f"异常被忽略: {_e}") - return Result - if isinstance(Node.func, ast.Attribute): - if isinstance(Node.func.value, ast.Name) and IsTModule(Node.func.value.id, SymbolTable): - if Node.func.attr == 'Bit' and len(Node.args) > 0: - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsBitField = True - if isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, int): - Result.BitWidth = Node.args[0].value - else: - Result.BitWidth = 1 - return Result - return CTypeInfo() - - @staticmethod - def _from_node_binop(Node: ast.BinOp, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.BinOp (BitOr) 节点""" - LeftInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.left, SymbolTable) - RightInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.right, SymbolTable) - - if LeftInfo.IsState or RightInfo.IsState: - Result: CTypeInfo = CTypeInfo() - Result.IsState = True - NonStateInfo: CTypeInfo = LeftInfo if not LeftInfo.IsState else RightInfo - StateInfo: CTypeInfo = LeftInfo if LeftInfo.IsState else RightInfo - if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (t._CTypedef,)) or NonStateInfo.PtrCount > 0): - Result.BaseType = NonStateInfo.BaseType - elif NonStateInfo.IsTypedef and NonStateInfo.Name: - if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (t._CTypedef,)) or NonStateInfo.PtrCount > 0): - Result.BaseType = NonStateInfo.BaseType - Result.PtrCount = NonStateInfo.PtrCount - Result.IsTypedef = True - Result.Name = NonStateInfo.Name - if NonStateInfo.OriginalType: - Result.OriginalType = NonStateInfo.OriginalType - else: - Result.BaseType = t.CStruct(name=NonStateInfo.Name) - Result.IsStruct = True - Result.IsTypedef = True - Result.Name = NonStateInfo.Name - if NonStateInfo.OriginalType: - Result.OriginalType = NonStateInfo.OriginalType - else: - Result.BaseType = t.CVoid() - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if not Result.Storage: - Result.Storage = t.CExport() - if LeftInfo.Storage and not isinstance(LeftInfo.Storage, t.CExport): - Result.Storage = LeftInfo.Storage - elif RightInfo.Storage and not isinstance(RightInfo.Storage, t.CExport): - Result.Storage = RightInfo.Storage - if LeftInfo.DataConst or RightInfo.DataConst: - Result.DataConst = True - if LeftInfo.VarConst or RightInfo.VarConst: - Result.VarConst = True - return Result - - if LeftInfo.IsPtr or RightInfo.IsPtr: - Result = CTypeInfo() - # 当双方都是指针时(如 (AST | t.CPtr) | t.CPtr),PtrCount 应相加 - # 而非取 max,否则 AST** 会被折叠为 AST*,导致对象切片问题 - if LeftInfo.IsPtr and RightInfo.IsPtr: - Result.PtrCount = LeftInfo.PtrCount + RightInfo.PtrCount - # BaseType 优先取非 void 侧(如 AST),而非 t.CPtr 的 void - if LeftInfo.BaseType and not isinstance(LeftInfo.BaseType, t.CVoid): - Result.BaseType = LeftInfo.BaseType - elif RightInfo.BaseType and not isinstance(RightInfo.BaseType, t.CVoid): - Result.BaseType = RightInfo.BaseType - else: - Result.BaseType = t.CUnsignedChar() - else: - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - NonPtrInfo = LeftInfo if not LeftInfo.IsPtr else RightInfo - PtrInfo = RightInfo if RightInfo.IsPtr else LeftInfo - if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (t._CTypedef,)) or NonPtrInfo.PtrCount > 0): - Result.BaseType = NonPtrInfo.BaseType - elif NonPtrInfo.IsTypedef and NonPtrInfo.Name: - if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (t._CTypedef,)) or NonPtrInfo.PtrCount > 0): - Result.BaseType = NonPtrInfo.BaseType - Result.IsTypedef = True - Result.Name = NonPtrInfo.Name - if NonPtrInfo.OriginalType: - Result.OriginalType = NonPtrInfo.OriginalType - else: - Result.BaseType = t.CStruct(name=NonPtrInfo.Name) - Result.IsStruct = True - elif PtrInfo.BaseType and (not isinstance(PtrInfo.BaseType, (t._CTypedef,)) or PtrInfo.PtrCount > 0): - Result.BaseType = PtrInfo.BaseType - else: - Result.BaseType = t.CUnsignedChar() - if LeftInfo.DataConst or RightInfo.DataConst: - Result.DataConst = True - if LeftInfo.VarConst or RightInfo.VarConst: - Result.VarConst = True - if LeftInfo.DataVolatile or RightInfo.DataVolatile: - Result.DataVolatile = True - if LeftInfo.VarVolatile or RightInfo.VarVolatile: - Result.VarVolatile = True - if LeftInfo.Storage: - Result.Storage = LeftInfo.Storage - elif RightInfo.Storage: - Result.Storage = RightInfo.Storage - return Result - - if LeftInfo.DataConst or RightInfo.DataConst: - Result = CTypeInfo() - BaseTypeSide = LeftInfo if not LeftInfo.DataConst else RightInfo - QualSide = LeftInfo if LeftInfo.DataConst else RightInfo - Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType - if not Result.BaseType: - Result.BaseType = t.CInt() - Result.DataConst = True - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if LeftInfo.VarConst or RightInfo.VarConst: - Result.VarConst = True - if LeftInfo.DataVolatile or RightInfo.DataVolatile: - Result.DataVolatile = True - if LeftInfo.Storage: - Result.Storage = LeftInfo.Storage - elif RightInfo.Storage: - Result.Storage = RightInfo.Storage - return Result - - if LeftInfo.DataVolatile or RightInfo.DataVolatile: - Result = CTypeInfo() - BaseTypeSide = LeftInfo if not LeftInfo.DataVolatile else RightInfo - QualSide = LeftInfo if LeftInfo.DataVolatile else RightInfo - Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType - if not Result.BaseType: - Result.BaseType = t.CInt() - Result.DataVolatile = True - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if LeftInfo.VarConst or RightInfo.VarConst: - Result.VarConst = True - if LeftInfo.Storage: - Result.Storage = LeftInfo.Storage - elif RightInfo.Storage: - Result.Storage = RightInfo.Storage - return Result - - if LeftInfo.Storage or RightInfo.Storage: - Result = CTypeInfo() - BaseTypeSide = LeftInfo if not LeftInfo.Storage else RightInfo - StorageSide = LeftInfo if LeftInfo.Storage else RightInfo - # CExtern | CExport 等价于 t.State:两边都有 Storage 时设置 IsState - if BaseTypeSide.IsState or StorageSide.IsState or (LeftInfo.Storage and RightInfo.Storage): - Result.IsState = True - Result.BaseType = t.CVoid() - Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage - return Result - Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else StorageSide.BaseType - if not Result.BaseType: - Result.BaseType = t.CInt() - Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if LeftInfo.DataConst or RightInfo.DataConst: - Result.DataConst = True - if LeftInfo.VarConst or RightInfo.VarConst: - Result.VarConst = True - return Result - - # 检查是否有位域类型 (t.Bit) - if LeftInfo.IsBitField: - Result = CTypeInfo() - Result.BaseType = LeftInfo.BaseType if LeftInfo.BaseType else t.CInt() - Result.IsBitField = True - Result.BitWidth = LeftInfo.BitWidth - return Result - if RightInfo.IsBitField: - Result = CTypeInfo() - Result.BaseType = RightInfo.BaseType if RightInfo.BaseType else t.CInt() - Result.IsBitField = True - Result.BitWidth = RightInfo.BitWidth - return Result - - # 处理字节序类型 (t.BigEndian, t.LittleEndian) - # 合并两侧:保留非字节序侧的实际类型(如 CUInt64T),取字节序侧的 ByteOrder - if LeftInfo.ByteOrder or RightInfo.ByteOrder: - Result = CTypeInfo() - ByteOrderSide: CTypeInfo = LeftInfo if LeftInfo.ByteOrder else RightInfo - OtherSide: CTypeInfo = RightInfo if LeftInfo.ByteOrder else LeftInfo - if OtherSide.BaseType and (not isinstance(OtherSide.BaseType, (t._CTypedef,)) or OtherSide.PtrCount > 0): - Result.BaseType = OtherSide.BaseType - elif ByteOrderSide.BaseType and (not isinstance(ByteOrderSide.BaseType, (t._CTypedef,)) or ByteOrderSide.PtrCount > 0): - Result.BaseType = ByteOrderSide.BaseType - else: - Result.BaseType = t.CInt() - Result.ByteOrder = LeftInfo.ByteOrder or RightInfo.ByteOrder - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - return Result - - if LeftInfo.IsFuncPtr or RightInfo.IsFuncPtr: - Result = CTypeInfo() - FuncPtrSide = LeftInfo if LeftInfo.IsFuncPtr else RightInfo - Result.IsFuncPtr = True - Result.FuncPtrParams = list(FuncPtrSide.FuncPtrParams) - Result.FuncPtrReturn = FuncPtrSide.FuncPtrReturn - if LeftInfo.Storage: - Result.Storage = LeftInfo.Storage - elif RightInfo.Storage: - Result.Storage = RightInfo.Storage - return Result - - if LeftInfo.IsTypedef and RightInfo.BaseType: - if LeftInfo.BaseType and (not isinstance(LeftInfo.BaseType, (t._CTypedef,)) or LeftInfo.PtrCount > 0): - Result = LeftInfo.Copy() - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if RightInfo.Storage: - Result.Storage = RightInfo.Storage - return Result - return RightInfo - if RightInfo.IsTypedef and LeftInfo.BaseType: - if RightInfo.BaseType and (not isinstance(RightInfo.BaseType, (t._CTypedef,)) or RightInfo.PtrCount > 0): - Result = RightInfo.Copy() - Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) - if LeftInfo.Storage: - Result.Storage = LeftInfo.Storage - return Result - return LeftInfo - - if LeftInfo.BaseType: - return LeftInfo - elif RightInfo.BaseType: - return RightInfo - return CTypeInfo() - - @staticmethod - def _from_node_subscript(Node: ast.Subscript, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.Subscript 节点""" - base: ast.AST = Node.value - if isinstance(base, ast.Attribute): - if isinstance(base.value, ast.Name) and IsTModule(base.value.id, SymbolTable) and base.attr == 'Bit': - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsBitField = True - if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int): - Result.BitWidth = Node.slice.value - else: - Result.BitWidth = 1 - return Result - if IsListAnnotation(Node): - slice_node: ast.AST = Node.slice - elts: list[ast.AST] = [] - if isinstance(slice_node, ast.Tuple): - elts = slice_node.elts - elif isinstance(slice_node, (ast.Attribute, ast.Name, ast.Subscript)): - elts = [slice_node] - if elts: - ElemInfo: CTypeInfo = TypeAnnotationResolver.from_node(elts[0], SymbolTable) - if ElemInfo and ElemInfo.BaseType: - Result: CTypeInfo = CTypeInfo() - Result.BaseType = ElemInfo.BaseType - Result.PtrCount = ElemInfo.PtrCount - Result.ArrayDims = list(ElemInfo.ArrayDims) - if len(elts) >= 2: - count_val: int | None = TypeAnnotationResolver.try_eval_const_expr(elts[1], SymbolTable) - if count_val is not None and isinstance(count_val, int) and count_val > 0: - Result.ArrayDims.insert(0, str(count_val)) - else: - Result.PtrCount += 1 - if ElemInfo.IsPtr and not ElemInfo.ArrayDims: - Result.PtrCount = max(Result.PtrCount, 1) - return Result - if isinstance(base, ast.Attribute): - parts: list[str] = [] - current: ast.AST = base - while isinstance(current, ast.Attribute): - parts.insert(0, current.attr) - current = current.value - if isinstance(current, ast.Name): - parts.insert(0, current.id) - if parts and IsTModule(parts[0], SymbolTable) and parts[-1] == t.CPtr.__name__: - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CVoid() - Result.PtrCount = 1 - slice_node: ast.AST = Node.slice - if isinstance(slice_node, ast.Subscript): - InnerInfo: CTypeInfo = TypeAnnotationResolver.from_node(slice_node, SymbolTable) - if InnerInfo: - if InnerInfo.PtrCount > 0: - Result.PtrCount += InnerInfo.PtrCount - if InnerInfo.BaseType and not isinstance(InnerInfo.BaseType, t.CVoid): - Result.BaseType = InnerInfo.BaseType - elif isinstance(slice_node, ast.Attribute): - SliceInfo: CTypeInfo = TypeAnnotationResolver.from_node(slice_node, SymbolTable) - if SliceInfo: - if SliceInfo.IsPtr: - Result.PtrCount += SliceInfo.PtrCount - elif SliceInfo.BaseType and not isinstance(SliceInfo.BaseType, t.CVoid): - Result.BaseType = SliceInfo.BaseType - elif isinstance(slice_node, ast.Name): - SliceType: type | None = getattr(t, slice_node.id, None) - if SliceType == t.CPtr: - Result.PtrCount += 1 - else: - SliceInfo = TypeAnnotationResolver.from_node(slice_node, SymbolTable) - if SliceInfo and SliceInfo.BaseType and not isinstance(SliceInfo.BaseType, t.CVoid): - Result.BaseType = SliceInfo.BaseType - return Result - if parts and IsTModule(parts[0], SymbolTable) and parts[-1] == 'Callable': - Result = CTypeInfo() - Result.IsFuncPtr = True - slice_node = Node.slice - if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: - params_list = slice_node.elts[0] - return_node = slice_node.elts[1] - ParamTypes = [] - if isinstance(params_list, ast.List): - for elt in params_list.elts: - ParamTypeInfo = TypeAnnotationResolver.from_node(elt, SymbolTable) - if ParamTypeInfo: - ParamTypes.append(('', ParamTypeInfo)) - if not ParamTypes: - ParamTypes.append(('', TypeAnnotationResolver.from_type_name('void'))) - Result.FuncPtrParams = ParamTypes - ReturnTypeInfo = TypeAnnotationResolver.from_node(return_node, SymbolTable) - Result.FuncPtrReturn = ReturnTypeInfo if ReturnTypeInfo else CTypeInfo.VoidTypeInfo() - return Result - return CTypeInfo() - - @staticmethod - def _from_node_attribute(Node: ast.Attribute, SymbolTable: dict | SymbolTable) -> CTypeInfo: - """处理 ast.Attribute 节点""" - ModuleParts: list[str] = [] - Current: ast.AST = Node - while isinstance(Current, ast.Attribute): - ModuleParts.insert(0, Current.attr) - Current = Current.value - - if isinstance(Current, ast.Name): - ModuleParts.insert(0, Current.id) - - TypeName: str - ModulePath: str | None - if len(ModuleParts) >= 2: - TypeName = ModuleParts[-1] - ModulePath = '.'.join(ModuleParts[:-1]) - elif len(ModuleParts) == 1: - TypeName = ModuleParts[0] - ModulePath = None - else: - return CTypeInfo() - - # 解析 import 别名: 如 import vpsdk.window as window -> window -> vpsdk.window - if ModulePath: - resolved: bool = False - import_aliases: dict = SymbolTable.import_aliases - if ModulePath in import_aliases: - ModulePath = import_aliases[ModulePath] - resolved = True - if not resolved and ModulePath in SymbolTable: - entry: CTypeInfo = SymbolTable[ModulePath] - if isinstance(entry, CTypeInfo) and entry.IsModuleAlias: - resolved_name = entry.ResolvedModule - if resolved_name: - ModulePath = resolved_name - - if ModulePath and IsTModulePath(ModulePath): - TypeClass: type | None = CTypeHelper.GetTModuleCType(TypeName) - if TypeClass is None: - TypeClass = getattr(t, TypeName, None) - if TypeClass is not None and TypeClass.HasPosition(t.CType.POINTER): - Info: CTypeInfo = CTypeInfo() - Info.PtrCount = 1 - if TypeClass == t.CArrayPtr: - Info.IsArrayPtr = True - Info.BaseType = t.CVoid - return Info - if TypeClass is not None and TypeClass.IsStorageClass(): - Info: CTypeInfo = CTypeInfo() - Info.Storage = TypeClass() - if TypeClass == t.State: - Info.IsState = True - Info.BaseType = t.CVoid() - return Info - if TypeClass is not None and TypeClass.IsTypeQualifier(): - Info: CTypeInfo = CTypeInfo() - if TypeClass == t.CConst: - Info.DataConst = True - elif TypeClass == t.CVolatile: - Info.DataVolatile = True - return Info - if TypeClass is not None and TypeClass in (t.BigEndian, t.LittleEndian): - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CInt() - Result.ByteOrder = 'big' if TypeClass == t.BigEndian else 'little' - return Result - if (TypeClass is not None - and isinstance(TypeClass, type) - and issubclass(TypeClass, t.CType) - and TypeClass is not t.CType - and TypeClass.HasPosition(t.CType.BASE)): - if TypeClass == t.State: - Result: CTypeInfo = CTypeInfo() - Result.IsState = True - Result.BaseType = t.CVoid() - return Result - Inst: t.CType = TypeClass() - Result: CTypeInfo = CTypeInfo() - Result.BaseType = TypeClass - Result.Name = type(Inst).__name__ - if hasattr(Inst, 'IsSigned'): - Result.IsSigned = Inst.IsSigned - return Result - CNAME: str | None = CTypeHelper.GetCName(TypeName) - if CNAME: - return TypeAnnotationResolver.from_type_name(CNAME) - - # 处理字节序类型 - if TypeName == 'BigEndian': - Result = CTypeInfo() - Result.BaseType = t.CInt() - Result.ByteOrder = 'big' - return Result - if TypeName == 'LittleEndian': - Result = CTypeInfo() - Result.BaseType = t.CInt() - Result.ByteOrder = 'little' - return Result - - FullName: str = f"{ModulePath}.{TypeName}" if ModulePath else TypeName - - if TypeName in SymbolTable: - Entry: CTypeInfo = SymbolTable[TypeName] - if Entry and Entry.IsTypedef: - Resolved: CTypeInfo = Entry.Copy() - if Resolved.BaseType is None: - Resolved.BaseType = t._CTypedef(TypeName) - return Resolved - if Entry and Entry.IsEnum: - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsEnum = True - Result.Name = TypeName - return Result - if Entry and Entry.IsExceptionClass: - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t.CInt() - Result.IsExceptionClass = True - Result.Name = TypeName - return Result - if Entry: - Result: CTypeInfo = Entry.Copy() - if Result.BaseType is None and (Result.IsStruct or Result.IsCpythonObject or Result.Name): - Result.BaseType = t.CStruct(name=TypeName) - Result.IsStruct = True - return Result - return CTypeInfo() - - if FullName in SymbolTable: - Info: CTypeInfo = SymbolTable[FullName] - if Info and Info.IsTypedef: - # 优先用 BaseType 解析(如 VOIDPTR 已解析为 BaseType=CVoid, PtrCount=1) - if Info.BaseType and (not isinstance(Info.BaseType, (t._CTypedef,)) or Info.PtrCount > 0): - Result = Info.Copy() - Result.IsTypedef = True - Result.Name = FullName - return Result - # 再用 OriginalType 解析(字符串如 'void *',或 CTypeInfo) - if Info.OriginalType: - if isinstance(Info.OriginalType, CTypeInfo) and Info.OriginalType.IsFuncPtr: - Result = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = Info.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = list(Info.OriginalType.FuncPtrParams) if Info.OriginalType.FuncPtrParams else [] - Result.IsTypedef = True - Result.Name = FullName - return Result - elif isinstance(Info.OriginalType, CTypeInfo): - Resolved: CTypeInfo = Info.OriginalType.Copy() - elif isinstance(Info.OriginalType, str) and Info.OriginalType == 'Callable': - Result = CTypeInfo() - Result.IsFuncPtr = True - Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() - Result.FuncPtrParams = [] - Result.IsTypedef = True - Result.Name = FullName - return Result - elif isinstance(Info.OriginalType, str): - Resolved = TypeAnnotationResolver.from_type_name(Info.OriginalType) - else: - Resolved = Info.OriginalType - if Resolved and Resolved.BaseType: - Resolved.IsTypedef = True - Resolved.Name = FullName - return Resolved - # 回退:保持原逻辑但设置 Name = FullName(供后续 TypeConvert 查找) - Result: CTypeInfo = CTypeInfo() - Result.BaseType = t._CTypedef(TypeName) - Result.IsTypedef = True - Result.Name = FullName - return Result - if Info: - Result: CTypeInfo = Info.Copy() - if Result.BaseType is None and (Result.IsStruct or Result.IsCpythonObject or Result.Name): - Result.BaseType = t.CStruct(name=TypeName) - Result.IsStruct = True - return Result - return CTypeInfo() - - return CTypeInfo() +from __future__ import annotations +import vast as ast +import warnings +from typing import TYPE_CHECKING + +from lib.core.Handles.HandlesBase import CTypeInfo, BuiltinTypeMap, CTypeHelper +from lib.core.ConstEvaluator import ConstEvaluator +from lib.core.SymbolUtils import IsTModule, IsTModulePath, IsListAnnotation +from lib.includes import t +from lib.constants.config import mode as _config_mode + +if TYPE_CHECKING: + from lib.core.SymbolTable import SymbolTable + + +class TypeAnnotationResolver: + """从 AST 节点解析类型注解,独立于 CTypeInfo 数据模型。""" + + @staticmethod + def from_type_name(TypeName: str) -> CTypeInfo: + """从简单类型名构造 CTypeInfo(不经过 FromStr 字符串解析)""" + # Handle pointer types like 'CUInt32T *', 'void *', etc. + ptr_count: int = 0 + base_name: str = TypeName + while base_name.endswith(' *') or base_name.endswith('*'): + ptr_count += 1 + base_name = base_name.rstrip(' *').rstrip() + + entry: tuple[type, int] | None = BuiltinTypeMap.Get(base_name) + if entry: + TypeClass: type + base_ptr: int + TypeClass, base_ptr = entry + info: CTypeInfo = CTypeInfo() + info.BaseType = TypeClass + info.PtrCount = base_ptr + ptr_count + return info + # Handle LLVM primitive type names (e.g., 'i64', 'double' from generic type inference) + llvm_map: dict = CTypeInfo._get_llvm_primitive_map() + llvm_entry: tuple[type, int] | None = llvm_map.get(base_name) + if llvm_entry: + TypeClass: type + base_ptr: int + TypeClass, base_ptr = llvm_entry + info: CTypeInfo = CTypeInfo() + info.BaseType = TypeClass + info.PtrCount = base_ptr + ptr_count + return info + # Fallback with pointer count + info: CTypeInfo = CTypeInfo.CreateFromTypeName(TypeName) + if ptr_count > 0: + info.PtrCount = ptr_count + return info + + @staticmethod + def try_eval_const_expr(node: ast.AST, SymbolTable: SymbolTable) -> int | float | str | None: + return ConstEvaluator.eval_with_symtab(node, SymbolTable) + + @staticmethod + def from_node(Node: ast.AST, SymbolTable: dict | SymbolTable) -> CTypeInfo: + """从 AST 节点解析 CTypeInfo + + Args: + Node: AST 节点(如 ast.Name, ast.Attribute 等) + SymbolTable: 符号表字典 + """ + if isinstance(Node, ast.Constant): + return TypeAnnotationResolver._from_node_constant(Node, SymbolTable) + if isinstance(Node, ast.Name): + return TypeAnnotationResolver._from_node_name(Node, SymbolTable) + if isinstance(Node, ast.Call): + return TypeAnnotationResolver._from_node_call(Node, SymbolTable) + if isinstance(Node, ast.BinOp) and isinstance(Node.op, ast.BitOr): + return TypeAnnotationResolver._from_node_binop(Node, SymbolTable) + if isinstance(Node, ast.Subscript): + return TypeAnnotationResolver._from_node_subscript(Node, SymbolTable) + if isinstance(Node, ast.Attribute): + return TypeAnnotationResolver._from_node_attribute(Node, SymbolTable) + return CTypeInfo() + + @staticmethod + def _from_node_constant(Node: ast.AST, SymbolTable: dict | SymbolTable) -> CTypeInfo: + """处理 ast.Constant 节点""" + TypeName: str = Node.value + return TypeAnnotationResolver.from_type_name(TypeName) + + @staticmethod + def _from_node_name(Node: ast.Name, SymbolTable: dict | SymbolTable) -> CTypeInfo: + """处理 ast.Name 节点""" + TypeName: str = Node.id + TypeObj: type | None = CTypeHelper.GetTModuleCType(TypeName) + if TypeObj is None: + TypeObj = getattr(t, TypeName, None) + if isinstance(TypeObj, type) and issubclass(TypeObj, t.CType) and TypeObj is not t.CType: + if TypeObj == t.CPtr: + Result: CTypeInfo = CTypeInfo() + Result.PtrCount = 1 + Result.BaseType = t.CVoid() + return Result + if TypeObj == t.State: + Result: CTypeInfo = CTypeInfo() + Result.IsState = True + Result.BaseType = t.CVoid() + return Result + Inst: t.CType = TypeObj() + Result: CTypeInfo = CTypeInfo() + Result.Name = type(Inst).__name__ + # 存储类修饰符(CExtern, CExport, CInline, CThreadLocal 等): + # position 含 STORAGE_CLASS 且不含 BASE → 纯修饰符,无实际类型 + if t.CType.STORAGE_CLASS in TypeObj.position and t.CType.BASE not in TypeObj.position: + Result.BaseType = t.CVoid() + Result.Storage = Inst + return Result + # 类型限定符(CConst, CVolatile 等) + if t.CType.TYPE_QUALIFIER in TypeObj.position and t.CType.BASE not in TypeObj.position: + Result.BaseType = t.CVoid() + if TypeObj == t.CConst: + Result.DataConst = True + elif TypeObj == t.CVolatile: + Result.DataVolatile = True + return Result + Result.BaseType = TypeObj + if hasattr(Inst, 'IsSigned'): + Result.IsSigned = Inst.IsSigned + return Result + # 检查 BuiltinTypeMap(覆盖 VOIDPTR, BYTEPTR 等指针别名) + builtin_entry: tuple[type, int] | None = BuiltinTypeMap.Get(TypeName) + if builtin_entry: + TypeClass: type + base_ptr: int + TypeClass, base_ptr = builtin_entry + Result: CTypeInfo = CTypeInfo() + Result.BaseType = TypeClass + Result.PtrCount = base_ptr + return Result + if TypeName in SymbolTable: + Entry: CTypeInfo | dict = SymbolTable[TypeName] + if Entry: + if isinstance(Entry, CTypeInfo): + if Entry.IsTypedef: + if Entry.BaseType and (not isinstance(Entry.BaseType, (t._CTypedef,)) or Entry.PtrCount > 0): + Result = Entry.Copy() + Result.IsTypedef = True + Result.Name = TypeName + return Result + if Entry.OriginalType: + if isinstance(Entry.OriginalType, CTypeInfo) and Entry.OriginalType.IsFuncPtr: + Result = CTypeInfo() + Result.IsFuncPtr = True + Result.FuncPtrReturn = Entry.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo() + Result.FuncPtrParams = list(Entry.OriginalType.FuncPtrParams) if Entry.OriginalType.FuncPtrParams else [] + Result.IsTypedef = True + Result.Name = TypeName + return Result + elif isinstance(Entry.OriginalType, CTypeInfo): + Resolved = Entry.OriginalType.Copy() + elif isinstance(Entry.OriginalType, str) and Entry.OriginalType == 'Callable': + Result = CTypeInfo() + Result.IsFuncPtr = True + Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + Result.FuncPtrParams = [] + Result.IsTypedef = True + Result.Name = TypeName + return Result + elif isinstance(Entry.OriginalType, str): + Resolved = TypeAnnotationResolver.from_type_name(Entry.OriginalType) + else: + Resolved = Entry.OriginalType + Resolved.IsTypedef = True + Resolved.Name = TypeName + return Resolved + TypeEntry = BuiltinTypeMap.Get(TypeName) + if TypeEntry: + Result = CTypeInfo() + Result.BaseType = TypeEntry[0]() + Result.PtrCount = TypeEntry[1] + Result.IsTypedef = True + Result.Name = TypeName + return Result + return Entry + if Entry.IsEnum: + Result = CTypeInfo() + Result.BaseType = t.CInt() + Result.IsEnum = True + Result.Name = TypeName + return Result + if Entry.IsExceptionClass: + Result = CTypeInfo() + Result.BaseType = t.CInt() + Result.IsExceptionClass = True + Result.Name = TypeName + return Result + if Entry.BaseType is None and (Entry.IsStruct or Entry.Name): + Entry.BaseType = t.CStruct(name=TypeName) + Entry.IsStruct = True + return Entry + elif isinstance(Entry, dict): + if Entry.get('type') == 'typedef': + OriginalType = Entry.get('OriginalType', '') + if OriginalType: + if OriginalType == 'Callable': + Result = CTypeInfo() + Result.IsFuncPtr = True + Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + Result.FuncPtrParams = [] + Result.IsTypedef = True + Result.Name = TypeName + return Result + Resolved = TypeAnnotationResolver.from_type_name(OriginalType) + Resolved.IsTypedef = True + Resolved.Name = TypeName + return Resolved + TypeEntry = BuiltinTypeMap.Get(TypeName) + if TypeEntry: + Result = CTypeInfo() + Result.BaseType = TypeEntry[0]() + Result.PtrCount = TypeEntry[1] + Result.IsTypedef = True + Result.Name = TypeName + return Result + Result = CTypeInfo() + Result.BaseType = t._CTypedef(TypeName) + Result.IsTypedef = True + Result.Name = TypeName + return Result + # 检查 t 类型别名(from t import CInt as myint) + if hasattr(SymbolTable, '_t_type_symbols'): + t_cls = SymbolTable._t_type_symbols.get(TypeName) + if t_cls is not None: + Result = CTypeInfo() + Result.BaseType = t_cls + return Result + # 特殊处理 str 类型,它应该是 char*(指针) + if TypeName in ('str', 'bytes'): + Result = CTypeInfo() + Result.BaseType = t.CChar() + Result.PtrCount = 1 + return Result + return TypeAnnotationResolver.from_type_name(TypeName) + + @staticmethod + def _from_node_call(Node: ast.Call, SymbolTable: dict | SymbolTable) -> CTypeInfo: + """处理 ast.Call 节点""" + if isinstance(Node.func, ast.Name) and Node.func.id == 'callable': + Result: CTypeInfo = CTypeInfo() + Result.IsFuncPtr = True + Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + Result.FuncPtrParams = [] + try: + if len(Node.args) > 0: + RetInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.args[0], SymbolTable) + if RetInfo: + Result.FuncPtrReturn = RetInfo + kw: ast.keyword + for kw in Node.keywords: + ParamInfo: CTypeInfo = TypeAnnotationResolver.from_node(kw.value, SymbolTable) + if ParamInfo: + Result.FuncPtrParams.append((kw.arg or '', ParamInfo)) + except Exception as _e: + if _config_mode == "strict": + warnings.warn(f"异常被忽略: {_e}") + return Result + if isinstance(Node.func, ast.Attribute): + if isinstance(Node.func.value, ast.Name) and IsTModule(Node.func.value.id, SymbolTable): + if Node.func.attr == 'Bit' and len(Node.args) > 0: + Result: CTypeInfo = CTypeInfo() + Result.BaseType = t.CInt() + Result.IsBitField = True + if isinstance(Node.args[0], ast.Constant) and isinstance(Node.args[0].value, int): + Result.BitWidth = Node.args[0].value + else: + Result.BitWidth = 1 + return Result + return CTypeInfo() + + @staticmethod + def _from_node_binop(Node: ast.BinOp, SymbolTable: dict | SymbolTable) -> CTypeInfo: + """处理 ast.BinOp (BitOr) 节点""" + LeftInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.left, SymbolTable) + RightInfo: CTypeInfo = TypeAnnotationResolver.from_node(Node.right, SymbolTable) + + if LeftInfo.IsState or RightInfo.IsState: + Result: CTypeInfo = CTypeInfo() + Result.IsState = True + NonStateInfo: CTypeInfo = LeftInfo if not LeftInfo.IsState else RightInfo + StateInfo: CTypeInfo = LeftInfo if LeftInfo.IsState else RightInfo + if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (t._CTypedef,)) or NonStateInfo.PtrCount > 0): + Result.BaseType = NonStateInfo.BaseType + elif NonStateInfo.IsTypedef and NonStateInfo.Name: + if NonStateInfo.BaseType and (not isinstance(NonStateInfo.BaseType, (t._CTypedef,)) or NonStateInfo.PtrCount > 0): + Result.BaseType = NonStateInfo.BaseType + Result.PtrCount = NonStateInfo.PtrCount + Result.IsTypedef = True + Result.Name = NonStateInfo.Name + if NonStateInfo.OriginalType: + Result.OriginalType = NonStateInfo.OriginalType + else: + Result.BaseType = t.CStruct(name=NonStateInfo.Name) + Result.IsStruct = True + Result.IsTypedef = True + Result.Name = NonStateInfo.Name + if NonStateInfo.OriginalType: + Result.OriginalType = NonStateInfo.OriginalType + else: + Result.BaseType = t.CVoid() + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if not Result.Storage: + Result.Storage = t.CExport() + if LeftInfo.Storage and not isinstance(LeftInfo.Storage, t.CExport): + Result.Storage = LeftInfo.Storage + elif RightInfo.Storage and not isinstance(RightInfo.Storage, t.CExport): + Result.Storage = RightInfo.Storage + if LeftInfo.DataConst or RightInfo.DataConst: + Result.DataConst = True + if LeftInfo.VarConst or RightInfo.VarConst: + Result.VarConst = True + return Result + + if LeftInfo.IsPtr or RightInfo.IsPtr: + Result = CTypeInfo() + # 当双方都是指针时(如 (AST | t.CPtr) | t.CPtr),PtrCount 应相加 + # 而非取 max,否则 AST** 会被折叠为 AST*,导致对象切片问题 + if LeftInfo.IsPtr and RightInfo.IsPtr: + Result.PtrCount = LeftInfo.PtrCount + RightInfo.PtrCount + # BaseType 优先取非 void 侧(如 AST),而非 t.CPtr 的 void + if LeftInfo.BaseType and not isinstance(LeftInfo.BaseType, t.CVoid): + Result.BaseType = LeftInfo.BaseType + elif RightInfo.BaseType and not isinstance(RightInfo.BaseType, t.CVoid): + Result.BaseType = RightInfo.BaseType + else: + Result.BaseType = t.CUnsignedChar() + else: + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + NonPtrInfo = LeftInfo if not LeftInfo.IsPtr else RightInfo + PtrInfo = RightInfo if RightInfo.IsPtr else LeftInfo + if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (t._CTypedef,)) or NonPtrInfo.PtrCount > 0): + Result.BaseType = NonPtrInfo.BaseType + elif NonPtrInfo.IsTypedef and NonPtrInfo.Name: + if NonPtrInfo.BaseType and (not isinstance(NonPtrInfo.BaseType, (t._CTypedef,)) or NonPtrInfo.PtrCount > 0): + Result.BaseType = NonPtrInfo.BaseType + Result.IsTypedef = True + Result.Name = NonPtrInfo.Name + if NonPtrInfo.OriginalType: + Result.OriginalType = NonPtrInfo.OriginalType + else: + Result.BaseType = t.CStruct(name=NonPtrInfo.Name) + Result.IsStruct = True + elif PtrInfo.BaseType and (not isinstance(PtrInfo.BaseType, (t._CTypedef,)) or PtrInfo.PtrCount > 0): + Result.BaseType = PtrInfo.BaseType + else: + Result.BaseType = t.CUnsignedChar() + if LeftInfo.DataConst or RightInfo.DataConst: + Result.DataConst = True + if LeftInfo.VarConst or RightInfo.VarConst: + Result.VarConst = True + if LeftInfo.DataVolatile or RightInfo.DataVolatile: + Result.DataVolatile = True + if LeftInfo.VarVolatile or RightInfo.VarVolatile: + Result.VarVolatile = True + if LeftInfo.Storage: + Result.Storage = LeftInfo.Storage + elif RightInfo.Storage: + Result.Storage = RightInfo.Storage + return Result + + if LeftInfo.DataConst or RightInfo.DataConst: + Result = CTypeInfo() + BaseTypeSide = LeftInfo if not LeftInfo.DataConst else RightInfo + QualSide = LeftInfo if LeftInfo.DataConst else RightInfo + Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType + if not Result.BaseType: + Result.BaseType = t.CInt() + Result.DataConst = True + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if LeftInfo.VarConst or RightInfo.VarConst: + Result.VarConst = True + if LeftInfo.DataVolatile or RightInfo.DataVolatile: + Result.DataVolatile = True + if LeftInfo.Storage: + Result.Storage = LeftInfo.Storage + elif RightInfo.Storage: + Result.Storage = RightInfo.Storage + return Result + + if LeftInfo.DataVolatile or RightInfo.DataVolatile: + Result = CTypeInfo() + BaseTypeSide = LeftInfo if not LeftInfo.DataVolatile else RightInfo + QualSide = LeftInfo if LeftInfo.DataVolatile else RightInfo + Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else QualSide.BaseType + if not Result.BaseType: + Result.BaseType = t.CInt() + Result.DataVolatile = True + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if LeftInfo.VarConst or RightInfo.VarConst: + Result.VarConst = True + if LeftInfo.Storage: + Result.Storage = LeftInfo.Storage + elif RightInfo.Storage: + Result.Storage = RightInfo.Storage + return Result + + if LeftInfo.Storage or RightInfo.Storage: + Result = CTypeInfo() + BaseTypeSide = LeftInfo if not LeftInfo.Storage else RightInfo + StorageSide = LeftInfo if LeftInfo.Storage else RightInfo + # CExtern | CExport 等价于 t.State:两边都有 Storage 时设置 IsState + if BaseTypeSide.IsState or StorageSide.IsState or (LeftInfo.Storage and RightInfo.Storage): + Result.IsState = True + Result.BaseType = t.CVoid() + Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage + return Result + Result.BaseType = BaseTypeSide.BaseType if BaseTypeSide.BaseType and (not isinstance(BaseTypeSide.BaseType, t.CVoid) or BaseTypeSide.PtrCount > 0) else StorageSide.BaseType + if not Result.BaseType: + Result.BaseType = t.CInt() + Result.Storage = LeftInfo.Storage if LeftInfo.Storage else RightInfo.Storage + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if LeftInfo.DataConst or RightInfo.DataConst: + Result.DataConst = True + if LeftInfo.VarConst or RightInfo.VarConst: + Result.VarConst = True + return Result + + # 检查是否有位域类型 (t.Bit) + if LeftInfo.IsBitField: + Result = CTypeInfo() + Result.BaseType = LeftInfo.BaseType if LeftInfo.BaseType else t.CInt() + Result.IsBitField = True + Result.BitWidth = LeftInfo.BitWidth + return Result + if RightInfo.IsBitField: + Result = CTypeInfo() + Result.BaseType = RightInfo.BaseType if RightInfo.BaseType else t.CInt() + Result.IsBitField = True + Result.BitWidth = RightInfo.BitWidth + return Result + + # 处理字节序类型 (t.BigEndian, t.LittleEndian) + # 合并两侧:保留非字节序侧的实际类型(如 CUInt64T),取字节序侧的 ByteOrder + if LeftInfo.ByteOrder or RightInfo.ByteOrder: + Result = CTypeInfo() + ByteOrderSide: CTypeInfo = LeftInfo if LeftInfo.ByteOrder else RightInfo + OtherSide: CTypeInfo = RightInfo if LeftInfo.ByteOrder else LeftInfo + if OtherSide.BaseType and (not isinstance(OtherSide.BaseType, (t._CTypedef,)) or OtherSide.PtrCount > 0): + Result.BaseType = OtherSide.BaseType + elif ByteOrderSide.BaseType and (not isinstance(ByteOrderSide.BaseType, (t._CTypedef,)) or ByteOrderSide.PtrCount > 0): + Result.BaseType = ByteOrderSide.BaseType + else: + Result.BaseType = t.CInt() + Result.ByteOrder = LeftInfo.ByteOrder or RightInfo.ByteOrder + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + return Result + + if LeftInfo.IsFuncPtr or RightInfo.IsFuncPtr: + Result = CTypeInfo() + FuncPtrSide = LeftInfo if LeftInfo.IsFuncPtr else RightInfo + Result.IsFuncPtr = True + Result.FuncPtrParams = list(FuncPtrSide.FuncPtrParams) + Result.FuncPtrReturn = FuncPtrSide.FuncPtrReturn + if LeftInfo.Storage: + Result.Storage = LeftInfo.Storage + elif RightInfo.Storage: + Result.Storage = RightInfo.Storage + return Result + + if LeftInfo.IsTypedef and RightInfo.BaseType: + if LeftInfo.BaseType and (not isinstance(LeftInfo.BaseType, (t._CTypedef,)) or LeftInfo.PtrCount > 0): + Result = LeftInfo.Copy() + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if RightInfo.Storage: + Result.Storage = RightInfo.Storage + return Result + return RightInfo + if RightInfo.IsTypedef and LeftInfo.BaseType: + if RightInfo.BaseType and (not isinstance(RightInfo.BaseType, (t._CTypedef,)) or RightInfo.PtrCount > 0): + Result = RightInfo.Copy() + Result.PtrCount = max(LeftInfo.PtrCount, RightInfo.PtrCount) + if LeftInfo.Storage: + Result.Storage = LeftInfo.Storage + return Result + return LeftInfo + + if LeftInfo.BaseType: + return LeftInfo + elif RightInfo.BaseType: + return RightInfo + return CTypeInfo() + + @staticmethod + def _from_node_subscript(Node: ast.Subscript, SymbolTable: dict | SymbolTable) -> CTypeInfo: + """处理 ast.Subscript 节点""" + base: ast.AST = Node.value + if isinstance(base, ast.Attribute): + if isinstance(base.value, ast.Name) and IsTModule(base.value.id, SymbolTable) and base.attr == 'Bit': + Result: CTypeInfo = CTypeInfo() + Result.BaseType = t.CInt() + Result.IsBitField = True + if isinstance(Node.slice, ast.Constant) and isinstance(Node.slice.value, int): + Result.BitWidth = Node.slice.value + else: + Result.BitWidth = 1 + return Result + if IsListAnnotation(Node): + slice_node: ast.AST = Node.slice + elts: list[ast.AST] = [] + if isinstance(slice_node, ast.Tuple): + elts = slice_node.elts + elif isinstance(slice_node, (ast.Attribute, ast.Name, ast.Subscript)): + elts = [slice_node] + if elts: + ElemInfo: CTypeInfo = TypeAnnotationResolver.from_node(elts[0], SymbolTable) + if ElemInfo and ElemInfo.BaseType: + Result: CTypeInfo = CTypeInfo() + Result.BaseType = ElemInfo.BaseType + Result.PtrCount = ElemInfo.PtrCount + Result.ArrayDims = list(ElemInfo.ArrayDims) + if len(elts) >= 2: + count_val: int | None = TypeAnnotationResolver.try_eval_const_expr(elts[1], SymbolTable) + if count_val is not None and isinstance(count_val, int) and count_val > 0: + Result.ArrayDims.insert(0, str(count_val)) + else: + Result.PtrCount += 1 + if ElemInfo.IsPtr and not ElemInfo.ArrayDims: + Result.PtrCount = max(Result.PtrCount, 1) + return Result + if isinstance(base, ast.Attribute): + parts: list[str] = [] + current: ast.AST = base + while isinstance(current, ast.Attribute): + parts.insert(0, current.attr) + current = current.value + if isinstance(current, ast.Name): + parts.insert(0, current.id) + if parts and IsTModule(parts[0], SymbolTable) and parts[-1] == t.CPtr.__name__: + Result: CTypeInfo = CTypeInfo() + Result.BaseType = t.CVoid() + Result.PtrCount = 1 + slice_node: ast.AST = Node.slice + if isinstance(slice_node, ast.Subscript): + InnerInfo: CTypeInfo = TypeAnnotationResolver.from_node(slice_node, SymbolTable) + if InnerInfo: + if InnerInfo.PtrCount > 0: + Result.PtrCount += InnerInfo.PtrCount + if InnerInfo.BaseType and not isinstance(InnerInfo.BaseType, t.CVoid): + Result.BaseType = InnerInfo.BaseType + elif isinstance(slice_node, ast.Attribute): + SliceInfo: CTypeInfo = TypeAnnotationResolver.from_node(slice_node, SymbolTable) + if SliceInfo: + if SliceInfo.IsPtr: + Result.PtrCount += SliceInfo.PtrCount + elif SliceInfo.BaseType and not isinstance(SliceInfo.BaseType, t.CVoid): + Result.BaseType = SliceInfo.BaseType + elif isinstance(slice_node, ast.Name): + SliceType: type | None = getattr(t, slice_node.id, None) + if SliceType == t.CPtr: + Result.PtrCount += 1 + else: + SliceInfo = TypeAnnotationResolver.from_node(slice_node, SymbolTable) + if SliceInfo and SliceInfo.BaseType and not isinstance(SliceInfo.BaseType, t.CVoid): + Result.BaseType = SliceInfo.BaseType + return Result + if parts and IsTModule(parts[0], SymbolTable) and parts[-1] == 'Callable': + Result = CTypeInfo() + Result.IsFuncPtr = True + slice_node = Node.slice + if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) == 2: + params_list = slice_node.elts[0] + return_node = slice_node.elts[1] + ParamTypes = [] + if isinstance(params_list, ast.List): + for elt in params_list.elts: + ParamTypeInfo = TypeAnnotationResolver.from_node(elt, SymbolTable) + if ParamTypeInfo: + ParamTypes.append(('', ParamTypeInfo)) + if not ParamTypes: + ParamTypes.append(('', TypeAnnotationResolver.from_type_name('void'))) + Result.FuncPtrParams = ParamTypes + ReturnTypeInfo = TypeAnnotationResolver.from_node(return_node, SymbolTable) + Result.FuncPtrReturn = ReturnTypeInfo if ReturnTypeInfo else CTypeInfo.VoidTypeInfo() + return Result + return CTypeInfo() + + @staticmethod + def _from_node_attribute(Node: ast.Attribute, SymbolTable: dict | SymbolTable) -> CTypeInfo: + """处理 ast.Attribute 节点""" + ModuleParts: list[str] = [] + Current: ast.AST = Node + while isinstance(Current, ast.Attribute): + ModuleParts.insert(0, Current.attr) + Current = Current.value + + if isinstance(Current, ast.Name): + ModuleParts.insert(0, Current.id) + + TypeName: str + ModulePath: str | None + if len(ModuleParts) >= 2: + TypeName = ModuleParts[-1] + ModulePath = '.'.join(ModuleParts[:-1]) + elif len(ModuleParts) == 1: + TypeName = ModuleParts[0] + ModulePath = None + else: + return CTypeInfo() + + # 解析 import 别名: 如 import vpsdk.window as window -> window -> vpsdk.window + if ModulePath: + resolved: bool = False + import_aliases: dict = SymbolTable.import_aliases + if ModulePath in import_aliases: + ModulePath = import_aliases[ModulePath] + resolved = True + if not resolved and ModulePath in SymbolTable: + entry: CTypeInfo = SymbolTable[ModulePath] + if isinstance(entry, CTypeInfo) and entry.IsModuleAlias: + resolved_name = entry.ResolvedModule + if resolved_name: + ModulePath = resolved_name + + if ModulePath and IsTModulePath(ModulePath): + TypeClass: type | None = CTypeHelper.GetTModuleCType(TypeName) + if TypeClass is None: + TypeClass = getattr(t, TypeName, None) + if TypeClass is not None and TypeClass.HasPosition(t.CType.POINTER): + Info: CTypeInfo = CTypeInfo() + Info.PtrCount = 1 + if TypeClass == t.CArrayPtr: + Info.IsArrayPtr = True + Info.BaseType = t.CVoid + return Info + if TypeClass is not None and TypeClass.IsStorageClass(): + Info: CTypeInfo = CTypeInfo() + Info.Storage = TypeClass() + if TypeClass == t.State: + Info.IsState = True + Info.BaseType = t.CVoid() + return Info + if TypeClass is not None and TypeClass.IsTypeQualifier(): + Info: CTypeInfo = CTypeInfo() + if TypeClass == t.CConst: + Info.DataConst = True + elif TypeClass == t.CVolatile: + Info.DataVolatile = True + return Info + if TypeClass is not None and TypeClass in (t.BigEndian, t.LittleEndian): + Result: CTypeInfo = CTypeInfo() + Result.BaseType = t.CInt() + Result.ByteOrder = 'big' if TypeClass == t.BigEndian else 'little' + return Result + if (TypeClass is not None + and isinstance(TypeClass, type) + and issubclass(TypeClass, t.CType) + and TypeClass is not t.CType + and TypeClass.HasPosition(t.CType.BASE)): + if TypeClass == t.State: + Result: CTypeInfo = CTypeInfo() + Result.IsState = True + Result.BaseType = t.CVoid() + return Result + Inst: t.CType = TypeClass() + Result: CTypeInfo = CTypeInfo() + Result.BaseType = TypeClass + Result.Name = type(Inst).__name__ + if hasattr(Inst, 'IsSigned'): + Result.IsSigned = Inst.IsSigned + return Result + CNAME: str | None = CTypeHelper.GetCName(TypeName) + if CNAME: + return TypeAnnotationResolver.from_type_name(CNAME) + + # 处理字节序类型 + if TypeName == 'BigEndian': + Result = CTypeInfo() + Result.BaseType = t.CInt() + Result.ByteOrder = 'big' + return Result + if TypeName == 'LittleEndian': + Result = CTypeInfo() + Result.BaseType = t.CInt() + Result.ByteOrder = 'little' + return Result + + FullName: str = f"{ModulePath}.{TypeName}" if ModulePath else TypeName + + if TypeName in SymbolTable: + Entry: CTypeInfo = SymbolTable[TypeName] + if Entry and Entry.IsTypedef: + Resolved: CTypeInfo = Entry.Copy() + if Resolved.BaseType is None: + Resolved.BaseType = t._CTypedef(TypeName) + return Resolved + if Entry and Entry.IsEnum: + Result: CTypeInfo = CTypeInfo() + Result.BaseType = t.CInt() + Result.IsEnum = True + Result.Name = TypeName + return Result + if Entry and Entry.IsExceptionClass: + Result: CTypeInfo = CTypeInfo() + Result.BaseType = t.CInt() + Result.IsExceptionClass = True + Result.Name = TypeName + return Result + if Entry: + Result: CTypeInfo = Entry.Copy() + if Result.BaseType is None and (Result.IsStruct or Result.IsCpythonObject or Result.Name): + Result.BaseType = t.CStruct(name=TypeName) + Result.IsStruct = True + return Result + return CTypeInfo() + + if FullName in SymbolTable: + Info: CTypeInfo = SymbolTable[FullName] + if Info and Info.IsTypedef: + # 优先用 BaseType 解析(如 VOIDPTR 已解析为 BaseType=CVoid, PtrCount=1) + if Info.BaseType and (not isinstance(Info.BaseType, (t._CTypedef,)) or Info.PtrCount > 0): + Result = Info.Copy() + Result.IsTypedef = True + Result.Name = FullName + return Result + # 再用 OriginalType 解析(字符串如 'void *',或 CTypeInfo) + if Info.OriginalType: + if isinstance(Info.OriginalType, CTypeInfo) and Info.OriginalType.IsFuncPtr: + Result = CTypeInfo() + Result.IsFuncPtr = True + Result.FuncPtrReturn = Info.OriginalType.FuncPtrReturn or CTypeInfo.VoidTypeInfo() + Result.FuncPtrParams = list(Info.OriginalType.FuncPtrParams) if Info.OriginalType.FuncPtrParams else [] + Result.IsTypedef = True + Result.Name = FullName + return Result + elif isinstance(Info.OriginalType, CTypeInfo): + Resolved: CTypeInfo = Info.OriginalType.Copy() + elif isinstance(Info.OriginalType, str) and Info.OriginalType == 'Callable': + Result = CTypeInfo() + Result.IsFuncPtr = True + Result.FuncPtrReturn = CTypeInfo.VoidTypeInfo() + Result.FuncPtrParams = [] + Result.IsTypedef = True + Result.Name = FullName + return Result + elif isinstance(Info.OriginalType, str): + Resolved = TypeAnnotationResolver.from_type_name(Info.OriginalType) + else: + Resolved = Info.OriginalType + if Resolved and Resolved.BaseType: + Resolved.IsTypedef = True + Resolved.Name = FullName + return Resolved + # 回退:保持原逻辑但设置 Name = FullName(供后续 TypeConvert 查找) + Result: CTypeInfo = CTypeInfo() + Result.BaseType = t._CTypedef(TypeName) + Result.IsTypedef = True + Result.Name = FullName + return Result + if Info: + Result: CTypeInfo = Info.Copy() + if Result.BaseType is None and (Result.IsStruct or Result.IsCpythonObject or Result.Name): + Result.BaseType = t.CStruct(name=TypeName) + Result.IsStruct = True + return Result + return CTypeInfo() + + return CTypeInfo() diff --git a/lib/includes/c.py b/lib/includes/c.py index c24a3db..43b07d8 100644 --- a/lib/includes/c.py +++ b/lib/includes/c.py @@ -1,722 +1,722 @@ -# C语法定义模块 -from __future__ import annotations - -import ast -import logging -from typing import Any, Optional - -from . import t -from lib.constants.config import mode as _config_mode - -def _to_str(node: Any) -> str: - if node is None: - return '' - if isinstance(node, str): - return node - if isinstance(node, list): - return ' && '.join([_to_str(n) for n in node]) - NodeType: str = type(node).__name__ - if NodeType == 'Constant': - return node.value - elif NodeType == 'ID': - return node.name - elif NodeType == 'BinaryOp': - left: str = _to_str(node.left) - right: str = _to_str(node.right) - return f'{left} {node.op} {right}' - elif NodeType == 'UnaryOp': - expr: str = _to_str(node.expr) - return f'{node.op}{expr}' - else: - return repr(node) - -class Asm: - @staticmethod - def _parse_asm_descr(expr: ast.AST) -> str: - """递归解析AST节点,确保获取t.ASM_DESCR的实际值,支持|组合 - 处理场景: - 1. t.ASM_DESCR.XXX → 取属性值 - 2. t.ASM_DESCR.XXX | t.ASM_DESCR.YYY → 拼接两个值 - 3. 常量字符串 → 直接返回 - """ - # 场景1:位或组合(XXX | YYY) - if isinstance(expr, ast.BinOp): - left_val: str = Asm._parse_asm_descr(expr.left) - right_val: str = Asm._parse_asm_descr(expr.right) - return left_val + right_val - - # 场景2:t.ASM_DESCR.XXX 多层属性访问 - elif isinstance(expr, ast.Attribute): - # 第一步:判断是否是 t.ASM_DESCR 的属性 - if isinstance(expr.value, ast.Attribute): - # 内层是 t.ASM_DESCR - if (isinstance(expr.value.value, ast.Name) and - expr.value.value.id == 't' and - expr.value.attr == 'ASM_DESCR'): - # 取 t.ASM_DESCR.XXX 的实际值 - AttrName: str = expr.attr - if hasattr(t.ASM_DESCR, AttrName): - return getattr(t.ASM_DESCR, AttrName, "") - - # 兼容 t.XXX 简化写法(如果有的话) - elif isinstance(expr.value, ast.Name) and expr.value.id == 't': - AttrName: str = expr.attr - if hasattr(t.ASM_DESCR, AttrName): - return getattr(t.ASM_DESCR, AttrName, "") - - # 场景3:直接传常量(如 "r"、"cc") - elif isinstance(expr, ast.Constant): - return expr.value - - # 其他场景返回空 - return "" - - @staticmethod - def _extract_val_expr(translator: Any, expr_node: ast.AST) -> str: - """从AST表达式节点提取值表达式的字符串形式""" - val_ExprNode: Any = translator.HandleExpr(expr_node)[0] - if isinstance(val_ExprNode, str): - return val_ExprNode - try: - return str(val_ExprNode) - except Exception as _e: - if _config_mode == "strict": - logging.warning(f"异常被忽略: {_e}") - return '' - - @staticmethod - def _parse_asm_template(translator: Any, args: list[ast.AST]) -> tuple[str, list[tuple[str, str]], list[tuple[str, str]], int]: - """解析f-string或常量模板字符串,返回(asm_code, output_ops, input_ops, operand_seq)""" - output_ops: list[tuple[str, str]] = [] - input_ops: list[tuple[str, str]] = [] - operand_seq: int = 0 - asm_code: str = "" - first_arg: ast.AST = args[0] - - if isinstance(first_arg, ast.JoinedStr): - asm_parts: list[str] = [] - for part in first_arg.values: - if isinstance(part, ast.Constant): - asm_parts.append(part.value) - elif isinstance(part, ast.FormattedValue): - expr: ast.AST = part.value - if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute) and expr.func.value.id == 'c': - # 解析内联的AsmInp/AsmOut - call_node: ast.Call = expr - val_expr: str = Asm._extract_val_expr(translator, call_node.args[0]) if len(call_node.args)>=1 else "" - constraint: str = Asm._parse_asm_descr(call_node.args[1]) if len(call_node.args)>=2 else "" - - if call_node.func.attr == 'AsmOut': - output_ops.append((val_expr, constraint)) - asm_parts.append(f"%{operand_seq}") - operand_seq += 1 - elif call_node.func.attr == 'AsmInp': - input_ops.append((val_expr, constraint)) - asm_parts.append(f"%{operand_seq}") - operand_seq += 1 - else: - asm_parts.append(translator.HandleExpr(expr)[0]) - asm_code = ''.join(asm_parts) - elif isinstance(first_arg, ast.Constant): - asm_code = first_arg.value - - return asm_code, output_ops, input_ops, operand_seq - - @staticmethod - def _parse_asm_operands(translator: Any, args: list[ast.AST], keywords: list[ast.keyword], output_ops: list[tuple[str, str]], input_ops: list[tuple[str, str]], operand_seq: int) -> tuple[list[tuple[str, str]], list[tuple[str, str]], int]: - """解析位置参数和关键字参数中的输出/输入操作数""" - - def parse_operand(arg: ast.AST) -> Optional[tuple[str, str, str]]: - """解析 AsmInp/AsmOut 参数""" - if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Attribute) and arg.func.value.id == 'c': - call_node: ast.Call = arg - val_expr: str = Asm._extract_val_expr(translator, call_node.args[0]) if len(call_node.args)>=1 else "" - constraint: str = Asm._parse_asm_descr(call_node.args[1]) if len(call_node.args)>=2 else "" - - if call_node.func.attr == 'AsmOut': - return ('out', val_expr, constraint) - elif call_node.func.attr == 'AsmInp': - return ('in', val_expr, constraint) - return None - - # 处理位置参数中的操作数 - for arg in args[1:]: - result: Optional[tuple[str, str, str]] = parse_operand(arg) - if result: - direction, val_expr, constraint = result - if direction == 'out': - output_ops.append((val_expr, constraint)) - operand_seq += 1 - elif direction == 'in': - input_ops.append((val_expr, constraint)) - operand_seq += 1 - - # 处理关键字参数中的操作数 - for kw in keywords: - if kw.arg == 'out': - # 处理 out 关键字参数 (输出操作数) - if isinstance(kw.value, ast.List): - for elt in kw.value.elts: - result = parse_operand(elt) - if result and result[0] == 'out': - output_ops.append((result[1], result[2])) - operand_seq += 1 - elif isinstance(kw.value, ast.Call): - result = parse_operand(kw.value) - if result and result[0] == 'out': - output_ops.append((result[1], result[2])) - operand_seq += 1 - elif kw.arg == 'inp' or kw.arg == 'inputs': - # 处理 inp/inputs 关键字参数 (输入操作数,追加到f-string中已有输入之后) - if isinstance(kw.value, ast.List): - for elt in kw.value.elts: - if isinstance(elt, ast.Tuple): - # 处理列表中的 (value, constraint) 元组格式 - if len(elt.elts) >= 2: - val_expr: str = Asm._extract_val_expr(translator, elt.elts[0]) if len(elt.elts) >= 1 else "" - constraint: str = Asm._parse_asm_descr(elt.elts[1]) - input_ops.append((val_expr, constraint)) - operand_seq += 1 - else: - result = parse_operand(elt) - if result and result[0] == 'in': - input_ops.append((result[1], result[2])) - operand_seq += 1 - elif isinstance(kw.value, ast.Call): - result = parse_operand(kw.value) - if result and result[0] == 'in': - input_ops.append((result[1], result[2])) - operand_seq += 1 - elif isinstance(kw.value, ast.Tuple): - # 处理 (value, constraint) 元组格式 - if len(kw.value.elts) >= 2: - val_expr: str = Asm._extract_val_expr(translator, kw.value.elts[0]) if len(kw.value.elts) >= 1 else "" - constraint: str = Asm._parse_asm_descr(kw.value.elts[1]) - input_ops.append((val_expr, constraint)) - operand_seq += 1 - - return output_ops, input_ops, operand_seq - - @staticmethod - def _parse_asm_clobbers(args: list[ast.AST], keywords: list[ast.keyword]) -> list[str]: - """解析位置参数和关键字参数中的破坏列表""" - clobbers: list[str] = [] - - # 处理位置参数中的破坏列表 - for arg in args[1:]: - if isinstance(arg, ast.List): - # 解析破坏列表(支持|组合) - for elt in arg.elts: - clobber_val: str = Asm._parse_asm_descr(elt) - if clobber_val: - clobbers.append(clobber_val) - - # 处理关键字参数中的破坏列表 - for kw in keywords: - if kw.arg == 'op': - # 处理 op 关键字参数 (clobber,破坏列表) - if isinstance(kw.value, ast.List): - for elt in kw.value.elts: - clobber_val: str = Asm._parse_asm_descr(elt) - if clobber_val: - clobbers.append(clobber_val) - elif kw.arg == 'clobber': - # 处理 clobber 关键字参数 - if isinstance(kw.value, ast.List): - for elt in kw.value.elts: - clobber_val: str = Asm._parse_asm_descr(elt) - if clobber_val: - clobbers.append(clobber_val) - - return clobbers - - @staticmethod - def _generate_asm_code(asm_code: str, output_ops: list[tuple[str, str]], input_ops: list[tuple[str, str]], clobbers: list[str], asm_format: str) -> list[str]: - """格式化汇编代码并生成最终的__asm__代码字符串""" - # 格式化汇编代码 - asm_lines: list[str] = [line.strip() for line in asm_code.split('\n') if line.strip()] - formatted_asm: str = '\n '.join([f'"{line}\\n"' for line in asm_lines]) - - # 拼接约束字符串 - # 输出约束:如果约束已包含 = 或 +,直接使用;否则添加 = - def format_constraint(constraint: str, is_output: bool = True) -> str: - if not constraint: - return "" - # 如果约束已包含修饰符,直接返回 - if '=' in constraint or '+' in constraint: - return constraint - # 否则添加适当的修饰符 - return ('=' if is_output else '') + constraint - - out_const: str = ', '.join([f'"{format_constraint(c, True)}"({v})' for v, c in output_ops]) if output_ops else "" - in_const: str = ', '.join([f'"{format_constraint(c, False)}"({v})' for v, c in input_ops]) if input_ops else "" - clobber_const: str = ', '.join([f'"{x}"' for x in clobbers]) if clobbers else "" - - # 构建约束部分:确保冒号格式正确 - constraint_parts: list[str] = [] - # 输出约束 - if output_ops: - constraint_parts.append(f': {out_const}') - elif input_ops or clobbers: - constraint_parts.append(':') - - # 输入约束 - if input_ops: - constraint_parts.append(f': {in_const}') - elif clobbers: - constraint_parts.append(':') - - # 破坏列表 - if clobbers: - constraint_parts.append(f': {clobber_const}') - - constraint_str: str = ' '.join(constraint_parts) - - # 生成最终代码 - if asm_format == 'ARM': - # ARM 使用 .arch 指令和不同的内联汇编语法 - final_asm: str = f'__asm__ __volatile__ (\n {formatted_asm} {constraint_str});' - elif asm_format == 'AT&T': - # AT&T 语法不需要额外标记,GCC 默认就是 AT&T - final_asm = f'__asm__ __volatile__ (\n {formatted_asm} {constraint_str});' - else: - # Intel 语法需要 .intel_syntax 指令 - final_asm = f'__asm__ __volatile__ (".intel_syntax noprefix\\n\\t"\n {formatted_asm} ".att_syntax prefix" {constraint_str});' - return [final_asm] - - @staticmethod - def HandleCall(translator: Any, args: list[ast.AST], keywords: list[ast.keyword]) -> list[str]: - if not args: - return ['__asm__ volatile ("nop");'] - - # 解析模板 - asm_code: str - output_ops: list[tuple[str, str]] - input_ops: list[tuple[str, str]] - operand_seq: int - asm_code, output_ops, input_ops, operand_seq = Asm._parse_asm_template(translator, args) - - # 解析操作数 - output_ops, input_ops, operand_seq = Asm._parse_asm_operands( - translator, args, keywords, output_ops, input_ops, operand_seq) - - # 解析破坏列表 - clobbers: list[str] = Asm._parse_asm_clobbers(args, keywords) - - # 解析汇编格式 - asm_format: str = 'Intel' - for kw in keywords: - if kw.arg == 'format': - if isinstance(kw.value, ast.Constant) and isinstance(kw.value.value, str): - asm_format = kw.value.value - - # 生成最终代码 - return Asm._generate_asm_code(asm_code, output_ops, input_ops, clobbers, asm_format) - -class AsmInp: - def __init__(self, value: Any, constraint: Any) -> None: - self.value: Any = value - self.constraint: Any = constraint - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[Any]: - return [] - -class AsmOut: - def __init__(self, value: Any, constraint: Any) -> None: - self.value: Any = value - self.constraint: Any = constraint - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[Any]: - return [] - -class NoBreak: - """ switch 分支无break """ - pass - -class Break: - """ switch 分支提前break """ - pass - -class Load: - """解引用a写入b,等价于 *b = *a,无拷贝副作用""" - def __init__(self, src: Any, dst: Any) -> None: - self.src: Any = src - self.dst: Any = dst - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - if len(args) >= 2: - src: Any = translator.HandleExpr(args[0])[0] - dst: Any = translator.HandleExpr(args[1])[0] - return [f'*({dst}) = *({src})'] - return [] - - -class Addr: - """取地址""" - def __init__(self, addr: Any) -> None: - self.addr: Any = addr - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.Addr() 调用""" - if args: - expr: Any = translator.HandleExpr(args[0])[0] - if isinstance(expr, str): - return [f'&{expr}'] - return [f'&{_to_str(expr)}'] - return ['0'] - - -class Deref: - """解引用""" - def __init__(self, ptr: Any) -> None: - self.ptr: Any = ptr - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.Deref() 调用""" - if args: - expr: Any = translator.HandleExpr(args[0])[0] - if hasattr(expr, 'op') and expr.op == '*': - return [expr] - return [f'*({_to_str(expr)})'] - return ['0'] - - -class DerefAs: - """解引用写入,等价于 *ptr = value""" - def __init__(self, ptr: Any, value: Any) -> None: - self.ptr: Any = ptr - self.value: Any = value - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.DerefAs() 调用""" - if len(args) >= 2: - ptr: Any = translator.HandleExpr(args[0])[0] - val: Any = translator.HandleExpr(args[1])[0] - return [f'*({_to_str(ptr)}) = {_to_str(val)}'] - return [] - - -class Set: - """设置值""" - def __init__(self, key: Any, value: Any) -> None: - self.key: Any = key - self.value: Any = value - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.Set() 调用""" - if len(args) >= 2: - target: Any = translator.HandleExpr(args[0])[0] - value: Any = translator.HandleExpr(args[1])[0] - return [f'{_to_str(target)} = {_to_str(value)}'] - return [] - - -class CReturn: - """多返回值装饰器 - - 用于实现函数多返回值,通过匿名结构体返回实现。 - 例如:@c.CReturn(t.CInt, t.CInt) 表示函数返回两个 int 值。 - 等价于 -> tuple[t.CInt, t.CInt] 返回类型注解。 - - 规则: - 1. CReturn 中有几个类型就说明要返回几个值 - 2. 函数返回类型为匿名结构体 { type1, type2, ... } - 3. return 语句使用 insert_value 构建结构体 - 4. 调用处使用 extract_value 提取各字段 - """ - def __init__(self, *ReturnTypes: Any) -> None: - self.ReturnTypes: tuple[Any, ...] = ReturnTypes - - def __call__(self, func: Any) -> Any: - """装饰器调用""" - # 将返回类型信息附加到函数上 - func._CreturnTypes = self.ReturnTypes - return func - - -class CDefine: - """#define 宏定义""" - def __init__(self, name: Any, value: Any) -> None: - self.name: Any = name - self.value: Any = value - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.CDefine() 调用""" - if len(args) >= 1: - if isinstance(args[0], ast.Constant): - name: Any = args[0].value - else: - name = 'MACRO' - if len(args) >= 2: - value: Any = translator.HandleExpr(args[1])[0] - return ['#define ' + str(name) + ' ' + _to_str(value)] - return ['#define ' + str(name)] - return [] - - -class CIfndef: - """#ifndef 条件编译""" - def __init__(self, condition: Any) -> None: - self.condition: Any = condition - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.CIfndef() 调用""" - if args: - condition: Any = translator.HandleExpr(args[0])[0] - return ['#ifndef ' + _to_str(condition)] - return ['#if 0'] - -class CIfdef: - """#ifdef 条件编译""" - def __init__(self, condition: Any) -> None: - self.condition: Any = condition - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.CIfdef() 调用""" - if args: - condition: Any = translator.HandleExpr(args[0])[0] - return ['#ifdef ' + _to_str(condition)] - return ['#if 0'] - -class CError: - """#error 错误信息""" - def __init__(self, condition: Any) -> None: - self.condition: Any = condition - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.CError() 调用""" - if args: - # 如果是字符串常量,保留引号 - if isinstance(args[0], ast.Constant) and isinstance(args[0].value, str): - return ['#error "' + args[0].value + '"'] - else: - condition: Any = translator.HandleExpr(args[0])[0] - return ['#error ' + _to_str(condition)] - return ['#error "Error: Condition is not met."'] - - -class TokenPast: - """## 连接符""" - def __init__(self, left: Any, right: Any) -> None: - self.left: Any = left - self.right: Any = right - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[Any]: - """处理 c.TokenPast() 调用""" - if len(args) >= 2: - # 处理左操作数 - 去掉引号 - if isinstance(args[0], ast.Constant): - left: str = str(args[0].value) - elif isinstance(args[0], ast.Name): - left = args[0].id - else: - left = _to_str(translator.HandleExpr(args[0])[0]) - - # 处理右操作数 - 去掉引号 - if isinstance(args[1], ast.Constant): - right: str = str(args[1].value) - elif isinstance(args[1], ast.Name): - right = args[1].id - else: - right = _to_str(translator.HandleExpr(args[1])[0]) - - # 返回字符串,但用特殊标记包装,让 _AstNodeToStr 能正确处理 - result: str = left + ' ## ' + right - # 使用一个特殊的类来包装结果,让 _AstNodeToStr 直接返回其值 - class TokenPastResult: - def __init__(self, value: str) -> None: - self.value: str = value - def __str__(self) -> str: - return self.value - return [TokenPastResult(result)] - return [''] - - -class CIf: - """#if 条件编译""" - def __init__(self, condition: Any) -> None: - self.condition: Any = condition - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.CIf() 调用""" - if args: - condition: Any = translator.HandleExpr(args[0])[0] - return ['#if ' + _to_str(condition)] - return ['#if 0'] - - -class CElif: - """#elif 条件编译""" - def __init__(self, condition: Any) -> None: - self.condition: Any = condition - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.CElif() 调用""" - if args: - condition: Any = translator.HandleExpr(args[0])[0] - return ['#elif ' + _to_str(condition)] - return ['#else'] - - -class CElse: - """#else 条件编译""" - def __init__(self) -> None: - pass - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.CElse() 调用""" - return ['#else'] - - -class CEndif: - """#endif 条件编译""" - def __init__(self) -> None: - pass - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.CEndif() 调用""" - return ['#endif'] - - -class CUndef: - """#undef 取消宏定义""" - def __init__(self, name: Any) -> None: - self.name: Any = name - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.CUndef(name) 调用""" - if args: - arg: Any = args[0] - if isinstance(arg, str): - name: str = arg - elif isinstance(arg, ast.Name): - name = arg.id - elif isinstance(arg, ast.Constant): - name = str(arg.value) - else: - name = str(arg) - return [f'#undef {name}'] - return ['#undef'] - - -class LLVMIR: - """内联 LLVM IR(无返回值,直接嵌入原始 IR 文本) - - 用法: c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}") - 或: c.LLVMIR(f"{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}") - - c.LInp(expr) - 输入操作数,替换为 expr 的 LLVM 值引用文本(%x 或常量) - c.LOut(expr) - 输出操作数:为 expr 变量分配唯一 SSA 寄存器 %llvmirN, - 模板嵌入后自动追加 store 写回变量 alloca - """ - def __init__(self, ir_template: Any, ret_type: Any = None) -> None: - self.ir_template: Any = ir_template - self.ret_type: Any = ret_type - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - return ['/* LLVMIR */'] - - -class LInp: - """LLVM IR 输入操作数标记 - - 用法: c.LInp(expr) - 标记 expr 为输入操作数 - 在 c.LLVMIR 的 f-string 中使用,翻译后替换为 %N 形式的操作数引用 - """ - def __init__(self, value: Any) -> None: - self.value: Any = value - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[Any]: - return [] - - -class LOut: - """LLVM IR 输出操作数标记 - - 用法: c.LOut(expr) - 标记 expr 为输出操作数 - 在 c.LLVMIR 的 f-string 中使用,翻译后替换为 %N 形式的操作数引用 - """ - def __init__(self, value: Any) -> None: - self.value: Any = value - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[Any]: - return [] - - -class CPragma: - """#pragma 指令 - - 用于生成 C 语言的 #pragma 指令。 - 例如:c.CPragma("GCC diagnostic push") 生成 #pragma GCC diagnostic push - """ - def __init__(self, directive: Any) -> None: - self.directive: Any = directive - - @staticmethod - def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: - """处理 c.CPragma() 调用""" - if args: - arg: Any = args[0] - if isinstance(arg, ast.Constant): - directive: Any = arg.value - else: - expr: Any = translator.HandleExpr(arg)[0] - directive = _to_str(expr) - return [f'#pragma {directive}'] - return ['#pragma'] - - -# C 库类字典,用于 HandleCSpecialCall -Library_C = { - 'Asm': Asm, - 'Load': Load, - 'Addr': Addr, - 'Deref': Deref, - 'Set': Set, - 'AsmInp': AsmInp, - 'AsmOut': AsmOut, - 'CDefine': CDefine, - 'CIfndef': CIfndef, - 'CIfdef': CIfdef, - 'CIf': CIf, - 'CElif': CElif, - 'CElse': CElse, - 'CEndif': CEndif, - 'CUndef': CUndef, - 'CError': CError, - 'TokenPast': TokenPast, - 'CReturn': CReturn, - 'CPragma': CPragma, - 'LLVMIR': LLVMIR, - 'LInp': LInp, - 'LOut': LOut, -} - - -class Attribute: - """函数/变量属性装饰器""" - def __init__(self, *attrs: Any) -> None: - self.attrs: tuple[Any, ...] = attrs - - def __call__(self, func: Any) -> Any: - # 将属性附加到函数上 - func._c_attributes = self.attrs - return func +# C语法定义模块 +from __future__ import annotations + +import vast as ast +import logging +from typing import Any, Optional + +from . import t +from lib.constants.config import mode as _config_mode + +def _to_str(node: Any) -> str: + if node is None: + return '' + if isinstance(node, str): + return node + if isinstance(node, list): + return ' && '.join([_to_str(n) for n in node]) + NodeType: str = type(node).__name__ + if NodeType == 'Constant': + return node.value + elif NodeType == 'ID': + return node.name + elif NodeType == 'BinaryOp': + left: str = _to_str(node.left) + right: str = _to_str(node.right) + return f'{left} {node.op} {right}' + elif NodeType == 'UnaryOp': + expr: str = _to_str(node.expr) + return f'{node.op}{expr}' + else: + return repr(node) + +class Asm: + @staticmethod + def _parse_asm_descr(expr: ast.AST) -> str: + """递归解析AST节点,确保获取t.ASM_DESCR的实际值,支持|组合 + 处理场景: + 1. t.ASM_DESCR.XXX → 取属性值 + 2. t.ASM_DESCR.XXX | t.ASM_DESCR.YYY → 拼接两个值 + 3. 常量字符串 → 直接返回 + """ + # 场景1:位或组合(XXX | YYY) + if isinstance(expr, ast.BinOp): + left_val: str = Asm._parse_asm_descr(expr.left) + right_val: str = Asm._parse_asm_descr(expr.right) + return left_val + right_val + + # 场景2:t.ASM_DESCR.XXX 多层属性访问 + elif isinstance(expr, ast.Attribute): + # 第一步:判断是否是 t.ASM_DESCR 的属性 + if isinstance(expr.value, ast.Attribute): + # 内层是 t.ASM_DESCR + if (isinstance(expr.value.value, ast.Name) and + expr.value.value.id == 't' and + expr.value.attr == 'ASM_DESCR'): + # 取 t.ASM_DESCR.XXX 的实际值 + AttrName: str = expr.attr + if hasattr(t.ASM_DESCR, AttrName): + return getattr(t.ASM_DESCR, AttrName, "") + + # 兼容 t.XXX 简化写法(如果有的话) + elif isinstance(expr.value, ast.Name) and expr.value.id == 't': + AttrName: str = expr.attr + if hasattr(t.ASM_DESCR, AttrName): + return getattr(t.ASM_DESCR, AttrName, "") + + # 场景3:直接传常量(如 "r"、"cc") + elif isinstance(expr, ast.Constant): + return expr.value + + # 其他场景返回空 + return "" + + @staticmethod + def _extract_val_expr(translator: Any, expr_node: ast.AST) -> str: + """从AST表达式节点提取值表达式的字符串形式""" + val_ExprNode: Any = translator.HandleExpr(expr_node)[0] + if isinstance(val_ExprNode, str): + return val_ExprNode + try: + return str(val_ExprNode) + except Exception as _e: + if _config_mode == "strict": + logging.warning(f"异常被忽略: {_e}") + return '' + + @staticmethod + def _parse_asm_template(translator: Any, args: list[ast.AST]) -> tuple[str, list[tuple[str, str]], list[tuple[str, str]], int]: + """解析f-string或常量模板字符串,返回(asm_code, output_ops, input_ops, operand_seq)""" + output_ops: list[tuple[str, str]] = [] + input_ops: list[tuple[str, str]] = [] + operand_seq: int = 0 + asm_code: str = "" + first_arg: ast.AST = args[0] + + if isinstance(first_arg, ast.JoinedStr): + asm_parts: list[str] = [] + for part in first_arg.values: + if isinstance(part, ast.Constant): + asm_parts.append(part.value) + elif isinstance(part, ast.FormattedValue): + expr: ast.AST = part.value + if isinstance(expr, ast.Call) and isinstance(expr.func, ast.Attribute) and expr.func.value.id == 'c': + # 解析内联的AsmInp/AsmOut + call_node: ast.Call = expr + val_expr: str = Asm._extract_val_expr(translator, call_node.args[0]) if len(call_node.args)>=1 else "" + constraint: str = Asm._parse_asm_descr(call_node.args[1]) if len(call_node.args)>=2 else "" + + if call_node.func.attr == 'AsmOut': + output_ops.append((val_expr, constraint)) + asm_parts.append(f"%{operand_seq}") + operand_seq += 1 + elif call_node.func.attr == 'AsmInp': + input_ops.append((val_expr, constraint)) + asm_parts.append(f"%{operand_seq}") + operand_seq += 1 + else: + asm_parts.append(translator.HandleExpr(expr)[0]) + asm_code = ''.join(asm_parts) + elif isinstance(first_arg, ast.Constant): + asm_code = first_arg.value + + return asm_code, output_ops, input_ops, operand_seq + + @staticmethod + def _parse_asm_operands(translator: Any, args: list[ast.AST], keywords: list[ast.keyword], output_ops: list[tuple[str, str]], input_ops: list[tuple[str, str]], operand_seq: int) -> tuple[list[tuple[str, str]], list[tuple[str, str]], int]: + """解析位置参数和关键字参数中的输出/输入操作数""" + + def parse_operand(arg: ast.AST) -> Optional[tuple[str, str, str]]: + """解析 AsmInp/AsmOut 参数""" + if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Attribute) and arg.func.value.id == 'c': + call_node: ast.Call = arg + val_expr: str = Asm._extract_val_expr(translator, call_node.args[0]) if len(call_node.args)>=1 else "" + constraint: str = Asm._parse_asm_descr(call_node.args[1]) if len(call_node.args)>=2 else "" + + if call_node.func.attr == 'AsmOut': + return ('out', val_expr, constraint) + elif call_node.func.attr == 'AsmInp': + return ('in', val_expr, constraint) + return None + + # 处理位置参数中的操作数 + for arg in args[1:]: + result: Optional[tuple[str, str, str]] = parse_operand(arg) + if result: + direction, val_expr, constraint = result + if direction == 'out': + output_ops.append((val_expr, constraint)) + operand_seq += 1 + elif direction == 'in': + input_ops.append((val_expr, constraint)) + operand_seq += 1 + + # 处理关键字参数中的操作数 + for kw in keywords: + if kw.arg == 'out': + # 处理 out 关键字参数 (输出操作数) + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + result = parse_operand(elt) + if result and result[0] == 'out': + output_ops.append((result[1], result[2])) + operand_seq += 1 + elif isinstance(kw.value, ast.Call): + result = parse_operand(kw.value) + if result and result[0] == 'out': + output_ops.append((result[1], result[2])) + operand_seq += 1 + elif kw.arg == 'inp' or kw.arg == 'inputs': + # 处理 inp/inputs 关键字参数 (输入操作数,追加到f-string中已有输入之后) + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + if isinstance(elt, ast.Tuple): + # 处理列表中的 (value, constraint) 元组格式 + if len(elt.elts) >= 2: + val_expr: str = Asm._extract_val_expr(translator, elt.elts[0]) if len(elt.elts) >= 1 else "" + constraint: str = Asm._parse_asm_descr(elt.elts[1]) + input_ops.append((val_expr, constraint)) + operand_seq += 1 + else: + result = parse_operand(elt) + if result and result[0] == 'in': + input_ops.append((result[1], result[2])) + operand_seq += 1 + elif isinstance(kw.value, ast.Call): + result = parse_operand(kw.value) + if result and result[0] == 'in': + input_ops.append((result[1], result[2])) + operand_seq += 1 + elif isinstance(kw.value, ast.Tuple): + # 处理 (value, constraint) 元组格式 + if len(kw.value.elts) >= 2: + val_expr: str = Asm._extract_val_expr(translator, kw.value.elts[0]) if len(kw.value.elts) >= 1 else "" + constraint: str = Asm._parse_asm_descr(kw.value.elts[1]) + input_ops.append((val_expr, constraint)) + operand_seq += 1 + + return output_ops, input_ops, operand_seq + + @staticmethod + def _parse_asm_clobbers(args: list[ast.AST], keywords: list[ast.keyword]) -> list[str]: + """解析位置参数和关键字参数中的破坏列表""" + clobbers: list[str] = [] + + # 处理位置参数中的破坏列表 + for arg in args[1:]: + if isinstance(arg, ast.List): + # 解析破坏列表(支持|组合) + for elt in arg.elts: + clobber_val: str = Asm._parse_asm_descr(elt) + if clobber_val: + clobbers.append(clobber_val) + + # 处理关键字参数中的破坏列表 + for kw in keywords: + if kw.arg == 'op': + # 处理 op 关键字参数 (clobber,破坏列表) + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + clobber_val: str = Asm._parse_asm_descr(elt) + if clobber_val: + clobbers.append(clobber_val) + elif kw.arg == 'clobber': + # 处理 clobber 关键字参数 + if isinstance(kw.value, ast.List): + for elt in kw.value.elts: + clobber_val: str = Asm._parse_asm_descr(elt) + if clobber_val: + clobbers.append(clobber_val) + + return clobbers + + @staticmethod + def _generate_asm_code(asm_code: str, output_ops: list[tuple[str, str]], input_ops: list[tuple[str, str]], clobbers: list[str], asm_format: str) -> list[str]: + """格式化汇编代码并生成最终的__asm__代码字符串""" + # 格式化汇编代码 + asm_lines: list[str] = [line.strip() for line in asm_code.split('\n') if line.strip()] + formatted_asm: str = '\n '.join([f'"{line}\\n"' for line in asm_lines]) + + # 拼接约束字符串 + # 输出约束:如果约束已包含 = 或 +,直接使用;否则添加 = + def format_constraint(constraint: str, is_output: bool = True) -> str: + if not constraint: + return "" + # 如果约束已包含修饰符,直接返回 + if '=' in constraint or '+' in constraint: + return constraint + # 否则添加适当的修饰符 + return ('=' if is_output else '') + constraint + + out_const: str = ', '.join([f'"{format_constraint(c, True)}"({v})' for v, c in output_ops]) if output_ops else "" + in_const: str = ', '.join([f'"{format_constraint(c, False)}"({v})' for v, c in input_ops]) if input_ops else "" + clobber_const: str = ', '.join([f'"{x}"' for x in clobbers]) if clobbers else "" + + # 构建约束部分:确保冒号格式正确 + constraint_parts: list[str] = [] + # 输出约束 + if output_ops: + constraint_parts.append(f': {out_const}') + elif input_ops or clobbers: + constraint_parts.append(':') + + # 输入约束 + if input_ops: + constraint_parts.append(f': {in_const}') + elif clobbers: + constraint_parts.append(':') + + # 破坏列表 + if clobbers: + constraint_parts.append(f': {clobber_const}') + + constraint_str: str = ' '.join(constraint_parts) + + # 生成最终代码 + if asm_format == 'ARM': + # ARM 使用 .arch 指令和不同的内联汇编语法 + final_asm: str = f'__asm__ __volatile__ (\n {formatted_asm} {constraint_str});' + elif asm_format == 'AT&T': + # AT&T 语法不需要额外标记,GCC 默认就是 AT&T + final_asm = f'__asm__ __volatile__ (\n {formatted_asm} {constraint_str});' + else: + # Intel 语法需要 .intel_syntax 指令 + final_asm = f'__asm__ __volatile__ (".intel_syntax noprefix\\n\\t"\n {formatted_asm} ".att_syntax prefix" {constraint_str});' + return [final_asm] + + @staticmethod + def HandleCall(translator: Any, args: list[ast.AST], keywords: list[ast.keyword]) -> list[str]: + if not args: + return ['__asm__ volatile ("nop");'] + + # 解析模板 + asm_code: str + output_ops: list[tuple[str, str]] + input_ops: list[tuple[str, str]] + operand_seq: int + asm_code, output_ops, input_ops, operand_seq = Asm._parse_asm_template(translator, args) + + # 解析操作数 + output_ops, input_ops, operand_seq = Asm._parse_asm_operands( + translator, args, keywords, output_ops, input_ops, operand_seq) + + # 解析破坏列表 + clobbers: list[str] = Asm._parse_asm_clobbers(args, keywords) + + # 解析汇编格式 + asm_format: str = 'Intel' + for kw in keywords: + if kw.arg == 'format': + if isinstance(kw.value, ast.Constant) and isinstance(kw.value.value, str): + asm_format = kw.value.value + + # 生成最终代码 + return Asm._generate_asm_code(asm_code, output_ops, input_ops, clobbers, asm_format) + +class AsmInp: + def __init__(self, value: Any, constraint: Any) -> None: + self.value: Any = value + self.constraint: Any = constraint + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[Any]: + return [] + +class AsmOut: + def __init__(self, value: Any, constraint: Any) -> None: + self.value: Any = value + self.constraint: Any = constraint + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[Any]: + return [] + +class NoBreak: + """ switch 分支无break """ + pass + +class Break: + """ switch 分支提前break """ + pass + +class Load: + """解引用a写入b,等价于 *b = *a,无拷贝副作用""" + def __init__(self, src: Any, dst: Any) -> None: + self.src: Any = src + self.dst: Any = dst + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + if len(args) >= 2: + src: Any = translator.HandleExpr(args[0])[0] + dst: Any = translator.HandleExpr(args[1])[0] + return [f'*({dst}) = *({src})'] + return [] + + +class Addr: + """取地址""" + def __init__(self, addr: Any) -> None: + self.addr: Any = addr + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.Addr() 调用""" + if args: + expr: Any = translator.HandleExpr(args[0])[0] + if isinstance(expr, str): + return [f'&{expr}'] + return [f'&{_to_str(expr)}'] + return ['0'] + + +class Deref: + """解引用""" + def __init__(self, ptr: Any) -> None: + self.ptr: Any = ptr + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.Deref() 调用""" + if args: + expr: Any = translator.HandleExpr(args[0])[0] + if hasattr(expr, 'op') and expr.op == '*': + return [expr] + return [f'*({_to_str(expr)})'] + return ['0'] + + +class DerefAs: + """解引用写入,等价于 *ptr = value""" + def __init__(self, ptr: Any, value: Any) -> None: + self.ptr: Any = ptr + self.value: Any = value + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.DerefAs() 调用""" + if len(args) >= 2: + ptr: Any = translator.HandleExpr(args[0])[0] + val: Any = translator.HandleExpr(args[1])[0] + return [f'*({_to_str(ptr)}) = {_to_str(val)}'] + return [] + + +class Set: + """设置值""" + def __init__(self, key: Any, value: Any) -> None: + self.key: Any = key + self.value: Any = value + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.Set() 调用""" + if len(args) >= 2: + target: Any = translator.HandleExpr(args[0])[0] + value: Any = translator.HandleExpr(args[1])[0] + return [f'{_to_str(target)} = {_to_str(value)}'] + return [] + + +class CReturn: + """多返回值装饰器 + + 用于实现函数多返回值,通过匿名结构体返回实现。 + 例如:@c.CReturn(t.CInt, t.CInt) 表示函数返回两个 int 值。 + 等价于 -> tuple[t.CInt, t.CInt] 返回类型注解。 + + 规则: + 1. CReturn 中有几个类型就说明要返回几个值 + 2. 函数返回类型为匿名结构体 { type1, type2, ... } + 3. return 语句使用 insert_value 构建结构体 + 4. 调用处使用 extract_value 提取各字段 + """ + def __init__(self, *ReturnTypes: Any) -> None: + self.ReturnTypes: tuple[Any, ...] = ReturnTypes + + def __call__(self, func: Any) -> Any: + """装饰器调用""" + # 将返回类型信息附加到函数上 + func._CreturnTypes = self.ReturnTypes + return func + + +class CDefine: + """#define 宏定义""" + def __init__(self, name: Any, value: Any) -> None: + self.name: Any = name + self.value: Any = value + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.CDefine() 调用""" + if len(args) >= 1: + if isinstance(args[0], ast.Constant): + name: Any = args[0].value + else: + name = 'MACRO' + if len(args) >= 2: + value: Any = translator.HandleExpr(args[1])[0] + return ['#define ' + str(name) + ' ' + _to_str(value)] + return ['#define ' + str(name)] + return [] + + +class CIfndef: + """#ifndef 条件编译""" + def __init__(self, condition: Any) -> None: + self.condition: Any = condition + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.CIfndef() 调用""" + if args: + condition: Any = translator.HandleExpr(args[0])[0] + return ['#ifndef ' + _to_str(condition)] + return ['#if 0'] + +class CIfdef: + """#ifdef 条件编译""" + def __init__(self, condition: Any) -> None: + self.condition: Any = condition + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.CIfdef() 调用""" + if args: + condition: Any = translator.HandleExpr(args[0])[0] + return ['#ifdef ' + _to_str(condition)] + return ['#if 0'] + +class CError: + """#error 错误信息""" + def __init__(self, condition: Any) -> None: + self.condition: Any = condition + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.CError() 调用""" + if args: + # 如果是字符串常量,保留引号 + if isinstance(args[0], ast.Constant) and isinstance(args[0].value, str): + return ['#error "' + args[0].value + '"'] + else: + condition: Any = translator.HandleExpr(args[0])[0] + return ['#error ' + _to_str(condition)] + return ['#error "Error: Condition is not met."'] + + +class TokenPast: + """## 连接符""" + def __init__(self, left: Any, right: Any) -> None: + self.left: Any = left + self.right: Any = right + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[Any]: + """处理 c.TokenPast() 调用""" + if len(args) >= 2: + # 处理左操作数 - 去掉引号 + if isinstance(args[0], ast.Constant): + left: str = str(args[0].value) + elif isinstance(args[0], ast.Name): + left = args[0].id + else: + left = _to_str(translator.HandleExpr(args[0])[0]) + + # 处理右操作数 - 去掉引号 + if isinstance(args[1], ast.Constant): + right: str = str(args[1].value) + elif isinstance(args[1], ast.Name): + right = args[1].id + else: + right = _to_str(translator.HandleExpr(args[1])[0]) + + # 返回字符串,但用特殊标记包装,让 _AstNodeToStr 能正确处理 + result: str = left + ' ## ' + right + # 使用一个特殊的类来包装结果,让 _AstNodeToStr 直接返回其值 + class TokenPastResult: + def __init__(self, value: str) -> None: + self.value: str = value + def __str__(self) -> str: + return self.value + return [TokenPastResult(result)] + return [''] + + +class CIf: + """#if 条件编译""" + def __init__(self, condition: Any) -> None: + self.condition: Any = condition + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.CIf() 调用""" + if args: + condition: Any = translator.HandleExpr(args[0])[0] + return ['#if ' + _to_str(condition)] + return ['#if 0'] + + +class CElif: + """#elif 条件编译""" + def __init__(self, condition: Any) -> None: + self.condition: Any = condition + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.CElif() 调用""" + if args: + condition: Any = translator.HandleExpr(args[0])[0] + return ['#elif ' + _to_str(condition)] + return ['#else'] + + +class CElse: + """#else 条件编译""" + def __init__(self) -> None: + pass + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.CElse() 调用""" + return ['#else'] + + +class CEndif: + """#endif 条件编译""" + def __init__(self) -> None: + pass + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.CEndif() 调用""" + return ['#endif'] + + +class CUndef: + """#undef 取消宏定义""" + def __init__(self, name: Any) -> None: + self.name: Any = name + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.CUndef(name) 调用""" + if args: + arg: Any = args[0] + if isinstance(arg, str): + name: str = arg + elif isinstance(arg, ast.Name): + name = arg.id + elif isinstance(arg, ast.Constant): + name = str(arg.value) + else: + name = str(arg) + return [f'#undef {name}'] + return ['#undef'] + + +class LLVMIR: + """内联 LLVM IR(无返回值,直接嵌入原始 IR 文本) + + 用法: c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}") + 或: c.LLVMIR(f"{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}") + + c.LInp(expr) - 输入操作数,替换为 expr 的 LLVM 值引用文本(%x 或常量) + c.LOut(expr) - 输出操作数:为 expr 变量分配唯一 SSA 寄存器 %llvmirN, + 模板嵌入后自动追加 store 写回变量 alloca + """ + def __init__(self, ir_template: Any, ret_type: Any = None) -> None: + self.ir_template: Any = ir_template + self.ret_type: Any = ret_type + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + return ['/* LLVMIR */'] + + +class LInp: + """LLVM IR 输入操作数标记 + + 用法: c.LInp(expr) - 标记 expr 为输入操作数 + 在 c.LLVMIR 的 f-string 中使用,翻译后替换为 %N 形式的操作数引用 + """ + def __init__(self, value: Any) -> None: + self.value: Any = value + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[Any]: + return [] + + +class LOut: + """LLVM IR 输出操作数标记 + + 用法: c.LOut(expr) - 标记 expr 为输出操作数 + 在 c.LLVMIR 的 f-string 中使用,翻译后替换为 %N 形式的操作数引用 + """ + def __init__(self, value: Any) -> None: + self.value: Any = value + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[Any]: + return [] + + +class CPragma: + """#pragma 指令 + + 用于生成 C 语言的 #pragma 指令。 + 例如:c.CPragma("GCC diagnostic push") 生成 #pragma GCC diagnostic push + """ + def __init__(self, directive: Any) -> None: + self.directive: Any = directive + + @staticmethod + def HandleCall(translator: Any, args: Any, keywords: Any) -> list[str]: + """处理 c.CPragma() 调用""" + if args: + arg: Any = args[0] + if isinstance(arg, ast.Constant): + directive: Any = arg.value + else: + expr: Any = translator.HandleExpr(arg)[0] + directive = _to_str(expr) + return [f'#pragma {directive}'] + return ['#pragma'] + + +# C 库类字典,用于 HandleCSpecialCall +Library_C = { + 'Asm': Asm, + 'Load': Load, + 'Addr': Addr, + 'Deref': Deref, + 'Set': Set, + 'AsmInp': AsmInp, + 'AsmOut': AsmOut, + 'CDefine': CDefine, + 'CIfndef': CIfndef, + 'CIfdef': CIfdef, + 'CIf': CIf, + 'CElif': CElif, + 'CElse': CElse, + 'CEndif': CEndif, + 'CUndef': CUndef, + 'CError': CError, + 'TokenPast': TokenPast, + 'CReturn': CReturn, + 'CPragma': CPragma, + 'LLVMIR': LLVMIR, + 'LInp': LInp, + 'LOut': LOut, +} + + +class Attribute: + """函数/变量属性装饰器""" + def __init__(self, *attrs: Any) -> None: + self.attrs: tuple[Any, ...] = attrs + + def __call__(self, func: Any) -> Any: + # 将属性附加到函数上 + func._c_attributes = self.attrs + return func diff --git a/lib/vast/ExprParser.py b/lib/vast/ExprParser.py new file mode 100644 index 0000000..6bcbd91 --- /dev/null +++ b/lib/vast/ExprParser.py @@ -0,0 +1,1453 @@ +"""vast.exprparser - Viper/Python 表达式语法分析器 + +实现与 CPython 3.12 语法规则一致的递归下降表达式解析: + +- 完整运算符优先级(lambda/条件/or/and/not/比较/位运算/移位/算术/一元/幂/await) +- 原子表达式:标识符/数字/字符串/常量/f-string/元组/列表/字典/集合 +- 推导式(list/set/dict/generator)、lambda、命名表达式(walrus) +- 调用(位置实参/关键字实参/*args/**kwargs)、属性、下标、切片 +- f-string(JoinedStr/FormattedValue,含嵌套表达式与格式说明符) + +本模块为 Mixin 设计:``Parser`` 继承 ``ExprParserMixin`` 获得表达式能力。 +所有产出节点与 CPython ``ast`` 结构完全一致,并填充 lineno/col_offset/ +end_lineno/end_col_offset 位置属性。 +""" +from __future__ import annotations + +import bisect + +from lib.vast import Nodes as N +from lib.vast.Tokenizer import ( + Token, NAME, NUMBER, STRING, FSTRING, OP, NEWLINE, NL, ENDMARKER, + Tokenizer, _STRING_PREFIX_CHARS, +) + + +def _JoinConstParts(parts: list[object]) -> str | bytes: + """拼接连续字符串字面量值(str 或 bytes,与 CPython 语义一致)。""" + if not parts: + return '' + if isinstance(parts[0], bytes): + buf: list[bytes] = [] + for p in parts: + if isinstance(p, bytes): + buf.append(p) + else: + buf.append(str(p).encode('utf-8')) + return b''.join(buf) + return ''.join(str(p) for p in parts) + + +class TokenStream: + """token 流管理基类:统一提供游标操作、位置标注工具。""" + + def __init__(self, tokens: list[Token], source: str, line_starts: list[int]) -> None: + self.Tokens: list[Token] = tokens + self.Source: str = source + self.LineStarts: list[int] = line_starts + self.Idx: int = 0 + + # ------------------------------------------------------------------ + # 游标操作 + # ------------------------------------------------------------------ + def _Peek(self, offset: int = 0) -> Token: + i: int = self.Idx + offset + if i >= len(self.Tokens): + return self.Tokens[-1] + return self.Tokens[i] + + def _Next(self) -> Token: + tok: Token = self.Tokens[self.Idx] + if self.Idx < len(self.Tokens) - 1: + self.Idx += 1 + return tok + + def _Prev(self) -> Token: + return self.Tokens[max(0, self.Idx - 1)] + + def _At(self, tok_type: str, value: str | None = None) -> bool: + tok: Token = self._Peek() + if tok.Type != tok_type: + return False + if value is not None and tok.Value != value: + return False + return True + + def _AtOp(self, value: str) -> bool: + return self._At(OP, value) + + def _AtName(self, value: str) -> bool: + return self._At(NAME, value) + + def _SkipNL(self) -> None: + """跳过括号内换行 token(NL)。""" + while self._Peek().Type == NL: + self._Next() + + def _SkipNEWLINE(self) -> None: + """跳过逻辑换行 token(NEWLINE)与空行/注释行(NL)。""" + while self._Peek().Type in (NEWLINE, NL): + self._Next() + + def _ExpectOp(self, value: str) -> Token: + tok: Token = self._Next() + if tok.Type != OP or tok.Value != value: + raise SyntaxError( + f"expected '{value}', got {tok.Type}({tok.Value!r}) " + f"at line {tok.Line}" + ) + return tok + + def _ExpectName(self, value: str | None = None) -> Token: + tok: Token = self._Next() + if tok.Type != NAME or (value is not None and tok.Value != value): + want: str = f" {value!r}" if value else '' + raise SyntaxError( + f"expected name{want}, " + f"got {tok.Type}({tok.Value!r}) at line {tok.Line}" + ) + return tok + + def _ExpectNEWLINE(self) -> None: + tok: Token = self._Next() + if tok.Type != NEWLINE: + raise SyntaxError( + f"expected newline, got {tok.Type}({tok.Value!r}) at line {tok.Line}" + ) + + # ------------------------------------------------------------------ + # 位置标注 + # ------------------------------------------------------------------ + def _FixLoc(self, node: N.AST, start_tok: Token, end_tok: Token | None = None) -> N.AST: + """为节点设置 4 个位置属性(end 缺省取前一个 token)。""" + if end_tok is None: + end_tok = self._Prev() + if 'lineno' in getattr(node, '_attributes', ()): + node.lineno = start_tok.Line + node.col_offset = start_tok.Col + node.end_lineno = end_tok.EndLine + node.end_col_offset = end_tok.EndCol + return node + + def _PosFromOffset(self, offset: int) -> tuple[int, int]: + """字符偏移 → (行号, UTF-8 字节列偏移)。""" + idx: int = bisect.bisect_right(self.LineStarts, offset) - 1 + line: int = idx + 1 + col: int = len(self.Source[self.LineStarts[idx]:offset].encode('utf-8')) + return line, col + + def _Relocate(self, tok: Token, base: int) -> None: + """将子表达式 token 按绝对偏移重定位(f-string 内部表达式用)。""" + tok.Start = base + tok.Start + tok.End = base + tok.End + line, col = self._PosFromOffset(tok.Start) + e_line, e_col = self._PosFromOffset(tok.End) + tok.Line, tok.Col, tok.EndLine, tok.EndCol = line, col, e_line, e_col + + +class ExprParserMixin(TokenStream): + """表达式解析器(Mixin,供 Parser 使用)。""" + + # ================================================================== + # 表达式顶层:lambda | 条件表达式 + # ================================================================== + def ParseExpr(self) -> N.expr: + """完整表达式:lambda 或条件表达式(含 walrus 前置)。""" + if self._AtName('lambda'): + return self._ParseLambda() + return self._ParseConditional() + + def ParseExprList(self) -> N.expr: + """testlist_star_expr:表达式或逗号分隔元组(赋值右值/return 值)。""" + start: Token = self._Peek() + first: N.expr = self.ParseExpr() + if self._AtOp(','): + elts: list[N.expr] = [first] + while self._AtOp(','): + self._Next() + self._SkipNL() + elts.append(self.ParseExpr()) + tup: N.Tuple = N.Tuple(elts=elts, ctx=N.Load()) + self._FixLoc(tup, start) + return tup + return first + + def _ParseConditional(self) -> N.expr: + """条件表达式:disjunction ('if' disjunction 'else' expression)?""" + start: Token = self._Peek() + body: N.expr = self._ParseDisjunction() + if self._AtName('if'): + self._Next() + test: N.expr = self._ParseDisjunction() + self._ExpectName('else') + orelse: N.expr = self.ParseExpr() + node: N.IfExp = N.IfExp(test=test, body=body, orelse=orelse) + self._FixLoc(node, start) + return node + return body + + # ================================================================== + # 布尔/比较 + # ================================================================== + def _ParseDisjunction(self) -> N.expr: + start: Token = self._Peek() + values: list[N.expr] = [self._ParseConjunction()] + while True: + self._SkipNL() + if self._AtName('or'): + self._Next() + values.append(self._ParseConjunction()) + continue + break + if len(values) == 1: + return values[0] + node: N.BoolOp = N.BoolOp(op=N.Or(), values=values) + self._FixLoc(node, start) + return node + + def _ParseConjunction(self) -> N.expr: + start: Token = self._Peek() + values: list[N.expr] = [self._ParseInversion()] + while True: + self._SkipNL() + if self._AtName('and'): + self._Next() + values.append(self._ParseInversion()) + continue + break + if len(values) == 1: + return values[0] + node: N.BoolOp = N.BoolOp(op=N.And(), values=values) + self._FixLoc(node, start) + return node + + def _ParseInversion(self) -> N.expr: + self._SkipNL() + if self._AtName('not'): + start: Token = self._Next() + operand: N.expr = self._ParseInversion() + node: N.UnaryOp = N.UnaryOp(op=N.Not(), operand=operand) + self._FixLoc(node, start) + return node + return self._ParseComparison() + + # 比较操作符映射 + _COMPARE_OPS: dict[str, type] = { + '<': N.Lt, '>': N.Gt, '<=': N.LtE, '>=': N.GtE, + '==': N.Eq, '!=': N.NotEq, + 'is': N.Is, 'is not': N.IsNot, + 'in': N.In, 'not in': N.NotIn, + } + + def _ParseComparison(self) -> N.expr: + start: Token = self._Peek() + left: N.expr = self._ParseBitOr() + ops: list[N.AST] = [] + comparators: list[N.expr] = [] + while True: + self._SkipNL() + tok: Token = self._Peek() + op_type: type | None = None + if tok.Type == OP and tok.Value in ('<', '>', '<=', '>=', '==', '!='): + op_type = self._COMPARE_OPS[tok.Value] + self._Next() + elif tok.Type == NAME and tok.Value == 'is': + self._Next() + if self._AtName('not'): + self._Next() + op_type = N.IsNot + else: + op_type = N.Is + elif tok.Type == NAME and tok.Value == 'in': + self._Next() + op_type = N.In + elif tok.Type == NAME and tok.Value == 'not' and self._Peek(1).Type == NAME and self._Peek(1).Value == 'in': + self._Next() + self._Next() + op_type = N.NotIn + else: + break + ops.append(op_type()) + comparators.append(self._ParseBitOr()) + if not ops: + return left + node: N.Compare = N.Compare(left=left, ops=ops, comparators=comparators) + self._FixLoc(node, start) + return node + + # ================================================================== + # 位运算 + # ================================================================== + def _ParseBitOr(self) -> N.expr: + start: Token = self._Peek() + left: N.expr = self._ParseBitXor() + while True: + self._SkipNL() + if self._AtOp('|'): + self._Next() + right: N.expr = self._ParseBitXor() + node: N.BinOp = N.BinOp(left=left, op=N.BitOr(), right=right) + self._FixLoc(node, start) + left = node + continue + break + return left + + def _ParseBitXor(self) -> N.expr: + start: Token = self._Peek() + left: N.expr = self._ParseBitAnd() + while True: + self._SkipNL() + if self._AtOp('^'): + self._Next() + right: N.expr = self._ParseBitAnd() + node: N.BinOp = N.BinOp(left=left, op=N.BitXor(), right=right) + self._FixLoc(node, start) + left = node + continue + break + return left + + def _ParseBitAnd(self) -> N.expr: + start: Token = self._Peek() + left: N.expr = self._ParseShift() + while True: + self._SkipNL() + if self._AtOp('&'): + self._Next() + right: N.expr = self._ParseShift() + node: N.BinOp = N.BinOp(left=left, op=N.BitAnd(), right=right) + self._FixLoc(node, start) + left = node + continue + break + return left + + def _ParseShift(self) -> N.expr: + start: Token = self._Peek() + left: N.expr = self._ParseArith() + while True: + self._SkipNL() + if self._AtOp('<<'): + self._Next() + right: N.expr = self._ParseArith() + node = N.BinOp(left=left, op=N.LShift(), right=right) + elif self._AtOp('>>'): + self._Next() + right = self._ParseArith() + node = N.BinOp(left=left, op=N.RShift(), right=right) + else: + break + self._FixLoc(node, start) + left = node + return left + + # ================================================================== + # 算术 + # ================================================================== + def _ParseArith(self) -> N.expr: + start: Token = self._Peek() + left: N.expr = self._ParseTerm() + while True: + self._SkipNL() + if self._AtOp('+'): + self._Next() + right: N.expr = self._ParseTerm() + node = N.BinOp(left=left, op=N.Add(), right=right) + elif self._AtOp('-'): + self._Next() + right = self._ParseTerm() + node = N.BinOp(left=left, op=N.Sub(), right=right) + else: + break + self._FixLoc(node, start) + left = node + return left + + def _ParseTerm(self) -> N.expr: + start: Token = self._Peek() + left: N.expr = self._ParseFactor() + while True: + self._SkipNL() + tok: Token = self._Peek() + op_type: type | None = None + if tok.Type == OP: + op_type = {'*': N.Mult, '/': N.Div, '//': N.FloorDiv, + '%': N.Mod, '@': N.MatMult}.get(tok.Value) + if op_type is None: + break + self._Next() + right: N.expr = self._ParseFactor() + node: N.BinOp = N.BinOp(left=left, op=op_type(), right=right) + self._FixLoc(node, start) + left = node + return left + + # ================================================================== + # 一元 / 幂 / await + # ================================================================== + def _ParseFactor(self) -> N.expr: + tok: Token = self._Peek() + if tok.Type == OP and tok.Value in ('+', '-', '~'): + self._Next() + operand: N.expr = self._ParseFactor() + op_type: type = {'+': N.UAdd, '-': N.USub, '~': N.Invert}[tok.Value] + node: N.UnaryOp = N.UnaryOp(op=op_type(), operand=operand) + self._FixLoc(node, tok) + return node + return self._ParsePower() + + def _ParsePower(self) -> N.expr: + start: Token = self._Peek() + base: N.expr = self._ParseAwaitPrimary() + if self._AtOp('**'): + self._Next() + exponent: N.expr = self._ParseFactor() # ** 右结合 + node: N.BinOp = N.BinOp(left=base, op=N.Pow(), right=exponent) + self._FixLoc(node, start) + return node + return base + + def _ParseAwaitPrimary(self) -> N.expr: + if self._AtName('await'): + start: Token = self._Next() + value: N.expr = self._ParsePrimary() + node: N.Await = N.Await(value=value) + self._FixLoc(node, start) + return node + return self._ParsePrimary() + + # ================================================================== + # 主表达式:原子 + trailer(调用/属性/下标) + # ================================================================== + def _ParsePrimary(self) -> N.expr: + start: Token = self._Peek() + node: N.expr = self._ParseAtom() + while True: + self._SkipNL() + tok: Token = self._Peek() + if tok.Type == OP and tok.Value == '.': + self._Next() + attr_tok: Token = self._ExpectName() + attr_node: N.Attribute = N.Attribute(value=node, attr=attr_tok.Value, ctx=N.Load()) + self._FixLoc(attr_node, start) + node = attr_node + elif tok.Type == OP and tok.Value == '(': + call_node: N.Call = self._ParseCallTail(node, start) + node = call_node + elif tok.Type == OP and tok.Value == '[': + sub_node: N.Subscript = self._ParseSubscriptTail(node, start) + node = sub_node + else: + break + return node + + def _ParseCallTail(self, func: N.expr, start: Token) -> N.Call: + self._ExpectOp('(') + args: list[N.expr] = [] + keywords: list[N.keyword] = [] + self._SkipNL() + if not self._AtOp(')'): + while True: + self._SkipNL() + # **kwargs + if self._AtOp('**'): + self._Next() + value: N.expr = self.ParseExpr() + kw: N.keyword = N.keyword(arg=None, value=value) + self._FixLoc(kw, self._Prev()) + keywords.append(kw) + else: + # *args + if self._AtOp('*'): + self._Next() + value = self.ParseExpr() + starred: N.Starred = N.Starred(value=value, ctx=N.Load()) + self._FixLoc(starred, self._Prev()) + args.append(starred) + else: + # 关键字参数:NAME '=' + if self._Peek().Type == NAME and self._Peek(1).Type == OP and self._Peek(1).Value == '=': + name_tok: Token = self._Next() + self._Next() # '=' + value = self.ParseExpr() + kw = N.keyword(arg=name_tok.Value, value=value) + self._FixLoc(kw, name_tok) + keywords.append(kw) + else: + # 生成器表达式作为唯一实参:f(x for y in z) + # 先解析第一个表达式,若随后是 'for' 则回填为 GeneratorExp + if not args and not keywords: + gen_start: Token = self._Peek() + gen_elt: N.expr = self.ParseExpr() + if self._AtName('for'): + gen_gens: list[N.comprehension] = self._ParseComprehensionGenerators() + gen: N.GeneratorExp = N.GeneratorExp(elt=gen_elt, generators=gen_gens) + self._FixLoc(gen, gen_start) + args.append(gen) + else: + args.append(gen_elt) + else: + args.append(self.ParseExpr()) + self._SkipNL() + if self._AtOp(','): + self._Next() + self._SkipNL() + if self._AtOp(')'): + break + continue + break + self._ExpectOp(')') + node: N.Call = N.Call(func=func, args=args, keywords=keywords) + self._FixLoc(node, start) + return node + + def _ParseSubscriptTail(self, value: N.expr, start: Token) -> N.Subscript: + self._ExpectOp('[') + self._SkipNL() + slice_node: N.AST = self._ParseSliceList() + self._SkipNL() + self._ExpectOp(']') + node: N.Subscript = N.Subscript(value=value, slice=slice_node, ctx=N.Load()) + self._FixLoc(node, start) + return node + + def _ParseSliceList(self) -> N.AST: + """解析下标列表:a[1] / a[1:2] / a[1:2:3] / a[1,2] / a[...] / a[::]""" + start: Token = self._Peek() + elts: list[N.AST] = [self._ParseSliceItem()] + while self._AtOp(','): + self._Next() + self._SkipNL() + elts.append(self._ParseSliceItem()) + if len(elts) == 1: + return elts[0] + tup: N.Tuple = N.Tuple(elts=elts, ctx=N.Load()) + self._FixLoc(tup, start) + return tup + + def _ParseSliceItem(self) -> N.AST: + start: Token = self._Peek() + # 含冒号 → Slice + if self._AtOp(':'): + lower: N.expr | None = None + upper: N.expr | None = None + step: N.expr | None = None + self._Next() # ':' + if not self._AtOp(':') and not self._AtOp(','): + if not self._AtOp(']'): + upper = self.ParseExpr() + if self._AtOp(':'): + self._Next() + if not self._AtOp(']') and not self._AtOp(',') and not self._AtOp(':'): + step = self.ParseExpr() + node: N.Slice = N.Slice(lower=lower, upper=upper, step=step) + self._FixLoc(node, start) + return node + # 检查 a:b 形式:第一个元素后直接冒号 + first: N.expr = self.ParseExpr() + if self._AtOp(':'): + lower = first + self._Next() + upper = None + step = None + if not self._AtOp(':') and not self._AtOp(']') and not self._AtOp(','): + upper = self.ParseExpr() + if self._AtOp(':'): + self._Next() + if not self._AtOp(']') and not self._AtOp(','): + step = self.ParseExpr() + node = N.Slice(lower=lower, upper=upper, step=step) + self._FixLoc(node, start) + return node + # 简单下标(含 Ellipsis) + if self._AtOp('...'): + # 已在 _ParseExpr 中处理为 Constant(Ellipsis) + pass + return first + + # ================================================================== + # 原子表达式 + # ================================================================== + def _ParseAtom(self) -> N.expr: + self._SkipNL() + tok: Token = self._Peek() + if tok.Type == NUMBER: + return self._ParseNumber() + if tok.Type in (STRING, FSTRING): + return self._ParseStringConcat() + if tok.Type == NAME: + if tok.Value in ('True', 'False', 'None'): + self._Next() + node: N.Constant = N.Constant(value={'True': True, 'False': False, 'None': None}[tok.Value], kind=None) + self._FixLoc(node, tok) + return node + self._Next() + node = N.Name(id=tok.Value, ctx=N.Load()) + self._FixLoc(node, tok) + return node + if tok.Type == OP: + if tok.Value == '(': + return self._ParseParen() + if tok.Value == '[': + return self._ParseList() + if tok.Value == '{': + return self._ParseDictSet() + if tok.Value == '...': + self._Next() + node = N.Constant(value=Ellipsis, kind=None) + self._FixLoc(node, tok) + return node + raise SyntaxError( + f"unexpected token {tok.Type}({tok.Value!r}) at line {tok.Line}" + ) + + # ------------------------------------------------------------------ + # 数字 + # ------------------------------------------------------------------ + def _ParseNumber(self) -> N.Constant: + tok: Token = self._Next() + text: str = tok.Value + try: + if text.lower().endswith('j'): + num: object = complex(text[:-1].replace('_', '')) + elif text.lower().startswith(('0x', '0o', '0b')): + num = int(text.replace('_', ''), 0) + elif any(c in text for c in '.eE'): + num = float(text.replace('_', '')) + else: + num = int(text.replace('_', ''), 10) + except ValueError: + # 无法解析:保留原字符串(理论上不会发生) + num = text + node: N.Constant = N.Constant(value=num, kind=None) + self._FixLoc(node, tok) + return node + + # ------------------------------------------------------------------ + # 字符串(含相邻拼接与 f-string 混合) + # ------------------------------------------------------------------ + def _ParseStringConcat(self) -> N.expr: + """解析连续字符串字面量并拼接。 + + 规则(与 CPython 一致): + - 全部为普通字符串 → 单个 Constant(值合并) + - 含 f-string → JoinedStr(字符串为 Constant,f-string 展开为 values) + """ + start: Token = self._Peek() + parts: list[N.expr] = [] # JoinedStr 的 values 或常量 + const_parts: list[object] = [] + has_fstring: bool = False + while True: + # 相邻字符串可跨括号内换行(NL)合并 + self._SkipNL() + tok: Token = self._Peek() + if tok.Type == STRING: + self._Next() + val: object = self._DecodeString(tok.Value) + const_parts.append(val) + elif tok.Type == FSTRING: + self._Next() + joined: N.JoinedStr = self._ParseFStringToken(tok) + has_fstring = True + if const_parts: + parts.append(self._MakeStrConstant(_JoinConstParts(const_parts), start)) + const_parts = [] + # 相邻 Constant 合并(f-string 字面量 + 后续常量段) + if parts and isinstance(parts[-1], N.Constant) and joined.values and isinstance(joined.values[0], N.Constant): + merged: str = str(parts[-1].value) + str(joined.values[0].value) + merged_const: N.Constant = N.Constant(value=merged, kind=None) + merged_const.lineno = parts[-1].lineno + merged_const.col_offset = parts[-1].col_offset + parts[-1] = merged_const + parts.extend(joined.values[1:]) + else: + parts.extend(joined.values) + else: + break + if not has_fstring: + node: N.Constant = N.Constant(value=_JoinConstParts(const_parts), kind=None) + self._FixLoc(node, start) + return node + if const_parts: + if parts and isinstance(parts[-1], N.Constant): + merged = str(parts[-1].value) + str(_JoinConstParts(const_parts)) + merged_const = N.Constant(value=merged, kind=None) + merged_const.lineno = parts[-1].lineno + merged_const.col_offset = parts[-1].col_offset + parts[-1] = merged_const + else: + parts.append(self._MakeStrConstant(str(_JoinConstParts(const_parts)), start)) + node = N.JoinedStr(values=parts) + self._FixLoc(node, start) + return node + + def _MakeStrConstant(self, value: str, start: Token) -> N.Constant: + node: N.Constant = N.Constant(value=value, kind=None) + node.lineno = start.Line + node.col_offset = start.Col + return node + + # ------------------------------------------------------------------ + # 字符串解码 + # ------------------------------------------------------------------ + def _DecodeString(self, raw: str) -> str | bytes: + """解码字符串字面量原始文本(含前缀与引号)为实际值。 + + 支持 r/b/u/f 前缀组合、单引号/双引号/三引号、常见转义序列。 + """ + # 提取前缀与引号 + i: int = 0 + while i < len(raw) and raw[i] in _STRING_PREFIX_CHARS: + i += 1 + prefix: str = raw[:i] + quote: str = raw[i] + triple: bool = raw.startswith(quote * 3, i) + body_start: int = i + (3 if triple else 1) + body_end: int = len(raw) - (3 if triple else 1) + body: str = raw[body_start:body_end] + is_raw: bool = 'r' in prefix.lower() + is_bytes: bool = 'b' in prefix.lower() + if is_bytes: + # bytes 字面量:逐字节解码(转义为字节值) + return self._DecodeBytes(body, is_raw) + # str 字面量 + return self._DecodeEscapes(body, is_raw) + + def _DecodeEscapes(self, body: str, is_raw: bool) -> str: + """解码字符串转义序列。""" + if is_raw: + return body + out: list[str] = [] + i: int = 0 + n: int = len(body) + while i < n: + ch: str = body[i] + if ch != '\\': + out.append(ch) + i += 1 + continue + i += 1 + if i >= n: + out.append('\\') + break + esc: str = body[i] + simple: dict[str, str] = { + '\\': '\\', "'": "'", '"': '"', 'n': '\n', 't': '\t', + 'r': '\r', 'b': '\b', 'f': '\f', 'v': '\v', 'a': '\a', + } + if esc in simple: + out.append(simple[esc]) + i += 1 + elif esc == 'x': + hex_digits: str = body[i + 1:i + 3] + out.append(chr(int(hex_digits, 16))) + i += 3 + elif esc == 'u': + hex_digits = body[i + 1:i + 5] + out.append(chr(int(hex_digits, 16))) + i += 5 + elif esc == 'U': + hex_digits = body[i + 1:i + 9] + out.append(chr(int(hex_digits, 16))) + i += 9 + elif esc.isdigit() and '0' <= esc <= '7': + oct_digits: str = body[i:i + 3] + j: int = 0 + while j < 3 and j < len(oct_digits) and '0' <= oct_digits[j] <= '7': + j += 1 + out.append(chr(int(oct_digits[:j], 8))) + i += j + else: + # 未知转义:保留原样(CPython 保留反斜杠) + out.append('\\' + esc) + i += 1 + return ''.join(out) + + def _DecodeBytes(self, body: str, is_raw: bool) -> bytes: + """解码 bytes 字面量(转义序列按字节处理,支持 r 前缀)。""" + if is_raw: + return body.encode('latin-1') + out: list[int] = [] + i: int = 0 + n: int = len(body) + while i < n: + ch: str = body[i] + if ch != '\\': + try: + out.append(ord(body[i])) + except Exception: + out.append(0) + i += 1 + continue + i += 1 + if i >= n: + out.append(ord('\\')) + break + esc: str = body[i] + simple: dict[str, int] = { + '\\': ord('\\'), "'": ord("'"), '"': ord('"'), + 'n': 10, 't': 9, 'r': 13, 'b': 8, 'f': 12, 'v': 11, 'a': 7, + } + if esc in simple: + out.append(simple[esc]) + i += 1 + elif esc == 'x': + out.append(int(body[i + 1:i + 3], 16)) + i += 3 + elif esc == 'u': + out.append(int(body[i + 1:i + 5], 16)) + i += 5 + elif esc == 'U': + out.append(int(body[i + 1:i + 9], 16)) + i += 9 + elif esc.isdigit() and '0' <= esc <= '7': + oct_digits: str = body[i:i + 3] + j: int = 0 + while j < 3 and j < len(oct_digits) and '0' <= oct_digits[j] <= '7': + j += 1 + out.append(int(oct_digits[:j], 8)) + i += j + else: + out.append(ord('\\')) + out.append(ord(esc)) + i += 1 + return bytes(out) + + # ------------------------------------------------------------------ + # f-string 解析 + # ------------------------------------------------------------------ + def _ParseFStringToken(self, tok: Token) -> N.JoinedStr: + """解析 FSTRING token 为 JoinedStr(values 为 Constant/FormattedValue)。""" + raw: str = tok.Value + values: list[N.expr] = self._ParseFStringBody(raw, tok, 0) + node: N.JoinedStr = N.JoinedStr(values=values) + self._FixLoc(node, tok) + return node + + def _ParseFStringBody(self, raw: str, outer_tok: Token, base_offset: int) -> list[N.expr]: + """解析 f-string 文本(含前缀与引号)为 values 列表。 + + Args: + raw: f-string 原始文本 + outer_tok: FSTRING token(用于绝对偏移换算) + base_offset: 文本在 token Value 中的起始偏移(嵌套用) + """ + # 提取前缀与引号 + i: int = 0 + while i < len(raw) and raw[i] in _STRING_PREFIX_CHARS: + i += 1 + prefix: str = raw[:i] + quote: str = raw[i] + triple: bool = raw.startswith(quote * 3, i) + is_raw: bool = 'r' in prefix.lower() + body_start: int = i + (3 if triple else 1) + body_end: int = len(raw) - (3 if triple else 1) + body: str = raw[body_start:body_end] + values: list[N.expr] = [] + literal: list[str] = [] + j: int = 0 + n: int = len(body) + rel_base: int = body_start + base_offset # 相对外层的偏移 + while j < n: + ch: str = body[j] + if ch == '{': + if j + 1 < n and body[j + 1] == '{': + literal.append('{') + j += 2 + continue + # 表达式段开始 + if literal: + cnode: N.Constant = N.Constant(value=self._DecodeEscapes(''.join(literal), is_raw), kind=None) + cnode.lineno, cnode.col_offset = outer_tok.Line, outer_tok.Col + values.append(cnode) + literal = [] + fv: N.FormattedValue = self._ParseFStringValue(body, j, outer_tok, rel_base) + values.append(fv) + # 更新 j 到表达式段之后 + j = self._FStringExprEnd + continue + elif ch == '}': + if j + 1 < n and body[j + 1] == '}': + literal.append('}') + j += 2 + continue + # 单独的 } 是语法错误,宽松处理为字面量 + literal.append('}') + j += 1 + continue + else: + literal.append(ch) + j += 1 + if literal: + cnode = N.Constant(value=self._DecodeEscapes(''.join(literal), is_raw), kind=None) + cnode.lineno, cnode.col_offset = outer_tok.Line, outer_tok.Col + values.append(cnode) + return values + + _FStringExprEnd: int = 0 # 表达式段结束位置(body 内偏移),供调用方跳转 + + def _ParseFStringValue(self, body: str, start: int, outer_tok: Token, rel_base: int) -> N.FormattedValue: + """解析 f-string 单个 {expr[!conv][:spec]} 段。 + + 返回 FormattedValue;将表达式段结束位置存入 self._FStringExprEnd。 + """ + j: int = start + 1 # 跳过 '{' + n: int = len(body) + depth: int = 1 + expr_start: int = j + expr_end: int = j + # 扫描结束字符:'}' 正常闭合;'!'/':' 为转换/格式说明符起点 + stop_char: str = '}' + # 扫描到匹配的 '}'(考虑括号嵌套与内部字符串); + # 顶层 '!' 或 ':' 表示表达式结束(转换/格式说明符开始) + while j < n: + ch: str = body[j] + if ch == '\\': + j += 2 + continue + if ch in '\'"': + # 跳过内部字符串字面量 + j = self._SkipInnerLiteral(body, j) + continue + if ch in '([{': + depth += 1 + j += 1 + continue + if ch in ')]}': + if depth == 1 and ch == '}': + expr_end = j + j += 1 + break + if depth == 1 and ch in ')}]': + # 不匹配:语法错误,宽松按结束处理 + expr_end = j + j += 1 + break + depth -= 1 + j += 1 + continue + if depth == 1 and (ch == '!' or ch == ':'): + # 转换/格式说明符起点:表达式结束(j 停在操作符处) + expr_end = j + stop_char = ch + break + j += 1 + self._FStringExprEnd = j + expr_text: str = body[expr_start:expr_end] + # 转换与格式说明符(仅当扫描停在 ! 或 : 时才解析) + conversion: int = -1 + format_spec: N.expr | None = None + k: int = j + if stop_char == '!': + k += 1 + if k < n and body[k] in 'rsa': + conversion = ord(body[k]) + k += 1 + # 转换后可能还有 :format_spec + if k < n and body[k] == ':': + stop_char = ':' + else: + # 无格式说明符:跳过 '}' 结束表达式段 + if k < n and body[k] == '}': + k += 1 + self._FStringExprEnd = k + if stop_char == ':': + k += 1 + # 格式说明符可含嵌套 {}(如 {x:{w}}) + spec_body: list[str] = [] + depth2: int = 1 + while k < n: + c2: str = body[k] + if c2 == '{': + depth2 += 1 + spec_body.append(c2) + k += 1 + elif c2 == '}': + depth2 -= 1 + if depth2 == 0: + break + spec_body.append(c2) + k += 1 + else: + spec_body.append(c2) + k += 1 + spec_text: str = ''.join(spec_body) + if any(c == '{' for c in spec_text): + # 嵌套表达式:构造 JoinedStr + inner_fs: str = 'f"' + spec_text.replace('"', '\\"') + '"' + inner_tok: Token = Token(FSTRING, inner_fs, outer_tok.Line, outer_tok.Col, + outer_tok.EndLine, outer_tok.EndCol) + format_spec = self._ParseFStringToken(inner_tok) + else: + # 静态格式说明符:CPython 包为 JoinedStr(values=[Constant]) + cnode: N.Constant = N.Constant(value=spec_text, kind=None) + cnode.lineno = outer_tok.Line + cnode.col_offset = outer_tok.Col + jstr: N.JoinedStr = N.JoinedStr(values=[cnode]) + format_spec = jstr + # k 现指向 '}':跳过它作为表达式段结束 + if k < n and body[k] == '}': + k += 1 + self._FStringExprEnd = k + # 解析表达式:子 token 流 + expr_node: N.expr = self._ParseSubExpression(expr_text, outer_tok, expr_start + rel_base) + fv: N.FormattedValue = N.FormattedValue(value=expr_node, conversion=conversion, format_spec=format_spec) + fv.lineno = outer_tok.Line + fv.col_offset = outer_tok.Col + fv.end_lineno = outer_tok.EndLine + fv.end_col_offset = outer_tok.EndCol + return fv + + def _SkipInnerLiteral(self, body: str, start: int) -> int: + """跳过 f-string 表达式内部的字符串字面量,返回结束位置。""" + j: int = start + # 前缀 + while j < len(body) and body[j] in _STRING_PREFIX_CHARS: + j += 1 + if j >= len(body) or body[j] not in '\'"': + return start + 1 + quote: str = body[j] + triple: bool = body.startswith(quote * 3, j) + j += 3 if triple else 1 + while j < len(body): + ch: str = body[j] + if ch == '\\': + j += 2 + continue + if ch == quote: + if triple: + if body.startswith(quote * 3, j): + j += 3 + return j + j += 1 + else: + j += 1 + return j + j += 1 + return j + + def _ParseSubExpression(self, text: str, outer_tok: Token, abs_base: int) -> N.expr: + """解析子表达式文本(f-string 内部),并重定位到绝对偏移。""" + sub_toks: list[Token] = Tokenizer(text).Tokenize() + # 过滤 ENDMARKER 后的 NEWLINE 等 + for t in sub_toks: + self._Relocate(t, abs_base) + # 保存主游标,切换到子 token 流 + saved_idx: int = self.Idx + saved_tokens: list[Token] = self.Tokens + self.Tokens = sub_toks + self.Idx = 0 + try: + expr: N.expr = self.ParseExpr() + finally: + self.Tokens = saved_tokens + self.Idx = saved_idx + return expr + + # ------------------------------------------------------------------ + # 括号 / 列表 / 字典 / 集合 / 推导式 + # ------------------------------------------------------------------ + def _ParseParen(self) -> N.expr: + start: Token = self._Next() # '(' + self._SkipNL() + # 空元组 () + if self._AtOp(')'): + self._Next() + tup: N.Tuple = N.Tuple(elts=[], ctx=N.Load()) + self._FixLoc(tup, start) + return tup + # yield 表达式 + if self._AtName('yield'): + yield_node: N.expr = self._ParseYield() + self._SkipNL() + self._ExpectOp(')') + return yield_node + # 命名表达式 (x := y) + if self._Peek().Type == NAME and self._Peek(1).Type == OP and self._Peek(1).Value == ':=': + name_tok: Token = self._Next() + self._Next() # ':=' + value: N.expr = self.ParseExpr() + self._SkipNL() + self._ExpectOp(')') + walrus: N.NamedExpr = N.NamedExpr(target=N.Name(id=name_tok.Value, ctx=N.Store()), value=value) + self._FixLoc(walrus, start) + return walrus + first: N.expr = self.ParseExpr() + self._SkipNL() + # 生成器表达式 (x for ...) + if self._AtName('for'): + generators: list[N.comprehension] = self._ParseComprehensionGenerators() + self._SkipNL() + self._ExpectOp(')') + gen: N.GeneratorExp = N.GeneratorExp(elt=first, generators=generators) + self._FixLoc(gen, start) + return gen + # 元组 (x,) / (x, y) + if self._AtOp(','): + elts: list[N.expr] = [first] + while self._AtOp(','): + self._Next() + self._SkipNL() + if self._AtOp(')'): + break + elts.append(self.ParseExpr()) + self._SkipNL() + self._ExpectOp(')') + tup = N.Tuple(elts=elts, ctx=N.Load()) + self._FixLoc(tup, start) + return tup + # 普通括号表达式 (x) + self._ExpectOp(')') + return first + + def _ParseList(self) -> N.expr: + start: Token = self._Next() # '[' + self._SkipNL() + if self._AtOp(']'): + self._Next() + lst: N.List = N.List(elts=[], ctx=N.Load()) + self._FixLoc(lst, start) + return lst + first: N.expr = self.ParseExpr() + self._SkipNL() + # 列表推导式 + if self._AtName('for'): + generators = self._ParseComprehensionGenerators() + self._SkipNL() + self._ExpectOp(']') + lc: N.ListComp = N.ListComp(elt=first, generators=generators) + self._FixLoc(lc, start) + return lc + # 普通列表 + elts = [first] + while self._AtOp(','): + self._Next() + self._SkipNL() + if self._AtOp(']'): + break + elts.append(self.ParseExpr()) + self._SkipNL() + self._ExpectOp(']') + lst = N.List(elts=elts, ctx=N.Load()) + self._FixLoc(lst, start) + return lst + + def _ParseDictSet(self) -> N.expr: + start: Token = self._Next() # '{' + self._SkipNL() + if self._AtOp('}'): + self._Next() + dct: N.Dict = N.Dict(keys=[], values=[]) + self._FixLoc(dct, start) + return dct + # ** 展开:{**d} + keys: list[N.expr | None] = [] + values: list[N.expr] = [] + while True: + self._SkipNL() + if self._AtOp('**'): + self._Next() + val: N.expr = self.ParseExpr() + keys.append(None) + values.append(val) + else: + key: N.expr = self.ParseExpr() + self._SkipNL() + if self._AtOp(':'): + self._Next() + self._SkipNL() + value: N.expr = self.ParseExpr() + keys.append(key) + values.append(value) + else: + # 集合元素 + elts: list[N.expr] = [key] + while self._AtOp(','): + self._Next() + self._SkipNL() + if self._AtOp('}'): + break + elts.append(self.ParseExpr()) + self._SkipNL() + # 集合推导式? + self._SkipNL() + if self._AtName('for'): + generators = self._ParseComprehensionGenerators() + self._SkipNL() + self._ExpectOp('}') + sc: N.SetComp = N.SetComp(elt=elts[0], generators=generators) + self._FixLoc(sc, start) + return sc + self._ExpectOp('}') + st: N.Set = N.Set(elts=elts) + self._FixLoc(st, start) + return st + self._SkipNL() + if self._AtOp(','): + self._Next() + self._SkipNL() + if self._AtOp('}'): + break + continue + break + # 字典推导式? + self._SkipNL() + if self._AtName('for'): + generators = self._ParseComprehensionGenerators() + self._SkipNL() + self._ExpectOp('}') + dc: N.DictComp = N.DictComp(key=keys[0] or N.Constant(value=None), value=values[0], generators=generators) + self._FixLoc(dc, start) + return dc + self._ExpectOp('}') + dct = N.Dict(keys=keys, values=values) + self._FixLoc(dct, start) + return dct + + def _ParseComprehensionGenerators(self) -> list[N.comprehension]: + """解析推导式生成器子句:for target in iter [if cond]* [async for ...]""" + generators: list[N.comprehension] = [] + while True: + is_async: bool = False + if self._AtName('async') and self._Peek(1).Type == NAME and self._Peek(1).Value == 'for': + self._Next() + is_async = True + if not self._AtName('for'): + break + start: Token = self._Next() # 'for' + target: N.expr = self._ParseComprehensionTarget() + self._ExpectName('in') + # iter 用 disjunction 级别解析,避免吞掉 'if' 条件 + iterable: N.expr = self._ParseDisjunction() + ifs: list[N.expr] = [] + while self._AtName('if'): + self._Next() + ifs.append(self._ParseDisjunction()) + comp: N.comprehension = N.comprehension(target=target, iter=iterable, ifs=ifs, is_async=int(is_async)) + self._FixLoc(comp, start) + generators.append(comp) + if self._AtName('for') or (self._AtName('async') and self._Peek(1).Type == NAME and self._Peek(1).Value == 'for'): + continue + break + return generators + + def _ParseComprehensionTarget(self) -> N.expr: + """解析推导式 for 目标(支持裸元组 a, b 解包)。""" + start: Token = self._Peek() + first: N.expr = self._ParseTarget() + if self._AtOp(','): + elts: list[N.expr] = [first] + while self._AtOp(','): + self._Next() + self._SkipNL() + elts.append(self._ParseTarget()) + tup: N.Tuple = N.Tuple(elts=elts, ctx=N.Store()) + self._FixLoc(tup, start) + return tup + return first + + def _ParseTarget(self) -> N.expr: + """解析赋值目标(Store 上下文),支持元组/列表解包。""" + start: Token = self._Peek() + if self._AtOp('('): + self._Next() + self._SkipNL() + elts: list[N.expr] = [] + if not self._AtOp(')'): + while True: + elts.append(self._ParseTarget()) + self._SkipNL() + if self._AtOp(','): + self._Next() + self._SkipNL() + if self._AtOp(')'): + break + continue + break + self._ExpectOp(')') + tup: N.Tuple = N.Tuple(elts=elts, ctx=N.Store()) + self._FixLoc(tup, start) + return tup + if self._AtOp('['): + self._Next() + self._SkipNL() + elts = [] + if not self._AtOp(']'): + while True: + elts.append(self._ParseTarget()) + self._SkipNL() + if self._AtOp(','): + self._Next() + self._SkipNL() + if self._AtOp(']'): + break + continue + break + self._ExpectOp(']') + lst: N.List = N.List(elts=elts, ctx=N.Store()) + self._FixLoc(lst, start) + return lst + if self._AtOp('*'): + self._Next() + value: N.expr = self._ParseTarget() + starred: N.Starred = N.Starred(value=value, ctx=N.Store()) + self._FixLoc(starred, start) + return starred + # 名称/属性/下标(Store) + tok: Token = self._Peek() + if tok.Type == NAME: + self._Next() + node: N.Name = N.Name(id=tok.Value, ctx=N.Store()) + self._FixLoc(node, tok) + return node + # 属性/下标目标:解析 Load 后改 Store + node = self._ParsePrimary() + self._SetStoreContext(node) + return node + + def _SetStoreContext(self, node: N.AST) -> None: + """将 Load 上下文节点递归改为 Store。""" + if isinstance(node, N.Attribute): + node.ctx = N.Store() + elif isinstance(node, N.Subscript): + node.ctx = N.Store() + elif isinstance(node, N.Name): + node.ctx = N.Store() + elif isinstance(node, (N.Tuple, N.List)): + node.ctx = N.Store() + for elt in node.elts: + self._SetStoreContext(elt) + elif isinstance(node, N.Starred): + node.ctx = N.Store() + self._SetStoreContext(node.value) + + # ------------------------------------------------------------------ + # lambda / yield + # ------------------------------------------------------------------ + def _ParseLambda(self) -> N.Lambda: + start: Token = self._Next() # 'lambda' + args: N.arguments + if self._AtOp(':'): + # 无参 lambda + args = N.arguments(posonlyargs=[], args=[], vararg=None, kwonlyargs=[], + kw_defaults=[], kwarg=None, defaults=[]) + else: + args = self._ParseArguments(skip_open=True, allow_lambda=True) + self._ExpectOp(':') + body: N.expr = self.ParseExpr() + node: N.Lambda = N.Lambda(args=args, body=body) + self._FixLoc(node, start) + return node + + def _ParseYield(self) -> N.expr: + start: Token = self._Next() # 'yield' + if self._AtName('from'): + self._Next() + value: N.expr = self.ParseExpr() + node: N.YieldFrom = N.YieldFrom(value=value) + self._FixLoc(node, start) + return node + if not self._AtOp(')'): + value = self.ParseExprList() + node: N.Yield = N.Yield(value=value) + else: + node = N.Yield(value=None) + self._FixLoc(node, start) + return node + + # ================================================================== + # 参数列表(lambda 与函数定义共用) + # ================================================================== + def _ParseArguments(self, skip_open: bool = False, allow_lambda: bool = False) -> N.arguments: + """解析参数列表。 + + 支持 posonly (/)、*args、kwonly、**kwargs、默认值、注解。 + defaults 与 posonlyargs+args 尾部对齐(CPython 语义)。 + + Args: + skip_open: True 时假定 '(' 已消费(lambda 场景无括号) + """ + if not skip_open: + self._ExpectOp('(') + self._SkipNL() + posonlyargs: list[N.arg] = [] + args: list[N.arg] = [] + kwonlyargs: list[N.arg] = [] + kw_defaults: list[N.expr | None] = [] + defaults: list[N.expr] = [] + vararg: N.arg | None = None + kwarg: N.arg | None = None + seen_star: bool = False + # 按解析顺序收集 (arg, default) 用于尾部对齐 + ordered: list[tuple[N.arg, N.expr | None]] = [] + if not self._AtOp(')'): + while True: + self._SkipNL() + if self._AtOp(')'): + break + if self._AtOp('*'): + self._Next() + if self._AtOp(','): + # 裸 *:分隔 kwonly + seen_star = True + self._Next() + if self._AtOp(')') or self._AtOp(':'): + break + continue + vararg = self._ParseArg(allow_annotation=not allow_lambda) + seen_star = True + elif self._AtOp('**'): + self._Next() + kwarg = self._ParseArg(allow_annotation=not allow_lambda) + else: + a: N.arg = self._ParseArg(allow_annotation=not allow_lambda) + default: N.expr | None = None + if self._AtOp('='): + self._Next() + default = self.ParseExpr() + if seen_star: + kwonlyargs.append(a) + kw_defaults.append(default) + else: + ordered.append((a, default)) + self._SkipNL() + if self._AtOp(','): + self._Next() + if self._AtOp(')'): + break + continue + break + # 切分 posonly 与普通 args:CPython 无显式 '/' 信息时全为普通 args + # 注意:本实现未显式解析 '/' 分隔,posonlyargs 保持空(TPC 源码不使用) + for a, d in ordered: + args.append(a) + defaults.append(d) + # defaults 尾部对齐:去掉开头的 None,且仅保留末尾连续默认值 + # CPython 语义:defaults 与 args 尾部对齐,若中间有缺省则语法错误。 + # 宽松处理:取最后一个 None 之后的全部默认值。 + last_none: int = -1 + for i, d in enumerate(defaults): + if d is None: + last_none = i + defaults = [d for d in defaults[last_none + 1:] if d is not None] + # 将带默认值的 arg 之前的参数清掉默认值列表长度 = 默认参数个数 + self._SkipNL() + if not skip_open: + self._ExpectOp(')') + node: N.arguments = N.arguments( + posonlyargs=posonlyargs, args=args, vararg=vararg, + kwonlyargs=kwonlyargs, kw_defaults=kw_defaults, kwarg=kwarg, + defaults=defaults, + ) + return node + + def _ParseArg(self, allow_annotation: bool) -> N.arg: + start: Token = self._ExpectName() + annotation: N.expr | None = None + if allow_annotation and self._AtOp(':'): + self._Next() + annotation = self.ParseExpr() + a: N.arg = N.arg(arg=start.Value, annotation=annotation, type_comment=None) + self._FixLoc(a, start) + return a diff --git a/lib/vast/Nodes.py b/lib/vast/Nodes.py new file mode 100644 index 0000000..a8aa790 --- /dev/null +++ b/lib/vast/Nodes.py @@ -0,0 +1,348 @@ +"""vast.nodes - 与 CPython 3.12 ast 完全同构的 AST 节点类 + +vast 是自研 Viper/Python 语法解析器,产出与标准库 ast 模块结构完全一致的 +AST 树,从而使编译器侧 ``import vast as ast`` 后原有代码零修改。 + +本模块定义全部 131 个 AST 节点类(含遗留兼容类),字段/属性与 CPython +3.12 的 ``ast`` 模块逐一对应: + +- ``_fields``:节点结构字段(顺序与位置参数构造一致) +- ``_attributes``:dump(include_attributes=True) 时随节点输出的位置属性 + +构造语义与 CPython 一致: +- 位置参数按 ``_fields`` 顺序赋值,超出字段数抛 TypeError +- 关键字参数全部 setattr(包括未知字段,与 CPython 行为一致) +- 未传入的字段不设置属性(访问时 AttributeError,与 CPython 一致) +""" +from __future__ import annotations + + +class AST: + """所有 AST 节点的基类(与 ast.AST 同构)。""" + + _fields: tuple[str, ...] = () + _attributes: tuple[str, ...] = () + + def __init__(self, *args: object, **kwargs: object) -> None: + fields: tuple[str, ...] = self._fields + if len(args) > len(fields): + raise TypeError( + f'{type(self).__name__} constructor takes at most ' + f'{len(fields)} positional arguments' + ) + for name, val in zip(fields, args): + setattr(self, name, val) + for k, v in kwargs.items(): + setattr(self, k, v) + + def __eq__(self, other: object) -> bool: + """AST 节点按对象身份比较(与 CPython ast 一致)。""" + return self is other + + +# ============================================================================= +# 节点定义表:字段表(含位置属性表),数据驱动生成全部节点类 +# ============================================================================= + +_POS_ATTRS: tuple[str, ...] = ('lineno', 'col_offset', 'end_lineno', 'end_col_offset') + +_NODE_DEFS: dict[str, tuple[tuple[str, ...], tuple[str, ...]]] = { + # ---- 模块/交互/表达式顶层 ---- + 'Module': (('body', 'type_ignores'), ()), + 'Interactive': (('body',), ()), + 'Expression': (('body',), ()), + 'FunctionType': (('argtypes', 'returns'), ()), + 'Suite': ((), ()), + + # ---- 语句 ---- + 'FunctionDef': (('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), _POS_ATTRS), + 'AsyncFunctionDef': (('name', 'args', 'body', 'decorator_list', 'returns', 'type_comment', 'type_params'), _POS_ATTRS), + 'ClassDef': (('name', 'bases', 'keywords', 'body', 'decorator_list', 'type_params'), _POS_ATTRS), + 'Return': (('value',), _POS_ATTRS), + 'Delete': (('targets',), _POS_ATTRS), + 'Assign': (('targets', 'value', 'type_comment'), _POS_ATTRS), + 'AugAssign': (('target', 'op', 'value'), _POS_ATTRS), + 'AnnAssign': (('target', 'annotation', 'value', 'simple'), _POS_ATTRS), + 'For': (('target', 'iter', 'body', 'orelse', 'type_comment'), _POS_ATTRS), + 'AsyncFor': (('target', 'iter', 'body', 'orelse', 'type_comment'), _POS_ATTRS), + 'While': (('test', 'body', 'orelse'), _POS_ATTRS), + 'If': (('test', 'body', 'orelse'), _POS_ATTRS), + 'With': (('items', 'body', 'type_comment'), _POS_ATTRS), + 'AsyncWith': (('items', 'body', 'type_comment'), _POS_ATTRS), + 'Match': (('subject', 'cases'), _POS_ATTRS), + 'Raise': (('exc', 'cause'), _POS_ATTRS), + 'Try': (('body', 'handlers', 'orelse', 'finalbody'), _POS_ATTRS), + 'TryStar': (('body', 'handlers', 'orelse', 'finalbody'), _POS_ATTRS), + 'Assert': (('test', 'msg'), _POS_ATTRS), + 'Import': (('names',), _POS_ATTRS), + 'ImportFrom': (('module', 'names', 'level'), _POS_ATTRS), + 'Global': (('names',), _POS_ATTRS), + 'Nonlocal': (('names',), _POS_ATTRS), + 'Expr': (('value',), _POS_ATTRS), + 'Pass': ((), _POS_ATTRS), + 'Break': ((), _POS_ATTRS), + 'Continue': ((), _POS_ATTRS), + + # ---- 表达式 ---- + 'BoolOp': (('op', 'values'), _POS_ATTRS), + 'NamedExpr': (('target', 'value'), _POS_ATTRS), + 'BinOp': (('left', 'op', 'right'), _POS_ATTRS), + 'UnaryOp': (('op', 'operand'), _POS_ATTRS), + 'Lambda': (('args', 'body'), _POS_ATTRS), + 'IfExp': (('test', 'body', 'orelse'), _POS_ATTRS), + 'Dict': (('keys', 'values'), _POS_ATTRS), + 'Set': (('elts',), _POS_ATTRS), + 'ListComp': (('elt', 'generators'), _POS_ATTRS), + 'SetComp': (('elt', 'generators'), _POS_ATTRS), + 'DictComp': (('key', 'value', 'generators'), _POS_ATTRS), + 'GeneratorExp': (('elt', 'generators'), _POS_ATTRS), + 'Await': (('value',), _POS_ATTRS), + 'Yield': (('value',), _POS_ATTRS), + 'YieldFrom': (('value',), _POS_ATTRS), + 'Compare': (('left', 'ops', 'comparators'), _POS_ATTRS), + 'Call': (('func', 'args', 'keywords'), _POS_ATTRS), + 'FormattedValue': (('value', 'conversion', 'format_spec'), _POS_ATTRS), + 'JoinedStr': (('values',), _POS_ATTRS), + 'Constant': (('value', 'kind'), _POS_ATTRS), + 'Attribute': (('value', 'attr', 'ctx'), _POS_ATTRS), + 'Subscript': (('value', 'slice', 'ctx'), _POS_ATTRS), + 'Starred': (('value', 'ctx'), _POS_ATTRS), + 'Name': (('id', 'ctx'), _POS_ATTRS), + 'List': (('elts', 'ctx'), _POS_ATTRS), + 'Tuple': (('elts', 'ctx'), _POS_ATTRS), + 'Slice': (('lower', 'upper', 'step'), _POS_ATTRS), + + # ---- match 模式(PEP 634) ---- + 'MatchValue': (('value',), _POS_ATTRS), + 'MatchSingleton': (('value',), _POS_ATTRS), + 'MatchSequence': (('patterns',), _POS_ATTRS), + 'MatchMapping': (('keys', 'patterns', 'rest'), _POS_ATTRS), + 'MatchClass': (('cls', 'patterns', 'kwd_attrs', 'kwd_patterns'), _POS_ATTRS), + 'MatchStar': (('name',), _POS_ATTRS), + 'MatchAs': (('pattern', 'name'), _POS_ATTRS), + 'MatchOr': (('patterns',), _POS_ATTRS), + + # ---- 类型参数(PEP 695,仅声明性支持) ---- + 'TypeVar': (('name', 'bound'), _POS_ATTRS), + 'TypeVarTuple': (('name',), _POS_ATTRS), + 'ParamSpec': (('name',), _POS_ATTRS), + 'TypeAlias': (('name', 'type_params', 'value'), _POS_ATTRS), + + # ---- 复合辅助节点 ---- + 'comprehension': (('target', 'iter', 'ifs', 'is_async'), ()), + 'ExceptHandler': (('type', 'name', 'body'), _POS_ATTRS), + 'arguments': (('posonlyargs', 'args', 'vararg', 'kwonlyargs', 'kw_defaults', 'kwarg', 'defaults'), ()), + 'arg': (('arg', 'annotation', 'type_comment'), _POS_ATTRS), + 'keyword': (('arg', 'value'), _POS_ATTRS), + 'alias': (('name', 'asname'), _POS_ATTRS), + 'withitem': (('context_expr', 'optional_vars'), ()), + 'match_case': (('pattern', 'guard', 'body'), ()), + 'TypeIgnore': (('lineno', 'tag'), ()), + + # ---- 运算符 / 上下文(无字段单例类) ---- + 'Add': ((), ()), + 'Sub': ((), ()), + 'Mult': ((), ()), + 'MatMult': ((), ()), + 'Div': ((), ()), + 'Mod': ((), ()), + 'Pow': ((), ()), + 'LShift': ((), ()), + 'RShift': ((), ()), + 'BitOr': ((), ()), + 'BitXor': ((), ()), + 'BitAnd': ((), ()), + 'FloorDiv': ((), ()), + 'Invert': ((), ()), + 'Not': ((), ()), + 'UAdd': ((), ()), + 'USub': ((), ()), + 'Eq': ((), ()), + 'NotEq': ((), ()), + 'Lt': ((), ()), + 'LtE': ((), ()), + 'Gt': ((), ()), + 'GtE': ((), ()), + 'Is': ((), ()), + 'IsNot': ((), ()), + 'In': ((), ()), + 'NotIn': ((), ()), + 'And': ((), ()), + 'Or': ((), ()), + 'Load': ((), ()), + 'Store': ((), ()), + 'Del': ((), ()), + 'AugLoad': ((), ()), + 'AugStore': ((), ()), + 'Param': ((), ()), + 'Ellipsis': ((), _POS_ATTRS), + + # ---- 遗留兼容类(已废弃但保留,供 hasattr 检查) ---- + 'Index': ((), ()), + 'ExtSlice': ((), ()), + + # ---- 抽象类型占位(纯类型标注用,不实例化) ---- + 'mod': ((), ()), + 'stmt': ((), ()), + 'expr': ((), ()), + 'expr_context': ((), ()), + 'boolop': ((), ()), + 'operator': ((), ()), + 'unaryop': ((), ()), + 'cmpop': ((), ()), + 'slice': ((), ()), + 'pattern': ((), ()), + 'type_ignore': ((), ()), + 'type_param': ((), ()), + 'excepthandler': ((), ()), +} + +_DOCS: dict[str, str] = { + 'FunctionDef': '函数定义节点(对应 def 语句)。', + 'AsyncFunctionDef': '异步函数定义节点(对应 async def)。', + 'ClassDef': '类定义节点(对应 class 语句)。', + 'AnnAssign': '带注解的赋值节点(x: T = v)。', + 'Constant': '常量节点(数字/字符串/bool/None/Ellipsis)。', + 'Name': '名称节点(标识符引用,含 Load/Store/Del 上下文)。', + 'Call': '函数调用节点。', + 'BinOp': '二元运算节点。', + 'Attribute': '属性访问节点(obj.attr)。', + 'Subscript': '下标访问节点(obj[idx])。', + 'arguments': '函数参数列表节点(含默认值、*args、**kwargs)。', + 'alias': 'import 别名节点。', + 'keyword': '关键字实参节点(f(x=1))。', + 'withitem': 'with 语句上下文节点。', +} + +# 类属性默认值(与 CPython 3.12 ast 节点一致): +# dump 时"实例值为 None 且类默认值为 None"的字段会被跳过; +# 无类默认值的字段(如 Constant.value)即使为 None 也会显示。 +_CLASS_DEFAULTS: dict[str, dict[str, object]] = { + 'AnnAssign': {'value': None}, + 'Assert': {'msg': None}, + 'Assign': {'type_comment': None}, + 'AsyncFor': {'type_comment': None}, + 'AsyncFunctionDef': {'returns': None, 'type_comment': None}, + 'AsyncWith': {'type_comment': None}, + 'Constant': {'kind': None}, + 'ExceptHandler': {'type': None, 'name': None}, + 'For': {'type_comment': None}, + 'FormattedValue': {'format_spec': None}, + 'FunctionDef': {'returns': None, 'type_comment': None}, + 'ImportFrom': {'module': None, 'level': None}, + 'match_case': {'guard': None}, + 'MatchAs': {'pattern': None, 'name': None}, + 'MatchMapping': {'rest': None}, + 'MatchStar': {'name': None}, + 'Raise': {'exc': None, 'cause': None}, + 'Return': {'value': None}, + 'Slice': {'lower': None, 'upper': None, 'step': None}, + 'TypeVar': {'bound': None}, + 'With': {'type_comment': None}, + 'Yield': {'value': None}, + 'alias': {'asname': None}, + 'arg': {'annotation': None, 'type_comment': None}, + 'arguments': {'vararg': None, 'kwarg': None}, + 'keyword': {'arg': None}, + 'withitem': {'optional_vars': None}, +} + + +# 节点抽象基类映射(与 CPython 3.12 一致:expr/stmt/mod/operator/cmpop/...) +# 节点类继承对应的抽象基类,使 isinstance(node, ast.expr) 等判断可用 +_BASE_CLASS: dict[str, str] = { + # stmt + 'AnnAssign': 'stmt', 'Assert': 'stmt', 'Assign': 'stmt', 'AsyncFor': 'stmt', + 'AsyncFunctionDef': 'stmt', 'AsyncWith': 'stmt', 'AugAssign': 'stmt', + 'Break': 'stmt', 'ClassDef': 'stmt', 'Continue': 'stmt', 'Delete': 'stmt', + 'Expr': 'stmt', 'For': 'stmt', 'FunctionDef': 'stmt', 'Global': 'stmt', + 'If': 'stmt', 'Import': 'stmt', 'ImportFrom': 'stmt', 'Match': 'stmt', + 'Nonlocal': 'stmt', 'Pass': 'stmt', 'Raise': 'stmt', 'Return': 'stmt', + 'Try': 'stmt', 'TryStar': 'stmt', 'TypeAlias': 'stmt', 'While': 'stmt', + 'With': 'stmt', + # expr + 'Attribute': 'expr', 'Await': 'expr', 'BinOp': 'expr', 'BoolOp': 'expr', + 'Call': 'expr', 'Compare': 'expr', 'Constant': 'expr', 'Dict': 'expr', + 'DictComp': 'expr', 'FormattedValue': 'expr', 'GeneratorExp': 'expr', + 'IfExp': 'expr', 'JoinedStr': 'expr', 'Lambda': 'expr', 'List': 'expr', + 'ListComp': 'expr', 'Name': 'expr', 'NamedExpr': 'expr', 'Set': 'expr', + 'SetComp': 'expr', 'Slice': 'expr', 'Starred': 'expr', 'Subscript': 'expr', + 'Tuple': 'expr', 'UnaryOp': 'expr', 'Yield': 'expr', 'YieldFrom': 'expr', + # mod + 'Module': 'mod', 'Interactive': 'mod', 'Expression': 'mod', + 'FunctionType': 'mod', 'Suite': 'mod', + # operator + 'Add': 'operator', 'Sub': 'operator', 'Mult': 'operator', 'MatMult': 'operator', + 'Div': 'operator', 'Mod': 'operator', 'Pow': 'operator', 'LShift': 'operator', + 'RShift': 'operator', 'BitOr': 'operator', 'BitXor': 'operator', + 'BitAnd': 'operator', 'FloorDiv': 'operator', + # unaryop + 'Invert': 'unaryop', 'Not': 'unaryop', 'UAdd': 'unaryop', 'USub': 'unaryop', + # boolop + 'And': 'boolop', 'Or': 'boolop', + # cmpop + 'Eq': 'cmpop', 'NotEq': 'cmpop', 'Lt': 'cmpop', 'LtE': 'cmpop', + 'Gt': 'cmpop', 'GtE': 'cmpop', 'Is': 'cmpop', 'IsNot': 'cmpop', + 'In': 'cmpop', 'NotIn': 'cmpop', + # expr_context + 'Load': 'expr_context', 'Store': 'expr_context', 'Del': 'expr_context', + 'AugLoad': 'expr_context', 'AugStore': 'expr_context', 'Param': 'expr_context', + # slice + 'Index': 'slice', 'ExtSlice': 'slice', + # pattern + 'MatchValue': 'pattern', 'MatchSingleton': 'pattern', 'MatchSequence': 'pattern', + 'MatchMapping': 'pattern', 'MatchClass': 'pattern', 'MatchStar': 'pattern', + 'MatchAs': 'pattern', 'MatchOr': 'pattern', + # type_param / type_ignore + 'TypeVar': 'type_param', 'TypeVarTuple': 'type_param', 'ParamSpec': 'type_param', + 'TypeIgnore': 'type_ignore', + # excepthandler + 'ExceptHandler': 'excepthandler', +} + + +def _MakeNodeClass(name: str, fields: tuple[str, ...], attrs: tuple[str, ...]) -> type: + """按字段表生成节点类(继承对应抽象基类)。""" + + def _Init(self: AST, *args: object, **kwargs: object) -> None: + if len(args) > len(fields): + raise TypeError( + f'{name} constructor takes at most {len(fields)} positional arguments' + ) + for fname, val in zip(fields, args): + setattr(self, fname, val) + for k, v in kwargs.items(): + setattr(self, k, v) + + base_name: str | None = _BASE_CLASS.get(name) + base_cls: type = globals()[base_name] if base_name else AST + ns: dict[str, object] = { + '__init__': _Init, + '_fields': fields, + '_attributes': attrs, + '__module__': __name__, + '__doc__': _DOCS.get(name, f'{name} AST 节点(与 ast.{name} 同构)。'), + } + # 类默认值(None 字段在 dump 时跳过) + for fname, fdefault in _CLASS_DEFAULTS.get(name, {}).items(): + ns[fname] = fdefault + cls: type = type(name, (base_cls,), ns) + return cls + + +# 动态生成全部节点类到本模块命名空间 +# 抽象基类(mod/stmt/expr/...)在 _NODE_DEFS 末尾定义,但需先生成 +_ABSTRACT_BASES: tuple[str, ...] = ( + 'mod', 'stmt', 'expr', 'expr_context', 'boolop', 'operator', 'unaryop', + 'cmpop', 'slice', 'pattern', 'type_ignore', 'type_param', 'excepthandler', +) +for _name in _ABSTRACT_BASES: + _fields, _attrs = _NODE_DEFS[_name] + globals()[_name] = _MakeNodeClass(_name, _fields, _attrs) +for _name, (_fields, _attrs) in _NODE_DEFS.items(): + if _name in _ABSTRACT_BASES: + continue + globals()[_name] = _MakeNodeClass(_name, _fields, _attrs) + +# 显式别名:AnnAssign 已在表内;这里保证模块级 __all__ 完整性 +__all__: list[str] = list(_NODE_DEFS.keys()) + ['AST'] diff --git a/lib/vast/Parser.py b/lib/vast/Parser.py new file mode 100644 index 0000000..4cd149c --- /dev/null +++ b/lib/vast/Parser.py @@ -0,0 +1,1044 @@ +"""vast.parser - Viper/Python 语句级语法分析器 + +基于 vast.tokenizer + vast.exprparser,实现与 CPython 3.12 ``ast.parse`` +结构完全一致的语句解析: + +- 简单语句:赋值/增强赋值/带注解赋值/表达式/import/from-import/global/ + nonlocal/del/assert/pass/break/continue/return/raise +- 复合语句:if/while/for/try/with/match/def/class/async def-for-with +- 装饰器、嵌套块(INDENT/DEDENT)、分号分隔、类型注解 +- Viper 软关键字 fn/fun/func/function → FunctionDef(并入解析器,无需 + ExpandSoftKeywords 预处理) + +产出与 CPython ast 完全一致的节点,含 4 位置属性。 +""" +from __future__ import annotations + +from lib.vast import Nodes as N +from lib.vast.ExprParser import ExprParserMixin +from lib.vast.Tokenizer import ( + Token, NAME, NUMBER, STRING, FSTRING, OP, NEWLINE, NL, INDENT, DEDENT, + ENDMARKER, SOFT_KEYWORDS, +) + + +class Parser(ExprParserMixin): + """Viper/Python 完整语法分析器。""" + + # ================================================================== + # 模块级入口 + # ================================================================== + def ParseModule(self) -> N.Module: + """解析整个模块:返回 Module(body=..., type_ignores=[])。""" + body: list[N.stmt] = [] + self._SkipNEWLINE() + while self._Peek().Type != ENDMARKER: + stmt: N.stmt = self.ParseStatement() + body.append(stmt) + # 分号分隔后续语句(简单语句一行多条) + while self._AtOp(';'): + self._Next() + if self._At(NEWLINE): + break + extra: N.stmt = self.ParseStatement() + self._FixLoc(extra, stmt) + body.append(extra) + self._SkipNEWLINE() + module: N.Module = N.Module(body=body, type_ignores=[]) + return module + + # ================================================================== + # 语句分派 + # ================================================================== + def ParseStatement(self) -> N.stmt: + """解析单条语句(含复合语句分派)。""" + tok: Token = self._Peek() + if tok.Type == NAME: + v: str = tok.Value + # 软关键字函数定义:fn/fun/func/function + 标识符 + if v in SOFT_KEYWORDS and self._Peek(1).Type == NAME: + return self._ParseFunctionDef() + if v == 'async': + nxt: Token = self._Peek(1) + if nxt.Type == NAME and nxt.Value == 'def': + return self._ParseFunctionDef(is_async=True) + if nxt.Type == NAME and nxt.Value == 'for': + return self._ParseFor(is_async=True) + if nxt.Type == NAME and nxt.Value == 'with': + return self._ParseWith(is_async=True) + if v == 'def': + return self._ParseFunctionDef() + if v == 'class': + return self._ParseClassDef() + if v == 'if': + return self._ParseIf() + if v == 'while': + return self._ParseWhile() + if v == 'for': + return self._ParseFor() + if v == 'try': + return self._ParseTry() + if v == 'with': + return self._ParseWith() + if v == 'match': + # 软关键字 match:尝试 match 语句,失败回退为表达式 + save: int = self.Idx + try: + return self._ParseMatch() + except SyntaxError: + self.Idx = save + if v == 'return': + return self._ParseReturn() + if v == 'raise': + return self._ParseRaise() + if v == 'import': + return self._ParseImport() + if v == 'from': + return self._ParseImportFrom() + if v == 'global': + return self._ParseGlobal('global') + if v == 'nonlocal': + return self._ParseGlobal('nonlocal') + if v == 'del': + return self._ParseDelete() + if v == 'assert': + return self._ParseAssert() + if v == 'pass': + self._Next() + node: N.Pass = N.Pass() + self._FixLoc(node, tok) + return node + if v == 'break': + self._Next() + node = N.Break() + self._FixLoc(node, tok) + return node + if v == 'continue': + self._Next() + node = N.Continue() + self._FixLoc(node, tok) + return node + if v == 'yield': + # yield 作为表达式语句 + return self._ParseExprStmt() + if tok.Type == OP and tok.Value == '@': + return self._ParseDecorated() + return self._ParseSimpleStmt() + + # ================================================================== + # 简单语句 + # ================================================================== + def _ParseSimpleStmt(self) -> N.stmt: + """解析简单语句(赋值/增强赋值/带注解赋值/表达式)。 + + 不消费分号/NEWLINE,由调用方循环(ParseModule/_ParseSuite)统一处理。 + """ + start: Token = self._Peek() + # 尝试带注解赋值 x: T [= v] + ann: N.stmt | None = self._TryParseAnnAssign() + if ann is not None: + return ann + # 表达式/赋值(testlist_star_expr) + expr: N.expr = self.ParseExprList() + # 赋值链 + if self._AtOp('='): + targets: list[N.expr] = [self._AsLoadTarget(expr)] + while True: + self._Next() # '=' + value: N.expr = self.ParseExprList() + if self._AtOp('='): + targets.append(self._AsLoadTarget(value)) + continue + break + node: N.Assign = N.Assign(targets=targets, value=value, type_comment=None) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('+='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Add(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('-='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Sub(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('*='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Mult(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('/='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Div(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('//='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.FloorDiv(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('%='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Mod(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('**='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Pow(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('<<='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.LShift(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('>>='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.RShift(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('&='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.BitAnd(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('|='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.BitOr(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('^='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.BitXor(), value=value) + self._FixLoc(node, start) + stmt = node + elif self._AtOp('@='): + self._Next() + value = self.ParseExpr() + node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.MatMult(), value=value) + self._FixLoc(node, start) + stmt = node + else: + node = N.Expr(value=expr) + self._FixLoc(node, start) + stmt = node + return stmt + + def _AsLoadTarget(self, expr: N.expr) -> N.expr: + """将已解析表达式(Load 上下文)转为赋值目标(Store 上下文)。""" + self._SetStoreContext(expr) + return expr + + def _TryParseAnnAssign(self) -> N.AnnAssign | None: + """尝试解析带注解赋值:x: T [= v] 或 x: T(目标为 Name/Attribute/Subscript)。 + + 注意:仅当目标为简单 Name/Attribute/Subscript 且后随 ':' 时匹配; + 元组/列表解包不做注解(返回 None 走普通路径)。 + """ + start: Token = self._Peek() + # 名称 + if self._At(NAME) and self._Peek(1).Type == OP and self._Peek(1).Value == ':': + name_tok: Token = self._Next() + self._Next() # ':' + annotation: N.expr = self.ParseExpr() + value: N.expr | None = None + if self._AtOp('='): + self._Next() + value = self.ParseExpr() + target: N.Name = N.Name(id=name_tok.Value, ctx=N.Store()) + self._FixLoc(target, name_tok) + node: N.AnnAssign = N.AnnAssign(target=target, annotation=annotation, + value=value, simple=1) + self._FixLoc(node, start) + return node + # 属性/下标目标(无简单解包) + if self._At(NAME) or (self._At(OP) and self._Peek().Value in ('(', '[')): + save: int = self.Idx + try: + expr: N.expr = self.ParseExpr() + except SyntaxError: + self.Idx = save + return None + if self._AtOp(':') and isinstance(expr, (N.Name, N.Attribute, N.Subscript)): + self._Next() + annotation = self.ParseExpr() + value = None + if self._AtOp('='): + self._Next() + value = self.ParseExpr() + self._SetStoreContext(expr) + simple: int = 1 if isinstance(expr, N.Name) else 0 + node = N.AnnAssign(target=expr, annotation=annotation, value=value, simple=simple) + self._FixLoc(node, start) + return node + self.Idx = save + return None + + # ------------------------------------------------------------------ + # return / raise / import / global / del / assert + # ------------------------------------------------------------------ + def _ParseReturn(self) -> N.Return: + start: Token = self._Next() # 'return' + value: N.expr | None = None + if not self._At(NEWLINE) and not self._AtOp(';'): + value = self.ParseExprList() + node: N.Return = N.Return(value=value) + self._FixLoc(node, start) + return node + + def _ParseRaise(self) -> N.Raise: + start: Token = self._Next() # 'raise' + exc: N.expr | None = None + cause: N.expr | None = None + if not self._At(NEWLINE) and not self._AtOp(';'): + exc = self.ParseExpr() + if self._AtName('from'): + self._Next() + cause = self.ParseExpr() + node: N.Raise = N.Raise(exc=exc, cause=cause) + self._FixLoc(node, start) + return node + + def _ParseImport(self) -> N.Import: + start: Token = self._Next() # 'import' + names: list[N.alias] = [] + while True: + name_parts: list[str] = [] + asname: str | None = None + # 点分模块名 + name_parts.append(self._ExpectName().Value) + while self._AtOp('.'): + self._Next() + name_parts.append(self._ExpectName().Value) + full: str = '.'.join(name_parts) + if self._AtName('as'): + self._Next() + asname = self._ExpectName().Value + alias: N.alias = N.alias(name=full, asname=asname) + self._FixLoc(alias, start) + names.append(alias) + if self._AtOp(','): + self._Next() + continue + break + node: N.Import = N.Import(names=names) + self._FixLoc(node, start) + return node + + def _ParseImportFrom(self) -> N.ImportFrom: + start: Token = self._Next() # 'from' + level: int = 0 + while self._AtOp('.'): + self._Next() + level += 1 + module: str | None = None + # from . import x → 点后直接是 import(无模块名) + if not self._AtName('import'): + parts: list[str] = [self._ExpectName().Value] + while self._AtOp('.'): + self._Next() + parts.append(self._ExpectName().Value) + module = '.'.join(parts) + self._ExpectName('import') + names: list[N.alias] = [] + # from x import * | (a, b) | a, b + if self._AtOp('('): + self._Next() + self._SkipNL() + if not self._AtOp(')'): + while True: + names.append(self._ParseImportAlias(start)) + self._SkipNL() + if self._AtOp(','): + self._Next() + self._SkipNL() + if self._AtOp(')'): + break + continue + break + self._ExpectOp(')') + else: + if self._AtOp('*'): + self._Next() + alias = N.alias(name='*', asname=None) + self._FixLoc(alias, start) + names.append(alias) + else: + while True: + names.append(self._ParseImportAlias(start)) + if self._AtOp(','): + self._Next() + continue + break + node: N.ImportFrom = N.ImportFrom(module=module, names=names, level=level) + self._FixLoc(node, start) + return node + + def _ParseImportAlias(self, start: Token) -> N.alias: + """解析单个 import 别名:name [as alias]。""" + name: str = self._ExpectName().Value + asname: str | None = None + if self._AtName('as'): + self._Next() + asname = self._ExpectName().Value + alias: N.alias = N.alias(name=name, asname=asname) + self._FixLoc(alias, start) + return alias + + def _ParseGlobal(self, kw: str) -> N.AST: + start: Token = self._Next() + names: list[str] = [] + while True: + names.append(self._ExpectName().Value) + if self._AtOp(','): + self._Next() + continue + break + node: N.AST = N.Global(names=names) if kw == 'global' else N.Nonlocal(names=names) + self._FixLoc(node, start) + return node + + def _ParseDelete(self) -> N.Delete: + start: Token = self._Next() # 'del' + targets: list[N.expr] = [] + while True: + expr: N.expr = self.ParseExpr() + self._SetDelContext(expr) + targets.append(expr) + if self._AtOp(','): + self._Next() + continue + break + node: N.Delete = N.Delete(targets=targets) + self._FixLoc(node, start) + return node + + def _SetDelContext(self, node: N.AST) -> None: + """将 Load 上下文节点递归改为 Del(del 语句目标)。""" + if isinstance(node, N.Name): + node.ctx = N.Del() + elif isinstance(node, N.Attribute): + node.ctx = N.Del() + elif isinstance(node, N.Subscript): + node.ctx = N.Del() + elif isinstance(node, (N.Tuple, N.List)): + node.ctx = N.Del() + for elt in node.elts: + self._SetDelContext(elt) + + def _ParseAssert(self) -> N.Assert: + start: Token = self._Next() # 'assert' + test: N.expr = self.ParseExpr() + msg: N.expr | None = None + if self._AtOp(','): + self._Next() + msg = self.ParseExpr() + node: N.Assert = N.Assert(test=test, msg=msg) + self._FixLoc(node, start) + return node + + def _ConsumeSemicolons(self) -> None: + """消费语句后的分号(允许空语句 ;;)。""" + while self._AtOp(';'): + self._Next() + + # ------------------------------------------------------------------ + # 表达式语句(含 yield) + # ------------------------------------------------------------------ + def _ParseExprStmt(self) -> N.stmt: + start: Token = self._Peek() + # yield 语句:yield [expr_list] + if self._AtName('yield'): + expr: N.expr = self._ParseYield() + else: + expr = self.ParseExprList() + node: N.Expr = N.Expr(value=expr) + self._FixLoc(node, start) + return node + + # ================================================================== + # 装饰器 + # ================================================================== + def _ParseDecorated(self) -> N.stmt: + """解析装饰器列表 + def/class。""" + decorator_list: list[N.expr] = [] + while self._AtOp('@'): + deco_start: Token = self._Next() # '@' + deco: N.expr = self.ParseExpr() + self._FixLoc(deco, deco_start) + decorator_list.append(deco) + self._ExpectNEWLINE() + self._SkipNEWLINE() + tok: Token = self._Peek() + if tok.Type == NAME and tok.Value == 'def': + return self._ParseFunctionDef(decorators=decorator_list) + if tok.Type == NAME and tok.Value == 'async': + nxt: Token = self._Peek(1) + if nxt.Type == NAME and nxt.Value == 'def': + return self._ParseFunctionDef(is_async=True, decorators=decorator_list) + if tok.Type == NAME and tok.Value == 'class': + return self._ParseClassDef(decorators=decorator_list) + raise SyntaxError(f"decorator must be followed by def/class, got {tok.Value!r}") + + # ================================================================== + # 函数定义(含软关键字 fn/fun/func/function) + # ================================================================== + def _ParseFunctionDef(self, is_async: bool = False, + decorators: list[N.expr] | None = None) -> N.FunctionDef: + start: Token = self._Next() # def/fn/...(或 async) + if start.Value == 'async': + start = self._Next() # def + name_tok: Token = self._ExpectName() + # 类型参数(PEP 695):def f[T]( + type_params: list[N.AST] = [] + if self._AtOp('['): + type_params = self._ParseTypeParams() + args: N.arguments = self._ParseArguments() + returns: N.expr | None = None + if self._AtOp('->'): + self._Next() + returns = self.ParseExpr() + self._ExpectOp(':') + body: list[N.stmt] = self._ParseSuite() + cls: type = N.AsyncFunctionDef if is_async else N.FunctionDef + node: N.FunctionDef = cls( + name=name_tok.Value, args=args, body=body, + decorator_list=decorators or [], returns=returns, + type_comment=None, type_params=type_params, + ) + self._FixLoc(node, start) + return node + + def _ParseTypeParams(self) -> list[N.AST]: + """解析 PEP 695 类型参数:[T, *Ts, **P, U: Bound]""" + self._ExpectOp('[') + self._SkipNL() + params: list[N.AST] = [] + if not self._AtOp(']'): + while True: + self._SkipNL() + star: int = 0 + if self._AtOp('*'): + self._Next() + star = 1 + elif self._AtOp('**'): + self._Next() + star = 2 + name_tok: Token = self._ExpectName() + bound: N.expr | None = None + if star == 0 and self._AtOp(':'): + self._Next() + bound = self.ParseExpr() + if star == 1: + tvt: N.TypeVarTuple = N.TypeVarTuple(name=name_tok.Value) + self._FixLoc(tvt, name_tok) + params.append(tvt) + elif star == 2: + ps: N.ParamSpec = N.ParamSpec(name=name_tok.Value) + self._FixLoc(ps, name_tok) + params.append(ps) + else: + tv: N.TypeVar = N.TypeVar(name=name_tok.Value, bound=bound) + self._FixLoc(tv, name_tok) + params.append(tv) + self._SkipNL() + if self._AtOp(','): + self._Next() + continue + break + self._ExpectOp(']') + return params + + # ================================================================== + # 类定义 + # ================================================================== + def _ParseClassDef(self, decorators: list[N.expr] | None = None) -> N.ClassDef: + start: Token = self._Next() # class + name_tok: Token = self._ExpectName() + type_params: list[N.AST] = [] + if self._AtOp('['): + type_params = self._ParseTypeParams() + bases: list[N.expr] = [] + keywords: list[N.keyword] = [] + if self._AtOp('('): + self._Next() + self._SkipNL() + if not self._AtOp(')'): + while True: + self._SkipNL() + if self._AtOp('**'): + self._Next() + value: N.expr = self.ParseExpr() + kw: N.keyword = N.keyword(arg=None, value=value) + self._FixLoc(kw, self._Prev()) + keywords.append(kw) + elif self._At(NAME) and self._Peek(1).Type == OP and self._Peek(1).Value == '=': + arg_tok: Token = self._Next() + self._Next() # '=' + value = self.ParseExpr() + kw = N.keyword(arg=arg_tok.Value, value=value) + self._FixLoc(kw, arg_tok) + keywords.append(kw) + else: + bases.append(self.ParseExpr()) + self._SkipNL() + if self._AtOp(','): + self._Next() + self._SkipNL() + if self._AtOp(')'): + break + continue + break + self._ExpectOp(')') + self._ExpectOp(':') + body: list[N.stmt] = self._ParseSuite() + node: N.ClassDef = N.ClassDef( + name=name_tok.Value, bases=bases, keywords=keywords, body=body, + decorator_list=decorators or [], type_params=type_params, + ) + self._FixLoc(node, start) + return node + + # ================================================================== + # 语句块(套件) + # ================================================================== + def _ParseSuite(self) -> list[N.stmt]: + """解析语句块:':' NEWLINE INDENT ... DEDENT 或单行简单语句。 + + 块首允许出现空行/注释行(NL),跳过后再检测 INDENT。 + """ + # 已消费 ':' 后的情况:检查是否换行 + if self._At(NEWLINE): + self._Next() + # 跳过空行/注释行 + while self._At(NL): + self._Next() + if self._At(INDENT): + self._Next() + body: list[N.stmt] = [] + self._SkipNEWLINE() + while self._Peek().Type != DEDENT and self._Peek().Type != ENDMARKER: + stmt: N.stmt = self.ParseStatement() + body.append(stmt) + # 分号分隔后续语句 + while self._AtOp(';'): + self._Next() + if self._At(NEWLINE): + break + extra: N.stmt = self.ParseStatement() + self._FixLoc(extra, stmt) + body.append(extra) + self._SkipNEWLINE() + self._Expect(DEDENT) + return body + # 空套件(语法错误,宽松返回空) + return [] + # 单行套件:statement (; statement)* NEWLINE + body = [self.ParseStatement()] + while self._AtOp(';'): + self._Next() + if self._At(NEWLINE): + break + body.append(self.ParseStatement()) + self._ExpectNEWLINE() + return body + + def _Expect(self, tok_type: str, value: str | None = None) -> Token: + """期望指定类型的 token。""" + tok: Token = self._Next() + if tok.Type != tok_type or (value is not None and tok.Value != value): + raise SyntaxError( + f"expected {tok_type}({value!r}), got {tok.Type}({tok.Value!r}) " + f"at line {tok.Line}" + ) + return tok + + def _ConsumeNewlines(self) -> None: + """消费连续 NEWLINE(空行)。""" + while self._At(NEWLINE): + self._Next() + + # ================================================================== + # if / while / for / try / with / match + # ================================================================== + def _ParseIf(self) -> N.If: + start: Token = self._Next() # if + test: N.expr = self.ParseExpr() + self._ExpectOp(':') + body: list[N.stmt] = self._ParseSuite() + orelse: list[N.stmt] = [] + if self._AtName('elif'): + # elif → 嵌套 If 于 orelse + orelse.append(self._ParseIf()) + elif self._AtName('else'): + self._Next() + self._ExpectOp(':') + orelse = self._ParseSuite() + node: N.If = N.If(test=test, body=body, orelse=orelse) + self._FixLoc(node, start) + return node + + def _ParseWhile(self) -> N.While: + start: Token = self._Next() # while + test: N.expr = self.ParseExpr() + self._ExpectOp(':') + body: list[N.stmt] = self._ParseSuite() + orelse: list[N.stmt] = [] + if self._AtName('else'): + self._Next() + self._ExpectOp(':') + orelse = self._ParseSuite() + node: N.While = N.While(test=test, body=body, orelse=orelse) + self._FixLoc(node, start) + return node + + def _ParseFor(self, is_async: bool = False) -> N.For: + start: Token = self._Next() + if start.Value == 'async': + start = self._Next() # for + target: N.expr = self._ParseTargetList() + self._ExpectName('in') + iterable: N.expr = self.ParseExpr() + self._ExpectOp(':') + body: list[N.stmt] = self._ParseSuite() + orelse: list[N.stmt] = [] + if self._AtName('else'): + self._Next() + self._ExpectOp(':') + orelse = self._ParseSuite() + cls: type = N.AsyncFor if is_async else N.For + node: N.For = cls(target=target, iter=iterable, body=body, orelse=orelse, + type_comment=None) + self._FixLoc(node, start) + return node + + def _ParseTargetList(self) -> N.expr: + """解析 for 目标列表(支持裸元组 a, b = ...)。""" + start: Token = self._Peek() + first: N.expr = self._ParseTarget() + if self._AtOp(','): + elts: list[N.expr] = [first] + while self._AtOp(','): + self._Next() + self._SkipNL() + elts.append(self._ParseTarget()) + tup: N.Tuple = N.Tuple(elts=elts, ctx=N.Store()) + self._FixLoc(tup, start) + return tup + return first + + def _ParseTry(self) -> N.Try: + start: Token = self._Next() # try + self._ExpectOp(':') + body: list[N.stmt] = self._ParseSuite() + handlers: list[N.ExceptHandler] = [] + orelse: list[N.stmt] = [] + finalbody: list[N.stmt] = [] + is_star: bool = False + while self._AtName('except'): + self._Next() + if self._AtOp('*'): + is_star = True + self._Next() + handlers.append(self._ParseExceptHandler()) + if self._AtName('else'): + self._Next() + self._ExpectOp(':') + orelse = self._ParseSuite() + if self._AtName('finally'): + self._Next() + self._ExpectOp(':') + finalbody = self._ParseSuite() + cls: type = N.TryStar if is_star else N.Try + node: N.Try = cls(body=body, handlers=handlers, orelse=orelse, finalbody=finalbody) + self._FixLoc(node, start) + return node + + def _ParseExceptHandler(self) -> N.ExceptHandler: + start: Token = self._Peek() + exc_type: N.expr | None = None + name: str | None = None + if not self._AtOp(':'): + exc_type = self.ParseExpr() + if self._AtName('as'): + self._Next() + name = self._ExpectName().Value + self._ExpectOp(':') + handler_body: list[N.stmt] = self._ParseSuite() + node: N.ExceptHandler = N.ExceptHandler(type=exc_type, name=name, body=handler_body) + self._FixLoc(node, start) + return node + + def _ParseWith(self, is_async: bool = False) -> N.With: + start: Token = self._Next() + if start.Value == 'async': + start = self._Next() # with + items: list[N.withitem] = [] + while True: + ctx: N.expr = self.ParseExpr() + optional_vars: N.expr | None = None + if self._AtName('as'): + self._Next() + optional_vars = self._ParseTarget() + item: N.withitem = N.withitem(context_expr=ctx, optional_vars=optional_vars) + self._FixLoc(item, start) + items.append(item) + if self._AtOp(','): + self._Next() + continue + break + self._ExpectOp(':') + body: list[N.stmt] = self._ParseSuite() + cls: type = N.AsyncWith if is_async else N.With + node: N.With = cls(items=items, body=body, type_comment=None) + self._FixLoc(node, start) + return node + + # ================================================================== + # match 语句(PEP 634) + # ================================================================== + def _ParseMatch(self) -> N.Match: + start: Token = self._Next() # match + subject: N.expr = self.ParseExpr() + self._ExpectOp(':') + self._ExpectNEWLINE() + self._Expect(INDENT) + cases: list[N.match_case] = [] + self._SkipNEWLINE() + while self._AtName('case'): + case_start: Token = self._Next() # case + pattern: N.pattern = self._ParsePattern() + guard: N.expr | None = None + if self._AtName('if'): + self._Next() + guard = self.ParseExpr() + self._ExpectOp(':') + case_body: list[N.stmt] = self._ParseSuite() + mc: N.match_case = N.match_case(pattern=pattern, guard=guard, body=case_body) + self._FixLoc(mc, case_start) + cases.append(mc) + self._SkipNEWLINE() + self._Expect(DEDENT) + node: N.Match = N.Match(subject=subject, cases=cases) + self._FixLoc(node, start) + return node + + def _ParsePattern(self) -> N.pattern: + """解析 match 模式(顶层,处理 | 或模式)。""" + start: Token = self._Peek() + patterns: list[N.pattern] = [self._ParsePatternOr()] + while self._AtOp('|'): + self._Next() + patterns.append(self._ParsePatternOr()) + if len(patterns) == 1: + return patterns[0] + node: N.MatchOr = N.MatchOr(patterns=patterns) + self._FixLoc(node, start) + return node + + def _ParsePatternOr(self) -> N.pattern: + """解析单模式(含 as 绑定)。""" + start: Token = self._Peek() + pat: N.pattern = self._ParsePatternAtom() + if self._AtName('as'): + self._Next() + name: str = self._ExpectName().Value + node: N.MatchAs = N.MatchAs(pattern=pat, name=name) + self._FixLoc(node, start) + return node + return pat + + def _ParsePatternAtom(self) -> N.pattern: + """解析模式原子:字面量/捕获/序列/映射/类/通配符。""" + start: Token = self._Peek() + tok: Token = self._Peek() + # 通配符 / 捕获 + if tok.Type == NAME: + # 字面量 True/False/None + if tok.Value in ('True', 'False', 'None'): + self._Next() + node: N.MatchSingleton = N.MatchSingleton( + value={'True': True, 'False': False, 'None': None}[tok.Value]) + self._FixLoc(node, tok) + return node + # 类模式:Name(...) 或 a.b(...) + if self._Peek(1).Type == OP and self._Peek(1).Value == '(': + return self._ParseMatchClass() + # 属性值模式 a.b(无括号) + if self._Peek(1).Type == OP and self._Peek(1).Value == '.': + return self._ParseMatchValueAttr() + # 捕获模式(含 _ 通配符;_ 产生空 MatchAs 与 CPython 一致) + self._Next() + node = N.MatchAs(pattern=None, name=None if tok.Value == '_' else tok.Value) + self._FixLoc(node, tok) + return node + # 序列模式 [a, b] / (a, b) + if tok.Type == OP and tok.Value in ('[', '('): + return self._ParseMatchSequence() + # 映射模式 {k: v, **rest} + if tok.Type == OP and tok.Value == '{': + return self._ParseMatchMapping() + # 字面量:数字/字符串/负号 + if tok.Type == NUMBER or tok.Type == STRING or tok.Type == FSTRING: + value: N.expr = self.ParseExpr() + node = N.MatchValue(value=value) + self._FixLoc(node, start) + return node + if tok.Type == OP and tok.Value in ('-', '+'): + value = self.ParseExpr() + node = N.MatchValue(value=value) + self._FixLoc(node, start) + return node + if tok.Type == OP and tok.Value == '*': + self._Next() + name = None + if not self._At(NEWLINE) and not self._AtOp(','): + name = self._ExpectName().Value + node = N.MatchStar(name=name) + self._FixLoc(node, tok) + return node + raise SyntaxError(f"unexpected pattern token {tok.Type}({tok.Value!r})") + + def _ParseMatchValueAttr(self) -> N.pattern: + """解析值模式属性访问:a.b.c(无括号)。""" + start: Token = self._Peek() + expr: N.expr = self.ParseExpr() + node: N.MatchValue = N.MatchValue(value=expr) + self._FixLoc(node, start) + return node + + def _ParseMatchClass(self) -> N.pattern: + """解析类模式:Name(pos, kw=v, ...) 或 a.b.c(...)。 + + 类名仅解析 Name/Attribute 链(不消费调用括号),括号由本方法消费。 + """ + start: Token = self._Peek() + cls_name: N.expr = self._ParsePatternClassName() + self._ExpectOp('(') + self._SkipNL() + patterns: list[N.pattern] = [] + kwd_attrs: list[str] = [] + kwd_patterns: list[N.pattern] = [] + if not self._AtOp(')'): + while True: + self._SkipNL() + if self._AtOp('*'): + self._Next() + patterns.append(self._ParsePattern()) + elif self._At(NAME) and self._Peek(1).Type == OP and self._Peek(1).Value == '=': + attr_tok: Token = self._Next() + self._Next() # '=' + kwd_attrs.append(attr_tok.Value) + kwd_patterns.append(self._ParsePattern()) + else: + patterns.append(self._ParsePattern()) + self._SkipNL() + if self._AtOp(','): + self._Next() + if self._AtOp(')'): + break + continue + break + self._ExpectOp(')') + node: N.MatchClass = N.MatchClass(cls=cls_name, patterns=patterns, + kwd_attrs=kwd_attrs, kwd_patterns=kwd_patterns) + self._FixLoc(node, start) + return node + + def _ParsePatternClassName(self) -> N.expr: + """解析类模式的类名(Name / a.b.c 属性链,不含调用括号)。""" + start: Token = self._Peek() + name_tok: Token = self._ExpectName() + node: N.expr = N.Name(id=name_tok.Value, ctx=N.Load()) + self._FixLoc(node, name_tok) + while self._AtOp('.'): + self._Next() + attr_tok: Token = self._ExpectName() + attr_node: N.Attribute = N.Attribute(value=node, attr=attr_tok.Value, ctx=N.Load()) + self._FixLoc(attr_node, start) + node = attr_node + return node + + def _ParseMatchSequence(self) -> N.pattern: + start: Token = self._Next() # '[' 或 '(' + close: str = ']' if start.Value == '[' else ')' + patterns: list[N.pattern] = [] + self._SkipNL() + if not self._AtOp(close): + while True: + self._SkipNL() + patterns.append(self._ParsePattern()) + self._SkipNL() + if self._AtOp(','): + self._Next() + if self._AtOp(close): + break + continue + break + self._ExpectOp(close) + node: N.MatchSequence = N.MatchSequence(patterns=patterns) + self._FixLoc(node, start) + return node + + def _ParseMatchMapping(self) -> N.pattern: + start: Token = self._Next() # '{' + keys: list[N.expr] = [] + patterns: list[N.pattern] = [] + rest: str | None = None + self._SkipNL() + if not self._AtOp('}'): + while True: + self._SkipNL() + if self._AtOp('**'): + self._Next() + rest = self._ExpectName().Value + else: + key: N.expr = self.ParseExpr() + self._ExpectOp(':') + keys.append(key) + patterns.append(self._ParsePattern()) + self._SkipNL() + if self._AtOp(','): + self._Next() + if self._AtOp('}'): + break + continue + break + self._ExpectOp('}') + node: N.MatchMapping = N.MatchMapping(keys=keys, patterns=patterns, rest=rest) + self._FixLoc(node, start) + return node + + +def Parse(source: str) -> N.Module: + """便捷入口:源码字符串 → Module AST(供 vast.parse 调用)。""" + from lib.vast.Tokenizer import Tokenizer + + tokens = Tokenizer(source).Tokenize() + line_starts: list[int] = [0] + # 从 token 流重建行起始表(由 Tokenizer 维护,此处直接计算) + line_starts = _ComputeLineStarts(source) + parser: Parser = Parser(tokens, source, line_starts) + return parser.ParseModule() + + +def _ComputeLineStarts(source: str) -> list[int]: + """计算源码所有行起始字符索引(含首行 0)。""" + starts: list[int] = [0] + for i, ch in enumerate(source): + if ch == '\n': + starts.append(i + 1) + return starts diff --git a/lib/vast/Tokenizer.py b/lib/vast/Tokenizer.py new file mode 100644 index 0000000..859bdde --- /dev/null +++ b/lib/vast/Tokenizer.py @@ -0,0 +1,490 @@ +"""vast.tokenizer - Viper/Python 词法分析器 + +将源码字符串切分为 token 流,与 CPython 3.12 ``tokenize`` 语义对齐: + +- 支持缩进 INDENT/DEDENT、逻辑行 NEWLINE、括号内续行 +- 支持字符串字面量(单引号/双引号/三引号、r/b/u/f 前缀与组合前缀) +- f-string 作为整体 FSTRING token 输出,内部表达式由 Parser 递归解析 +- 数字字面量(十进制/十六进制/八进制/二进制/浮点/复数 j/下划线分隔) +- 运算符最长匹配 + +位置信息与 CPython 一致:``col_offset`` 为 UTF-8 字节偏移(非字符偏移), +行号为 1-based。行列信息通过行起始索引表 + bisect 统一换算,保证跨行 +token(字符串/三引号)的行列准确。 + +软关键字 fn/fun/func/function 不作为独立 token 类型处理(并入解析器), +tokenizer 产出普通 NAME,由 Parser 在语句首识别为函数定义关键字。 +""" +from __future__ import annotations + +import bisect + +# ============================================================================= +# Token 类型常量 +# ============================================================================= +ENDMARKER = 'ENDMARKER' +NAME = 'NAME' +NUMBER = 'NUMBER' +STRING = 'STRING' +FSTRING = 'FSTRING' +OP = 'OP' +NEWLINE = 'NEWLINE' +INDENT = 'INDENT' +DEDENT = 'DEDENT' +COMMENT = 'COMMENT' +NL = 'NL' + +# 多字符运算符(最长优先,含 Python 3.12 全部运算符) +_OPERATORS: tuple[str, ...] = ( + '**=', '//=', '<<=', '>>=', '**', '//', '<<', '>>', '<=', '>=', '==', '!=', + ':=', '->', '+=', '-=', '*=', '/=', '%=', '@=', '&=', '|=', '^=', '...', + '(', ')', '[', ']', '{', '}', ',', ':', '.', ';', '+', '-', '*', '/', '%', + '@', '&', '|', '^', '~', '<', '>', '=', '!', +) + +# 行首空白 + 关键字 + 空白 + 标识符 → 软关键字函数定义(Parser 层处理) +SOFT_KEYWORDS: frozenset[str] = frozenset({'fn', 'fun', 'func', 'function'}) + +# 字符串前缀字母集合(允许任意顺序/大小写组合,如 fr、Rb、BF) +_STRING_PREFIX_CHARS: frozenset[str] = frozenset('rRbBuUfF') +_F_PREFIX = frozenset('fF') +_R_PREFIX = frozenset('rR') +_B_PREFIX = frozenset('bB') + + +class Token: + """词法 token。 + + Attributes: + Type: token 类型(NAME/NUMBER/STRING/FSTRING/OP/NEWLINE/...) + Value: token 原始文本 + Line: 1-based 行号 + Col: UTF-8 字节偏移(0-based) + EndLine: 结束行号 + EndCol: 结束列(UTF-8 字节偏移) + Start: 源码字符偏移(含 UTF-8 字节偏移换算依赖,供 f-string 内部定位) + End: 源码字符偏移(exclusive) + """ + __slots__ = ('Type', 'Value', 'Line', 'Col', 'EndLine', 'EndCol', 'Start', 'End') + + def __init__(self, tok_type: str, value: str, line: int, col: int, + end_line: int, end_col: int) -> None: + self.Type: str = tok_type + self.Value: str = value + self.Line: int = line + self.Col: int = col + self.EndLine: int = end_line + self.EndCol: int = end_col + self.Start: int = -1 + self.End: int = -1 + + def __repr__(self) -> str: + return (f'Token({self.Type}, {self.Value!r}, ' + f'{self.Line}:{self.Col}-{self.EndLine}:{self.EndCol})') + + +def _IsIdentStart(ch: str) -> bool: + """标识符起始字符:字母或下划线(兼容非 ASCII)。""" + return ch == '_' or ch.isalpha() or ord(ch) > 127 + + +def _IsIdentPart(ch: str) -> bool: + """标识符组成部分:字母/数字/下划线。""" + return ch == '_' or ch.isalnum() or ord(ch) > 127 + + +class Tokenizer: + """Viper/Python 源码 → token 流。 + + Usage:: + + toks: list[Token] = Tokenizer(source).Tokenize() + """ + + def __init__(self, source: str) -> None: + self.Source: str = source + self.Length: int = len(source) + self.Pos: int = 0 # 当前字符索引 + self.Tokens: list[Token] = [] + # 括号深度:>0 表示在括号内(逻辑行不结束) + self.BracketDepth: int = 0 + # 缩进栈:0 为根 + self.Indents: list[int] = [0] + # 行首标志(决定是否进行缩进分析) + self.AtLineStart: bool = True + # 反斜杠续行延续标志:续行后的物理行行首空白不产生 INDENT + self.ContinuationLine: bool = False + # 空行/注释行标志:本物理行无实质内容,行尾换行产 NL 而非 NEWLINE + self.BlankLine: bool = False + # 注释 token 收集(Parser 忽略,但保留供诊断) + self.Comments: list[Token] = [] + # 行起始字符索引表(索引 0 对应第 1 行),用于行列换算 + self._LineStarts: list[int] = [0] + + # ------------------------------------------------------------------ + # 位置换算 + # ------------------------------------------------------------------ + def _PosInfo(self, pos: int) -> tuple[int, int]: + """将字符索引换算为 (1-based 行号, UTF-8 字节列偏移)。""" + idx: int = bisect.bisect_right(self._LineStarts, pos) - 1 + line: int = idx + 1 + col_bytes: int = len(self.Source[self._LineStarts[idx]:pos].encode('utf-8')) + return line, col_bytes + + def _Make(self, tok_type: str, start: int, end: int) -> Token: + """以 [start, end) 源码区间构造 token。""" + start_line, start_col = self._PosInfo(start) + end_line, end_col = self._PosInfo(end) + tok: Token = Token(tok_type, self.Source[start:end], start_line, start_col, + end_line, end_col) + tok.Start = start + tok.End = end + return tok + + def _RegisterNewline(self, pos_after_nl: int) -> None: + """登记换行:pos_after_nl 是换行序列之后的字符索引(即新行行首)。""" + self._LineStarts.append(pos_after_nl) + + # ------------------------------------------------------------------ + # 主入口 + # ------------------------------------------------------------------ + def Tokenize(self) -> list[Token]: + """执行词法分析,返回完整 token 流(以 ENDMARKER 结尾)。""" + while self.Pos < self.Length: + ch: str = self.Source[self.Pos] + if (self.AtLineStart and self.BracketDepth == 0 + and not self.ContinuationLine and ch not in '\r\n'): + self._HandleIndent() + if self.Pos >= self.Length: + break + continue + if ch in ' \t\f': + self.Pos += 1 + continue + if ch == '\r': + self.Pos += 1 + if self.Pos < self.Length and self.Source[self.Pos] == '\n': + self.Pos += 1 + self._HandleNewline(self.Pos) + continue + if ch == '\n': + self.Pos += 1 + self._HandleNewline(self.Pos) + continue + if ch == '#': + self._ScanComment() + continue + if ch == '\\': + self._ScanContinuation() + continue + if ch in '([{': + self.BracketDepth += 1 + self._EmitOp() + continue + if ch in ')]}': + if self.BracketDepth > 0: + self.BracketDepth -= 1 + self._EmitOp() + continue + if ch == "'" or ch == '"' or _IsIdentStart(ch): + if self._TryScanString(): + continue + if ch.isdigit(): + self._ScanNumber() + continue + if _IsIdentStart(ch): + self._ScanName() + continue + if ch.isdigit() or (ch == '.' and self.Pos + 1 < self.Length + and self.Source[self.Pos + 1].isdigit()): + self._ScanNumber() + continue + self._EmitOp() + self._FinishFile() + return self.Tokens + + # ------------------------------------------------------------------ + # 换行 / 缩进 / 续行 / 注释 + # ------------------------------------------------------------------ + def _HandleNewline(self, pos_after_nl: int) -> None: + """处理物理换行:括号外为 NEWLINE,括号内为 NL。 + + Args: + pos_after_nl: 换行序列之后的字符索引(新行行首)。 + """ + # 找换行序列起点(\n 或 \r\n) + nl_start: int = self.Pos - 1 + if nl_start > 0 and self.Source[nl_start] == '\n' and self.Source[nl_start - 1] == '\r': + nl_start -= 1 + if self.BracketDepth > 0 or self.BlankLine or (self.AtLineStart and not self.ContinuationLine): + self.Tokens.append(self._Make(NL, nl_start, self.Pos)) + else: + self.Tokens.append(self._Make(NEWLINE, nl_start, self.Pos)) + self._RegisterNewline(pos_after_nl) + self.AtLineStart = True + self.ContinuationLine = False + self.BlankLine = False + + def _HandleIndent(self) -> None: + """行首缩进分析:产出 INDENT/DEDENT 或忽略。""" + start: int = self.Pos + col: int = 0 + while self.Pos < self.Length: + ch: str = self.Source[self.Pos] + if ch == ' ': + col += 1 + self.Pos += 1 + elif ch == '\t': + col = (col // 8 + 1) * 8 + self.Pos += 1 + elif ch == '\f': + self.Pos += 1 + else: + break + self.AtLineStart = False + # 空行/注释行不产生缩进 token,且行尾换行应产 NL(逻辑行不结束) + if self.Pos >= self.Length or self.Source[self.Pos] in '\r\n#': + self.BlankLine = True + return + cur: int = self.Indents[-1] + if col > cur: + self.Indents.append(col) + self.Tokens.append(self._Make(INDENT, start, self.Pos)) + elif col < cur: + while self.Indents and self.Indents[-1] > col: + self.Indents.pop() + self.Tokens.append(self._Make(DEDENT, self.Pos, self.Pos)) + + def _ScanContinuation(self) -> None: + """反斜杠续行:跳过 \\ + 换行(逻辑行内,不产生 NEWLINE)。""" + if self.Pos + 1 < self.Length and self.Source[self.Pos + 1] in '\r\n': + self.Pos += 1 + if self.Pos < self.Length and self.Source[self.Pos] == '\r': + self.Pos += 1 + if self.Pos < self.Length and self.Source[self.Pos] == '\n': + self.Pos += 1 + self._RegisterNewline(self.Pos) + self.AtLineStart = True + self.ContinuationLine = True + else: + self.Pos += 1 + + def _ScanComment(self) -> None: + """扫描注释到行尾(不产出 COMMENT token,仅保留)。""" + start: int = self.Pos + while self.Pos < self.Length and self.Source[self.Pos] not in '\r\n': + self.Pos += 1 + tok: Token = self._Make(COMMENT, start, self.Pos) + self.Comments.append(tok) + + # ------------------------------------------------------------------ + # 基础 token + # ------------------------------------------------------------------ + def _EmitOp(self) -> None: + """运算符最长匹配(含 ... 与增强赋值运算符)。""" + start: int = self.Pos + for op in _OPERATORS: + if self.Source.startswith(op, self.Pos): + self.Pos += len(op) + self.Tokens.append(self._Make(OP, start, self.Pos)) + self.AtLineStart = False + return + # 未知字符:单字符 OP 兜底 + self.Pos += 1 + self.Tokens.append(self._Make(OP, start, self.Pos)) + self.AtLineStart = False + + def _ScanName(self) -> None: + """扫描标识符。""" + start: int = self.Pos + while self.Pos < self.Length and _IsIdentPart(self.Source[self.Pos]): + self.Pos += 1 + self.Tokens.append(self._Make(NAME, start, self.Pos)) + self.AtLineStart = False + + def _ScanNumber(self) -> None: + """扫描数字字面量:进制前缀/十进制/浮点/指数/复数 j/下划线。""" + start: int = self.Pos + # 进制前缀 0x/0o/0b + if self.Source[self.Pos] == '0' and self.Pos + 1 < self.Length: + nxt: str = self.Source[self.Pos + 1] + if nxt in 'xXoObB': + self.Pos += 2 + while self.Pos < self.Length and (self.Source[self.Pos].isalnum() + or self.Source[self.Pos] == '_'): + self.Pos += 1 + self.Tokens.append(self._Make(NUMBER, start, self.Pos)) + self.AtLineStart = False + return + # 整数部分 + while self.Pos < self.Length and (self.Source[self.Pos].isdigit() + or self.Source[self.Pos] == '_'): + self.Pos += 1 + # 浮点小数点 + if self.Pos < self.Length and self.Source[self.Pos] == '.': + self.Pos += 1 + while self.Pos < self.Length and (self.Source[self.Pos].isdigit() + or self.Source[self.Pos] == '_'): + self.Pos += 1 + # 指数 + if self.Pos < self.Length and self.Source[self.Pos] in 'eE': + save: int = self.Pos + self.Pos += 1 + if self.Pos < self.Length and self.Source[self.Pos] in '+-': + self.Pos += 1 + if self.Pos < self.Length and (self.Source[self.Pos].isdigit() + or self.Source[self.Pos] == '_'): + while self.Pos < self.Length and (self.Source[self.Pos].isdigit() + or self.Source[self.Pos] == '_'): + self.Pos += 1 + else: + self.Pos = save # 不是指数,回退 + # 复数 j + if self.Pos < self.Length and self.Source[self.Pos] in 'jJ': + self.Pos += 1 + self.Tokens.append(self._Make(NUMBER, start, self.Pos)) + self.AtLineStart = False + + # ------------------------------------------------------------------ + # 字符串 + # ------------------------------------------------------------------ + def _TryScanString(self) -> bool: + """尝试从当前位置扫描字符串字面量(含 r/b/u/f 前缀)。 + + - 前缀字母序列后紧跟引号 → 按字符串扫描,返回 True + - 否则回退位置,返回 False(由调用方走标识符/数字路径) + """ + start: int = self.Pos + # 收集前缀字母 + while self.Pos < self.Length and self.Source[self.Pos] in _STRING_PREFIX_CHARS: + self.Pos += 1 + # 前缀后必须是引号,否则回退 + if self.Pos >= self.Length or self.Source[self.Pos] not in '\'"': + self.Pos = start + return False + prefix: str = self.Source[start:self.Pos] + is_fstring: bool = any(c in _F_PREFIX for c in prefix) + quote: str = self.Source[self.Pos] + triple: bool = self.Source.startswith(quote * 3, self.Pos) + if triple: + self.Pos += 3 + else: + self.Pos += 1 + self._ScanStringBody(quote, triple, is_fstring) + end: int = self.Pos + tok_type: str = FSTRING if is_fstring else STRING + self.Tokens.append(self._Make(tok_type, start, end)) + self.AtLineStart = False + return True + + def _ScanStringBody(self, quote: str, triple: bool, is_fstring: bool) -> None: + """扫描字符串主体直到结束引号(处理转义、f-string 花括号、跨行登记)。""" + while self.Pos < self.Length: + ch: str = self.Source[self.Pos] + if ch == '\\': + # 反斜杠转义:\{{ 中反斜杠只转义自身,后续 {{ 仍需按花括号转义处理 + if self.Pos + 1 < self.Length and self.Source[self.Pos + 1] in '{}': + self.Pos += 1 + else: + self.Pos += 2 + continue + if ch == '\n': + # 三引号字符串跨行:登记行起始,保证后续行列换算准确 + self.Pos += 1 + self._RegisterNewline(self.Pos) + continue + if is_fstring and ch == '{': + if self.Source.startswith('{{', self.Pos): + self.Pos += 2 + continue + self._ScanFStringExpr() + continue + if is_fstring and ch == '}': + if self.Source.startswith('}}', self.Pos): + self.Pos += 2 + continue + self.Pos += 1 + continue + if ch == quote: + if triple: + if self.Source.startswith(quote * 3, self.Pos): + self.Pos += 3 + return + self.Pos += 1 + else: + self.Pos += 1 + return + self.Pos += 1 + # 未闭合字符串:直接结束(Parser 层报语法错误) + + def _ScanFStringExpr(self) -> None: + """跳过 f-string 的 {expr[!conv][:spec]} 表达式段。 + + 表达式内可含字符串字面量(含嵌套 f-string)与括号嵌套,需整体跳过; + 跨行时登记行起始(三引号 f-string)。 + """ + self.Pos += 1 # 跳过 { + depth: int = 1 + while self.Pos < self.Length: + ch: str = self.Source[self.Pos] + if ch == '\\': + self.Pos += 2 + continue + if ch == '\n': + self.Pos += 1 + self._RegisterNewline(self.Pos) + continue + if ch in '\'"': + self._SkipInnerString() + continue + if ch == '(' or ch == '[' or ch == '{': + depth += 1 + self.Pos += 1 + continue + if ch == ')' or ch == ']': + depth -= 1 + self.Pos += 1 + continue + if ch == '}': + if depth == 1: + self.Pos += 1 + return + depth -= 1 + self.Pos += 1 + continue + self.Pos += 1 + + def _SkipInnerString(self) -> None: + """跳过 f-string 表达式内部的字符串字面量(含前缀与三引号)。""" + save: int = self.Pos + while self.Pos < self.Length and self.Source[self.Pos] in _STRING_PREFIX_CHARS: + self.Pos += 1 + if self.Pos >= self.Length or self.Source[self.Pos] not in '\'"': + self.Pos = save + self.Pos += 1 + return + inner_quote: str = self.Source[self.Pos] + triple: bool = self.Source.startswith(inner_quote * 3, self.Pos) + if triple: + self.Pos += 3 + self._ScanStringBody(inner_quote, True, False) + else: + self.Pos += 1 + self._ScanStringBody(inner_quote, False, False) + + # ------------------------------------------------------------------ + # 文件尾 + # ------------------------------------------------------------------ + def _FinishFile(self) -> None: + """文件末尾:补 NEWLINE、DEDENT、ENDMARKER。""" + if self.Tokens and self.Tokens[-1].Type not in (NEWLINE, DEDENT, INDENT): + self.Tokens.append(self._Make(NEWLINE, self.Pos, self.Pos)) + while len(self.Indents) > 1: + self.Indents.pop() + self.Tokens.append(self._Make(DEDENT, self.Pos, self.Pos)) + self.Tokens.append(self._Make(ENDMARKER, self.Pos, self.Pos)) + + +def TokenizeSource(source: str) -> list[Token]: + """便捷入口:源码 → token 流。""" + return Tokenizer(source).Tokenize() diff --git a/lib/vast/Unparser.py b/lib/vast/Unparser.py new file mode 100644 index 0000000..0a179ea --- /dev/null +++ b/lib/vast/Unparser.py @@ -0,0 +1,533 @@ +"""vast.unparser - AST 还原为源码字符串(与 ast.unparse 语义一致) + +TPC 编译器多处用 ``ast.unparse`` 提取类型注解字符串(如 ``t.CArray[...]``、 +``list[i32, N]``、数组维度、默认值文本等)。本模块实现全部节点类型的 +源码还原,保证 ``import vast as ast`` 后这些调用零修改。 +""" +from __future__ import annotations + +from lib.vast import Nodes as N + + +class Unparser: + """递归将 vast 节点还原为源码文本。""" + + def __init__(self) -> None: + self._Depth: int = 0 + + # ------------------------------------------------------------------ + # 顶层 + # ------------------------------------------------------------------ + def Unparse(self, node: N.AST) -> str: + if isinstance(node, N.Module): + return '\n'.join(self._stmt(s) for s in node.body) + if isinstance(node, N.Expression): + return self._expr(node.body) + return self._expr(node) if isinstance(node, N.expr) else self._stmt(node) # type: ignore[arg-type] + + # ------------------------------------------------------------------ + # 语句 + # ------------------------------------------------------------------ + def _stmt(self, node: N.AST) -> str: + name: str = type(node).__name__ + m: dict[str, object] = { + 'FunctionDef': self._FunctionDef, + 'AsyncFunctionDef': self._FunctionDef, + 'ClassDef': self._ClassDef, + 'Return': self._Return, + 'Delete': self._Delete, + 'Assign': self._Assign, + 'AugAssign': self._AugAssign, + 'AnnAssign': self._AnnAssign, + 'For': self._For, + 'AsyncFor': self._For, + 'While': self._While, + 'If': self._If, + 'With': self._With, + 'AsyncWith': self._With, + 'Raise': self._Raise, + 'Try': self._Try, + 'TryStar': self._Try, + 'Assert': self._Assert, + 'Import': self._Import, + 'ImportFrom': self._ImportFrom, + 'Global': self._Global, + 'Nonlocal': self._Global, + 'Expr': self._ExprStmt, + 'Pass': self._Pass, + 'Break': lambda n: 'break', + 'Continue': lambda n: 'continue', + 'Match': self._Match, + } + fn = m.get(name) + if fn is not None: + return fn(node) # type: ignore[operator] + raise NotImplementedError(f'unparse stmt: {name}') + + def _Block(self, body: list[N.stmt]) -> str: + self._Depth += 1 + pad: str = ' ' * self._Depth + lines: list[str] = [f'{pad}{self._stmt(s)}' for s in body] + self._Depth -= 1 + return '\n'.join(lines) + + def _FunctionDef(self, node: N.FunctionDef) -> str: + kw: str = 'async def' if isinstance(node, N.AsyncFunctionDef) else 'def' + decos: str = ''.join(f'@{self._expr(d)}\n' for d in node.decorator_list) + params: str = self._Arguments(node.args) + ret: str = '' + if node.returns is not None: + ret = f' -> {self._expr(node.returns)}' + body: str = self._Block(node.body) + return f'{decos}{kw} {node.name}({params}){ret}:\n{body}' + + def _ClassDef(self, node: N.ClassDef) -> str: + decos: str = ''.join(f'@{self._expr(d)}\n' for d in node.decorator_list) + args: list[str] = [self._expr(b) for b in node.bases] + for kw in node.keywords: + args.append(f'{kw.arg}={self._expr(kw.value)}' if kw.arg else f'**{self._expr(kw.value)}') + header: str = f'class {node.name}' + (f'({", ".join(args)})' if args else '') + ':' + return f'{decos}{header}\n{self._Block(node.body)}' + + def _Return(self, node: N.Return) -> str: + return 'return' if node.value is None else f'return {self._expr(node.value)}' + + def _Delete(self, node: N.Delete) -> str: + return 'del ' + ', '.join(self._expr(t) for t in node.targets) + + def _Assign(self, node: N.Assign) -> str: + return ', '.join(self._expr(t) for t in node.targets) + f' = {self._expr(node.value)}' + + def _AugAssign(self, node: N.AugAssign) -> str: + ops: dict[type, str] = { + N.Add: '+', N.Sub: '-', N.Mult: '*', N.Div: '/', N.FloorDiv: '//', + N.Mod: '%', N.Pow: '**', N.LShift: '<<', N.RShift: '>>', + N.BitOr: '|', N.BitXor: '^', N.BitAnd: '&', N.MatMult: '@', + } + op: str = ops.get(type(node.op), '?') + return f'{self._expr(node.target)} {op}= {self._expr(node.value)}' + + def _AnnAssign(self, node: N.AnnAssign) -> str: + val: str = f' = {self._expr(node.value)}' if node.value is not None else '' + return f'{self._expr(node.target)}: {self._expr(node.annotation)}{val}' + + def _For(self, node: N.For) -> str: + kw: str = 'async for' if isinstance(node, N.AsyncFor) else 'for' + orelse: str = f'\n{" " * self._Depth}else:\n{self._Block(node.orelse)}' if node.orelse else '' + return f'{kw} {self._expr(node.target)} in {self._expr(node.iter)}:\n{self._Block(node.body)}{orelse}' + + def _While(self, node: N.While) -> str: + orelse: str = f'\n{" " * self._Depth}else:\n{self._Block(node.orelse)}' if node.orelse else '' + return f'while {self._expr(node.test)}:\n{self._Block(node.body)}{orelse}' + + def _If(self, node: N.If) -> str: + out: str = f'if {self._expr(node.test)}:\n{self._Block(node.body)}' + if node.orelse: + if len(node.orelse) == 1 and isinstance(node.orelse[0], N.If): + out += f'\n{" " * self._Depth}elif {self._expr(node.orelse[0].test)}:\n{self._Block(node.orelse[0].body)}' + out += self._IfTail(node.orelse[0]) + else: + out += f'\n{" " * self._Depth}else:\n{self._Block(node.orelse)}' + return out + + def _IfTail(self, node: N.If) -> str: + out: str = '' + if node.orelse: + if len(node.orelse) == 1 and isinstance(node.orelse[0], N.If): + out += f'\n{" " * self._Depth}elif {self._expr(node.orelse[0].test)}:\n{self._Block(node.orelse[0].body)}' + out += self._IfTail(node.orelse[0]) + else: + out += f'\n{" " * self._Depth}else:\n{self._Block(node.orelse)}' + return out + + def _With(self, node: N.With) -> str: + kw: str = 'async with' if isinstance(node, N.AsyncWith) else 'with' + items: list[str] = [] + for item in node.items: + s: str = self._expr(item.context_expr) + if item.optional_vars is not None: + s += f' as {self._expr(item.optional_vars)}' + items.append(s) + return f'{kw} {", ".join(items)}:\n{self._Block(node.body)}' + + def _Raise(self, node: N.Raise) -> str: + if node.exc is None: + return 'raise' + out: str = f'raise {self._expr(node.exc)}' + if node.cause is not None: + out += f' from {self._expr(node.cause)}' + return out + + def _Try(self, node: N.Try) -> str: + out: str = f'try:\n{self._Block(node.body)}' + for h in node.handlers: + hdr: str = 'except*' if isinstance(node, N.TryStar) else 'except' + if h.type is not None: + hdr += f' {self._expr(h.type)}' + if h.name: + hdr += f' as {h.name}' + out += f'\n{" " * self._Depth}{hdr}:\n{self._Block(h.body)}' + if node.orelse: + out += f'\n{" " * self._Depth}else:\n{self._Block(node.orelse)}' + if node.finalbody: + out += f'\n{" " * self._Depth}finally:\n{self._Block(node.finalbody)}' + return out + + def _Assert(self, node: N.Assert) -> str: + out: str = f'assert {self._expr(node.test)}' + if node.msg is not None: + out += f', {self._expr(node.msg)}' + return out + + def _Import(self, node: N.Import) -> str: + names: list[str] = [] + for a in node.names: + s: str = a.name + if a.asname: + s += f' as {a.asname}' + names.append(s) + return 'import ' + ', '.join(names) + + def _ImportFrom(self, node: N.ImportFrom) -> str: + dots: str = '.' * node.level + mod: str = node.module or '' + names: list[str] = [] + for a in node.names: + s: str = a.name + if a.asname: + s += f' as {a.asname}' + names.append(s) + return f'from {dots}{mod} import {", ".join(names)}' + + def _Global(self, node: N.AST) -> str: + kw: str = 'global' if isinstance(node, N.Global) else 'nonlocal' + return f'{kw} {", ".join(node.names)}' + + def _ExprStmt(self, node: N.Expr) -> str: + return self._expr(node.value) + + def _Pass(self, node: N.Pass) -> str: + return 'pass' + + def _Match(self, node: N.Match) -> str: + out: str = f'match {self._expr(node.subject)}:\n' + self._Depth += 1 + pad: str = ' ' * self._Depth + for case in node.cases: + guard: str = f' if {self._expr(case.guard)}' if case.guard else '' + out += f'{pad}case {self._Pattern(case.pattern)}{guard}:\n' + self._Depth += 1 + out += self._Block(case.body) + self._Depth -= 1 + self._Depth -= 1 + return out + + def _Pattern(self, node: N.pattern) -> str: + name: str = type(node).__name__ + if isinstance(node, N.MatchValue): + return self._expr(node.value) + if isinstance(node, N.MatchSingleton): + return repr(node.value) + if isinstance(node, N.MatchSequence): + return '[' + ', '.join(self._Pattern(p) for p in node.patterns) + ']' + if isinstance(node, N.MatchMapping): + parts: list[str] = [] + for k, p in zip(node.keys, node.patterns): + parts.append(f'{self._expr(k)}: {self._Pattern(p)}') + if node.rest: + parts.append(f'**{node.rest}') + return '{' + ', '.join(parts) + '}' + if isinstance(node, N.MatchClass): + pos: list[str] = [self._Pattern(p) for p in node.patterns] + kw: list[str] = [f'{a}={self._Pattern(p)}' for a, p in zip(node.kwd_attrs, node.kwd_patterns)] + return f'{self._expr(node.cls)}({", ".join(pos + kw)})' + if isinstance(node, N.MatchStar): + return f'*{node.name}' if node.name else '*_' + if isinstance(node, N.MatchAs): + if node.pattern is not None: + return f'{self._Pattern(node.pattern)} as {node.name}' + return node.name or '_' + if isinstance(node, N.MatchOr): + return ' | '.join(self._Pattern(p) for p in node.patterns) + raise NotImplementedError(f'unparse pattern: {name}') + + # ------------------------------------------------------------------ + # 表达式 + # ------------------------------------------------------------------ + def _expr(self, node: N.AST) -> str: + name: str = type(node).__name__ + m: dict[str, object] = { + 'Name': self._Name, + 'Constant': self._Constant, + 'Attribute': self._Attribute, + 'Call': self._Call, + 'BinOp': self._BinOp, + 'UnaryOp': self._UnaryOp, + 'BoolOp': self._BoolOp, + 'Compare': self._Compare, + 'Subscript': self._Subscript, + 'Slice': self._Slice, + 'Tuple': self._Tuple, + 'List': self._List, + 'Set': self._Set, + 'Dict': self._Dict, + 'JoinedStr': self._JoinedStr, + 'FormattedValue': self._FormattedValue, + 'Lambda': self._Lambda, + 'IfExp': self._IfExp, + 'Starred': self._Starred, + 'ListComp': self._ListComp, + 'SetComp': self._ListComp, + 'GeneratorExp': self._ListComp, + 'DictComp': self._DictComp, + 'NamedExpr': self._NamedExpr, + 'Await': self._Await, + 'Yield': self._Yield, + 'YieldFrom': self._YieldFrom, + } + fn = m.get(name) + if fn is not None: + return fn(node) # type: ignore[operator] + raise NotImplementedError(f'unparse expr: {name}') + + def _Name(self, node: N.Name) -> str: + return node.id + + def _Constant(self, node: N.Constant) -> str: + v = node.value + if v is Ellipsis: + return '...' + if v is None: + return 'None' + if v is True: + return 'True' + if v is False: + return 'False' + if isinstance(v, str): + return repr(v) + if isinstance(v, bytes): + return repr(v) + if isinstance(v, complex): + # 复数文本 + return repr(v) + return repr(v) + + def _Attribute(self, node: N.Attribute) -> str: + return f'{self._expr(node.value)}.{node.attr}' + + def _Call(self, node: N.Call) -> str: + args: list[str] = [self._expr(a) for a in node.args] + for kw in node.keywords: + if kw.arg is None: + args.append(f'**{self._expr(kw.value)}') + else: + args.append(f'{kw.arg}={self._expr(kw.value)}') + return f'{self._expr(node.func)}({", ".join(args)})' + + _BINOP_OPS: dict[type, str] = { + N.Add: '+', N.Sub: '-', N.Mult: '*', N.Div: '/', N.FloorDiv: '//', + N.Mod: '%', N.Pow: '**', N.LShift: '<<', N.RShift: '>>', + N.BitOr: '|', N.BitXor: '^', N.BitAnd: '&', N.MatMult: '@', + } + + def _BinOp(self, node: N.BinOp) -> str: + op: str = self._BINOP_OPS.get(type(node.op), '?') + return f'{self._expr(node.left)} {op} {self._expr(node.right)}' + + def _UnaryOp(self, node: N.UnaryOp) -> str: + ops: dict[type, str] = {N.USub: '-', N.UAdd: '+', N.Not: 'not ', N.Invert: '~'} + op: str = ops.get(type(node.op), '?') + return f'{op}{self._expr(node.operand)}' + + def _BoolOp(self, node: N.BoolOp) -> str: + kw: str = 'or' if isinstance(node.op, N.Or) else 'and' + return f' {kw} '.join(self._expr(v) for v in node.values) + + _CMPOPS: dict[type, str] = { + N.Eq: '==', N.NotEq: '!=', N.Lt: '<', N.LtE: '<=', N.Gt: '>', N.GtE: '>=', + N.Is: 'is', N.IsNot: 'is not', N.In: 'in', N.NotIn: 'not in', + } + + def _Compare(self, node: N.Compare) -> str: + parts: list[str] = [self._expr(node.left)] + for op, comp in zip(node.ops, node.comparators): + parts.append(self._CMPOPS.get(type(op), '?')) + parts.append(self._expr(comp)) + return ' '.join(parts) + + def _Subscript(self, node: N.Subscript) -> str: + return f'{self._expr(node.value)}[{self._SliceLike(node.slice)}]' + + def _SliceLike(self, node: N.AST) -> str: + if isinstance(node, N.Slice): + return self._Slice(node) + if isinstance(node, N.Tuple): + # 切片元组:a[1, 2] / a[i, j:k] 元素按需渲染 + return ', '.join(self._SliceLike(e) for e in node.elts) + return self._expr(node) + + def _Slice(self, node: N.Slice) -> str: + """渲染切片:a[1:2] / a[::2] / a[:2] / a[1:2:3]。""" + parts: list[str] = [] + if node.lower is not None: + parts.append(self._expr(node.lower)) + # 冒号:upper 或 step 存在时才需要第一个冒号 + if node.upper is not None or node.step is not None: + if len(parts) < 1: + parts.append('') + parts.append(self._expr(node.upper) if node.upper is not None else '') + if node.step is not None: + if len(parts) < 2: + parts.append('') + parts.append('') + parts.append(self._expr(node.step)) + return ':'.join(parts) + + def _Tuple(self, node: N.Tuple) -> str: + if len(node.elts) == 1: + return f'({self._expr(node.elts[0])},)' + return '(' + ', '.join(self._expr(e) for e in node.elts) + ')' + + def _List(self, node: N.List) -> str: + return '[' + ', '.join(self._expr(e) for e in node.elts) + ']' + + def _Set(self, node: N.Set) -> str: + return '{' + ', '.join(self._expr(e) for e in node.elts) + '}' + + def _Dict(self, node: N.Dict) -> str: + parts: list[str] = [] + for k, v in zip(node.keys, node.values): + if k is None: + parts.append(f'**{self._expr(v)}') + else: + parts.append(f'{self._expr(k)}: {self._expr(v)}') + return '{' + ', '.join(parts) + '}' + + def _JoinedStr(self, node: N.JoinedStr) -> str: + out: list[str] = [] + for v in node.values: + if isinstance(v, N.Constant): + # 字面量段:转义内部引号与花括号 + lit: str = str(v.value) + lit = lit.replace('{', '{{').replace('}', '}}') + lit = lit.replace("'", "\\'") + out.append(lit) + else: + out.append('{' + self._FormattedValueRaw(v) + '}') + inner: str = ''.join(out) + # 优先单引号(与 CPython unparse 一致) + return "f'" + inner + "'" + + def _FormattedValue(self, node: N.FormattedValue) -> str: + return "f'{" + self._FormattedValueRaw(node) + "}'" + + def _FormattedValueRaw(self, node: N.FormattedValue) -> str: + s: str = self._expr(node.value) + if node.conversion >= 0: + s += f'!{chr(node.conversion)}' + if node.format_spec is not None: + if isinstance(node.format_spec, N.JoinedStr): + spec: str = '' + for v in node.format_spec.values: + if isinstance(v, N.Constant): + spec += str(v.value) + else: + spec += '{' + self._FormattedValueRaw(v) + '}' + else: + spec = self._expr(node.format_spec) + s += f':{spec}' + return s + + def _Lambda(self, node: N.Lambda) -> str: + return f'lambda {self._Arguments(node.args)}: {self._expr(node.body)}' + + def _IfExp(self, node: N.IfExp) -> str: + return f'{self._expr(node.body)} if {self._expr(node.test)} else {self._expr(node.orelse)}' + + def _Starred(self, node: N.Starred) -> str: + return f'*{self._expr(node.value)}' + + def _ComprehensionClauses(self, gens: list[N.comprehension]) -> str: + out: list[str] = [] + for g in gens: + kw: str = 'async for' if g.is_async else 'for' + s: str = f' {kw} {self._expr(g.target)} in {self._expr(g.iter)}' + for cond in g.ifs: + s += f' if {self._expr(cond)}' + out.append(s) + return ''.join(out) + + def _ListComp(self, node: N.AST) -> str: + cls_name: str = type(node).__name__ + if isinstance(node, N.SetComp): + fmt: str = '{' + close: str = '}' + elt: str = self._expr(node.elt) + elif isinstance(node, N.GeneratorExp): + fmt, close, elt = '(', ')', self._expr(node.elt) + elif isinstance(node, N.DictComp): + return '{' + f'{self._expr(node.key)}: {self._expr(node.value)}' + self._ComprehensionClauses(node.generators) + '}' + else: + fmt, close, elt = '[', ']', self._expr(node.elt) + return fmt + elt + self._ComprehensionClauses(node.generators) + close + + def _DictComp(self, node: N.DictComp) -> str: + return '{' + f'{self._expr(node.key)}: {self._expr(node.value)}' + \ + self._ComprehensionClauses(node.generators) + '}' + + def _NamedExpr(self, node: N.NamedExpr) -> str: + return f'{self._expr(node.target)} := {self._expr(node.value)}' + + def _Await(self, node: N.Await) -> str: + return f'await {self._expr(node.value)}' + + def _Yield(self, node: N.Yield) -> str: + return 'yield' if node.value is None else f'yield {self._expr(node.value)}' + + def _YieldFrom(self, node: N.YieldFrom) -> str: + return f'yield from {self._expr(node.value)}' + + # ------------------------------------------------------------------ + # 参数列表 + # ------------------------------------------------------------------ + def _Arguments(self, args: N.arguments) -> str: + parts: list[str] = [] + n_args: int = len(args.posonlyargs) + len(args.args) + n_defaults: int = len(args.defaults) + # 合并 posonly + 普通参数,defaults 尾部对齐 + all_args: list[N.arg] = list(args.posonlyargs) + list(args.args) + all_defaults: list[N.expr | None] = [None] * (n_args - n_defaults) + list(args.defaults) + for i, a in enumerate(all_args): + s: str = a.arg + if a.annotation is not None: + s += f': {self._expr(a.annotation)}' + if all_defaults[i] is not None: + s += f'={self._expr(all_defaults[i])}' + parts.append(s) + if args.posonlyargs and i == len(args.posonlyargs) - 1: + parts.append('/') + if args.vararg is not None: + s = f'*{args.vararg.arg}' + if args.vararg.annotation is not None: + s += f': {self._expr(args.vararg.annotation)}' + parts.append(s) + elif args.kwonlyargs: + parts.append('*') + for a, d in zip(args.kwonlyargs, args.kw_defaults): + s = a.arg + if a.annotation is not None: + s += f': {self._expr(a.annotation)}' + if d is not None: + s += f'={self._expr(d)}' + parts.append(s) + if args.kwarg is not None: + s = f'**{args.kwarg.arg}' + if args.kwarg.annotation is not None: + s += f': {self._expr(args.kwarg.annotation)}' + parts.append(s) + return ', '.join(parts) + + +def Unparse(node: N.AST) -> str: + """便捷入口。""" + return Unparser().Unparse(node) diff --git a/lib/vast/Utils.py b/lib/vast/Utils.py new file mode 100644 index 0000000..67dc3c7 --- /dev/null +++ b/lib/vast/Utils.py @@ -0,0 +1,281 @@ +"""vast.utils - AST 遍历与序列化工具 + +与 CPython ``ast`` 模块辅助函数同构: + +- ``iter_fields`` / ``iter_child_nodes`` / ``walk`` +- ``dump``(含 annotate_fields / include_attributes / indent) +- ``copy_location`` / ``fix_missing_locations`` / ``get_source_segment`` +- ``literal_eval``(常量求值) +""" +from __future__ import annotations + +from lib.vast.Nodes import AST +from lib.vast.Tokenizer import Token + + +def iter_fields(node: AST): + """按 _fields 顺序产出 (字段名, 值)。""" + for field in node._fields: + try: + yield field, getattr(node, field) + except AttributeError: + pass + + +def iter_child_nodes(node: AST): + """产出全部子节点(递归扁平,跳过 None 与空列表)。""" + for _name, field in iter_fields(node): + if isinstance(field, AST): + yield field + elif isinstance(field, list): + for item in field: + if isinstance(item, AST): + yield item + + +def walk(node: AST): + """深度优先遍历,产出自身与全部后代节点。""" + from collections import deque + + todo: deque[AST] = deque([node]) + while todo: + n: AST = todo.popleft() + yield n + todo.extend(iter_child_nodes(n)) + + +def dump(node: AST, annotate_fields: bool = True, include_attributes: bool = False, + indent: int | str | None = None) -> str: + """将 AST 节点格式化为字符串(精确复刻 CPython 3.12 ast.dump)。 + + - annotate_fields: 是否显示字段名(默认 True) + - include_attributes: 是否附加 lineno/col_offset 等位置属性 + - indent: 缩进(int 或字符串),None 为单行紧凑输出 + + 与 CPython 一致的行为: + - 值为 None 且类默认值为 None 的字段跳过(如 FunctionDef.returns) + - 节点字段全部为"简单值"且 ≤3 个时单行输出 + """ + if not isinstance(node, AST): + raise TypeError(f'expected AST, got {type(node).__name__!r}') + + if indent is not None and not isinstance(indent, str): + indent = ' ' * indent + + def _format(node: object, level: int = 0): + if indent is not None: + level += 1 + prefix: str = '\n' + indent * level # type: ignore[operator] + sep: str = ',\n' + indent * level # type: ignore[operator] + else: + prefix = '' + sep = ', ' + if isinstance(node, AST): + cls: type = type(node) + args: list[str] = [] + allsimple: bool = True + keywords: bool = annotate_fields + for name in node._fields: + try: + value = getattr(node, name) + except AttributeError: + keywords = True + continue + if value is None and getattr(cls, name, ...) is None: + keywords = True + continue + value, simple = _format(value, level) + allsimple = allsimple and simple + if keywords: + args.append(f'{name}={value}') + else: + args.append(value) + if include_attributes and node._attributes: + for name in node._attributes: + try: + value = getattr(node, name) + except AttributeError: + continue + if value is None and getattr(cls, name, ...) is None: + continue + value, simple = _format(value, level) + allsimple = allsimple and simple + args.append(f'{name}={value}') + if allsimple and len(args) <= 3: + return f'{type(node).__name__}({", ".join(args)})', not args + return f'{type(node).__name__}({prefix}{sep.join(args)})', False + elif isinstance(node, list): + if not node: + return '[]', True + return f'[{prefix}{sep.join(_format(x, level)[0] for x in node)}]', False + return repr(node), True + + return _format(node)[0] + + +def copy_location(new_node: AST, old_node: AST) -> AST: + """复制 old_node 的位置属性到 new_node(与 ast.copy_location 一致)。""" + for attr in ('lineno', 'col_offset', 'end_lineno', 'end_col_offset'): + try: + setattr(new_node, attr, getattr(old_node, attr)) + except AttributeError: + pass + return new_node + + +def fix_missing_locations(node: AST) -> AST: + """为缺失位置的节点补全(从最近的祖先复制;递归处理)。""" + def _fix(n: AST, parent_loc: dict[str, int] | None) -> None: + has_loc: bool = hasattr(n, 'lineno') and getattr(n, 'lineno', None) is not None + if hasattr(n, 'lineno') and getattr(n, 'lineno', None) is None and parent_loc: + for attr, val in parent_loc.items(): + setattr(n, attr, val) + loc: dict[str, int] | None = None + if hasattr(n, 'lineno') and getattr(n, 'lineno', None) is not None: + loc = {a: getattr(n, a) for a in + ('lineno', 'col_offset', 'end_lineno', 'end_col_offset') + if getattr(n, a, None) is not None} + for child in iter_child_nodes(n): + _fix(child, loc) + + _fix(node, None) + return node + + +def get_source_segment(source: str, node: AST, padded: bool = False) -> str | None: + """提取节点对应的源码片段(与 ast.get_source_segment 一致)。""" + try: + lineno: int | None = getattr(node, 'lineno', None) + end_lineno: int | None = getattr(node, 'end_lineno', None) + col_offset: int | None = getattr(node, 'col_offset', None) + end_col_offset: int | None = getattr(node, 'end_col_offset', None) + if lineno is None or end_lineno is None or col_offset is None or end_col_offset is None: + return None + lines: list[str] = source.splitlines(keepends=True) + if lineno < 1 or lineno > len(lines): + return None + first: str = lines[lineno - 1] + # col_offset 是 UTF-8 字节偏移 → 转字符偏移 + start_char: int = _ByteToChar(first, col_offset) + if lineno == end_lineno: + end_char: int = _ByteToChar(first, end_col_offset) + segment: str = first[start_char:end_char] + else: + last: str = lines[end_lineno - 1] + end_char = _ByteToChar(last, end_col_offset) + middle: list[str] = lines[lineno:end_lineno - 1] + segment = first[start_char:] + ''.join(middle) + last[:end_char] + if padded: + return segment + return segment + except Exception: + return None + + +def _ByteToChar(line: str, byte_offset: int) -> int: + """UTF-8 字节偏移 → 字符偏移。""" + b: bytes = line.encode('utf-8') + return len(b[:byte_offset].decode('utf-8', errors='replace')) if byte_offset > 0 else 0 + + +def literal_eval(node_or_string: AST | str): + """安全求值常量表达式(与 ast.literal_eval 语义一致)。 + + 支持常量、元组/列表/集合/字典、一元 +/-、BinOp 算术、切片。 + """ + if isinstance(node_or_string, str): + from lib.vast.Tokenizer import Tokenizer + + toks: list[Token] = Tokenizer(node_or_string).Tokenize() + if toks and toks[0].Type == 'NEWLINE': + raise ValueError('malformed node or string') + from lib.vast.Parser import _ComputeLineStarts + + from lib.vast.ExprParser import ExprParserMixin + + class _EV(ExprParserMixin): + def __init__(self) -> None: + super().__init__(toks, node_or_string, _ComputeLineStarts(node_or_string)) + + parser = _EV() + node: AST = parser.ParseExpr() + elif isinstance(node_or_string, AST): + node = node_or_string + else: + raise TypeError('bad argument type') + + return _EvalLiteral(node) + + +def _EvalLiteral(node: AST): + """递归常量求值核心。""" + if isinstance(node, AST): + pass + name: str = type(node).__name__ + # 常量 + if name == 'Constant': + value = node.value + if isinstance(value, (int, float, complex, str, bool, bytes, type(None), Ellipsis)): # type: ignore[comparison-overlap] + return value + raise ValueError('malformed node or string: unsupported constant') + if name == 'Tuple': + return tuple(_EvalLiteral(e) for e in node.elts) + if name == 'List': + return [_EvalLiteral(e) for e in node.elts] + if name == 'Set': + return {_EvalLiteral(e) for e in node.elts} + if name == 'Dict': + if len(node.keys) != len(node.values): + raise ValueError('malformed node or string: Dict') + out: dict = {} + for k, v in zip(node.keys, node.values): + if k is None: + raise ValueError('malformed node or string: ** in Dict') + out[_EvalLiteral(k)] = _EvalLiteral(v) + return out + if name == 'UnaryOp': + operand = _EvalLiteral(node.operand) + if isinstance(node.op, (__import__('lib.vast.Nodes', fromlist=['USub']).USub,)): + return -operand + if isinstance(node.op, (__import__('lib.vast.Nodes', fromlist=['UAdd']).UAdd,)): + return +operand + if isinstance(node.op, (__import__('lib.vast.Nodes', fromlist=['Not']).Not,)): + return not operand + raise ValueError('malformed node or string: unary op') + if name == 'BinOp': + from lib.vast.Nodes import Add, Sub, Mult, Div, FloorDiv, Mod, Pow, LShift, RShift, BitOr, BitXor, BitAnd + + left = _EvalLiteral(node.left) + right = _EvalLiteral(node.right) + op = node.op + if isinstance(op, Add): + return left + right + if isinstance(op, Sub): + return left - right + if isinstance(op, Mult): + return left * right + if isinstance(op, Div): + return left / right + if isinstance(op, FloorDiv): + return left // right + if isinstance(op, Mod): + return left % right + if isinstance(op, Pow): + return left ** right + if isinstance(op, LShift): + return left << right + if isinstance(op, RShift): + return left >> right + if isinstance(op, BitOr): + return left | right + if isinstance(op, BitXor): + return left ^ right + if isinstance(op, BitAnd): + return left & right + raise ValueError('malformed node or string: bin op') + if name == 'Slice': + lower = _EvalLiteral(node.lower) if node.lower is not None else None + upper = _EvalLiteral(node.upper) if node.upper is not None else None + step = _EvalLiteral(node.step) if node.step is not None else None + return slice(lower, upper, step) + raise ValueError(f'malformed node or string: {name}') diff --git a/lib/vast/__init__.py b/lib/vast/__init__.py new file mode 100644 index 0000000..6a32436 --- /dev/null +++ b/lib/vast/__init__.py @@ -0,0 +1,69 @@ +"""vast - Viper/Python 自研语法解析器(ast 替代品) + +vast 提供与 CPython 3.12 标准库 ``ast`` 完全一致的 API: + +- 节点类:``AST`` 及全部 131 个节点类(Name/Call/BinOp/FunctionDef/...) +- 解析入口:``parse(source, filename, mode, ...)`` 产出 ``Module`` +- 辅助函数:``dump`` / ``walk`` / ``iter_child_nodes`` / ``iter_fields`` / + ``unparse`` / ``copy_location`` / ``fix_missing_locations`` / + ``get_source_segment`` / ``literal_eval`` +- 类型标注占位:``expr`` / ``stmt`` / ``operator`` / ``cmpop`` 等 + +编译器侧替换方式(零修改其余代码):: + + import vast as ast + +vast 原生支持 Viper 软关键字 fn/fun/func/function(并入解析器),无需 +ExpandSoftKeywords 预处理。 +""" +from __future__ import annotations + +import sys as _sys + +from lib.vast.Nodes import AST +from lib.vast.Nodes import _NODE_DEFS + +# 将全部节点类提升到包命名空间 +for _name in _NODE_DEFS: + globals()[_name] = getattr(_sys.modules['lib.vast.Nodes'], _name) + +from lib.vast.Parser import Parse # noqa: E402 +from lib.vast.Utils import ( # noqa: E402 + iter_fields, iter_child_nodes, walk, dump, copy_location, + fix_missing_locations, get_source_segment, literal_eval, +) +from lib.vast.Unparser import Unparse as unparse # noqa: E402 +from lib.vast.Tokenizer import SOFT_KEYWORDS # noqa: E402 + + +def parse(source: str, filename: str = '', mode: str = 'exec', *, + type_comments: bool = False, feature_version: tuple[int, int] | int | None = None) -> AST: + """解析源码字符串为 AST(与 ast.parse 同签名、同结构)。 + + Args: + source: 源码文本 + filename: 文件名(仅用于错误报告,vast 保留) + mode: 'exec'(模块)/ 'eval'(单表达式)/ 'single'(交互式) + type_comments: 是否解析 # type: 注释(vast 暂返回 None 字段) + feature_version: 目标 Python 版本(vast 忽略,保持兼容) + """ + tree: AST = Parse(source) + if mode == 'exec': + return tree + if mode == 'eval': + if len(tree.body) != 1 or not isinstance(tree.body[0], _sys.modules['lib.vast.Nodes'].Expr): + raise SyntaxError('invalid syntax for eval mode') + expr_node: AST = _sys.modules['lib.vast.Nodes'].Expression( + body=tree.body[0].value) + return expr_node + if mode == 'single': + interactive: AST = _sys.modules['lib.vast.Nodes'].Interactive(body=tree.body) + return interactive + raise ValueError(f"invalid mode {mode!r}") + + +__all__: list[str] = [ + 'AST', 'parse', 'dump', 'walk', 'iter_fields', 'iter_child_nodes', + 'unparse', 'copy_location', 'fix_missing_locations', + 'get_source_segment', 'literal_eval', 'SOFT_KEYWORDS', +] + list(_NODE_DEFS.keys())