def test_to_bytecode(self): # if test: # x = 2 # x = 5 blocks = ControlFlowGraph() blocks.add_block() blocks.add_block() blocks[0].extend( [ Instr("LOAD_NAME", "test", lineno=1), Instr("POP_JUMP_IF_FALSE", blocks[2], lineno=1), ] ) blocks[1].extend( [ Instr("LOAD_CONST", 5, lineno=2), Instr("STORE_NAME", "x", lineno=2), Instr("JUMP_FORWARD", blocks[2], lineno=2), ] ) blocks[2].extend( [ Instr("LOAD_CONST", 7, lineno=3), Instr("STORE_NAME", "x", lineno=3), Instr("LOAD_CONST", None, lineno=3), Instr("RETURN_VALUE", lineno=3), ] ) bytecode = blocks.to_bytecode() label = Label() self.assertEqual( bytecode, [ Instr("LOAD_NAME", "test", lineno=1), Instr("POP_JUMP_IF_FALSE", label, lineno=1), Instr("LOAD_CONST", 5, lineno=2), Instr("STORE_NAME", "x", lineno=2), Instr("JUMP_FORWARD", label, lineno=2), label, Instr("LOAD_CONST", 7, lineno=3), Instr("STORE_NAME", "x", lineno=3), Instr("LOAD_CONST", None, lineno=3), Instr("RETURN_VALUE", lineno=3), ], )
def test_get_block_index(self): blocks = ControlFlowGraph() block0 = blocks[0] block1 = blocks.add_block() block2 = blocks.add_block() self.assertEqual(blocks.get_block_index(block0), 0) self.assertEqual(blocks.get_block_index(block1), 1) self.assertEqual(blocks.get_block_index(block2), 2) other_block = BasicBlock() self.assertRaises(ValueError, blocks.get_block_index, other_block)
def test_add_del_block(self): code = ControlFlowGraph() code[0].append(Instr("LOAD_CONST", 0)) block = code.add_block() self.assertEqual(len(code), 2) self.assertIs(block, code[1]) code[1].append(Instr("LOAD_CONST", 2)) self.assertBlocksEqual(code, [Instr("LOAD_CONST", 0)], [Instr("LOAD_CONST", 2)]) del code[0] self.assertBlocksEqual(code, [Instr("LOAD_CONST", 2)]) del code[0] self.assertEqual(len(code), 0)
def test_to_code(self): # test resolution of jump labels bytecode = ControlFlowGraph() bytecode.first_lineno = 3 bytecode.argcount = 3 if sys.version_info > (3, 8): bytecode.posonlyargcount = 0 bytecode.kwonlyargcount = 2 bytecode.name = "func" bytecode.filename = "hello.py" bytecode.flags = 0x43 bytecode.argnames = ("arg", "arg2", "arg3", "kwonly", "kwonly2") bytecode.docstring = None block0 = bytecode[0] block1 = bytecode.add_block() block2 = bytecode.add_block() block0.extend([ Instr("LOAD_FAST", "x", lineno=4), Instr("POP_JUMP_IF_FALSE", block2, lineno=4), ]) block1.extend([ Instr("LOAD_FAST", "arg", lineno=5), Instr("STORE_FAST", "x", lineno=5) ]) block2.extend([ Instr("LOAD_CONST", 3, lineno=6), Instr("STORE_FAST", "x", lineno=6), Instr("LOAD_FAST", "x", lineno=7), Instr("RETURN_VALUE", lineno=7), ]) if WORDCODE: expected = (b"|\x05" b"r\x08" b"|\x00" b"}\x05" b"d\x01" b"}\x05" b"|\x05" b"S\x00") else: expected = (b"|\x05\x00" b"r\x0c\x00" b"|\x00\x00" b"}\x05\x00" b"d\x01\x00" b"}\x05\x00" b"|\x05\x00" b"S") code = bytecode.to_code() self.assertEqual(code.co_consts, (None, 3)) self.assertEqual(code.co_argcount, 3) if sys.version_info > (3, 8): self.assertEqual(code.co_posonlyargcount, 0) self.assertEqual(code.co_kwonlyargcount, 2) self.assertEqual(code.co_nlocals, 6) self.assertEqual(code.co_stacksize, 1) # FIXME: don't use hardcoded constants self.assertEqual(code.co_flags, 0x43) self.assertEqual(code.co_code, expected) self.assertEqual(code.co_names, ()) self.assertEqual(code.co_varnames, ("arg", "arg2", "arg3", "kwonly", "kwonly2", "x")) self.assertEqual(code.co_filename, "hello.py") self.assertEqual(code.co_name, "func") self.assertEqual(code.co_firstlineno, 3) # verify stacksize argument is honored explicit_stacksize = code.co_stacksize + 42 code = bytecode.to_code(stacksize=explicit_stacksize) self.assertEqual(code.co_stacksize, explicit_stacksize)
def test_delitem(self): cfg = ControlFlowGraph() b = cfg.add_block() del cfg[b] self.assertEqual(len(cfg.get_instructions()), 0)