blob: 34bd99f2a402cca3c52a63b8796240f6a495d216 [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 Hettingerfd2d1f72004-08-23 23:37:48 +0000136 def test_elim_extra_return(self):
137 # RETURN LOAD_CONST None RETURN --> RETURN
138 def f(x):
139 return x
140 asm = disassemble(f)
141 self.assert_('LOAD_CONST' not in asm)
142 self.assert_('(None)' not in asm)
143 self.assertEqual(asm.split().count('RETURN_VALUE'), 1)
144
145
146
147def test_main(verbose=None):
148 import sys
149 from test import test_support
150 test_classes = (TestTranforms,)
151 test_support.run_unittest(*test_classes)
152
153 # verify reference counting
154 if verbose and hasattr(sys, "gettotalrefcount"):
155 import gc
156 counts = [None] * 5
157 for i in xrange(len(counts)):
158 test_support.run_unittest(*test_classes)
159 gc.collect()
160 counts[i] = sys.gettotalrefcount()
161 print counts
162
163if __name__ == "__main__":
164 test_main(verbose=True)