Skip to content

Commit b45e3c5

Browse files
committed
Fixed add_unbound_method_to_stack and add_bound_method_to_stack so that if any argument is a lamba expression they will correctly be evaluated.
1 parent d768106 commit b45e3c5

File tree

3 files changed

+274
-286
lines changed

3 files changed

+274
-286
lines changed

code_generation/mini_lambda_template.mako

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@
33
# ----
44
from typing import Any
55

6-
from mini_lambda.base import StackableFunctionEvaluator, evaluate, get_repr
6+
from mini_lambda.base import StackableFunctionEvaluator, evaluate, get_repr, FunctionDefinitionError
77
from mini_lambda.base import PRECEDENCE_ADD_SUB, PRECEDENCE_MUL_DIV_ETC, PRECEDENCE_COMPARISON, \
88
PRECEDENCE_EXPONENTIATION, PRECEDENCE_SHIFTS, PRECEDENCE_POS_NEG_BITWISE_NOT, \
99
PRECEDENCE_SUBSCRIPTION_SLICING_CALL_ATTRREF
1010
from sys import getsizeof
1111

1212

13-
class FunctionDefinitionError(Exception):
14-
""" An exception thrown when defining a function incorrectly """
15-
16-
1713
class _LambdaExpressionGenerated(StackableFunctionEvaluator):
1814
"""
1915
This generated class implements a bunch of magic methods, so that calling these magic methods on an object will
@@ -30,18 +26,6 @@ class _LambdaExpressionGenerated(StackableFunctionEvaluator):
3026
package-level to provide a replacement (The exception message provides the replacement method name).
3127
"""
3228

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-
4529
# ******* All magic methods that need to be implemented ********
4630

4731
## For each method to override

mini_lambda/base.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
PRECEDENCE_MAX = 17
2222

2323

24+
class FunctionDefinitionError(Exception):
25+
""" An exception thrown when defining a function incorrectly """
26+
27+
2428
class 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

Comments
 (0)