import operator
if not hasattr(operator, "div"):
operator.div = operator.truediv
opnames = {
operator.add : "+",
operator.sub : "-",
operator.mul : "*",
operator.div : "/",
operator.floordiv : "//",
operator.mod : "+",
operator.pow : "**",
operator.xor : "^",
operator.lshift : "<<",
operator.rshift : ">>",
operator.and_ : "and",
operator.or_ : "or",
operator.not_ : "not",
operator.neg : "-",
operator.pos : "+",
operator.contains : "in",
operator.gt : ">",
operator.ge : ">=",
operator.lt : "<",
operator.le : "<=",
operator.eq : "==",
operator.ne : "!=",
}
class ExprMixin(object):
__slots__ = ()
def __add__(self, other):
return BinExpr(operator.add, self, other)
def __sub__(self, other):
return BinExpr(operator.sub, self, other)
def __mul__(self, other):
return BinExpr(operator.mul, self, other)
def __floordiv__(self, other):
return BinExpr(operator.floordiv, self, other)
def __truediv__(self, other):
return BinExpr(operator.div, self, other)
__div__ = __floordiv__
def __mod__(self, other):
return BinExpr(operator.mod, self, other)
def __pow__(self, other):
return BinExpr(operator.pow, self, other)
def __xor__(self, other):
return BinExpr(operator.xor, self, other)
def __rshift__(self, other):
return BinExpr(operator.rshift, self, other)
def __lshift__(self, other):
return BinExpr(operator.rshift, self, other)
def __and__(self, other):
return BinExpr(operator.and_, self, other)
def __or__(self, other):
return BinExpr(operator.or_, self, other)
def __radd__(self, other):
return BinExpr(operator.add, other, self)
def __rsub__(self, other):
return BinExpr(operator.sub, other, self)
def __rmul__(self, other):
return BinExpr(operator.mul, other, self)
def __rfloordiv__(self, other):
return BinExpr(operator.floordiv, other, self)
def __rtruediv__(self, other):
return BinExpr(operator.div, other, self)
__rdiv__ = __rfloordiv__
def __rmod__(self, other):
return BinExpr(operator.mod, other, self)
def __rpow__(self, other):
return BinExpr(operator.pow, other, self)
def __rxor__(self, other):
return BinExpr(operator.xor, other, self)
def __rrshift__(self, other):
return BinExpr(operator.rshift, other, self)
def __rlshift__(self, other):
return BinExpr(operator.rshift, other, self)
def __rand__(self, other):
return BinExpr(operator.and_, other, self)
def __ror__(self, other):
return BinExpr(operator.or_, other, self)
def __neg__(self):
return UniExpr(operator.neg, self)
def __pos__(self):
return UniExpr(operator.pos, self)
def __invert__(self):
return UniExpr(operator.not_, self)
__inv__ = __invert__
def __contains__(self, other):
return BinExpr(operator.contains, self, other)
def __gt__(self, other):
return BinExpr(operator.gt, self, other)
def __ge__(self, other):
return BinExpr(operator.ge, self, other)
def __lt__(self, other):
return BinExpr(operator.lt, self, other)
def __le__(self, other):
return BinExpr(operator.le, self, other)
def __eq__(self, other):
return BinExpr(operator.eq, self, other)
def __ne__(self, other):
return BinExpr(operator.ne, self, other)
class UniExpr(ExprMixin):
__slots__ = ["op", "operand"]
def __init__(self, op, operand):
self.op = op
self.operand = operand
def __repr__(self):
return "%s %r" % (opnames[self.op], self.operand)
def __call__(self, context):
operand = self.operand(context) if callable(self.operand) else self.operand
return self.op(operand)
class BinExpr(ExprMixin):
__slots__ = ["op", "lhs", "rhs"]
def __init__(self, op, lhs, rhs):
self.op = op
self.lhs = lhs
self.rhs = rhs
def __repr__(self):
return "(%r %s %r)" % (self.lhs, opnames[self.op], self.rhs)
def __call__(self, context):
lhs = self.lhs(context) if callable(self.lhs) else self.lhs
rhs = self.rhs(context) if callable(self.rhs) else self.rhs
return self.op(lhs, rhs)
class Path(ExprMixin):
__slots__ = ["__name", "__parent"]
def __init__(self, name, parent = None):
self.__name = name
self.__parent = parent
def __repr__(self):
if self.__parent is None:
return self.__name
return "%r.%s" % (self.__parent, self.__name)
def __call__(self, context):
if self.__parent is None:
return context
context2 = self.__parent(context)
return context2[self.__name]
def __getattr__(self, name):
return Path(name, self)
# let the magic begin!
this = Path("this")
if __name__ == "__main__":
x = ~((this.foo * 2 + 3 << 2) % 11)
print (x)
print (x({"foo" : 7}))