getting wild
This commit is contained in:
parent
5dfde1fb23
commit
f74ef82275
4 changed files with 44 additions and 18 deletions
|
|
@ -156,7 +156,11 @@ class Script:
|
||||||
if lambda_type := spec.is_lambda_function:
|
if lambda_type := spec.is_lambda_function:
|
||||||
|
|
||||||
lambda_function_names = set(
|
lambda_function_names = set(
|
||||||
[lamb.value for lamb in function.args if isinstance(lamb, Lambda)]
|
[
|
||||||
|
lamb.value
|
||||||
|
for lamb in SyntaxTree(function.args).lambdas
|
||||||
|
if isinstance(lamb, Lambda)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Only case len(lambda_function_names) > 1 is when used in if-statements
|
# Only case len(lambda_function_names) > 1 is when used in if-statements
|
||||||
|
|
@ -202,7 +206,11 @@ class Script:
|
||||||
if lambda_type := spec.is_lambda_function:
|
if lambda_type := spec.is_lambda_function:
|
||||||
|
|
||||||
lambda_function_names = set(
|
lambda_function_names = set(
|
||||||
[lamb.value for lamb in function.args if isinstance(lamb, Lambda)]
|
[
|
||||||
|
lamb.value
|
||||||
|
for lamb in SyntaxTree(function.args).lambdas
|
||||||
|
if isinstance(lamb, Lambda)
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Only case len(lambda_function_names) > 1 is when used in if-statements
|
# Only case len(lambda_function_names) > 1 is when used in if-statements
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,14 @@ class VariableDependency(ABC):
|
||||||
def _iterable_arguments(self) -> List[Argument]:
|
def _iterable_arguments(self) -> List[Argument]:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _recurse_get(self, ttype: Type[TType]) -> List[TType]:
|
def _recurse_get(self, ttype: Type[TType], subclass: bool = False) -> List[TType]:
|
||||||
output: List[TType] = []
|
output: List[TType] = []
|
||||||
for arg in self._iterable_arguments:
|
for arg in self._iterable_arguments:
|
||||||
if isinstance(arg, ttype):
|
if subclass and issubclass(type(arg), ttype):
|
||||||
output.append(arg)
|
output.append(arg)
|
||||||
|
elif isinstance(arg, ttype):
|
||||||
|
output.append(arg)
|
||||||
|
|
||||||
if isinstance(arg, VariableDependency):
|
if isinstance(arg, VariableDependency):
|
||||||
output.extend(arg._recurse_get(ttype))
|
output.extend(arg._recurse_get(ttype))
|
||||||
|
|
||||||
|
|
@ -56,6 +59,11 @@ class VariableDependency(ABC):
|
||||||
def function_arguments(self) -> Set[FunctionArgument]:
|
def function_arguments(self) -> Set[FunctionArgument]:
|
||||||
return set(self._recurse_get(FunctionArgument))
|
return set(self._recurse_get(FunctionArgument))
|
||||||
|
|
||||||
|
@final
|
||||||
|
@property
|
||||||
|
def lambdas(self) -> Set[Lambda]:
|
||||||
|
return set(self._recurse_get(Lambda, subclass=True))
|
||||||
|
|
||||||
@final
|
@final
|
||||||
@property
|
@property
|
||||||
def custom_functions(self) -> Set[ParsedCustomFunction]:
|
def custom_functions(self) -> Set[ParsedCustomFunction]:
|
||||||
|
|
|
||||||
|
|
@ -60,12 +60,6 @@ def is_type_compatible(
|
||||||
arg_type: Type[NamedType] = arg.__class__
|
arg_type: Type[NamedType] = arg.__class__
|
||||||
if isinstance(arg, BuiltInFunctionType):
|
if isinstance(arg, BuiltInFunctionType):
|
||||||
arg_type = arg.output_type() # built-in function
|
arg_type = arg.output_type() # built-in function
|
||||||
elif isinstance(arg, Lambda):
|
|
||||||
# lambda, check if expected_arg_type is a subclass
|
|
||||||
# Do not return on just that to also allow lambdas to be returned as
|
|
||||||
# ReturnableArguments (i.e in an %if statement)
|
|
||||||
if issubclass(expected_arg_type, arg_type):
|
|
||||||
return True
|
|
||||||
elif isinstance(arg, FunctionType):
|
elif isinstance(arg, FunctionType):
|
||||||
return True # custom-function, can be anything, so pass for now
|
return True # custom-function, can be anything, so pass for now
|
||||||
elif isinstance(arg, Variable):
|
elif isinstance(arg, Variable):
|
||||||
|
|
@ -94,6 +88,12 @@ def is_type_compatible(
|
||||||
if not issubclass(union_type, expected_arg_type):
|
if not issubclass(union_type, expected_arg_type):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
elif issubclass(arg_type, Lambda) and issubclass(expected_arg_type, arg_type):
|
||||||
|
# lambda, check if expected_arg_type is a subclass
|
||||||
|
# Do not return on just that to also allow lambdas to be returned as
|
||||||
|
# ReturnableArguments (i.e in an %if statement)
|
||||||
|
return True
|
||||||
|
|
||||||
elif not issubclass(arg_type, expected_arg_type):
|
elif not issubclass(arg_type, expected_arg_type):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,12 @@ class TestLambdaFunction:
|
||||||
}
|
}
|
||||||
).resolve() == {"output": Integer(4)}
|
).resolve() == {"output": Integer(4)}
|
||||||
|
|
||||||
def test_custom_function_lambda_in_variable_incompatible_number_of_args(self):
|
|
||||||
|
class TestLambdaFunctionIncompatibleNumArguments:
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"lambda_value", ["%enumerate_output", "%if(False, %capitalize, %enumerate_output)"]
|
||||||
|
)
|
||||||
|
def test_custom_function_lambda_in_variable(self, lambda_value: str):
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
IncompatibleFunctionArguments,
|
IncompatibleFunctionArguments,
|
||||||
match=re.escape(
|
match=re.escape(
|
||||||
|
|
@ -65,11 +70,12 @@ class TestLambdaFunction:
|
||||||
{
|
{
|
||||||
"%enumerate_output": "{[$0, $1]}",
|
"%enumerate_output": "{[$0, $1]}",
|
||||||
"array1": "{['a', 'b', 'c']}",
|
"array1": "{['a', 'b', 'c']}",
|
||||||
"output": "{%array_apply(array1, %enumerate_output)}",
|
"output": f"{{%array_apply(array1, {lambda_value})}}",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_function_lambda_in_variable_incompatible_number_of_args(self):
|
@pytest.mark.parametrize("lambda_value", ["%replace", "%if(False, %capitalize, %replace)"])
|
||||||
|
def test_function_lambda_in_variable(self, lambda_value: str):
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
IncompatibleFunctionArguments,
|
IncompatibleFunctionArguments,
|
||||||
match=re.escape(
|
match=re.escape(
|
||||||
|
|
@ -80,11 +86,14 @@ class TestLambdaFunction:
|
||||||
Script(
|
Script(
|
||||||
{
|
{
|
||||||
"array1": "{['a', 'b', 'c']}",
|
"array1": "{['a', 'b', 'c']}",
|
||||||
"output": "{%array_apply(array1, %replace)}",
|
"output": f"{{%array_apply(array1, {lambda_value})}}",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_custom_function_lambda_in_custom_function_incompatible_number_of_args(self):
|
@pytest.mark.parametrize(
|
||||||
|
"lambda_value", ["%enumerate_output", "%if(False, %concat, %enumerate_output)"]
|
||||||
|
)
|
||||||
|
def test_custom_function_lambda_in_custom_function(self, lambda_value: str):
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
IncompatibleFunctionArguments,
|
IncompatibleFunctionArguments,
|
||||||
match=re.escape(
|
match=re.escape(
|
||||||
|
|
@ -96,11 +105,12 @@ class TestLambdaFunction:
|
||||||
{
|
{
|
||||||
"%enumerate_output": "{[$0, $1, $2]}",
|
"%enumerate_output": "{[$0, $1, $2]}",
|
||||||
"array1": "{['a', 'b', 'c']}",
|
"array1": "{['a', 'b', 'c']}",
|
||||||
"%output": "{%array_enumerate(array1, %enumerate_output)}",
|
"%output": f"{{%array_enumerate(array1, {lambda_value})}}",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_function_lambda_in_custom_function_incompatible_number_of_args(self):
|
@pytest.mark.parametrize("lambda_value", ["%replace", "%if(False, %concat, %replace)"])
|
||||||
|
def test_function_lambda_in_custom_function(self, lambda_value: str):
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
IncompatibleFunctionArguments,
|
IncompatibleFunctionArguments,
|
||||||
match=re.escape(
|
match=re.escape(
|
||||||
|
|
@ -111,6 +121,6 @@ class TestLambdaFunction:
|
||||||
Script(
|
Script(
|
||||||
{
|
{
|
||||||
"array1": "{['a', 'b', 'c']}",
|
"array1": "{['a', 'b', 'c']}",
|
||||||
"%output": "{%array_enumerate(array1, %replace)}",
|
"%output": f"{{%array_enumerate(array1, {lambda_value})}}",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue