snapshot before regression test

This commit is contained in:
t
2026-07-18 19:25:40 +08:00
commit 796222a300
2295 changed files with 206453 additions and 0 deletions

View 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

View 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)

View 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]

View 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)

View 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 对象进行,不经过中间字符串格式

View 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'
]