blob: 16d0268b1cf310f13676ddd52cc01b87a3fe9b09 [file] [log] [blame]
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +00001import dis
2import sys
3from cStringIO import StringIO
4import unittest
5
6def 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
16def dis_single(line):
17 return disassemble(compile(line, '', 'single'))
18
19class 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):
Tim Peters66cb0182004-08-26 05:23:19 +000045 None
46 return x
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000047 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)
Raymond Hettingerd882e362007-03-02 19:19:05 +000052 def f():
53 'Adding a docstring made this test fail in Py2.5.0'
54 return None
55 self.assert_('LOAD_CONST' in disassemble(f))
56 self.assert_('LOAD_GLOBAL' not in disassemble(f))
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000057
58 def test_while_one(self):
59 # Skip over: LOAD_CONST trueconst JUMP_IF_FALSE xx POP_TOP
60 def f():
Tim Peters66cb0182004-08-26 05:23:19 +000061 while 1:
62 pass
63 return list
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000064 asm = disassemble(f)
65 for elem in ('LOAD_CONST', 'JUMP_IF_FALSE'):
66 self.assert_(elem not in asm)
67 for elem in ('JUMP_ABSOLUTE',):
68 self.assert_(elem in asm)
69
70 def test_pack_unpack(self):
71 for line, elem in (
Raymond Hettinger2c31a052004-09-22 18:44:21 +000072 ('a, = a,', 'LOAD_CONST',),
73 ('a, b = a, b', 'ROT_TWO',),
74 ('a, b, c = a, b, c', 'ROT_THREE',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000075 ):
76 asm = dis_single(line)
77 self.assert_(elem in asm)
78 self.assert_('BUILD_TUPLE' not in asm)
79 self.assert_('UNPACK_TUPLE' not in asm)
80
Raymond Hettinger2c31a052004-09-22 18:44:21 +000081 def test_folding_of_tuples_of_constants(self):
82 for line, elem in (
Raymond Hettinger5dec0962004-11-02 04:20:10 +000083 ('a = 1,2,3', '((1, 2, 3))'),
84 ('("a","b","c")', "(('a', 'b', 'c'))"),
85 ('a,b,c = 1,2,3', '((1, 2, 3))'),
86 ('(None, 1, None)', '((None, 1, None))'),
87 ('((1, 2), 3, 4)', '(((1, 2), 3, 4))'),
Raymond Hettinger2c31a052004-09-22 18:44:21 +000088 ):
89 asm = dis_single(line)
90 self.assert_(elem in asm)
91 self.assert_('BUILD_TUPLE' not in asm)
92
Raymond Hettinger23109ef2004-10-26 08:59:14 +000093 # Bug 1053819: Tuple of constants misidentified when presented with:
94 # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . .
95 # The following would segfault upon compilation
96 def crater():
97 (~[
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,
107 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
108 ],)
109
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000110 def test_folding_of_binops_on_constants(self):
111 for line, elem in (
112 ('a = 2+3+4', '(9)'), # chained fold
113 ('"@"*4', "('@@@@')"), # check string ops
114 ('a="abc" + "def"', "('abcdef')"), # check string ops
115 ('a = 3**4', '(81)'), # binary power
116 ('a = 3*4', '(12)'), # binary multiply
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000117 ('a = 13//4', '(3)'), # binary floor divide
118 ('a = 14%4', '(2)'), # binary modulo
119 ('a = 2+3', '(5)'), # binary add
120 ('a = 13-4', '(9)'), # binary subtract
121 ('a = (12,13)[1]', '(13)'), # binary subscr
122 ('a = 13 << 2', '(52)'), # binary lshift
123 ('a = 13 >> 2', '(3)'), # binary rshift
124 ('a = 13 & 7', '(5)'), # binary and
125 ('a = 13 ^ 7', '(10)'), # binary xor
126 ('a = 13 | 7', '(15)'), # binary or
127 ):
128 asm = dis_single(line)
129 self.assert_(elem in asm, asm)
130 self.assert_('BINARY_' not in asm)
131
132 # Verify that unfoldables are skipped
133 asm = dis_single('a=2+"b"')
134 self.assert_('(2)' in asm)
135 self.assert_("('b')" in asm)
136
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000137 # Verify that large sequences do not result from folding
138 asm = dis_single('a="x"*1000')
139 self.assert_('(1000)' in asm)
140
Raymond Hettingerafd842f2005-02-20 12:46:54 +0000141 def test_folding_of_unaryops_on_constants(self):
142 for line, elem in (
143 ('`1`', "('1')"), # unary convert
144 ('-0.5', '(-0.5)'), # unary negative
145 ('~-2', '(1)'), # unary invert
146 ):
147 asm = dis_single(line)
148 self.assert_(elem in asm, asm)
149 self.assert_('UNARY_' not in asm)
150
151 # Verify that unfoldables are skipped
152 for line, elem in (
153 ('-"abc"', "('abc')"), # unary negative
154 ('~"abc"', "('abc')"), # unary invert
155 ):
156 asm = dis_single(line)
157 self.assert_(elem in asm, asm)
158 self.assert_('UNARY_' in asm)
159
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000160 def test_elim_extra_return(self):
161 # RETURN LOAD_CONST None RETURN --> RETURN
162 def f(x):
163 return x
164 asm = disassemble(f)
165 self.assert_('LOAD_CONST' not in asm)
166 self.assert_('(None)' not in asm)
167 self.assertEqual(asm.split().count('RETURN_VALUE'), 1)
168
169
170
171def test_main(verbose=None):
172 import sys
173 from test import test_support
174 test_classes = (TestTranforms,)
175 test_support.run_unittest(*test_classes)
176
177 # verify reference counting
178 if verbose and hasattr(sys, "gettotalrefcount"):
179 import gc
180 counts = [None] * 5
181 for i in xrange(len(counts)):
182 test_support.run_unittest(*test_classes)
183 gc.collect()
184 counts[i] = sys.gettotalrefcount()
185 print counts
186
187if __name__ == "__main__":
188 test_main(verbose=True)