Files
TransPyC/lib/core/SymbolTable.py
2026-06-16 16:09:42 +08:00

999 lines
53 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.SymbolNode import SymbolNode
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper
from lib.includes import t
from typing import Any, Dict, Iterator
import ast
import re
def _IsTModuleType(TypeName: str) -> bool:
"""检测类型名称是否是 t 模块中的类型CType 或其他特殊类型)"""
if TypeName in ('t', 'State', 'Bit', 'Anonymous', 'Postdefinition'):
return True
TypeClass = getattr(t, TypeName, None)
if TypeClass and isinstance(TypeClass, type):
if issubclass(TypeClass, t.CType):
return True
FallbackClass = getattr(t, f'_{TypeName}', None)
if FallbackClass and isinstance(FallbackClass, type):
if issubclass(FallbackClass, t.CType):
return True
return False
def _AnnotationContainsTType(node, TypeName: str) -> bool:
"""检测 AST 节点中是否包含指定名称的 t 模块类型"""
if isinstance(node, ast.Attribute):
if (hasattr(node.value, 'id') and node.value.id == 't' and
node.attr == TypeName):
return True
elif isinstance(node, ast.BinOp):
return _AnnotationContainsTType(node.left, TypeName) or _AnnotationContainsTType(node.right, TypeName)
elif isinstance(node, ast.Call):
if _AnnotationContainsTType(node.func, TypeName):
return True
for arg in node.args:
if _AnnotationContainsTType(arg, TypeName):
return True
elif isinstance(node, ast.Subscript):
if _AnnotationContainsTType(node.value, TypeName):
return True
if _AnnotationContainsTType(node.slice, TypeName):
return True
return False
class SymbolTable:
def __init__(self, translator: "Translator"):
self.translator = translator
self._root = SymbolNode(name='root', NodeType='root')
def clear(self):
self._root = SymbolNode(name='root', NodeType='root')
def get(self, name: str, default=None) -> CTypeInfo:
node = self._FindNode(name)
if node:
return node.attributes
return default
def set(self, name: str, value: Any):
self._InsertNode(name, value)
self._cached_len = -1
def update(self, symbols: Dict[str, Any]):
for name, value in symbols.items():
self.set(name, value)
def keys(self) -> Iterator[str]:
return self._CollectKeys(self._root)
def values(self) -> Iterator[CTypeInfo]:
for node in self._CollectNodes(self._root):
yield node.attributes
def items(self) -> Iterator[tuple[str, CTypeInfo]]:
for node in self._CollectNodes(self._root):
yield node.name, node.attributes
def pop(self, name: str, *args) -> CTypeInfo:
node = self._FindNode(name)
if node and node.parent:
node.parent.RemoveChild(node.name)
return node.attributes
if args:
return args[0]
raise KeyError(name)
def __getitem__(self, name: str) -> CTypeInfo:
node = self._FindNode(name)
if node:
return node.attributes
raise KeyError(name)
def __setitem__(self, name: str, value: Any):
self.set(name, value)
def __delitem__(self, name: str):
node = self._FindNode(name)
if node and node.parent:
node.parent.RemoveChild(node.name)
self._cached_len = -1
else:
raise KeyError(name)
def __contains__(self, name: str) -> bool:
return self._FindNode(name) is not None
def __len__(self) -> int:
if not hasattr(self, '_cached_len') or self._cached_len < 0:
self._cached_len = sum(1 for _ in self._CollectNodes(self._root))
return self._cached_len
def __iter__(self) -> Iterator[str]:
return self.keys()
def ToDict(self) -> Dict[str, Any]:
return self._root.ToDict()
def FromDict(self, symbols: Dict[str, Any]):
self._root = SymbolNode.FromDict('root', symbols)
def LoadModuleSymbols(self, FullModulePath: str, asname: str, lineno: int = 0) -> list[str]:
return self._LoadSymbolsFromFile(FullModulePath, asname, lineno)
def _LoadSymbolsFromFile(self, FilePath: str, namespace_prefix: str | list[str], lineno: int = 0) -> list[str]:
from lib.core.Handles.HandlesTypeMerge import HandlesTypeMerge
import ast
LoadedSymbols = []
try:
with open(FilePath, 'r', encoding='utf-8') as f:
ModuleCode = f.read()
ModuleTree = ast.parse(ModuleCode)
ClassMembers = {}
AnonymousTypes = {}
for node in ModuleTree.body:
if isinstance(node, ast.ClassDef):
ClassName = node.name
MembersInfo = {}
def CollectMembers(ClassNode, prefix=''):
for item in ClassNode.body:
if isinstance(item, ast.AnnAssign):
if isinstance(item.target, ast.Name):
MemberName = item.target.id
FullName = f'{prefix}{MemberName}' if prefix else MemberName
MemberTypeInfo = CTypeInfo.FromNode(item.annotation, self.translator.SymbolTable)
if MemberTypeInfo is None:
MemberTypeInfo = CTypeInfo()
MemberTypeInfo.BaseType = t.CInt()
IsPtr = MemberTypeInfo.IsPtr
if isinstance(item.annotation, ast.BinOp):
AnnotationStr = ast.dump(item.annotation)
if 'CPtr' in AnnotationStr:
IsPtr = True
MembersInfo[FullName] = MemberTypeInfo.Copy()
elif isinstance(item, ast.ClassDef):
IsAnonymous = any(
any(_AnnotationContainsTType(base, 'Anonymous') for base in item.bases)
) if item.bases else False
if IsAnonymous:
IsUnion = any(
any(_AnnotationContainsTType(base, 'CUnion') for base in item.bases)
)
NestedMemberName = f'{prefix}{item.name}' if prefix else item.name
MembersInfo[NestedMemberName] = CTypeInfo()
MembersInfo[NestedMemberName].BaseType = f'union {item.name}' if IsUnion else f'struct {item.name}'
MembersInfo[NestedMemberName].PtrCount = 0
MembersInfo[NestedMemberName].ArrayDims = []
NewPrefix = f'{prefix}{item.name}.' if prefix else f'{item.name}.'
CollectMembers(item, NewPrefix)
AnonymousMembers = {}
for FullName, MemberInfo in MembersInfo.items():
if FullName.startswith(f"{NestedMemberName}."):
MemberName = FullName[len(NestedMemberName) + 1:]
AnonymousMembers[MemberName] = MemberInfo
if item.name not in AnonymousTypes:
AnonymousTypes[item.name] = {
'IsUnion': IsUnion,
'members': AnonymousMembers,
'lineno': item.lineno
}
CollectMembers(node)
ClassMembers[ClassName] = MembersInfo
LoadedSymbols = []
prefixes = [namespace_prefix] if isinstance(namespace_prefix, str) else namespace_prefix
for prefix in prefixes:
for node in ModuleTree.body:
if isinstance(node, ast.ClassDef):
ClassName = node.name
MembersInfo = ClassMembers.get(ClassName, {})
TypeKind = 'struct'
IsCpythonObject = False
IsPacked = 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
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 == 'c' and decorator.func.attr == 'Attribute':
for arg in decorator.args:
if isinstance(arg, ast.Attribute):
if isinstance(arg.value, ast.Attribute):
if hasattr(arg.value.value, 'id') and arg.value.value.id == 't' and arg.value.attr == 'attr' and arg.attr == 'packed':
IsPacked = True
for base in node.bases:
if _AnnotationContainsTType(base, 'CUnion'):
TypeKind = 'union'
break
elif _AnnotationContainsTType(base, 'CEnum'):
TypeKind = 'enum'
break
elif _AnnotationContainsTType(base, 'CStruct'):
TypeKind = 'struct'
break
elif _AnnotationContainsTType(base, 'Object'):
IsCpythonObject = True
TypeKind = 'struct'
break
elif isinstance(base, ast.Name) and base.id == 'Exception':
TypeKind = 'exception'
break
elif isinstance(base, ast.Name):
base_entry = self.get(base.id)
if base_entry and hasattr(base_entry, 'IsExceptionClass') and base_entry.IsExceptionClass:
TypeKind = 'exception'
break
if prefix == prefixes[0]:
self._InsertClassSymbol(ClassName, TypeKind, node.lineno, FilePath, MembersInfo, IsCpythonObject, IsPacked)
LoadedSymbols.append(ClassName)
FullName = f"{prefix}.{ClassName}"
self._InsertClassSymbol(FullName, TypeKind, node.lineno, FilePath, MembersInfo, IsCpythonObject, IsPacked)
LoadedSymbols.append(FullName)
if TypeKind == 'enum':
next_enum_value = 0
for item in node.body:
if isinstance(item, ast.Assign):
if len(item.targets) == 1 and isinstance(item.targets[0], ast.Name):
MemberName = item.targets[0].id
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
next_enum_value = item.value.value + 1
else:
next_enum_value += 1
if prefix == prefixes[0]:
self._InsertEnumMemberSymbol(MemberName, ClassName, item.lineno, FilePath)
LoadedSymbols.append(MemberName)
ClassMemberName = f"{ClassName}.{MemberName}"
self._InsertEnumMemberSymbol(ClassMemberName, ClassName, item.lineno, FilePath)
LoadedSymbols.append(ClassMemberName)
FullMemberName = f"{prefix}.{MemberName}"
self._InsertEnumMemberSymbol(FullMemberName, ClassName, item.lineno, FilePath)
LoadedSymbols.append(FullMemberName)
elif isinstance(item, ast.AnnAssign):
if isinstance(item.target, ast.Name):
MemberName = item.target.id
if item.value:
if isinstance(item.value, ast.Constant) and isinstance(item.value.value, int):
next_enum_value = item.value.value + 1
else:
next_enum_value += 1
else:
next_enum_value += 1
if prefix == prefixes[0]:
self._InsertEnumMemberSymbol(MemberName, ClassName, item.lineno, FilePath)
LoadedSymbols.append(MemberName)
ClassMemberName = f"{ClassName}.{MemberName}"
self._InsertEnumMemberSymbol(ClassMemberName, ClassName, item.lineno, FilePath)
LoadedSymbols.append(ClassMemberName)
FullMemberName = f"{prefix}.{MemberName}"
self._InsertEnumMemberSymbol(FullMemberName, ClassName, item.lineno, FilePath)
LoadedSymbols.append(FullMemberName)
elif isinstance(node, ast.AnnAssign):
if isinstance(node.target, ast.Name):
VarName = node.target.id
HasCDefine = _AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False
HasPostdef = _AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False
HasCtypedef = _AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False
IsPostdefWithTypedef = HasPostdef and HasCtypedef
if HasCDefine:
DefineValue = None
if node.value:
DefineValue = self._eval_const_expr(node.value)
if prefix == prefixes[0]:
self._InsertDefineSymbol(VarName, DefineValue, node.lineno, FilePath)
LoadedSymbols.append(VarName)
FullName = f"{prefix}.{VarName}"
self._InsertDefineSymbol(FullName, DefineValue, node.lineno, FilePath)
LoadedSymbols.append(FullName)
continue
def FindBaseType(n):
if isinstance(n, ast.Attribute):
if hasattr(n.value, 'id') and n.value.id == 't':
if n.attr == 'CPtr':
return 'ptr'
return n.attr
elif isinstance(n, ast.Subscript):
if isinstance(n.value, ast.Attribute) and isinstance(n.value.value, ast.Name) and n.value.value.id == 't' and n.value.attr == 'Callable':
return 'Callable'
elif isinstance(n, ast.BinOp) and isinstance(n.op, ast.BitOr):
LeftResult = FindBaseType(n.left)
if LeftResult == 'ptr':
RightResult = FindBaseType(n.right)
return (RightResult if RightResult and RightResult != 'ptr' else 'void') + ' *'
if LeftResult == 'Callable':
return 'Callable'
RightResult = FindBaseType(n.right)
if RightResult == 'ptr':
return (LeftResult if LeftResult and LeftResult != 'ptr' else 'void') + ' *'
if RightResult == 'Callable':
return 'Callable'
if LeftResult:
return LeftResult
if RightResult:
return RightResult
return None
if IsPostdefWithTypedef:
def FindPostdefArg(n):
if isinstance(n, ast.Call):
if isinstance(n.func, ast.Attribute):
if hasattr(n.func.value, 'id') and n.func.value.id == 't' and n.func.attr == 'Postdefinition':
if n.args and isinstance(n.args[0], ast.Name):
return n.args[0].id
elif isinstance(n, ast.BinOp) and isinstance(n.op, ast.BitOr):
LeftResult = FindPostdefArg(n.left)
if LeftResult:
return LeftResult
RightResult = FindPostdefArg(n.right)
if RightResult:
return RightResult
return None
OriginalClass = FindPostdefArg(node.annotation)
if OriginalClass and OriginalClass in ClassMembers:
MembersInfo = ClassMembers[OriginalClass]
OriginalType_kind = 'struct'
if OriginalClass in self:
OrigTypeInfo = self[OriginalClass]
if OrigTypeInfo.TypeCls in (t.CStruct, t.CEnum, t.CUnion):
if OrigTypeInfo.TypeCls is t.CStruct:
OriginalType_kind = 'struct'
elif OrigTypeInfo.TypeCls is t.CEnum:
OriginalType_kind = 'enum'
elif OrigTypeInfo.TypeCls is t.CUnion:
OriginalType_kind = 'union'
if prefix == prefixes[0]:
self._InsertTypedefSymbol(VarName, OriginalType_kind, OriginalClass, node.lineno, FilePath, MembersInfo)
LoadedSymbols.append(VarName)
FullName = f"{prefix}.{VarName}"
self._InsertTypedefSymbol(FullName, OriginalType_kind, OriginalClass, node.lineno, FilePath, MembersInfo)
LoadedSymbols.append(FullName)
else:
if prefix == prefixes[0]:
self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath)
LoadedSymbols.append(VarName)
FullName = f"{prefix}.{VarName}"
self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath)
LoadedSymbols.append(FullName)
elif HasCtypedef:
BaseTypeName = FindBaseType(node.annotation)
_TYPE_QUALIFIERS = {'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'}
if BaseTypeName == 'Callable':
OriginalType = CTypeInfo()
OriginalType.IsFuncPtr = True
OriginalType.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
OriginalType.FuncPtrParams = []
if prefix == prefixes[0]:
self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath)
LoadedSymbols.append(VarName)
FullName = f"{prefix}.{VarName}"
self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath)
LoadedSymbols.append(FullName)
continue
elif BaseTypeName and BaseTypeName not in _TYPE_QUALIFIERS:
CName = CTypeHelper.GetCName(BaseTypeName)
if CName and CName != BaseTypeName:
OriginalType = CName
else:
OriginalType = BaseTypeName[1:] if BaseTypeName.startswith('C') else BaseTypeName
if prefix == prefixes[0]:
self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath)
LoadedSymbols.append(VarName)
FullName = f"{prefix}.{VarName}"
self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath)
LoadedSymbols.append(FullName)
else:
if node.value:
ValueBaseType = FindBaseType(node.value)
_PTR_MODIFIERS = {'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'}
if ValueBaseType and ValueBaseType not in _PTR_MODIFIERS:
CName = CTypeHelper.GetCName(ValueBaseType)
if CName and CName != ValueBaseType:
OriginalType = CName
else:
OriginalType = ValueBaseType[1:] if ValueBaseType.startswith('C') else ValueBaseType
if prefix == prefixes[0]:
self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath)
LoadedSymbols.append(VarName)
FullName = f"{prefix}.{VarName}"
self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath)
LoadedSymbols.append(FullName)
continue
if isinstance(node.value, ast.BinOp) and isinstance(node.value.op, ast.BitOr):
LeftType = self._ResolveTypedefValueType(node.value.left)
RightType = self._ResolveTypedefValueType(node.value.right)
IsPtrType = RightType == 'ptr' or LeftType == 'ptr'
if IsPtrType:
BaseName = LeftType if LeftType != 'ptr' else (RightType if RightType != 'ptr' else '')
if BaseName:
OriginalType = BaseName + ' *'
else:
OriginalType = 'void *'
elif LeftType:
OriginalType = LeftType
elif RightType:
OriginalType = RightType
if OriginalType:
if prefix == prefixes[0]:
self._InsertTypedefSymbol(VarName, 'typedef', OriginalType, node.lineno, FilePath)
LoadedSymbols.append(VarName)
FullName = f"{prefix}.{VarName}"
self._InsertTypedefSymbol(FullName, 'typedef', OriginalType, node.lineno, FilePath)
LoadedSymbols.append(FullName)
continue
if isinstance(node.value, ast.Name):
RefName = node.value.id
if RefName in self:
RefInfo = self[RefName]
if RefInfo and RefInfo.IsTypedef and RefInfo.OriginalType:
if prefix == prefixes[0]:
self._InsertTypedefSymbol(VarName, 'typedef', RefInfo.OriginalType, node.lineno, FilePath)
LoadedSymbols.append(VarName)
FullName = f"{prefix}.{VarName}"
self._InsertTypedefSymbol(FullName, 'typedef', RefInfo.OriginalType, node.lineno, FilePath)
LoadedSymbols.append(FullName)
continue
if prefix == prefixes[0]:
self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath)
LoadedSymbols.append(VarName)
FullName = f"{prefix}.{VarName}"
self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath)
LoadedSymbols.append(FullName)
else:
if prefix == prefixes[0]:
self._InsertTypedefSymbol(VarName, None, None, node.lineno, FilePath)
LoadedSymbols.append(VarName)
FullName = f"{prefix}.{VarName}"
self._InsertTypedefSymbol(FullName, None, None, node.lineno, FilePath)
LoadedSymbols.append(FullName)
elif isinstance(node, ast.FunctionDef):
FuncName = node.name
RetType = self._GetFuncRetTypeStr(node.returns)
ParamTypes = []
for arg in node.args.args:
if arg.annotation:
ParamTypes.append(self._GetFuncParamTypeStr(arg.annotation))
else:
ParamTypes.append('i8*')
FuncIsVariadic = node.args.vararg is not None
FuncIsInline = self._CheckAnnotationHasCInline(node.returns)
if prefix == prefixes[0]:
self._InsertFuncSymbol(FuncName, RetType, ParamTypes, node.lineno, FilePath, FuncIsVariadic, FuncIsInline)
LoadedSymbols.append(FuncName)
FullName = f"{prefix}.{FuncName}"
self._InsertFuncSymbol(FullName, RetType, ParamTypes, node.lineno, FilePath, FuncIsVariadic, FuncIsInline)
LoadedSymbols.append(FullName)
self._InsertModuleSymbol(prefix, lineno, FilePath)
for AnonymousTypeName, AnonymousTypeData in AnonymousTypes.items():
if prefix == prefixes[0]:
self._InsertAnonymousSymbol(AnonymousTypeName, AnonymousTypeData['IsUnion'], AnonymousTypeData['members'], AnonymousTypeData['lineno'], FilePath)
FullTypeName = f"{prefix}.{AnonymousTypeName}"
self._InsertAnonymousSymbol(FullTypeName, AnonymousTypeData['IsUnion'], AnonymousTypeData['members'], AnonymousTypeData['lineno'], FilePath)
if LoadedSymbols:
pass
return LoadedSymbols
except Exception as e:
import traceback
print(traceback.format_exc())
print(f"[SymbolTable Error] Failed to load module: {FilePath} - {e}")
return []
def _GetLLVMTypeStr(self, node):
if node is None:
return 'i32'
if isinstance(node, ast.Name):
if node.id == 'str':
return 'i8*'
elif node.id == 'int':
return 'i32'
elif node.id == 'bool':
return 'i8'
elif node.id == 'float':
return 'double'
elif node.id == 'None':
return 'void'
elif node.id in ('UINT8PTR', 'INT8PTR', 'BYTEPTR'):
return 'i8*'
elif node.id in ('UINT16PTR', 'INT16PTR'):
return 'i16*'
elif node.id in ('UINT32PTR', 'INT32PTR'):
return 'i32*'
elif node.id in ('UINT64PTR', 'INT64PTR'):
return 'i64*'
else:
if node.id in self:
entry = self[node.id]
if entry and hasattr(entry, 'IsTypedef') and entry.IsTypedef and hasattr(entry, 'OriginalType') and entry.OriginalType:
if isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.IsFuncPtr:
return 'i8*'
elif isinstance(entry.OriginalType, CTypeInfo) and entry.OriginalType.BaseType:
return entry.OriginalType.ToString()
elif isinstance(entry.OriginalType, str):
return entry.OriginalType
return 'i32'
elif isinstance(node, ast.Attribute):
attr_name = node.attr if hasattr(node, 'attr') else ''
from lib.includes.t import CTypeRegistry
llvm_str = CTypeRegistry.NameToLLVM(attr_name)
if llvm_str is not None:
return llvm_str
if attr_name in ('CState', 'CDefine', 'CTypedef', 'CExtern', 'CStatic', 'CConst', 'State'):
return ''
if attr_name in ('CCharPtr', 'CIntPtr', 'CVoidPtr', 'CArrayPtr'):
return 'i8*'
if attr_name == 'CVoidPtr':
return 'i8*'
if attr_name and attr_name[0].isupper() and attr_name not in CTypeRegistry._name_to_class:
return f'%struct.{attr_name}*'
if attr_name and attr_name not in CTypeRegistry._name_to_class:
return f'%struct.{attr_name}*'
return 'i32'
elif isinstance(node, ast.Subscript):
if isinstance(node.value, ast.Name) and node.value.id == 'tuple':
slice_node = node.slice
elem_types = []
if isinstance(slice_node, ast.Tuple):
for elt in slice_node.elts:
elem_types.append(self._GetLLVMTypeStr(elt))
else:
elem_types.append(self._GetLLVMTypeStr(slice_node))
if elem_types:
return '{ ' + ', '.join(elem_types) + ' }'
if isinstance(node.value, ast.Name) and node.value.id == 'list':
slice_node = node.slice
if isinstance(slice_node, ast.Tuple) and len(slice_node.elts) >= 1:
elem_type = self._GetLLVMTypeStr(slice_node.elts[0])
else:
elem_type = self._GetLLVMTypeStr(slice_node)
return elem_type + '*'
return 'i32'
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left = self._GetLLVMTypeStr(node.left)
right = self._GetLLVMTypeStr(node.right)
if right and right.endswith('*'):
return right
if left and left.endswith('*'):
return left
if left and left not in ('i32', 'void', 'i64'):
return left
if right and right not in ('i32', 'void', 'i64'):
return right
return left if left else right
elif isinstance(node, ast.Constant):
if isinstance(node.value, bool):
return 'i8'
return 'i32'
elif isinstance(node, ast.Call):
if isinstance(node.func, ast.Attribute):
if hasattr(node.func.value, 'id') and node.func.value.id == 't':
return self._GetLLVMTypeStr(ast.Attribute(value=ast.Name(id='t'), attr=node.func.attr))
return 'i32'
return 'i32'
def _GetFuncRetTypeStr(self, returns_node):
if returns_node is None:
return 'i32'
actual = returns_node
if isinstance(returns_node, ast.BinOp) and isinstance(returns_node.op, ast.BitOr):
left_str = self._GetLLVMTypeStr(returns_node.left)
right_str = self._GetLLVMTypeStr(returns_node.right)
if right_str and right_str.endswith('*'):
return right_str
if left_str and left_str.endswith('*'):
return left_str
if left_str and left_str not in ('i32', 'void', 'i64'):
return left_str
if right_str and right_str not in ('i32', 'void', 'i64'):
return right_str
return left_str
result = self._GetLLVMTypeStr(actual)
return result if result else 'i32'
@staticmethod
def _CheckAnnotationHasCInline(annotation_node) -> bool:
if annotation_node is None:
return False
if isinstance(annotation_node, ast.Attribute):
if hasattr(annotation_node.value, 'id') and annotation_node.value.id == 't' and annotation_node.attr == 'CInline':
return True
if isinstance(annotation_node, ast.Name):
if annotation_node.id == 'CInline':
return True
if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
return SymbolTable._CheckAnnotationHasCInline(annotation_node.left) or SymbolTable._CheckAnnotationHasCInline(annotation_node.right)
return False
def _GetFuncParamTypeStr(self, annotation_node):
if annotation_node is None:
return 'i8*'
actual = annotation_node
if isinstance(annotation_node, ast.BinOp) and isinstance(annotation_node.op, ast.BitOr):
left_str = self._GetLLVMTypeStr(annotation_node.left)
right_str = self._GetLLVMTypeStr(annotation_node.right)
if right_str and right_str.endswith('*'):
return right_str
if left_str and left_str.endswith('*'):
return left_str
if right_str and right_str not in ('i32', 'void', 'i64'):
return right_str
if left_str and left_str not in ('i32', 'void', 'i64'):
return left_str
if left_str and left_str.endswith('*'):
return left_str
return right_str if right_str else left_str
result = self._GetLLVMTypeStr(actual)
return result if result else 'i8*'
def _ResolveTypedefValueType(self, node):
if node is None:
return ''
if isinstance(node, ast.Name):
if node.id in self:
Entry = self[node.id]
if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef and Entry.OriginalType:
return Entry.OriginalType
return ''
if isinstance(node, ast.Attribute):
if isinstance(node.value, ast.Name) and node.value.id == 't':
CName = CTypeHelper.GetCName(node.attr)
if CName and CName == '*':
return 'ptr'
if CName:
return CName
return ''
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_str = self._ResolveTypedefValueType(node.left)
right_str = self._ResolveTypedefValueType(node.right)
if right_str == 'ptr' or (right_str and right_str.endswith('*')):
base = left_str if left_str and left_str != 'ptr' else ''
return base + ' *' if base else 'void *'
if left_str == 'ptr' or (left_str and left_str.endswith('*')):
base = right_str if right_str and right_str != 'ptr' else ''
return base + ' *' if base else 'void *'
if right_str and right_str not in ('ptr', 'void', 'i32', 'i64'):
return right_str
if left_str and left_str not in ('ptr', 'void', 'i32', 'i64'):
return left_str
return left_str if left_str else right_str
return ''
def _InsertClassSymbol(self, FullName: str, TypeKind: str, lineno: int, FilePath: str, members: dict, IsCpythonObject: bool, IsPacked: bool = False):
parts = FullName.split('.')
current = self._root
for i, part in enumerate(parts[:-1]):
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
node = SymbolNode.CreateClass(
name=LastPart,
TypeKind=TypeKind,
members=members,
lineno=lineno,
file=FilePath,
IsCpythonObject=IsCpythonObject,
IsPacked=IsPacked
)
current.AddChild(node)
def _InsertEnumMemberSymbol(self, FullName: str, EnumName: str, lineno: int, FilePath: str):
from lib.core.Handles.HandlesBase import CTypeInfo
parts = FullName.split('.')
current = self._root
for i, part in enumerate(parts[:-1]):
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
info = CTypeInfo()
info.IsEnumMember = True
info.EnumName = EnumName
info.Lineno = lineno
info.file = FilePath
node = SymbolNode(name=LastPart, NodeType='enum_member')
node.attributes = info
current.AddChild(node)
def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass, lineno: int, FilePath: str, members: dict | None = None):
parts = FullName.split('.')
current = self._root
for i, part in enumerate(parts[:-1]):
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
if isinstance(OriginalClass, CTypeInfo):
OriginalType = OriginalClass
elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass):
OriginalType = OriginalClass
if OriginalType == 'CVoid *':
OriginalType = 'void *'
elif OriginalType_kind == 'typedef' and OriginalClass == 'void':
OriginalType = 'void *'
elif OriginalType_kind == 'typedef' and OriginalClass:
OriginalType = OriginalClass
elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str):
OriginalType = f'{OriginalType_kind} {OriginalClass}'
else:
OriginalType = OriginalClass
node = SymbolNode.CreateTypedef(
name=LastPart,
OriginalType=OriginalType,
members=members,
lineno=lineno,
file=FilePath
)
current.AddChild(node)
def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str):
node = SymbolNode.CreateModule(
name=name,
lineno=lineno,
file=FilePath
)
self._root.AddChild(node)
def _InsertFuncSymbol(self, FullName: str, RetType, ParamTypes: list, lineno: int, FilePath: str, IsVariadic: bool = False, IsInline: bool = False):
parts = FullName.split('.')
current = self._root
for i, part in enumerate(parts[:-1]):
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
from lib.core.Handles.HandlesBase import CTypeInfo
info = CTypeInfo()
info.IsFunction = True
if isinstance(RetType, str):
info.FuncPtrReturn = CTypeInfo.FromTypeName(RetType) if RetType else CTypeInfo.VoidTypeInfo()
elif isinstance(RetType, CTypeInfo):
info.FuncPtrReturn = RetType
else:
info.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
info.FuncPtrParams = [(f'arg{i}', pt) for i, pt in enumerate(ParamTypes)]
info.IsVariadic = IsVariadic
info.IsInline = IsInline
if IsInline:
info.Storage = t.CInline()
info.Lineno = lineno
info.file = FilePath
node = SymbolNode(name=LastPart, NodeType='function')
node.attributes = info
current.AddChild(node)
def _InsertDefineSymbol(self, FullName: str, DefineValue, lineno: int, FilePath: str):
parts = FullName.split('.')
current = self._root
for i, part in enumerate(parts[:-1]):
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
from lib.core.Handles.HandlesBase import CTypeInfo
info = CTypeInfo()
info.IsDefine = True
info.DefineValue = DefineValue
info.Lineno = lineno
info.file = FilePath
node = SymbolNode(name=LastPart, NodeType='define')
node.attributes = info
current.AddChild(node)
def _eval_const_expr(self, node):
"""计算常量表达式的值"""
import ast
if isinstance(node, ast.Constant):
return node.value
elif isinstance(node, ast.BinOp):
left = self._eval_const_expr(node.left)
right = self._eval_const_expr(node.right)
if left is None or right is None:
return None
if isinstance(node.op, ast.Add):
return left + right
elif isinstance(node.op, ast.Sub):
return left - right
elif isinstance(node.op, ast.Mult):
return left * right
elif isinstance(node.op, ast.Div):
return left // right if isinstance(left, int) and isinstance(right, int) else left / right
elif isinstance(node.op, ast.FloorDiv):
return left // right
elif isinstance(node.op, ast.Mod):
return left % right
elif isinstance(node.op, ast.Pow):
return left ** right
elif isinstance(node.op, ast.LShift):
return left << right
elif isinstance(node.op, ast.RShift):
return left >> right
elif isinstance(node.op, ast.BitOr):
return left | right
elif isinstance(node.op, ast.BitXor):
return left ^ right
elif isinstance(node.op, ast.BitAnd):
return left & right
elif isinstance(node, ast.UnaryOp):
operand = self._eval_const_expr(node.operand)
if operand is None:
return None
if isinstance(node.op, ast.USub):
return -operand
elif isinstance(node.op, ast.UAdd):
return +operand
elif isinstance(node.op, ast.Invert):
return ~operand
elif isinstance(node, ast.Name):
# 引用其他常量
if node.id in self:
info = self[node.id]
if hasattr(info, 'IsDefine') and info.IsDefine and hasattr(info, 'DefineValue') and info.DefineValue is not None:
return info.DefineValue
return None
def _InsertAnonymousSymbol(self, FullName: str, IsUnion: bool, members: dict, lineno: int, FilePath: str):
parts = FullName.split('.')
current = self._root
for i, part in enumerate(parts[:-1]):
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
node = SymbolNode.CreateAnonymous(
name=LastPart,
IsUnion=IsUnion,
members=members,
lineno=lineno,
file=FilePath
)
current.AddChild(node)
def _FindNode(self, name: str) -> SymbolNode | None:
if '.' not in name:
return self._root.GetChild(name)
parts = name.split('.')
current = self._root
for part in parts:
if current.HasChild(part):
current = current.GetChild(part)
else:
return None
return current
def _InsertNode(self, name: str, attributes: dict | "CTypeInfo"):
from lib.core.Handles.HandlesBase import CTypeInfo
parts = name.split('.')
current = self._root
for part in parts[:-1]:
if not current.HasChild(part):
node = SymbolNode(name=part, NodeType='namespace')
current.AddChild(node)
current = current.GetChild(part)
LastPart = parts[-1]
if isinstance(attributes, CTypeInfo):
node = SymbolNode(name=LastPart, NodeType='type', lineno=attributes.Lineno or 0)
node.attributes = attributes
current.AddChild(node)
return
NodeType = attributes.get('type', 'unknown')
# 根据节点类型使用相应的工厂函数
if NodeType == 'member':
node = SymbolNode.CreateMember(
name=LastPart,
TypeName=attributes.get('type', ''),
IsPtr=attributes.get('IsPtr', False),
dims=attributes.get('dims', []),
lineno=attributes.get('lineno', 0),
file=attributes.get('file', '')
)
elif NodeType == 'typedef':
node = SymbolNode.CreateTypedef(
name=LastPart,
OriginalType=attributes.get('OriginalType', ''),
members=attributes.get('members', None),
lineno=attributes.get('lineno', 0),
file=attributes.get('file', '')
)
elif NodeType == 'module':
node = SymbolNode.CreateModule(
name=LastPart,
lineno=attributes.get('lineno', 0),
file=attributes.get('file', '')
)
elif attributes.get('IsAnonymous'):
node = SymbolNode.CreateAnonymous(
name=LastPart,
IsUnion=NodeType == 'union',
members=attributes.get('members', {}),
lineno=attributes.get('lineno', 0),
file=attributes.get('file', '')
)
else:
# 其他类型struct, union, enum, function, variable 等)
node = SymbolNode.CreateClass(
name=LastPart,
TypeKind=NodeType,
members=attributes.get('members', None),
lineno=attributes.get('lineno', 0),
file=attributes.get('file', ''),
IsCpythonObject=attributes.get('IsCpythonObject', False)
)
# 设置其他属性
for key, value in attributes.items():
if key not in ('type', 'lineno', 'file', 'members', 'IsCpythonObject', 'IsAnonymous'):
node.set(key, value)
current.AddChild(node)
def _CollectKeys(self, node: SymbolNode) -> Iterator[str]:
for name, child in node.children.items():
yield child.name
yield from self._CollectKeys(child)
def _CollectNodes(self, node: SymbolNode) -> Iterator[SymbolNode]:
for child in node.children.values():
yield child
yield from self._CollectNodes(child)