Files
TransPyC/lib/core/SymbolTable.py
2026-06-18 12:42:44 +08:00

935 lines
50 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.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._symbols: Dict[str, CTypeInfo] = {}
def clear(self):
self._symbols.clear()
def get(self, name: str, default=None) -> CTypeInfo:
return self._symbols.get(name, default)
def set(self, name: str, value: Any):
if isinstance(value, CTypeInfo):
self._symbols[name] = value
else:
# 兼容旧代码传入 dict 的情况
info = self._CTypeInfoFromDict(name, value)
self._symbols[name] = info
def update(self, symbols: Dict[str, Any]):
for name, value in symbols.items():
self.set(name, value)
def keys(self) -> Iterator[str]:
return iter(self._symbols.keys())
def values(self) -> Iterator[CTypeInfo]:
return iter(self._symbols.values())
def items(self) -> Iterator[tuple[str, CTypeInfo]]:
return iter(self._symbols.items())
def pop(self, name: str, *args) -> CTypeInfo:
return self._symbols.pop(name, *args)
def __getitem__(self, name: str) -> CTypeInfo:
if name in self._symbols:
return self._symbols[name]
raise KeyError(name)
def __setitem__(self, name: str, value: Any):
self.set(name, value)
def __delitem__(self, name: str):
del self._symbols[name]
def __contains__(self, name: str) -> bool:
return name in self._symbols
def __len__(self) -> int:
return len(self._symbols)
def __iter__(self) -> Iterator[str]:
return iter(self._symbols)
def ToDict(self) -> Dict[str, Any]:
"""序列化为字典格式"""
result = {}
for name, info in self._symbols.items():
entry = {'name': name}
if info.BaseType:
entry['BaseType'] = str(info.BaseType)
if info.PtrCount:
entry['PtrCount'] = info.PtrCount
if info.IsTypedef:
entry['IsTypedef'] = True
if info.IsStruct:
entry['IsStruct'] = True
if info.IsEnum:
entry['IsEnum'] = True
if info.IsUnion:
entry['IsUnion'] = True
if info.IsFunction:
entry['IsFunction'] = True
if info.IsVariable:
entry['IsVariable'] = True
if info.IsDefine:
entry['IsDefine'] = True
if info.OriginalType:
entry['OriginalType'] = str(info.OriginalType)
if info.Lineno:
entry['lineno'] = info.Lineno
if info.file:
entry['file'] = info.file
if info.Members:
entry['members'] = info.Members
extra = info._sm._extra
if extra:
entry.update(extra)
result[name] = entry
return result
def FromDict(self, symbols: Dict[str, Any]):
"""从字典格式反序列化"""
self._symbols.clear()
for name, attrs in symbols.items():
if isinstance(attrs, dict):
info = self._CTypeInfoFromDict(name, attrs)
self._symbols[name] = info
elif isinstance(attrs, CTypeInfo):
self._symbols[name] = attrs
def _CTypeInfoFromDict(self, name: str, attrs: dict) -> CTypeInfo:
"""从旧 dict 格式创建 CTypeInfo兼容旧代码"""
info = CTypeInfo()
info.Name = name
node_type = attrs.get('type', '')
if node_type == 'struct' or attrs.get('IsStruct'):
info.IsStruct = True
elif node_type == 'enum' or attrs.get('IsEnum'):
info.IsEnum = True
elif node_type == 'union' or attrs.get('IsUnion'):
info.IsUnion = True
elif node_type == 'typedef' or attrs.get('IsTypedef'):
info.IsTypedef = True
elif node_type == 'function' or attrs.get('IsFunction'):
info.IsFunction = True
elif node_type == 'variable' or attrs.get('IsVariable'):
info.IsVariable = True
elif node_type == 'define' or attrs.get('IsDefine'):
info.IsDefine = True
elif node_type == 'enum_member' or attrs.get('IsEnumMember'):
info.IsEnumMember = True
if 'PtrCount' in attrs:
info.PtrCount = attrs['PtrCount']
if 'OriginalType' in attrs:
info.OriginalType = attrs['OriginalType']
if 'lineno' in attrs:
info.Lineno = attrs['lineno']
if 'file' in attrs:
info.file = attrs['file']
if 'members' in attrs:
info.Members = attrs['members']
if 'IsPtr' in attrs:
info.IsPtr = attrs['IsPtr']
if 'dims' in attrs:
info.ArrayDims = attrs['dims']
if 'IsCpythonObject' in attrs:
info.IsCpythonObject = attrs['IsCpythonObject']
if 'IsAnonymous' in attrs:
info.IsAnonymous = attrs['IsAnonymous']
if 'IsPacked' in attrs:
info.IsPacked = attrs['IsPacked']
if 'EnumName' in attrs:
info.EnumName = attrs['EnumName']
if 'DefineValue' in attrs:
info.DefineValue = attrs['DefineValue']
# 其他属性存入 _extra
skip_keys = {'type', 'PtrCount', 'OriginalType', 'lineno', 'file',
'members', 'IsPtr', 'dims', 'IsCpythonObject', 'IsAnonymous',
'IsPacked', 'EnumName', 'DefineValue',
'IsStruct', 'IsEnum', 'IsUnion', 'IsTypedef',
'IsFunction', 'IsVariable', 'IsDefine', 'IsEnumMember'}
for key, value in attrs.items():
if key not in skip_keys:
info.set(key, value)
return info
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.type_cls in (t.CStruct, t.CEnum, t.CUnion):
if OrigTypeInfo.type_cls is t.CStruct:
OriginalType_kind = 'struct'
elif OrigTypeInfo.type_cls is t.CEnum:
OriginalType_kind = 'enum'
elif OrigTypeInfo.type_cls 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):
info = CTypeInfo()
info.Lineno = lineno
info.file = FilePath
info.Members = members if members else {}
if TypeKind == 'struct':
info.IsStruct = True
elif TypeKind == 'union':
info.IsUnion = True
elif TypeKind == 'enum':
info.IsEnum = True
elif TypeKind == 'exception':
info.IsStruct = True
info.IsExceptionClass = True
if IsCpythonObject:
info.IsCpythonObject = True
if IsPacked:
info.IsPacked = True
self._symbols[FullName] = info
def _InsertEnumMemberSymbol(self, FullName: str, EnumName: str, lineno: int, FilePath: str):
info = CTypeInfo()
info.IsEnumMember = True
info.EnumName = EnumName
info.Lineno = lineno
info.file = FilePath
self._symbols[FullName] = info
def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass, lineno: int, FilePath: str, members: dict | None = None):
info = CTypeInfo()
info.IsTypedef = True
info.Lineno = lineno
info.file = FilePath
if members:
info.Members = members
if isinstance(OriginalClass, CTypeInfo):
info.OriginalType = OriginalClass
elif OriginalType_kind == 'typedef' and OriginalClass and isinstance(OriginalClass, str) and ('*' in OriginalClass):
OriginalType = OriginalClass
if OriginalType == 'CVoid *':
OriginalType = 'void *'
info.OriginalType = OriginalType
elif OriginalType_kind == 'typedef' and OriginalClass == 'void':
info.OriginalType = 'void *'
elif OriginalType_kind == 'typedef' and OriginalClass:
info.OriginalType = OriginalClass
elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str):
info.OriginalType = f'{OriginalType_kind} {OriginalClass}'
else:
info.OriginalType = OriginalClass
self._symbols[FullName] = info
def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str):
info = CTypeInfo()
info.IsModuleAlias = True
info.Lineno = lineno
info.file = FilePath
self._symbols[name] = info
def _InsertFuncSymbol(self, FullName: str, RetType, ParamTypes: list, lineno: int, FilePath: str, IsVariadic: bool = False, IsInline: bool = False):
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
self._symbols[FullName] = info
def _InsertDefineSymbol(self, FullName: str, DefineValue, lineno: int, FilePath: str):
info = CTypeInfo()
info.IsDefine = True
info.DefineValue = DefineValue
info.Lineno = lineno
info.file = FilePath
self._symbols[FullName] = info
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):
info = CTypeInfo()
if IsUnion:
info.IsUnion = True
else:
info.IsStruct = True
info.IsAnonymous = True
info.Members = members if members else {}
info.Lineno = lineno
info.file = FilePath
self._symbols[FullName] = info