blob: bedf7632492cf5113e41dd2ac4e628aa53488b3a [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)
52
53 def test_while_one(self):
54 # Skip over: LOAD_CONST trueconst JUMP_IF_FALSE xx POP_TOP
55 def f():
Tim Peters66cb0182004-08-26 05:23:19 +000056 while 1:
57 pass
58 return list
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000059 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 (
Raymond Hettinger2c31a052004-09-22 18:44:21 +000067 ('a, = a,', 'LOAD_CONST',),
68 ('a, b = a, b', 'ROT_TWO',),
69 ('a, b, c = a, b, c', 'ROT_THREE',),
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +000070 ):
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
Raymond Hettinger2c31a052004-09-22 18:44:21 +000076 def test_folding_of_tuples_of_constants(self):
77 for line, elem in (
Raymond Hettinger5dec0962004-11-02 04:20:10 +000078 ('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))'),
Raymond Hettinger2c31a052004-09-22 18:44:21 +000083 ):
84 asm = dis_single(line)
85 self.assert_(elem in asm)
86 self.assert_('BUILD_TUPLE' not in asm)
87
Raymond Hettinger23109ef2004-10-26 08:59:14 +000088 # 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
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000105 def test_folding_of_binops_on_constants(self):
106 for line, elem in (
107 ('a = 2+3+4', '(9)'), # chained fold
108 ('"@"*4', "('@@@@')"), # check string ops
109 ('a="abc" + "def"', "('abcdef')"), # check string ops
110 ('a = 3**4', '(81)'), # binary power
111 ('a = 3*4', '(12)'), # binary multiply
Raymond Hettingerc34f8672005-01-02 06:17:33 +0000112 ('a = 13//4', '(3)'), # binary floor divide
113 ('a = 14%4', '(2)'), # binary modulo
114 ('a = 2+3', '(5)'), # binary add
115 ('a = 13-4', '(9)'), # binary subtract
116 ('a = (12,13)[1]', '(13)'), # binary subscr
117 ('a = 13 << 2', '(52)'), # binary lshift
118 ('a = 13 >> 2', '(3)'), # binary rshift
119 ('a = 13 & 7', '(5)'), # binary and
120 ('a = 13 ^ 7', '(10)'), # binary xor
121 ('a = 13 | 7', '(15)'), # binary or
122 ):
123 asm = dis_single(line)
124 self.assert_(elem in asm, asm)
125 self.assert_('BINARY_' not in asm)
126
127 # Verify that unfoldables are skipped
128 asm = dis_single('a=2+"b"')
129 self.assert_('(2)' in asm)
130 self.assert_("('b')" in asm)
131
Raymond Hettinger9feb2672005-01-26 12:50:05 +0000132 # Verify that large sequences do not result from folding
133 asm = dis_single('a="x"*1000')
134 self.assert_('(1000)' in asm)
135
Raymond Hettingera1645742005-02-06 22:05:42 +0000136 def test_set_conversion(self):
137 for line in (
138 'x in (1,2,3)',
139 'x not in (1,2,3)',
140 'not x in (1,2,3)',
141 'not x not in (1,2,3)',
142 ):
143 asm = dis_single(line)
144 self.assert_('frozenset' in asm)
145
Raymond Hettingerfd2d1f72004-08-23 23:37:48 +0000146 def test_elim_extra_return(self):
147 # RETURN LOAD_CONST None RETURN --> RETURN
148 def f(x):
149 return x
150 asm = disassemble(f)
151 self.assert_('LOAD_CONST' not in asm)
152 self.assert_('(None)' not in asm)
153 self.assertEqual(asm.split().count('RETURN_VALUE'), 1)
154
155
156
157def test_main(verbose=None):
158 import sys
159 from test import test_support
160 test_classes = (TestTranforms,)
161 test_support.run_unittest(*test_classes)
162
163 # verify reference counting
164 if verbose and hasattr(sys, "gettotalrefcount"):
165 import gc
166 counts = [None] * 5
167 for i in xrange(len(counts)):
168 test_support.run_unittest(*test_classes)
169 gc.collect()
170 counts[i] = sys.gettotalrefcount()
171 print counts
172
173if __name__ == "__main__":
174 test_main(verbose=True)