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))
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))
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))
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))
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))
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))
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))
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))
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))
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"))
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"
def compile(self, tape, compiler): wrapped = W_Int32(value=self.value) index = compiler.register_constant(wrapped) tape.emit(bytecode.LOAD_CONST, index)
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))