Exemplo n.º 1
0
def test_expression_pointer_decl():
    e2 = crep.cpp_value("dude", top_level_scope(), ctyp.terminal("int"))
    assert False == e2.is_pointer()

    e3 = crep.cpp_value("dude", top_level_scope(),
                        ctyp.terminal("int", is_pointer=True))
    assert True == e3.is_pointer()
Exemplo n.º 2
0
def test_cpp_value_as_str():
    'Make sure we can generate a str from a value - this will be important for errors'
    v1 = crep.cpp_value('dude', top_level_scope(), ctyp.terminal('int'))
    assert 'dude' in str(v1)

    v2 = crep.cpp_value('dude', top_level_scope(), None)
    assert 'dude' in str(v2)
Exemplo n.º 3
0
def test_variable_pointer():
    'Make sure is_pointer can deal with a non-type correctly'
    v1 = crep.cpp_value('dude', top_level_scope(), ctyp.terminal('int'))
    v2 = crep.cpp_value('dude', top_level_scope(), None)

    assert v1.cpp_type().type == 'int'
    with pytest.raises(RuntimeError) as e:
        v2.cpp_type()
Exemplo n.º 4
0
def test_sequence_type():
    tc = gc_scope_top_level()
    s_value = crep.cpp_value('0.0', tc, ctyp.terminal('int', False))
    i_value = crep.cpp_value('1.0', tc, ctyp.terminal('object', False))

    seq = crep.cpp_sequence(s_value, i_value, tc)

    assert seq.sequence_value().cpp_type().type == 'int'
def test_as_root_as_single_column():
    q = query_ast_visitor()
    node = ast.parse('1/1')
    value_obj = crep.cpp_value('i', gc_scope_top_level(), ctyp.terminal('int'))
    sequence = crep.cpp_sequence(
        value_obj,
        crep.cpp_value('i', gc_scope_top_level(), ctyp.terminal('int')),
        gc_scope_top_level())
    node.rep = sequence  # type: ignore
    as_root = q.get_as_ROOT(node)

    assert isinstance(as_root, rh.cpp_ttree_rep)
Exemplo n.º 6
0
def test_deepest_scope_equal():
    g = generated_code()
    s1 = statement.iftest("true")
    s2 = statement.set_var("v1", "true")
    g.add_statement(s1)
    scope_1 = g.current_scope()

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

    assert v1 == deepest_scope(v1, v2)
    assert v2 == deepest_scope(v2, v1)
Exemplo n.º 7
0
    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=ctyp.terminal('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 test_as_root_as_dict():
    q = query_ast_visitor()
    node = ast.parse('1/1')
    dict_obj = crep.cpp_dict(
        {
            ast.Constant(value='hi'):
            crep.cpp_value('i', gc_scope_top_level(), ctyp.terminal('int'))
        }, gc_scope_top_level())
    sequence = crep.cpp_sequence(
        dict_obj,  # type: ignore
        crep.cpp_value('i', gc_scope_top_level(), ctyp.terminal('int')),
        gc_scope_top_level())
    node.rep = sequence  # type: ignore
    as_root = q.get_as_ROOT(node)

    assert isinstance(as_root, rh.cpp_ttree_rep)
Exemplo n.º 9
0
def process_ast_node(visitor, gc, call_node: ast.Call):
    r'''Inject the proper code into the output stream to deal with this C++ code.

    We expect this to be run on the back-end of the system.

    visitor - The node visitor that is converting the code into C++
    gc - the generated code object that we fill with actual code
    call_node - a Call ast node, with func being a CPPCodeValue.

    Result:
    representation - A value that represents the output
    '''

    # We write everything into a new scope to prevent conflicts. So we have to declare the result ahead of time.
    cpp_ast_node = cast(CPPCodeValue, call_node.func)
    result_rep = cpp_ast_node.result_rep(gc.current_scope())

    gc.declare_variable(result_rep)

    # Include files
    for i in cpp_ast_node.include_files:
        gc.add_include(i)

    # Build the dictionary for replacement for the object we are calling
    # against, if any.
    repl_list = []
    if cpp_ast_node.replacement_instance_obj is not None:
        repl_list += [
            (cpp_ast_node.replacement_instance_obj[0],
             visitor.resolve_id(
                 cpp_ast_node.replacement_instance_obj[1]).rep.as_cpp())
        ]

    # Process the arguments that are getting passed to the function
    for arg, dest in zip(cpp_ast_node.args, call_node.args):
        rep = visitor.get_rep(dest)
        repl_list += [(arg, rep.as_cpp())]

    # Emit the statements.
    blk = statements.block()
    visitor._gc.add_statement(blk)

    for s in cpp_ast_node.running_code:
        l_s = s
        for src, dest in repl_list:
            l_s = l_s.replace(src, str(dest))
        blk.add_statement(statements.arbitrary_statement(l_s))

    # Set the result and close the scope
    assert cpp_ast_node.result is not None
    blk.add_statement(
        statements.set_var(
            result_rep,
            cpp_value(cpp_ast_node.result, gc.current_scope(),
                      result_rep.cpp_type())))
    gc.pop_scope()

    return result_rep
Exemplo n.º 10
0
    def visit_Subscript(self, node):
        'Index into an array. Check types, as tuple indexing can be very bad for us'
        v = self.get_rep(node.value)
        if not isinstance(v, crep.cpp_collection):
            raise Exception("Do not know how to take the index of type '{0}'".format(v.cpp_type()))

        index = self.get_rep(node.slice)
        node.rep = crep.cpp_value("{0}.at({1})".format(v.as_cpp(), index.as_cpp()), self._gc.current_scope(), cpp_type=v.get_element_type())  # type: ignore
        self._result = node.rep
Exemplo n.º 11
0
    def call_First(self, node: ast.AST, args: List[ast.AST]) -> Any:
        'We are in a sequence. Take the first element of the sequence and use that for future things.'

        # Unpack the source here
        assert len(args) == 1
        source = args[0]

        # Make sure we are in a loop.
        seq = self.as_sequence(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  # type: ignore
        self._result = first_value
Exemplo n.º 12
0
def test_variable_type__with_initial_update():
    tc = gc_scope_top_level()
    expr = "a"
    c_type = ctyp.terminal('int', False)
    c_init = crep.cpp_value('0.0', tc, ctyp.terminal('int', False))

    v = crep.cpp_variable(expr, tc, c_type, c_init)
    v.update_type(ctyp.terminal('float', False))

    assert v.cpp_type().type == 'float'
    assert v.initial_value().cpp_type().type == 'float'
Exemplo n.º 13
0
    def visit_UnaryOp(self, node: ast.UnaryOp):
        if type(node.op) not in _known_unary_operators:
            raise Exception(f"Do not know how to translate Unary operator {ast.dump(node.op)}!")

        operand = self.get_rep(node.operand)

        s = operand.scope()
        r = crep.cpp_value(f"({_known_unary_operators[type(node.op)]}({operand.as_cpp()}))",
                           s, operand.cpp_type())
        node.rep = r  # type: ignore
        self._result = r
Exemplo n.º 14
0
    def visit_Compare(self, node):
        'A compare between two things. Python supports more than that, but not implemented yet.'
        if len(node.ops) != 1:
            raise Exception("Do not support 1 < a < 10 comparisons yet!")

        left = self.get_rep(node.left)
        right = self.get_rep(node.comparators[0])

        r = crep.cpp_value('({0}{1}{2})'.format(left.as_cpp(), compare_operations[type(node.ops[0])], right.as_cpp()), self._gc.current_scope(), ctyp.terminal("bool"))
        node.rep = r
        self._result = r
Exemplo n.º 15
0
    def visit_function_ast(self, call_node):
        'Drop-in replacement for a function'
        # Get the arguments
        cpp_func = call_node.func
        arg_reps = [self.get_rep_value(a) for a in call_node.args]

        # Code up a call
        r = crep.cpp_value('{0}({1})'.format(cpp_func.cpp_name, ','.join(a.as_cpp() for a in arg_reps)), self._gc.current_scope(), cpp_type=cpp_func.cpp_return_type)

        # Include files and return the resulting expression
        for i in cpp_func.include_files:
            self._gc.add_include(i)
        call_node.rep = r
        return r
Exemplo n.º 16
0
    def make_sequence_from_collection(self, rep):
        '''
        Take a collection and produce a sequence. Eventually this should likely be some sort of
        plug-in architecture. But for now, we will just assume everything looks like a vector. When
        it comes time for a new type, this is where it should go.
        '''
        element_type = rep.cpp_type().element_type()
        iterator_value = crep.cpp_value(unique_name("i_obj"), None, element_type)  # type: ignore
        l_statement = statement.loop(iterator_value, crep.dereference_var(rep))  # type: ignore
        self._gc.add_statement(l_statement)
        iterator_value.reset_scope(self._gc.current_scope())

        # For a new sequence like this the sequence and iterator value are the same
        return crep.cpp_sequence(iterator_value, iterator_value, self._gc.current_scope())
Exemplo n.º 17
0
    def visit_BinOp(self, node):
        'An in-line add'
        if type(node.op) not in _known_binary_operators:
            raise Exception(f"Do not know how to translate Binary operator {ast.dump(node.op)}!")
        left = self.get_rep(node.left)
        right = self.get_rep(node.right)

        best_type = most_accurate_type([left.cpp_type(), right.cpp_type()])
        if type(node.op) is ast.Div:
            best_type = ctyp.terminal('double', False)

        s = deepest_scope(left, right).scope()
        r = crep.cpp_value(f"({left.as_cpp()}{_known_binary_operators[type(node.op)]}{right.as_cpp()})",
                           s, best_type)

        # Cache the result to push it back further up.
        node.rep = r
        self._result = r
Exemplo n.º 18
0
    def visit_Call_Member(self, call_node):
        'Method call on an object'

        # Visit everything down a level.
        self.generic_visit(call_node)

        # figure out what we are calling against, and the
        # method name we are going to be calling against.
        calling_against = self.get_rep(call_node.func.value)
        function_name = call_node.func.attr
        if not isinstance(calling_against, crep.cpp_value):
            # We didn't use get_rep_value above because now we can make a better error message.
            raise Exception("Do not know how to call '{0}' on '{1}'".format(function_name, type(calling_against).__name__))

        # We support member calls that directly translate only. Here, for example, this is only for
        # obj.pt() or similar. The translation is direct.
        c_stub = calling_against.as_cpp() + ("->" if calling_against.is_pointer() else ".")
        result_type = determine_type_mf(calling_against.cpp_type(), function_name)
        self._result = crep.cpp_value(c_stub + function_name + "()", calling_against.scope(), result_type)
Exemplo n.º 19
0
 def visit_Num(self, node):
     node.rep = crep.cpp_value(node.n, self._gc.current_scope(), guess_type_from_number(node.n))
     self._result = node.rep
Exemplo n.º 20
0
    def _create_accumulator(self, seq: crep.cpp_sequence, acc_type: ctyp.terminal, initial_value=None):
        'Helper to create an accumulator for the Aggregate function'
        accumulator_type = acc_type

        # When we implement other types of aggregate, this code will need to
        # be back in.
        # if accumulator_type is None:
        #     sv = seq.sequence_value()
        #     if not isinstance(sv, crep.cpp_value):
        #         raise Exception("Do not know how to accumulate a sequence!")
        #     accumulator_type = sv.cpp_type()
        if not check_accumulator_type(accumulator_type):
            raise ValueError(f"Aggregate over a sequence of type '{str(accumulator_type)}' is not supported.")

        # Getting the scope level right is tricky. If this is a straight sequence of items, then we want the sequence level.
        # But if this is a sequence of sequences, we are aggregating over the sequence itself. So we need to do it one level
        # up from where the iterator is running on the interior sequence.
        seq_val = seq.sequence_value()
        if isinstance(seq_val, crep.cpp_sequence):
            accumulator_scope = seq_val.iterator_value().scope()[-1]
        else:
            accumulator_scope = seq.iterator_value().scope()[-1]
        accumulator = crep.cpp_variable(unique_name("aggResult"),
                                        accumulator_scope,
                                        accumulator_type,
                                        initial_value=initial_value if initial_value is not None else crep.cpp_value(accumulator_type.default_value(), self._gc.current_scope(), accumulator_type))
        accumulator_scope.declare_variable(accumulator)

        return accumulator, accumulator_scope
Exemplo n.º 21
0
 def visit_Str(self, node):
     node.rep = crep.cpp_value('"{0}"'.format(node.s), self._gc.current_scope(), ctyp.terminal("string"))
     self._result = node.rep