修复了大量存在的问题,增加了假鸭子类型等等机制
This commit is contained in:
@@ -15,7 +15,14 @@ ConstEvaluator 提供三个级别的求值:
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Callable, Optional, TYPE_CHECKING
|
||||
|
||||
import llvmlite.ir as ir
|
||||
|
||||
from lib.core.Handles.HandlesBase import CTypeInfo
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
|
||||
|
||||
|
||||
class ConstEvaluator:
|
||||
@@ -40,7 +47,7 @@ class ConstEvaluator:
|
||||
# ==================================================================
|
||||
|
||||
@staticmethod
|
||||
def eval_with_symtab(node: ast.AST, symtab) -> Optional[Any]:
|
||||
def eval_with_symtab(node: ast.AST, symtab: Any) -> Optional[Any]:
|
||||
"""求值常量表达式,支持从 SymbolTable 查找 define 值。
|
||||
|
||||
支持: Constant, BinOp, UnaryOp, Name(define), Attribute(define)
|
||||
@@ -49,7 +56,7 @@ class ConstEvaluator:
|
||||
return node.value
|
||||
if isinstance(node, ast.Name):
|
||||
if hasattr(symtab, '__contains__') and node.id in symtab:
|
||||
info = symtab[node.id]
|
||||
info: CTypeInfo = symtab[node.id]
|
||||
if info.IsDefine and isinstance(info.DefineValue, int):
|
||||
return info.DefineValue
|
||||
return None
|
||||
@@ -71,7 +78,7 @@ class ConstEvaluator:
|
||||
if isinstance(node, ast.BoolOp):
|
||||
if isinstance(node.op, ast.And):
|
||||
for val in node.values:
|
||||
result = ConstEvaluator.eval_full(val, ctx)
|
||||
result: Any = ConstEvaluator.eval_full(val, ctx)
|
||||
if result is None:
|
||||
return None
|
||||
if not result:
|
||||
@@ -79,7 +86,7 @@ class ConstEvaluator:
|
||||
return 1
|
||||
elif isinstance(node.op, ast.Or):
|
||||
for val in node.values:
|
||||
result = ConstEvaluator.eval_full(val, ctx)
|
||||
result: Any = ConstEvaluator.eval_full(val, ctx)
|
||||
if result is None:
|
||||
return None
|
||||
if result:
|
||||
@@ -89,14 +96,16 @@ class ConstEvaluator:
|
||||
|
||||
# Compare (HandlesIf 逻辑)
|
||||
if isinstance(node, ast.Compare):
|
||||
left = ConstEvaluator.eval_full(node.left, ctx)
|
||||
left: Any = ConstEvaluator.eval_full(node.left, ctx)
|
||||
if left is None:
|
||||
return None
|
||||
op: ast.cmpop
|
||||
comparator: ast.AST
|
||||
for op, comparator in zip(node.ops, node.comparators):
|
||||
right = ConstEvaluator.eval_full(comparator, ctx)
|
||||
right: Any = ConstEvaluator.eval_full(comparator, ctx)
|
||||
if right is None:
|
||||
return None
|
||||
result = ConstEvaluator._eval_compare_op(op, left, right)
|
||||
result: bool | None = ConstEvaluator._eval_compare_op(op, left, right)
|
||||
if result is None:
|
||||
return None
|
||||
if not result:
|
||||
@@ -118,7 +127,7 @@ class ConstEvaluator:
|
||||
|
||||
# UnaryOp
|
||||
if isinstance(node, ast.UnaryOp):
|
||||
operand = ConstEvaluator.eval_full(node.operand, ctx)
|
||||
operand: Any = ConstEvaluator.eval_full(node.operand, ctx)
|
||||
if operand is None:
|
||||
return None
|
||||
if isinstance(node.op, ast.Not):
|
||||
@@ -131,6 +140,10 @@ class ConstEvaluator:
|
||||
return ~operand
|
||||
return None
|
||||
|
||||
# Call — 编译时函数调用(如 ctraits.isptr(x))
|
||||
if isinstance(node, ast.Call):
|
||||
return ConstEvaluator._eval_compile_time_call(node, ctx)
|
||||
|
||||
# BinOp
|
||||
return ConstEvaluator._eval_arith(node, lambda n: ConstEvaluator.eval_full(n, ctx))
|
||||
|
||||
@@ -139,16 +152,73 @@ class ConstEvaluator:
|
||||
# ==================================================================
|
||||
|
||||
@staticmethod
|
||||
def _eval_arith(node: ast.AST, recurse) -> Optional[Any]:
|
||||
def _eval_compile_time_call(node: ast.Call, ctx: 'EvalContext') -> Optional[Any]:
|
||||
"""处理编译时函数调用,如 ctraits.isptr(x)"""
|
||||
func: ast.expr = node.func
|
||||
func_name: str | None = None
|
||||
module_name: str | None = None
|
||||
|
||||
if isinstance(func, ast.Attribute):
|
||||
if isinstance(func.value, ast.Name):
|
||||
module_name = func.value.id
|
||||
func_name = func.attr
|
||||
elif isinstance(func, ast.Name):
|
||||
func_name = func.id
|
||||
|
||||
# ctraits.isptr(x) — 带模块前缀
|
||||
# isptr(x) — 通过 from ctraits import isptr 导入
|
||||
is_isptr: bool = False
|
||||
if module_name == 'ctraits' and func_name == 'isptr':
|
||||
is_isptr = True
|
||||
elif func_name == 'isptr' and not module_name:
|
||||
# 检查是否通过 from ctraits import isptr 导入
|
||||
t_c_imported = getattr(ctx.translator, '_t_c_imported_names', {}) if ctx.translator else {}
|
||||
if func_name in t_c_imported:
|
||||
src_module, _ = t_c_imported[func_name]
|
||||
if src_module == 'ctraits':
|
||||
is_isptr = True
|
||||
# 也检查符号表中是否有 ctraits.isptr
|
||||
if not is_isptr and ctx.symtab:
|
||||
sym = ctx.symtab.lookup('ctraits.isptr') if hasattr(ctx.symtab, 'lookup') else None
|
||||
if sym:
|
||||
is_isptr = True
|
||||
|
||||
if is_isptr and node.args and ctx.translator:
|
||||
try:
|
||||
arg_node: ast.expr = node.args[0]
|
||||
# 局部变量:优先通过 LLVM 类型判断(GetCTypeInfo 无法解析局部变量名)
|
||||
if ctx.Gen and isinstance(arg_node, ast.Name):
|
||||
var_name: str = arg_node.id
|
||||
variables: dict = getattr(ctx.Gen, 'variables', {})
|
||||
if var_name in variables:
|
||||
var_val: Any = variables[var_name]
|
||||
if hasattr(var_val, 'type') and isinstance(var_val.type, ir.PointerType):
|
||||
pointee: ir.Type = var_val.type.pointee
|
||||
if isinstance(pointee, ir.PointerType):
|
||||
return 1
|
||||
return 0
|
||||
# 类型名 / typedef:通过 TypeMergeHandler 获取 CTypeInfo
|
||||
type_info = ctx.translator.TypeMergeHandler.GetCTypeInfo(arg_node)
|
||||
if type_info and (type_info.IsPtr or type_info.PtrCount > 0):
|
||||
return 1
|
||||
if type_info and not (type_info.IsPtr or type_info.PtrCount > 0):
|
||||
return 0
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _eval_arith(node: ast.AST, recurse: Callable[[ast.AST], Any]) -> Optional[Any]:
|
||||
"""通用算术求值:BinOp + UnaryOp"""
|
||||
if isinstance(node, ast.BinOp):
|
||||
left = recurse(node.left)
|
||||
right = recurse(node.right)
|
||||
left: Any = recurse(node.left)
|
||||
right: Any = 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)
|
||||
operand: Any = recurse(node.operand)
|
||||
if operand is None:
|
||||
return None
|
||||
if isinstance(node.op, ast.USub):
|
||||
@@ -161,7 +231,7 @@ class ConstEvaluator:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _apply_binop(op: ast.operator, left, right) -> Optional[Any]:
|
||||
def _apply_binop(op: ast.operator, left: Any, right: Any) -> Optional[Any]:
|
||||
"""应用二元运算符"""
|
||||
try:
|
||||
if isinstance(op, ast.Add):
|
||||
@@ -197,7 +267,7 @@ class ConstEvaluator:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _eval_compare_op(op, left, right) -> Optional[bool]:
|
||||
def _eval_compare_op(op: ast.cmpop, left: Any, right: Any) -> Optional[bool]:
|
||||
"""应用比较运算符"""
|
||||
if isinstance(op, ast.Eq):
|
||||
return left == right
|
||||
@@ -214,25 +284,27 @@ class ConstEvaluator:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _eval_attribute_define(node: ast.Attribute, symtab) -> Optional[Any]:
|
||||
def _eval_attribute_define(node: ast.Attribute, symtab: Any) -> Optional[Any]:
|
||||
"""从 SymbolTable 查找 Attribute 形式的 define 值"""
|
||||
parts = []
|
||||
current = node
|
||||
parts: list[str] = []
|
||||
current: ast.AST = 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)]
|
||||
attr_name: str = parts[-1]
|
||||
possible_keys: list[str] = [attr_name, '.'.join(parts)]
|
||||
for key in possible_keys:
|
||||
if hasattr(symtab, '__contains__') and key in symtab:
|
||||
info = symtab[key]
|
||||
info: CTypeInfo = symtab[key]
|
||||
if info.IsDefine and isinstance(info.DefineValue, int):
|
||||
return info.DefineValue
|
||||
# 模糊匹配
|
||||
if len(parts) >= 2:
|
||||
mod_key: str
|
||||
mod_info: CTypeInfo
|
||||
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:
|
||||
@@ -240,7 +312,7 @@ class ConstEvaluator:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _intify(val):
|
||||
def _intify(val: Any) -> Any:
|
||||
"""float → int 转换(仅当 float 值恰好是整数时)"""
|
||||
if isinstance(val, float) and val == int(val):
|
||||
return int(val)
|
||||
@@ -253,36 +325,37 @@ class EvalContext:
|
||||
由调用方构造并传入 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 __init__(self, Gen: LlvmCodeGenerator | None = None, symtab: Any = None, platform_macros: dict | None = None, translator: Any = None):
|
||||
self.Gen: LlvmCodeGenerator | None = Gen
|
||||
self.symtab: Any = symtab
|
||||
self._platform_macros: dict | None = platform_macros
|
||||
self.translator: Any = translator
|
||||
|
||||
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]
|
||||
val: Any = 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]
|
||||
val: Any = 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
|
||||
info: CTypeInfo = self.symtab[name]
|
||||
val: Any = 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()
|
||||
macros: dict = self._get_platform_macros()
|
||||
if name in macros:
|
||||
return macros[name]
|
||||
|
||||
@@ -290,35 +363,39 @@ class EvalContext:
|
||||
|
||||
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
|
||||
module_name: str | None = node.value.id if isinstance(node.value, ast.Name) else None
|
||||
attr_name: str = node.attr
|
||||
|
||||
if module_name and attr_name:
|
||||
combined_key = f"{module_name}.{attr_name}"
|
||||
combined_key: str = 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]
|
||||
val: Any = self.Gen._define_constants[combined_key]
|
||||
if isinstance(val, (int, float)):
|
||||
return ConstEvaluator._intify(val)
|
||||
|
||||
# 2. SymbolTable (精确匹配 + 后缀匹配)
|
||||
if self.symtab:
|
||||
key: str
|
||||
info: CTypeInfo
|
||||
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()
|
||||
all_dc: dict = self._get_all_define_constants()
|
||||
if combined_key in all_dc:
|
||||
val = all_dc[combined_key]
|
||||
val: Any = all_dc[combined_key]
|
||||
if isinstance(val, (int, float)):
|
||||
return ConstEvaluator._intify(val)
|
||||
if attr_name in all_dc:
|
||||
val = all_dc[attr_name]
|
||||
val: Any = all_dc[attr_name]
|
||||
if isinstance(val, (int, float)):
|
||||
return ConstEvaluator._intify(val)
|
||||
dc_key: str
|
||||
dc_val: Any
|
||||
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)):
|
||||
@@ -326,23 +403,23 @@ class EvalContext:
|
||||
|
||||
# 4. SymbolTable 短名查找
|
||||
if self.symtab and attr_name in self.symtab:
|
||||
info = self.symtab[attr_name]
|
||||
info: CTypeInfo = 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]
|
||||
val: Any = 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)
|
||||
macros: dict = self._get_platform_macros()
|
||||
full_key: str | None = 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
|
||||
short_name: str = full_key.split('.')[-1] if '.' in full_key else full_key
|
||||
if short_name in macros:
|
||||
return macros[short_name]
|
||||
|
||||
@@ -360,9 +437,9 @@ class EvalContext:
|
||||
return self._platform_macros
|
||||
if not self.Gen:
|
||||
return {}
|
||||
macros = {}
|
||||
pi = getattr(self.Gen, '_platform_info', {})
|
||||
ptr_size = getattr(self.Gen, 'ptr_size', 8)
|
||||
macros: dict[str, int] = {}
|
||||
pi: dict = getattr(self.Gen, '_platform_info', {})
|
||||
ptr_size: int = getattr(self.Gen, 'ptr_size', 8)
|
||||
if pi.get('is_windows'):
|
||||
macros['_WIN32'] = 1
|
||||
if not pi.get('is_32bit'):
|
||||
@@ -393,8 +470,8 @@ class EvalContext:
|
||||
@staticmethod
|
||||
def _get_attr_full_name(node: ast.Attribute) -> Optional[str]:
|
||||
"""从 Attribute 节点提取完整名称 (e.g. 'module.name')"""
|
||||
parts = []
|
||||
current = node
|
||||
parts: list[str] = []
|
||||
current: ast.AST = node
|
||||
while isinstance(current, ast.Attribute):
|
||||
parts.append(current.attr)
|
||||
current = current.value
|
||||
|
||||
Reference in New Issue
Block a user