2121PRECEDENCE_MAX = 17
2222
2323
24+ class FunctionDefinitionError (Exception ):
25+ """ An exception thrown when defining a function incorrectly """
26+
27+
2428class StackableFunctionEvaluator :
2529 """
2630 A StackableFunctionEvaluator is a wrapper for a function (self._fun) with a SINGLE argument.
@@ -88,6 +92,18 @@ def to_string(self):
8892 """
8993 return self ._str_expr
9094
95+ def assert_has_same_root_var (self , other : Any ):
96+ """
97+ Asserts that if other is also a StackableFunctionEvaluator, then it has the same root variable
98+ :param other:
99+ :return:
100+ """
101+ if isinstance (other , StackableFunctionEvaluator ):
102+ # check that both work on the same variable
103+ if self ._root_var != other ._root_var :
104+ raise FunctionDefinitionError ('It is not allowed to combine several variables (x, s, l...) in the same '
105+ 'expression' )
106+
91107 def add_unbound_method_to_stack (self , method , * m_args ):
92108 """
93109 Returns a new StackableFunctionEvaluator whose inner function will be
@@ -98,12 +114,14 @@ def add_unbound_method_to_stack(self, method, *m_args):
98114 :param m_args: optional args to apply in method calls
99115 :return:
100116 """
117+ for other in m_args :
118+ self .assert_has_same_root_var (other )
101119
102120 def evaluate_inner_function_and_apply_method (input ):
103121 # first evaluate the inner function
104122 res = self .evaluate (input )
105123 # then call the method
106- return method (res , * m_args )
124+ return method (res , * [ evaluate ( arg , input ) for arg in m_args ] )
107125
108126 # return a new InputEvaluator of the same type than self, with the new function as inner function
109127 # Note: we use precedence=None for coma-separated items inside the parenthesis
@@ -124,14 +142,16 @@ def add_bound_method_to_stack(self, method_name, *m_args):
124142 :param m_args: optional args to apply in method calls
125143 :return:
126144 """
145+ for other in m_args :
146+ self .assert_has_same_root_var (other )
127147
128148 def evaluate_inner_function_and_apply_object_method (raw_input ):
129149 # first evaluate the inner function
130150 res = self .evaluate (raw_input )
131151 # then retrieve the (bound) method on the result object, from its name
132152 object_method = getattr (res , method_name )
133153 # finally call the method
134- return object_method (* m_args )
154+ return object_method (* [ evaluate ( other , input ) for other in m_args ] )
135155
136156 # return a new InputEvaluator of the same type than self, with the new function as inner function
137157 # Note: we use precedence=None for coma-separated items inside the parenthesis
0 commit comments