snapshot before regression test
This commit is contained in:
381
lib/core/Translator/AnnotationLoader.py
Normal file
381
lib/core/Translator/AnnotationLoader.py
Normal file
@@ -0,0 +1,381 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import os
|
||||
import importlib
|
||||
import types
|
||||
from typing import Any
|
||||
|
||||
import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes)
|
||||
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
from lib.core.SymbolUtils import IsTModule, AnnotationContainsName
|
||||
from lib.includes import t
|
||||
from lib.includes.t import CType, CEnum
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
|
||||
class AnnotationLoaderMixin:
|
||||
"""注解模块加载 Mixin
|
||||
|
||||
提供注解模块/文件的加载与符号表注册能力。
|
||||
"""
|
||||
|
||||
def _LoadAnnotationModule(self, ModuleName: str, library_name: str | None = None, parse_method: str = 'auto') -> int:
|
||||
"""加载注解模块并将 CType 子类注册为 typedef
|
||||
|
||||
支持两种模式:
|
||||
1. AST 模式:如果 ModuleName 是文件路径,解析文件提取 CType
|
||||
2. importlib 模式:如果 ModuleName 是模块名,导入模块提取 CType
|
||||
|
||||
Args:
|
||||
ModuleName: 模块名或文件路径
|
||||
library_name: 手动指定的库名称,用于注册到符号表。如果为 None,则从 ModuleName 推断
|
||||
parse_method: 解析方法,可选值:
|
||||
- 'auto': 自动检测(默认)
|
||||
- 'file': 强制使用 AST 模式(文件路径)
|
||||
- 'module': 强制使用 importlib 模式(模块名)
|
||||
"""
|
||||
def register_to_symboltable(module: types.ModuleType, lib_name: str | None = None, source_file: str | None = None) -> int:
|
||||
"""将模块中的 CType 子类和 CEnum 类注册到符号表"""
|
||||
count: int = 0
|
||||
for AttrName in dir(module):
|
||||
attr: type = getattr(module, AttrName)
|
||||
# 优先检查是否是 CEnum 子类(枚举)
|
||||
if isinstance(attr, type) and issubclass(attr, CEnum) and attr is not CEnum:
|
||||
# 注册枚举类型
|
||||
EnumNode: CTypeInfo = CTypeInfo()
|
||||
EnumNode.Name = AttrName
|
||||
EnumNode.BaseType = t.CEnum()
|
||||
EnumNode.IsEnum = True
|
||||
EnumNode.set('enum_class', attr)
|
||||
EnumNode.set('source', 'annotation_module')
|
||||
EnumNode.library_name = lib_name
|
||||
EnumNode.file = source_file
|
||||
self.SymbolTable.insert(AttrName, EnumNode)
|
||||
if lib_name:
|
||||
FullName: str = f'{lib_name}.{AttrName}'
|
||||
full_EnumNode: CTypeInfo = CTypeInfo()
|
||||
full_EnumNode.Name = FullName
|
||||
full_EnumNode.IsEnum = True
|
||||
full_EnumNode.set('enum_class', attr)
|
||||
full_EnumNode.set('source', 'annotation_module')
|
||||
full_EnumNode.library_name = lib_name
|
||||
full_EnumNode.file = source_file
|
||||
self.SymbolTable.insert(FullName, full_EnumNode)
|
||||
# 枚举成员也需要注册
|
||||
for MemberName in dir(attr):
|
||||
if not MemberName.startswith('_'):
|
||||
member: int = getattr(attr, MemberName, None)
|
||||
if isinstance(member, int):
|
||||
MemberNode: CTypeInfo = CTypeInfo()
|
||||
MemberNode.Name = MemberName
|
||||
MemberNode.BaseType = t.CEnum(AttrName)
|
||||
MemberNode.value = member
|
||||
MemberNode.EnumName = AttrName
|
||||
MemberNode.library_name = lib_name
|
||||
MemberNode.IsEnumMember = True
|
||||
self.SymbolTable.insert(MemberName, MemberNode)
|
||||
self.SymbolTable.insert(f"{AttrName}.{MemberName}", MemberNode)
|
||||
self.SymbolTable.insert(f"{AttrName}_{MemberName}", MemberNode)
|
||||
if lib_name:
|
||||
self.SymbolTable.insert(f"{lib_name}.{AttrName}.{MemberName}", MemberNode)
|
||||
self.SymbolTable.insert(f"{lib_name}_{AttrName}_{MemberName}", MemberNode)
|
||||
count += 1
|
||||
# 检查是否是 CType 子类(typedef 别名)
|
||||
elif isinstance(attr, type) and issubclass(attr, CType) and attr is not CType:
|
||||
# 继承 CType 的类是类型别名(typedef),不是结构体
|
||||
# 使用手动指定的库名称作为前缀
|
||||
if lib_name:
|
||||
FullName: str = f'{lib_name}.{AttrName}'
|
||||
else:
|
||||
FullName = AttrName
|
||||
# 同时注册带前缀和不带前缀的名称(都是 typedef 别名)
|
||||
TypedefNode: CTypeInfo = CTypeInfo()
|
||||
TypedefNode.Name = AttrName
|
||||
TypedefNode.IsTypedef = True
|
||||
TypedefNode.OriginalType = attr.__name__
|
||||
TypedefNode.set('source', 'annotation_module')
|
||||
TypedefNode.library_name = lib_name
|
||||
TypedefNode.file = source_file
|
||||
self.SymbolTable.insert(AttrName, TypedefNode)
|
||||
if lib_name and FullName != AttrName:
|
||||
FullTypedef_node: CTypeInfo = CTypeInfo()
|
||||
FullTypedef_node.Name = FullName
|
||||
FullTypedef_node.IsTypedef = True
|
||||
FullTypedef_node.OriginalType = attr.__name__
|
||||
FullTypedef_node.set('source', 'annotation_module')
|
||||
FullTypedef_node.library_name = lib_name
|
||||
FullTypedef_node.file = source_file
|
||||
self.SymbolTable.insert(FullName, FullTypedef_node)
|
||||
count += 1
|
||||
# 检查是否是下划线前缀的 CType 子类(如 _CTypedef -> CTypedef)
|
||||
elif AttrName.startswith('_') and len(AttrName) > 1:
|
||||
PublicName: str = AttrName[1:]
|
||||
PublicAttr: type | None = getattr(module, PublicName, None)
|
||||
if PublicAttr is not None and not isinstance(attr, type):
|
||||
continue
|
||||
if isinstance(attr, type) and issubclass(attr, CType) and attr is not CType:
|
||||
if not self.SymbolTable.has(PublicName):
|
||||
if lib_name:
|
||||
FullName: str = f'{lib_name}.{PublicName}'
|
||||
else:
|
||||
FullName = PublicName
|
||||
TypedefNode: CTypeInfo = CTypeInfo()
|
||||
TypedefNode.Name = PublicName
|
||||
TypedefNode.IsTypedef = True
|
||||
TypedefNode.OriginalType = attr.__name__
|
||||
TypedefNode.set('source', 'annotation_module')
|
||||
TypedefNode.library_name = lib_name
|
||||
TypedefNode.file = source_file
|
||||
self.SymbolTable.insert(PublicName, TypedefNode)
|
||||
if lib_name and FullName != PublicName:
|
||||
FullTypedef_node: CTypeInfo = CTypeInfo()
|
||||
FullTypedef_node.Name = FullName
|
||||
FullTypedef_node.IsTypedef = True
|
||||
FullTypedef_node.OriginalType = attr.__name__
|
||||
FullTypedef_node.set('source', 'annotation_module')
|
||||
FullTypedef_node.library_name = lib_name
|
||||
FullTypedef_node.file = source_file
|
||||
self.SymbolTable.insert(FullName, FullTypedef_node)
|
||||
count += 1
|
||||
return count
|
||||
|
||||
# 确定解析方法
|
||||
use_file_mode: bool = False
|
||||
if parse_method == 'file':
|
||||
use_file_mode = True
|
||||
elif parse_method == 'module':
|
||||
use_file_mode = False
|
||||
else: # auto
|
||||
use_file_mode = os.path.isfile(ModuleName)
|
||||
|
||||
# 确定库名称
|
||||
lib_name: str | None = library_name
|
||||
if lib_name is None:
|
||||
if use_file_mode:
|
||||
# 从文件路径推断库名称
|
||||
lib_name = os.path.splitext(os.path.basename(ModuleName))[0]
|
||||
else:
|
||||
# 模块名就是库名称
|
||||
lib_name = ModuleName
|
||||
|
||||
# 根据解析方法加载模块
|
||||
if use_file_mode:
|
||||
# AST 模式:使用 AST 解析文件,不执行代码
|
||||
try:
|
||||
# 临时保存当前的 EmbeddedAssignments 和 TypedefAssignments
|
||||
saved_embedded: dict = self.EmbeddedAssignments.copy()
|
||||
saved_typedef: dict = self.TypedefAssignments.copy()
|
||||
|
||||
# 清空 PD 收集(注解文件不应该收集 PD 语句)
|
||||
self.EmbeddedAssignments = {}
|
||||
self.TypedefAssignments = {}
|
||||
|
||||
# 直接调用 ParsePythonFile 解析文件提取类型信息
|
||||
# 注意:这不会执行任何 Python 代码,只是解析 AST
|
||||
# UpdateCurrentFile=False 表示不修改 CurrentFile
|
||||
self.ParsePythonFile(ModuleName, UpdateCurrentFile=False)
|
||||
|
||||
# 恢复主代码文件的 PD 收集
|
||||
self.EmbeddedAssignments = saved_embedded
|
||||
self.TypedefAssignments = saved_typedef
|
||||
|
||||
# 从文件名推断类型前缀(如 test_t -> test_t.xxx)
|
||||
TypePrefix: str = lib_name
|
||||
count: int = 0
|
||||
|
||||
# 检查符号表中新增的类型(注解文件解析后的所有 struct 类型)
|
||||
# 需要检查这些类型是否继承自 CType,如果是则是 typedef 别名
|
||||
new_types: list[str] = []
|
||||
for TypeName, TypeInfo in self.SymbolTable.items():
|
||||
if TypeInfo.IsStruct:
|
||||
new_types.append(TypeName)
|
||||
|
||||
# 再次遍历 AST,检测继承自 CType 的类
|
||||
try:
|
||||
with open(ModuleName, 'r', encoding='utf-8') as f:
|
||||
ann_content: str = f.read()
|
||||
ann_tree: ast.Module = ast.parse(ann_content)
|
||||
for node in ann_tree.body:
|
||||
if isinstance(node, ast.ClassDef):
|
||||
ClassName: str = node.name
|
||||
# 检查是否有基类
|
||||
for base in node.bases:
|
||||
if isinstance(base, ast.Name) and base.id == 'CType':
|
||||
# 这个类继承自 CType,是 typedef 别名
|
||||
# 更新符号表中的类型为 typedef
|
||||
if self.SymbolTable.has(ClassName):
|
||||
TypedefNode: CTypeInfo = CTypeInfo()
|
||||
TypedefNode.Name = ClassName
|
||||
TypedefNode.IsTypedef = True
|
||||
TypedefNode.OriginalType = self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}')
|
||||
TypedefNode.set('source', 'annotation_module')
|
||||
TypedefNode.set('is_ctype_subclass', True)
|
||||
self.SymbolTable.insert(ClassName, TypedefNode)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"解析注解文件类型定义失败: {_e}", "Exception")
|
||||
|
||||
# 为所有新增的类型添加库前缀和 source 标记
|
||||
for TypeName in new_types:
|
||||
# 添加带前缀的类型名
|
||||
FullName: str = f'{TypePrefix}.{TypeName}'
|
||||
TypeInfo: CTypeInfo | dict[str, Any] = self.SymbolTable[TypeName].copy()
|
||||
TypeInfo['source'] = 'annotation_module'
|
||||
TypeInfo['original_name'] = TypeName
|
||||
self.SymbolTable.insert(FullName, TypeInfo)
|
||||
count += 1
|
||||
|
||||
# 再次遍历 AST,查找注解文件中的 typedef 语句(AnnAssign with t.CTypedef)
|
||||
# 注意:必须在类定义处理完之后再处理 typedef
|
||||
typedef_annots: list[tuple[str, str]] = []
|
||||
# 查找 CEnum 成员变量(AnnAssign with t.CEnum | t.State 或 t.CEnum)
|
||||
cEnumMembers: list[tuple[str, int | None]] = []
|
||||
try:
|
||||
with open(ModuleName, 'r', encoding='utf-8') as f:
|
||||
ann_content: str = f.read()
|
||||
ann_tree: ast.Module = ast.parse(ann_content)
|
||||
for node in ann_tree.body:
|
||||
# 检测 xxx: t.CEnum 形式的枚举成员变量
|
||||
if isinstance(node, ast.AnnAssign):
|
||||
if isinstance(node.target, ast.Name) and node.annotation:
|
||||
TargetName: str = node.target.id
|
||||
# 检查注解是否是 BinOp (Union) 或直接是 Attribute
|
||||
IsCenum: bool = False
|
||||
if isinstance(node.annotation, ast.BinOp):
|
||||
# 检查是否包含 CEnum
|
||||
if AnnotationContainsName(node.annotation, 'CEnum'):
|
||||
IsCenum = True
|
||||
elif isinstance(node.annotation, ast.Attribute):
|
||||
# 直接是 t.CEnum
|
||||
if node.annotation.attr == t.CEnum.__name__:
|
||||
IsCenum = True
|
||||
|
||||
if IsCenum:
|
||||
# 检查值是否是 Constant (枚举成员值)
|
||||
if node.value and isinstance(node.value, ast.Constant):
|
||||
value: int | str | float | None = node.value.value
|
||||
else:
|
||||
value = None
|
||||
cEnumMembers.append((TargetName, value))
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"解析 CEnum 成员变量失败: {_e}", "Exception")
|
||||
|
||||
# 处理 CEnum 成员变量
|
||||
for TargetName, value in cEnumMembers:
|
||||
# 注册枚举成员
|
||||
MemberNode: CTypeInfo = CTypeInfo()
|
||||
MemberNode.Name = TargetName
|
||||
MemberNode.BaseType = t.CEnum(TypePrefix)
|
||||
MemberNode.value = value
|
||||
MemberNode.EnumName = TypePrefix
|
||||
MemberNode.library_name = TypePrefix
|
||||
MemberNode.IsEnumMember = True
|
||||
self.SymbolTable.insert(TargetName, MemberNode)
|
||||
self.SymbolTable.insert(f"{TypePrefix}.{TargetName}", MemberNode)
|
||||
self.SymbolTable.insert(f"{TypePrefix}_{TargetName}", MemberNode)
|
||||
|
||||
try:
|
||||
with open(ModuleName, 'r', encoding='utf-8') as f:
|
||||
ann_content: str = f.read()
|
||||
ann_tree: ast.Module = ast.parse(ann_content)
|
||||
for node in ann_tree.body:
|
||||
# 检测 xxx: t.CTypedef = xxx 形式的 typedef 语句
|
||||
if isinstance(node, ast.AnnAssign):
|
||||
if isinstance(node.target, ast.Name) and node.annotation and node.value:
|
||||
TargetName: str = node.target.id
|
||||
# 检查注解是否是 t.CTypedef
|
||||
if isinstance(node.annotation, ast.Attribute):
|
||||
if isinstance(node.annotation.value, ast.Name):
|
||||
if IsTModule(node.annotation.value.id) and node.annotation.attr == 'CTypedef':
|
||||
# 检查值是否是 Name
|
||||
if isinstance(node.value, ast.Name):
|
||||
original_name: str = node.value.id
|
||||
typedef_annots.append((TargetName, original_name))
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"解析 typedef 语句失败: {_e}", "Exception")
|
||||
|
||||
# 处理 typedef 注解
|
||||
for TargetName, original_name in typedef_annots:
|
||||
# 检查原始类型是否在符号表中(带前缀或不带前缀)
|
||||
orig_with_prefix: str = f'{TypePrefix}.{original_name}'
|
||||
if self.SymbolTable.has(orig_with_prefix):
|
||||
# 添加带前缀的 typedef 别名
|
||||
FullTypedef_name: str = f'{TypePrefix}.{TargetName}'
|
||||
TypedefNode: CTypeInfo = CTypeInfo()
|
||||
TypedefNode.Name = FullTypedef_name
|
||||
TypedefNode.IsTypedef = True
|
||||
orig_entry: CTypeInfo | dict[str, Any] = self.SymbolTable.lookup(orig_with_prefix)
|
||||
orig_type_str: str = f'struct {original_name}'
|
||||
if isinstance(orig_entry, dict):
|
||||
if orig_entry.get('type') == 'typedef':
|
||||
orig_type_str = orig_entry.get('OriginalType', f'struct {original_name}')
|
||||
elif orig_entry.get('type') == 'enum':
|
||||
orig_type_str = f'enum {original_name}'
|
||||
elif orig_entry.IsTypedef:
|
||||
orig_type_str = orig_entry.OriginalType or f'struct {original_name}'
|
||||
elif orig_entry.IsEnum:
|
||||
orig_type_str = f'enum {original_name}'
|
||||
TypedefNode.OriginalType = orig_type_str
|
||||
TypedefNode.set('source', 'annotation_module')
|
||||
TypedefNode.set('original_name', TargetName)
|
||||
self.SymbolTable.insert(FullTypedef_name, TypedefNode)
|
||||
count += 1
|
||||
|
||||
self.AnnotationModules.add(lib_name)
|
||||
return count
|
||||
except Exception as e:
|
||||
# 恢复 PD 收集
|
||||
self.EmbeddedAssignments = saved_embedded
|
||||
self.TypedefAssignments = saved_typedef
|
||||
self.LogWarning(f"AST模式加载注解模块失败: {ModuleName}, 错误: {e}")
|
||||
return 0
|
||||
else:
|
||||
# importlib 模式:导入模块
|
||||
try:
|
||||
module: types.ModuleType = importlib.import_module(ModuleName)
|
||||
count: int = register_to_symboltable(module, lib_name, None)
|
||||
self.AnnotationModules.add(lib_name)
|
||||
return count
|
||||
except ImportError:
|
||||
self.LogWarning(f"importlib模式加载注解模块失败: {ModuleName}")
|
||||
return 0
|
||||
except Exception as e:
|
||||
self.LogWarning(f"加载注解模块失败: {ModuleName}, 错误: {e}")
|
||||
return 0
|
||||
|
||||
def _LoadAnnotationFiles(self, FilePaths: list[str | tuple]) -> None:
|
||||
"""加载多个注解文件并注册到符号表
|
||||
|
||||
Args:
|
||||
FilePaths: 文件路径列表,每个元素可以是:
|
||||
- str: 文件路径或模块名
|
||||
- tuple: (path, options) 或 (path, library_name, parse_method)
|
||||
"""
|
||||
for item in FilePaths:
|
||||
if isinstance(item, tuple):
|
||||
if len(item) >= 3:
|
||||
path: str
|
||||
library_name: str
|
||||
parse_method: str
|
||||
path, library_name, parse_method = item[:3]
|
||||
count: int = self._LoadAnnotationModule(path, library_name, parse_method)
|
||||
elif len(item) == 2:
|
||||
path: str
|
||||
library_name: str
|
||||
path, library_name = item
|
||||
count: int = self._LoadAnnotationModule(path, library_name, 'auto')
|
||||
else:
|
||||
count: int = self._LoadAnnotationModule(item)
|
||||
else:
|
||||
count: int = self._LoadAnnotationModule(item)
|
||||
|
||||
# 别名,保持向后兼容
|
||||
LoadAnnotationFiles = _LoadAnnotationFiles
|
||||
157
lib/core/Translator/BaseTranslator.py
Normal file
157
lib/core/Translator/BaseTranslator.py
Normal file
@@ -0,0 +1,157 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
from typing import Any, Callable, Dict, TYPE_CHECKING
|
||||
|
||||
from lib.core.Exportable import Exportable
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import llvmlite.ir as ir
|
||||
|
||||
from lib.core.Handles import (
|
||||
IfHandle, ForHandle, WhileHandle,
|
||||
AnnAssignHandle,
|
||||
HandlesTypeMerge, ExprHandle, BodyHandle,
|
||||
ReturnHandle, AssignHandle, AugAssignHandle, DeleteHandle,
|
||||
WithHandle, TryHandle, AssertHandle, RaiseHandle, MatchHandle,
|
||||
ExprUtils, ExprOpsHandle, ExprAttrHandle, ExprBuiltinHandle,
|
||||
ExprAsmHandle, ExprFormatHandle, ExprLambdaHandle, ExprCallHandle,
|
||||
CSpecialCallHandle, TSpecialCallHandle,
|
||||
ClassHandle,
|
||||
FunctionHandle,
|
||||
ImportHandle
|
||||
)
|
||||
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
|
||||
|
||||
|
||||
def _StrictLog(logger: Callable[[str], None], msg: str) -> None:
|
||||
"""在 strict 模式下记录异常日志"""
|
||||
if _ConfigMode == "strict":
|
||||
logger(msg)
|
||||
|
||||
|
||||
class BaseTranslatorMixin:
|
||||
"""代码转换器基础 Mixin
|
||||
|
||||
提供 __init__、日志、调试输出与表达式处理等基础能力。
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.VarScopes: list[Dict[str, SymbolNode]] = [{}] # 跟踪变量作用域,第一个是全局作用域
|
||||
self.FunctionReturnTypes: Dict[str, CTypeInfo] = {} # 记录函数名和其返回类型
|
||||
self.CurrentCReturnTypes: list[CTypeInfo] | None = None # 当前函数的 CReturn 类型列表
|
||||
self._CurrentCpythonObjectClass: str | None = None # 当前正在处理的 CPython 对象类名
|
||||
self.FunctionDefCache: dict = {} # 函数定义缓存
|
||||
self.OriginalLines: list[str] = [] # 原始代码行
|
||||
self.Content: str = ''
|
||||
self.DebugFile: str | None = None # 调试输出文件路径
|
||||
self.IsHeader: bool = False # 是否生成头文件(仅处理定义、宏、导入等,忽略函数体)
|
||||
self.AnnotationModules: set[str] = set() # 注解模块集合,用于识别类型定义模块
|
||||
self.Warnings: list[str] = [] # 警告日志
|
||||
self._ErrorStack: list[tuple[str, str, str]] = [] # 错误栈,按顺序收集错误位置
|
||||
self.Errors: list[dict[str, str | None]] = [] # 错误日志
|
||||
self.SliceCount: int = 0 # 切片计数
|
||||
self.SliceInfos: list = [] # 切片信息列表
|
||||
self.SliceLevel: int = 3 # 切片优化级别
|
||||
self.GeneratedTypes: set[str] = set() # 在当前代码中生成的类型(struct/typedef)
|
||||
self.EmbeddedAssignments: dict[str, list] = {} # {ClassName: [var1, var2, ...]} 嵌入的实例化变量
|
||||
self.TypedefAssignments: dict[str, list] = {} # {ClassName: [(var1, IsPtr), ...]} 嵌入的 typedef/指针变量
|
||||
self.ChainAssignmentArrays: list = [] # 链式赋值数组形式 [(ClassName, VarName, ArraySize_node), ...]
|
||||
self.tree: ast.AST | None = None # 保存解析后的 AST 树
|
||||
self.LibraryPaths: list[str] = ['.'] # 库搜索路径列表,默认包含当前目录
|
||||
self.InClass: bool = False # 是否正在处理 class 定义
|
||||
self._UserTypeModules: dict = {}
|
||||
self._source_module_sig_files: 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._t_c_imported_names: dict = {}
|
||||
|
||||
# 导出表
|
||||
self.Exportable = Exportable(filename='')
|
||||
|
||||
self.SymbolTable = SymbolTable(self)
|
||||
self.IfHandler = IfHandle(self)
|
||||
self.ForHandler = ForHandle(self)
|
||||
self.WhileHandler = WhileHandle(self)
|
||||
self.AnnAssignHandler = AnnAssignHandle(self)
|
||||
self.TypeMergeHandler = HandlesTypeMerge(self)
|
||||
self.ExprHandler = ExprHandle(self)
|
||||
self.ExprUtils = ExprUtils(self)
|
||||
self.ExprOpsHandle = ExprOpsHandle(self)
|
||||
self.ExprAttrHandle = ExprAttrHandle(self)
|
||||
self.ExprBuiltinHandle = ExprBuiltinHandle(self)
|
||||
self.ExprAsmHandle = ExprAsmHandle(self)
|
||||
self.ExprFormatHandle = ExprFormatHandle(self)
|
||||
self.ExprLambdaHandle = ExprLambdaHandle(self)
|
||||
self.ExprCallHandle = ExprCallHandle(self)
|
||||
self.CSpecialCallHandle = CSpecialCallHandle(self)
|
||||
self.TSpecialCallHandle = TSpecialCallHandle(self)
|
||||
self.ClassHandler = ClassHandle(self)
|
||||
self.FunctionHandler = FunctionHandle(self)
|
||||
self.ImportHandler = ImportHandle(self)
|
||||
self.BodyHandler = BodyHandle(self)
|
||||
self.ReturnHandler = ReturnHandle(self)
|
||||
self.AssignHandler = AssignHandle(self)
|
||||
self.AugAssignHandler = AugAssignHandle(self)
|
||||
self.DeleteHandler = DeleteHandle(self)
|
||||
self.WithHandler = WithHandle(self)
|
||||
self.TryHandler = TryHandle(self)
|
||||
self.AssertHandler = AssertHandle(self)
|
||||
self.RaiseHandler = RaiseHandle(self)
|
||||
self.MatchHandler = MatchHandle(self)
|
||||
|
||||
def LogWarning(self, message: str, LineNum: int | None = None) -> None:
|
||||
"""记录警告
|
||||
|
||||
Args:
|
||||
message: 警告消息
|
||||
LineNum: 行号(可选)
|
||||
"""
|
||||
warning = f"Warning: {message}"
|
||||
if LineNum is not None:
|
||||
warning += f" (line {LineNum})"
|
||||
self.Warnings.append(warning)
|
||||
|
||||
def LogError(self, message: str, LineNum: int | None = None) -> None:
|
||||
"""记录错误
|
||||
|
||||
Args:
|
||||
message: 错误消息
|
||||
LineNum: 行号
|
||||
"""
|
||||
_vlog().error(message)
|
||||
entry: dict[str, str | int | None] = {'message': message, 'line': LineNum}
|
||||
self.Errors.append(entry)
|
||||
|
||||
# 检查 config 中是否有 debug 文件
|
||||
DebugFile: str | None = None
|
||||
if hasattr(self, 'config') and self.config:
|
||||
DebugFile = getattr(self.config, 'debug', None)
|
||||
|
||||
if DebugFile:
|
||||
with open(DebugFile, 'a', encoding='utf-8') as f:
|
||||
LineInfo: str = f' line {LineNum}' if LineNum else ''
|
||||
f.write(f'[ERROR]{LineInfo}: {message}\n')
|
||||
|
||||
def SetDebugFile(self, FilePath: str) -> None:
|
||||
"""设置调试输出文件"""
|
||||
self.DebugFile = FilePath
|
||||
|
||||
def DebugPrint(self, *args: Any, **kwargs: Any) -> None:
|
||||
"""输出调试信息到文件"""
|
||||
if self.DebugFile:
|
||||
with open(self.DebugFile, 'a', encoding='utf-8') as f:
|
||||
print(*args, file=f, **kwargs)
|
||||
|
||||
def HandleExpr(self, Node: ast.AST, UseSingleQuote: bool = False, VarType: ir.Type | None = None) -> Any:
|
||||
return self.ExprHandler.HandleExpr(Node, UseSingleQuote, VarType)
|
||||
305
lib/core/Translator/ConstEval.py
Normal file
305
lib/core/Translator/ConstEval.py
Normal file
@@ -0,0 +1,305 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
from typing import TYPE_CHECKING
|
||||
import llvmlite.ir as ir
|
||||
|
||||
from lib.core.ConstEvaluator import ConstEvaluator
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
|
||||
|
||||
class ConstEvalMixin:
|
||||
"""常量表达式求值 Mixin
|
||||
|
||||
提供数组初始化常量构建与常量表达式求值能力。
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def _bswap_constant_value(val: int, width: int) -> int:
|
||||
"""编译期字节序交换"""
|
||||
if width == 16:
|
||||
return ((val & 0xFF) << 8) | ((val >> 8) & 0xFF)
|
||||
elif width == 32:
|
||||
return ((val & 0xFF) << 24) | ((val & 0xFF00) << 8) | ((val >> 8) & 0xFF00) | ((val >> 24) & 0xFF)
|
||||
elif width == 64:
|
||||
return ((val & 0xFF) << 56) | ((val & 0xFF00) << 40) | ((val & 0xFF0000) << 24) | ((val & 0xFF000000) << 8) | ((val >> 8) & 0xFF000000) | ((val >> 24) & 0xFF0000) | ((val >> 40) & 0xFF00) | ((val >> 56) & 0xFF)
|
||||
return val
|
||||
|
||||
def _BuildArrayInitConstants(self, value_node: ast.AST, ElemType: ir.Type, elem_type_node: ast.AST, ArrayCount: int, Gen: LlvmCodeGenerator, byte_order: str = '') -> list[ir.Constant] | None:
|
||||
_zv: ir.Constant | None = Gen._zero_value_for_type(ElemType)
|
||||
_fallback: ir.Constant = _zv if _zv is not None else ir.Constant(ElemType, ir.Undefined)
|
||||
if not isinstance(value_node, (ast.List, ast.Set)):
|
||||
return None
|
||||
if isinstance(ElemType, ir.ArrayType):
|
||||
constants: list[ir.Constant] = []
|
||||
for elt in value_node.elts:
|
||||
if isinstance(elt, (ast.List, ast.Set)):
|
||||
inner_consts: list[ir.Constant] | None = self._BuildMultiDimArrayInitConstants(elt, ElemType, Gen)
|
||||
if inner_consts:
|
||||
try:
|
||||
constants.append(ir.Constant(ElemType, inner_consts))
|
||||
except Exception: # fallback to _fallback on constant construction failure
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
while len(constants) < ArrayCount:
|
||||
constants.append(_fallback)
|
||||
return constants[:ArrayCount]
|
||||
StructName: str | None = None
|
||||
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
|
||||
StructName = elem_type_node.id
|
||||
constants = []
|
||||
for elt in value_node.elts:
|
||||
if StructName and isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == StructName:
|
||||
const: ir.Constant | None = self.ClassHandler._BuildStructConstant(elt, StructName, Gen)
|
||||
if const:
|
||||
constants.append(const)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.Constant):
|
||||
# 字符串常量:根据引号类型决定 i8 或 i8*
|
||||
if isinstance(elt.value, str):
|
||||
const: ir.Constant | None = self._BuildStringLiteralConstant(elt, ElemType, Gen)
|
||||
if const:
|
||||
constants.append(const)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
const = self._BuildScalarConstantUnified(elt, ElemType, Gen)
|
||||
if const:
|
||||
constants.append(const)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.UnaryOp):
|
||||
const = self._BuildScalarConstantUnified(elt, ElemType, Gen)
|
||||
if const:
|
||||
constants.append(const)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'chr':
|
||||
if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, int):
|
||||
try:
|
||||
constants.append(ir.Constant(ElemType, elt.args[0].value & 0xFF))
|
||||
except Exception: # fallback to _fallback on constant construction failure
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'ord':
|
||||
if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, str) and len(elt.args[0].value) == 1:
|
||||
try:
|
||||
constants.append(ir.Constant(ElemType, ord(elt.args[0].value)))
|
||||
except Exception: # fallback to _fallback on constant construction failure
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
const_val: int | float | str | None = self._try_eval_const_call(elt, Gen)
|
||||
if const_val is not None:
|
||||
try:
|
||||
constants.append(ir.Constant(ElemType, const_val))
|
||||
except Exception: # fallback to _fallback on constant construction failure
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
while len(constants) < ArrayCount:
|
||||
constants.append(_fallback)
|
||||
if byte_order == 'big' and isinstance(ElemType, ir.IntType) and ElemType.width in (16, 32, 64):
|
||||
swapped: list[ir.Constant] = []
|
||||
for c in constants:
|
||||
if isinstance(c, ir.Constant) and isinstance(c.type, ir.IntType) and isinstance(c.constant, int):
|
||||
swapped_val: int = self._bswap_constant_value(int(c.constant), ElemType.width)
|
||||
swapped.append(ir.Constant(ElemType, swapped_val))
|
||||
else:
|
||||
swapped.append(c)
|
||||
constants = swapped
|
||||
return constants[:ArrayCount]
|
||||
|
||||
def _BuildStringLiteralConstant(self, node: ast.Constant, target_type: ir.Type, Gen: LlvmCodeGenerator) -> ir.Constant | None:
|
||||
"""根据引号类型决定字符串常量的类型:
|
||||
|
||||
- 单引号单字符 → i8 (char 值)
|
||||
- 双引号/单引号多字符/三重引号 → i8* (C 字符串指针)
|
||||
- 空字符串 → 0 (None),传入 ptr 目标自动隐式转换
|
||||
"""
|
||||
if not isinstance(node.value, str):
|
||||
return None
|
||||
s: str = node.value
|
||||
# 空字符串 → 0 (None)
|
||||
if len(s) == 0:
|
||||
try:
|
||||
return ir.Constant(target_type, 0)
|
||||
except Exception:
|
||||
return None
|
||||
# 获取源代码以判断引号类型
|
||||
quote_char: str | None = None
|
||||
is_triple: bool = False
|
||||
col_offset: int = getattr(node, 'col_offset', 0)
|
||||
node_lineno: int = getattr(node, 'lineno', 0)
|
||||
# AST 的 lineno 可能不准确(常量节点可能指向下一行),
|
||||
# 因此在 lineno 和 lineno-1 两行中查找引号
|
||||
for try_lineno in (node_lineno, node_lineno - 1):
|
||||
source_line: str | None = Gen._get_source_line(try_lineno)
|
||||
if source_line and col_offset < len(source_line):
|
||||
ch: str = source_line[col_offset]
|
||||
if ch in ("'", '"'):
|
||||
quote_char = ch
|
||||
if col_offset + 2 < len(source_line) and source_line[col_offset:col_offset + 3] in ("'''", '"""'):
|
||||
is_triple = True
|
||||
break
|
||||
# 判断是否为 char (i8):单引号、非三重、单字符
|
||||
is_char: bool = (not is_triple) and (quote_char == "'") and (len(s) == 1)
|
||||
if is_char:
|
||||
# 单引号单字符 → i8
|
||||
if isinstance(target_type, ir.IntType):
|
||||
try:
|
||||
return ir.Constant(target_type, ord(s))
|
||||
except Exception:
|
||||
return None
|
||||
# 目标类型不是整数 → 类型不匹配
|
||||
return None
|
||||
else:
|
||||
# 双引号/多字符/三重 → i8* (C 字符串)
|
||||
if isinstance(target_type, ir.PointerType):
|
||||
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 = f"str_const_{id(node)}"
|
||||
gv: ir.GlobalVariable = ir.GlobalVariable(Gen.module, arr_type, name=gv_name)
|
||||
gv.initializer = ir.Constant(arr_type, bytearray(str_bytes))
|
||||
gv.linkage = 'internal'
|
||||
return ir.Constant(target_type, gv.get_reference())
|
||||
# 目标类型不是指针 → 类型不匹配
|
||||
return None
|
||||
|
||||
def _BuildScalarConstantUnified(self, node: ast.AST, target_type: ir.Type, Gen: LlvmCodeGenerator) -> ir.Constant | None:
|
||||
"""统一的标量常量构建方法。
|
||||
|
||||
合并原 HandlesClassDef._BuildScalarConstant 与 HandlesImports._BuildScalarConstant 的特性:
|
||||
- 支持 bool/int/float/str/ast.UnaryOp(USub)/ast.Name(True/False)
|
||||
- 字符串处理委托给 _BuildStringLiteralConstant
|
||||
- 显式拒绝 BaseStructType
|
||||
- 全部 try/except 保护
|
||||
"""
|
||||
# 显式拒绝结构体类型
|
||||
if isinstance(target_type, ir.BaseStructType):
|
||||
return None
|
||||
# 处理常量节点
|
||||
if isinstance(node, ast.Constant):
|
||||
# bool 必须在 int 之前判断(bool 是 int 的子类)
|
||||
if isinstance(node.value, bool):
|
||||
try:
|
||||
return ir.Constant(target_type, 1 if node.value else 0)
|
||||
except Exception:
|
||||
return None
|
||||
elif isinstance(node.value, int):
|
||||
try:
|
||||
return ir.Constant(target_type, node.value)
|
||||
except Exception:
|
||||
return None
|
||||
elif isinstance(node.value, float):
|
||||
try:
|
||||
return ir.Constant(target_type, node.value)
|
||||
except Exception:
|
||||
return None
|
||||
elif isinstance(node.value, str):
|
||||
# 字符串处理委托给 _BuildStringLiteralConstant
|
||||
const: ir.Constant | None = self._BuildStringLiteralConstant(node, target_type, Gen)
|
||||
if const is not None:
|
||||
return const
|
||||
# 回退:直接创建字符串全局变量(i8*)
|
||||
try:
|
||||
return Gen._create_string_global(node.value)
|
||||
except Exception:
|
||||
return None
|
||||
# 处理一元负号
|
||||
elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.USub):
|
||||
if isinstance(node.operand, ast.Constant) and isinstance(node.operand.value, int):
|
||||
try:
|
||||
return ir.Constant(target_type, -node.operand.value)
|
||||
except Exception:
|
||||
return None
|
||||
# 处理 True/False 名称节点
|
||||
elif isinstance(node, ast.Name):
|
||||
if node.id == 'True':
|
||||
try:
|
||||
return ir.Constant(target_type, 1)
|
||||
except Exception:
|
||||
return None
|
||||
elif node.id == 'False':
|
||||
try:
|
||||
if isinstance(target_type, ir.PointerType):
|
||||
return ir.Constant(target_type, None)
|
||||
return ir.Constant(target_type, 0)
|
||||
except Exception:
|
||||
return None
|
||||
return None
|
||||
|
||||
def _try_eval_const_call(self, node: ast.AST, Gen: LlvmCodeGenerator) -> int | None:
|
||||
if isinstance(node, ast.Call):
|
||||
func_name: str | None = None
|
||||
if isinstance(node.func, ast.Name):
|
||||
func_name = node.func.id
|
||||
elif isinstance(node.func, ast.Attribute):
|
||||
func_name = node.func.attr
|
||||
if func_name:
|
||||
arg_vals: list[int | float | str | None] = []
|
||||
for arg in node.args:
|
||||
v: int | float | str | None = self._try_eval_const_expr(arg, Gen)
|
||||
if v is None:
|
||||
return None
|
||||
arg_vals.append(v)
|
||||
if func_name == 'COLOR_RGB' and len(arg_vals) == 3:
|
||||
r: int | float | str | None
|
||||
g: int | float | str | None
|
||||
b: int | float | str | None
|
||||
r, g, b = arg_vals
|
||||
return (255 << 24) | (int(b) << 16) | (int(g) << 8) | int(r)
|
||||
if func_name in Gen._DefineConstants:
|
||||
return Gen._DefineConstants[func_name]
|
||||
for key in Gen.functions:
|
||||
if key.endswith(f'__{func_name}'):
|
||||
return None
|
||||
return None
|
||||
return self._try_eval_const_expr(node, Gen)
|
||||
|
||||
def _try_eval_const_expr(self, node: ast.AST, Gen: LlvmCodeGenerator) -> int | float | str | None:
|
||||
return ConstEvaluator.eval_with_symtab(node, self.SymbolTable)
|
||||
|
||||
def _BuildMultiDimArrayInitConstants(self, value_node: ast.AST, ArrayType: ir.ArrayType, Gen: LlvmCodeGenerator) -> list[ir.Constant] | None:
|
||||
inner_type: ir.Type = ArrayType.element
|
||||
count: int = ArrayType.count
|
||||
elts: list[ast.AST] = list(value_node.elts) if hasattr(value_node, 'elts') else []
|
||||
_zv: ir.Constant | None = Gen._zero_value_for_type(inner_type)
|
||||
_fallback: ir.Constant = _zv if _zv is not None else ir.Constant(inner_type, ir.Undefined)
|
||||
constants: list[ir.Constant] = []
|
||||
for elt in elts:
|
||||
if isinstance(inner_type, ir.ArrayType):
|
||||
if isinstance(elt, (ast.List, ast.Set)):
|
||||
inner_consts: list[ir.Constant] | None = self._BuildMultiDimArrayInitConstants(elt, inner_type, Gen)
|
||||
if inner_consts:
|
||||
constants.append(ir.Constant(inner_type, inner_consts))
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.Constant):
|
||||
const: ir.Constant | None = self._BuildScalarConstantUnified(elt, inner_type, Gen)
|
||||
if const:
|
||||
constants.append(const)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.UnaryOp):
|
||||
const = self._BuildScalarConstantUnified(elt, inner_type, Gen)
|
||||
if const:
|
||||
constants.append(const)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
while len(constants) < count:
|
||||
constants.append(_fallback)
|
||||
return constants[:count]
|
||||
642
lib/core/Translator/LlvmGenerator.py
Normal file
642
lib/core/Translator/LlvmGenerator.py
Normal file
@@ -0,0 +1,642 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import re
|
||||
import llvmlite.ir as ir
|
||||
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, CTypeHelper
|
||||
from lib.includes import t
|
||||
from lib.constants.config import mode as _config_mode
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
from lib.core.DecoratorPass import run as _run_decorator_pass
|
||||
from lib.core.SymbolUtils import IsTModule, AnnotationContainsName
|
||||
|
||||
|
||||
class LlvmGeneratorMixin:
|
||||
"""LLVM IR 生成 Mixin
|
||||
|
||||
提供 LLVM IR 直接生成、模块级 LLVM IR 处理与 C 代码生成入口能力。
|
||||
"""
|
||||
|
||||
def GenerateLlvmDirect(self, Tree: ast.Module) -> str:
|
||||
Gen: LlvmCodeGenerator = self.LlvmGen
|
||||
|
||||
# === 新增:轻量 AST 遍历,收集类图信息,解决前向引用 ===
|
||||
Gen._class_graph: dict[str, dict[str, bool | list[str]]] = {}
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
if isinstance(Node, ast.ClassDef):
|
||||
bases: list[str] = []
|
||||
for base in Node.bases:
|
||||
if hasattr(base, 'id'):
|
||||
bases.append(base.id)
|
||||
elif hasattr(base, 'attr'):
|
||||
bases.append(base.attr)
|
||||
has_methods: bool = any(isinstance(item, ast.FunctionDef) for item in Node.body)
|
||||
# 检测 @t.NoVTable 装饰器(非多态继承基类标记)
|
||||
has_novtable: bool = False
|
||||
if hasattr(Node, 'decorator_list') and Node.decorator_list:
|
||||
for decorator in Node.decorator_list:
|
||||
if isinstance(decorator, ast.Attribute):
|
||||
if getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'NoVTable':
|
||||
has_novtable = True
|
||||
elif isinstance(decorator, ast.Name):
|
||||
if decorator.id == 'NoVTable':
|
||||
has_novtable = True
|
||||
Gen._class_graph[Node.name] = {
|
||||
'bases': bases,
|
||||
'has_methods': has_methods,
|
||||
'has_novtable': has_novtable,
|
||||
}
|
||||
# === 结束新增 ===
|
||||
|
||||
# 预扫描:为所有 -> str 注解的函数注册正确的返回类型 i8*
|
||||
# 这样在类方法中调用这些函数时,前向声明会使用正确的类型
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
if isinstance(Node, ast.FunctionDef):
|
||||
if Node.returns and isinstance(Node.returns, ast.Name) and Node.returns.id == 'str':
|
||||
Gen.known_return_types[Node.name] = ir.PointerType(ir.IntType(8))
|
||||
|
||||
# 首先收集所有 CDefine 常量,确保类定义中可以引用
|
||||
def _extract_call_const_val(node: ast.AST) -> int | str | float | None:
|
||||
if isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
if getattr(node.func.value, 'id', None) == 't':
|
||||
if node.args and isinstance(node.args[0], ast.Constant):
|
||||
return node.args[0].value
|
||||
elif isinstance(node.func, ast.Name):
|
||||
if node.args and isinstance(node.args[0], ast.Constant):
|
||||
return node.args[0].value
|
||||
return None
|
||||
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name) and Node.value:
|
||||
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(Node.annotation)
|
||||
if TypeInfo and TypeInfo.BaseType and ((isinstance(TypeInfo.BaseType, type) and issubclass(TypeInfo.BaseType, t.CDefine)) or isinstance(TypeInfo.BaseType, t.CDefine)):
|
||||
val: int | str | float | None = None
|
||||
if isinstance(Node.value, ast.Constant):
|
||||
val = Node.value.value
|
||||
else:
|
||||
val = _extract_call_const_val(Node.value)
|
||||
if val is not None:
|
||||
if not hasattr(Gen, '_define_constants'):
|
||||
Gen._define_constants: dict[str, int | str | float | bool] = {}
|
||||
Gen._define_constants[Node.target.id] = val
|
||||
existing = self.SymbolTable.lookup(Node.target.id)
|
||||
if not (existing and existing.IsTypedef and existing.OriginalType):
|
||||
sym_info: _CTypeInfo = _CTypeInfo()
|
||||
sym_info.IsDefine = True
|
||||
sym_info.DefineValue = val
|
||||
self.SymbolTable.insert(Node.target.id, sym_info)
|
||||
elif isinstance(Node, ast.Assign):
|
||||
for target in Node.targets:
|
||||
if isinstance(target, ast.Name):
|
||||
TypeInfo: CTypeInfo | None = None
|
||||
if Node.type_comment:
|
||||
try:
|
||||
tc_ast: ast.Expression = ast.parse(Node.type_comment, mode='eval')
|
||||
TypeInfo = self.TypeMergeHandler.GetCTypeInfo(tc_ast.body)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"解析类型注释失败: {_e}", "Exception")
|
||||
if TypeInfo and TypeInfo.BaseType and ((isinstance(TypeInfo.BaseType, type) and issubclass(TypeInfo.BaseType, t.CDefine)) or isinstance(TypeInfo.BaseType, t.CDefine)):
|
||||
val: int | str | float | None = None
|
||||
if isinstance(Node.value, ast.Constant):
|
||||
val = Node.value.value
|
||||
else:
|
||||
val = _extract_call_const_val(Node.value)
|
||||
if val is not None:
|
||||
if not hasattr(Gen, '_define_constants'):
|
||||
Gen._define_constants: dict[str, int | str | float | bool] = {}
|
||||
Gen._define_constants[target.id] = val
|
||||
sym_info: _CTypeInfo = _CTypeInfo()
|
||||
sym_info.IsDefine = True
|
||||
sym_info.DefineValue = val
|
||||
self.SymbolTable.insert(target.id, sym_info)
|
||||
|
||||
# 预扫描所有顶层函数定义,填充 FunctionDefCache(不创建 LLVM 声明)
|
||||
# 这样类方法编译时遇到未声明的函数可以按需前向声明
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
if isinstance(Node, ast.FunctionDef):
|
||||
FuncName: str = Node.name
|
||||
if FuncName not in self.FunctionDefCache:
|
||||
self.FunctionDefCache[FuncName] = Node
|
||||
|
||||
# 首先处理所有导入语句,确保模块在类型解析前被加载
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
Gen._set_node_info(Node)
|
||||
try:
|
||||
if isinstance(Node, ast.Import):
|
||||
self.ImportHandler._EmitImportDeclarationsLlvm(Node, Gen)
|
||||
elif isinstance(Node, ast.ImportFrom):
|
||||
self.ImportHandler._EmitImportFromDeclarationsLlvm(Node, Gen)
|
||||
except Exception as e:
|
||||
lineno: int = getattr(Node, 'lineno', 0)
|
||||
source_line: str | None = Gen._get_source_line(lineno)
|
||||
src_file: str = getattr(Gen, '_current_source_file', '')
|
||||
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._ErrorStack.append((type(e).__name__, str(e), line_info))
|
||||
|
||||
# 前向声明所有顶层函数,确保全局变量初始化时能引用函数指针
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
if isinstance(Node, ast.FunctionDef):
|
||||
Gen._set_node_info(Node)
|
||||
self.FunctionHandler._EmitFunctionForwardDeclLlvm(Node, Gen)
|
||||
|
||||
# 预创建全局变量(带初始化器),确保类方法编译时能引用全局数组等
|
||||
Gen._current_tree: ast.Module = Tree
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
Gen._set_node_info(Node)
|
||||
if isinstance(Node, ast.AnnAssign):
|
||||
self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen)
|
||||
elif isinstance(Node, ast.Assign):
|
||||
self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen)
|
||||
|
||||
# 首先处理所有类定义(包括 CUnion),确保类型定义在使用前完成
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
if isinstance(Node, ast.ClassDef):
|
||||
Gen._set_node_info(Node)
|
||||
self.ClassHandler._EmitClassLlvm(Node, Gen)
|
||||
|
||||
Gen._generate_structs()
|
||||
Gen._create_Vtable_globals()
|
||||
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
Gen._set_node_info(Node)
|
||||
try:
|
||||
if isinstance(Node, ast.Import):
|
||||
continue
|
||||
elif isinstance(Node, ast.ImportFrom):
|
||||
continue
|
||||
elif isinstance(Node, ast.ClassDef):
|
||||
continue
|
||||
elif isinstance(Node, ast.FunctionDef):
|
||||
self.FunctionHandler._EmitFunctionLlvm(Node, Gen)
|
||||
elif isinstance(Node, ast.AnnAssign):
|
||||
self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen)
|
||||
elif isinstance(Node, ast.Assign):
|
||||
self.AssignHandler._EmitGlobalAssignLlvm(Node, Gen)
|
||||
elif isinstance(Node, ast.If):
|
||||
pass
|
||||
elif isinstance(Node, ast.Expr):
|
||||
self._HandleModuleLevelExprLlvm(Node, Gen)
|
||||
except Exception as e:
|
||||
lineno: int = getattr(Node, 'lineno', 0)
|
||||
source_line: str | None = Gen._get_source_line(lineno)
|
||||
src_file: str = getattr(Gen, '_current_source_file', '')
|
||||
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._ErrorStack.append((type(e).__name__, str(e), line_info))
|
||||
raise
|
||||
Gen._set_Vtable_initializers()
|
||||
# 执行 DecoratorPass:为带自定义装饰器的函数生成 wrapper
|
||||
_run_decorator_pass(Gen)
|
||||
ir_code: str = Gen.finalize()
|
||||
return ir_code
|
||||
|
||||
def _HandleModuleLevelExprLlvm(self, Node: ast.Expr, Gen: LlvmCodeGenerator) -> None:
|
||||
if not isinstance(Node.value, ast.Call):
|
||||
return
|
||||
call: ast.Call = Node.value
|
||||
if not isinstance(call.func, ast.Attribute):
|
||||
return
|
||||
if not isinstance(call.func.value, ast.Name) or call.func.value.id != 'c':
|
||||
return
|
||||
func_name: str = call.func.attr
|
||||
if func_name == 'LLVMIR':
|
||||
self._HandleModuleLevelLLVMIR(call, Gen)
|
||||
|
||||
def _HandleModuleLevelLLVMIR(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> None:
|
||||
if not Node.args:
|
||||
return
|
||||
first_arg: ast.expr = Node.args[0]
|
||||
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
|
||||
ir_text: str = first_arg.value
|
||||
elif isinstance(first_arg, ast.JoinedStr):
|
||||
parts: list[str] = []
|
||||
for value in first_arg.values:
|
||||
if isinstance(value, ast.Constant) and isinstance(value.value, str):
|
||||
parts.append(value.value)
|
||||
elif isinstance(value, ast.FormattedValue):
|
||||
parts.append('')
|
||||
ir_text = ''.join(parts)
|
||||
else:
|
||||
return
|
||||
self._InsertModuleLevelLLVMIR(Gen, ir_text)
|
||||
|
||||
def _InsertModuleLevelLLVMIR(self, Gen: LlvmCodeGenerator, ir_text: str) -> None:
|
||||
for line in ir_text.strip().split('\n'):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
module_flags_match: re.Match[str] | None = re.match(r'!llvm\.module\.flags\s*=\s*!\{(!\d+)\}', line)
|
||||
if module_flags_match:
|
||||
ref: str = module_flags_match.group(1)
|
||||
if not hasattr(Gen, '_pending_module_flags'):
|
||||
Gen._pending_module_flags: list = []
|
||||
Gen._pending_module_flags_refs: str = ref
|
||||
continue
|
||||
metadata_match: re.Match[str] | None = re.match(r'(!\d+)\s*=\s*!\{(.+)\}', line)
|
||||
if metadata_match:
|
||||
md_id: str = metadata_match.group(1)
|
||||
md_body: str = metadata_match.group(2)
|
||||
fields: list[ir.Constant | ir.MetaDataString | str] = []
|
||||
for field_str in re.split(r',\s*', md_body):
|
||||
field_str = field_str.strip()
|
||||
if not field_str:
|
||||
continue
|
||||
int_m: re.Match[str] | None = re.match(r'^i32\s+(\d+)$', field_str)
|
||||
if int_m:
|
||||
fields.append(ir.Constant(ir.IntType(32), int(int_m.group(1))))
|
||||
continue
|
||||
str_m: re.Match[str] | None = re.match(r'^"([^"]*)"$', field_str)
|
||||
if str_m:
|
||||
fields.append(ir.MetaDataString(Gen.module, str_m.group(1)))
|
||||
continue
|
||||
mdstr_m: re.Match[str] | None = re.match(r'^!"([^"]*)"$', field_str)
|
||||
if mdstr_m:
|
||||
fields.append(ir.MetaDataString(Gen.module, mdstr_m.group(1)))
|
||||
continue
|
||||
int_m2: re.Match[str] | None = re.match(r'^(\d+)$', field_str)
|
||||
if int_m2:
|
||||
fields.append(ir.Constant(ir.IntType(32), int(int_m2.group(1))))
|
||||
continue
|
||||
ref_m: re.Match[str] | None = re.match(r'^(!\d+)$', field_str)
|
||||
if ref_m:
|
||||
fields.append(ref_m.group(1))
|
||||
continue
|
||||
if fields:
|
||||
if not hasattr(Gen, '_pending_metadata'):
|
||||
Gen._pending_metadata: list[tuple[str, list]] = []
|
||||
Gen._pending_metadata.append((md_id, fields))
|
||||
continue
|
||||
self._FlushModuleMetadata(Gen)
|
||||
|
||||
def _FlushModuleMetadata(self, Gen: LlvmCodeGenerator) -> None:
|
||||
if not hasattr(Gen, '_pending_metadata') or not Gen._pending_metadata:
|
||||
return
|
||||
md_map: dict[str, ir.MetaDataString] = {}
|
||||
for md_id, fields in Gen._pending_metadata:
|
||||
resolved: list[ir.Constant | ir.MetaDataString] = []
|
||||
for f in fields:
|
||||
if isinstance(f, str) and f.startswith('!'):
|
||||
ref: ir.MetaDataString | None = md_map.get(f)
|
||||
if ref:
|
||||
resolved.append(ref)
|
||||
else:
|
||||
resolved.append(f)
|
||||
md_value: ir.MetaDataString = Gen.module.add_metadata(resolved)
|
||||
md_map[md_id] = md_value
|
||||
if hasattr(Gen, '_pending_module_flags_refs'):
|
||||
ref: str = Gen._pending_module_flags_refs
|
||||
md_node: ir.MetaDataString | None = md_map.get(ref)
|
||||
if md_node:
|
||||
Gen.module.add_named_metadata('llvm.module.flags', md_node)
|
||||
Gen._pending_metadata = []
|
||||
Gen._pending_module_flags_refs = None
|
||||
|
||||
def GenerateCCode(self, Tree: ast.Module, target: str = 'llvm') -> str:
|
||||
"""生成代码
|
||||
|
||||
Args:
|
||||
Tree: Python AST 树
|
||||
target: 目标代码类型,仅支持 'llvm'
|
||||
|
||||
Returns:
|
||||
生成的代码字符串
|
||||
"""
|
||||
self._generated_vars: set[str] = set()
|
||||
self.VarScopes = [{}] # 全局作用域
|
||||
|
||||
# 预扫描 import 语句,注册别名,确保类型解析时能正确解析模块别名
|
||||
if not getattr(self, '_ImportedModules', None):
|
||||
self._ImportedModules: set[str] = set()
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
if isinstance(Node, ast.Import):
|
||||
for alias in Node.names:
|
||||
name: str = alias.name
|
||||
if name in ('c', 't'):
|
||||
continue
|
||||
self._ImportedModules.add(name)
|
||||
if alias.asname:
|
||||
self.SymbolTable.import_aliases[alias.asname] = name
|
||||
elif isinstance(Node, ast.ImportFrom):
|
||||
module_name: str | None = Node.module
|
||||
if module_name and module_name not in ('c', 't'):
|
||||
self._ImportedModules.add(module_name)
|
||||
for alias in Node.names:
|
||||
if alias.asname:
|
||||
self.SymbolTable.import_aliases[alias.asname] = f"{module_name}.{alias.name}"
|
||||
|
||||
for Node in ast.iter_child_nodes(Tree):
|
||||
if isinstance(Node, ast.ClassDef):
|
||||
ClassName: str = Node.name
|
||||
|
||||
# 检查是否是特殊类型(枚举或联合体)
|
||||
IsSpecialType: bool = False
|
||||
if Node.bases:
|
||||
for base in Node.bases:
|
||||
if hasattr(base, 'attr'):
|
||||
if base.attr in ['CEnum', 'Enum', 'CUnion', 'REnum']:
|
||||
IsSpecialType = True
|
||||
break
|
||||
elif hasattr(base, 'id'):
|
||||
if base.id in ['CEnum', 'Enum', 'CUnion', 'REnum']:
|
||||
IsSpecialType = True
|
||||
break
|
||||
|
||||
# 如果是特殊类型,跳过这里的处理(由 HandleClassDef 处理)
|
||||
if IsSpecialType:
|
||||
continue
|
||||
|
||||
members: dict[str, CTypeInfo] = {}
|
||||
IsTypedef: bool = False
|
||||
TypedefName: str | None = None
|
||||
|
||||
if hasattr(Node, 'annotation') and Node.annotation:
|
||||
try:
|
||||
if AnnotationContainsName(Node.annotation, 'CTypedef'):
|
||||
IsTypedef = True
|
||||
if isinstance(Node.annotation, ast.Call):
|
||||
if Node.annotation.args:
|
||||
if isinstance(Node.annotation.args[0], ast.Constant):
|
||||
TypedefName = Node.annotation.args[0].value
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"解析 typedef 注解失败: {_e}", "Exception")
|
||||
|
||||
if not IsTypedef:
|
||||
for item in Node.body:
|
||||
if isinstance(item, ast.Assign):
|
||||
for target in item.targets:
|
||||
if isinstance(target, ast.Name) and target.id == '__annotations__':
|
||||
if isinstance(item.value, ast.Dict):
|
||||
for key, value in zip(item.value.keys, item.value.values):
|
||||
if isinstance(key, ast.Constant) and key.value == '__type__':
|
||||
if AnnotationContainsName(value, 'CTypedef'):
|
||||
IsTypedef = True
|
||||
|
||||
if IsTypedef:
|
||||
TypedefKey: str = TypedefName if TypedefName else ClassName
|
||||
TypedefNode: CTypeInfo = CTypeInfo()
|
||||
TypedefNode.Name = TypedefKey
|
||||
TypedefNode.IsTypedef = True
|
||||
TypedefNode.OriginalType = f'struct {ClassName}'
|
||||
TypedefNode.set('IsComplete', True)
|
||||
TypedefNode.file = '<stdin>'
|
||||
self.SymbolTable.insert(TypedefKey, TypedefNode)
|
||||
|
||||
for item in Node.body:
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
VarName: str = item.target.id
|
||||
try:
|
||||
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(item.annotation)
|
||||
if TypeInfo is None:
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = t.CInt()
|
||||
IsPtr: bool = TypeInfo.IsPtr
|
||||
if not IsPtr:
|
||||
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
|
||||
if AnnotationContainsName(item.annotation, 'CPtr'):
|
||||
IsPtr = True
|
||||
dims: list[int] = []
|
||||
if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant):
|
||||
if isinstance(item.annotation.value, ast.Name):
|
||||
if IsTModule(item.annotation.value.id, self.SymbolTable):
|
||||
if hasattr(item.annotation, 'slice'):
|
||||
try:
|
||||
dims.append(int(item.annotation.slice.value))
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.LogWarning(f"异常被忽略: {_e}")
|
||||
MemberInfo: CTypeInfo = TypeInfo.Copy()
|
||||
if dims:
|
||||
MemberInfo.ArrayDims = [str(d) for d in dims]
|
||||
members[VarName] = MemberInfo
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.LogWarning(f"异常被忽略: {_e}")
|
||||
|
||||
if not IsTypedef:
|
||||
StructNode: CTypeInfo = CTypeInfo()
|
||||
StructNode.Name = ClassName
|
||||
StructNode.IsStruct = True
|
||||
StructNode.Members = members or {}
|
||||
StructNode.file = '<stdin>'
|
||||
existing: CTypeInfo | None = self.SymbolTable.lookup(ClassName)
|
||||
if existing:
|
||||
if hasattr(existing, 'IsCpythonObject') and existing.IsCpythonObject:
|
||||
StructNode.IsCpythonObject = True
|
||||
self.SymbolTable.insert(ClassName, StructNode)
|
||||
elif isinstance(Node, ast.FunctionDef):
|
||||
FuncName: str = Node.name
|
||||
if not self.SymbolTable.has(FuncName):
|
||||
FuncNode: CTypeInfo = CTypeInfo()
|
||||
FuncNode.Name = FuncName
|
||||
FuncNode.IsFunction = True
|
||||
FuncNode.file = '<stdin>'
|
||||
self.SymbolTable.insert(FuncName, FuncNode)
|
||||
elif isinstance(Node, ast.AnnAssign):
|
||||
if isinstance(Node.target, ast.Name):
|
||||
VarName: str = Node.target.id
|
||||
|
||||
VarType: str = 'unknown'
|
||||
IsPtr: bool = False
|
||||
IsTypedef_assignment: bool = False
|
||||
|
||||
if Node.annotation:
|
||||
try:
|
||||
if AnnotationContainsName(Node.annotation, 'CTypedef'):
|
||||
IsTypedef_assignment = True
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.LogWarning(f"异常被忽略: {_e}")
|
||||
|
||||
if IsTypedef_assignment and Node.value:
|
||||
if isinstance(Node.value, ast.Name):
|
||||
OriginalType: str = Node.value.id
|
||||
if OriginalType in self.GeneratedTypes:
|
||||
OriginalInfo: CTypeInfo | None = self.SymbolTable.lookup(OriginalType)
|
||||
if OriginalInfo:
|
||||
if isinstance(OriginalInfo, dict):
|
||||
actual_type: str = OriginalInfo.get('type', 'struct')
|
||||
elif isinstance(OriginalInfo, CTypeInfo):
|
||||
if OriginalInfo.IsEnum:
|
||||
actual_type = 'enum'
|
||||
elif OriginalInfo.IsTypedef:
|
||||
actual_type = 'typedef'
|
||||
elif OriginalInfo.IsStruct:
|
||||
actual_type = 'struct'
|
||||
else:
|
||||
actual_type = 'struct'
|
||||
else:
|
||||
actual_type = 'struct'
|
||||
if actual_type == 'enum':
|
||||
TypedefNode: CTypeInfo = CTypeInfo()
|
||||
TypedefNode.Name = VarName
|
||||
TypedefNode.IsTypedef = True
|
||||
TypedefNode.OriginalType = f'enum {OriginalType}'
|
||||
TypedefNode.file = '<stdin>'
|
||||
self.SymbolTable.insert(VarName, TypedefNode)
|
||||
elif actual_type == 'typedef':
|
||||
TypedefNode = CTypeInfo()
|
||||
TypedefNode.Name = VarName
|
||||
TypedefNode.IsTypedef = True
|
||||
if isinstance(OriginalInfo, dict):
|
||||
TypedefNode.OriginalType = OriginalInfo.get('OriginalType', f'struct {OriginalType}')
|
||||
elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType:
|
||||
TypedefNode.OriginalType = OriginalInfo.OriginalType
|
||||
else:
|
||||
TypedefNode.OriginalType = f'struct {OriginalType}'
|
||||
TypedefNode.file = '<stdin>'
|
||||
self.SymbolTable.insert(VarName, TypedefNode)
|
||||
else:
|
||||
TypedefNode = CTypeInfo()
|
||||
TypedefNode.Name = VarName
|
||||
TypedefNode.IsTypedef = True
|
||||
TypedefNode.OriginalType = f'struct {OriginalType}'
|
||||
TypedefNode.file = '<stdin>'
|
||||
self.SymbolTable.insert(VarName, TypedefNode)
|
||||
self.GeneratedTypes.add(VarName)
|
||||
continue
|
||||
else:
|
||||
OriginalInfo: CTypeInfo | None = self.SymbolTable.lookup(OriginalType)
|
||||
if OriginalInfo:
|
||||
if isinstance(OriginalInfo, dict):
|
||||
actual_type: str = OriginalInfo.get('type', 'struct')
|
||||
elif isinstance(OriginalInfo, CTypeInfo):
|
||||
if OriginalInfo.IsEnum:
|
||||
actual_type = 'enum'
|
||||
elif OriginalInfo.IsTypedef:
|
||||
actual_type = 'typedef'
|
||||
elif OriginalInfo.IsStruct:
|
||||
actual_type = 'struct'
|
||||
else:
|
||||
actual_type = 'struct'
|
||||
else:
|
||||
actual_type = 'struct'
|
||||
if actual_type == 'typedef':
|
||||
TypedefNode: CTypeInfo = CTypeInfo()
|
||||
TypedefNode.Name = VarName
|
||||
TypedefNode.IsTypedef = True
|
||||
if isinstance(OriginalInfo, dict):
|
||||
TypedefNode.OriginalType = OriginalInfo.get('OriginalType', f'struct {OriginalType}')
|
||||
elif isinstance(OriginalInfo, CTypeInfo) and OriginalInfo.OriginalType:
|
||||
TypedefNode.OriginalType = OriginalInfo.OriginalType
|
||||
else:
|
||||
TypedefNode.OriginalType = f'struct {OriginalType}'
|
||||
TypedefNode.file = '<stdin>'
|
||||
self.SymbolTable.insert(VarName, TypedefNode)
|
||||
self.GeneratedTypes.add(VarName)
|
||||
if isinstance(OriginalInfo, dict):
|
||||
OriginalInfo['skip_generation'] = True
|
||||
continue
|
||||
elif actual_type == 'struct':
|
||||
TypedefNode = CTypeInfo()
|
||||
TypedefNode.Name = VarName
|
||||
TypedefNode.IsTypedef = True
|
||||
TypedefNode.OriginalType = f'struct {OriginalType}'
|
||||
TypedefNode.file = '<stdin>'
|
||||
self.SymbolTable.insert(VarName, TypedefNode)
|
||||
self.GeneratedTypes.add(VarName)
|
||||
if isinstance(OriginalInfo, dict):
|
||||
OriginalInfo['skip_generation'] = True
|
||||
continue
|
||||
elif actual_type == 'enum':
|
||||
TypedefNode = CTypeInfo()
|
||||
TypedefNode.Name = VarName
|
||||
TypedefNode.IsTypedef = True
|
||||
TypedefNode.OriginalType = f'enum {OriginalType}'
|
||||
TypedefNode.file = '<stdin>'
|
||||
self.SymbolTable.insert(VarName, TypedefNode)
|
||||
self.GeneratedTypes.add(VarName)
|
||||
if isinstance(OriginalInfo, dict):
|
||||
OriginalInfo['skip_generation'] = True
|
||||
continue
|
||||
elif isinstance(Node.value, ast.Attribute):
|
||||
CName: str | None = CTypeHelper.GetCName(Node.value.attr)
|
||||
if CName:
|
||||
TypedefNode: CTypeInfo = CTypeInfo()
|
||||
TypedefNode.Name = VarName
|
||||
TypedefNode.IsTypedef = True
|
||||
TypedefNode.OriginalType = CName
|
||||
TypedefNode.file = '<stdin>'
|
||||
self.SymbolTable.insert(VarName, TypedefNode)
|
||||
self.GeneratedTypes.add(VarName)
|
||||
continue
|
||||
|
||||
if Node.annotation:
|
||||
try:
|
||||
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(Node.annotation)
|
||||
IsPtr = TypeInfo.IsPtr if TypeInfo else False
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
self.LogWarning(f"异常被忽略: {_e}")
|
||||
# 如果符号已经存在且是 typedef,不要覆盖它
|
||||
existing = self.SymbolTable.lookup(VarName)
|
||||
if existing and existing.IsTypedef and existing.OriginalType:
|
||||
# typedef 已正确插入,保持现有条目不覆盖
|
||||
pass
|
||||
else:
|
||||
var_node: CTypeInfo = CTypeInfo()
|
||||
var_node.Name = VarName
|
||||
var_node.IsVariable = True
|
||||
var_node.PtrCount = 1 if IsPtr else 0
|
||||
var_node.file = '<stdin>'
|
||||
self.SymbolTable.insert(VarName, var_node)
|
||||
|
||||
self.LlvmGen: LlvmCodeGenerator = LlvmCodeGenerator(
|
||||
triple=getattr(self, 'triple', None),
|
||||
datalayout=getattr(self, 'datalayout', None),
|
||||
)
|
||||
self.LlvmGen._Trans = self
|
||||
self.LlvmGen._import_handler_ref = self.ImportHandler
|
||||
if hasattr(self, '_module_sha1'):
|
||||
self.LlvmGen.module_sha1 = self._module_sha1
|
||||
if hasattr(self, '_ModuleSha1Map'):
|
||||
self.LlvmGen.ModuleSha1Map = self._ModuleSha1Map
|
||||
if hasattr(self, '_struct_sha1_map'):
|
||||
self.LlvmGen._struct_sha1_map = self._struct_sha1_map
|
||||
if hasattr(self, '_temp_dir'):
|
||||
self.LlvmGen._temp_dir = self._temp_dir
|
||||
if hasattr(self, '_export_extern_funcs'):
|
||||
self.LlvmGen._export_extern_funcs = self._export_extern_funcs
|
||||
self.LlvmGen.setup_from_symbol_table(self.SymbolTable)
|
||||
if hasattr(self, 'CurrentFile') and self.CurrentFile:
|
||||
self.LlvmGen._set_source_info(self.CurrentFile)
|
||||
|
||||
# --- 修复:共享 vtable 状态跨模块 ---
|
||||
# 根因:LlvmGen 每模块重新创建,class_vtable/class_methods 等是实例级属性,
|
||||
# 不跨模块共享。导致模块 B 编译时 _specialize_generic_class 触发的
|
||||
# pool.alloc(48) 找不到 MemManager 的虚表状态,直接调用 stub 返回 NULL → 段错误。
|
||||
# 修复:将 vtable 状态存储在 Translator 对象上并赋值给每个新 Gen。
|
||||
if not hasattr(self, '_shared_class_vtable'):
|
||||
self._shared_class_vtable: set[str] = set()
|
||||
self._shared_cross_module_vtable: set[str] = set()
|
||||
self._shared_class_methods: dict[str, list[str]] = {}
|
||||
self._shared_cross_module_novtable: set[str] = set()
|
||||
# 合并 setup_from_symbol_table 创建的实例级 class_methods 到共享 dict
|
||||
# (仅添加新类,不覆盖已有方法列表)
|
||||
for _cls_name, _methods in self.LlvmGen.class_methods.items():
|
||||
if _cls_name not in self._shared_class_methods:
|
||||
self._shared_class_methods[_cls_name] = _methods
|
||||
else:
|
||||
for _m in _methods:
|
||||
if _m not in self._shared_class_methods[_cls_name]:
|
||||
self._shared_class_methods[_cls_name].append(_m)
|
||||
# 替换为共享状态
|
||||
self.LlvmGen.class_vtable = self._shared_class_vtable
|
||||
self.LlvmGen._cross_module_vtable_classes = self._shared_cross_module_vtable
|
||||
self.LlvmGen.class_methods = self._shared_class_methods
|
||||
self.LlvmGen._cross_module_novtable = self._shared_cross_module_novtable
|
||||
# --- 修复结束 ---
|
||||
|
||||
return self.GenerateLlvmDirect(Tree)
|
||||
452
lib/core/Translator/PythonParser.py
Normal file
452
lib/core/Translator/PythonParser.py
Normal file
@@ -0,0 +1,452 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import json
|
||||
import struct
|
||||
|
||||
from lib.utils.helpers import DetectFileType
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
from lib.core.SymbolUtils import IsTModule, AnnotationContainsName
|
||||
from lib.includes import t
|
||||
from lib.constants.config import mode as _ConfigMode
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
|
||||
class PythonParserMixin:
|
||||
"""Python 文件解析 Mixin
|
||||
|
||||
提供辅助文件解析、symbin 文件加载与 Python 源文件解析能力。
|
||||
"""
|
||||
|
||||
def ParseHelperFiles(self, HelperFiles: list[str], encoding: str = 'utf-8') -> None:
|
||||
"""解析辅助文件,提取符号信息
|
||||
|
||||
支持 .py, .c, .h 和 .symbin 文件
|
||||
"""
|
||||
for FilePath in HelperFiles:
|
||||
ext: str = DetectFileType(FilePath)
|
||||
if ext == '.py':
|
||||
self.ParsePythonFile(FilePath, encoding, UpdateCurrentFile=False)
|
||||
elif ext == '.c':
|
||||
pass # .c 文件解析已移除,不再使用旧的正则解析路径
|
||||
elif FilePath.endswith('.symbin'):
|
||||
self.LoadSymbinFile(FilePath)
|
||||
|
||||
def LoadSymbinFile(self, FilePath: str) -> None:
|
||||
"""从.symbin文件加载符号表
|
||||
|
||||
Args:
|
||||
FilePath: .symbin文件路径
|
||||
"""
|
||||
try:
|
||||
with open(FilePath, 'rb') as f:
|
||||
data: bytes = f.read()
|
||||
|
||||
# 导入序列化函数(避免循环导入)
|
||||
# 解析二进制格式
|
||||
if len(data) < 4:
|
||||
_vlog().warning(f"无效的 symbin 文件 (太短): {FilePath}")
|
||||
return
|
||||
|
||||
# 解析4字节长度头(小端序)
|
||||
length: int = struct.unpack('<I', data[:4])[0]
|
||||
JsonData: bytes = data[4:4+length]
|
||||
symbols: dict = json.loads(JsonData.decode('utf-8'))
|
||||
|
||||
# 合并到当前符号表
|
||||
self.SymbolTable.update(symbols)
|
||||
self.DebugPrint(f"[SYMBIN] Loaded {len(symbols)} symbols from {FilePath}")
|
||||
|
||||
except Exception as e:
|
||||
_vlog().warning(f"加载 symbin 文件失败 {FilePath}: {e}")
|
||||
|
||||
def ParsePythonFile(self, FilePath: str, encoding: str = 'utf-8', UpdateCurrentFile: bool = True) -> None:
|
||||
"""解析Python文件,提取类、函数、变量信息
|
||||
|
||||
Args:
|
||||
FilePath: 要解析的文件路径
|
||||
encoding: 文件编码
|
||||
UpdateCurrentFile: 是否更新 CurrentFile(默认为 True,处理导入时设为 False)
|
||||
"""
|
||||
try:
|
||||
with open(FilePath, 'r', encoding=encoding) as f:
|
||||
content: str = f.read()
|
||||
|
||||
# 保存当前处理的文件路径(仅在主文件处理时更新)
|
||||
if UpdateCurrentFile:
|
||||
self.CurrentFile = FilePath
|
||||
|
||||
# 解析Python代码为AST
|
||||
tree: ast.Module = ast.parse(content)
|
||||
|
||||
# 保存 AST 树供后续使用
|
||||
self.tree = tree
|
||||
|
||||
# 第一遍:检测特殊赋值语句,收集跟在 class 后面的
|
||||
# 遍历 tree.body,找到所有 ClassDef,然后收集紧随其后的赋值语句
|
||||
i: int = 0
|
||||
while i < len(tree.body):
|
||||
node: ast.stmt = tree.body[i]
|
||||
|
||||
# 检测 ClassDef
|
||||
if isinstance(node, ast.ClassDef):
|
||||
ClassName: str = node.name
|
||||
# 使用类名_行号作为唯一 key
|
||||
ClassKey: str = f"{ClassName}_{node.lineno}"
|
||||
|
||||
# 检查后面的语句,收集特殊赋值
|
||||
j: int = i + 1
|
||||
while j < len(tree.body):
|
||||
NextNode: ast.stmt = tree.body[j]
|
||||
|
||||
if isinstance(NextNode, ast.Assign):
|
||||
# 检测 xxx = xxx 或 xxx = yyy
|
||||
if len(NextNode.targets) == 1 and isinstance(NextNode.targets[0], ast.Name):
|
||||
TargetName: str = NextNode.targets[0].id
|
||||
if isinstance(NextNode.value, ast.Name):
|
||||
ValueName: str = NextNode.value.id
|
||||
if ValueName == ClassName:
|
||||
# 这是 class 的实例化
|
||||
if ClassKey not in self.EmbeddedAssignments:
|
||||
self.EmbeddedAssignments[ClassKey] = []
|
||||
self.EmbeddedAssignments[ClassKey].append(TargetName)
|
||||
j += 1
|
||||
continue
|
||||
elif isinstance(NextNode, ast.AnnAssign):
|
||||
# 检测 xxx: t.Postdefinition(yyy) 或 xxx: t.CTypedef = xxx 或 xxx: t.CPtr = xxx
|
||||
if isinstance(NextNode.target, ast.Name):
|
||||
TargetName: str = NextNode.target.id
|
||||
# 先处理新格式:t.Postdefinition(...)
|
||||
annotation: ast.expr | None = NextNode.annotation
|
||||
PostdefNode: ast.Call | None = None
|
||||
|
||||
# 递归搜索整个注解树,找到 t.Postdefinition(...) 调用
|
||||
def find_PostdefNode(node: ast.AST) -> ast.Call | None:
|
||||
if isinstance(node, ast.Call):
|
||||
if isinstance(node.func, ast.Attribute):
|
||||
if hasattr(node.func.value, 'id') and IsTModule(node.func.value.id, self.SymbolTable) and node.func.attr == 'Postdefinition':
|
||||
return node
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
LeftResult: ast.Call | None = find_PostdefNode(node.left)
|
||||
if LeftResult:
|
||||
return LeftResult
|
||||
RightResult: ast.Call | None = find_PostdefNode(node.right)
|
||||
if RightResult:
|
||||
return RightResult
|
||||
return None
|
||||
|
||||
PostdefNode = find_PostdefNode(annotation)
|
||||
# 检查是否找到 t.Postdefinition(...) 调用
|
||||
if PostdefNode:
|
||||
if (isinstance(PostdefNode.func, ast.Attribute) and
|
||||
hasattr(PostdefNode.func, 'value') and
|
||||
hasattr(PostdefNode.func.value, 'id') and
|
||||
IsTModule(PostdefNode.func.value.id, self.SymbolTable) and
|
||||
PostdefNode.func.attr == 'Postdefinition' and
|
||||
PostdefNode.args):
|
||||
# 检查第一个参数是否是当前类名
|
||||
arg: ast.expr = PostdefNode.args[0]
|
||||
if isinstance(arg, ast.Name) and arg.id == ClassName:
|
||||
# 检查是否包含 CTypedef 或 CPtr
|
||||
HasCtypedef: bool = AnnotationContainsName(NextNode.annotation, 'CTypedef')
|
||||
IsPtr: bool = AnnotationContainsName(NextNode.annotation, 'CPtr')
|
||||
|
||||
# 解析维度列表(第二个参数)
|
||||
dimensions: list[ast.expr] = []
|
||||
if len(PostdefNode.args) > 1:
|
||||
# 第二个参数应该是一个列表
|
||||
dim_arg: ast.expr = PostdefNode.args[1]
|
||||
if isinstance(dim_arg, ast.List):
|
||||
for DimExpr in dim_arg.elts:
|
||||
dimensions.append(DimExpr)
|
||||
|
||||
# 如果没有从 Postdefinition 参数中获取维度,尝试从类型注解中的 Subscript 获取
|
||||
# 例如:memory_block_t[MAX_ORDER + 1] | t.CPtr
|
||||
if not dimensions:
|
||||
def extract_subscript_dims(node: ast.AST) -> list[ast.expr]:
|
||||
"""递归提取 Subscript 节点的维度"""
|
||||
dims: list[ast.expr] = []
|
||||
if isinstance(node, ast.Subscript):
|
||||
# 提取当前维度
|
||||
if isinstance(node.slice, ast.Constant):
|
||||
dims.append(ast.Constant(value=node.slice.value))
|
||||
elif isinstance(node.slice, ast.Name):
|
||||
dims.append(ast.Name(id=node.slice.id, ctx=ast.Load()))
|
||||
elif isinstance(node.slice, ast.BinOp):
|
||||
dims.append(node.slice)
|
||||
# 递归提取更外层的维度
|
||||
dims.extend(extract_subscript_dims(node.value))
|
||||
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
|
||||
# 处理 Type | t.CPtr 的情况,检查左侧
|
||||
dims.extend(extract_subscript_dims(node.left))
|
||||
return dims
|
||||
|
||||
# 从注解中提取维度
|
||||
subscript_dims: list[ast.expr] = extract_subscript_dims(annotation)
|
||||
if subscript_dims:
|
||||
# 反转维度顺序(从内到外)
|
||||
dimensions = list(reversed(subscript_dims))
|
||||
|
||||
# 获取赋值值
|
||||
value: ast.expr | None = None
|
||||
if hasattr(NextNode, 'value') and NextNode.value is not None:
|
||||
value = NextNode.value
|
||||
|
||||
# 添加到对应的 assignments
|
||||
# 对于 t.Postdefinition(...),只有包含 CTypedef 或 CPtr 时才视为 typedef 类型
|
||||
if HasCtypedef or IsPtr:
|
||||
if ClassKey not in self.TypedefAssignments:
|
||||
self.TypedefAssignments[ClassKey] = []
|
||||
# 如果有维度信息,使用字典存储
|
||||
if dimensions:
|
||||
self.TypedefAssignments[ClassKey].append({
|
||||
'name': TargetName,
|
||||
'IsPtr': IsPtr,
|
||||
'dimensions': dimensions,
|
||||
'value': value
|
||||
})
|
||||
else:
|
||||
self.TypedefAssignments[ClassKey].append((TargetName, IsPtr))
|
||||
else:
|
||||
if ClassKey not in self.EmbeddedAssignments:
|
||||
self.EmbeddedAssignments[ClassKey] = []
|
||||
# 如果有维度信息,使用字典存储
|
||||
if dimensions:
|
||||
self.EmbeddedAssignments[ClassKey].append({
|
||||
'name': TargetName,
|
||||
'dimensions': dimensions,
|
||||
'value': value
|
||||
})
|
||||
else:
|
||||
self.EmbeddedAssignments[ClassKey].append(TargetName)
|
||||
|
||||
# 检查是否有 __set_default__ 初始化
|
||||
if AnnotationContainsName(NextNode.annotation, '__set_default__'):
|
||||
self._handle_set_default_in_parse(ClassKey, TargetName, ClassName, NextNode)
|
||||
j += 1
|
||||
continue
|
||||
# 再处理旧格式:xxx: t.CTypedef = xxx 或 xxx: t.CPtr = xxx
|
||||
# 注意:这种格式的 typedef 不应该被合并到结构体定义中,
|
||||
# 而应该生成独立的 typedef 语句,所以不添加到 TypedefAssignments
|
||||
elif NextNode.annotation and isinstance(NextNode.annotation, ast.Attribute):
|
||||
if isinstance(NextNode.annotation.value, ast.Name):
|
||||
annot_id: str = NextNode.annotation.value.id
|
||||
annot_attr: str = NextNode.annotation.attr
|
||||
if annot_id == 't' and NextNode.value:
|
||||
if isinstance(NextNode.value, ast.Name):
|
||||
ValueName: str = NextNode.value.id
|
||||
if ValueName == ClassName:
|
||||
# 检查是 CTypedef 还是 CPtr
|
||||
if annot_attr == t.CPtr.__name__:
|
||||
# t.CPtr 表示指针变量,加入 TypedefAssignments,设置 IsPtr=True
|
||||
if ClassKey not in self.TypedefAssignments:
|
||||
self.TypedefAssignments[ClassKey] = []
|
||||
self.TypedefAssignments[ClassKey].append((TargetName, True))
|
||||
j += 1
|
||||
continue
|
||||
# 注意:t.CTypedef 不在这里处理,由 HandlesAnnAssign 生成独立的 typedef 语句
|
||||
# 如果不是特殊赋值,停止收集
|
||||
break
|
||||
|
||||
i = j
|
||||
continue
|
||||
|
||||
i += 1
|
||||
|
||||
# 提取类定义(作为结构体)
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.ClassDef):
|
||||
ClassName: str = node.name
|
||||
# 先把类名加入 GeneratedTypes,这样 GetTypeName 可以正确识别
|
||||
self.GeneratedTypes.add(ClassName)
|
||||
|
||||
# 检测是否是 CEnum
|
||||
IsCenum: bool = False
|
||||
for base in node.bases:
|
||||
if isinstance(base, ast.Attribute):
|
||||
if base.attr in ('CEnum', 'REnum'):
|
||||
IsCenum = True
|
||||
break
|
||||
elif isinstance(base, ast.Name):
|
||||
if base.id in ('CEnum', 'REnum'):
|
||||
IsCenum = True
|
||||
break
|
||||
|
||||
# 检测是否有 @t.Object 装饰器或继承自 t.Object
|
||||
IsCpythonObject: 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.SymbolTable) and
|
||||
decorator.attr == 'Object'):
|
||||
IsCpythonObject = True
|
||||
break
|
||||
elif isinstance(decorator, ast.Call):
|
||||
if isinstance(decorator.func, ast.Attribute):
|
||||
if (hasattr(decorator.func.value, 'id') and
|
||||
IsTModule(decorator.func.value.id, self.SymbolTable) and
|
||||
decorator.func.attr == 'Object'):
|
||||
IsCpythonObject = True
|
||||
break
|
||||
elif isinstance(decorator.func, ast.Name):
|
||||
if decorator.func.id == 'Object':
|
||||
IsCpythonObject = True
|
||||
break
|
||||
elif isinstance(decorator, ast.Name):
|
||||
if decorator.id == 'Object':
|
||||
IsCpythonObject = True
|
||||
break
|
||||
if not IsCpythonObject and hasattr(node, 'bases') and node.bases:
|
||||
for base in node.bases:
|
||||
if isinstance(base, ast.Attribute):
|
||||
if (hasattr(base.value, 'id') and
|
||||
IsTModule(base.value.id, self.SymbolTable) and
|
||||
base.attr == 'Object'):
|
||||
IsCpythonObject = True
|
||||
break
|
||||
elif isinstance(base, ast.Name):
|
||||
if base.id == 'Object':
|
||||
IsCpythonObject = True
|
||||
break
|
||||
|
||||
if IsCenum:
|
||||
# 注册为 enum 类型
|
||||
EnumNode: CTypeInfo = CTypeInfo()
|
||||
EnumNode.Name = ClassName
|
||||
EnumNode.IsEnum = True
|
||||
EnumNode.set('file', '<stdin>')
|
||||
self.SymbolTable.insert(ClassName, EnumNode)
|
||||
|
||||
# 注册 enum 成员(提取枚举值,与 SymbolExtractor 逻辑一致)
|
||||
next_enum_value: int = 0
|
||||
for item in node.body:
|
||||
MemberName: str | None = None
|
||||
ItemValue: object | None = None
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
MemberName = item.target.id
|
||||
ItemValue = item.value
|
||||
elif isinstance(item, ast.Assign) and len(item.targets) == 1 and isinstance(item.targets[0], ast.Name):
|
||||
MemberName = item.targets[0].id
|
||||
ItemValue = item.value
|
||||
if MemberName is None:
|
||||
continue
|
||||
MemberNode: CTypeInfo = CTypeInfo()
|
||||
MemberNode.Name = MemberName
|
||||
MemberNode.BaseType = t.CEnum(ClassName)
|
||||
# 提取枚举值:优先用显式赋值,否则自动编号
|
||||
if ItemValue is not None and isinstance(ItemValue, ast.Constant) and isinstance(ItemValue.value, int):
|
||||
MemberNode.value = ItemValue.value
|
||||
next_enum_value = ItemValue.value + 1
|
||||
else:
|
||||
MemberNode.value = next_enum_value
|
||||
next_enum_value += 1
|
||||
MemberNode.EnumName = ClassName
|
||||
MemberNode.library_name = None
|
||||
MemberNode.IsEnumMember = True
|
||||
self.SymbolTable.insert(MemberName, MemberNode)
|
||||
self.SymbolTable.insert(f"{ClassName}.{MemberName}", MemberNode)
|
||||
self.SymbolTable.insert(f"{ClassName}_{MemberName}", MemberNode)
|
||||
|
||||
continue
|
||||
|
||||
# 检测是否是 Anonymous
|
||||
IsAnonymous: bool = False
|
||||
|
||||
# 提取结构体成员信息
|
||||
members: dict[str, CTypeInfo] = {}
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
VarName: str = item.target.id
|
||||
try:
|
||||
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(item.annotation)
|
||||
if TypeInfo is None:
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = t.CInt()
|
||||
IsPtr: bool = TypeInfo.IsPtr
|
||||
if not IsPtr:
|
||||
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
|
||||
if AnnotationContainsName(item.annotation, 'CPtr'):
|
||||
IsPtr = True
|
||||
dims: list[int] = []
|
||||
if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant):
|
||||
if isinstance(item.annotation.value, ast.Name):
|
||||
if IsTModule(item.annotation.value.id, self.SymbolTable):
|
||||
if hasattr(item.annotation, 'slice'):
|
||||
try:
|
||||
dims.append(int(item.annotation.slice.value))
|
||||
except Exception as _e:
|
||||
if _ConfigMode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"解析数组维度失败: {_e}", "Exception")
|
||||
MemberInfo: CTypeInfo = TypeInfo.Copy()
|
||||
if dims:
|
||||
MemberInfo.ArrayDims = [str(d) for d in dims]
|
||||
members[VarName] = MemberInfo
|
||||
except Exception as _e:
|
||||
if _ConfigMode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"解析结构体成员失败: {_e}", "Exception")
|
||||
StructNode: CTypeInfo = CTypeInfo()
|
||||
StructNode.Name = ClassName
|
||||
StructNode.IsStruct = True
|
||||
StructNode.Members = members or {}
|
||||
StructNode.set('file', '<stdin>')
|
||||
StructNode.set('IsAnonymous', IsAnonymous)
|
||||
StructNode.set('IsCpythonObject', IsCpythonObject)
|
||||
self.SymbolTable.insert(ClassName, StructNode)
|
||||
elif isinstance(node, ast.FunctionDef):
|
||||
FuncName: str = node.name
|
||||
if not self.SymbolTable.has(FuncName):
|
||||
FuncNode: CTypeInfo = CTypeInfo()
|
||||
FuncNode.Name = FuncName
|
||||
FuncNode.IsFunction = True
|
||||
FuncNode.set('file', '<stdin>')
|
||||
self.SymbolTable.insert(FuncName, FuncNode)
|
||||
elif isinstance(node, ast.AnnAssign):
|
||||
if isinstance(node.target, ast.Name):
|
||||
VarName: str = node.target.id
|
||||
# 检查是否是 t.CTypedef 格式,如果是则跳过(由 HandleClassDef 处理)
|
||||
is_ctypedef: bool = False
|
||||
if node.annotation:
|
||||
if isinstance(node.annotation, ast.Attribute):
|
||||
if isinstance(node.annotation.value, ast.Name):
|
||||
if IsTModule(node.annotation.value.id, self.SymbolTable) and node.annotation.attr == 'CTypedef':
|
||||
is_ctypedef = True
|
||||
elif isinstance(node.annotation, ast.BinOp) and isinstance(node.annotation.op, ast.BitOr):
|
||||
def _has_ctype(ann: ast.AST) -> bool:
|
||||
if isinstance(ann, ast.Attribute):
|
||||
return hasattr(ann.value, 'id') and IsTModule(ann.value.id) and ann.attr == 'CTypedef'
|
||||
if isinstance(ann, ast.BinOp) and isinstance(ann.op, ast.BitOr):
|
||||
return _has_ctype(ann.left) or _has_ctype(ann.right)
|
||||
if isinstance(ann, ast.Subscript):
|
||||
return _has_ctype(ann.value)
|
||||
return False
|
||||
if _has_ctype(node.annotation):
|
||||
is_ctypedef = True
|
||||
if not is_ctypedef:
|
||||
# 如果符号已经存在且是 typedef,不要覆盖它
|
||||
existing = self.SymbolTable.lookup(VarName)
|
||||
if existing and existing.IsTypedef and existing.OriginalType:
|
||||
pass
|
||||
else:
|
||||
IsPtr: bool = False
|
||||
if node.annotation:
|
||||
try:
|
||||
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(node.annotation)
|
||||
IsPtr = TypeInfo.IsPtr if TypeInfo else False
|
||||
except Exception as _e:
|
||||
if _ConfigMode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"获取类型信息失败(ParsePythonFile): {_e}", "Exception")
|
||||
var_node: CTypeInfo = CTypeInfo()
|
||||
var_node.Name = VarName
|
||||
var_node.IsVariable = True
|
||||
var_node.set('IsPtr', IsPtr)
|
||||
var_node.set('file', '<stdin>')
|
||||
self.SymbolTable.insert(VarName, var_node)
|
||||
except Exception as e:
|
||||
_vlog().warning(f'解析 Python 文件失败 {FilePath}: {e}')
|
||||
|
||||
# ParseCFile 已移除 - .h/.c 文件的旧正则解析路径不再使用
|
||||
# 类型解析现在直接通过 CTypeInfo 对象进行,不经过中间字符串格式
|
||||
11
lib/core/Translator/__init__.py
Normal file
11
lib/core/Translator/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""Translator 包 - 代码转换器模块"""
|
||||
from lib.core.Translator.BaseTranslator import BaseTranslatorMixin, _StrictLog
|
||||
from lib.core.Translator.AnnotationLoader import AnnotationLoaderMixin
|
||||
from lib.core.Translator.PythonParser import PythonParserMixin
|
||||
from lib.core.Translator.LlvmGenerator import LlvmGeneratorMixin
|
||||
from lib.core.Translator.ConstEval import ConstEvalMixin
|
||||
|
||||
__all__ = [
|
||||
'BaseTranslatorMixin', 'AnnotationLoaderMixin', 'PythonParserMixin',
|
||||
'LlvmGeneratorMixin', 'ConstEvalMixin', '_StrictLog'
|
||||
]
|
||||
Reference in New Issue
Block a user