def __call__(self, *args, **kwargs): """ Returns a new _LambdaExpression performing '<r>.__call__(*args, **kwargs)' on the result <r> of this expression's evaluation """ # return self.add_bound_method_to_stack('__call__', *args, **kwargs) root_var, _ = _get_root_var(self, *args, **kwargs) def ___call__(input): # first evaluate the inner function r = self.evaluate(input) # then call the method return r.__call__( *[evaluate(other, input) for other in args], **{ arg_name: evaluate(other, input) for arg_name, other in kwargs.items() }) # return a new LambdaExpression of the same type than self, with the new function as inner function # Note: we use precedence=None for coma-separated items inside the parenthesis string_expr = get_repr(self, _PRECEDENCE_SUBSCRIPTION_SLICING_CALL_ATTRREF) \ + '(' + ', '.join([get_repr(arg, None) for arg in args]) \ + (', ' if (len(args) > 0 and len(kwargs) > 0) else '')\ + ', '.join([arg_name + '=' + get_repr(arg, None) for arg_name, arg in kwargs.items()]) + ')' return type(self)( fun=___call__, precedence_level=_PRECEDENCE_SUBSCRIPTION_SLICING_CALL_ATTRREF, str_expr=string_expr, root_var=root_var)
def __or__(self, other): """ A logical OR between this _LambdaExpression and something else. The other part can either be * a scalar * a callable * a _LambdaExpression A special operation can be performed by doing '| _'. This will 'close' the expression and return a callable view of it :param other: :return: """ # Abandoned - operator | does not have precedence over comparison operators (<, >, ...) # if other is _: # # special character: close and return # return self.as_function() if not callable(other): # then the other part has already been evaluated, since this operator is not a short-circuit like the 'or' # keyword. This is probably an error from the developer ? Warn him/her warn( "One of the sides of an '|' operator is not a _LambdaExpression and therefore will always have the same" " value, whatever the input. This is most probably a mistake in the expression." ) if other: # the other part is True, there will never be a need to evaluate. return True else: # the other part is False, return a boolean expression of self (The Bool function is created later) return getattr(this_module, 'Bool')(self) else: # check that both work on the same variable root_var, _ = _get_root_var(self, other) # create a new _LambdaExpression able to evaluate both sides with short-circuit capability def evaluate_both_inner_functions_and_combine(input): # first evaluate self left = self.evaluate(input) if left: # short-circuit: the left part is True, no need to evaluate the right part return True else: # evaluate the right part return bool(evaluate(other, input)) string_expr = get_repr(self, _PRECEDENCE_BITWISE_OR) + ' | ' + get_repr( other, _PRECEDENCE_BITWISE_OR) return _LambdaExpression( fun=evaluate_both_inner_functions_and_combine, precedence_level=_PRECEDENCE_BITWISE_OR, str_expr=string_expr, root_var=root_var)
def __rpow__(self, other): """ Returns a new _LambdaExpression performing 'other ** <r>' on the result <r> of this expression's evaluation """ root_var, _ = _get_root_var(self, other) def ___rpow__(input): # first evaluate the inner function r = self.evaluate(input) # then call the method return evaluate(other, input)**r # return a new LambdaExpression of the same type than self, with the new function as inner function string_expr = get_repr(other, _PRECEDENCE_EXPONENTIATION) + ' ** ' \ + get_repr(self, _PRECEDENCE_POS_NEG_BITWISE_NOT) return type(self)(fun=___rpow__, precedence_level=13, str_expr=string_expr, root_var=root_var)
def __and__(self, other): """ A logical AND between this _LambdaExpression and something else. The other part can either be * a scalar * a callable * a _LambdaExpression :param other: :return: """ if not callable(other): # then the other part has already been evaluated, since this operator is not a short-circuit like the 'and' # keyword. This is probably an error from the developer ? Warn him/her warn( "One of the sides of an '&' operator is not a _LambdaExpression and therefore will always have the " "same value, whatever the input. This is most probably a mistake in the expression." ) if not other: # the other part is False, there will never be a need to evaluate. return False else: # the other part is True, return a boolean expression of self. (The Bool function is created later) return getattr(this_module, 'Bool')(self) else: # check that both work on the same variable root_var, _ = _get_root_var(self, other) # create a new _LambdaExpression able to evaluate both sides with short-circuit capability def evaluate_both_inner_functions_and_combine(input): # first evaluate self left = self.evaluate(input) if not left: # short-circuit: the left part is False, no need to evaluate the right part return False else: # evaluate the right part return bool(evaluate(other, input)) string_expr = get_repr(self, _PRECEDENCE_BITWISE_AND) + ' & ' + get_repr( other, _PRECEDENCE_BITWISE_AND) return _LambdaExpression( fun=evaluate_both_inner_functions_and_combine, precedence_level=_PRECEDENCE_BITWISE_AND, str_expr=string_expr, root_var=root_var)
def __xor__(self, other): """ A logical XOR between this _LambdaExpression and something else. The other part can either be * a scalar * a callable * a _LambdaExpression :param other: :return: """ if not callable(other): # then the other part has already been evaluated, since this operator is not a short-circuit like the 'or' # keyword. This is probably an error from the developer ? Warn him/her warn( "One of the sides of an '^' operator is not a _LambdaExpression and therefore will always have the " "same value, whatever the input. This is most probably a mistake in the expression." ) if other: # the other part is True, so this becomes a Not expression of self (The Not function is created later) return self.not_() else: # the other part is False, return a boolean expression of self (The Bool function is created later) return getattr(this_module, 'Bool')(self) else: # check that both work on the same variable root_var, _ = _get_root_var(self, other) # create a new _LambdaExpression able to evaluate both sides def evaluate_both_inner_functions_and_combine(input): # first evaluate self left = self.evaluate(input) # evaluate the right part right = evaluate(other, input) return (left and not right) or (not left and right) string_expr = get_repr(self, _PRECEDENCE_BITWISE_XOR) + ' ^ ' + get_repr( other, _PRECEDENCE_BITWISE_XOR) return _LambdaExpression( fun=evaluate_both_inner_functions_and_combine, precedence_level=_PRECEDENCE_BITWISE_XOR, str_expr=string_expr, root_var=root_var)
def __getattr__(self, name): """ Returns a new _LambdaExpression performing 'getattr(<r>, *args)' on the result <r> of this expression's evaluation """ root_var, _ = _get_root_var(self, name) def ___getattr__(input): # first evaluate the inner function r = self.evaluate(input) # then call the method return getattr(r, evaluate(name, input)) # return a new LambdaExpression of the same type than self, with the new function as inner function string_expr = get_repr( self, _PRECEDENCE_SUBSCRIPTION_SLICING_CALL_ATTRREF) + '.' + name return type(self)( fun=___getattr__, precedence_level=_PRECEDENCE_SUBSCRIPTION_SLICING_CALL_ATTRREF, str_expr=string_expr, root_var=root_var)
def __rdivmod__(self, other): """ Returns a new _LambdaExpression performing '<r>.__rdivmod__(*args)' on the result <r> of this expression's evaluation """ # return self.add_bound_method_to_stack('__rdivmod__', *args) root_var, _ = _get_root_var(self, other) def ___rdivmod__(input): # first evaluate the inner function r = self.evaluate(input) # then call the method return divmod(evaluate(other, input), r) # return a new LambdaExpression of the same type than self, with the new function as inner function # Note: we use precedence=None for coma-separated items inside the parenthesis string_expr = 'divmod(' + get_repr(other, None) + ', ' + get_repr( self, None) + ')' return type(self)( fun=___rdivmod__, precedence_level=_PRECEDENCE_SUBSCRIPTION_SLICING_CALL_ATTRREF, str_expr=string_expr, root_var=root_var)