Esempio n. 1
0
    def test_it_calls_a_function_with_no_args(self):
        byte_code = Bytecode(
            tape=compiler.Tape(instructions=[
                CALL,
                0,
                RETURN,
                1,
            ]),
            constants=[
                W_Function(
                    name="callee",
                    arity=0,
                    bytecode=Bytecode(
                        name="<the callee's bytecode>",
                        arguments=(),
                        variables={},
                        constants=[W_Int32(42)],
                        tape=compiler.Tape(instructions=[
                            LOAD_CONST,
                            0,
                            RETURN,
                            1,
                        ]),
                    ),
                )
            ],
            name="<test_calls_a_function_with_no_args>",
            arguments=(),
            variables={},
        )

        rv = interpreter.CyCy().run(byte_code)
        self.assertEqual(rv, W_Int32(42))
Esempio n. 2
0
    def test_binary_leq(self):
        byte_code_lt = Bytecode(
            tape=compiler.Tape(instructions=[
                LOAD_CONST,
                0,
                LOAD_CONST,
                1,
                BINARY_LEQ,
                0,
                RETURN,
                1,
            ]),
            constants=[W_Int32(1), W_Int32(0)],
            name="<test_binary_neq>",
            arguments=(),
            variables={},
        )
        byte_code_leq = Bytecode(
            tape=compiler.Tape(instructions=[
                LOAD_CONST,
                0,
                LOAD_CONST,
                0,
                BINARY_LEQ,
                0,
                RETURN,
                1,
            ]),
            constants=[W_Int32(0)],
            name="<test_binary_neq>",
            arguments=(),
            variables={},
        )
        byte_code_gt = Bytecode(
            tape=compiler.Tape(instructions=[
                LOAD_CONST,
                0,
                LOAD_CONST,
                1,
                BINARY_LEQ,
                0,
                RETURN,
                1,
            ]),
            constants=[W_Int32(0), W_Int32(1)],
            name="<test_binary_neq>",
            arguments=(),
            variables={},
        )

        rv = interpreter.CyCy().run(byte_code_lt)
        self.assertEqual(rv, W_Bool(True))

        rv = interpreter.CyCy().run(byte_code_leq)
        self.assertEqual(rv, W_Bool(True))

        rv = interpreter.CyCy().run(byte_code_gt)
        self.assertEqual(rv, W_Bool(False))
Esempio n. 3
0
    def test_binary_sub(self):
        byte_code = Bytecode(
            tape=compiler.Tape(instructions=[
                LOAD_CONST, 0, LOAD_CONST, 1, BINARY_SUB, NO_ARG, RETURN, 1
            ]),
            constants=[W_Int32(1), W_Int32(2)],
            name="<test_binary_add>",
            arguments=(),
            variables={},
        )

        rv = interpreter.CyCy().run(byte_code)
        self.assertEqual(rv, W_Int32(1))
Esempio n. 4
0
    def test_it_handles_load_const(self):
        byte_code = Bytecode(
            tape=compiler.Tape(instructions=[
                LOAD_CONST,
                0,
                RETURN,
                1,
            ]),
            constants=[W_Int32(0)],
            name="<test_load_const>",
            arguments=(),
            variables={},
        )

        rv = interpreter.CyCy().run(byte_code)
        self.assertEqual(rv, W_Int32(0))
Esempio n. 5
0
    def test_include_statement(self):
        w_return = self.cycy.interpret([
            """
                #include "foo.h"

                int main(void) { return foo(); }
                """,
        ], )
        self.assertEqual(w_return, W_Int32(12))
Esempio n. 6
0
    def test_jump(self):
        byte_code = Bytecode(
            tape=compiler.Tape(instructions=[
                LOAD_CONST,
                0,
                JUMP,
                6,  # jump to just past LOAD_CONST 1
                LOAD_CONST,
                1,
                RETURN,
                1,
            ]),
            constants=[W_Int32(0), W_Int32(1)],
            name="<test_array_dereferences>",
            arguments=[],
            variables={},
        )

        rv = interpreter.CyCy().run(byte_code)
        self.assertEqual(rv, W_Int32(0))
Esempio n. 7
0
    def test_store_and_load_variable(self):
        byte_code = Bytecode(
            tape=compiler.Tape(instructions=[
                LOAD_CONST,
                0,
                STORE_VARIABLE,
                0,
                LOAD_VARIABLE,
                0,
                RETURN,
                1,
            ]),
            constants=[W_Int32(1)],
            name="<test_binary_add>",
            arguments=(),
            variables={"x": 0},
        )

        rv = interpreter.CyCy().run(byte_code)
        self.assertEqual(rv, W_Int32(1))
Esempio n. 8
0
    def test_while_loop(self):
        byte_code = self.get_bytecode("int main(void) {"
                                      "  int x = 0;"
                                      "  int i = 3;"
                                      "  while (i) {"
                                      "    x = x + 1;"
                                      "    i = i - 1;"
                                      "  }"
                                      "  return x;"
                                      "}")

        rv = self.interpreter.run(byte_code)
        self.assertEqual(rv, W_Int32(3))
Esempio n. 9
0
    def test_it_does_fibonacci(self):
        source = dedent("""\
        int fib(int x) {
            while (x <= 2) {
                return 1;
            }
            return fib(x - 1) + fib(x - 2);
        }
        int main(void) {
            return fib(5);
        }
        """)

        w_returned = self.cycy.interpret([source])
        self.assertEqual(w_returned, W_Int32(5))
Esempio n. 10
0
    def test_array_dereferences(self):
        byte_code = Bytecode(
            tape=compiler.Tape(instructions=[
                LOAD_CONST,
                0,
                STORE_VARIABLE,
                0,
                LOAD_CONST,
                1,
                LOAD_VARIABLE,
                0,
                DEREFERENCE,
                NO_ARG,
                RETURN,
                1,
            ]),
            constants=[W_String("bar"), W_Int32(1)],
            name="<test_array_dereferences>",
            arguments=[],
            variables={"foo": ""},
        )

        rv = interpreter.CyCy().run(byte_code)
        self.assertEqual(rv, W_Char("a"))
Esempio n. 11
0
    def run(self, byte_code, arguments=[]):
        pc = 0
        stack = []
        variables = [None] * len(byte_code.variables)

        assert len(byte_code.arguments) == len(arguments)
        for i in xrange(len(byte_code.arguments)):
            name = byte_code.arguments[i]
            index = byte_code.variables[name]
            variables[index] = arguments[i]

        while pc < len(byte_code.tape):
            jitdriver.jit_merge_point(
                pc=pc,
                stack=stack,
                variables=variables,
                byte_code=byte_code,
                arguments=arguments,
                interpreter=self,
            )

            opcode = byte_code.tape[pc]
            arg = byte_code.tape[pc + 1]
            pc += 2

            if opcode == bytecode.LOAD_CONST:
                value = byte_code.constants[arg]
                stack.append(value)
            elif opcode == bytecode.BINARY_NEQ:
                left = stack.pop()
                right = stack.pop()
                assert isinstance(left, W_Int32) or isinstance(left, W_Char)
                assert isinstance(right, W_Int32)
                stack.append(W_Bool(left.neq(right)))
            elif opcode == bytecode.PUTC:
                value = stack.pop()
                assert isinstance(value, W_Char)
                os.write(1, value.char)
                # TODO: error handling?
            elif opcode == bytecode.BINARY_LEQ:
                left = stack.pop()
                right = stack.pop()
                assert isinstance(left, W_Int32)
                assert isinstance(right, W_Int32)
                stack.append(W_Bool(left.leq(right)))
            elif opcode == bytecode.CALL:
                w_func = byte_code.constants[arg]

                args = []
                for _ in xrange(w_func.arity):
                    args.append(stack.pop())

                return_value = w_func.call(arguments=args, interpreter=self)
                if return_value is not None:
                    stack.append(return_value)
            elif opcode == bytecode.RETURN:
                if arg == 1:
                    return stack.pop()
                else:
                    return None
            elif opcode == bytecode.STORE_VARIABLE:
                val = stack.pop()
                variables[arg] = val
            elif opcode == bytecode.LOAD_VARIABLE:
                stack.append(variables[arg])
            elif opcode == bytecode.BINARY_ADD:
                left = stack.pop()
                right = stack.pop()
                assert isinstance(left, W_Int32)
                assert isinstance(right, W_Int32)
                stack.append(W_Int32(left.add(right)))
            elif opcode == bytecode.BINARY_SUB:
                left = stack.pop()
                right = stack.pop()
                assert isinstance(left, W_Int32)
                assert isinstance(right, W_Int32)
                stack.append(W_Int32(left.sub(right)))
            elif opcode == bytecode.DEREFERENCE:
                array = stack.pop()
                index = stack.pop()
                assert isinstance(array, W_String)
                assert isinstance(index, W_Int32)
                stack.append(W_Char(array.dereference(index)))
            elif opcode == bytecode.JUMP:
                old_pc = pc
                pc = arg
                if pc < old_pc:
                    # If we're jumping backwards, we're entering a loop
                    # so we can probably enter the jit
                    jitdriver.can_enter_jit(
                        pc=pc,
                        stack=stack,
                        variables=variables,
                        byte_code=byte_code,
                        arguments=arguments,
                        interpreter=self,
                    )
            elif opcode == bytecode.JUMP_IF_NOT_ZERO:
                val = stack.pop()
                if val.is_true():
                    pc = arg
            elif opcode == bytecode.JUMP_IF_ZERO:
                val = stack.pop()
                if not val.is_true():
                    pc = arg

        assert False, "bytecode exited the main loop without returning"
Esempio n. 12
0
 def compile(self, tape, compiler):
     wrapped = W_Int32(value=self.value)
     index = compiler.register_constant(wrapped)
     tape.emit(bytecode.LOAD_CONST, index)
Esempio n. 13
0
 def test_binary_sub(self):
     byte_code = self.get_bytecode("int main(void) { return 7 - 3; }")
     rv = self.interpreter.run(byte_code)
     self.assertEqual(rv, W_Int32(4))