Files
SCam/eval.py
2021-09-29 16:10:29 +02:00

79 lines
1.6 KiB
Python

import ast
import operator
from utils import typename
BIN_OPS = {
ast.Add: operator.add,
ast.Sub: operator.sub,
ast.Mult: operator.mul,
ast.Div: operator.truediv,
ast.Mod: operator.mod
}
UNARY_OPS = {
ast.UAdd: operator.pos,
ast.USub: operator.neg
}
def forgiving_eval(value):
try:
return arithmetic_eval(value)
except:
return value
def arithmetic_eval(s):
node = ast.parse(s, mode="eval")
return ast_node_eval(node.body)
def ast_node_eval(node):
if isinstance(node, ast.Expression):
return ast_node_eval(node.body)
elif isinstance(node, ast.Str):
return node.s
elif isinstance(node, ast.Num):
return node.n
elif isinstance(node, ast.BinOp):
op = get_operator(node, BIN_OPS)
left = ast_node_eval(node.left)
right = ast_node_eval(node.right)
return op(left, right)
elif isinstance(node, ast.UnaryOp):
op = get_operator(node, UNARY_OPS)
operand = ast_node_eval(node.operand)
return op(operand)
else:
tn = typename(node)
raise ArithmeticEvalError(f"Unsupported node type {tn}")
def get_operator(node, ops):
op_type = type(node.op)
try:
op = ops[op_type]
except KeyError as e:
nn = typename(node)
on = typename(node.op)
raise ArithmeticEvalError(f"Unsupported {nn} {on}") from e
else:
return op
class ArithmeticEvalError(Exception):
pass
#TODO:
#print like SyntaxError:
# "something with an error here"
# ^
#this needs full string and offset of current node within full string stored