예제 #1
0
    def code(self, codegen):
        lhs = self.lhs
        rhs = self.rhs

        left = codegen.visit(lhs)
        right = codegen.visit(rhs)

        if left.type == Integer.as_llvm() and right.type == Integer.as_llvm():
            return int_ops(codegen.builder, left, right, self)
        return float_ops(codegen.builder, left, right, self)
예제 #2
0
    def test_of_different_types_cant_be_compared(self):
        v1 = Integer(1)
        add = Add(Integer(81), Integer(14))

        expected_message = f'You can\'t compare a Value and {add.__class__.__name__}.' \
                           f'\nTokens being compared:\n{v1.dump()}\n{add}'

        # noinspection PyUnresolvedReferences
        v1.__eq__.when.called_with(add).should.throw(LogicError,
                                                     expected_message)
예제 #3
0
    def test_of_different_types_cant_be_compared(self):
        add = Add(Integer(18), Integer(120))
        v1 = Integer(1)

        expected_message = f'You can\'t compare a BinaryOp and {v1.__class__.__name__}.' \
                           f'\nTokens being compared:\n{add.dump()}\n{v1.dump}'

        # noinspection PyUnresolvedReferences
        add.__eq__.when.called_with(v1).should.throw(LogicError,
                                                     expected_message)
예제 #4
0
    def cast(self, from_, to):
        if from_.type == Integer.as_llvm() and to is Bool:
            result = self.alloc_and_store(from_, Integer.as_llvm())
            result = self.load(result)
            return self.builder.icmp_signed('!=', result, self.const(0))
        if from_.type == Float.as_llvm() and to is Bool:
            result = self.alloc_and_store(from_, Float.as_llvm())
            result = self.load(result)
            return self.builder.fcmp_ordered('!=', result, self.const(0.0))

        raise NotImplementedError('Unsupported cast')
예제 #5
0
    def test_can_be_created_from_a_list_of_statements(self):
        s1 = Add(Integer(8), Integer(10))
        s2 = Mul(Integer(18), Integer(1))
        body = [
            s1,
            s2,
        ]

        b1 = Block(body)
        b1.statements.should.contain(s1)
        b1.statements.should.contain(s2)
예제 #6
0
    def test_respects_precedences(self):
        parse("1 + 2 * 3").should.contain(
            Add(Integer(1), Mul(Integer(2), Integer(3))))

        parse("2 / 3 - 1").should.contain(
            Sub(Div(Integer(2), Integer(3)), Integer(1)))

        parse("5 * 2 - 3").should.contain(
            Sub(Mul(Integer(5), Integer(2)), Integer(3)))
예제 #7
0
    def code(self, codegen):
        init_block = codegen.add_block('for.init')
        cond_block = codegen.add_block('for.cond')
        codegen.loop_cond_blocks.append(cond_block)

        body_block = codegen.add_block('for.body')
        end_block = codegen.add_block('for.end')
        codegen.loop_end_blocks.append(end_block)

        codegen.branch(init_block)
        codegen.position_at_end(init_block)
        vector = codegen.visit(self.iterable)

        size = codegen.call('vector_size', [vector])

        size = codegen.alloc_and_store(size, Integer.as_llvm(), name='size')
        index = codegen.alloc_and_store(codegen.const(0), Integer.as_llvm(),
                                        'index')

        codegen.branch(cond_block)
        codegen.position_at_end(cond_block)

        should_go_on = codegen.builder.icmp_signed('<', codegen.load(index),
                                                   codegen.load(size))

        codegen.cbranch(should_go_on, body_block, end_block)

        codegen.position_at_end(body_block)

        pos = codegen.load(index)
        val = codegen.vector_get(vector, pos)

        codegen.assign(self.var.val, val, Integer.as_llvm())

        codegen.visit(self.body)

        if not codegen.is_break:
            codegen.builder.store(codegen.builder.add(codegen.const(1), pos),
                                  index)
            codegen.branch(cond_block)
        else:
            codegen.is_break = False

        codegen.position_at_end(end_block)
        codegen.loop_end_blocks.pop()
        codegen.loop_cond_blocks.pop()
예제 #8
0
    def const(self, val):
        # has to come first because freaking `isinstance(True, int) == True`
        if isinstance(val, bool):
            return ir.Constant(Bool.as_llvm(), val and 1 or 0)
        if isinstance(val, int):
            return ir.Constant(Integer.as_llvm(), val)
        if isinstance(val, float):
            return ir.Constant(Float.as_llvm(), val)

        raise NotImplementedError
예제 #9
0
    def _add_builtins(self):
        malloc_ty = ir.FunctionType(Int8.as_llvm().as_pointer(),
                                    [Integer.as_llvm()])
        ir.Function(self.module, malloc_ty, 'malloc')

        free_ty = ir.FunctionType(Any.as_llvm(), [Int8.as_llvm().as_pointer()])
        ir.Function(self.module, free_ty, 'free')

        puts_ty = ir.FunctionType(Integer.as_llvm(),
                                  [Int8.as_llvm().as_pointer()])
        ir.Function(self.module, puts_ty, 'puts')

        int_to_string_ty = ir.FunctionType(Int8.as_llvm().as_pointer(), [
            Integer.as_llvm(),
            Int8.as_llvm().as_pointer(),
            Integer.as_llvm()
        ])
        ir.Function(self.module, int_to_string_ty, 'int_to_string')

        printf_ty = ir.FunctionType(Integer.as_llvm(),
                                    [Int8.as_llvm().as_pointer()],
                                    var_arg=True)
        ir.Function(self.module, printf_ty, 'printf')

        vector_init_ty = ir.FunctionType(Any.as_llvm(),
                                         [List.as_llvm().as_pointer()])
        ir.Function(self.module, vector_init_ty, 'vector_init')

        vector_append_ty = ir.FunctionType(
            Any.as_llvm(),
            [List.as_llvm().as_pointer(),
             Int8.as_llvm().as_pointer()])
        ir.Function(self.module, vector_append_ty, 'vector_append')

        vector_get_ty = ir.FunctionType(
            Int8.as_llvm().as_pointer(),
            [List.as_llvm().as_pointer(),
             Integer.as_llvm()])
        ir.Function(self.module, vector_get_ty, 'vector_get')

        vector_size_ty = ir.FunctionType(Integer.as_llvm(),
                                         [List.as_llvm().as_pointer()])
        ir.Function(self.module, vector_size_ty, 'vector_size')
예제 #10
0
 def test_distinguish_by_type(self):
     Integer(1).should_not.be.equal(Float(1.0))
     Float(1.0).should_not.be.equal(Integer(1))
예제 #11
0
 def int(self, const):
     return Integer(const.value)
예제 #12
0
 def test_expr(self):
     parse(f'print(2 / 3 - 1)').should.contain(
         Print(Sub(Div(Integer(2), Integer(3)), Integer(1))))
예제 #13
0
 def vector_get(self, vector, index):
     val = self.call('vector_get', [vector, index])
     val = self.builder.ptrtoint(val, Integer.as_llvm())
     return val
예제 #14
0
 def test_division_floors_down(self):
     parse("15 / 2").should.contain(Div(Integer(15), Integer(2)))
예제 #15
0
 def test_multiplication(self):
     parse("7 * 2").should.contain(Mul(Integer(7), Integer(2)))
예제 #16
0
 def test_addition(self):
     parse("1 + 1").should.contain(Add(Integer(1), Integer(1)))
예제 #17
0
 def test_can_be_created_from_single_statement(self):
     body = Add(Integer(8), Integer(10))
     b1 = Block(body)
     b1.statements.should.contain(body)
예제 #18
0
    def test_works_for_programs(self):
        p1 = Program(Block(Add(Integer(8), Integer(10))))
        p2 = Program(Block(Add(Integer(8), Integer(10))))

        # noinspection PyUnresolvedReferences
        p1.should.be.equal(p2)
예제 #19
0
 def test_supports_multiple_lines(self):
     parse("1 - 1\n2 * 3\n",
           only_statements=False).block.statements.should.be.equal([
               Sub(Integer(1), Integer(1)),
               Mul(Integer(2), Integer(3)),
           ])
예제 #20
0
 def test_cast_to_int_when_initialized_with_strings(self):
     v1 = Integer('1')
     v1.val.should.be.a(int)
예제 #21
0
 def test_subtraction(self):
     parse("6 - 2").should.contain(Sub(Integer(6), Integer(2)))
예제 #22
0
 def test_has_a_block(self):
     prog = parse("1 + 1")
     prog.block.should.equal(Block(Add(Integer(1), Integer(1))))
예제 #23
0
 def test_division(self):
     parse("14 / 2").should.contain(Div(Integer(14), Integer(2)))
예제 #24
0
 def test_has_a_llvm_representation(self):
     Integer.as_llvm().should.be.equal(ir.IntType(32))
예제 #25
0
 def test_supports_negative_numbers(self):
     parse("1 + -1").should.contain(Sub(Integer(1), Integer(-1)))
예제 #26
0
 def test_can_be_compared(self):
     Integer(1).should.be.equal(Integer(1))
     Integer(1).should_not.be.equal(Integer(2))
예제 #27
0
 def test_int(self):
     integer = 42
     parse(f'print({integer})').should.contain(Print(Integer(integer)))
예제 #28
0
 def test_has_a_block_with_expression(self):
     prog = parse("1 + 1")
     prog.block.statements.should.contain(Add(Integer(1), Integer(1)))
예제 #29
0
 def test_expr_with_parenthesis(self):
     parse(f'print(2 / (3 - 1))').should.contain(
         Print(Div(Integer(2), Sub(Integer(3), Integer(1)))))
예제 #30
0
 def test_can_be_compared(self):
     Print(Integer(10)).should.be.equal(Print(Integer(10)))
     Print(Integer(10)).should_not.be.equal(Print(Integer(11)))