def test_deepest_scope_one_greater():
    g = generated_code()
    s1 = statement.iftest("true")
    s2 = statement.iftest("true")
    g.add_statement(s1)
    scope_1 = g.current_scope()
    g.add_statement(s2)
    scope_2 = g.current_scope()

    v1 = crep.cpp_value("v1", scope_1, ctyp.terminal('int'))
    v2 = crep.cpp_value("v2", scope_2, ctyp.terminal('int'))

    assert v2 == deepest_scope(v1, v2)
    assert v2 == deepest_scope(v2, v1)
    def visit_BoolOp(self, node):
        '''A bool op like And or Or on a set of values
        This is a bit more complex than just "anding" things as we want to make sure to short-circuit the
        evaluation if we need to.
        '''

        # The result of this test
        result = crep.cpp_variable(unique_name('bool_op'),
                                   self._gc.current_scope(),
                                   cpp_type='bool')
        self._gc.declare_variable(result)

        # How we check and short-circuit depends on if we are doing and or or.
        check_expr = result.as_cpp() if type(
            node.op) == ast.And else '!{0}'.format(result.as_cpp())
        check = crep.cpp_value(check_expr,
                               self._gc.current_scope(),
                               cpp_type='bool')

        first = True
        scope = self._gc.current_scope()
        for v in node.values:
            if not first:
                self._gc.add_statement(statement.iftest(check))

            rep_v = self.get_rep(v)
            self._gc.add_statement(statement.set_var(result, rep_v))

            if not first:
                self._gc.set_scope(scope)
            first = False

        # Cache result variable so those above us have something to use.
        self._result = result
        node.rep = result
    def visit_IfExp(self, node):
        r'''
        We'd like to be able to use the "?" operator in C++, but the
        problem is lazy evaluation. It could be when we look at one or the
        other item, a bunch of prep work has to be done - and that will
        show up in separate statements. So we have to use if/then/else with
        a result value.
        '''

        # The result we'll store everything in.
        result = crep.cpp_variable(unique_name("if_else_result"),
                                   self._gc.current_scope(),
                                   cpp_type=ctyp.terminal("double"))
        self._gc.declare_variable(result)

        # We always have to evaluate the test.
        current_scope = self._gc.current_scope()
        test_expr = self.get_rep(node.test)
        self._gc.add_statement(statement.iftest(test_expr))
        if_scope = self._gc.current_scope()

        # Next, we do the true and false if statement.
        self._gc.add_statement(
            statement.set_var(result, self.get_rep(node.body)))
        self._gc.set_scope(if_scope)
        self._gc.pop_scope()
        self._gc.add_statement(statement.elsephrase())
        self._gc.add_statement(
            statement.set_var(result, self.get_rep(node.orelse)))
        self._gc.set_scope(current_scope)

        # Done, the result is the rep of this node!
        node.rep = result
        self._result = result
    def visit_Call_Aggregate_only(self, node: ast.Call):
        '''
        - (acc lambda): the accumulator is set to the first element, and the lambda is called to
                        update it after that. This is called `agg_only`.
        '''
        agg_lambda = node.args[0]

        # Get the sequence we are calling against and the accumulator
        if not isinstance(node.func, ast.Attribute):
            raise BaseException("Wrong type of function")
        seq = self.as_sequence(node.func.value)
        accumulator, accumulator_scope = self.create_accumulator(seq)

        # We have to do a simple if statement here so that the first time through we can set the
        # accumulator, and the second time we can add to it.

        is_first_iter = crep.cpp_variable(unique_name("is_first"),
                                          self._gc.current_scope(),
                                          cpp_type=ctyp.terminal('bool'),
                                          initial_value=crep.cpp_value(
                                              'true', self._gc.current_scope(),
                                              ctyp.terminal('bool')))
        accumulator_scope.declare_variable(is_first_iter)

        # Set the scope where we will be doing the accumulation
        sv = seq.sequence_value()
        if isinstance(sv, crep.cpp_sequence):
            self._gc.set_scope(sv.iterator_value().scope()[-1])
        else:
            self._gc.set_scope(sv.scope())

        # Code up if statement to select out the first element.
        if_first = statement.iftest(is_first_iter)
        self._gc.add_statement(if_first)
        self._gc.add_statement(
            statement.set_var(
                is_first_iter,
                crep.cpp_value("false", self._gc.current_scope(),
                               ctyp.terminal('bool'))))

        # Set the accumulator
        self._gc.add_statement(
            statement.set_var(accumulator, seq.sequence_value()))
        self._gc.pop_scope()

        # Now do the if statement and make the call to calculate the accumulation.
        self._gc.add_statement(statement.elsephrase())
        call = ast.Call(
            func=agg_lambda,
            args=[accumulator.as_ast(),
                  seq.sequence_value().as_ast()])
        self._gc.add_statement(
            statement.set_var(accumulator, self.get_rep(call)))

        # Finally, since this is a terminal, we need to pop off the top.
        self._gc.set_scope(accumulator_scope)

        # Cache the results in our result in case we are skipping nodes in the AST.
        node.rep = accumulator
        self._result = accumulator
Example #5
0
def test_get_rep_works_and_doesnt():
    g = generated_code()
    s1 = statement.iftest("true")
    g.set_rep("dude", 5)
    assert 5 is g.get_rep("dude")
    g.pop_scope()
    assert None is g.get_rep("dude")
Example #6
0
def test_insert_in_middle():
    s1 = statement.iftest("true")
    s2 = statement.set_var("v1", "true")
    g = generated_code()

    g.add_statement(s1)
    g.add_statement(s2)

    s3 = statement.iftest("fork")
    g.add_statement(s3, below=s1)

    assert 1 == len(s1._statements)
    assert 1 == len(s3._statements)

    assert s1._statements[0] is s3
    assert s3._statements[0] is s2
def test_nothing_else_starts_with_top_level_scope():
    top = gc_scope_top_level()
    g = generated_code()
    s1 = statement.iftest("true")
    g.add_statement(s1)
    scope_1 = g.current_scope()

    assert not top.starts_with(scope_1)
def test_everything_starts_with_top_level_scope():
    top = gc_scope_top_level()
    g = generated_code()
    s1 = statement.iftest("true")
    g.add_statement(s1)
    scope_1 = g.current_scope()

    assert scope_1.starts_with(top)
Example #9
0
def test_get_rep_hidden():
    g = generated_code()
    g.set_rep("dude", 5)
    s1 = statement.iftest("true")
    g.add_statement(s1)
    g.set_rep("dude", 10)
    assert 10 is g.get_rep("dude")
    g.pop_scope()
    assert 5 is g.get_rep("dude")
Example #10
0
def test_insert_two_levels():
    s1 = statement.iftest("true")
    s2 = statement.set_var("v1", "true")
    g = generated_code()

    g.add_statement(s1)
    g.add_statement(s2)

    assert 1 == len(s1._statements)
    def visit_First(self, node):
        'We are in a sequence. Take the first element of the sequence and use that for future things.'

        # Make sure we are in a loop.
        seq = self.as_sequence(node.source)

        # The First terminal works by protecting the code with a if (first_time) {} block.
        # We need to declare the first_time variable outside the block where the thing we are
        # looping over here is defined. This is a little tricky, so we delegate to another method.
        loop_scope = seq.iterator_value().scope()
        outside_block_scope = loop_scope[-1]

        # Define the variable to track this outside that block.
        is_first = crep.cpp_variable(unique_name('is_first'),
                                     outside_block_scope,
                                     cpp_type=ctyp.terminal('bool'),
                                     initial_value=crep.cpp_value(
                                         'true', self._gc.current_scope(),
                                         ctyp.terminal('bool')))
        outside_block_scope.declare_variable(is_first)

        # Now, as long as is_first is true, we can execute things inside this statement.
        # The trick is putting the if statement in the right place. We need to locate it just one level
        # below where we defined the scope above.
        s = statement.iftest(is_first)
        s.add_statement(
            statement.set_var(
                is_first,
                crep.cpp_value('false',
                               top_level_scope(),
                               cpp_type=ctyp.terminal('bool'))))

        sv = seq.sequence_value()
        if isinstance(sv, crep.cpp_sequence):
            self._gc.set_scope(sv.iterator_value().scope()[-1])
        else:
            self._gc.set_scope(sv.scope())
        self._gc.add_statement(s)

        # If we just found the first sequence in a sequence, return that.
        # Otherwise return a new version of the value.
        first_value = sv if isinstance(
            sv, crep.cpp_sequence) else sv.copy_with_new_scope(
                self._gc.current_scope())

        node.rep = first_value
        self._result = first_value
    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
Example #13
0
def test_get_rep_when_set_level_up():
    g = generated_code()
    g.set_rep("dude", 5)
    s1 = statement.iftest("true")
    g.add_statement(s1)
    assert 5 is g.get_rep("dude")