Пример #1
0
 def visit_comprehension(self, node):
     new_node = gast.comprehension(
         target=self._visit(node.target),
         iter=self._visit(node.iter),
         ifs=self._visit(node.ifs),
         is_async=0,
     )
     return ast.copy_location(new_node, node)
Пример #2
0
 def visit_comprehension(self, node):
     new_node = gast.comprehension(
         target=self._visit(node.target),
         iter=self._visit(node.iter),
         ifs=self._visit(node.ifs),
         is_async=0,
     )
     return ast.copy_location(new_node, node)
Пример #3
0
 def visit_comprehension(self, node):
     new_node = gast.comprehension(
         target=self._visit(node.target),
         iter=self._visit(node.iter),
         ifs=self._visit(node.ifs),
         is_async=0,
     )
     gast.copy_location(new_node, node)
     new_node.end_lineno = new_node.end_col_offset = None
     return new_node
Пример #4
0
    def do_transform(ifelse_ast: AST) -> AST:
        # filter out non-ifelse statements
        if not isinstance(ifelse_ast, If):
            return ifelse_ast

        # convert ifelse condition branches into functions with the arguments
        # set to the names of the base input symbols and return values set to output symbols.
        # base symbols are use to generate the arguments as the full symbol might be qualified
        # ie A.x which is not a valid argument name: https://github.com/joeltio/bento-box/issues/37
        args = list(ifelse_ast.base_in_syms.keys())
        returns = list(ifelse_ast.output_syms.keys())
        fn_asts = [
            wrap_func_ast(
                name=name,
                args=args,
                block=block,
                returns=returns,
                # zip() requires the returned outputs to be iterable
                return_tuple=True,
            ) for name, block in zip(["__if_block", "__else_block"],
                                     [ifelse_ast.body, ifelse_ast.orelse])
        ]

        # deepcopy the condition before tracing the if/else block functions to
        # prevent side effects tracing from interfering with the condition.
        condition_ast = name_ast("__if_condition")
        eval_condition_ast = assign_ast(
            targets=[condition_ast],
            values=[call_func_ast("deepcopy", args=[ifelse_ast.test])],
        )

        # call if/else block functions to trace results of evaluating each branch
        # of the conditional if/else block functions have arguments with the same
        # names as symbols we have to pass in.
        # deepcopy to prevent input symbols from being passed by reference and
        # causing interference between branches https://github.com/joeltio/bento-box/issues/39
        import_deepcopy_ast = import_from_ast(module="copy",
                                              names=["deepcopy"])

        call_args = {
            a: call_func_ast(
                fn_name="deepcopy",
                args=[name_ast(a)],
            )
            for a in args
        }
        branch_outputs = [
            name_ast(n) for n in ["__if_outputs", "__else_outputs"]
        ]
        call_fn_asts = [
            assign_ast(
                targets=[target],
                values=[call_func_ast(fn_ast.name, args=call_args)],
            ) for target, fn_ast in zip(branch_outputs, fn_asts)
        ]

        # create switch nodes for each output symbol via list comprehension
        plot_switch_fn = parse_ast(Plotter.switch).body[0]
        # g.switch(test, if_out, else_out)
        call_switch_ast = call_func_ast(
            fn_name=plot_switch_fn.name,
            args={
                "condition": condition_ast,
                "true": name_ast("if_out"),
                "false": name_ast("else_out"),
            },
            attr_parent=ast.convert_fn.plotter_name,
        )

        # (symbol, ...) = [g.switch(...) for if_out, else_out in zip(if_outputs, else_outputs)]
        switch_asts = assign_ast(
            targets=[name_ast(r, ctx=Store()) for r in returns],
            values=[
                ListComp(
                    elt=call_switch_ast,
                    generators=[
                        comprehension(
                            target=Tuple(
                                elts=[
                                    name_ast("if_out"),
                                    name_ast("else_out"),
                                ],
                                ctx=Load(),
                            ),
                            iter=call_func_ast(
                                fn_name="zip",
                                args=branch_outputs,
                            ),
                            ifs=[],
                            is_async=False,
                        )
                    ],
                )
            ],
            force_tuple=True,
        )
        # wrap transformed code block as single AST node
        return wrap_block_ast(block=fn_asts +
                              [import_deepcopy_ast, eval_condition_ast] +
                              call_fn_asts + [switch_asts], )