def test_lambda_replace_simple_expression(): a1 = ast.parse("lambda x: x") nexpr = ast.parse("lambda y: y + 1") expr = lambda_unwrap(nexpr).body a2 = lambda_body_replace(lambda_unwrap(a1), expr) a2_txt = ast.dump(a2) assert "op=Add(), right=Num(n=1))" in a2_txt
def test_lambda_replace_simple_expression(): a1 = ast.parse("lambda x: x") nexpr = ast.parse("lambda y: y + 1") expr = lambda_unwrap(nexpr).body a2 = lambda_body_replace(lambda_unwrap(a1), expr) a2_txt = ast.dump(a2) if sys.version_info < (3, 8): assert "op=Add(), right=Num(n=1))" in a2_txt elif sys.version_info < (3, 9): assert "op=Add(), right=Constant(value=1, kind=None))" in a2_txt else: assert "op=Add(), right=Constant(value=1))" in a2_txt
def convolute(ast_g: ast.Lambda, ast_f: ast.Lambda): "Return an AST that represents g(f(args))" # Combine the lambdas into a single call by calling g with f as an argument l_g = make_args_unique(lambda_unwrap(ast_g)) l_f = make_args_unique(lambda_unwrap(ast_f)) x = arg_name() f_arg = ast.Name(x, ast.Load()) call_g = ast.Call(l_g, [ast.Call(l_f, [f_arg], [])], []) call_g_lambda = lambda_build(x, call_g) # Build a new call to nest the functions return call_g_lambda
def call_Where(self, node: ast.AST, args: List[ast.AST]): 'Apply a filtering to the current loop.' assert len(args) == 2 source = args[0] filter = args[1] assert isinstance(filter, ast.Lambda) # Make sure we are in a loop seq = self.as_sequence(source) # Simulate the filtering call - we want the resulting value to test. filter = lambda_unwrap(filter) c = ast.Call(func=filter, args=[seq.sequence_value().as_ast()]) rep = self.get_rep(c) # Create an if statement self._gc.add_statement(statement.iftest(rep)) # Ok - new sequence. This the same as the old sequence, only the sequence value is updated. # Protect against sequence of sequences (LOVE type checkers, which caught this as a possibility) w_val = seq.sequence_value() if isinstance(w_val, crep.cpp_sequence): raise Exception("Error: A Where clause must evaluate to a value, not a sequence") new_sequence_var = w_val.copy_with_new_scope(self._gc.current_scope()) node.rep = crep.cpp_sequence(new_sequence_var, seq.iterator_value(), self._gc.current_scope()) # type: ignore self._result = node.rep # type: ignore
def call_SelectMany(self, node: ast.AST, args: List[ast.AST]): r''' Apply the selection function to the base to generate a collection, and then loop over that collection. ''' assert len(args) == 2 source = args[0] selection = args[1] assert isinstance(selection, ast.Lambda) # Make sure the source is around. We have to do this because code generation in this # framework is lazy. And if the `selection` function does not use the source, and # looking at that source might generate a loop, that loop won't be generated! Ops! _ = self.as_sequence(source) # We need to "call" the source with the function. So build up a new # call, and then visit it. c = ast.Call(func=lambda_unwrap(selection), args=[source]) # Get the collection, and then generate the loop over it. # It could be that this comes back from something that is already iterating (like a Select statement), # in which case we are already looping. seq = self.as_sequence(c) node.rep = seq # type: ignore self._result = seq return seq
def convolute(ast_g: ast.Lambda, ast_f: ast.Lambda): 'Return an AST that represents g(f(args))' # TODO: fix up the ast.Calls to use lambda_call if possible # Combine the lambdas into a single call by calling g with f as an argument l_g = copy.deepcopy(lambda_unwrap(ast_g)) l_f = copy.deepcopy(lambda_unwrap(ast_f)) x = arg_name() f_arg = ast.Name(x, ast.Load()) call_g = ast.Call(l_g, [ast.Call(l_f, [f_arg], [])], []) # TODO: Rewrite with lambda_build args = ast.arguments(args=[ast.arg(arg=x)]) call_g_lambda = ast.Lambda(args=args, body=call_g) # Build a new call to nest the functions return call_g_lambda
def convolute(ast_g, ast_f): 'Return an AST that represents g(f(args))' # TODO: fix up the ast.Calls to use lambda_call if possible # Sanity checks. For example, g can have only one input argument (e.g. f's result) if (not lambda_test(ast_g)) or (not lambda_test(ast_f)): raise BaseException("Only lambdas in Selects!") # Combine the lambdas into a single call by calling g with f as an argument l_g = copy.deepcopy(lambda_unwrap(ast_g)) l_f = copy.deepcopy(lambda_unwrap(ast_f)) x = arg_name() f_arg = ast.Name(x, ast.Load()) call_g = ast.Call(l_g, [ast.Call(l_f, [f_arg], [])], []) # TODO: Rewrite with lambda_build args = ast.arguments(args=[ast.arg(arg=x)]) call_g_lambda = ast.Lambda(args=args, body=call_g) # Build a new call to nest the functions return call_g_lambda
def visit_Select(self, select_ast): 'Transform the iterable from one form to another' # Make sure we are in a loop seq = self.as_sequence(select_ast.source) # Simulate this as a "call" selection = lambda_unwrap(select_ast.selection) c = ast.Call(func=selection, args=[seq.sequence_value().as_ast()]) new_sequence_value = self.get_rep(c) # We need to build a new sequence. rep = crep.cpp_sequence(new_sequence_value, seq.iterator_value()) select_ast.rep = rep self._result = rep
def call_Select(self, node: ast.Call, args: List[ast.arg]): 'Transform the iterable from one form to another' assert len(args) == 2 source = args[0] selection = cast(ast.Lambda, args[1]) # Make sure we are in a loop seq = self.as_sequence(source) # Simulate this as a "call" selection = lambda_unwrap(selection) c = ast.Call(func=selection, args=[seq.sequence_value().as_ast()]) new_sequence_value = self.get_rep(c) # We need to build a new sequence. rep = crep.cpp_sequence(new_sequence_value, seq.iterator_value(), self._gc.current_scope()) node.rep = rep # type: ignore self._result = rep return rep
def visit_Where(self, node): 'Apply a filtering to the current loop.' # Make sure we are in a loop seq = self.as_sequence(node.source) # Simulate the filtering call - we want the resulting value to test. filter = lambda_unwrap(node.filter) c = ast.Call(func=filter, args=[seq.sequence_value().as_ast()]) rep = self.get_rep(c) # Create an if statement self._gc.add_statement(statement.iftest(rep)) # Ok - new sequence. This the same as the old sequence, only the sequence value is updated. # Protect against sequence of sequences (LOVE type checkers, which caught this as a possibility) w_val = seq.sequence_value() if isinstance(w_val, crep.cpp_sequence): raise BaseException( "Internal error: don't know how to look at a sequence") new_sequence_var = w_val.copy_with_new_scope(self._gc.current_scope()) node.rep = crep.cpp_sequence(new_sequence_var, seq.iterator_value()) self._result = node.rep
def test_parse_as_ast_lambda(): ln = lambda_unwrap(ast.parse("lambda x: x + 1")) r = parse_as_ast(ln) assert isinstance(r, ast.Lambda)