| 
									
										
										
										
											2023-05-01 22:29:30 +01:00
										 |  |  | import types | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from test.support.bytecode_helper import AssemblerTestCase | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Tests for the code-object creation stage of the compiler. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class IsolatedAssembleTests(AssemblerTestCase): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def complete_metadata(self, metadata, filename="myfile.py"): | 
					
						
							|  |  |  |         if metadata is None: | 
					
						
							|  |  |  |             metadata = {} | 
					
						
							|  |  |  |         for key in ['name', 'qualname']: | 
					
						
							|  |  |  |             metadata.setdefault(key, key) | 
					
						
							|  |  |  |         for key in ['consts']: | 
					
						
							|  |  |  |             metadata.setdefault(key, []) | 
					
						
							| 
									
										
										
										
											2023-05-09 11:02:14 -06:00
										 |  |  |         for key in ['names', 'varnames', 'cellvars', 'freevars', 'fasthidden']: | 
					
						
							| 
									
										
										
										
											2023-05-01 22:29:30 +01:00
										 |  |  |             metadata.setdefault(key, {}) | 
					
						
							|  |  |  |         for key in ['argcount', 'posonlyargcount', 'kwonlyargcount']: | 
					
						
							|  |  |  |             metadata.setdefault(key, 0) | 
					
						
							|  |  |  |         metadata.setdefault('firstlineno', 1) | 
					
						
							|  |  |  |         metadata.setdefault('filename', filename) | 
					
						
							|  |  |  |         return metadata | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def assemble_test(self, insts, metadata, expected): | 
					
						
							|  |  |  |         metadata = self.complete_metadata(metadata) | 
					
						
							|  |  |  |         insts = self.complete_insts_info(insts) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         co = self.get_code_object(metadata['filename'], insts, metadata) | 
					
						
							|  |  |  |         self.assertIsInstance(co, types.CodeType) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expected_metadata = {} | 
					
						
							|  |  |  |         for key, value in metadata.items(): | 
					
						
							| 
									
										
										
										
											2023-05-09 11:02:14 -06:00
										 |  |  |             if key == "fasthidden": | 
					
						
							|  |  |  |                 # not exposed on code object | 
					
						
							|  |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2023-05-01 22:29:30 +01:00
										 |  |  |             if isinstance(value, list): | 
					
						
							|  |  |  |                 expected_metadata[key] = tuple(value) | 
					
						
							|  |  |  |             elif isinstance(value, dict): | 
					
						
							|  |  |  |                 expected_metadata[key] = tuple(value.keys()) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 expected_metadata[key] = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for key, value in expected_metadata.items(): | 
					
						
							|  |  |  |             self.assertEqual(getattr(co, "co_" + key), value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         f = types.FunctionType(co, {}) | 
					
						
							|  |  |  |         for args, res in expected.items(): | 
					
						
							|  |  |  |             self.assertEqual(f(*args), res) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_simple_expr(self): | 
					
						
							|  |  |  |         metadata = { | 
					
						
							|  |  |  |             'filename' : 'avg.py', | 
					
						
							|  |  |  |             'name'     : 'avg', | 
					
						
							|  |  |  |             'qualname' : 'stats.avg', | 
					
						
							| 
									
										
										
										
											2023-05-09 14:33:40 +01:00
										 |  |  |             'consts'   : {2 : 0}, | 
					
						
							| 
									
										
										
										
											2023-05-01 22:29:30 +01:00
										 |  |  |             'argcount' : 2, | 
					
						
							|  |  |  |             'varnames' : {'x' : 0, 'y' : 1}, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # code for "return (x+y)/2" | 
					
						
							|  |  |  |         insts = [ | 
					
						
							|  |  |  |             ('RESUME', 0), | 
					
						
							|  |  |  |             ('LOAD_FAST', 0, 1),   # 'x' | 
					
						
							|  |  |  |             ('LOAD_FAST', 1, 1),   # 'y' | 
					
						
							|  |  |  |             ('BINARY_OP', 0, 1),   # '+' | 
					
						
							|  |  |  |             ('LOAD_CONST', 0, 1),  # 2 | 
					
						
							|  |  |  |             ('BINARY_OP', 11, 1),   # '/' | 
					
						
							|  |  |  |             ('RETURN_VALUE', 1), | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  |         expected = {(3, 4) : 3.5, (-100, 200) : 50, (10, 18) : 14} | 
					
						
							|  |  |  |         self.assemble_test(insts, metadata, expected) | 
					
						
							| 
									
										
										
										
											2023-06-29 10:34:00 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_expression_with_pseudo_instruction_load_closure(self): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         def mod_two(x): | 
					
						
							|  |  |  |             def inner(): | 
					
						
							|  |  |  |                 return x | 
					
						
							|  |  |  |             return inner() % 2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         inner_code = mod_two.__code__.co_consts[1] | 
					
						
							|  |  |  |         assert isinstance(inner_code, types.CodeType) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         metadata = { | 
					
						
							|  |  |  |             'filename' : 'mod_two.py', | 
					
						
							|  |  |  |             'name'     : 'mod_two', | 
					
						
							|  |  |  |             'qualname' : 'nested.mod_two', | 
					
						
							|  |  |  |             'cellvars' : {'x' : 0}, | 
					
						
							|  |  |  |             'consts': {None: 0, inner_code: 1, 2: 2}, | 
					
						
							|  |  |  |             'argcount' : 1, | 
					
						
							|  |  |  |             'varnames' : {'x' : 0}, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         instructions = [ | 
					
						
							|  |  |  |             ('RESUME', 0,), | 
					
						
							|  |  |  |             ('LOAD_CLOSURE', 0, 1), | 
					
						
							|  |  |  |             ('BUILD_TUPLE', 1, 1), | 
					
						
							|  |  |  |             ('LOAD_CONST', 1, 1), | 
					
						
							|  |  |  |             ('MAKE_FUNCTION', 0, 2), | 
					
						
							|  |  |  |             ('SET_FUNCTION_ATTRIBUTE', 8, 2), | 
					
						
							| 
									
										
										
										
											2023-08-09 11:19:39 -07:00
										 |  |  |             ('PUSH_NULL', 0, 1), | 
					
						
							| 
									
										
										
										
											2023-06-29 10:34:00 -06:00
										 |  |  |             ('CALL', 0, 2),                     # (lambda: x)() | 
					
						
							|  |  |  |             ('LOAD_CONST', 2, 2),               # 2 | 
					
						
							|  |  |  |             ('BINARY_OP', 6, 2),                # % | 
					
						
							|  |  |  |             ('RETURN_VALUE', 0, 2) | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expected = {(0,): 0, (1,): 1, (2,): 0, (120,): 0, (121,): 1} | 
					
						
							|  |  |  |         self.assemble_test(instructions, metadata, expected) |