Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | import dis |
2 | import sys | |
3 | from cStringIO import StringIO | |
4 | import unittest | |
5 | ||
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 | |
15 | ||
16 | def dis_single(line): | |
17 | return disassemble(compile(line, '', 'single')) | |
18 | ||
19 | class TestTranforms(unittest.TestCase): | |
20 | ||
21 | def test_unot(self): | |
22 | # UNARY_NOT JUMP_IF_FALSE POP_TOP --> JUMP_IF_TRUE POP_TOP' | |
23 | def unot(x): | |
24 | if not x == 2: | |
25 | del x | |
26 | asm = disassemble(unot) | |
27 | for elem in ('UNARY_NOT', 'JUMP_IF_FALSE'): | |
28 | self.assert_(elem not in asm) | |
29 | for elem in ('JUMP_IF_TRUE', 'POP_TOP'): | |
30 | self.assert_(elem in asm) | |
31 | ||
32 | def test_elim_inversion_of_is_or_in(self): | |
33 | for line, elem in ( | |
34 | ('not a is b', '(is not)',), | |
35 | ('not a in b', '(not in)',), | |
36 | ('not a is not b', '(is)',), | |
37 | ('not a not in b', '(in)',), | |
38 | ): | |
39 | asm = dis_single(line) | |
40 | self.assert_(elem in asm) | |
41 | ||
42 | def test_none_as_constant(self): | |
43 | # LOAD_GLOBAL None --> LOAD_CONST None | |
44 | def f(x): | |
45 | None | |
46 | return x | |
47 | asm = disassemble(f) | |
48 | for elem in ('LOAD_GLOBAL',): | |
49 | self.assert_(elem not in asm) | |
50 | for elem in ('LOAD_CONST', '(None)'): | |
51 | self.assert_(elem in asm) | |
52 | ||
53 | def test_while_one(self): | |
54 | # Skip over: LOAD_CONST trueconst JUMP_IF_FALSE xx POP_TOP | |
55 | def f(): | |
56 | while 1: | |
57 | pass | |
58 | return list | |
59 | asm = disassemble(f) | |
60 | for elem in ('LOAD_CONST', 'JUMP_IF_FALSE'): | |
61 | self.assert_(elem not in asm) | |
62 | for elem in ('JUMP_ABSOLUTE',): | |
63 | self.assert_(elem in asm) | |
64 | ||
65 | def test_pack_unpack(self): | |
66 | for line, elem in ( | |
67 | ('a, = a,', 'LOAD_CONST',), | |
68 | ('a, b = a, b', 'ROT_TWO',), | |
69 | ('a, b, c = a, b, c', 'ROT_THREE',), | |
70 | ): | |
71 | asm = dis_single(line) | |
72 | self.assert_(elem in asm) | |
73 | self.assert_('BUILD_TUPLE' not in asm) | |
74 | self.assert_('UNPACK_TUPLE' not in asm) | |
75 | ||
76 | def test_folding_of_tuples_of_constants(self): | |
77 | for line, elem in ( | |
78 | ('a = 1,2,3', '((1, 2, 3))'), | |
79 | ('("a","b","c")', "(('a', 'b', 'c'))"), | |
80 | ('a,b,c = 1,2,3', '((1, 2, 3))'), | |
81 | ('(None, 1, None)', '((None, 1, None))'), | |
82 | ('((1, 2), 3, 4)', '(((1, 2), 3, 4))'), | |
83 | ): | |
84 | asm = dis_single(line) | |
85 | self.assert_(elem in asm) | |
86 | self.assert_('BUILD_TUPLE' not in asm) | |
87 | ||
88 | # Bug 1053819: Tuple of constants misidentified when presented with: | |
89 | # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . . | |
90 | # The following would segfault upon compilation | |
91 | def crater(): | |
92 | (~[ | |
93 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, | |
94 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, | |
95 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, | |
96 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, | |
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 | ],) | |
104 | ||
105 | def test_elim_extra_return(self): | |
106 | # RETURN LOAD_CONST None RETURN --> RETURN | |
107 | def f(x): | |
108 | return x | |
109 | asm = disassemble(f) | |
110 | self.assert_('LOAD_CONST' not in asm) | |
111 | self.assert_('(None)' not in asm) | |
112 | self.assertEqual(asm.split().count('RETURN_VALUE'), 1) | |
113 | ||
114 | ||
115 | ||
116 | def test_main(verbose=None): | |
117 | import sys | |
118 | from test import test_support | |
119 | test_classes = (TestTranforms,) | |
120 | test_support.run_unittest(*test_classes) | |
121 | ||
122 | # verify reference counting | |
123 | if verbose and hasattr(sys, "gettotalrefcount"): | |
124 | import gc | |
125 | counts = [None] * 5 | |
126 | for i in xrange(len(counts)): | |
127 | test_support.run_unittest(*test_classes) | |
128 | gc.collect() | |
129 | counts[i] = sys.gettotalrefcount() | |
130 | print counts | |
131 | ||
132 | if __name__ == "__main__": | |
133 | test_main(verbose=True) |