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
.assertTrue(elem
not in asm
)
29 self
.assertTrue('POP_JUMP_IF_TRUE' in 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
.assertTrue(elem
in asm
)
41 def test_none_as_constant(self
):
42 # LOAD_GLOBAL None --> LOAD_CONST None
47 for elem
in ('LOAD_GLOBAL',):
48 self
.assertTrue(elem
not in asm
)
49 for elem
in ('LOAD_CONST', '(None)'):
50 self
.assertTrue(elem
in asm
)
52 'Adding a docstring made this test fail in Py2.5.0'
54 self
.assertTrue('LOAD_CONST' in disassemble(f
))
55 self
.assertTrue('LOAD_GLOBAL' not in 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
.assertTrue(elem
not in asm
)
66 for elem
in ('JUMP_ABSOLUTE',):
67 self
.assertTrue(elem
in 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
.assertTrue(elem
in asm
)
77 self
.assertTrue('BUILD_TUPLE' not in asm
)
78 self
.assertTrue('UNPACK_TUPLE' not in 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
.assertTrue(elem
in asm
)
90 self
.assertTrue('BUILD_TUPLE' not in 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
.assertTrue(elem
in asm
, asm
)
129 self
.assertTrue('BINARY_' not in asm
)
131 # Verify that unfoldables are skipped
132 asm
= dis_single('a=2+"b"')
133 self
.assertTrue('(2)' in asm
)
134 self
.assertTrue("('b')" in asm
)
136 # Verify that large sequences do not result from folding
137 asm
= dis_single('a="x"*1000')
138 self
.assertTrue('(1000)' in 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
.assertTrue(elem
in asm
, asm
)
148 self
.assertTrue('UNARY_' not in asm
)
150 # Verify that unfoldables are skipped
152 ('-"abc"', "('abc')"), # unary negative
153 ('~"abc"', "('abc')"), # unary invert
155 asm
= dis_single(line
)
156 self
.assertTrue(elem
in asm
, asm
)
157 self
.assertTrue('UNARY_' in asm
)
159 def test_elim_extra_return(self
):
160 # RETURN LOAD_CONST None RETURN --> RETURN
164 self
.assertTrue('LOAD_CONST' not in asm
)
165 self
.assertTrue('(None)' not in 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
.assertTrue('JUMP_FORWARD' not in asm
)
174 self
.assertTrue('JUMP_ABSOLUTE' not in 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
.assertTrue('JUMP_FORWARD' not in asm
)
190 self
.assertTrue('JUMP_ABSOLUTE' not in 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
.assertTrue('JUMP_FORWARD' not in 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
,)
209 test_support
.run_unittest(*test_classes
)
211 # verify reference counting
212 if verbose
and hasattr(sys
, "gettotalrefcount"):
215 for i
in xrange(len(counts
)):
216 test_support
.run_unittest(*test_classes
)
218 counts
[i
] = sys
.gettotalrefcount()
221 if __name__
== "__main__":
222 test_main(verbose
=True)