mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 18:28:49 +00:00 
			
		
		
		
	 e2f710792b
			
		
	
	
		e2f710792b
		
			
		
	
	
	
	
		
			
			* Detect source file encoding. * Use the "replace" error handler even for UTF-8 (default) encoding. * Remove the BOM. * Fix detection of too long lines if they contain NUL. * Return the head rather than the tail for truncated long lines.
		
			
				
	
	
		
			159 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			159 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
 | |
| import textwrap
 | |
| from test.support.bytecode_helper import CodegenTestCase
 | |
| 
 | |
| # Tests for the code-generation stage of the compiler.
 | |
| # Examine the un-optimized code generated from the AST.
 | |
| 
 | |
| class IsolatedCodeGenTests(CodegenTestCase):
 | |
| 
 | |
|     def assertInstructionsMatch_recursive(self, insts, expected_insts):
 | |
|         expected_nested = [i for i in expected_insts if isinstance(i, list)]
 | |
|         expected_insts = [i for i in expected_insts if not isinstance(i, list)]
 | |
|         self.assertInstructionsMatch(insts, expected_insts)
 | |
|         self.assertEqual(len(insts.get_nested()), len(expected_nested))
 | |
|         for n_insts, n_expected in zip(insts.get_nested(), expected_nested):
 | |
|             self.assertInstructionsMatch_recursive(n_insts, n_expected)
 | |
| 
 | |
|     def codegen_test(self, snippet, expected_insts):
 | |
|         import ast
 | |
|         a = ast.parse(snippet, "my_file.py", "exec")
 | |
|         insts = self.generate_code(a)
 | |
|         self.assertInstructionsMatch_recursive(insts, expected_insts)
 | |
| 
 | |
|     def test_if_expression(self):
 | |
|         snippet = "42 if True else 24"
 | |
|         false_lbl = self.Label()
 | |
|         expected = [
 | |
|             ('RESUME', 0, 0),
 | |
|             ('LOAD_CONST', 0, 1),
 | |
|             ('TO_BOOL', 0, 1),
 | |
|             ('POP_JUMP_IF_FALSE', false_lbl := self.Label(), 1),
 | |
|             ('LOAD_CONST', 1, 1),
 | |
|             ('JUMP_NO_INTERRUPT', exit_lbl := self.Label()),
 | |
|             false_lbl,
 | |
|             ('LOAD_CONST', 2, 1),
 | |
|             exit_lbl,
 | |
|             ('POP_TOP', None),
 | |
|             ('LOAD_CONST', 3),
 | |
|             ('RETURN_VALUE', None),
 | |
|         ]
 | |
|         self.codegen_test(snippet, expected)
 | |
| 
 | |
|     def test_for_loop(self):
 | |
|         snippet = "for x in l:\n\tprint(x)"
 | |
|         false_lbl = self.Label()
 | |
|         expected = [
 | |
|             ('RESUME', 0, 0),
 | |
|             ('LOAD_NAME', 0, 1),
 | |
|             ('GET_ITER', None, 1),
 | |
|             loop_lbl := self.Label(),
 | |
|             ('FOR_ITER', exit_lbl := self.Label(), 1),
 | |
|             ('NOP', None, 1, 1),
 | |
|             ('STORE_NAME', 1, 1),
 | |
|             ('LOAD_NAME', 2, 2),
 | |
|             ('PUSH_NULL', None, 2),
 | |
|             ('LOAD_NAME', 1, 2),
 | |
|             ('CALL', 1, 2),
 | |
|             ('POP_TOP', None),
 | |
|             ('JUMP', loop_lbl),
 | |
|             exit_lbl,
 | |
|             ('END_FOR', None),
 | |
|             ('POP_TOP', None),
 | |
|             ('LOAD_CONST', 0),
 | |
|             ('RETURN_VALUE', None),
 | |
|         ]
 | |
|         self.codegen_test(snippet, expected)
 | |
| 
 | |
|     def test_function(self):
 | |
|         snippet = textwrap.dedent("""
 | |
|             def f(x):
 | |
|                 return x + 42
 | |
|         """)
 | |
|         expected = [
 | |
|             # Function definition
 | |
|             ('RESUME', 0),
 | |
|             ('LOAD_CONST', 0),
 | |
|             ('MAKE_FUNCTION', None),
 | |
|             ('STORE_NAME', 0),
 | |
|             ('LOAD_CONST', 1),
 | |
|             ('RETURN_VALUE', None),
 | |
|             [
 | |
|                 # Function body
 | |
|                 ('RESUME', 0),
 | |
|                 ('LOAD_FAST', 0),
 | |
|                 ('LOAD_CONST', 1),
 | |
|                 ('BINARY_OP', 0),
 | |
|                 ('RETURN_VALUE', None),
 | |
|                 ('LOAD_CONST', 0),
 | |
|                 ('RETURN_VALUE', None),
 | |
|             ]
 | |
|         ]
 | |
|         self.codegen_test(snippet, expected)
 | |
| 
 | |
|     def test_nested_functions(self):
 | |
|         snippet = textwrap.dedent("""
 | |
|             def f():
 | |
|                 def h():
 | |
|                     return 12
 | |
|                 def g():
 | |
|                     x = 1
 | |
|                     y = 2
 | |
|                     z = 3
 | |
|                     u = 4
 | |
|                     return 42
 | |
|         """)
 | |
|         expected = [
 | |
|             # Function definition
 | |
|             ('RESUME', 0),
 | |
|             ('LOAD_CONST', 0),
 | |
|             ('MAKE_FUNCTION', None),
 | |
|             ('STORE_NAME', 0),
 | |
|             ('LOAD_CONST', 1),
 | |
|             ('RETURN_VALUE', None),
 | |
|             [
 | |
|                 # Function body
 | |
|                 ('RESUME', 0),
 | |
|                 ('LOAD_CONST', 1),
 | |
|                 ('MAKE_FUNCTION', None),
 | |
|                 ('STORE_FAST', 0),
 | |
|                 ('LOAD_CONST', 2),
 | |
|                 ('MAKE_FUNCTION', None),
 | |
|                 ('STORE_FAST', 1),
 | |
|                 ('LOAD_CONST', 0),
 | |
|                 ('RETURN_VALUE', None),
 | |
|                 [
 | |
|                     ('RESUME', 0),
 | |
|                     ('NOP', None),
 | |
|                     ('LOAD_CONST', 1),
 | |
|                     ('RETURN_VALUE', None),
 | |
|                     ('LOAD_CONST', 0),
 | |
|                     ('RETURN_VALUE', None),
 | |
|                 ],
 | |
|                 [
 | |
|                     ('RESUME', 0),
 | |
|                     ('LOAD_CONST', 1),
 | |
|                     ('STORE_FAST', 0),
 | |
|                     ('LOAD_CONST', 2),
 | |
|                     ('STORE_FAST', 1),
 | |
|                     ('LOAD_CONST', 3),
 | |
|                     ('STORE_FAST', 2),
 | |
|                     ('LOAD_CONST', 4),
 | |
|                     ('STORE_FAST', 3),
 | |
|                     ('NOP', None),
 | |
|                     ('LOAD_CONST', 5),
 | |
|                     ('RETURN_VALUE', None),
 | |
|                     ('LOAD_CONST', 0),
 | |
|                     ('RETURN_VALUE', None),
 | |
|                 ],
 | |
|             ],
 | |
|         ]
 | |
|         self.codegen_test(snippet, expected)
 | |
| 
 | |
|     def test_syntax_error__return_not_in_function(self):
 | |
|         snippet = "return 42"
 | |
|         with self.assertRaisesRegex(SyntaxError, "'return' outside function") as cm:
 | |
|             self.codegen_test(snippet, None)
 | |
|         self.assertIsNone(cm.exception.text)
 | |
|         self.assertEqual(cm.exception.offset, 1)
 | |
|         self.assertEqual(cm.exception.end_offset, 10)
 |