修复了大量存在的问题,增加了假鸭子类型等等机制

This commit is contained in:
2026-06-25 14:49:46 +08:00
parent 19f2787db0
commit d88d11b646
827 changed files with 32617 additions and 18316 deletions

View File

@@ -3,9 +3,16 @@ from __future__ import annotations
import ast
import sys
import os
import importlib
import types
from typing import Any
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolUtils import IsTModule
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:
@@ -14,7 +21,7 @@ class AnnotationLoaderMixin:
提供注解模块/文件的加载与符号表注册能力。
"""
def _LoadAnnotationModule(self, ModuleName: str, library_name: str = None, parse_method: str = 'auto'):
def _LoadAnnotationModule(self, ModuleName: str, library_name: str | None = None, parse_method: str = 'auto') -> int:
"""加载注解模块并将 CType 子类注册为 typedef
支持两种模式:
@@ -29,25 +36,20 @@ class AnnotationLoaderMixin:
- 'file': 强制使用 AST 模式(文件路径)
- 'module': 强制使用 importlib 模式(模块名)
"""
import importlib
import sys
import os
CurrentDir = os.path.dirname(os.path.abspath(__file__))
ProjectRoot = os.path.dirname(os.path.dirname(os.path.dirname(CurrentDir)))
CurrentDir: str = os.path.dirname(os.path.abspath(__file__))
ProjectRoot: str = os.path.dirname(os.path.dirname(os.path.dirname(CurrentDir)))
if ProjectRoot not in sys.path:
sys.path.insert(0, ProjectRoot)
def register_to_symboltable(module, lib_name: str = None, source_file: str = None):
def register_to_symboltable(module: types.ModuleType, lib_name: str | None = None, source_file: str | None = None) -> int:
"""将模块中的 CType 子类和 CEnum 类注册到符号表"""
from lib.includes.t import CType, CEnum
count = 0
count: int = 0
for AttrName in dir(module):
attr = getattr(module, AttrName)
attr: type = getattr(module, AttrName)
# 优先检查是否是 CEnum 子类(枚举)
if isinstance(attr, type) and issubclass(attr, CEnum) and attr is not CEnum:
# 注册枚举类型
EnumNode = CTypeInfo()
EnumNode: CTypeInfo = CTypeInfo()
EnumNode.Name = AttrName
EnumNode.BaseType = t.CEnum()
EnumNode.IsEnum = True
@@ -57,8 +59,8 @@ class AnnotationLoaderMixin:
EnumNode.file = source_file
self.SymbolTable.insert(AttrName, EnumNode)
if lib_name:
FullName = f'{lib_name}.{AttrName}'
full_EnumNode = CTypeInfo()
FullName: str = f'{lib_name}.{AttrName}'
full_EnumNode: CTypeInfo = CTypeInfo()
full_EnumNode.Name = FullName
full_EnumNode.IsEnum = True
full_EnumNode.set('enum_class', attr)
@@ -69,9 +71,9 @@ class AnnotationLoaderMixin:
# 枚举成员也需要注册
for MemberName in dir(attr):
if not MemberName.startswith('_'):
member = getattr(attr, MemberName, None)
member: int = getattr(attr, MemberName, None)
if isinstance(member, int):
MemberNode = CTypeInfo()
MemberNode: CTypeInfo = CTypeInfo()
MemberNode.Name = MemberName
MemberNode.BaseType = t.CEnum(AttrName)
MemberNode.value = member
@@ -90,23 +92,23 @@ class AnnotationLoaderMixin:
# 继承 CType 的类是类型别名typedef不是结构体
# 使用手动指定的库名称作为前缀
if lib_name:
FullName = f'{lib_name}.{AttrName}'
FullName: str = f'{lib_name}.{AttrName}'
else:
FullName = AttrName
# 同时注册带前缀和不带前缀的名称(都是 typedef 别名)
TypedefNode = CTypeInfo()
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = AttrName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = attr().CName
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()
FullTypedef_node: CTypeInfo = CTypeInfo()
FullTypedef_node.Name = FullName
FullTypedef_node.IsTypedef = True
FullTypedef_node.OriginalType = attr().CName
FullTypedef_node.OriginalType = attr.__name__
FullTypedef_node.set('source', 'annotation_module')
FullTypedef_node.library_name = lib_name
FullTypedef_node.file = source_file
@@ -114,29 +116,29 @@ class AnnotationLoaderMixin:
count += 1
# 检查是否是下划线前缀的 CType 子类(如 _CTypedef -> CTypedef
elif AttrName.startswith('_') and len(AttrName) > 1:
PublicName = AttrName[1:]
PublicAttr = getattr(module, PublicName, None)
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 = f'{lib_name}.{PublicName}'
FullName: str = f'{lib_name}.{PublicName}'
else:
FullName = PublicName
TypedefNode = CTypeInfo()
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = PublicName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = attr().CName
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()
FullTypedef_node: CTypeInfo = CTypeInfo()
FullTypedef_node.Name = FullName
FullTypedef_node.IsTypedef = True
FullTypedef_node.OriginalType = attr().CName
FullTypedef_node.OriginalType = attr.__name__
FullTypedef_node.set('source', 'annotation_module')
FullTypedef_node.library_name = lib_name
FullTypedef_node.file = source_file
@@ -145,7 +147,7 @@ class AnnotationLoaderMixin:
return count
# 确定解析方法
use_file_mode = False
use_file_mode: bool = False
if parse_method == 'file':
use_file_mode = True
elif parse_method == 'module':
@@ -154,7 +156,7 @@ class AnnotationLoaderMixin:
use_file_mode = os.path.isfile(ModuleName)
# 确定库名称
lib_name = library_name
lib_name: str | None = library_name
if lib_name is None:
if use_file_mode:
# 从文件路径推断库名称
@@ -168,8 +170,8 @@ class AnnotationLoaderMixin:
# AST 模式:使用 AST 解析文件,不执行代码
try:
# 临时保存当前的 EmbeddedAssignments 和 TypedefAssignments
saved_embedded = self.EmbeddedAssignments.copy()
saved_typedef = self.TypedefAssignments.copy()
saved_embedded: dict = self.EmbeddedAssignments.copy()
saved_typedef: dict = self.TypedefAssignments.copy()
# 清空 PD 收集(注解文件不应该收集 PD 语句)
self.EmbeddedAssignments = {}
@@ -185,12 +187,12 @@ class AnnotationLoaderMixin:
self.TypedefAssignments = saved_typedef
# 从文件名推断类型前缀(如 test_t -> test_t.xxx
TypePrefix = lib_name
count = 0
TypePrefix: str = lib_name
count: int = 0
# 检查符号表中新增的类型(注解文件解析后的所有 struct 类型)
# 需要检查这些类型是否继承自 CType如果是则是 typedef 别名
new_types = []
new_types: list[str] = []
for TypeName, TypeInfo in self.SymbolTable.items():
if TypeInfo.IsStruct:
new_types.append(TypeName)
@@ -198,18 +200,18 @@ class AnnotationLoaderMixin:
# 再次遍历 AST检测继承自 CType 的类
try:
with open(ModuleName, 'r', encoding='utf-8') as f:
ann_content = f.read()
ann_tree = ast.parse(ann_content)
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 = node.name
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()
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = ClassName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = self.SymbolTable[ClassName].get('OriginalType', f'struct {ClassName}')
@@ -217,17 +219,15 @@ class AnnotationLoaderMixin:
TypedefNode.set('is_ctype_subclass', True)
self.SymbolTable.insert(ClassName, TypedefNode)
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode
if _ConfigMode == "strict":
if _config_mode == "strict":
raise
_vlog().warning(f"解析注解文件类型定义失败: {_e}", "Exception")
# 为所有新增的类型添加库前缀和 source 标记
for TypeName in new_types:
# 添加带前缀的类型名
FullName = f'{TypePrefix}.{TypeName}'
TypeInfo = self.SymbolTable[TypeName].copy()
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)
@@ -235,23 +235,23 @@ class AnnotationLoaderMixin:
# 再次遍历 AST查找注解文件中的 typedef 语句AnnAssign with t.CTypedef
# 注意:必须在类定义处理完之后再处理 typedef
typedef_annots = []
typedef_annots: list[tuple[str, str]] = []
# 查找 CEnum 成员变量AnnAssign with t.CEnum | t.State 或 t.CEnum
cEnumMembers = []
cEnumMembers: list[tuple[str, int | None]] = []
try:
with open(ModuleName, 'r', encoding='utf-8') as f:
ann_content = f.read()
ann_tree = ast.parse(ann_content)
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 = node.target.id
TargetName: str = node.target.id
# 检查注解是否是 BinOp (Union) 或直接是 Attribute
IsCenum = False
IsCenum: bool = False
if isinstance(node.annotation, ast.BinOp):
# 检查是否包含 CEnum
annot_str = ast.dump(node.annotation)
annot_str: str = ast.dump(node.annotation)
if 'CEnum' in annot_str:
IsCenum = True
elif isinstance(node.annotation, ast.Attribute):
@@ -262,21 +262,19 @@ class AnnotationLoaderMixin:
if IsCenum:
# 检查值是否是 Constant (枚举成员值)
if node.value and isinstance(node.value, ast.Constant):
value = node.value.value
value: int | str | float | None = node.value.value
else:
value = None
cEnumMembers.append((TargetName, value))
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode
if _ConfigMode == "strict":
if _config_mode == "strict":
raise
_vlog().warning(f"解析 CEnum 成员变量失败: {_e}", "Exception")
# 处理 CEnum 成员变量
for TargetName, value in cEnumMembers:
# 注册枚举成员
MemberNode = CTypeInfo()
MemberNode: CTypeInfo = CTypeInfo()
MemberNode.Name = TargetName
MemberNode.BaseType = t.CEnum(TypePrefix)
MemberNode.value = value
@@ -289,40 +287,38 @@ class AnnotationLoaderMixin:
try:
with open(ModuleName, 'r', encoding='utf-8') as f:
ann_content = f.read()
ann_tree = ast.parse(ann_content)
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 = node.target.id
TargetName: str = node.target.id
# 检查注解是否是 t.CTypedef
if isinstance(node.annotation, ast.Attribute):
if isinstance(node.annotation.value, ast.Name):
if node.annotation.value.id == 't' and node.annotation.attr == 'CTypedef':
if IsTModule(node.annotation.value.id) and node.annotation.attr == 'CTypedef':
# 检查值是否是 Name
if isinstance(node.value, ast.Name):
original_name = node.value.id
original_name: str = node.value.id
typedef_annots.append((TargetName, original_name))
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode
if _ConfigMode == "strict":
if _config_mode == "strict":
raise
_vlog().warning(f"解析 typedef 语句失败: {_e}", "Exception")
# 处理 typedef 注解
for TargetName, original_name in typedef_annots:
# 检查原始类型是否在符号表中(带前缀或不带前缀)
orig_with_prefix = f'{TypePrefix}.{original_name}'
orig_with_prefix: str = f'{TypePrefix}.{original_name}'
if self.SymbolTable.has(orig_with_prefix):
# 添加带前缀的 typedef 别名
FullTypedef_name = f'{TypePrefix}.{TargetName}'
TypedefNode = CTypeInfo()
FullTypedef_name: str = f'{TypePrefix}.{TargetName}'
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = FullTypedef_name
TypedefNode.IsTypedef = True
orig_entry = self.SymbolTable.lookup(orig_with_prefix)
orig_type_str = f'struct {original_name}'
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}')
@@ -349,8 +345,8 @@ class AnnotationLoaderMixin:
else:
# importlib 模式:导入模块
try:
module = importlib.import_module(ModuleName)
count = register_to_symboltable(module, lib_name, None)
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:
@@ -360,7 +356,7 @@ class AnnotationLoaderMixin:
self.LogWarning(f"加载注解模块失败: {ModuleName}, 错误: {e}")
return 0
def _LoadAnnotationFiles(self, FilePaths: list):
def _LoadAnnotationFiles(self, FilePaths: list[str | tuple]) -> None:
"""加载多个注解文件并注册到符号表
Args:
@@ -371,15 +367,20 @@ class AnnotationLoaderMixin:
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 = self._loadAnnotationModule(path, library_name, parse_method)
count: int = self._LoadAnnotationModule(path, library_name, parse_method)
elif len(item) == 2:
path: str
library_name: str
path, library_name = item
count = self._loadAnnotationModule(path, library_name, 'auto')
count: int = self._LoadAnnotationModule(path, library_name, 'auto')
else:
count = self._loadAnnotationModule(item)
count: int = self._LoadAnnotationModule(item)
else:
count = self._loadAnnotationModule(item)
count: int = self._LoadAnnotationModule(item)
# 别名,保持向后兼容
LoadAnnotationFiles = _LoadAnnotationFiles

View File

@@ -1,11 +1,15 @@
from __future__ import annotations
from typing import Dict
import ast
from typing import Any, Callable, Dict, TYPE_CHECKING
import sys
import os
from lib.core.Exportable import Exportable
if TYPE_CHECKING:
import llvmlite.ir as ir
sys.path.append(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))), 'lib', 'includes'))
from lib.includes import c
from lib.includes import t
@@ -27,10 +31,11 @@ from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.SymbolTable import SymbolTable
from lib.core.SymbolNode import SymbolNode
from lib.constants.config import mode as _ConfigMode
from lib.core.VLogger import get_logger as _vlog
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
def _StrictLog(logger, msg):
def _StrictLog(logger: Callable[[str], None], msg: str) -> None:
"""在 strict 模式下记录异常日志"""
if _ConfigMode == "strict":
logger(msg)
@@ -42,11 +47,11 @@ class BaseTranslatorMixin:
提供 __init__、日志、调试输出与表达式处理等基础能力。
"""
def __init__(self):
def __init__(self) -> None:
self.VarScopes: list[Dict[str, SymbolNode]] = [{}] # 跟踪变量作用域,第一个是全局作用域
self.FunctionReturnTypes: Dict[str, CTypeInfo] = {} # 记录函数名和其返回类型
self.CurrentCReturnTypes: list[CTypeInfo] = None # 当前函数的 CReturn 类型列表
self._CurrentCpythonObjectClass: str = None # 当前正在处理的 CPython 对象类名
self.CurrentCReturnTypes: list[CTypeInfo] | None = None # 当前函数的 CReturn 类型列表
self._CurrentCpythonObjectClass: str | None = None # 当前正在处理的 CPython 对象类名
self.FunctionDefCache: dict = {} # 函数定义缓存
self.OriginalLines: list[str] = [] # 原始代码行
self.Content: str = ''
@@ -54,20 +59,20 @@ class BaseTranslatorMixin:
self.IsHeader: bool = False # 是否生成头文件(仅处理定义、宏、导入等,忽略函数体)
self.AnnotationModules: set[str] = set() # 注解模块集合,用于识别类型定义模块
self.Warnings: list[str] = [] # 警告日志
self._ErrorStack = [] # 错误栈,按顺序收集错误位置
self.Errors = [] # 错误日志
self.SliceCount = 0 # 切片计数
self.SliceInfos = [] # 切片信息列表
self.SliceLevel = 3 # 切片优化级别
self.GeneratedTypes = set() # 在当前代码中生成的类型struct/typedef
self.EmbeddedAssignments = {} # {ClassName: [var1, var2, ...]} 嵌入的实例化变量
self.TypedefAssignments = {} # {ClassName: [(var1, IsPtr), ...]} 嵌入的 typedef/指针变量
self.ChainAssignmentArrays = [] # 链式赋值数组形式 [(ClassName, VarName, ArraySize_node), ...]
self.tree = None # 保存解析后的 AST 树
self.LibraryPaths = ['.'] # 库搜索路径列表,默认包含当前目录
self.InClass = False # 是否正在处理 class 定义
self._UserTypeModules = {}
self._source_module_sig_files = {}
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.exception_registry: dict = {}
self.exception_parents: dict = {}
@@ -107,7 +112,7 @@ class BaseTranslatorMixin:
self.RaiseHandler = RaiseHandle(self)
self.MatchHandler = MatchHandle(self)
def LogWarning(self, message: str, LineNum: int = None):
def LogWarning(self, message: str, LineNum: int | None = None) -> None:
"""记录警告
Args:
@@ -119,36 +124,36 @@ class BaseTranslatorMixin:
warning += f" (line {LineNum})"
self.Warnings.append(warning)
def LogError(self, message: str, LineNum: int = None):
def LogError(self, message: str, LineNum: int | None = None) -> None:
"""记录错误
Args:
message: 错误消息
LineNum: 行号
"""
print(f"[ERROR] {message}")
entry = {'message': message, 'line': LineNum}
_vlog().error(message)
entry: dict[str, str | int | None] = {'message': message, 'line': LineNum}
self.Errors.append(entry)
# 检查 config 中是否有 debug 文件
DebugFile = None
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 = f' line {LineNum}' if LineNum else ''
LineInfo: str = f' line {LineNum}' if LineNum else ''
f.write(f'[ERROR]{LineInfo}: {message}\n')
def SetDebugFile(self, FilePath):
def SetDebugFile(self, FilePath: str) -> None:
"""设置调试输出文件"""
self.DebugFile = FilePath
def DebugPrint(self, *args, **kwargs):
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, UseSingleQuote=False, VarType=None):
def HandleExpr(self, Node: ast.AST, UseSingleQuote: bool = False, VarType: ir.Type | None = None) -> Any:
return self.ExprHandler.HandleExpr(Node, UseSingleQuote, VarType)

View File

@@ -1,8 +1,14 @@
from __future__ import annotations
import ast
from typing import Any, 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
@@ -10,17 +16,27 @@ class ConstEvalMixin:
提供数组初始化常量构建与常量表达式求值能力。
"""
def _BuildArrayInitConstants(self, value_node, ElemType, elem_type_node, ArrayCount, Gen):
from lib.core.Handles.HandlesAssign import AssignHandle
_zv = AssignHandle._zero_value(ElemType)
_fallback = _zv if _zv is not None else ir.Constant(ElemType, ir.Undefined)
@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 = []
constants: list[ir.Constant] = []
for elt in value_node.elts:
if isinstance(elt, (ast.List, ast.Set)):
inner_consts = self._BuildMultiDimArrayInitConstants(elt, ElemType, Gen)
inner_consts: list[ir.Constant] | None = self._BuildMultiDimArrayInitConstants(elt, ElemType, Gen)
if inner_consts:
try:
constants.append(ir.Constant(ElemType, inner_consts))
@@ -33,25 +49,33 @@ class ConstEvalMixin:
while len(constants) < ArrayCount:
constants.append(_fallback)
return constants[:ArrayCount]
StructName = None
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 = self.ClassHandler._BuildStructConstant(elt, StructName, Gen)
const: ir.Constant | None = self.ClassHandler._BuildStructConstant(elt, StructName, Gen)
if const:
constants.append(const)
else:
constants.append(_fallback)
elif isinstance(elt, ast.Constant):
const = self.ClassHandler._BuildScalarConstant(elt, ElemType)
if const:
constants.append(const)
# 字符串常量:根据引号类型决定 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:
constants.append(_fallback)
const = self._BuildScalarConstantUnified(elt, ElemType, Gen)
if const:
constants.append(const)
else:
constants.append(_fallback)
elif isinstance(elt, ast.UnaryOp):
const = self.ClassHandler._BuildScalarConstant(elt, ElemType)
const = self._BuildScalarConstantUnified(elt, ElemType, Gen)
if const:
constants.append(const)
else:
@@ -73,7 +97,7 @@ class ConstEvalMixin:
else:
constants.append(_fallback)
else:
const_val = self._try_eval_const_call(elt, Gen)
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))
@@ -83,24 +107,155 @@ class ConstEvalMixin:
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 _try_eval_const_call(self, node, Gen):
import ast
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 = None
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 = []
arg_vals: list[int | float | str | None] = []
for arg in node.args:
v = self._try_eval_const_expr(arg, Gen)
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:
@@ -111,22 +266,20 @@ class ConstEvalMixin:
return None
return self._try_eval_const_expr(node, Gen)
def _try_eval_const_expr(self, node, Gen):
from lib.core.ConstEvaluator import ConstEvaluator
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, ArrayType, Gen):
from lib.core.Handles.HandlesAssign import AssignHandle
inner_type = ArrayType.element
count = ArrayType.count
elts = list(value_node.elts) if hasattr(value_node, 'elts') else []
_zv = AssignHandle._zero_value(inner_type)
_fallback = _zv if _zv is not None else ir.Constant(inner_type, ir.Undefined)
constants = []
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 = self._BuildMultiDimArrayInitConstants(elt, inner_type, Gen)
inner_consts: list[ir.Constant] | None = self._BuildMultiDimArrayInitConstants(elt, inner_type, Gen)
if inner_consts:
constants.append(ir.Constant(inner_type, inner_consts))
else:
@@ -134,13 +287,13 @@ class ConstEvalMixin:
else:
constants.append(_fallback)
elif isinstance(elt, ast.Constant):
const = self.ClassHandler._BuildScalarConstant(elt, inner_type)
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.ClassHandler._BuildScalarConstant(elt, inner_type)
const = self._BuildScalarConstantUnified(elt, inner_type, Gen)
if const:
constants.append(const)
else:

View File

@@ -3,13 +3,18 @@ from __future__ import annotations
import ast
import os
import re
from typing import Any
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.Translator.BaseTranslator import _StrictLog
from lib.core.SymbolUtils import IsTModule, AnnotationContainsName
class LlvmGeneratorMixin:
@@ -18,8 +23,25 @@ class LlvmGeneratorMixin:
提供 LLVM IR 直接生成、模块级 LLVM IR 处理与 C 代码生成入口能力。
"""
def GenerateLlvmDirect(self, Tree):
Gen = self.LlvmGen
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)
Gen._class_graph[Node.name] = {
'bases': bases,
'has_methods': has_methods,
}
# === 结束新增 ===
# 预扫描:为所有 -> str 注解的函数注册正确的返回类型 i8*
# 这样在类方法中调用这些函数时,前向声明会使用正确的类型
@@ -29,7 +51,7 @@ class LlvmGeneratorMixin:
Gen.known_return_types[Node.name] = ir.PointerType(ir.IntType(8))
# 首先收集所有 CDefine 常量,确保类定义中可以引用
def _extract_call_const_val(node):
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':
@@ -42,48 +64,44 @@ class LlvmGeneratorMixin:
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.AnnAssign) and isinstance(Node.target, ast.Name) and Node.value:
TypeInfo = self.TypeMergeHandler.GetCTypeInfo(Node.annotation)
if TypeInfo and TypeInfo.BaseType and hasattr(TypeInfo.BaseType, 'CName') and TypeInfo.BaseType.CName == '#define':
val = None
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 = {}
Gen._define_constants: dict[str, int | str | float | bool] = {}
Gen._define_constants[Node.target.id] = val
from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo
sym_info = _CTypeInfo()
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 = None
TypeInfo: CTypeInfo | None = None
if Node.type_comment:
try:
tc_ast = ast.parse(Node.type_comment, mode='eval')
tc_ast: ast.Expression = ast.parse(Node.type_comment, mode='eval')
TypeInfo = self.TypeMergeHandler.GetCTypeInfo(tc_ast.body)
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"解析类型注释失败: {_e}", "Exception")
if TypeInfo and TypeInfo.BaseType and hasattr(TypeInfo.BaseType, 'CName') and TypeInfo.BaseType.CName == '#define':
val = None
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 = {}
Gen._define_constants: dict[str, int | str | float | bool] = {}
Gen._define_constants[target.id] = val
from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo
sym_info = _CTypeInfo()
sym_info: _CTypeInfo = _CTypeInfo()
sym_info.IsDefine = True
sym_info.DefineValue = val
self.SymbolTable.insert(target.id, sym_info)
@@ -92,7 +110,7 @@ class LlvmGeneratorMixin:
# 这样类方法编译时遇到未声明的函数可以按需前向声明
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.FunctionDef):
FuncName = Node.name
FuncName: str = Node.name
if FuncName not in self.FunctionDefCache:
self.FunctionDefCache[FuncName] = Node
@@ -105,17 +123,17 @@ class LlvmGeneratorMixin:
elif isinstance(Node, ast.ImportFrom):
self.ImportHandler._EmitImportFromDeclarationsLlvm(Node, Gen)
except Exception as e:
lineno = getattr(Node, 'lineno', 0)
source_line = Gen._get_source_line(lineno)
src_file = getattr(Gen, '_current_source_file', '')
src_path = src_file if src_file else 'unknown'
line_info = "源代码 (%s, line %d)" % (src_path, lineno)
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))
# 预创建全局变量(带初始化器),确保类方法编译时能引用全局数组等
Gen._current_tree = Tree
Gen._current_tree: ast.Module = Tree
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.AnnAssign):
self.AssignHandler._EmitGlobalAnnAssignLlvm(Node, Gen)
@@ -155,42 +173,41 @@ class LlvmGeneratorMixin:
elif isinstance(Node, ast.Expr):
self._HandleModuleLevelExprLlvm(Node, Gen)
except Exception as e:
lineno = getattr(Node, 'lineno', 0)
source_line = Gen._get_source_line(lineno)
src_file = getattr(Gen, '_current_source_file', '')
src_path = src_file if src_file else 'unknown'
line_info = "源代码 (%s, line %d)" % (src_path, lineno)
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
from lib.core.DecoratorPass import run as _run_decorator_pass
_run_decorator_pass(Gen)
ir_code = Gen.finalize()
ir_code: str = Gen.finalize()
return ir_code
def _HandleModuleLevelExprLlvm(self, Node, Gen):
def _HandleModuleLevelExprLlvm(self, Node: ast.Expr, Gen: LlvmCodeGenerator) -> None:
if not isinstance(Node.value, ast.Call):
return
call = Node.value
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 = call.func.attr
func_name: str = call.func.attr
if func_name == 'LLVMIR':
self._HandleModuleLevelLLVMIR(call, Gen)
def _HandleModuleLevelLLVMIR(self, Node, Gen):
def _HandleModuleLevelLLVMIR(self, Node: ast.Call, Gen: LlvmCodeGenerator) -> None:
if not Node.args:
return
first_arg = Node.args[0]
first_arg: ast.expr = Node.args[0]
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
ir_text = first_arg.value
ir_text: str = first_arg.value
elif isinstance(first_arg, ast.JoinedStr):
parts = []
parts: list[str] = []
for value in first_arg.values:
if isinstance(value, ast.Constant) and isinstance(value.value, str):
parts.append(value.value)
@@ -201,79 +218,78 @@ class LlvmGeneratorMixin:
return
self._InsertModuleLevelLLVMIR(Gen, ir_text)
def _InsertModuleLevelLLVMIR(self, Gen, ir_text):
import re
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(r'!llvm\.module\.flags\s*=\s*!\{(!\d+)\}', line)
module_flags_match: re.Match[str] | None = re.match(r'!llvm\.module\.flags\s*=\s*!\{(!\d+)\}', line)
if module_flags_match:
ref = module_flags_match.group(1)
ref: str = module_flags_match.group(1)
if not hasattr(Gen, '_pending_module_flags'):
Gen._pending_module_flags = []
Gen._pending_module_flags_refs = ref
Gen._pending_module_flags: list = []
Gen._pending_module_flags_refs: str = ref
continue
metadata_match = re.match(r'(!\d+)\s*=\s*!\{(.+)\}', line)
metadata_match: re.Match[str] | None = re.match(r'(!\d+)\s*=\s*!\{(.+)\}', line)
if metadata_match:
md_id = metadata_match.group(1)
md_body = metadata_match.group(2)
fields = []
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(r'^i32\s+(\d+)$', field_str)
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(r'^"([^"]*)"$', field_str)
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(r'^!"([^"]*)"$', field_str)
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(r'^(\d+)$', field_str)
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(r'^(!\d+)$', field_str)
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 = []
Gen._pending_metadata: list[tuple[str, list]] = []
Gen._pending_metadata.append((md_id, fields))
continue
self._FlushModuleMetadata(Gen)
def _FlushModuleMetadata(self, Gen):
def _FlushModuleMetadata(self, Gen: LlvmCodeGenerator) -> None:
if not hasattr(Gen, '_pending_metadata') or not Gen._pending_metadata:
return
md_map = {}
md_map: dict[str, ir.MetaDataString] = {}
for md_id, fields in Gen._pending_metadata:
resolved = []
resolved: list[ir.Constant | ir.MetaDataString] = []
for f in fields:
if isinstance(f, str) and f.startswith('!'):
ref = md_map.get(f)
ref: ir.MetaDataString | None = md_map.get(f)
if ref:
resolved.append(ref)
else:
resolved.append(f)
md_value = Gen.module.add_metadata(resolved)
md_value: ir.MetaDataString = Gen.module.add_metadata(resolved)
md_map[md_id] = md_value
if hasattr(Gen, '_pending_module_flags_refs'):
ref = Gen._pending_module_flags_refs
md_node = md_map.get(ref)
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, target='llvm'):
def GenerateCCode(self, Tree: ast.Module, target: str = 'llvm') -> str:
"""生成代码
Args:
@@ -283,23 +299,23 @@ class LlvmGeneratorMixin:
Returns:
生成的代码字符串
"""
self._generated_vars = set()
self._generated_vars: set[str] = set()
self.VarScopes = [{}] # 全局作用域
# 预扫描 import 语句,注册别名,确保类型解析时能正确解析模块别名
if not getattr(self, '_ImportedModules', None):
self._ImportedModules = set()
self._ImportedModules: set[str] = set()
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.Import):
for alias in Node.names:
name = alias.name
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 = Node.module
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:
@@ -308,10 +324,10 @@ class LlvmGeneratorMixin:
for Node in ast.iter_child_nodes(Tree):
if isinstance(Node, ast.ClassDef):
ClassName = Node.name
ClassName: str = Node.name
# 检查是否是特殊类型(枚举或联合体)
IsSpecialType = False
IsSpecialType: bool = False
if Node.bases:
for base in Node.bases:
if hasattr(base, 'attr'):
@@ -327,13 +343,13 @@ class LlvmGeneratorMixin:
if IsSpecialType:
continue
members = {}
IsTypedef = False
TypedefName = None
members: dict[str, CTypeInfo] = {}
IsTypedef: bool = False
TypedefName: str | None = None
if hasattr(Node, 'annotation') and Node.annotation:
try:
AnnotationStr = ast.dump(Node.annotation)
AnnotationStr: str = ast.dump(Node.annotation)
if 'CTypedef' in AnnotationStr:
IsTypedef = True
if isinstance(Node.annotation, ast.Call):
@@ -341,8 +357,6 @@ class LlvmGeneratorMixin:
if isinstance(Node.annotation.args[0], ast.Constant):
TypedefName = Node.annotation.args[0].value
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
if _config_mode == "strict":
raise
_vlog().warning(f"解析 typedef 注解失败: {_e}", "Exception")
@@ -355,7 +369,7 @@ class LlvmGeneratorMixin:
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__':
value_str = ast.dump(value)
value_str: str = ast.dump(value)
if 'CTypedef' in value_str:
IsTypedef = True
if isinstance(value, ast.Call):
@@ -364,8 +378,8 @@ class LlvmGeneratorMixin:
TypedefName = value.args[0].value
if IsTypedef:
TypedefKey = TypedefName if TypedefName else ClassName
TypedefNode = CTypeInfo()
TypedefKey: str = TypedefName if TypedefName else ClassName
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = TypedefKey
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = f'struct {ClassName}'
@@ -375,80 +389,79 @@ class LlvmGeneratorMixin:
for item in Node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
VarName = item.target.id
VarName: str = item.target.id
try:
TypeInfo = self.TypeMergeHandler.GetCTypeInfo(item.annotation)
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(item.annotation)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
IsPtr = TypeInfo.IsPtr
IsPtr: bool = TypeInfo.IsPtr
if not IsPtr:
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
LeftStr = ast.dump(item.annotation.left)
RightStr = ast.dump(item.annotation.right)
if 'CPtr' in LeftStr or 'CPtr' in RightStr:
if AnnotationContainsName(item.annotation, 'CPtr'):
IsPtr = True
dims = []
dims: list[int] = []
if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant):
if isinstance(item.annotation.value, ast.Name):
if item.annotation.value.id == 't':
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 __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
if _config_mode == "strict":
self.LogWarning(f"异常被忽略: {_e}")
MemberInfo = TypeInfo.Copy()
MemberInfo: CTypeInfo = TypeInfo.Copy()
if dims:
MemberInfo.ArrayDims = [str(d) for d in dims]
members[VarName] = MemberInfo
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
if _config_mode == "strict":
self.LogWarning(f"异常被忽略: {_e}")
if not IsTypedef:
StructNode = CTypeInfo()
StructNode: CTypeInfo = CTypeInfo()
StructNode.Name = ClassName
StructNode.IsStruct = True
StructNode.Members = members or {}
StructNode.file = '<stdin>'
if self.SymbolTable.has(ClassName):
existing = self.SymbolTable[ClassName]
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 = Node.name
FuncNode = CTypeInfo()
FuncNode.Name = FuncName
FuncNode.IsFunction = True
FuncNode.file = '<stdin>'
self.SymbolTable.insert(FuncName, FuncNode)
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 = Node.target.id
VarName: str = Node.target.id
VarType = 'unknown'
IsPtr = False
IsTypedef_assignment = False
VarType: str = 'unknown'
IsPtr: bool = False
IsTypedef_assignment: bool = False
if Node.annotation:
try:
AnnotationStr = ast.dump(Node.annotation)
AnnotationStr: str = ast.dump(Node.annotation)
if 'CTypedef' in AnnotationStr:
IsTypedef_assignment = True
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
if _config_mode == "strict":
self.LogWarning(f"异常被忽略: {_e}")
if IsTypedef_assignment and Node.value:
if isinstance(Node.value, ast.Name):
OriginalType = Node.value.id
OriginalType: str = Node.value.id
if OriginalType in self.GeneratedTypes:
if self.SymbolTable.has(OriginalType):
OriginalInfo = self.SymbolTable[OriginalType]
OriginalInfo: CTypeInfo | None = self.SymbolTable.lookup(OriginalType)
if OriginalInfo:
if isinstance(OriginalInfo, dict):
actual_type = OriginalInfo.get('type', 'struct')
actual_type: str = OriginalInfo.get('type', 'struct')
elif isinstance(OriginalInfo, CTypeInfo):
if OriginalInfo.IsEnum:
actual_type = 'enum'
@@ -461,7 +474,7 @@ class LlvmGeneratorMixin:
else:
actual_type = 'struct'
if actual_type == 'enum':
TypedefNode = CTypeInfo()
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = VarName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = f'enum {OriginalType}'
@@ -491,10 +504,10 @@ class LlvmGeneratorMixin:
self.GeneratedTypes.add(VarName)
continue
else:
if self.SymbolTable.has(OriginalType):
OriginalInfo = self.SymbolTable[OriginalType]
OriginalInfo: CTypeInfo | None = self.SymbolTable.lookup(OriginalType)
if OriginalInfo:
if isinstance(OriginalInfo, dict):
actual_type = OriginalInfo.get('type', 'struct')
actual_type: str = OriginalInfo.get('type', 'struct')
elif isinstance(OriginalInfo, CTypeInfo):
if OriginalInfo.IsEnum:
actual_type = 'enum'
@@ -507,7 +520,7 @@ class LlvmGeneratorMixin:
else:
actual_type = 'struct'
if actual_type == 'typedef':
TypedefNode = CTypeInfo()
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = VarName
TypedefNode.IsTypedef = True
if isinstance(OriginalInfo, dict):
@@ -548,10 +561,9 @@ class LlvmGeneratorMixin:
OriginalInfo['skip_generation'] = True
continue
elif isinstance(Node.value, ast.Attribute):
from lib.core.Handles.HandlesBase import CTypeHelper
CName = CTypeHelper.GetCName(Node.value.attr)
CName: str | None = CTypeHelper.GetCName(Node.value.attr)
if CName:
TypedefNode = CTypeInfo()
TypedefNode: CTypeInfo = CTypeInfo()
TypedefNode.Name = VarName
TypedefNode.IsTypedef = True
TypedefNode.OriginalType = CName
@@ -562,19 +574,19 @@ class LlvmGeneratorMixin:
if Node.annotation:
try:
TypeInfo = self.TypeMergeHandler.GetCTypeInfo(Node.annotation)
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(Node.annotation)
IsPtr = TypeInfo.IsPtr if TypeInfo else False
except Exception as _e:
if __import__('lib.constants.config', fromlist=['mode']).mode == "strict":
if _config_mode == "strict":
self.LogWarning(f"异常被忽略: {_e}")
var_node = CTypeInfo()
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(
self.LlvmGen: LlvmCodeGenerator = LlvmCodeGenerator(
triple=getattr(self, 'triple', None),
datalayout=getattr(self, 'datalayout', None),
)

View File

@@ -8,8 +8,10 @@ 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
from lib.core.Translator.BaseTranslator import _StrictLog
@@ -19,13 +21,13 @@ class PythonParserMixin:
提供辅助文件解析、symbin 文件加载与 Python 源文件解析能力。
"""
def ParseHelperFiles(self, HelperFiles, encoding='utf-8'):
def ParseHelperFiles(self, HelperFiles: list[str], encoding: str = 'utf-8') -> None:
"""解析辅助文件,提取符号信息
支持 .py, .c, .h 和 .symbin 文件
"""
for FilePath in HelperFiles:
ext = DetectFileType(FilePath)
ext: str = DetectFileType(FilePath)
if ext == '.py':
self.ParsePythonFile(FilePath, encoding, UpdateCurrentFile=False)
elif ext == '.c':
@@ -33,7 +35,7 @@ class PythonParserMixin:
elif FilePath.endswith('.symbin'):
self.LoadSymbinFile(FilePath)
def LoadSymbinFile(self, FilePath):
def LoadSymbinFile(self, FilePath: str) -> None:
"""从.symbin文件加载符号表
Args:
@@ -41,32 +43,27 @@ class PythonParserMixin:
"""
try:
with open(FilePath, 'rb') as f:
data = f.read()
data: bytes = f.read()
# 导入序列化函数(避免循环导入)
import sys
import os
import json
import struct
# 解析二进制格式
if len(data) < 4:
print(f"Warning: Invalid symbin file (too short): {FilePath}")
_vlog().warning(f"无效的 symbin 文件 (太短): {FilePath}")
return
# 解析4字节长度头小端序
length = struct.unpack('<I', data[:4])[0]
JsonData = data[4:4+length]
symbols = json.loads(JsonData.decode('utf-8'))
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:
print(f"Warning: Failed to Load symbin file {FilePath}: {e}")
_vlog().warning(f"加载 symbin 文件失败 {FilePath}: {e}")
def ParsePythonFile(self, FilePath, encoding='utf-8', UpdateCurrentFile=True):
def ParsePythonFile(self, FilePath: str, encoding: str = 'utf-8', UpdateCurrentFile: bool = True) -> None:
"""解析Python文件提取类、函数、变量信息
Args:
@@ -76,41 +73,41 @@ class PythonParserMixin:
"""
try:
with open(FilePath, 'r', encoding=encoding) as f:
content = f.read()
content: str = f.read()
# 保存当前处理的文件路径(仅在主文件处理时更新)
if UpdateCurrentFile:
self.CurrentFile = FilePath
# 解析Python代码为AST
tree = ast.parse(content)
tree: ast.Module = ast.parse(content)
# 保存 AST 树供后续使用
self.tree = tree
# 第一遍:检测特殊赋值语句,收集跟在 class 后面的
# 遍历 tree.body找到所有 ClassDef然后收集紧随其后的赋值语句
i = 0
i: int = 0
while i < len(tree.body):
node = tree.body[i]
node: ast.stmt = tree.body[i]
# 检测 ClassDef
if isinstance(node, ast.ClassDef):
ClassName = node.name
ClassName: str = node.name
# 使用类名_行号作为唯一 key
ClassKey = f"{ClassName}_{node.lineno}"
ClassKey: str = f"{ClassName}_{node.lineno}"
# 检查后面的语句,收集特殊赋值
j = i + 1
j: int = i + 1
while j < len(tree.body):
NextNode = tree.body[j]
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 = NextNode.targets[0].id
TargetName: str = NextNode.targets[0].id
if isinstance(NextNode.value, ast.Name):
ValueName = NextNode.value.id
ValueName: str = NextNode.value.id
if ValueName == ClassName:
# 这是 class 的实例化
if ClassKey not in self.EmbeddedAssignments:
@@ -121,23 +118,23 @@ class PythonParserMixin:
elif isinstance(NextNode, ast.AnnAssign):
# 检测 xxx: t.Postdefinition(yyy) 或 xxx: t.CTypedef = xxx 或 xxx: t.CPtr = xxx
if isinstance(NextNode.target, ast.Name):
TargetName = NextNode.target.id
TargetName: str = NextNode.target.id
# 先处理新格式t.Postdefinition(...)
annotation = NextNode.annotation
original_AnnotationStr = ast.dump(NextNode.annotation)
PostdefNode = None
annotation: ast.expr | None = NextNode.annotation
original_AnnotationStr: str = ast.dump(NextNode.annotation)
PostdefNode: ast.Call | None = None
# 递归搜索整个注解树,找到 t.Postdefinition(...) 调用
def find_PostdefNode(node):
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 node.func.value.id == 't' and node.func.attr == 'Postdefinition':
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 = find_PostdefNode(node.left)
LeftResult: ast.Call | None = find_PostdefNode(node.left)
if LeftResult:
return LeftResult
RightResult = find_PostdefNode(node.right)
RightResult: ast.Call | None = find_PostdefNode(node.right)
if RightResult:
return RightResult
return None
@@ -148,25 +145,25 @@ class PythonParserMixin:
if (isinstance(PostdefNode.func, ast.Attribute) and
hasattr(PostdefNode.func, 'value') and
hasattr(PostdefNode.func.value, 'id') and
PostdefNode.func.value.id == 't' and
IsTModule(PostdefNode.func.value.id, self.SymbolTable) and
PostdefNode.func.attr == 'Postdefinition' and
PostdefNode.args):
# 检查第一个参数是否是当前类名
arg = PostdefNode.args[0]
arg: ast.expr = PostdefNode.args[0]
if isinstance(arg, ast.Name) and arg.id == ClassName:
# 检查是否包含 CTypedef 或 CPtr
HasCtypedef = False
IsPtr = False
HasCtypedef: bool = False
IsPtr: bool = False
if 'CTypedef' in original_AnnotationStr:
HasCtypedef = True
if 'CPtr' in original_AnnotationStr:
IsPtr = True
# 解析维度列表(第二个参数)
dimensions = []
dimensions: list[ast.expr] = []
if len(PostdefNode.args) > 1:
# 第二个参数应该是一个列表
dim_arg = 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)
@@ -174,9 +171,9 @@ class PythonParserMixin:
# 如果没有从 Postdefinition 参数中获取维度,尝试从类型注解中的 Subscript 获取
# 例如memory_block_t[MAX_ORDER + 1] | t.CPtr
if not dimensions:
def extract_subscript_dims(node):
def extract_subscript_dims(node: ast.AST) -> list[ast.expr]:
"""递归提取 Subscript 节点的维度"""
dims = []
dims: list[ast.expr] = []
if isinstance(node, ast.Subscript):
# 提取当前维度
if isinstance(node.slice, ast.Constant):
@@ -193,13 +190,13 @@ class PythonParserMixin:
return dims
# 从注解中提取维度
subscript_dims = extract_subscript_dims(annotation)
subscript_dims: list[ast.expr] = extract_subscript_dims(annotation)
if subscript_dims:
# 反转维度顺序(从内到外)
dimensions = list(reversed(subscript_dims))
# 获取赋值值
value = None
value: ast.expr | None = None
if hasattr(NextNode, 'value') and NextNode.value is not None:
value = NextNode.value
@@ -241,11 +238,11 @@ class PythonParserMixin:
# 而应该生成独立的 typedef 语句,所以不添加到 TypedefAssignments
elif NextNode.annotation and isinstance(NextNode.annotation, ast.Attribute):
if isinstance(NextNode.annotation.value, ast.Name):
annot_id = NextNode.annotation.value.id
annot_attr = NextNode.annotation.attr
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 = NextNode.value.id
ValueName: str = NextNode.value.id
if ValueName == ClassName:
# 检查是 CTypedef 还是 CPtr
if annot_attr == t.CPtr.__name__:
@@ -267,15 +264,15 @@ class PythonParserMixin:
# 提取类定义(作为结构体)
for node in ast.walk(tree):
if isinstance(node, ast.ClassDef):
ClassName = node.name
ClassName: str = node.name
# 先把类名加入 GeneratedTypes这样 GetTypeName 可以正确识别
self.GeneratedTypes.add(ClassName)
# 检测是否是 CEnum
IsCenum = False
IsCenum: bool = False
for base in node.bases:
if isinstance(base, ast.Attribute):
BaseStr = ast.dump(base)
BaseStr: str = ast.dump(base)
if 'CEnum' in BaseStr or 'REnum' in BaseStr:
IsCenum = True
break
@@ -285,19 +282,19 @@ class PythonParserMixin:
break
# 检测是否有 @t.Object 装饰器或继承自 t.Object
IsCpythonObject = False
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
decorator.value.id == 't' 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
decorator.func.value.id == 't' and
IsTModule(decorator.func.value.id, self.SymbolTable) and
decorator.func.attr == 'Object'):
IsCpythonObject = True
break
@@ -313,7 +310,7 @@ class PythonParserMixin:
for base in node.bases:
if isinstance(base, ast.Attribute):
if (hasattr(base.value, 'id') and
base.value.id == 't' and
IsTModule(base.value.id, self.SymbolTable) and
base.attr == 'Object'):
IsCpythonObject = True
break
@@ -324,7 +321,7 @@ class PythonParserMixin:
if IsCenum:
# 注册为 enum 类型
EnumNode = CTypeInfo()
EnumNode: CTypeInfo = CTypeInfo()
EnumNode.Name = ClassName
EnumNode.IsEnum = True
EnumNode.set('file', '<stdin>')
@@ -333,8 +330,8 @@ class PythonParserMixin:
# 注册 enum 成员
for item in node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
MemberName = item.target.id
MemberNode = CTypeInfo()
MemberName: str = item.target.id
MemberNode: CTypeInfo = CTypeInfo()
MemberNode.Name = MemberName
MemberNode.BaseType = t.CEnum(ClassName)
MemberNode.value = None
@@ -348,49 +345,43 @@ class PythonParserMixin:
continue
# 检测是否是 Anonymous
IsAnonymous = False
IsAnonymous: bool = False
# 提取结构体成员信息
members = {}
members: dict[str, CTypeInfo] = {}
for item in node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
VarName = item.target.id
VarName: str = item.target.id
try:
TypeInfo = self.TypeMergeHandler.GetCTypeInfo(item.annotation)
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(item.annotation)
if TypeInfo is None:
TypeInfo = CTypeInfo()
TypeInfo.BaseType = t.CInt()
IsPtr = TypeInfo.IsPtr
IsPtr: bool = TypeInfo.IsPtr
if not IsPtr:
if isinstance(item.annotation, ast.BinOp) and isinstance(item.annotation.op, ast.BitOr):
LeftStr = ast.dump(item.annotation.left)
RightStr = ast.dump(item.annotation.right)
if 'CPtr' in LeftStr or 'CPtr' in RightStr:
if AnnotationContainsName(item.annotation, 'CPtr'):
IsPtr = True
dims = []
dims: list[int] = []
if hasattr(item.annotation, 'slice') and isinstance(item.annotation.slice, ast.Constant):
if isinstance(item.annotation.value, ast.Name):
if item.annotation.value.id == 't':
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:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode
if _ConfigMode == "strict":
raise
_vlog().warning(f"解析数组维度失败: {_e}", "Exception")
MemberInfo = TypeInfo.Copy()
MemberInfo: CTypeInfo = TypeInfo.Copy()
if dims:
MemberInfo.ArrayDims = [str(d) for d in dims]
members[VarName] = MemberInfo
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode
if _ConfigMode == "strict":
raise
_vlog().warning(f"解析结构体成员失败: {_e}", "Exception")
StructNode = CTypeInfo()
StructNode: CTypeInfo = CTypeInfo()
StructNode.Name = ClassName
StructNode.IsStruct = True
StructNode.Members = members or {}
@@ -399,26 +390,27 @@ class PythonParserMixin:
StructNode.set('IsCpythonObject', IsCpythonObject)
self.SymbolTable.insert(ClassName, StructNode)
elif isinstance(node, ast.FunctionDef):
FuncName = node.name
FuncNode = CTypeInfo()
FuncNode.Name = FuncName
FuncNode.IsFunction = True
FuncNode.set('file', '<stdin>')
self.SymbolTable.insert(FuncName, FuncNode)
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 = node.target.id
VarName: str = node.target.id
# 检查是否是 t.CTypedef 格式,如果是则跳过(由 HandleClassDef 处理)
is_ctypedef = False
is_ctypedef: bool = False
if node.annotation:
if isinstance(node.annotation, ast.Attribute):
if isinstance(node.annotation.value, ast.Name):
if node.annotation.value.id == 't' and node.annotation.attr == 'CTypedef':
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):
def _has_ctype(ann: ast.AST) -> bool:
if isinstance(ann, ast.Attribute):
return hasattr(ann.value, 'id') and ann.value.id == 't' and ann.attr == 'CTypedef'
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):
@@ -427,25 +419,23 @@ class PythonParserMixin:
if _has_ctype(node.annotation):
is_ctypedef = True
if not is_ctypedef:
IsPtr = False
IsPtr: bool = False
if node.annotation:
try:
TypeInfo = self.TypeMergeHandler.GetCTypeInfo(node.annotation)
TypeInfo: CTypeInfo | None = self.TypeMergeHandler.GetCTypeInfo(node.annotation)
IsPtr = TypeInfo.IsPtr if TypeInfo else False
except Exception as _e:
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _ConfigMode
if _ConfigMode == "strict":
raise
_vlog().warning(f"获取类型信息失败(ParsePythonFile): {_e}", "Exception")
var_node = CTypeInfo()
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:
print(f'Warning: Failed to parse Python file {FilePath}: {e}')
_vlog().warning(f'解析 Python 文件失败 {FilePath}: {e}')
# ParseCFile 已移除 - .h/.c 文件的旧正则解析路径不再使用
# 类型解析现在直接通过 CTypeInfo 对象进行,不经过中间字符串格式