LEFT | RIGHT |
1 import dis | 1 import dis |
2 import sys | 2 import sys |
3 from io import StringIO | 3 from cStringIO import StringIO |
4 import unittest | 4 import unittest |
5 | 5 |
6 def disassemble(func): | 6 def disassemble(func): |
7 f = StringIO() | 7 f = StringIO() |
8 tmp = sys.stdout | 8 tmp = sys.stdout |
9 sys.stdout = f | 9 sys.stdout = f |
10 dis.dis(func) | 10 dis.dis(func) |
11 sys.stdout = tmp | 11 sys.stdout = tmp |
12 result = f.getvalue() | 12 result = f.getvalue() |
13 f.close() | 13 f.close() |
14 return result | 14 return result |
15 | 15 |
16 def dis_single(line): | 16 def dis_single(line): |
17 return disassemble(compile(line, '', 'single')) | 17 return disassemble(compile(line, '', 'single')) |
18 | 18 |
19 class TestTranforms(unittest.TestCase): | 19 class TestTranforms(unittest.TestCase): |
20 | 20 |
21 def test_unot(self): | 21 def test_unot(self): |
22 # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE' | 22 # UNARY_NOT POP_JUMP_IF_FALSE --> POP_JUMP_IF_TRUE |
23 def unot(x): | 23 def unot(x): |
24 if not x == 2: | 24 if not x == 2: |
25 del x | 25 del x |
26 asm = disassemble(unot) | 26 asm = disassemble(unot) |
27 for elem in ('UNARY_NOT', 'POP_JUMP_IF_FALSE'): | 27 for elem in ('UNARY_NOT', 'POP_JUMP_IF_FALSE'): |
28 self.assert_(elem not in asm) | 28 self.assert_(elem not in asm) |
29 for elem in ('POP_JUMP_IF_TRUE',): | 29 self.assert_('POP_JUMP_IF_TRUE' in asm) |
30 self.assert_(elem in asm) | |
31 | 30 |
32 def test_elim_inversion_of_is_or_in(self): | 31 def test_elim_inversion_of_is_or_in(self): |
33 for line, elem in ( | 32 for line, elem in ( |
34 ('not a is b', '(is not)',), | 33 ('not a is b', '(is not)',), |
35 ('not a in b', '(not in)',), | 34 ('not a in b', '(not in)',), |
36 ('not a is not b', '(is)',), | 35 ('not a is not b', '(is)',), |
37 ('not a not in b', '(in)',), | 36 ('not a not in b', '(in)',), |
38 ): | 37 ): |
39 asm = dis_single(line) | 38 asm = dis_single(line) |
40 self.assert_(elem in asm) | 39 self.assert_(elem in asm) |
41 | 40 |
42 def test_global_as_constant(self): | 41 def test_none_as_constant(self): |
43 # LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False | 42 # LOAD_GLOBAL None --> LOAD_CONST None |
44 def f(x): | 43 def f(x): |
45 None | 44 None |
46 None | |
47 return x | 45 return x |
48 def g(x): | 46 asm = disassemble(f) |
49 True | 47 for elem in ('LOAD_GLOBAL',): |
50 return x | 48 self.assert_(elem not in asm) |
51 def h(x): | 49 for elem in ('LOAD_CONST', '(None)'): |
52 False | 50 self.assert_(elem in asm) |
53 return x | |
54 for func, name in ((f, 'None'), (g, 'True'), (h, 'False')): | |
55 asm = disassemble(func) | |
56 for elem in ('LOAD_GLOBAL',): | |
57 self.assert_(elem not in asm) | |
58 for elem in ('LOAD_CONST', '('+name+')'): | |
59 self.assert_(elem in asm) | |
60 def f(): | 51 def f(): |
61 'Adding a docstring made this test fail in Py2.5.0' | 52 'Adding a docstring made this test fail in Py2.5.0' |
62 return None | 53 return None |
63 self.assert_('LOAD_CONST' in disassemble(f)) | 54 self.assert_('LOAD_CONST' in disassemble(f)) |
64 self.assert_('LOAD_GLOBAL' not in disassemble(f)) | 55 self.assert_('LOAD_GLOBAL' not in disassemble(f)) |
65 | 56 |
66 def test_while_one(self): | 57 def test_while_one(self): |
67 # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx | 58 # Skip over: LOAD_CONST trueconst POP_JUMP_IF_FALSE xx |
68 def f(): | 59 def f(): |
69 while 1: | 60 while 1: |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 asm = dis_single('a=2+"b"') | 132 asm = dis_single('a=2+"b"') |
142 self.assert_('(2)' in asm) | 133 self.assert_('(2)' in asm) |
143 self.assert_("('b')" in asm) | 134 self.assert_("('b')" in asm) |
144 | 135 |
145 # Verify that large sequences do not result from folding | 136 # Verify that large sequences do not result from folding |
146 asm = dis_single('a="x"*1000') | 137 asm = dis_single('a="x"*1000') |
147 self.assert_('(1000)' in asm) | 138 self.assert_('(1000)' in asm) |
148 | 139 |
149 def test_folding_of_unaryops_on_constants(self): | 140 def test_folding_of_unaryops_on_constants(self): |
150 for line, elem in ( | 141 for line, elem in ( |
| 142 ('`1`', "('1')"), # unary convert |
151 ('-0.5', '(-0.5)'), # unary negative | 143 ('-0.5', '(-0.5)'), # unary negative |
152 ('~-2', '(1)'), # unary invert | 144 ('~-2', '(1)'), # unary invert |
153 ): | 145 ): |
154 asm = dis_single(line) | 146 asm = dis_single(line) |
155 self.assert_(elem in asm, asm) | 147 self.assert_(elem in asm, asm) |
156 self.assert_('UNARY_' not in asm) | 148 self.assert_('UNARY_' not in asm) |
157 | 149 |
158 # Verify that unfoldables are skipped | 150 # Verify that unfoldables are skipped |
159 for line, elem in ( | 151 for line, elem in ( |
160 ('-"abc"', "('abc')"), # unary negative | 152 ('-"abc"', "('abc')"), # unary negative |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 # Eliminate dead code: jumps immediately after returns can't be reached | 194 # Eliminate dead code: jumps immediately after returns can't be reached |
203 def f(cond1, cond2): | 195 def f(cond1, cond2): |
204 while 1: | 196 while 1: |
205 if cond1: return 4 | 197 if cond1: return 4 |
206 asm = disassemble(f) | 198 asm = disassemble(f) |
207 self.assert_('JUMP_FORWARD' not in asm) | 199 self.assert_('JUMP_FORWARD' not in asm) |
208 # There should be one jump for the while loop. | 200 # There should be one jump for the while loop. |
209 self.assertEqual(asm.split().count('JUMP_ABSOLUTE'), 1) | 201 self.assertEqual(asm.split().count('JUMP_ABSOLUTE'), 1) |
210 self.assertEqual(asm.split().count('RETURN_VALUE'), 2) | 202 self.assertEqual(asm.split().count('RETURN_VALUE'), 2) |
211 | 203 |
212 def test_make_function_doesnt_bail(self): | |
213 def f(): | |
214 def g()->1+1: | |
215 pass | |
216 return g | |
217 asm = disassemble(f) | |
218 self.assert_('BINARY_ADD' not in asm) | |
219 | |
220 | 204 |
221 def test_main(verbose=None): | 205 def test_main(verbose=None): |
222 import sys | 206 import sys |
223 from test import support | 207 from test import test_support |
224 test_classes = (TestTranforms,) | 208 test_classes = (TestTranforms,) |
225 support.run_unittest(*test_classes) | 209 test_support.run_unittest(*test_classes) |
226 | 210 |
227 # verify reference counting | 211 # verify reference counting |
228 if verbose and hasattr(sys, "gettotalrefcount"): | 212 if verbose and hasattr(sys, "gettotalrefcount"): |
229 import gc | 213 import gc |
230 counts = [None] * 5 | 214 counts = [None] * 5 |
231 for i in range(len(counts)): | 215 for i in xrange(len(counts)): |
232 support.run_unittest(*test_classes) | 216 test_support.run_unittest(*test_classes) |
233 gc.collect() | 217 gc.collect() |
234 counts[i] = sys.gettotalrefcount() | 218 counts[i] = sys.gettotalrefcount() |
235 print(counts) | 219 print counts |
236 | 220 |
237 if __name__ == "__main__": | 221 if __name__ == "__main__": |
238 test_main(verbose=True) | 222 test_main(verbose=True) |
LEFT | RIGHT |