33import unittest
44import dis
55import io
6- from _testinternalcapi import optimize_cfg
6+ from _testinternalcapi import compiler_codegen , optimize_cfg
77
88_UNSPECIFIED = object ()
99
@@ -44,8 +44,7 @@ def assertNotInBytecode(self, x, opname, argval=_UNSPECIFIED):
4444 msg = msg % (opname , argval , disassembly )
4545 self .fail (msg )
4646
47-
48- class CfgOptimizationTestCase (unittest .TestCase ):
47+ class CompilationStepTestCase (unittest .TestCase ):
4948
5049 HAS_ARG = set (dis .hasarg )
5150 HAS_TARGET = set (dis .hasjrel + dis .hasjabs + dis .hasexc )
@@ -58,24 +57,35 @@ def Label(self):
5857 self .last_label += 1
5958 return self .last_label
6059
61- def complete_insts_info (self , insts ):
62- # fill in omitted fields in location, and oparg 0 for ops with no arg.
63- instructions = []
64- for item in insts :
65- if isinstance (item , int ):
66- instructions .append (item )
67- else :
68- assert isinstance (item , tuple )
69- inst = list (reversed (item ))
70- opcode = dis .opmap [inst .pop ()]
71- oparg = inst .pop () if opcode in self .HAS_ARG_OR_TARGET else 0
72- loc = inst + [- 1 ] * (4 - len (inst ))
73- instructions .append ((opcode , oparg , * loc ))
74- return instructions
60+ def compareInstructions (self , actual_ , expected_ ):
61+ # get two lists where each entry is a label or
62+ # an instruction tuple. Compare them, while mapping
63+ # each actual label to a corresponding expected label
64+ # based on their locations.
65+
66+ self .assertIsInstance (actual_ , list )
67+ self .assertIsInstance (expected_ , list )
68+
69+ actual = self .normalize_insts (actual_ )
70+ expected = self .normalize_insts (expected_ )
71+ self .assertEqual (len (actual ), len (expected ))
72+
73+ # compare instructions
74+ for act , exp in zip (actual , expected ):
75+ if isinstance (act , int ):
76+ self .assertEqual (exp , act )
77+ continue
78+ self .assertIsInstance (exp , tuple )
79+ self .assertIsInstance (act , tuple )
80+ # crop comparison to the provided expected values
81+ if len (act ) > len (exp ):
82+ act = act [:len (exp )]
83+ self .assertEqual (exp , act )
7584
7685 def normalize_insts (self , insts ):
7786 """ Map labels to instruction index.
7887 Remove labels which are not used as jump targets.
88+ Map opcodes to opnames.
7989 """
8090 labels_map = {}
8191 targets = set ()
@@ -107,31 +117,34 @@ def normalize_insts(self, insts):
107117 res .append ((opcode , arg , * loc ))
108118 return res
109119
120+
121+ class CodegenTestCase (CompilationStepTestCase ):
122+
123+ def generate_code (self , ast ):
124+ insts = compiler_codegen (ast , "my_file.py" , 0 )
125+ return insts
126+
127+
128+ class CfgOptimizationTestCase (CompilationStepTestCase ):
129+
130+ def complete_insts_info (self , insts ):
131+ # fill in omitted fields in location, and oparg 0 for ops with no arg.
132+ instructions = []
133+ for item in insts :
134+ if isinstance (item , int ):
135+ instructions .append (item )
136+ else :
137+ assert isinstance (item , tuple )
138+ inst = list (reversed (item ))
139+ opcode = dis .opmap [inst .pop ()]
140+ oparg = inst .pop () if opcode in self .HAS_ARG_OR_TARGET else 0
141+ loc = inst + [- 1 ] * (4 - len (inst ))
142+ instructions .append ((opcode , oparg , * loc ))
143+ return instructions
144+
110145 def get_optimized (self , insts , consts ):
111146 insts = self .complete_insts_info (insts )
112147 insts = optimize_cfg (insts , consts )
113148 return insts , consts
114149
115- def compareInstructions (self , actual_ , expected_ ):
116- # get two lists where each entry is a label or
117- # an instruction tuple. Compare them, while mapping
118- # each actual label to a corresponding expected label
119- # based on their locations.
120-
121- self .assertIsInstance (actual_ , list )
122- self .assertIsInstance (expected_ , list )
123150
124- actual = self .normalize_insts (actual_ )
125- expected = self .normalize_insts (expected_ )
126- self .assertEqual (len (actual ), len (expected ))
127-
128- # compare instructions
129- for act , exp in zip (actual , expected ):
130- if isinstance (act , int ):
131- self .assertEqual (exp , act )
132- continue
133- self .assertIsInstance (exp , tuple )
134- self .assertIsInstance (act , tuple )
135- # pad exp with -1's (if location info is incomplete)
136- exp += (- 1 ,) * (len (act ) - len (exp ))
137- self .assertEqual (exp , act )
0 commit comments