Skip to content

Commit 7589cef

Browse files
committed
Renamed InputEvaluator to LambdaExpression.
Added the possibility to use the variable several times in operations that do not have operators, such as function calls, getitem, etc. Added checks everywhere to make sure that two different variables can not be combined in the same expression
1 parent 56434b3 commit 7589cef

File tree

4 files changed

+562
-443
lines changed

4 files changed

+562
-443
lines changed

code_generation/mini_lambda_template.mako

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# ----
22
# This file is generated by mini_lambda_methods_generation.py - do not modify it !
33
# ----
4+
from typing import Any
5+
46
from mini_lambda.base import StackableFunctionEvaluator, evaluate, get_repr
57
from mini_lambda.base import PRECEDENCE_ADD_SUB, PRECEDENCE_MUL_DIV_ETC, PRECEDENCE_COMPARISON, \
68
PRECEDENCE_EXPONENTIATION, PRECEDENCE_SHIFTS, PRECEDENCE_POS_NEG_BITWISE_NOT, \
@@ -12,11 +14,11 @@ class FunctionDefinitionError(Exception):
1214
""" An exception thrown when defining a function incorrectly """
1315

1416

15-
class _InputEvaluatorGenerated(StackableFunctionEvaluator):
17+
class _LambdaExpressionGenerated(StackableFunctionEvaluator):
1618
"""
1719
This generated class implements a bunch of magic methods, so that calling these magic methods on an object will
1820
result in adding that magic method to the StackableFunctionEvaluator's stack.
19-
This allows for example x[1] to return a new _InputEvaluatorGenerated whose stack is able to call [1] (getitem(1))
21+
This allows for example x[1] to return a new _LambdaExpressionGenerated whose stack is able to call [1] (getitem(1))
2022
on the result of the current stack's evaluation
2123

2224
The methods added below belong to two categories
@@ -28,14 +30,26 @@ class _InputEvaluatorGenerated(StackableFunctionEvaluator):
2830
package-level to provide a replacement (The exception message provides the replacement method name).
2931
"""
3032

33+
def assert_has_same_root_var(self, other: Any):
34+
"""
35+
Asserts that if other is also a StackableFunctionEvaluator, then it has the same root variable
36+
:param other:
37+
:return:
38+
"""
39+
if isinstance(other, StackableFunctionEvaluator):
40+
# check that both work on the same variable
41+
if self._root_var != other._root_var:
42+
raise FunctionDefinitionError('It is not allowed to combine several variables (x, s, l...) in the same '
43+
'expression')
44+
3145
# ******* All magic methods that need to be implemented ********
3246

3347
## For each method to override
3448
% for o in to_override:
3549
% if o.uni_operator:
3650
## ----------unitary operator such as '-'-------------------
3751
def ${o.method_name}(self):
38-
""" Returns a new _InputEvaluator performing '${o.uni_operator}<r>' on the result <r> of this evaluator's evaluation """
52+
""" Returns a new _LambdaExpression performing '${o.uni_operator}<r>' on the result <r> of this evaluator's evaluation """
3953
## def _${o.method_name}(r, input):
4054
## return ${o.uni_operator}r
4155
## return self.add_unbound_method_to_stack(_${o.method_name})
@@ -45,7 +59,7 @@ class _InputEvaluatorGenerated(StackableFunctionEvaluator):
4559
# then call the method
4660
return ${o.uni_operator}res
4761

48-
# return a new InputEvaluator of the same type than self, with the new function as inner function
62+
# return a new LambdaExpression of the same type than self, with the new function as inner function
4963
string_expr = '${o.uni_operator}' + get_repr(self, ${o.precedence_level})
5064
return type(self)(fun=_${o.method_name}, precedence_level=${o.precedence_level}, str_expr=string_expr, root_var=self._root_var)
5165

@@ -54,35 +68,37 @@ class _InputEvaluatorGenerated(StackableFunctionEvaluator):
5468
% if o.is_operator_left:
5569
## --------pairwise operator - left---------------------
5670
def ${o.method_name}(self, other):
57-
""" Returns a new _InputEvaluator performing '<r> ${o.pair_operator} other' on the result <r> of this evaluator's evaluation """
71+
""" Returns a new _LambdaExpression performing '<r> ${o.pair_operator} other' on the result <r> of this evaluator's evaluation """
5872
## def _${o.method_name}(r, input):
5973
## return r ${o.pair_operator} evaluate(other, input)
6074
## return self.add_unbound_method_to_stack(_${o.method_name})
75+
self.assert_has_same_root_var(other)
6176
def _${o.method_name}(input):
6277
# first evaluate the inner function
6378
r = self.evaluate(input)
6479
# then call the method
6580
return r ${o.pair_operator} evaluate(other, input)
6681

67-
# return a new InputEvaluator of the same type than self, with the new function as inner function
82+
# return a new LambdaExpression of the same type than self, with the new function as inner function
6883
string_expr = get_repr(self, ${o.precedence_level}) + ' ${o.pair_operator} ' + get_repr(other, ${o.precedence_level})
6984
return type(self)(fun=_${o.method_name}, precedence_level=${o.precedence_level}, str_expr=string_expr, root_var=self._root_var)
7085

7186
## -----------------------------
7287
% else:
7388
## --------pairwise operator - left---------------------
7489
def ${o.method_name}(self, other):
75-
""" Returns a new _InputEvaluator performing 'other ${o.pair_operator} <r>' on the result <r> of this evaluator's evaluation """
90+
""" Returns a new _LambdaExpression performing 'other ${o.pair_operator} <r>' on the result <r> of this evaluator's evaluation """
7691
## def _${o.method_name}(r, input):
7792
## return evaluate(other, input) ${o.pair_operator} r
7893
## return self.add_unbound_method_to_stack(_${o.method_name})
94+
self.assert_has_same_root_var(other)
7995
def _${o.method_name}(input):
8096
# first evaluate the inner function
8197
r = self.evaluate(input)
8298
# then call the method
8399
return evaluate(other, input) ${o.pair_operator} r
84100

85-
# return a new InputEvaluator of the same type than self, with the new function as inner function
101+
# return a new LambdaExpression of the same type than self, with the new function as inner function
86102
string_expr = get_repr(other, ${o.precedence_level}) + ' ${o.pair_operator} ' + get_repr(self, ${o.precedence_level})
87103
return type(self)(fun=_${o.method_name}, precedence_level=${o.precedence_level}, str_expr=string_expr, root_var=self._root_var)
88104

@@ -91,17 +107,19 @@ class _InputEvaluatorGenerated(StackableFunctionEvaluator):
91107
% elif o.unbound_method:
92108
## --------unbound method---------------------
93109
def ${o.method_name}(self, *args):
94-
""" Returns a new _InputEvaluator performing '${o.unbound_method.__name__}(<r>, *args)' on the result <r> of this evaluator's evaluation """
110+
""" Returns a new _LambdaExpression performing '${o.unbound_method.__name__}(<r>, *args)' on the result <r> of this evaluator's evaluation """
95111
## def _${o.method_name}(r, input, *args):
96112
## return ${o.unbound_method.__name__}(r, input, *args)
97113
## return self.add_unbound_method_to_stack(_${o.method_name}, *args)
114+
for other in args:
115+
self.assert_has_same_root_var(other)
98116
def _${o.method_name}(input):
99117
# first evaluate the inner function
100118
r = self.evaluate(input)
101119
# then call the method
102-
return ${o.unbound_method.__name__}(r, *args)
120+
return ${o.unbound_method.__name__}(r, *[evaluate(other, input) for other in args])
103121

104-
# return a new InputEvaluator of the same type than self, with the new function as inner function
122+
# return a new LambdaExpression of the same type than self, with the new function as inner function
105123
# Note: we use precedence=None for coma-separated items inside the parenthesis
106124
string_expr = '${o.unbound_method.__name__}(' + get_repr(self, None) + ', ' + ', '.join([get_repr(arg, None) for arg in args]) + ')'
107125
return type(self)(fun=_${o.method_name}, precedence_level=PRECEDENCE_SUBSCRIPTION_SLICING_CALL_ATTRREF,
@@ -111,15 +129,17 @@ class _InputEvaluatorGenerated(StackableFunctionEvaluator):
111129
% else:
112130
## --------general case---------------------
113131
def ${o.method_name}(self, *args):
114-
""" Returns a new _InputEvaluator performing '<r>.${o.method_name}(*args)' on the result <r> of this evaluator's evaluation """
132+
""" Returns a new _LambdaExpression performing '<r>.${o.method_name}(*args)' on the result <r> of this evaluator's evaluation """
115133
# return self.add_bound_method_to_stack('${o.method_name}', *args)
134+
for other in args:
135+
self.assert_has_same_root_var(other)
116136
def _${o.method_name}(input):
117137
# first evaluate the inner function
118138
r = self.evaluate(input)
119139
# then call the method
120-
return r.${o.method_name}(*args)
140+
return r.${o.method_name}(*[evaluate(other, input) for other in args])
121141

122-
# return a new InputEvaluator of the same type than self, with the new function as inner function
142+
# return a new LambdaExpression of the same type than self, with the new function as inner function
123143
# Note: we use precedence=None for coma-separated items inside the parenthesis
124144
string_expr = get_repr(self, PRECEDENCE_SUBSCRIPTION_SLICING_CALL_ATTRREF) + '.${o.method_name}(' + ', '.join([get_repr(arg, None) for arg in args]) + ')'
125145
return type(self)(fun=_${o.method_name}, precedence_level=PRECEDENCE_SUBSCRIPTION_SLICING_CALL_ATTRREF,
@@ -133,10 +153,10 @@ class _InputEvaluatorGenerated(StackableFunctionEvaluator):
133153
% for o in to_override_with_exception:
134154
def ${o.method_name}(self, *args):
135155
"""
136-
This magic method can not be used on an _InputEvaluator, because unfortunately python checks the
156+
This magic method can not be used on an _LambdaExpression, because unfortunately python checks the
137157
result type and does not allow it to be a custom type.
138158
"""
139-
raise FunctionDefinitionError('${o.method_name} is not supported by _InputEvaluator, since python raises an'
159+
raise FunctionDefinitionError('${o.method_name} is not supported by _LambdaExpression, since python raises an'
140160
' error when its output is not directly an object of the type it expects.'
141161
'Please use the ${o.module_method_name}() method provided at mini_lambda package'
142162
' level instead. If you did not use ${o.method_name} in your expression, you '
@@ -148,8 +168,8 @@ class _InputEvaluatorGenerated(StackableFunctionEvaluator):
148168

149169
# ******* All replacement methods for the magic methods throwing exceptions ********
150170
% for o in to_override_with_exception:
151-
def ${o.module_method_name}(evaluator: _InputEvaluatorGenerated):
152-
""" This is a replacement method for _InputEvaluator '${o.method_name}' magic method """
171+
def ${o.module_method_name}(evaluator: _LambdaExpressionGenerated):
172+
""" This is a replacement method for _LambdaExpression '${o.method_name}' magic method """
153173
% if o.unbound_method:
154174
return evaluator.add_unbound_method_to_stack(${o.unbound_method.__name__})
155175
% else:

0 commit comments

Comments
 (0)