可用的回归测试通过的标准版本
This commit is contained in:
186
lib/core/Translator/ConstEval.py
Normal file
186
lib/core/Translator/ConstEval.py
Normal file
@@ -0,0 +1,186 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import llvmlite.ir as ir
|
||||
|
||||
|
||||
class ConstEvalMixin:
|
||||
"""常量表达式求值 Mixin
|
||||
|
||||
提供数组初始化常量构建与常量表达式求值能力。
|
||||
"""
|
||||
|
||||
def _BuildArrayInitConstants(self, value_node, ElemType, elem_type_node, ArrayCount, Gen):
|
||||
from lib.core.Handles.HandlesAssign import AssignHandle
|
||||
_zv = AssignHandle._zero_value(ElemType)
|
||||
_fallback = _zv if _zv is not None else ir.Constant(ElemType, ir.Undefined)
|
||||
if not isinstance(value_node, (ast.List, ast.Set)):
|
||||
return None
|
||||
if isinstance(ElemType, ir.ArrayType):
|
||||
constants = []
|
||||
for elt in value_node.elts:
|
||||
if isinstance(elt, (ast.List, ast.Set)):
|
||||
inner_consts = self._BuildMultiDimArrayInitConstants(elt, ElemType, Gen)
|
||||
if inner_consts:
|
||||
try:
|
||||
constants.append(ir.Constant(ElemType, inner_consts))
|
||||
except Exception: # fallback to _fallback on constant construction failure
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
while len(constants) < ArrayCount:
|
||||
constants.append(_fallback)
|
||||
return constants[:ArrayCount]
|
||||
StructName = None
|
||||
if isinstance(elem_type_node, ast.Name) and elem_type_node.id in Gen.structs:
|
||||
StructName = elem_type_node.id
|
||||
constants = []
|
||||
for elt in value_node.elts:
|
||||
if StructName and isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == StructName:
|
||||
const = self.ClassHandler._BuildStructConstant(elt, StructName, Gen)
|
||||
if const:
|
||||
constants.append(const)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.Constant):
|
||||
const = self.ClassHandler._BuildScalarConstant(elt, ElemType)
|
||||
if const:
|
||||
constants.append(const)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.UnaryOp):
|
||||
const = self.ClassHandler._BuildScalarConstant(elt, ElemType)
|
||||
if const:
|
||||
constants.append(const)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'chr':
|
||||
if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, int):
|
||||
try:
|
||||
constants.append(ir.Constant(ElemType, elt.args[0].value & 0xFF))
|
||||
except Exception: # fallback to _fallback on constant construction failure
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.Call) and isinstance(elt.func, ast.Name) and elt.func.id == 'ord':
|
||||
if elt.args and isinstance(elt.args[0], ast.Constant) and isinstance(elt.args[0].value, str) and len(elt.args[0].value) == 1:
|
||||
try:
|
||||
constants.append(ir.Constant(ElemType, ord(elt.args[0].value)))
|
||||
except Exception: # fallback to _fallback on constant construction failure
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
const_val = self._try_eval_const_call(elt, Gen)
|
||||
if const_val is not None:
|
||||
try:
|
||||
constants.append(ir.Constant(ElemType, const_val))
|
||||
except Exception: # fallback to _fallback on constant construction failure
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
while len(constants) < ArrayCount:
|
||||
constants.append(_fallback)
|
||||
return constants[:ArrayCount]
|
||||
|
||||
def _try_eval_const_call(self, node, Gen):
|
||||
import ast
|
||||
if isinstance(node, ast.Call):
|
||||
func_name = None
|
||||
if isinstance(node.func, ast.Name):
|
||||
func_name = node.func.id
|
||||
elif isinstance(node.func, ast.Attribute):
|
||||
func_name = node.func.attr
|
||||
if func_name:
|
||||
arg_vals = []
|
||||
for arg in node.args:
|
||||
v = self._try_eval_const_expr(arg, Gen)
|
||||
if v is None:
|
||||
return None
|
||||
arg_vals.append(v)
|
||||
if func_name == 'COLOR_RGB' and len(arg_vals) == 3:
|
||||
r, g, b = arg_vals
|
||||
return (255 << 24) | (int(b) << 16) | (int(g) << 8) | int(r)
|
||||
if func_name in Gen._DefineConstants:
|
||||
return Gen._DefineConstants[func_name]
|
||||
for key in Gen.functions:
|
||||
if key.endswith(f'__{func_name}'):
|
||||
return None
|
||||
return None
|
||||
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
|
||||
|
||||
def _BuildMultiDimArrayInitConstants(self, value_node, ArrayType, Gen):
|
||||
from lib.core.Handles.HandlesAssign import AssignHandle
|
||||
inner_type = ArrayType.element
|
||||
count = ArrayType.count
|
||||
elts = list(value_node.elts) if hasattr(value_node, 'elts') else []
|
||||
_zv = AssignHandle._zero_value(inner_type)
|
||||
_fallback = _zv if _zv is not None else ir.Constant(inner_type, ir.Undefined)
|
||||
constants = []
|
||||
for elt in elts:
|
||||
if isinstance(inner_type, ir.ArrayType):
|
||||
if isinstance(elt, (ast.List, ast.Set)):
|
||||
inner_consts = self._BuildMultiDimArrayInitConstants(elt, inner_type, Gen)
|
||||
if inner_consts:
|
||||
constants.append(ir.Constant(inner_type, inner_consts))
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.Constant):
|
||||
const = self.ClassHandler._BuildScalarConstant(elt, inner_type)
|
||||
if const:
|
||||
constants.append(const)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
elif isinstance(elt, ast.UnaryOp):
|
||||
const = self.ClassHandler._BuildScalarConstant(elt, inner_type)
|
||||
if const:
|
||||
constants.append(const)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
else:
|
||||
constants.append(_fallback)
|
||||
while len(constants) < count:
|
||||
constants.append(_fallback)
|
||||
return constants[:count]
|
||||
Reference in New Issue
Block a user