修复了大量存在的问题,增加了假鸭子类型等等机制
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
@@ -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 对象进行,不经过中间字符串格式
|
||||
|
||||
Reference in New Issue
Block a user