Update decimal test data to the most recent set from Mike Cowlishaw.
[python.git] / Lib / test / test_peepholer.py
blob1f6efb503f56bb427ad9a13e6654cd2d38f4bd13
1 import dis
2 import sys
3 from cStringIO import StringIO
4 import unittest
6 def disassemble(func):
7 f = StringIO()
8 tmp = sys.stdout
9 sys.stdout = f
10 dis.dis(func)
11 sys.stdout = tmp
12 result = f.getvalue()
13 f.close()
14 return result
16 def dis_single(line):
17 return disassemble(compile(line, '', 'single'))
19 class TestTranforms(unittest.TestCase):
21 def test_unot(self):
22 # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE
23 def unot(x):
24 if not x == 2:
25 del x
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):
32 for line, elem in (
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
43 def f(x):
44 None
45 return x
46 asm = disassemble(f)
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)
51 def f():
52 'Adding a docstring made this test fail in Py2.5.0'
53 return None
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
59 def f():
60 while 1:
61 pass
62 return list
63 asm = disassemble(f)
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):
70 for line, elem in (
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):
81 for line, elem in (
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
95 def crater():
96 (~[
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):
110 for line, elem in (
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):
141 for line, elem in (
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
151 for line, elem in (
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
161 def f(x):
162 return x
163 asm = disassemble(f)
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
172 asm = disassemble(f)
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
179 def f(cond1, cond2):
180 if cond1: return 1
181 if cond2: return 2
182 while 1:
183 return 3
184 while 1:
185 if cond1: return 4
186 return 5
187 return 6
188 asm = disassemble(f)
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
195 def f(cond1, cond2):
196 while 1:
197 if cond1: return 4
198 asm = disassemble(f)
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):
206 import sys
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"):
213 import gc
214 counts = [None] * 5
215 for i in xrange(len(counts)):
216 test_support.run_unittest(*test_classes)
217 gc.collect()
218 counts[i] = sys.gettotalrefcount()
219 print counts
221 if __name__ == "__main__":
222 test_main(verbose=True)