阶段 2 完成

This commit is contained in:
2026-06-18 12:42:44 +08:00
parent 599335e93d
commit f99666420b
19 changed files with 874 additions and 641 deletions

View File

@@ -2,7 +2,6 @@ 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
@@ -45,81 +44,167 @@ def _AnnotationContainsTType(node, TypeName: str) -> bool:
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)
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)
@@ -693,102 +778,70 @@ class SymbolTable:
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
info = CTypeInfo()
info.Lineno = lineno
info.file = FilePath
info.Members = members if members else {}
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)
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
LastPart = parts[-1]
node = SymbolNode.CreateClass(
name=LastPart,
TypeKind=TypeKind,
members=members,
lineno=lineno,
file=FilePath,
IsCpythonObject=IsCpythonObject,
IsPacked=IsPacked
)
current.AddChild(node)
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):
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)
self._symbols[FullName] = info
def _InsertTypedefSymbol(self, FullName: str, OriginalType_kind: str | None, OriginalClass, lineno: int, FilePath: str, members: dict | None = None):
parts = FullName.split('.')
current = self._root
info = CTypeInfo()
info.IsTypedef = True
info.Lineno = lineno
info.file = FilePath
if members:
info.Members = members
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
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':
OriginalType = 'void *'
info.OriginalType = 'void *'
elif OriginalType_kind == 'typedef' and OriginalClass:
OriginalType = OriginalClass
info.OriginalType = OriginalClass
elif OriginalType_kind and OriginalClass and isinstance(OriginalClass, str):
OriginalType = f'{OriginalType_kind} {OriginalClass}'
info.OriginalType = f'{OriginalType_kind} {OriginalClass}'
else:
OriginalType = OriginalClass
node = SymbolNode.CreateTypedef(
name=LastPart,
OriginalType=OriginalType,
members=members,
lineno=lineno,
file=FilePath
)
current.AddChild(node)
info.OriginalType = OriginalClass
self._symbols[FullName] = info
def _InsertModuleSymbol(self, name: str, lineno: int, FilePath: str):
node = SymbolNode.CreateModule(
name=name,
lineno=lineno,
file=FilePath
)
self._root.AddChild(node)
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):
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):
@@ -804,30 +857,15 @@ class SymbolTable:
info.Storage = t.CInline()
info.Lineno = lineno
info.file = FilePath
node = SymbolNode(name=LastPart, NodeType='function')
node.attributes = info
current.AddChild(node)
self._symbols[FullName] = info
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)
self._symbols[FullName] = info
def _eval_const_expr(self, node):
"""计算常量表达式的值"""
@@ -882,117 +920,15 @@ class SymbolTable:
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', '')
)
info = CTypeInfo()
if IsUnion:
info.IsUnion = True
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)
info.IsStruct = True
info.IsAnonymous = True
info.Members = members if members else {}
info.Lineno = lineno
info.file = FilePath
self._symbols[FullName] = info
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)