将 EnumName/value/IsSigned 加入 FIELD_ROUTES,消除所有冗余 hasattr/getattr

This commit is contained in:
2026-06-18 19:09:50 +08:00
parent f99666420b
commit d7b98cc9c5
33 changed files with 1722 additions and 1200 deletions

Binary file not shown.

404
lib/core/ConstEvaluator.py Normal file
View File

@@ -0,0 +1,404 @@
"""统一常量表达式求值器
整合了原先分散在 5 处的常量求值逻辑:
- SymbolTable._eval_const_expr
- CTypeInfo.TryEvalConstExpr
- ConstEvalMixin._try_eval_const_expr
- HandlesAssign._eval_const_expr
- HandlesIf._eval_const_expr
ConstEvaluator 提供三个级别的求值:
1. eval_basic(node) — 纯 AST 常量 + 算术(无外部依赖)
2. eval_with_symtab(node) — + SymbolTable 中的 define 查找
3. eval_full(node, ctx) — + Gen._define_constants / _all_define_constants / 平台宏
"""
from __future__ import annotations
import ast
from typing import Any, Optional
class ConstEvaluator:
"""统一常量表达式求值器"""
# ==================================================================
# Level 1: 纯 AST 常量 + 算术(无外部依赖)
# ==================================================================
@staticmethod
def eval_basic(node: ast.AST) -> Optional[Any]:
"""求值纯常量表达式,不依赖任何外部符号表。
支持: Constant, BinOp, UnaryOp
"""
if isinstance(node, ast.Constant):
return node.value
return ConstEvaluator._eval_arith(node, ConstEvaluator.eval_basic)
# ==================================================================
# Level 2: + SymbolTable define 查找
# ==================================================================
@staticmethod
def eval_with_symtab(node: ast.AST, symtab) -> Optional[Any]:
"""求值常量表达式,支持从 SymbolTable 查找 define 值。
支持: Constant, BinOp, UnaryOp, Name(define), Attribute(define)
"""
if isinstance(node, ast.Constant):
return node.value
if isinstance(node, ast.Name):
if hasattr(symtab, '__contains__') and node.id in symtab:
info = symtab[node.id]
if info.IsDefine and isinstance(info.DefineValue, int):
return info.DefineValue
return None
if isinstance(node, ast.Attribute):
return ConstEvaluator._eval_attribute_define(node, symtab)
return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_with_symtab(n, symtab))
# ==================================================================
# Level 3: + Gen._define_constants / _all_define_constants / 平台宏
# ==================================================================
@staticmethod
def eval_full(node: ast.AST, ctx: 'EvalContext') -> Optional[Any]:
"""完整求值,支持 define_constants、平台宏、BoolOp、Compare。
ctx: EvalContext 实例,封装了 Gen、SymbolTable 等上下文。
"""
# BoolOp (HandlesIf 逻辑)
if isinstance(node, ast.BoolOp):
if isinstance(node.op, ast.And):
for val in node.values:
result = ConstEvaluator.eval_full(val, ctx)
if result is None:
return None
if not result:
return 0
return 1
elif isinstance(node.op, ast.Or):
for val in node.values:
result = ConstEvaluator.eval_full(val, ctx)
if result is None:
return None
if result:
return 1
return 0
return None
# Compare (HandlesIf 逻辑)
if isinstance(node, ast.Compare):
left = ConstEvaluator.eval_full(node.left, ctx)
if left is None:
return None
for op, comparator in zip(node.ops, node.comparators):
right = ConstEvaluator.eval_full(comparator, ctx)
if right is None:
return None
result = ConstEvaluator._eval_compare_op(op, left, right)
if result is None:
return None
if not result:
return 0
left = right
return 1
# Constant — 直接返回原始值bool→0/1 转换由 HandlesIf 自行处理
if isinstance(node, ast.Constant):
return node.value
# Name — 查 define_constants / SymbolTable / 平台宏
if isinstance(node, ast.Name):
return ctx.lookup_name(node.id)
# Attribute — 查 define_constants / SymbolTable / 平台宏
if isinstance(node, ast.Attribute):
return ctx.lookup_attribute(node)
# UnaryOp
if isinstance(node, ast.UnaryOp):
operand = ConstEvaluator.eval_full(node.operand, ctx)
if operand is None:
return None
if isinstance(node.op, ast.Not):
return 1 if not operand else 0
if isinstance(node.op, ast.USub):
return -operand
if isinstance(node.op, ast.UAdd):
return +operand
if isinstance(node.op, ast.Invert):
return ~operand
return None
# BinOp
return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_full(n, ctx))
# ==================================================================
# 内部辅助
# ==================================================================
@staticmethod
def _eval_arith(node: ast.AST, recurse) -> Optional[Any]:
"""通用算术求值BinOp + UnaryOp"""
if isinstance(node, ast.BinOp):
left = recurse(node.left)
right = recurse(node.right)
if left is None or right is None:
return None
return ConstEvaluator._apply_binop(node.op, left, right)
if isinstance(node, ast.UnaryOp):
operand = recurse(node.operand)
if operand is None:
return None
if isinstance(node.op, ast.USub):
return -operand
if isinstance(node.op, ast.UAdd):
return +operand
if isinstance(node.op, ast.Invert):
return ~operand
return None
return None
@staticmethod
def _apply_binop(op: ast.operator, left, right) -> Optional[Any]:
"""应用二元运算符"""
try:
if isinstance(op, ast.Add):
return left + right
elif isinstance(op, ast.Sub):
return left - right
elif isinstance(op, ast.Mult):
return left * right
elif isinstance(op, ast.Div):
return left // right if isinstance(left, int) and isinstance(right, int) else left / right
elif isinstance(op, ast.FloorDiv):
if isinstance(right, (int, float)) and right == 0:
return None
return left // right
elif isinstance(op, ast.Mod):
if isinstance(right, (int, float)) and right == 0:
return None
return left % right
elif isinstance(op, ast.Pow):
return left ** right
elif isinstance(op, ast.LShift):
return left << right
elif isinstance(op, ast.RShift):
return left >> right
elif isinstance(op, ast.BitOr):
return left | right
elif isinstance(op, ast.BitXor):
return left ^ right
elif isinstance(op, ast.BitAnd):
return left & right
except Exception:
return None
return None
@staticmethod
def _eval_compare_op(op, left, right) -> Optional[bool]:
"""应用比较运算符"""
if isinstance(op, ast.Eq):
return left == right
elif isinstance(op, ast.NotEq):
return left != right
elif isinstance(op, ast.Lt):
return left < right
elif isinstance(op, ast.LtE):
return left <= right
elif isinstance(op, ast.Gt):
return left > right
elif isinstance(op, ast.GtE):
return left >= right
return None
@staticmethod
def _eval_attribute_define(node: ast.Attribute, symtab) -> Optional[Any]:
"""从 SymbolTable 查找 Attribute 形式的 define 值"""
parts = []
current = node
while isinstance(current, ast.Attribute):
parts.append(current.attr)
current = current.value
if isinstance(current, ast.Name):
parts.append(current.id)
parts.reverse()
attr_name = parts[-1]
possible_keys = [attr_name, '.'.join(parts)]
for key in possible_keys:
if hasattr(symtab, '__contains__') and key in symtab:
info = symtab[key]
if info.IsDefine and isinstance(info.DefineValue, int):
return info.DefineValue
# 模糊匹配
if len(parts) >= 2:
for mod_key, mod_info in (symtab.items() if hasattr(symtab, 'items') else []):
if mod_info.IsDefine and isinstance(mod_info.DefineValue, int):
if mod_key.endswith('.' + attr_name) or mod_key == attr_name:
return mod_info.DefineValue
return None
@staticmethod
def _intify(val):
"""float → int 转换(仅当 float 值恰好是整数时)"""
if isinstance(val, float) and val == int(val):
return int(val)
return val
class EvalContext:
"""常量求值上下文,封装 Gen / SymbolTable / 平台宏查找逻辑。
由调用方构造并传入 ConstEvaluator.eval_full()。
"""
def __init__(self, Gen=None, symtab=None, platform_macros: dict | None = None):
self.Gen = Gen
self.symtab = symtab
self._platform_macros = platform_macros
def lookup_name(self, name: str) -> Optional[Any]:
"""查找 Name 节点的值define_constants → SymbolTable → 平台宏"""
# 1. Gen._define_constants
if self.Gen and hasattr(self.Gen, '_define_constants') and name in self.Gen._define_constants:
val = self.Gen._define_constants[name]
if isinstance(val, (int, float)):
return ConstEvaluator._intify(val)
# 2. Gen._DefineConstants (大写版本)
if self.Gen and hasattr(self.Gen, '_DefineConstants') and name in self.Gen._DefineConstants:
val = self.Gen._DefineConstants[name]
if isinstance(val, (int, float)):
return ConstEvaluator._intify(val)
# 3. SymbolTable
if self.symtab and name in self.symtab:
info = self.symtab[name]
val = info.value
if isinstance(val, (int, float)):
return ConstEvaluator._intify(val)
if info.IsDefine and isinstance(info.DefineValue, (int, float)):
return ConstEvaluator._intify(info.DefineValue)
# 4. 平台宏
macros = self._get_platform_macros()
if name in macros:
return macros[name]
return None
def lookup_attribute(self, node: ast.Attribute) -> Optional[Any]:
"""查找 Attribute 节点的值"""
module_name = node.value.id if isinstance(node.value, ast.Name) else None
attr_name = node.attr
if module_name and attr_name:
combined_key = f"{module_name}.{attr_name}"
# 1. Gen._define_constants
if self.Gen and hasattr(self.Gen, '_define_constants') and combined_key in self.Gen._define_constants:
val = self.Gen._define_constants[combined_key]
if isinstance(val, (int, float)):
return ConstEvaluator._intify(val)
# 2. SymbolTable (精确匹配 + 后缀匹配)
if self.symtab:
for key, info in self.symtab.items():
if key.endswith(f".{combined_key}") or key == combined_key:
if info.IsDefine and isinstance(info.DefineValue, (int, float)):
return ConstEvaluator._intify(info.DefineValue)
# 3. _all_define_constants
all_dc = self._get_all_define_constants()
if combined_key in all_dc:
val = all_dc[combined_key]
if isinstance(val, (int, float)):
return ConstEvaluator._intify(val)
if attr_name in all_dc:
val = all_dc[attr_name]
if isinstance(val, (int, float)):
return ConstEvaluator._intify(val)
for dc_key, dc_val in all_dc.items():
if dc_key == attr_name or dc_key.endswith(f".{attr_name}"):
if isinstance(dc_val, (int, float)):
return ConstEvaluator._intify(dc_val)
# 4. SymbolTable 短名查找
if self.symtab and attr_name in self.symtab:
info = self.symtab[attr_name]
if info.IsDefine and isinstance(info.DefineValue, (int, float)):
return ConstEvaluator._intify(info.DefineValue)
# 5. Gen._define_constants 短名
if self.Gen and hasattr(self.Gen, '_define_constants') and attr_name in self.Gen._define_constants:
val = self.Gen._define_constants[attr_name]
if isinstance(val, (int, float)):
return ConstEvaluator._intify(val)
# 6. 平台宏
macros = self._get_platform_macros()
full_key = self._get_attr_full_name(node)
if full_key:
if full_key in macros:
return macros[full_key]
short_name = full_key.split('.')[-1] if '.' in full_key else full_key
if short_name in macros:
return macros[short_name]
return None
def _get_all_define_constants(self) -> dict:
"""获取 _all_define_constants"""
if self.Gen and hasattr(self.Gen, '_all_define_constants'):
return self.Gen._all_define_constants
return {}
def _get_platform_macros(self) -> dict:
"""获取平台宏"""
if self._platform_macros is not None:
return self._platform_macros
if not self.Gen:
return {}
macros = {}
pi = getattr(self.Gen, '_platform_info', {})
ptr_size = getattr(self.Gen, 'ptr_size', 8)
if pi.get('is_windows'):
macros['_WIN32'] = 1
if not pi.get('is_32bit'):
macros['_WIN64'] = 1
macros['WIN64'] = 1
macros['WIN32'] = 1
if pi.get('is_linux'):
macros['__linux__'] = 1
if pi.get('is_macos'):
macros['__APPLE__'] = 1
macros['__MACH__'] = 1
if pi.get('is_x86_64'):
macros['__x86_64__'] = 1
macros['__x86_64'] = 1
macros['_M_X64'] = 1
elif pi.get('is_arm64'):
macros['__aarch64__'] = 1
macros['_M_ARM64'] = 1
if not pi.get('is_32bit') and pi.get('is_linux'):
macros['__LP64__'] = 1
elif pi.get('is_32bit'):
macros['_ILP32'] = 1
macros['SIZEOF_VOID_P'] = ptr_size
macros['__SIZEOF_POINTER__'] = ptr_size
macros['NDEBUG'] = 0
return macros
@staticmethod
def _get_attr_full_name(node: ast.Attribute) -> Optional[str]:
"""从 Attribute 节点提取完整名称 (e.g. 'module.name')"""
parts = []
current = node
while isinstance(current, ast.Attribute):
parts.append(current.attr)
current = current.value
if isinstance(current, ast.Name):
parts.append(current.id)
parts.reverse()
return '.'.join(parts) if parts else None

View File

@@ -0,0 +1,79 @@
"""诊断系统 — 收集编译过程中的警告和错误
替代原先静默回退的模式:
- return 'i32' → 记录 Warning + 回退到 'i32'
- return [] → 记录 Error + 回退到 []
使用方式:
diag = DiagnosticCollector()
diag.warn(file, lineno, "无法解析类型,回退到 i32")
diag.error(file, lineno, f"加载模块失败: {path}")
diag.report() # 打印所有诊断信息
"""
from __future__ import annotations
import os
from dataclasses import dataclass, field
from enum import Enum
from typing import List, Optional
class DiagnosticLevel(Enum):
WARNING = "WARNING"
ERROR = "ERROR"
@dataclass
class Diagnostic:
level: DiagnosticLevel
file: str
lineno: int
message: str
def __str__(self):
short_file = os.path.basename(self.file) if self.file else "<unknown>"
return f"[{self.level.value}] {short_file}:{self.lineno}{self.message}"
class DiagnosticCollector:
"""诊断信息收集器"""
def __init__(self):
self._diagnostics: List[Diagnostic] = []
def warn(self, file: str, lineno: int, message: str):
self._diagnostics.append(Diagnostic(DiagnosticLevel.WARNING, file, lineno, message))
def error(self, file: str, lineno: int, message: str):
self._diagnostics.append(Diagnostic(DiagnosticLevel.ERROR, file, lineno, message))
@property
def warnings(self) -> List[Diagnostic]:
return [d for d in self._diagnostics if d.level == DiagnosticLevel.WARNING]
@property
def errors(self) -> List[Diagnostic]:
return [d for d in self._diagnostics if d.level == DiagnosticLevel.ERROR]
@property
def has_errors(self) -> bool:
return any(d.level == DiagnosticLevel.ERROR for d in self._diagnostics)
@property
def has_warnings(self) -> bool:
return any(d.level == DiagnosticLevel.WARNING for d in self._diagnostics)
def report(self, min_level: DiagnosticLevel = DiagnosticLevel.WARNING):
"""打印所有诊断信息"""
for d in self._diagnostics:
if d.level.value >= min_level.value:
print(d)
def clear(self):
self._diagnostics.clear()
def __len__(self):
return len(self._diagnostics)
def __bool__(self):
return len(self._diagnostics) > 0

View File

@@ -82,7 +82,7 @@ class AnnAssignHandle(BaseHandle):
IsUnion = False
if ClassName and ClassName in self.Trans.SymbolTable:
TypeInfo = self.Trans.SymbolTable[ClassName]
if hasattr(TypeInfo, 'IsUnion') and TypeInfo.IsUnion:
if TypeInfo.IsUnion:
IsUnion = True
if ClassName and ClassName in Gen.structs:
ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value)

View File

@@ -440,8 +440,8 @@ class AssignHandle:
sym_key = f"{ModulePath}.{FuncName}"
sym_info = self.Trans.SymbolTable.get(sym_key)
if sym_info and sym_info.IsFunction:
ret_type_info = getattr(sym_info, 'FuncPtrReturn', None)
param_type_infos = [pt for _, pt in getattr(sym_info, 'FuncPtrParams', [])]
ret_type_info = sym_info.FuncPtrReturn
param_type_infos = [pt for _, pt in (sym_info.FuncPtrParams or [])]
if ret_type_info:
if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType:
ret_type = ret_type_info.ToLLVM(Gen)
@@ -616,7 +616,7 @@ class AssignHandle:
if ClassName and ClassName in Gen.structs:
PropKey = f'{ClassName}.{AttrName}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList:
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList:
SelfVar = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
@@ -734,7 +734,7 @@ class AssignHandle:
if ClassName and ClassName in Gen.structs:
PropKey = f'{ClassName}.{AttrName}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList:
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_SETTER in PropInfo.MetaList:
ObjVal = self.Trans.ExprHandler.HandleExprLlvm(Target.value)
SetterFunc = Gen._get_function(PropKey + '$set')
if SetterFunc and ObjVal:
@@ -1222,7 +1222,7 @@ class AssignHandle:
elif isinstance(count_node, ast.Name):
if count_node.id in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[count_node.id]
if isinstance(getattr(SymInfo, 'value', None), int):
if isinstance(SymInfo.value, int):
ArrayCount = SymInfo.value
if ArrayCount == 1 and count_node.id in getattr(Gen, '_define_constants', {}):
DefVal = Gen._define_constants[count_node.id]
@@ -1558,94 +1558,10 @@ class AssignHandle:
Gen.variables[VarName] = GlobalVar
def _eval_const_expr(self, node, Gen):
"""计算常量表达式的值"""
import ast
if isinstance(node, ast.Constant):
return node.value
elif isinstance(node, ast.BinOp):
left = self._eval_const_expr(node.left, Gen)
right = self._eval_const_expr(node.right, Gen)
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, Gen)
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 getattr(Gen, '_define_constants', {}):
return Gen._define_constants[node.id]
if node.id in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[node.id]
val = getattr(SymInfo, 'value', None)
if isinstance(val, (int, float)):
return val
if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)):
return SymInfo.DefineValue
elif isinstance(node, ast.Attribute):
module_name = node.value.id if isinstance(node.value, ast.Name) else None
attr_name = node.attr
if module_name and attr_name:
combined_key = f"{module_name}.{attr_name}"
if combined_key in getattr(Gen, '_define_constants', {}):
val = Gen._define_constants[combined_key]
if isinstance(val, (int, float)):
return int(val) if isinstance(val, float) and val == int(val) else val
for key, SymInfo in self.Trans.SymbolTable.items():
if key.endswith(f".{combined_key}") or key == combined_key:
if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)):
return int(SymInfo.DefineValue) if isinstance(SymInfo.DefineValue, float) and SymInfo.DefineValue == int(SymInfo.DefineValue) else SymInfo.DefineValue
all_dc = getattr(self.Trans, '_all_define_constants', None) or getattr(Gen, '_all_define_constants', {})
if combined_key in all_dc:
val = all_dc[combined_key]
if isinstance(val, (int, float)):
return int(val) if isinstance(val, float) and val == int(val) else val
if attr_name in all_dc:
val = all_dc[attr_name]
if isinstance(val, (int, float)):
return int(val) if isinstance(val, float) and val == int(val) else val
for dc_key, dc_val in all_dc.items():
if dc_key == attr_name or dc_key.endswith(f".{attr_name}"):
if isinstance(dc_val, (int, float)):
return int(dc_val) if isinstance(dc_val, float) and dc_val == int(dc_val) else dc_val
if attr_name in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[attr_name]
if getattr(SymInfo, 'IsDefine', None) and isinstance(getattr(SymInfo, 'DefineValue', None), (int, float)):
return int(SymInfo.DefineValue) if isinstance(SymInfo.DefineValue, float) and SymInfo.DefineValue == int(SymInfo.DefineValue) else SymInfo.DefineValue
if attr_name in getattr(Gen, '_define_constants', {}):
val = Gen._define_constants[attr_name]
if isinstance(val, (int, float)):
return int(val) if isinstance(val, float) and val == int(val) else val
return None
"""计算常量表达式的值(委托到 ConstEvaluator"""
from lib.core.ConstEvaluator import ConstEvaluator, EvalContext
ctx = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable)
return ConstEvaluator.eval_full(node, ctx)
def _eval_global_count(self, node, Gen):
val = self._eval_const_expr(node, Gen)

View File

@@ -395,74 +395,8 @@ class CTypeInfo:
@staticmethod
def TryEvalConstExpr(node, SymbolTable):
if isinstance(node, ast.Constant) and isinstance(node.value, int):
return node.value
if isinstance(node, ast.BinOp):
left = CTypeInfo.TryEvalConstExpr(node.left, SymbolTable)
right = CTypeInfo.TryEvalConstExpr(node.right, SymbolTable)
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.FloorDiv):
return left // right if right != 0 else None
elif isinstance(node.op, ast.Mod):
return left % right if right != 0 else None
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.BitAnd):
return left & right
elif isinstance(node.op, ast.BitXor):
return left ^ right
elif isinstance(node.op, ast.Pow):
return left ** right
return None
if isinstance(node, ast.UnaryOp):
operand = CTypeInfo.TryEvalConstExpr(node.operand, SymbolTable)
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
return None
if isinstance(node, ast.Name):
if node.id in SymbolTable:
info = SymbolTable[node.id]
if getattr(info, 'IsDefine', None) and isinstance(getattr(info, 'DefineValue', None), int):
return info.DefineValue
if isinstance(node, ast.Attribute):
parts = []
current = node
while isinstance(current, ast.Attribute):
parts.append(current.attr)
current = current.value
if isinstance(current, ast.Name):
parts.append(current.id)
parts.reverse()
attr_name = parts[-1]
possible_keys = [attr_name, '.'.join(parts)]
for key in possible_keys:
if key in SymbolTable:
info = SymbolTable[key]
if getattr(info, 'IsDefine', None) and isinstance(getattr(info, 'DefineValue', None), int):
return info.DefineValue
if len(parts) >= 2:
for mod_key, mod_info in SymbolTable.items():
if getattr(mod_info, 'IsDefine', None) and isinstance(getattr(mod_info, 'DefineValue', None), int):
if mod_key.endswith('.' + attr_name) or mod_key == attr_name:
return mod_info.DefineValue
return None
from lib.core.ConstEvaluator import ConstEvaluator
return ConstEvaluator.eval_with_symtab(node, SymbolTable)
@classmethod
def FromNode(cls, Node: ast.AST, SymbolTable: dict) -> "CTypeInfo":
@@ -1136,10 +1070,6 @@ class CTypeInfo:
NewInfo._ts.original_type = NewInfo._ts.original_type.Copy()
if NewInfo._ts.array_ptr:
NewInfo._ts.array_ptr = NewInfo._ts.array_ptr.Copy()
# 实例上的动态属性也需要拷贝(如 IsSigned 等)
for key, val in self.__dict__.items():
if key not in ('_ts', '_sm'):
object.__setattr__(NewInfo, key, val)
return NewInfo
def get(self, key, default=None):

View File

@@ -40,7 +40,7 @@ class DeleteHandle(BaseHandle):
if ClassName:
PropKey = f'{ClassName}.{AttrName}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
SelfVar = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
@@ -54,7 +54,7 @@ class DeleteHandle(BaseHandle):
if ClassName:
PropKey = f'{ClassName}.{AttrName}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_DELETER in PropInfo.MetaList:
obj_val = self.Trans.ExprHandler.HandleExprLlvm(target.value)
if obj_val:
DeleterFunc = Gen._get_function(PropKey + '$del')

View File

@@ -329,7 +329,7 @@ class ExprHandle(BaseHandle):
if VarName not in getattr(Gen, '_define_constants', {}):
try:
sym_info = self.translator.SymbolTable.get(VarName)
if sym_info and getattr(sym_info, 'IsDefine', None) and getattr(sym_info, 'DefineValue', None) is not None:
if sym_info and sym_info.IsDefine and sym_info.DefineValue is not None:
val = sym_info.DefineValue
if isinstance(val, int):
# Use VarType hint if available
@@ -400,9 +400,9 @@ class ExprHandle(BaseHandle):
return ir.Constant(ir.IntType(32), 1 if VarName == 'True' else 0)
if VarName in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[VarName]
if getattr(SymInfo, 'IsEnumMember', None) and isinstance(getattr(SymInfo, 'value', None), int):
if SymInfo.IsEnumMember and isinstance(SymInfo.value, int):
return ir.Constant(ir.IntType(32), SymInfo.value)
if getattr(SymInfo, 'IsFunction', False) or getattr(SymInfo, 'IsFuncPtr', False):
if SymInfo.IsFunction or SymInfo.IsFuncPtr:
MangledName = Gen._mangle_func_name(VarName)
if MangledName in Gen.module.globals:
g = Gen.module.globals[MangledName]

View File

@@ -92,7 +92,7 @@ class ExprAttrHandle(BaseHandle):
PossibleKeys.append(key)
for lookup_key in PossibleKeys:
SymInfo = self.Trans.SymbolTable.get(lookup_key)
if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None:
if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None:
return self._make_define_constant(Gen, SymInfo.DefineValue)
# 也检查 _define_constants
define_constants = getattr(Gen, '_define_constants', {})
@@ -202,7 +202,7 @@ class ExprAttrHandle(BaseHandle):
# 检查 property getter
PropKey = f'{ClassName}.{Node.attr}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList:
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList:
SelfVar = Gen._get_var_ptr('self')
if SelfVar:
SelfPtr = Gen._load(SelfVar, name="self")
@@ -234,16 +234,16 @@ class ExprAttrHandle(BaseHandle):
def _handle_attr_enum(self, Node, VarName):
"""处理枚举成员访问 (VarName 是枚举类型名)"""
SymInfo = self.Trans.SymbolTable.get(VarName)
if not SymInfo or not getattr(SymInfo, 'IsEnum', None):
if not SymInfo or not SymInfo.IsEnum:
return None
if Node.attr in self.Trans.SymbolTable:
MemberInfo = self.Trans.SymbolTable[Node.attr]
if getattr(MemberInfo, 'IsEnumMember', None) and getattr(MemberInfo, 'EnumName', None) == VarName:
if isinstance(getattr(MemberInfo, 'value', None), int):
if MemberInfo.IsEnumMember and MemberInfo.EnumName == VarName:
if isinstance(MemberInfo.value, int):
return ir.Constant(ir.IntType(32), MemberInfo.value)
for key, info in self.Trans.SymbolTable.items():
if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == VarName and key == Node.attr:
if isinstance(getattr(info, 'value', None), int):
if info.IsEnumMember and info.EnumName == VarName and key == Node.attr:
if isinstance(info.value, int):
return ir.Constant(ir.IntType(32), info.value)
return None
@@ -285,7 +285,7 @@ class ExprAttrHandle(BaseHandle):
# 检查 property getter
PropKey = f'{ClassName}.{AttrName}'
PropInfo = self.Trans.SymbolTable.get(PropKey)
if PropInfo and hasattr(PropInfo, 'MetaList') and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList:
if PropInfo and PropInfo.MetaList and FuncMeta.PROPERTY_GETTER in PropInfo.MetaList:
ObjVal = self.HandleExprLlvm(Node.value)
GetterFunc = Gen._get_function(PropKey)
if GetterFunc and ObjVal:
@@ -297,7 +297,7 @@ class ExprAttrHandle(BaseHandle):
TypeInfo = self.Trans.SymbolTable.get(ClassName)
IsUnion = TypeInfo.IsUnion if TypeInfo else False
IsCenum = TypeInfo.IsEnum if TypeInfo else False
IsRenum = getattr(TypeInfo, 'IsRenum', False) if TypeInfo else False
IsRenum = TypeInfo.IsRenum if TypeInfo else False
# REnum 处理
if IsRenum:
@@ -322,12 +322,12 @@ class ExprAttrHandle(BaseHandle):
for qname in (f"{ClassName}.{AttrName}", f"{ClassName}_{AttrName}"):
if qname in self.Trans.SymbolTable:
info = self.Trans.SymbolTable[qname]
if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int):
if info.IsEnumMember and isinstance(info.value, int):
return ir.Constant(ir.IntType(32), info.value)
for key, info in self.Trans.SymbolTable.items():
if key == AttrName:
if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == ClassName:
if isinstance(getattr(info, 'value', None), int):
if info.IsEnumMember and info.EnumName == ClassName:
if isinstance(info.value, int):
return ir.Constant(ir.IntType(32), info.value)
break
@@ -1062,7 +1062,7 @@ class ExprAttrHandle(BaseHandle):
possible_keys.append(key)
for lookup_key in possible_keys:
SymInfo = self.Trans.SymbolTable.get(lookup_key)
if SymInfo and getattr(SymInfo, 'IsDefine', None) and getattr(SymInfo, 'DefineValue', None) is not None:
if SymInfo and SymInfo.IsDefine and SymInfo.DefineValue is not None:
val = SymInfo.DefineValue
if isinstance(val, int):
if val > 0x7FFFFFFF or val < -0x80000000:
@@ -1085,21 +1085,21 @@ class ExprAttrHandle(BaseHandle):
for enum_key in enum_keys:
if enum_key in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[enum_key]
if getattr(SymInfo, 'IsEnum', None):
if SymInfo.IsEnum:
for qname in (f"{enum_key}.{member_name}", f"{enum_key}_{member_name}"):
if qname in self.Trans.SymbolTable:
info = self.Trans.SymbolTable[qname]
if getattr(info, 'IsEnumMember', None) and isinstance(getattr(info, 'value', None), int):
if info.IsEnumMember and isinstance(info.value, int):
return ir.Constant(ir.IntType(32), info.value)
for key, info in self.Trans.SymbolTable.items():
if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_key and key == member_name:
if isinstance(getattr(info, 'value', None), int):
if info.IsEnumMember and info.EnumName == enum_key and key == member_name:
if isinstance(info.value, int):
return ir.Constant(ir.IntType(32), info.value)
for key, info in self.Trans.SymbolTable.items():
if getattr(info, 'IsEnumMember', None) and key == member_name:
if isinstance(getattr(info, 'value', None), int):
if info.IsEnumMember and key == member_name:
if isinstance(info.value, int):
for enum_key in enum_keys:
if getattr(info, 'EnumName', None) == enum_key:
if info.EnumName == enum_key:
return ir.Constant(ir.IntType(32), info.value)
return None

View File

@@ -539,7 +539,7 @@ class ExprBuiltinHandle(BaseHandle):
LastPart = arg.attr
if LastPart in self.Trans.SymbolTable:
AttrInfo = self.Trans.SymbolTable[LastPart]
if getattr(AttrInfo, 'IsEnumMember', None) and getattr(AttrInfo, 'EnumName', None):
if AttrInfo.IsEnumMember and AttrInfo.EnumName:
enum_type_name = AttrInfo.EnumName
elif isinstance(arg.value, ast.Attribute):
attr_path = _get_attr_path(arg)
@@ -554,14 +554,14 @@ class ExprBuiltinHandle(BaseHandle):
for qname in (qualified_name_dot, qualified_name_under):
if qname in self.Trans.SymbolTable:
info = self.Trans.SymbolTable[qname]
if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_class_name:
if info.IsEnumMember and info.EnumName == enum_class_name:
enum_member_found = info
break
if not enum_member_found:
for key in self.Trans.SymbolTable:
if key == LastPart:
info = self.Trans.SymbolTable[key]
if getattr(info, 'IsEnumMember', None) and getattr(info, 'EnumName', None) == enum_class_name:
if info.IsEnumMember and info.EnumName == enum_class_name:
enum_member_found = info
break
if enum_member_found:

View File

@@ -435,7 +435,7 @@ class ExprCallHandle(BaseHandle):
if first_part in aliases:
ModulePath = aliases[first_part] + ModulePath[len(first_part):]
is_instance_var = isinstance(Node.func.value, ast.Name) and Node.func.value.id in Gen.var_struct_class and Node.func.value.id not in Gen.ModuleSha1Map
is_class_name = isinstance(Node.func.value, ast.Name) and (Node.func.value.id in Gen.structs or (Node.func.value.id in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[Node.func.value.id], 'IsStruct', False)))
is_class_name = isinstance(Node.func.value, ast.Name) and (Node.func.value.id in Gen.structs or (Node.func.value.id in self.Trans.SymbolTable and self.Trans.SymbolTable[Node.func.value.id].IsStruct))
if is_instance_var and not is_class_name:
return self._HandleMethodCallLlvm(Node)
FuncAttr = Node.func.attr
@@ -454,11 +454,11 @@ class ExprCallHandle(BaseHandle):
result = self._HandleClassNewLlvm(Node, FuncAttr)
if result is not None:
return result
if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None):
if SymInfo.IsEnumMember and SymInfo.EnumName:
EnumName = SymInfo.EnumName
if EnumName in self.Trans.SymbolTable:
EnumInfo = self.Trans.SymbolTable[EnumName]
if getattr(EnumInfo, 'IsRenum', False):
if EnumInfo.IsRenum:
result = self._HandleREnumConstructLlvm(Node, EnumName, FuncAttr, SymInfo.value)
if result is not None:
return result
@@ -480,9 +480,9 @@ class ExprCallHandle(BaseHandle):
FullAttrKey = f"{ModulePath}.{FuncAttr}"
if FullAttrKey in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[FullAttrKey]
if getattr(SymInfo, 'IsTypedef', False):
if SymInfo.IsTypedef:
return ir.Constant(ir.IntType(32), 0)
if getattr(SymInfo, 'IsStruct', False):
if SymInfo.IsStruct:
if FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr)
if FuncAttr in Gen.structs:
@@ -533,7 +533,7 @@ class ExprCallHandle(BaseHandle):
raise Exception(f"Undefined method: 't.{FuncAttr}'")
if isinstance(Node.func.value, ast.Attribute):
inner_attr = Node.func.value.attr
if inner_attr in Gen.structs or (inner_attr in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[inner_attr], 'IsStruct', False)):
if inner_attr in Gen.structs or (inner_attr in self.Trans.SymbolTable and self.Trans.SymbolTable[inner_attr].IsStruct):
static_result = self._HandleStaticMethodCallLlvm(Node, inner_attr, FuncAttr)
if static_result is not None:
return static_result
@@ -569,11 +569,11 @@ class ExprCallHandle(BaseHandle):
if FuncAttr and ModulePath and ModulePath not in {'t', 'c'}:
# 先检查 FuncAttr 是否是函数/变量,如果是则跳过 struct 声明
_attr_sym = self.Trans.SymbolTable.get(FuncAttr)
_is_func_or_var = _attr_sym and (getattr(_attr_sym, 'IsFunction', False) or getattr(_attr_sym, 'IsVariable', False))
_is_func_or_var = _attr_sym and (_attr_sym.IsFunction or _attr_sym.IsVariable)
if not _is_func_or_var and ModulePath:
_full_key = f"{ModulePath}.{FuncAttr}"
_full_sym = self.Trans.SymbolTable.get(_full_key)
if _full_sym and (getattr(_full_sym, 'IsFunction', False) or getattr(_full_sym, 'IsVariable', False)):
if _full_sym and (_full_sym.IsFunction or _full_sym.IsVariable):
_is_func_or_var = True
# 优先检查 FuncAttr 是否为 struct/类构造器
if not _is_func_or_var and FuncAttr not in Gen.structs:
@@ -587,7 +587,7 @@ class ExprCallHandle(BaseHandle):
FullAttrKey = f"{ModulePath}.{FuncAttr}"
if FullAttrKey in self.Trans.SymbolTable:
FullSymInfo = self.Trans.SymbolTable[FullAttrKey]
if getattr(FullSymInfo, 'IsStruct', False) or getattr(FullSymInfo, 'IsCpythonObject', False):
if FullSymInfo.IsStruct or FullSymInfo.IsCpythonObject:
if FuncAttr not in Gen.structs:
self._ensure_struct_declared(FuncAttr)
if FuncAttr in Gen.structs:
@@ -649,7 +649,7 @@ class ExprCallHandle(BaseHandle):
Gen = self.Trans.LlvmGen
# 如果名称是函数或变量,不应创建 struct
SymInfo = self.Trans.SymbolTable.get(class_name)
if SymInfo and (getattr(SymInfo, 'IsFunction', False) or getattr(SymInfo, 'IsVariable', False)):
if SymInfo and (SymInfo.IsFunction or SymInfo.IsVariable):
return
if class_name in Gen.structs:
existing = Gen.structs[class_name]
@@ -721,16 +721,16 @@ class ExprCallHandle(BaseHandle):
SymKey = f'{ClassName}.{MethodName}'
SymInfo = self.Trans.SymbolTable.get(SymKey) or self.Trans.SymbolTable.get(MethodName)
if SymInfo and SymInfo.IsFunction:
ret_type_info = getattr(SymInfo, 'FuncPtrReturn', None)
ret_type_info = SymInfo.FuncPtrReturn
if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType:
ret_type = ret_type_info.ToLLVM(Gen)
else:
ret_type = Gen._CType2LLVM('i32', False)
param_type_infos = [pt for _, pt in (getattr(SymInfo, 'FuncPtrParams', None) or [])]
param_type_infos = [pt for _, pt in (SymInfo.FuncPtrParams or [])]
if isinstance(ret_type, ir.VoidType):
ret_type = ir.IntType(32)
llvm_param_types = []
is_static = hasattr(SymInfo, 'MetaList') and FuncMeta.STATIC_METHOD in SymInfo.MetaList
is_static = FuncMeta.STATIC_METHOD in SymInfo.MetaList
if ClassName in Gen.structs and not is_static:
llvm_param_types.append(ir.PointerType(Gen.structs[ClassName]))
for pt in param_type_infos:
@@ -762,8 +762,8 @@ class ExprCallHandle(BaseHandle):
CallArgs = []
SymKey = f'{ClassName}.{MethodName}'
SymInfo = self.Trans.SymbolTable.get(SymKey) or self.Trans.SymbolTable.get(MethodName)
is_static_call = SymInfo is not None and hasattr(SymInfo, 'MetaList') and FuncMeta.STATIC_METHOD in SymInfo.MetaList
is_classmethod_call = SymInfo is not None and hasattr(SymInfo, 'MetaList') and FuncMeta.CLASS_METHOD in SymInfo.MetaList
is_static_call = SymInfo is not None and FuncMeta.STATIC_METHOD in SymInfo.MetaList
is_classmethod_call = SymInfo is not None and FuncMeta.CLASS_METHOD in SymInfo.MetaList
# @classmethod: 在参数列表前插入 cls栈上分配的类实例指针
if is_classmethod_call and ClassName in Gen.structs:
ClsPtr = Gen._alloca(Gen.structs[ClassName], name=f"cls_{ClassName}")
@@ -1230,13 +1230,13 @@ class ExprCallHandle(BaseHandle):
mangled_name = Gen._mangle_func_name(func_name, ModulePath)
sym_key = f'{ModulePath}.{func_name}'
sym_info = self.Trans.SymbolTable.get(sym_key) or self.Trans.SymbolTable.get(func_name)
is_inline = sym_info and (getattr(sym_info, 'IsInline', False) or isinstance(getattr(sym_info, 'Storage', None), t.CInline))
if is_inline and getattr(sym_info, 'InlineBody', None):
is_inline = sym_info and (sym_info.IsInline or isinstance(sym_info.Storage, t.CInline))
if is_inline and sym_info.InlineBody:
self._HandleInlineExpandLlvm(Node, sym_info)
return ir.Constant(ir.IntType(32), 1)
sym_info_exact = self.Trans.SymbolTable.get(sym_key)
if sym_info_exact:
exact_params = getattr(sym_info_exact, 'FuncPtrParams', [])
exact_params = sym_info_exact.FuncPtrParams
exact_param_names = [pn for pn, _ in exact_params]
if exact_param_names:
provided = len(Node.args)
@@ -1280,15 +1280,15 @@ class ExprCallHandle(BaseHandle):
if not sym_info:
sym_info = self.Trans.SymbolTable.get(func_name)
if sym_info:
is_func = getattr(sym_info, 'IsFunction', False)
sym_is_variadic = getattr(sym_info, 'IsVariadic', False)
is_func = sym_info.IsFunction
sym_is_variadic = sym_info.IsVariadic
if is_func:
ret_type_info = getattr(sym_info, 'FuncPtrReturn', None)
ret_type_info = sym_info.FuncPtrReturn
if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType:
ret_type = ret_type_info.ToLLVM(Gen)
else:
ret_type = Gen._CType2LLVM('i32', False)
sym_params = getattr(sym_info, 'FuncPtrParams', [])
sym_params = sym_info.FuncPtrParams
param_type_infos = [pt for _, pt in sym_params]
if isinstance(ret_type, ir.VoidType):
ret_type = ir.IntType(32)
@@ -1411,15 +1411,15 @@ class ExprCallHandle(BaseHandle):
if not sym_info:
sym_info = self.Trans.SymbolTable.get(func_name)
if sym_info:
is_func = getattr(sym_info, 'IsFunction', False)
sym_is_variadic = getattr(sym_info, 'IsVariadic', False)
is_func = sym_info.IsFunction
sym_is_variadic = sym_info.IsVariadic
if is_func:
ret_type_info = getattr(sym_info, 'FuncPtrReturn', None)
ret_type_info = sym_info.FuncPtrReturn
if isinstance(ret_type_info, CTypeInfo) and ret_type_info.BaseType:
ret_type = ret_type_info.ToLLVM(Gen)
else:
ret_type = Gen._CType2LLVM('i32', False)
param_type_infos = [pt for _, pt in getattr(sym_info, 'FuncPtrParams', [])]
param_type_infos = [pt for _, pt in sym_info.FuncPtrParams]
if isinstance(ret_type, ir.VoidType):
ret_type = ir.IntType(32)
llvm_param_types = []
@@ -1830,7 +1830,7 @@ class ExprCallHandle(BaseHandle):
if ClassName:
SymKey = f'{ClassName}.{MethodName}'
SymInfo = self.Trans.SymbolTable.get(SymKey)
if SymInfo and hasattr(SymInfo, 'MetaList'):
if SymInfo and SymInfo.MetaList:
if FuncMeta.STATIC_METHOD in SymInfo.MetaList:
return self._HandleStaticMethodCallLlvm(Node, ClassName, MethodName)
if FuncMeta.CLASS_METHOD in SymInfo.MetaList:

View File

@@ -73,7 +73,7 @@ class IfHandle(BaseHandle):
return True
if name in self.Trans.SymbolTable:
info = self.Trans.SymbolTable[name]
if getattr(info, 'IsDefine', False):
if info.IsDefine:
return True
platform_macros = self._get_platform_macros()
return name in platform_macros
@@ -86,8 +86,8 @@ class IfHandle(BaseHandle):
return val
if name in self.Trans.SymbolTable:
info = self.Trans.SymbolTable[name]
if getattr(info, 'IsDefine', False):
val = getattr(info, 'DefineValue', 0)
if info.IsDefine:
val = info.DefineValue
if isinstance(val, (int, float)):
return val
platform_macros = self._get_platform_macros()
@@ -129,118 +129,21 @@ class IfHandle(BaseHandle):
return macros
def _eval_const_expr(self, node):
if isinstance(node, ast.Constant):
val = node.value
if isinstance(val, bool):
return 1 if val else 0
if isinstance(val, int):
return val
if isinstance(val, float):
return 1 if val != 0.0 else 0
return 0
if isinstance(node, ast.Name):
name = node.id
val = self._get_macro_value(name)
if val is not None:
return val
return None
if isinstance(node, ast.Attribute):
full_key = self._get_attr_full_name(node)
if full_key:
val = self._get_macro_value(full_key)
if val is not None:
return val
short_name = full_key.split('.')[-1] if '.' in full_key else full_key
val = self._get_macro_value(short_name)
if val is not None:
return val
return None
if isinstance(node, ast.UnaryOp):
operand = self._eval_const_expr(node.operand)
if operand is None:
return None
if isinstance(node.op, ast.Not):
return 1 if not operand else 0
if isinstance(node.op, ast.USub):
return -operand
if isinstance(node.op, ast.Invert):
return ~operand
return None
if 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
try:
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.FloorDiv):
return left // right if right != 0 else 0
elif isinstance(node.op, ast.Mod):
return left % right if right != 0 else 0
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.BitAnd):
return left & right
elif isinstance(node.op, ast.BitXor):
return left ^ right
except Exception:
return None
return None
if isinstance(node, ast.BoolOp):
if isinstance(node.op, ast.And):
for val in node.values:
result = self._eval_const_expr(val)
if result is None:
return None
if not result:
return 0
return 1
elif isinstance(node.op, ast.Or):
for val in node.values:
result = self._eval_const_expr(val)
if result is None:
return None
if result:
return 1
return 0
if isinstance(node, ast.Compare):
left = self._eval_const_expr(node.left)
if left is None:
return None
for op, comparator in zip(node.ops, node.comparators):
right = self._eval_const_expr(comparator)
if right is None:
return None
if isinstance(op, ast.Eq):
result = left == right
elif isinstance(op, ast.NotEq):
result = left != right
elif isinstance(op, ast.Lt):
result = left < right
elif isinstance(op, ast.LtE):
result = left <= right
elif isinstance(op, ast.Gt):
result = left > right
elif isinstance(op, ast.GtE):
result = left >= right
else:
return None
if not result:
return 0
return 1
if isinstance(node, ast.Call):
if self._is_cif_call(node):
from lib.core.ConstEvaluator import ConstEvaluator, EvalContext
Gen = self.Trans.LlvmGen
ctx = EvalContext(Gen=Gen, symtab=self.Trans.SymbolTable)
result = ConstEvaluator.eval_full(node, ctx)
if result is None:
# 保留 CIf 嵌套调用处理HandlesIf 特有逻辑)
if isinstance(node, ast.Call) and self._is_cif_call(node):
return self._evaluate_cif_condition(node)
return None
return None
# HandlesIf 需要 bool/float → int 转换(#if 条件编译语义)
if isinstance(result, bool):
return 1 if result else 0
if isinstance(result, float):
return 1 if result != 0.0 else 0
return result
def _HandleIfLlvm(self, Node):
Gen = self.Trans.LlvmGen

View File

@@ -74,14 +74,14 @@ class ImportHandle(BaseHandle):
if not asname or asname == name:
# Check if this name is a CDefine constant in SymbolTable
sym_info = self.Trans.SymbolTable.get(name)
if sym_info and getattr(sym_info, 'IsDefine', None) and getattr(sym_info, 'DefineValue', None) is not None:
if sym_info and sym_info.IsDefine and sym_info.DefineValue is not None:
define_constants = vars(Gen).setdefault('_define_constants', {})
if name not in define_constants:
define_constants[name] = sym_info.DefineValue
# Also check with module prefix
for prefix_key in [f"{module}.{name}", name]:
sym_info2 = self.Trans.SymbolTable.get(prefix_key)
if sym_info2 and getattr(sym_info2, 'IsDefine', None) and getattr(sym_info2, 'DefineValue', None) is not None:
if sym_info2 and sym_info2.IsDefine and sym_info2.DefineValue is not None:
define_constants = vars(Gen).setdefault('_define_constants', {})
if name not in define_constants:
define_constants[name] = sym_info2.DefineValue
@@ -893,7 +893,7 @@ class ImportHandle(BaseHandle):
elif isinstance(value_node, ast.Name):
if value_node.id in getattr(self.Trans, 'SymbolTable', {}):
info = self.Trans.SymbolTable[value_node.id]
if getattr(info, 'IsDefine', None) and getattr(info, 'DefineValue', None) is not None:
if info.IsDefine and info.DefineValue is not None:
return info.DefineValue
elif isinstance(value_node, ast.Call):
if isinstance(value_node.func, ast.Attribute):
@@ -1020,7 +1020,7 @@ class ImportHandle(BaseHandle):
ParamTypes = []
is_method = is_class_method or '.__' in FuncName
class_name_for_method = FuncName.split('.')[0] if '.' in FuncName else None
class_is_cpython = class_name_for_method and class_name_for_method in self.Trans.SymbolTable and getattr(self.Trans.SymbolTable[class_name_for_method], 'IsCpythonObject', False)
class_is_cpython = class_name_for_method and class_name_for_method in self.Trans.SymbolTable and self.Trans.SymbolTable[class_name_for_method].IsCpythonObject
for i, Arg in enumerate(Node.args.args):
if i == 0 and is_method:
# self parameter of a method should always be a pointer to the struct

View File

@@ -21,7 +21,7 @@ class MatchHandle(BaseHandle):
VarName = Node.subject.id
if VarName in self.Trans.SymbolTable:
TypeInfo = self.Trans.SymbolTable[VarName]
if getattr(TypeInfo, 'IsRenum', False):
if TypeInfo.IsRenum:
IsRenumMatch = True
RenumName = TypeInfo.Name
SubjectPtr = Gen._loadVar(VarName)
@@ -37,11 +37,11 @@ class MatchHandle(BaseHandle):
VariantName = cls_node.attr
if VariantName and VariantName in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[VariantName]
if getattr(SymInfo, 'IsEnumMember', False) and getattr(SymInfo, 'EnumName', None):
if SymInfo.IsEnumMember and SymInfo.EnumName:
EnumName = SymInfo.EnumName
if EnumName in self.Trans.SymbolTable:
EnumInfo = self.Trans.SymbolTable[EnumName]
if getattr(EnumInfo, 'IsRenum', False):
if EnumInfo.IsRenum:
IsRenumMatch = True
RenumName = EnumName
if SubjectPtr is None:
@@ -209,7 +209,7 @@ class MatchHandle(BaseHandle):
TagValue = None
if VariantName in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[VariantName]
if getattr(SymInfo, 'IsEnumMember', False):
if SymInfo.IsEnumMember:
TagValue = SymInfo.value
if TagValue is not None:
CaseValues.append(ir.Constant(ir.IntType(32), TagValue))

View File

@@ -120,8 +120,8 @@ class HandlesTypeMerge(BaseHandle):
# 也尝试在符号表中查找模块别名
if ModulePath in self.Trans.SymbolTable:
entry = self.Trans.SymbolTable[ModulePath]
if isinstance(entry, CTypeInfo) and getattr(entry, 'IsModuleAlias', False):
resolved = getattr(entry, 'ResolvedModule', None)
if isinstance(entry, CTypeInfo) and entry.IsModuleAlias:
resolved = entry.ResolvedModule
if resolved:
ModulePath = resolved

View File

@@ -25,7 +25,7 @@ class WithHandle(BaseHandle):
if ClassName and ClassName not in Gen.structs:
if ClassName in self.Trans.SymbolTable:
SymInfo = self.Trans.SymbolTable[ClassName]
if getattr(SymInfo, 'IsStruct', False) or getattr(SymInfo, 'IsRenum', False):
if SymInfo.IsStruct or SymInfo.IsRenum:
pass
else:
ClassName = None

View File

@@ -173,28 +173,28 @@ class BaseGenMixin:
return ir.IntType(8)
if hasattr(self, 'SymbolTable') and self.SymbolTable and clean_name in self.SymbolTable:
Entry = self.SymbolTable[clean_name]
if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef:
if Entry.IsTypedef:
resolved_str = self._resolve_typedef(clean_name)
if resolved_str != clean_name:
return self._type_str_to_llvm(resolved_str)
if hasattr(Entry, 'BaseType') and Entry.BaseType:
if Entry.BaseType:
from lib.includes import t as _t
if not isinstance(Entry.BaseType, (_t._CTypedef,)) or getattr(Entry, 'PtrCount', 0) > 0:
if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0:
resolved = self._resolve_ctype_to_str(Entry)
if resolved:
return self._type_str_to_llvm(resolved)
if hasattr(Entry, 'IsRenum') and Entry.IsRenum:
if Entry.IsRenum:
if clean_name in self.structs:
return self.structs[clean_name]
if hasattr(Entry, 'IsEnum') and Entry.IsEnum:
if Entry.IsEnum:
return ir.IntType(32)
if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass:
if Entry.IsExceptionClass:
return ir.IntType(32)
if hasattr(Entry, 'IsFunction') and Entry.IsFunction:
if Entry.IsFunction:
return ir.PointerType(ir.IntType(8))
if hasattr(Entry, 'IsVariable') and Entry.IsVariable:
if Entry.IsVariable:
return ir.PointerType(ir.IntType(8))
if hasattr(Entry, 'BaseType'):
if Entry.BaseType:
from lib.includes import t as _t
if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum):
return ir.IntType(32)
@@ -237,17 +237,17 @@ class BaseGenMixin:
# 2. 再查 SymbolTable用户定义的 typedef
if hasattr(self, 'SymbolTable') and self.SymbolTable and name in self.SymbolTable:
Entry = self.SymbolTable[name]
if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef:
if hasattr(Entry, 'BaseType') and Entry.BaseType:
if Entry.IsTypedef:
if Entry.BaseType:
from lib.includes import t as _t
if not isinstance(Entry.BaseType, (_t._CTypedef,)) and getattr(Entry, 'PtrCount', 0) == 0:
if not isinstance(Entry.BaseType, (_t._CTypedef,)) and Entry.PtrCount == 0:
llvm_str = CTypeRegistry.CTypeToLLVM(type(Entry.BaseType) if isinstance(Entry.BaseType, _t.CType) else Entry.BaseType)
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
return int(llvm_str[1:])
if hasattr(Entry, 'OriginalType') and Entry.OriginalType:
if Entry.OriginalType:
from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo
if isinstance(Entry.OriginalType, _CTypeInfo) and Entry.OriginalType.BaseType:
if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and getattr(Entry.OriginalType, 'PtrCount', 0) == 0:
if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and Entry.OriginalType.PtrCount == 0:
llvm_str = CTypeRegistry.CTypeToLLVM(type(Entry.OriginalType.BaseType) if isinstance(Entry.OriginalType.BaseType, _t.CType) else Entry.OriginalType.BaseType)
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
return int(llvm_str[1:])

View File

@@ -207,13 +207,13 @@ class StructGenMixin:
is_packed = ClassName in self.class_packed
if hasattr(self, 'SymbolTable') and self.SymbolTable and ClassName in self.SymbolTable:
Entry = self.SymbolTable[ClassName]
if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass:
if Entry.IsExceptionClass:
continue
if hasattr(Entry, 'IsEnum') and Entry.IsEnum:
if not getattr(Entry, 'IsRenum', False):
if Entry.IsEnum:
if not Entry.IsRenum:
continue
if hasattr(Entry, 'IsTypedef') and Entry.IsTypedef:
if hasattr(Entry, 'BaseType') and Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)):
if Entry.IsTypedef:
if Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)):
import lib.includes.t as _t
if not isinstance(Entry.BaseType, (_t._CTypedef,)):
continue
@@ -304,10 +304,10 @@ class StructGenMixin:
for ClassName in all_classes:
if hasattr(self, 'SymbolTable') and self.SymbolTable and ClassName in self.SymbolTable:
Entry = self.SymbolTable[ClassName]
if hasattr(Entry, 'IsExceptionClass') and Entry.IsExceptionClass:
if Entry.IsExceptionClass:
continue
if hasattr(Entry, 'IsEnum') and Entry.IsEnum:
if not getattr(Entry, 'IsRenum', False):
if Entry.IsEnum:
if not Entry.IsRenum:
continue
existing_st = self.structs.get(ClassName)
if isinstance(existing_st, ir.IdentifiedStructType) and existing_st.elements is not None and len(existing_st.elements) > 0:

View File

@@ -137,7 +137,7 @@ class TypeConvertMixin:
if isinstance(BaseType, _t.CDefine):
# Use 64-bit type if the define value exceeds 32-bit range
if type_info and hasattr(type_info, 'DefineValue') and isinstance(type_info.DefineValue, int):
if type_info and isinstance(type_info.DefineValue, int):
if type_info.DefineValue < 0 or type_info.DefineValue > 0xFFFFFFFF:
return ir.IntType(64)
return ir.IntType(32)
@@ -180,8 +180,8 @@ class TypeConvertMixin:
if OriginalType:
current = OriginalType
continue
elif hasattr(Entry, 'IsTypedef') and Entry.IsTypedef:
if hasattr(Entry, 'OriginalType') and Entry.OriginalType:
elif Entry.IsTypedef:
if Entry.OriginalType:
if isinstance(Entry.OriginalType, _CTypeInfo):
if Entry.OriginalType.IsFuncPtr:
return 'Callable'
@@ -189,9 +189,9 @@ class TypeConvertMixin:
elif isinstance(Entry.OriginalType, str):
current = Entry.OriginalType
continue
if hasattr(Entry, 'BaseType') and Entry.BaseType:
if Entry.BaseType:
from lib.includes import t as _t
if not isinstance(Entry.BaseType, (_t._CTypedef,)) or getattr(Entry, 'PtrCount', 0) > 0:
if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0:
resolved = self._resolve_ctype_to_str(Entry)
if resolved and resolved != current:
current = resolved
@@ -396,24 +396,24 @@ class TypeConvertMixin:
return basic_stripped
if hasattr(self, 'SymbolTable') and self.SymbolTable and type_str in self.SymbolTable:
_Entry = self.SymbolTable[type_str]
if hasattr(_Entry, 'IsTypedef') and _Entry.IsTypedef:
if _Entry.IsTypedef:
resolved_str = self._resolve_typedef(type_str)
if resolved_str != type_str:
return self._type_str_to_llvm(resolved_str, IsPtr)
if hasattr(_Entry, 'BaseType') and _Entry.BaseType:
if _Entry.BaseType:
from lib.includes import t as _t
if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or getattr(_Entry, 'PtrCount', 0) > 0:
if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or _Entry.PtrCount > 0:
resolved = self._resolve_ctype_to_str(_Entry)
if resolved:
return self._type_str_to_llvm(resolved, IsPtr)
if hasattr(_Entry, 'IsRenum') and _Entry.IsRenum:
if _Entry.IsRenum:
if type_str in self.structs:
return self.structs[type_str]
if hasattr(_Entry, 'IsEnum') and _Entry.IsEnum:
if _Entry.IsEnum:
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
if hasattr(_Entry, 'IsExceptionClass') and _Entry.IsExceptionClass:
if _Entry.IsExceptionClass:
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
if hasattr(_Entry, 'BaseType'):
if _Entry.BaseType:
from lib.includes import t as _t
if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum:
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
@@ -431,24 +431,24 @@ class TypeConvertMixin:
return basic_last
if hasattr(self, 'SymbolTable') and self.SymbolTable and LastPart in self.SymbolTable:
_Entry = self.SymbolTable[LastPart]
if hasattr(_Entry, 'IsTypedef') and _Entry.IsTypedef:
if _Entry.IsTypedef:
resolved_str = self._resolve_typedef(LastPart)
if resolved_str != LastPart:
return self._type_str_to_llvm(resolved_str, IsPtr)
if hasattr(_Entry, 'BaseType') and _Entry.BaseType:
if _Entry.BaseType:
from lib.includes import t as _t
if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or getattr(_Entry, 'PtrCount', 0) > 0:
if not isinstance(_Entry.BaseType, (_t._CTypedef,)) or _Entry.PtrCount > 0:
resolved = self._resolve_ctype_to_str(_Entry)
if resolved:
return self._type_str_to_llvm(resolved, IsPtr)
if hasattr(_Entry, 'IsRenum') and _Entry.IsRenum:
if _Entry.IsRenum:
if LastPart in self.structs:
return self.structs[LastPart]
if hasattr(_Entry, 'IsEnum') and _Entry.IsEnum:
if _Entry.IsEnum:
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
if hasattr(_Entry, 'IsExceptionClass') and _Entry.IsExceptionClass:
if _Entry.IsExceptionClass:
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))
if hasattr(_Entry, 'BaseType'):
if _Entry.BaseType:
from lib.includes import t as _t
if (isinstance(_Entry.BaseType, type) and issubclass(_Entry.BaseType, _t.CEnum)) or _Entry.BaseType is _t.CEnum:
return ir.IntType(32) if not IsPtr else ir.PointerType(ir.IntType(32))

79
lib/core/SymbolData.py Normal file
View File

@@ -0,0 +1,79 @@
"""符号表处理的数据结构:四阶段管线中传递的中间数据"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Tuple
@dataclass
class ClassSymbolData:
"""从 AST 提取的类符号数据"""
name: str
type_kind: str # 'struct', 'union', 'enum', 'exception'
lineno: int
members: Dict[str, Any]
is_cpython_object: bool = False
is_packed: bool = False
enum_members: List[Tuple[str, int, int]] = field(default_factory=list) # (name, value, lineno)
@dataclass
class TypedefSymbolData:
"""Typedef 符号数据(含原始注解和解析结果)"""
name: str
lineno: int
# 原始注解数据(由 Extractor 设置Resolver 使用)
annotation: Any = None
value: Any = None
has_cdefine: bool = False
has_postdef: bool = False
has_ctypedef: bool = False
# 解析结果(由 Resolver 设置Inserter 使用)
original_type_kind: Optional[str] = None
original_class: Any = None
members: Optional[Dict] = None
@dataclass
class FuncSymbolData:
"""函数符号数据(含原始注解和解析结果)"""
name: str
lineno: int
# 原始数据(由 Extractor 设置)
returns_node: Any = None
params: List = field(default_factory=list) # [(name, annotation_node), ...]
is_variadic: bool = False
is_inline: bool = False
# 解析结果(由 Resolver 设置)
ret_type: Any = None
param_types: List = field(default_factory=list) # [str, ...]
@dataclass
class DefineSymbolData:
"""Define 符号数据(含原始值和解析结果)"""
name: str
lineno: int
# 原始数据(由 Extractor 设置)
value_node: Any = None
# 解析结果(由 Resolver 设置)
value: Any = None
@dataclass
class AnonymousTypeData:
"""匿名类型数据"""
name: str
is_union: bool
members: Dict[str, Any]
lineno: int
@dataclass
class ModuleSymbols:
"""从模块提取的完整符号数据,在四阶段管线中传递"""
file_path: str
classes: List[ClassSymbolData] = field(default_factory=list)
typedefs: List[TypedefSymbolData] = field(default_factory=list)
functions: List[FuncSymbolData] = field(default_factory=list)
defines: List[DefineSymbolData] = field(default_factory=list)
anonymous_types: Dict[str, AnonymousTypeData] = field(default_factory=dict)

237
lib/core/SymbolExtractor.py Normal file
View File

@@ -0,0 +1,237 @@
"""Pass 1: ASTSymbolExtractor — 从 AST 提取原始符号信息"""
from __future__ import annotations
import ast
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
from lib.core.SymbolData import (
ModuleSymbols, ClassSymbolData, TypedefSymbolData,
FuncSymbolData, DefineSymbolData, AnonymousTypeData
)
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.includes import t
from lib.core.SymbolUtils import AnnotationContainsTType, CheckAnnotationHasCInline
class ASTSymbolExtractor:
"""从 Python 源文件的 AST 中提取所有符号信息"""
def __init__(self, symbol_table: SymbolTable):
self._symtab = symbol_table
def extract(self, file_path: str) -> ModuleSymbols:
"""提取文件中的所有符号信息"""
with open(file_path, 'r', encoding='utf-8') as f:
code = f.read()
tree = ast.parse(code)
result = ModuleSymbols(file_path=file_path)
# 第一步:收集所有类的成员和匿名类型
class_members = {}
for node in tree.body:
if isinstance(node, ast.ClassDef):
members = {}
self._collect_members(node, members, result.anonymous_types)
class_members[node.name] = members
# 第二步:从每个顶层节点提取符号信息
for node in tree.body:
if isinstance(node, ast.ClassDef):
members_info = class_members.get(node.name, {})
result.classes.append(self._extract_class(node, members_info))
elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
self._extract_ann_assign(node, result)
elif isinstance(node, ast.FunctionDef):
result.functions.append(self._extract_function(node))
return result
# ------------------------------------------------------------------
# 成员收集(递归处理嵌套匿名类)
# ------------------------------------------------------------------
def _collect_members(self, class_node, members, anonymous_types, prefix=''):
"""递归收集类成员,包括嵌套匿名类型"""
for item in class_node.body:
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
member_name = item.target.id
full_name = f'{prefix}{member_name}' if prefix else member_name
member_type = CTypeInfo.FromNode(item.annotation, self._symtab)
if member_type is None:
member_type = CTypeInfo()
member_type.BaseType = t.CInt()
is_ptr = member_type.IsPtr
if isinstance(item.annotation, ast.BinOp):
annotation_str = ast.dump(item.annotation)
if 'CPtr' in annotation_str:
is_ptr = True
members[full_name] = member_type.Copy()
elif isinstance(item, ast.ClassDef):
is_anonymous = any(
any(AnnotationContainsTType(base, 'Anonymous') for base in item.bases)
) if item.bases else False
if is_anonymous:
is_union = any(
any(AnnotationContainsTType(base, 'CUnion') for base in item.bases)
)
nested_name = f'{prefix}{item.name}' if prefix else item.name
members[nested_name] = CTypeInfo()
members[nested_name].BaseType = f'union {item.name}' if is_union else f'struct {item.name}'
members[nested_name].PtrCount = 0
members[nested_name].ArrayDims = []
new_prefix = f'{prefix}{item.name}.' if prefix else f'{item.name}.'
self._collect_members(item, members, anonymous_types, new_prefix)
anonymous_members = {}
for full_name, member_info in members.items():
if full_name.startswith(f"{nested_name}."):
member_name = full_name[len(nested_name) + 1:]
anonymous_members[member_name] = member_info
if item.name not in anonymous_types:
anonymous_types[item.name] = AnonymousTypeData(
name=item.name,
is_union=is_union,
members=anonymous_members,
lineno=item.lineno
)
# ------------------------------------------------------------------
# 类符号提取
# ------------------------------------------------------------------
def _extract_class(self, node, members_info) -> ClassSymbolData:
"""从 ClassDef 节点提取类符号数据"""
type_kind = 'struct'
is_cpython_object = False
is_packed = 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'):
is_cpython_object = 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':
is_packed = True
# 检查基类
for base in node.bases:
if AnnotationContainsTType(base, 'CUnion'):
type_kind = 'union'
break
elif AnnotationContainsTType(base, 'CEnum'):
type_kind = 'enum'
break
elif AnnotationContainsTType(base, 'CStruct'):
type_kind = 'struct'
break
elif AnnotationContainsTType(base, 'Object'):
is_cpython_object = True
type_kind = 'struct'
break
elif isinstance(base, ast.Name) and base.id == 'Exception':
type_kind = 'exception'
break
elif isinstance(base, ast.Name):
base_entry = self._symtab.get(base.id)
if base_entry and base_entry.IsExceptionClass:
type_kind = 'exception'
break
# 提取枚举成员
enum_members = []
if type_kind == '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):
member_name = 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
enum_members.append((member_name, next_enum_value - 1, item.lineno))
elif isinstance(item, ast.AnnAssign):
if isinstance(item.target, ast.Name):
member_name = 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
enum_members.append((member_name, next_enum_value - 1, item.lineno))
return ClassSymbolData(
name=node.name,
type_kind=type_kind,
lineno=node.lineno,
members=members_info,
is_cpython_object=is_cpython_object,
is_packed=is_packed,
enum_members=enum_members,
)
# ------------------------------------------------------------------
# AnnAssign 提取typedef / define
# ------------------------------------------------------------------
def _extract_ann_assign(self, node, result: ModuleSymbols):
"""从 AnnAssign 节点提取 typedef 或 define 数据"""
var_name = node.target.id
has_cdefine = AnnotationContainsTType(node.annotation, 'CDefine') if node.annotation else False
has_postdef = AnnotationContainsTType(node.annotation, 'Postdefinition') if node.annotation else False
has_ctypedef = AnnotationContainsTType(node.annotation, 'CTypedef') if node.annotation else False
if has_cdefine:
result.defines.append(DefineSymbolData(
name=var_name,
lineno=node.lineno,
value_node=node.value,
))
else:
result.typedefs.append(TypedefSymbolData(
name=var_name,
lineno=node.lineno,
annotation=node.annotation,
value=node.value,
has_cdefine=has_cdefine,
has_postdef=has_postdef,
has_ctypedef=has_ctypedef,
))
# ------------------------------------------------------------------
# 函数提取
# ------------------------------------------------------------------
def _extract_function(self, node) -> FuncSymbolData:
"""从 FunctionDef 节点提取函数符号数据"""
params = [(arg.arg, arg.annotation) for arg in node.args.args]
is_variadic = node.args.vararg is not None
is_inline = CheckAnnotationHasCInline(node.returns)
return FuncSymbolData(
name=node.name,
lineno=node.lineno,
returns_node=node.returns,
params=params,
is_variadic=is_variadic,
is_inline=is_inline,
)

View File

@@ -0,0 +1,68 @@
"""Pass 3: SymbolInserter — 将解析后的符号插入 SymbolTable主命名空间"""
from __future__ import annotations
from typing import TYPE_CHECKING, List
if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
from lib.core.SymbolData import ModuleSymbols
class SymbolInserter:
"""将解析后的符号插入 SymbolTable 的主命名空间(无前缀)"""
def __init__(self, symbol_table: SymbolTable):
self._symtab = symbol_table
def insert(self, module_symbols: ModuleSymbols) -> List[str]:
"""插入所有符号到主命名空间,返回已加载的符号名列表"""
loaded = []
file_path = module_symbols.file_path
# 插入类符号
for cls in module_symbols.classes:
self._symtab._InsertClassSymbol(
cls.name, cls.type_kind, cls.lineno, file_path,
cls.members, cls.is_cpython_object, cls.is_packed
)
loaded.append(cls.name)
# 插入枚举成员(短名 + 类名.成员名)
if cls.type_kind == 'enum':
for member_name, _member_value, member_lineno in cls.enum_members:
self._symtab._InsertEnumMemberSymbol(member_name, cls.name, member_lineno, file_path)
loaded.append(member_name)
class_member_name = f"{cls.name}.{member_name}"
self._symtab._InsertEnumMemberSymbol(class_member_name, cls.name, member_lineno, file_path)
loaded.append(class_member_name)
# 插入 typedef 符号
for td in module_symbols.typedefs:
self._symtab._InsertTypedefSymbol(
td.name, td.original_type_kind, td.original_class,
td.lineno, file_path, td.members
)
loaded.append(td.name)
# 插入函数符号
for func in module_symbols.functions:
self._symtab._InsertFuncSymbol(
func.name, func.ret_type, func.param_types,
func.lineno, file_path, func.is_variadic, func.is_inline
)
loaded.append(func.name)
# 插入 define 符号
for define in module_symbols.defines:
self._symtab._InsertDefineSymbol(
define.name, define.value, define.lineno, file_path
)
loaded.append(define.name)
# 插入匿名类型符号(短名)
for anon_name, anon_data in module_symbols.anonymous_types.items():
self._symtab._InsertAnonymousSymbol(
anon_name, anon_data.is_union, anon_data.members,
anon_data.lineno, file_path
)
return loaded

View File

@@ -0,0 +1,76 @@
"""Pass 4: PackageReexporter — 将符号重新导出到命名空间前缀下"""
from __future__ import annotations
from typing import TYPE_CHECKING, List
if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
from lib.core.SymbolData import ModuleSymbols
class PackageReexporter:
"""将已解析的符号重新导出到命名空间前缀下(如 mpool.MPool"""
def __init__(self, symbol_table: SymbolTable):
self._symtab = symbol_table
def reexport(self, module_symbols: ModuleSymbols, prefixes: List[str], lineno: int = 0) -> List[str]:
"""将符号重新导出到所有命名空间前缀下,返回新增的符号名列表"""
loaded = []
file_path = module_symbols.file_path
primary_prefix = prefixes[0] if prefixes else None
for prefix in prefixes:
# 插入类符号(前缀.类名)
for cls in module_symbols.classes:
full_name = f"{prefix}.{cls.name}"
self._symtab._InsertClassSymbol(
full_name, cls.type_kind, cls.lineno, file_path,
cls.members, cls.is_cpython_object, cls.is_packed
)
loaded.append(full_name)
# 插入枚举成员(前缀.成员名)
if cls.type_kind == 'enum':
for member_name, _member_value, member_lineno in cls.enum_members:
full_member_name = f"{prefix}.{member_name}"
self._symtab._InsertEnumMemberSymbol(full_member_name, cls.name, member_lineno, file_path)
loaded.append(full_member_name)
# 插入 typedef 符号(前缀.名称)
for td in module_symbols.typedefs:
full_name = f"{prefix}.{td.name}"
self._symtab._InsertTypedefSymbol(
full_name, td.original_type_kind, td.original_class,
td.lineno, file_path, td.members
)
loaded.append(full_name)
# 插入函数符号(前缀.名称)
for func in module_symbols.functions:
full_name = f"{prefix}.{func.name}"
self._symtab._InsertFuncSymbol(
full_name, func.ret_type, func.param_types,
func.lineno, file_path, func.is_variadic, func.is_inline
)
loaded.append(full_name)
# 插入 define 符号(前缀.名称)
for define in module_symbols.defines:
full_name = f"{prefix}.{define.name}"
self._symtab._InsertDefineSymbol(
full_name, define.value, define.lineno, file_path
)
loaded.append(full_name)
# 插入模块别名
self._symtab._InsertModuleSymbol(prefix, lineno, file_path)
# 插入匿名类型符号(前缀.名称)
for anon_name, anon_data in module_symbols.anonymous_types.items():
full_type_name = f"{prefix}.{anon_name}"
self._symtab._InsertAnonymousSymbol(
full_type_name, anon_data.is_union, anon_data.members,
anon_data.lineno, file_path
)
return loaded

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,224 @@
"""Pass 2: TypeResolver — 解析 typedef 类型、函数签名、define 值"""
from __future__ import annotations
import ast
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
from lib.core.SymbolData import (
ModuleSymbols, TypedefSymbolData, FuncSymbolData, DefineSymbolData
)
from lib.core.Handles.HandlesBase import CTypeInfo, CTypeHelper
from lib.includes import t
class TypeResolver:
"""解析从 AST 提取的原始符号中的类型信息"""
def __init__(self, symbol_table: SymbolTable):
self._symtab = symbol_table
def resolve(self, module_symbols: ModuleSymbols) -> ModuleSymbols:
"""解析所有类型信息,就地更新 ModuleSymbols"""
# 构建 class_members 查找表typedef Postdefinition 需要)
class_members = {cls.name: cls.members for cls in module_symbols.classes}
# 解析 typedef
for td in module_symbols.typedefs:
self._resolve_typedef(td, class_members)
# 解析函数签名
for func in module_symbols.functions:
self._resolve_function(func)
# 解析 define 值
for define in module_symbols.defines:
self._resolve_define(define)
return module_symbols
# ------------------------------------------------------------------
# Typedef 解析
# ------------------------------------------------------------------
def _resolve_typedef(self, td: TypedefSymbolData, class_members: dict):
"""解析单个 typedef 的类型信息"""
is_postdef_with_typedef = td.has_postdef and td.has_ctypedef
if is_postdef_with_typedef:
self._resolve_postdef_typedef(td, class_members)
elif td.has_ctypedef:
self._resolve_ctypedef_typedef(td)
else:
# 无特殊注解的 typedef
td.original_type_kind = None
td.original_class = None
def _resolve_postdef_typedef(self, td: TypedefSymbolData, class_members: dict):
"""解析 Postdefinition + CTypedef 组合注解"""
original_class = self._find_postdef_arg(td.annotation)
if original_class and original_class in class_members:
members_info = class_members[original_class]
original_type_kind = 'struct'
if original_class in self._symtab:
orig_type_info = self._symtab[original_class]
if orig_type_info.type_cls in (t.CStruct, t.CEnum, t.CUnion):
if orig_type_info.type_cls is t.CStruct:
original_type_kind = 'struct'
elif orig_type_info.type_cls is t.CEnum:
original_type_kind = 'enum'
elif orig_type_info.type_cls is t.CUnion:
original_type_kind = 'union'
td.original_type_kind = original_type_kind
td.original_class = original_class
td.members = members_info
else:
td.original_type_kind = None
td.original_class = None
def _resolve_ctypedef_typedef(self, td: TypedefSymbolData):
"""解析 CTypedef 注解"""
base_type_name = self._find_base_type(td.annotation)
_TYPE_QUALIFIERS = {'CTypedef', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern', 'CDefine', 'CPostdefinition'}
if base_type_name == 'Callable':
original_type = CTypeInfo()
original_type.IsFuncPtr = True
original_type.FuncPtrReturn = CTypeInfo.VoidTypeInfo()
original_type.FuncPtrParams = []
td.original_type_kind = 'typedef'
td.original_class = original_type
elif base_type_name and base_type_name not in _TYPE_QUALIFIERS:
cname = CTypeHelper.GetCName(base_type_name)
if cname and cname != base_type_name:
td.original_class = cname
else:
td.original_class = base_type_name[1:] if base_type_name.startswith('C') else base_type_name
td.original_type_kind = 'typedef'
else:
# 尝试从值表达式解析
self._resolve_typedef_from_value(td)
def _resolve_typedef_from_value(self, td: TypedefSymbolData):
"""从值表达式解析 typedef 类型"""
if not td.value:
td.original_type_kind = None
td.original_class = None
return
value_base_type = self._find_base_type(td.value)
_PTR_MODIFIERS = {'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'}
if value_base_type and value_base_type not in _PTR_MODIFIERS:
cname = CTypeHelper.GetCName(value_base_type)
if cname and cname != value_base_type:
td.original_class = cname
else:
td.original_class = value_base_type[1:] if value_base_type.startswith('C') else value_base_type
td.original_type_kind = 'typedef'
return
if isinstance(td.value, ast.BinOp) and isinstance(td.value.op, ast.BitOr):
left_type = self._symtab._ResolveTypedefValueType(td.value.left)
right_type = self._symtab._ResolveTypedefValueType(td.value.right)
is_ptr_type = right_type == 'ptr' or left_type == 'ptr'
if is_ptr_type:
base_name = left_type if left_type != 'ptr' else (right_type if right_type != 'ptr' else '')
if base_name:
original_type = base_name + ' *'
else:
original_type = 'void *'
td.original_class = original_type
td.original_type_kind = 'typedef'
elif left_type:
td.original_class = left_type
td.original_type_kind = 'typedef'
elif right_type:
td.original_class = right_type
td.original_type_kind = 'typedef'
return
if isinstance(td.value, ast.Name):
ref_name = td.value.id
if ref_name in self._symtab:
ref_info = self._symtab[ref_name]
if ref_info and ref_info.IsTypedef and ref_info.OriginalType:
td.original_class = ref_info.OriginalType
td.original_type_kind = 'typedef'
return
td.original_type_kind = None
td.original_class = None
# ------------------------------------------------------------------
# 函数签名解析
# ------------------------------------------------------------------
def _resolve_function(self, func: FuncSymbolData):
"""解析函数的返回类型和参数类型"""
func.ret_type = self._symtab._GetFuncRetTypeStr(func.returns_node)
func.param_types = []
for _arg_name, annotation in func.params:
if annotation:
func.param_types.append(self._symtab._GetFuncParamTypeStr(annotation))
else:
func.param_types.append('i8*')
# ------------------------------------------------------------------
# Define 值解析
# ------------------------------------------------------------------
def _resolve_define(self, define: DefineSymbolData):
"""解析 define 常量值"""
if define.value_node:
define.value = self._symtab._eval_const_expr(define.value_node)
# ------------------------------------------------------------------
# 静态工具方法(原 _LoadSymbolsFromFile 中的闭包)
# ------------------------------------------------------------------
@staticmethod
def _find_base_type(node):
"""从注解 AST 节点中查找基础类型名称"""
if isinstance(node, ast.Attribute):
if hasattr(node.value, 'id') and node.value.id == 't':
if node.attr == 'CPtr':
return 'ptr'
return node.attr
elif isinstance(node, ast.Subscript):
if isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and node.value.value.id == 't' and node.value.attr == 'Callable':
return 'Callable'
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_result = TypeResolver._find_base_type(node.left)
if left_result == 'ptr':
right_result = TypeResolver._find_base_type(node.right)
return (right_result if right_result and right_result != 'ptr' else 'void') + ' *'
if left_result == 'Callable':
return 'Callable'
right_result = TypeResolver._find_base_type(node.right)
if right_result == 'ptr':
return (left_result if left_result and left_result != 'ptr' else 'void') + ' *'
if right_result == 'Callable':
return 'Callable'
if left_result:
return left_result
if right_result:
return right_result
return None
@staticmethod
def _find_postdef_arg(node):
"""从注解 AST 节点中查找 Postdefinition 参数"""
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 node.args and isinstance(node.args[0], ast.Name):
return node.args[0].id
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
left_result = TypeResolver._find_postdef_arg(node.left)
if left_result:
return left_result
right_result = TypeResolver._find_postdef_arg(node.right)
if right_result:
return right_result
return None

56
lib/core/SymbolUtils.py Normal file
View File

@@ -0,0 +1,56 @@
"""共享工具函数:符号表处理中使用的 AST 分析工具"""
from __future__ import annotations
import ast
from lib.includes import t
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
def CheckAnnotationHasCInline(annotation_node) -> bool:
"""检测注解节点中是否包含 CInline"""
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 CheckAnnotationHasCInline(annotation_node.left) or CheckAnnotationHasCInline(annotation_node.right)
return False

View File

@@ -328,9 +328,9 @@ class AnnotationLoaderMixin:
orig_type_str = orig_entry.get('OriginalType', f'struct {original_name}')
elif orig_entry.get('type') == 'enum':
orig_type_str = f'enum {original_name}'
elif hasattr(orig_entry, 'IsTypedef') and orig_entry.IsTypedef:
orig_type_str = getattr(orig_entry, 'OriginalType', f'struct {original_name}')
elif hasattr(orig_entry, 'IsEnum') and orig_entry.IsEnum:
elif orig_entry.IsTypedef:
orig_type_str = orig_entry.OriginalType or f'struct {original_name}'
elif orig_entry.IsEnum:
orig_type_str = f'enum {original_name}'
TypedefNode.OriginalType = orig_type_str
TypedefNode.set('source', 'annotation_module')

View File

@@ -112,42 +112,8 @@ class ConstEvalMixin:
return self._try_eval_const_expr(node, Gen)
def _try_eval_const_expr(self, node, Gen):
import ast
if isinstance(node, ast.Constant):
return node.value
elif isinstance(node, ast.BinOp):
left = self._try_eval_const_expr(node.left, Gen)
right = self._try_eval_const_expr(node.right, Gen)
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.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.BitAnd):
return left & right
elif isinstance(node.op, ast.BitXor):
return left ^ right
elif isinstance(node, ast.UnaryOp):
operand = self._try_eval_const_expr(node.operand, Gen)
if operand is None:
return None
if isinstance(node.op, ast.USub):
return -operand
elif isinstance(node.op, ast.Invert):
return ~operand
elif isinstance(node, ast.Name):
if node.id in getattr(Gen, '_DefineConstants', {}):
return Gen._DefineConstants[node.id]
return None
from lib.core.ConstEvaluator import ConstEvaluator
return ConstEvaluator.eval_with_symtab(node, self.SymbolTable)
def _BuildMultiDimArrayInitConstants(self, value_node, ArrayType, Gen):
from lib.core.Handles.HandlesAssign import AssignHandle

View File

@@ -67,6 +67,7 @@ FIELD_ROUTES = {
'ArrayPtr': ('ts', 'array_ptr'),
'IsState': ('ts', 'is_state'),
'OriginalType': ('ts', 'original_type'),
'IsSigned': ('ts', 'is_signed'),
# --- SymbolMeta 字段 ---
'Name': ('sm', 'name'),
@@ -87,6 +88,8 @@ FIELD_ROUTES = {
'IsModuleAlias': ('sm', 'is_module_alias'),
'ResolvedModule': ('sm', 'resolved_module'),
'DefineValue': ('sm', 'define_value'),
'EnumName': ('sm', 'enum_name'),
'value': ('sm', 'enum_value'),
# --- _kind_flags独立 bool存储在 SymbolMeta._kind_flags---
'IsStruct': ('kf', 'IsStruct'),
@@ -127,6 +130,7 @@ class TypeSpec:
'is_array_ptr', 'array_ptr',
'is_state',
'original_type',
'is_signed',
)
def __init__(self):
@@ -150,6 +154,7 @@ class TypeSpec:
self.array_ptr: Any = None # CTypeInfo
self.is_state: bool = False
self.original_type: Any = None # CTypeInfo | str | None (typedef 原始类型)
self.is_signed: Optional[bool] = None # None = 未设置, True/False = 有符号/无符号
@property
def base_type(self) -> Any:
@@ -203,6 +208,7 @@ class TypeSpec:
new.array_ptr = self.array_ptr
new.is_state = self.is_state
new.original_type = self.original_type
new.is_signed = self.is_signed
return new
@@ -222,6 +228,7 @@ class SymbolMeta:
'members',
'is_cpython_object', 'is_packed',
'define_value',
'enum_name', 'enum_value',
'is_inline', 'inline_body', 'inline_params',
'is_anonymous',
'renum_variants',
@@ -241,6 +248,8 @@ class SymbolMeta:
self.is_cpython_object: bool = False
self.is_packed: bool = False
self.define_value: Any = None
self.enum_name: str = "" # 枚举成员所属的枚举类名
self.enum_value: Any = None # 枚举成员的值
self.is_inline: bool = False
self.inline_body: list | None = None
self.inline_params: list | None = None
@@ -287,6 +296,8 @@ class SymbolMeta:
new.is_cpython_object = self.is_cpython_object
new.is_packed = self.is_packed
new.define_value = self.define_value
new.enum_name = self.enum_name
new.enum_value = self.enum_value
new.is_inline = self.is_inline
new.inline_body = self.inline_body
new.inline_params = list(self.inline_params) if self.inline_params else None