def visit_SelectMany_of_SelectMany(self, parent: ast.Call,
                                       selection: ast.Lambda):
        '''
        Transformation #1:
        seq.SelectMany(x: f(x)).SelectMany(y: f(y))
        => SelectMany(SelectMany(seq, x: f(x)), y: f(y))
        is turned into:
        seq.SelectMany(x: f(x).SelectMany(y: f(y)))
        => SelectMany(seq, x: SelectMany(f(x), y: f(y)))
        '''
        _, args = unpack_Call(parent)
        assert (args is not None) and len(args) == 2
        seq = args[0]
        func_f = args[1]
        assert isinstance(func_f, ast.Lambda)
        func_g = selection

        captured_arg = func_f.args.args[0].arg
        captured_body = func_f.body
        new_select = function_call(
            'SelectMany',
            [cast(ast.AST, captured_body),
             cast(ast.AST, func_g)])
        new_select_lambda = lambda_build(captured_arg, new_select)
        new_selectmany = function_call(
            'SelectMany', [seq, cast(ast.AST, new_select_lambda)])
        return new_selectmany
Exemple #2
0
    def select_method_call_on_first(self, node: ast.Call):
        """Turn
        First(seq).method(args)
        into
        First(Select(seq, s: s.method(args)))
        """
        # Extract the call info
        assert isinstance(node.func, ast.Attribute)
        method_name = node.func.attr
        method_args = node.args
        method_keywords = (
            node.keywords
            if hasattr(node, "keywords") else node.kwargs  # type: ignore
        )

        assert isinstance(node.func.value, ast.Call)
        seq = node.func.value.args[0]

        # Now rebuild the call
        a = arg_name()
        call_args = {
            "func": ast.Attribute(value=ast.Name(a, ast.Load()),
                                  attr=method_name),
            "args": method_args,
        }
        if hasattr(node, "keywords"):
            call_args["keywords"] = method_keywords
        else:
            call_args["kwargs"] = method_keywords

        seq_a_call = ast.Call(**call_args)
        select = make_Select(seq, lambda_build(a, seq_a_call))

        return self.visit(function_call("First", [cast(ast.AST, select)]))
    def call_SelectMany(self, node: ast.Call, args: List[ast.AST]):
        r'''
        Transformation #1:
        seq.SelectMany(x: f(x)).SelectMany(y: f(y))
        => SelectMany(SelectMany(seq, x: f(x)), y: f(y))
        is turned into:
        seq.SelectMany(x: f(x).SelectMany(y: f(y)))
        => SelectMany(seq, x: SelectMany(f(x), y: f(y)))

        Transformation #2:
        seq.Select(x: f(x)).SelectMany(y: g(y))
        => SelectMany(Select(seq, x: f(x)), y:g(y))
        is turned into
        seq.SelectMany(x: g(f(x)))
        => SelectMany(seq, x: g(f(x)))

        Transformation #3:
        seq.Where(x: f(x)).SelectMany(y: g(y))
        '''
        selection = args[1]
        assert isinstance(selection, ast.Lambda)
        parent_select = self.visit(args[0])
        if is_call_of(parent_select, 'SelectMany'):
            return self.visit_SelectMany_of_SelectMany(parent_select,
                                                       selection)
        elif is_call_of(parent_select, 'Select'):
            return self.visit_SelectMany_of_Select(parent_select, selection)
        else:
            return function_call(
                'SelectMany',
                [parent_select, self.visit(selection)])
    def visit_Where_of_SelectMany(self, parent, filter):
        '''
        seq.SelectMany(x: f(x)).Where(y: g(y))
        => Where(SelectMany(seq, x: f(x)), y: g(y))
        Is turned into:
        seq.SelectMany(x: f(x).Where(y: g(y)))
        => SelectMany(seq, x: Where(f(x), g(y)))
        '''
        _, args = unpack_Call(parent)
        seq = args[0]
        func_f = args[1]
        assert isinstance(func_f, ast.Lambda)

        func_g = filter
        lambda_where = lambda_body_replace(
            func_f, function_call("Where", [lambda_body(func_f), func_g]))

        return self.visit(function_call('SelectMany', [seq, lambda_where]))
 def visit_Call(self, call_node: ast.Call) -> Optional[ast.AST]:
     node = self.generic_visit(call_node)
     if node is None or not isinstance(node, ast.Call):
         return node
     if not isinstance(node.func, ast.Attribute):
         return node
     if node.func.attr not in function_names:
         return node
     return function_call(node.func.attr, cast(List[ast.AST], [node.func.value] + node.args))
Exemple #6
0
def test_function_call_simple():
    a = function_call('dude', [as_ast(1)])
    print(ast.dump(ast.parse('dude(1)')))
    if sys.version_info < (3, 8):
        expected = "Call(func=Name(id='dude', ctx=Load()), args=[Num(n=1)], keywords=[])"
    elif sys.version_info < (3, 9):
        expected = "Call(func=Name(id='dude', ctx=Load()), args=[Constant(value=1, kind=None)], keywords=[])"
    else:
        expected = "Call(func=Name(id='dude', ctx=Load()), args=[Constant(value=1)], keywords=[])"
    assert expected == ast.dump(a)
Exemple #7
0
def _generate_count_call(seq: ast.AST, lambda_string: str = "lambda acc,v: acc+1") -> ast.Call:
    r"""
    Given a sequence, generate an Aggregate call that will count the number
    of items in the sequence.

    seq: The sequence to be counted

    returns:
    agg_ast - An ast call to the Aggregate call.
    """
    agg_lambda = cast(ast.Expr, ast.parse(lambda_string).body[0]).value
    agg_start = ast.Num(0) if sys.version_info < (3, 8, 0) else ast.Constant(0, kind=None)

    return function_call("Aggregate", [seq, cast(ast.AST, agg_start), cast(ast.AST, agg_lambda)])
Exemple #8
0
    def visit_Attribute_Of_First(self, first: ast.AST, attr: str):
        """
        Convert a seq.First().attr
        ==>
        seq.Select(l: l.attr).First()

        Other work will do the conversion as needed.
        """

        # Build the select that starts from the source and does the slice.
        a = arg_name()
        select = make_Select(
            first,
            lambda_build(
                a, ast.Attribute(value=ast.Name(a, ast.Load()), attr=attr)))

        return self.visit(function_call("First", [cast(ast.AST, select)]))
    def visit_Select_of_SelectMany(self, parent, selection):
        r'''
        seq.SelectMany(x: f(x)).Select(y: g(y))
        => Select(SelectMany(seq, x: f(x)), y: g(y))
        is turned into
        seq.SelectMany(x: f(x).Select(y: g(y)))
        => SelectMany(seq, x: Select(f(x), y: g(y)))
        '''
        (_, args) = unpack_Call(parent)
        source = args[0]
        func_f = args[1]
        assert isinstance(func_f, ast.Lambda)
        func_g = selection

        lambda_select = \
            lambda_body_replace(func_f, make_Select(lambda_body(func_f), func_g))  # type: ast.AST
        return self.visit(function_call('SelectMany', [source, lambda_select]))
    def visit_Subscript_Of_First(self, first: ast.AST, s):
        '''
        Convert a seq.First()[0]
        ==>
        seq.Select(l: l[0]).First()

        Other work will do the conversion as needed.
        '''

        # Build the select that starts from the source and does the slice.
        a = arg_name()
        select = make_Select(
            first,
            lambda_build(a,
                         ast.Subscript(ast.Name(a, ast.Load()), s,
                                       ast.Load())))

        return self.visit(function_call('First', [cast(ast.AST, select)]))
def _generate_count_call(seq: ast.AST,
                         lambda_string: str = "lambda acc,v: acc+1"
                         ) -> ast.Call:
    r'''
        Given a sequence, generate an Aggregate call that will count the number
        of items in the sequence.

        seq: The sequence to be counted

        returns:
        agg_ast - An ast call to the Aggregate call.
    '''
    agg_lambda = cast(ast.Expr, ast.parse(lambda_string).body[0]).value
    agg_start = ast.Num(0)

    return function_call(
        'Aggregate',
        [seq, cast(ast.AST, agg_start),
         cast(ast.AST, agg_lambda)])
    def visit_SelectMany_of_Select(self, parent_select: ast.Call,
                                   selection: ast.Lambda):
        '''
        seq.Select(x: f(x)).SelectMany(y: g(y))
        => SelectMany(Select(seq, x: f(x)), y:g(y))
        is turned into
        seq.SelectMany(x: f(x).Select(y: g(y)))
        => SelectMany(seq, x: Select(f(x), y: g(y)))
        '''
        _, select_args = unpack_Call(parent_select)
        assert (select_args is not None) and len(select_args) == 2
        seq = select_args[0]
        func_f = select_args[1]
        assert isinstance(func_f, ast.Lambda)
        func_g = selection

        w = function_call('SelectMany',
                          [seq, self.visit(convolute(func_g, func_f))])
        return w
    def visit_Where_of_Select(self, parent, filter):
        '''
        seq.Select(x: f(x)).Where(y: g(y))
        => Where(Select(seq, x: f(x)), y: g(y))
        Is turned into:
        seq.Where(x: g(f(x))).Select(x: f(x))
        => Select(Where(seq, x: g(f(x)), f(x))
        '''
        _, args = unpack_Call(parent)
        source = args[0]
        func_f = args[1]
        assert isinstance(func_f, ast.Lambda)
        func_g = filter

        w = function_call(
            'Where', [source, self.visit(convolute(func_g, func_f))])
        s = make_Select(w, func_f)

        # Recursively visit this mess to see if the Where needs to move further up.
        return self.visit(s)
    def call_Where(self, node: ast.Call, args: List[ast.AST]) -> ast.AST:
        r'''
        Transformation #1:
        seq.Where(x: f(x)).Where(x: g(x))
        => Where(Where(seq, x: f(x)), y: g(y))
        is turned into
        seq.Where(x: f(x) and g(y))
        => Where(seq, x: f(x) and g(y))

        Transformation #2:
        seq.Select(x: f(x)).Where(y: g(y))
        => Where(Select(seq, x: f(x)), y: g(y))
        Is turned into:
        seq.Where(x: g(f(x))).Select(x: f(x))
        => Select(Where(seq, x: g(f(x)), f(x))

        Transformation #3:
        seq.SelectMany(x: f(x)).Where(y: g(y))
        => Where(SelectMany(seq, x: f(x)), y: g(y))
        Is turned into:
        seq.SelectMany(x: f(x).Where(y: g(y)))
        => SelectMany(seq, x: Where(f(x), g(y)))
        '''
        source = args[0]
        filter = args[1]
        assert isinstance(filter, ast.Lambda)

        parent_where = self.visit(source)
        if is_call_of(parent_where, 'Where'):
            return self.visit_Where_of_Where(parent_where, filter)
        elif is_call_of(parent_where, 'Select'):
            return self.visit_Where_of_Select(parent_where, filter)
        elif is_call_of(parent_where, 'SelectMany'):
            return self.visit_Where_of_SelectMany(parent_where, filter)
        else:
            f = self.visit(filter)
            if lambda_is_true(f):
                return parent_where
            else:
                return function_call('Where', [parent_where, f])
    def visit_Where_of_Where(self, parent: ast.Call, filter: ast.Lambda):
        '''
        seq.Where(x: f(x)).Where(x: g(x))
        => Where(Where(seq, x: f(x)), y: g(y))
        is turned into
        seq.Where(x: f(x) and g(y))
        => Where(seq, x: f(x) and g(y))
        '''
        # Unpack arguments and f and g functions
        _, args = unpack_Call(parent)
        source = args[0]
        func_f = args[1]
        assert isinstance(func_f, ast.Lambda)
        func_g = filter

        arg = arg_name()
        convolution = lambda_build(
            arg,
            ast.BoolOp(ast.And(),
                       [lambda_call(arg, func_f),
                        lambda_call(arg, func_g)]))  # type: ast.AST
        return self.visit(function_call('Where', [source, convolution]))
Exemple #16
0
def test_good_ev_call():
    'Test a good call for an event collection'
    doit = function_call('Jets', [ast.parse('"antikt"').body[0].value])  # type: ignore

    getCollection(collections[0], doit)
Exemple #17
0
def test_good_ev_call_arg_number_bad():
    'Wrong number of arguments to a collection call'
    doit = function_call('Jets', [ast.parse('"antikt"').body[0].value, ast.parse('55').body[0].value])  # type: ignore

    with pytest.raises(ValueError):
        getCollection(collections[0], doit)
Exemple #18
0
def test_good_ev_call_bad_arg_type():
    'Bad collection type'
    doit = function_call('Jets', [ast.parse('55').body[0].value])  # type: ignore

    with pytest.raises(ValueError):
        getCollection(collections[0], doit)
def make_Select(source: ast.AST, selection: ast.AST):
    'Make a select, and return source is selection is an identity'
    return source if lambda_is_identity(selection) else function_call(
        'Select', [source, selection])
Exemple #20
0
def test_function_call_simple():
    a = function_call('dude', [as_ast(1)])
    print(ast.dump(ast.parse('dude(1)')))
    expected = "Call(func=Name(id='dude', ctx=Load()), args=[Num(n=1)], keywords=[])"
    assert expected == ast.dump(a)