3 from cStringIO import StringIO
17 return disassemble(compile(line, '', 'single'))
19 class TestTranforms(unittest.TestCase):
22 # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE
26 asm = disassemble(unot)
27 for elem in ('UNARY_NOT', 'POP_JUMP_IF_FALSE'):
28 self.assertNotIn(elem, asm)
29 self.assertIn('POP_JUMP_IF_TRUE', asm)
31 def test_elim_inversion_of_is_or_in(self):
33 ('not a is b', '(is not)',),
34 ('not a in b', '(not in)',),
35 ('not a is not b', '(is)',),
36 ('not a not in b', '(in)',),
38 asm = dis_single(line)
39 self.assertIn(elem, asm)
41 def test_none_as_constant(self):
42 # LOAD_GLOBAL None --> LOAD_CONST None
47 for elem in ('LOAD_GLOBAL',):
48 self.assertNotIn(elem, asm)
49 for elem in ('LOAD_CONST', '(None)'):
50 self.assertIn(elem, asm)
52 'Adding a docstring made this test fail in Py2.5.0'
54 self.assertIn('LOAD_CONST', disassemble(f))
55 self.assertNotIn('LOAD_GLOBAL', disassemble(f))
57 def test_while_one(self):
58 # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx
64 for elem in ('LOAD_CONST', 'POP_JUMP_IF_FALSE'):
65 self.assertNotIn(elem, asm)
66 for elem in ('JUMP_ABSOLUTE',):
67 self.assertIn(elem, asm)
69 def test_pack_unpack(self):
71 ('a, = a,', 'LOAD_CONST',),
72 ('a, b = a, b', 'ROT_TWO',),
73 ('a, b, c = a, b, c', 'ROT_THREE',),
75 asm = dis_single(line)
76 self.assertIn(elem, asm)
77 self.assertNotIn('BUILD_TUPLE', asm)
78 self.assertNotIn('UNPACK_TUPLE', asm)
80 def test_folding_of_tuples_of_constants(self):
82 ('a = 1,2,3', '((1, 2, 3))'),
83 ('("a","b","c")', "(('a', 'b', 'c'))"),
84 ('a,b,c = 1,2,3', '((1, 2, 3))'),
85 ('(None, 1, None)', '((None, 1, None))'),
86 ('((1, 2), 3, 4)', '(((1, 2), 3, 4))'),
88 asm = dis_single(line)
89 self.assertIn(elem, asm)
90 self.assertNotIn('BUILD_TUPLE', asm)
92 # Bug 1053819: Tuple of constants misidentified when presented with:
93 # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . .
94 # The following would segfault upon compilation
97 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
98 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
99 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
100 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
101 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
102 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
103 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
104 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
105 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
106 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
109 def test_folding_of_binops_on_constants(self):
111 ('a = 2+3+4', '(9)'), # chained fold
112 ('"@"*4', "('@@@@')"), # check string ops
113 ('a="abc" + "def"', "('abcdef')"), # check string ops
114 ('a = 3**4', '(81)'), # binary power
115 ('a = 3*4', '(12)'), # binary multiply
116 ('a = 13//4', '(3)'), # binary floor divide
117 ('a = 14%4', '(2)'), # binary modulo
118 ('a = 2+3', '(5)'), # binary add
119 ('a = 13-4', '(9)'), # binary subtract
120 ('a = (12,13)[1]', '(13)'), # binary subscr
121 ('a = 13 << 2', '(52)'), # binary lshift
122 ('a = 13 >> 2', '(3)'), # binary rshift
123 ('a = 13 & 7', '(5)'), # binary and
124 ('a = 13 ^ 7', '(10)'), # binary xor
125 ('a = 13 | 7', '(15)'), # binary or
127 asm = dis_single(line)
128 self.assertIn(elem, asm, asm)
129 self.assertNotIn('BINARY_', asm)
131 # Verify that unfoldables are skipped
132 asm = dis_single('a=2+"b"')
133 self.assertIn('(2)', asm)
134 self.assertIn("('b')", asm)
136 # Verify that large sequences do not result from folding
137 asm = dis_single('a="x"*1000')
138 self.assertIn('(1000)', asm)
140 def test_folding_of_unaryops_on_constants(self):
142 ('`1`', "('1')"), # unary convert
143 ('-0.5', '(-0.5)'), # unary negative
144 ('~-2', '(1)'), # unary invert
146 asm = dis_single(line)
147 self.assertIn(elem, asm, asm)
148 self.assertNotIn('UNARY_', asm)
150 # Verify that unfoldables are skipped
152 ('-"abc"', "('abc')"), # unary negative
153 ('~"abc"', "('abc')"), # unary invert
155 asm = dis_single(line)
156 self.assertIn(elem, asm, asm)
157 self.assertIn('UNARY_', asm)
159 def test_elim_extra_return(self):
160 # RETURN LOAD_CONST None RETURN --> RETURN
164 self.assertNotIn('LOAD_CONST', asm)
165 self.assertNotIn('(None)', asm)
166 self.assertEqual(asm.split().count('RETURN_VALUE'), 1)
168 def test_elim_jump_to_return(self):
169 # JUMP_FORWARD to RETURN --> RETURN
170 def f(cond, true_value, false_value):
171 return true_value if cond else false_value
173 self.assertNotIn('JUMP_FORWARD', asm)
174 self.assertNotIn('JUMP_ABSOLUTE', asm)
175 self.assertEqual(asm.split().count('RETURN_VALUE'), 2)
177 def test_elim_jump_after_return1(self):
178 # Eliminate dead code: jumps immediately after returns can't be reached
189 self.assertNotIn('JUMP_FORWARD', asm)
190 self.assertNotIn('JUMP_ABSOLUTE', asm)
191 self.assertEqual(asm.split().count('RETURN_VALUE'), 6)
193 def test_elim_jump_after_return2(self):
194 # Eliminate dead code: jumps immediately after returns can't be reached
199 self.assertNotIn('JUMP_FORWARD', asm)
200 # There should be one jump for the while loop.
201 self.assertEqual(asm.split().count('JUMP_ABSOLUTE'), 1)
202 self.assertEqual(asm.split().count('RETURN_VALUE'), 2)
205 def test_main(verbose=None):
207 from test import test_support
208 test_classes = (TestTranforms,)
210 with test_support.check_py3k_warnings(
211 ("backquote not supported", SyntaxWarning)):
212 test_support.run_unittest(*test_classes)
214 # verify reference counting
215 if verbose and hasattr(sys, "gettotalrefcount"):
218 for i in xrange(len(counts)):
219 test_support.run_unittest(*test_classes)
221 counts[i] = sys.gettotalrefcount()
224 if __name__ == "__main__":
225 test_main(verbose=True)