修复了大量存在的问题,增加了假鸭子类型等等机制

This commit is contained in:
2026-06-25 14:49:46 +08:00
parent 19f2787db0
commit d88d11b646
827 changed files with 32617 additions and 18316 deletions

View File

@@ -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