| 
									
										
										
										
											2023-05-26 15:32:03 +02:00
										 |  |  | import contextlib | 
					
						
							|  |  |  | import subprocess | 
					
						
							| 
									
										
										
										
											2020-11-04 23:01:08 +00:00
										 |  |  | import sysconfig | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  | import textwrap | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2021-06-13 07:07:24 +09:00
										 |  |  | import os | 
					
						
							|  |  |  | import shutil | 
					
						
							|  |  |  | import tempfile | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  | from pathlib import Path | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | from test import test_tools | 
					
						
							| 
									
										
										
										
											2020-04-23 14:46:22 +01:00
										 |  |  | from test import support | 
					
						
							| 
									
										
										
										
											2023-05-26 15:32:03 +02:00
										 |  |  | from test.support import os_helper, import_helper | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  | from test.support.script_helper import assert_python_ok | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 17:37:30 +01:00
										 |  |  | _py_cflags_nodist = sysconfig.get_config_var("PY_CFLAGS_NODIST") | 
					
						
							|  |  |  | _pgo_flag = sysconfig.get_config_var("PGO_PROF_USE_FLAG") | 
					
						
							| 
									
										
										
										
											2020-11-04 23:01:08 +00:00
										 |  |  | if _pgo_flag and _py_cflags_nodist and _pgo_flag in _py_cflags_nodist: | 
					
						
							|  |  |  |     raise unittest.SkipTest("peg_generator test disabled under PGO build") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  | test_tools.skip_if_missing("peg_generator") | 
					
						
							|  |  |  | with test_tools.imports_under_tool("peg_generator"): | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |     from pegen.grammar_parser import GeneratedParser as GrammarParser | 
					
						
							|  |  |  |     from pegen.testutil import ( | 
					
						
							|  |  |  |         parse_string, | 
					
						
							|  |  |  |         generate_parser_c_extension, | 
					
						
							|  |  |  |         generate_c_parser_source, | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  | TEST_TEMPLATE = """
 | 
					
						
							|  |  |  | tmp_dir = {extension_path!r} | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  | import ast | 
					
						
							|  |  |  | import traceback | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import unittest | 
					
						
							| 
									
										
										
										
											2020-05-02 05:23:06 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | from test import test_tools | 
					
						
							|  |  |  | with test_tools.imports_under_tool("peg_generator"): | 
					
						
							|  |  |  |     from pegen.ast_dump import ast_dump | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | sys.path.insert(0, tmp_dir) | 
					
						
							|  |  |  | import parse | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Tests(unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def check_input_strings_for_grammar( | 
					
						
							|  |  |  |         self, | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         valid_cases = (), | 
					
						
							|  |  |  |         invalid_cases = (), | 
					
						
							|  |  |  |     ): | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         if valid_cases: | 
					
						
							|  |  |  |             for case in valid_cases: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |                 parse.parse_string(case, mode=0) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if invalid_cases: | 
					
						
							|  |  |  |             for case in invalid_cases: | 
					
						
							|  |  |  |                 with self.assertRaises(SyntaxError): | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |                     parse.parse_string(case, mode=0) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |     def verify_ast_generation(self, stmt): | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         expected_ast = ast.parse(stmt) | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         actual_ast = parse.parse_string(stmt, mode=1) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         self.assertEqual(ast_dump(expected_ast), ast_dump(actual_ast)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |     def test_parse(self): | 
					
						
							|  |  |  |         {test_source} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unittest.main() | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-22 12:04:36 +02:00
										 |  |  | @support.requires_subprocess() | 
					
						
							| 
									
										
										
										
											2021-06-13 07:07:24 +09:00
										 |  |  | class TestCParser(unittest.TestCase): | 
					
						
							| 
									
										
										
										
											2022-04-06 15:55:58 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-23 19:04:17 +02:00
										 |  |  |     _has_run = False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-06 15:55:58 -06:00
										 |  |  |     @classmethod | 
					
						
							|  |  |  |     def setUpClass(cls): | 
					
						
							| 
									
										
										
										
											2023-06-23 19:04:17 +02:00
										 |  |  |         if cls._has_run: | 
					
						
							|  |  |  |             # Since gh-104798 (Use setuptools in peg-generator and reenable | 
					
						
							|  |  |  |             # tests), this test case has been producing ref leaks. Initial | 
					
						
							|  |  |  |             # debugging points to bug(s) in setuptools and/or importlib. | 
					
						
							|  |  |  |             # See gh-105063 for more info. | 
					
						
							|  |  |  |             raise unittest.SkipTest("gh-105063: can not rerun because of ref. leaks") | 
					
						
							|  |  |  |         cls._has_run = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-25 18:34:14 +03:00
										 |  |  |         # When running under regtest, a separate tempdir is used | 
					
						
							| 
									
										
										
										
											2022-04-06 15:55:58 -06:00
										 |  |  |         # as the current directory and watched for left-overs. | 
					
						
							|  |  |  |         # Reusing that as the base for temporary directories | 
					
						
							|  |  |  |         # ensures everything is cleaned up properly and | 
					
						
							|  |  |  |         # cleans up afterwards if not (with warnings). | 
					
						
							|  |  |  |         cls.tmp_base = os.getcwd() | 
					
						
							|  |  |  |         if os.path.samefile(cls.tmp_base, os_helper.SAVEDCWD): | 
					
						
							|  |  |  |             cls.tmp_base = None | 
					
						
							|  |  |  |         # Create a directory for the reuseable static library part of | 
					
						
							|  |  |  |         # the pegen extension build process.  This greatly reduces the | 
					
						
							|  |  |  |         # runtime overhead of spawning compiler processes. | 
					
						
							|  |  |  |         cls.library_dir = tempfile.mkdtemp(dir=cls.tmp_base) | 
					
						
							|  |  |  |         cls.addClassCleanup(shutil.rmtree, cls.library_dir) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-26 15:32:03 +02:00
										 |  |  |         with contextlib.ExitStack() as stack: | 
					
						
							|  |  |  |             python_exe = stack.enter_context(support.setup_venv_with_pip_setuptools_wheel("venv")) | 
					
						
							|  |  |  |             sitepackages = subprocess.check_output( | 
					
						
							|  |  |  |                 [python_exe, "-c", "import sysconfig; print(sysconfig.get_path('platlib'))"], | 
					
						
							|  |  |  |                 text=True, | 
					
						
							|  |  |  |             ).strip() | 
					
						
							|  |  |  |             stack.enter_context(import_helper.DirsOnSysPath(sitepackages)) | 
					
						
							|  |  |  |             cls.addClassCleanup(stack.pop_all().close) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @support.requires_venv_with_pip() | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |     def setUp(self): | 
					
						
							| 
									
										
										
										
											2021-04-23 14:02:41 +02:00
										 |  |  |         self._backup_config_vars = dict(sysconfig._CONFIG_VARS) | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         cmd = support.missing_compiler_executable() | 
					
						
							|  |  |  |         if cmd is not None: | 
					
						
							|  |  |  |             self.skipTest("The %r command is not found" % cmd) | 
					
						
							| 
									
										
										
										
											2021-06-13 07:07:24 +09:00
										 |  |  |         self.old_cwd = os.getcwd() | 
					
						
							| 
									
										
										
										
											2022-04-06 15:55:58 -06:00
										 |  |  |         self.tmp_path = tempfile.mkdtemp(dir=self.tmp_base) | 
					
						
							| 
									
										
										
										
											2022-05-08 17:49:09 +03:00
										 |  |  |         self.enterContext(os_helper.change_cwd(self.tmp_path)) | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def tearDown(self): | 
					
						
							| 
									
										
										
										
											2021-06-13 07:07:24 +09:00
										 |  |  |         os.chdir(self.old_cwd) | 
					
						
							|  |  |  |         shutil.rmtree(self.tmp_path) | 
					
						
							| 
									
										
										
										
											2021-04-23 14:02:41 +02:00
										 |  |  |         sysconfig._CONFIG_VARS.clear() | 
					
						
							|  |  |  |         sysconfig._CONFIG_VARS.update(self._backup_config_vars) | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def build_extension(self, grammar_source): | 
					
						
							|  |  |  |         grammar = parse_string(grammar_source, GrammarParser) | 
					
						
							| 
									
										
										
										
											2022-04-06 15:55:58 -06:00
										 |  |  |         # Because setUp() already changes the current directory to the | 
					
						
							|  |  |  |         # temporary path, use a relative path here to prevent excessive | 
					
						
							|  |  |  |         # path lengths when compiling. | 
					
						
							|  |  |  |         generate_parser_c_extension(grammar, Path('.'), library_dir=self.library_dir) | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def run_test(self, grammar_source, test_source): | 
					
						
							|  |  |  |         self.build_extension(grammar_source) | 
					
						
							|  |  |  |         test_source = textwrap.indent(textwrap.dedent(test_source), 8 * " ") | 
					
						
							|  |  |  |         assert_python_ok( | 
					
						
							|  |  |  |             "-c", | 
					
						
							|  |  |  |             TEST_TEMPLATE.format(extension_path=self.tmp_path, test_source=test_source), | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |     def test_c_parser(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         start[mod_ty]: a[asdl_stmt_seq*]=stmt* $ { _PyAST_Module(a, NULL, p->arena) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         stmt[stmt_ty]: a=expr_stmt { a } | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         expr_stmt[stmt_ty]: a=expression NEWLINE { _PyAST_Expr(a, EXTRA) } | 
					
						
							|  |  |  |         expression[expr_ty]: ( l=expression '+' r=term { _PyAST_BinOp(l, Add, r, EXTRA) } | 
					
						
							|  |  |  |                             | l=expression '-' r=term { _PyAST_BinOp(l, Sub, r, EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |                             | t=term { t } | 
					
						
							|  |  |  |                             ) | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         term[expr_ty]: ( l=term '*' r=factor { _PyAST_BinOp(l, Mult, r, EXTRA) } | 
					
						
							|  |  |  |                     | l=term '/' r=factor { _PyAST_BinOp(l, Div, r, EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |                     | f=factor { f } | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |         factor[expr_ty]: ('(' e=expression ')' { e } | 
					
						
							|  |  |  |                         | a=atom { a } | 
					
						
							|  |  |  |                         ) | 
					
						
							|  |  |  |         atom[expr_ty]: ( n=NAME { n } | 
					
						
							|  |  |  |                     | n=NUMBER { n } | 
					
						
							|  |  |  |                     | s=STRING { s } | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         expressions = [ | 
					
						
							|  |  |  |             "4+5", | 
					
						
							|  |  |  |             "4-5", | 
					
						
							|  |  |  |             "4*5", | 
					
						
							|  |  |  |             "1+4*5", | 
					
						
							|  |  |  |             "1+4/5", | 
					
						
							|  |  |  |             "(1+1) + (1+1)", | 
					
						
							|  |  |  |             "(1+1) - (1+1)", | 
					
						
							|  |  |  |             "(1+1) * (1+1)", | 
					
						
							|  |  |  |             "(1+1) / (1+1)", | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for expr in expressions: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |             the_ast = parse.parse_string(expr, mode=1) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |             expected_ast = ast.parse(expr) | 
					
						
							|  |  |  |             self.assertEqual(ast_dump(the_ast), ast_dump(expected_ast)) | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_lookahead(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         start: NAME &NAME expr NEWLINE? ENDMARKER | 
					
						
							|  |  |  |         expr: NAME | NUMBER | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         valid_cases = ["foo bar"] | 
					
						
							|  |  |  |         invalid_cases = ["foo 34"] | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.check_input_strings_for_grammar(valid_cases, invalid_cases) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_negative_lookahead(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         start: NAME !NAME expr NEWLINE? ENDMARKER | 
					
						
							|  |  |  |         expr: NAME | NUMBER | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         valid_cases = ["foo 34"] | 
					
						
							|  |  |  |         invalid_cases = ["foo bar"] | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.check_input_strings_for_grammar(valid_cases, invalid_cases) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_cut(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         start: X ~ Y Z | X Q S | 
					
						
							|  |  |  |         X: 'x' | 
					
						
							|  |  |  |         Y: 'y' | 
					
						
							|  |  |  |         Z: 'z' | 
					
						
							|  |  |  |         Q: 'q' | 
					
						
							|  |  |  |         S: 's' | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         valid_cases = ["x y z"] | 
					
						
							|  |  |  |         invalid_cases = ["x q s"] | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.check_input_strings_for_grammar(valid_cases, invalid_cases) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_gather(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         start: ';'.pass_stmt+ NEWLINE | 
					
						
							|  |  |  |         pass_stmt: 'pass' | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         valid_cases = ["pass", "pass; pass"] | 
					
						
							|  |  |  |         invalid_cases = ["pass;", "pass; pass;"] | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.check_input_strings_for_grammar(valid_cases, invalid_cases) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_left_recursion(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         start: expr NEWLINE | 
					
						
							|  |  |  |         expr: ('-' term | expr '+' term | term) | 
					
						
							|  |  |  |         term: NUMBER | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         valid_cases = ["-34", "34", "34 + 12", "1 + 1 + 2 + 3"] | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.check_input_strings_for_grammar(valid_cases) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_advanced_left_recursive(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         start: NUMBER | sign start | 
					
						
							|  |  |  |         sign: ['-'] | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         valid_cases = ["23", "-34"] | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.check_input_strings_for_grammar(valid_cases) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_mutually_left_recursive(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         start: foo 'E' | 
					
						
							|  |  |  |         foo: bar 'A' | 'B' | 
					
						
							|  |  |  |         bar: foo 'C' | 'D' | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         valid_cases = ["B E", "D A C A E"] | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.check_input_strings_for_grammar(valid_cases) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_nasty_mutually_left_recursive(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         start: target '=' | 
					
						
							|  |  |  |         target: maybe '+' | NAME | 
					
						
							|  |  |  |         maybe: maybe '-' | target | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         valid_cases = ["x ="] | 
					
						
							|  |  |  |         invalid_cases = ["x - + ="] | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.check_input_strings_for_grammar(valid_cases, invalid_cases) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_return_stmt_noexpr_action(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         start[mod_ty]: a=[statements] ENDMARKER { _PyAST_Module(a, NULL, p->arena) } | 
					
						
							| 
									
										
										
										
											2020-10-03 15:28:51 +01:00
										 |  |  |         statements[asdl_stmt_seq*]: a[asdl_stmt_seq*]=statement+ { a } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         statement[stmt_ty]: simple_stmt | 
					
						
							|  |  |  |         simple_stmt[stmt_ty]: small_stmt | 
					
						
							|  |  |  |         small_stmt[stmt_ty]: return_stmt | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         return_stmt[stmt_ty]: a='return' NEWLINE { _PyAST_Return(NULL, EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         stmt = "return" | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.verify_ast_generation(stmt) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_gather_action_ast(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         start[mod_ty]: a[asdl_stmt_seq*]=';'.pass_stmt+ NEWLINE ENDMARKER { _PyAST_Module(a, NULL, p->arena) } | 
					
						
							|  |  |  |         pass_stmt[stmt_ty]: a='pass' { _PyAST_Pass(EXTRA)} | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         stmt = "pass; pass" | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.verify_ast_generation(stmt) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_pass_stmt_action(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         start[mod_ty]: a=[statements] ENDMARKER { _PyAST_Module(a, NULL, p->arena) } | 
					
						
							| 
									
										
										
										
											2020-10-03 15:28:51 +01:00
										 |  |  |         statements[asdl_stmt_seq*]: a[asdl_stmt_seq*]=statement+ { a } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         statement[stmt_ty]: simple_stmt | 
					
						
							|  |  |  |         simple_stmt[stmt_ty]: small_stmt | 
					
						
							|  |  |  |         small_stmt[stmt_ty]: pass_stmt | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         pass_stmt[stmt_ty]: a='pass' NEWLINE { _PyAST_Pass(EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         stmt = "pass" | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.verify_ast_generation(stmt) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_if_stmt_action(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         start[mod_ty]: a=[statements] ENDMARKER { _PyAST_Module(a, NULL, p->arena) } | 
					
						
							| 
									
										
										
										
											2020-10-03 15:28:51 +01:00
										 |  |  |         statements[asdl_stmt_seq*]: a=statement+ { (asdl_stmt_seq*)_PyPegen_seq_flatten(p, a) } | 
					
						
							|  |  |  |         statement[asdl_stmt_seq*]:  a=compound_stmt { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a) } | simple_stmt | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-03 15:28:51 +01:00
										 |  |  |         simple_stmt[asdl_stmt_seq*]: a=small_stmt b=further_small_stmt* [';'] NEWLINE { | 
					
						
							|  |  |  |                                             (asdl_stmt_seq*)_PyPegen_seq_insert_in_front(p, a, b) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         further_small_stmt[stmt_ty]: ';' a=small_stmt { a } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         block: simple_stmt | NEWLINE INDENT a=statements DEDENT { a } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         compound_stmt: if_stmt | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         if_stmt: 'if' a=full_expression ':' b=block { _PyAST_If(a, b, NULL, EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         small_stmt[stmt_ty]: pass_stmt | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         pass_stmt[stmt_ty]: a='pass' { _PyAST_Pass(EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         full_expression: NAME | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         stmt = "pass" | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.verify_ast_generation(stmt) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_same_name_different_types(self) -> None: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         start[mod_ty]: a[asdl_stmt_seq*]=import_from+ NEWLINE ENDMARKER { _PyAST_Module(a, NULL, p->arena)} | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         import_from[stmt_ty]: ( a='from' !'import' c=simple_name 'import' d=import_as_names_from { | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |                                 _PyAST_ImportFrom(c->v.Name.id, d, 0, EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |                             | a='from' '.' 'import' c=import_as_names_from { | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |                                 _PyAST_ImportFrom(NULL, c, 1, EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |                             ) | 
					
						
							|  |  |  |         simple_name[expr_ty]: NAME | 
					
						
							| 
									
										
										
										
											2020-10-03 15:28:51 +01:00
										 |  |  |         import_as_names_from[asdl_alias_seq*]: a[asdl_alias_seq*]=','.import_as_name_from+ { a } | 
					
						
							| 
									
										
										
										
											2021-04-10 16:56:28 -04:00
										 |  |  |         import_as_name_from[alias_ty]: a=NAME 'as' b=NAME { _PyAST_alias(((expr_ty) a)->v.Name.id, ((expr_ty) b)->v.Name.id, EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         for stmt in ("from a import b as c", "from . import a as b"): | 
					
						
							|  |  |  |             expected_ast = ast.parse(stmt) | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |             actual_ast = parse.parse_string(stmt, mode=1) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |             self.assertEqual(ast_dump(expected_ast), ast_dump(actual_ast)) | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_with_stmt_with_paren(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         start[mod_ty]: a=[statements] ENDMARKER { _PyAST_Module(a, NULL, p->arena) } | 
					
						
							| 
									
										
										
										
											2020-10-03 15:28:51 +01:00
										 |  |  |         statements[asdl_stmt_seq*]: a=statement+ { (asdl_stmt_seq*)_PyPegen_seq_flatten(p, a) } | 
					
						
							|  |  |  |         statement[asdl_stmt_seq*]: a=compound_stmt { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         compound_stmt[stmt_ty]: with_stmt | 
					
						
							|  |  |  |         with_stmt[stmt_ty]: ( | 
					
						
							| 
									
										
										
										
											2020-10-03 15:28:51 +01:00
										 |  |  |             a='with' '(' b[asdl_withitem_seq*]=','.with_item+ ')' ':' c=block { | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |                 _PyAST_With(b, (asdl_stmt_seq*) _PyPegen_singleton_seq(p, c), NULL, EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         ) | 
					
						
							|  |  |  |         with_item[withitem_ty]: ( | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |             e=NAME o=['as' t=NAME { t }] { _PyAST_withitem(e, _PyPegen_set_expr_context(p, o, Store), p->arena) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         ) | 
					
						
							|  |  |  |         block[stmt_ty]: a=pass_stmt NEWLINE { a } | NEWLINE INDENT a=pass_stmt DEDENT { a } | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         pass_stmt[stmt_ty]: a='pass' { _PyAST_Pass(EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							|  |  |  |         stmt = "with (\\n    a as b,\\n    c as d\\n): pass" | 
					
						
							|  |  |  |         the_ast = parse.parse_string(stmt, mode=1) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         self.assertTrue(ast_dump(the_ast).startswith( | 
					
						
							|  |  |  |             "Module(body=[With(items=[withitem(context_expr=Name(id='a', ctx=Load()), optional_vars=Name(id='b', ctx=Store())), " | 
					
						
							|  |  |  |             "withitem(context_expr=Name(id='c', ctx=Load()), optional_vars=Name(id='d', ctx=Store()))]" | 
					
						
							|  |  |  |         )) | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_ternary_operator(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |         start[mod_ty]: a=expr ENDMARKER { _PyAST_Module(a, NULL, p->arena) } | 
					
						
							|  |  |  |         expr[asdl_stmt_seq*]: a=listcomp NEWLINE { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, _PyAST_Expr(a, EXTRA)) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         listcomp[expr_ty]: ( | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |             a='[' b=NAME c=for_if_clauses d=']' { _PyAST_ListComp(b, c, EXTRA) } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2020-10-03 15:28:51 +01:00
										 |  |  |         for_if_clauses[asdl_comprehension_seq*]: ( | 
					
						
							| 
									
										
										
										
											2023-07-26 16:34:15 +01:00
										 |  |  |             a[asdl_comprehension_seq*]=(y=['async'] 'for' a=NAME 'in' b=NAME c[asdl_expr_seq*]=('if' z=NAME { z })* | 
					
						
							| 
									
										
										
										
											2021-04-07 21:34:22 +02:00
										 |  |  |                 { _PyAST_comprehension(_PyAST_Name(((expr_ty) a)->v.Name.id, Store, EXTRA), b, c, (y == NULL) ? 0 : 1, p->arena) })+ { a } | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         ) | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         stmt = "[i for i in a if b]" | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         self.verify_ast_generation(stmt) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_syntax_error_for_string(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							|  |  |  |         start: expr+ NEWLINE? ENDMARKER | 
					
						
							|  |  |  |         expr: NAME | 
					
						
							|  |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2020-06-25 14:31:30 +03:00
										 |  |  |         test_source = r"""
 | 
					
						
							|  |  |  |         for text in ("a b 42 b a", "\u540d \u540d 42 \u540d \u540d"): | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |             try: | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |                 parse.parse_string(text, mode=0) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |             except SyntaxError as e: | 
					
						
							|  |  |  |                 tb = traceback.format_exc() | 
					
						
							|  |  |  |             self.assertTrue('File "<string>", line 1' in tb) | 
					
						
							|  |  |  |             self.assertTrue(f"SyntaxError: invalid syntax" in tb) | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_headers_and_trailer(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							|  |  |  |         @header 'SOME HEADER' | 
					
						
							|  |  |  |         @subheader 'SOME SUBHEADER' | 
					
						
							|  |  |  |         @trailer 'SOME TRAILER' | 
					
						
							|  |  |  |         start: expr+ NEWLINE? ENDMARKER | 
					
						
							|  |  |  |         expr: x=NAME | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         grammar = parse_string(grammar_source, GrammarParser) | 
					
						
							|  |  |  |         parser_source = generate_c_parser_source(grammar) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertTrue("SOME HEADER" in parser_source) | 
					
						
							|  |  |  |         self.assertTrue("SOME SUBHEADER" in parser_source) | 
					
						
							|  |  |  |         self.assertTrue("SOME TRAILER" in parser_source) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_error_in_rules(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							|  |  |  |         start: expr+ NEWLINE? ENDMARKER | 
					
						
							|  |  |  |         expr: NAME {PyTuple_New(-1)} | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # PyTuple_New raises SystemError if an invalid argument was passed. | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |         test_source = """
 | 
					
						
							| 
									
										
										
										
											2020-04-22 23:29:27 +01:00
										 |  |  |         with self.assertRaises(SystemError): | 
					
						
							| 
									
										
										
										
											2020-04-24 16:51:09 +03:00
										 |  |  |             parse.parse_string("a", mode=0) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-05-26 10:58:44 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_no_soft_keywords(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							|  |  |  |         start: expr+ NEWLINE? ENDMARKER | 
					
						
							|  |  |  |         expr: 'foo' | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         grammar = parse_string(grammar_source, GrammarParser) | 
					
						
							|  |  |  |         parser_source = generate_c_parser_source(grammar) | 
					
						
							|  |  |  |         assert "expect_soft_keyword" not in parser_source | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_soft_keywords(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							|  |  |  |         start: expr+ NEWLINE? ENDMARKER | 
					
						
							|  |  |  |         expr: "foo" | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         grammar = parse_string(grammar_source, GrammarParser) | 
					
						
							|  |  |  |         parser_source = generate_c_parser_source(grammar) | 
					
						
							|  |  |  |         assert "expect_soft_keyword" in parser_source | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_soft_keywords_parse(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							|  |  |  |         start: "if" expr '+' expr NEWLINE | 
					
						
							|  |  |  |         expr: NAME | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         test_source = """
 | 
					
						
							|  |  |  |         valid_cases = ["if if + if"] | 
					
						
							|  |  |  |         invalid_cases = ["if if"] | 
					
						
							|  |  |  |         self.check_input_strings_for_grammar(valid_cases, invalid_cases) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2020-05-27 00:15:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_soft_keywords_lookahead(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							|  |  |  |         start: &"if" "if" expr '+' expr NEWLINE | 
					
						
							|  |  |  |         expr: NAME | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         test_source = """
 | 
					
						
							|  |  |  |         valid_cases = ["if if + if"] | 
					
						
							|  |  |  |         invalid_cases = ["if if"] | 
					
						
							|  |  |  |         self.check_input_strings_for_grammar(valid_cases, invalid_cases) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							| 
									
										
										
										
											2021-08-12 17:37:30 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_forced(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							|  |  |  |         start: NAME &&':' | NAME | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         test_source = """
 | 
					
						
							|  |  |  |         self.assertEqual(parse.parse_string("number :", mode=0), None) | 
					
						
							|  |  |  |         with self.assertRaises(SyntaxError) as e: | 
					
						
							|  |  |  |             parse.parse_string("a", mode=0) | 
					
						
							|  |  |  |         self.assertIn("expected ':'", str(e.exception)) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_forced_with_group(self) -> None: | 
					
						
							|  |  |  |         grammar_source = """
 | 
					
						
							|  |  |  |         start: NAME &&(':' | ';') | NAME | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         test_source = """
 | 
					
						
							|  |  |  |         self.assertEqual(parse.parse_string("number :", mode=0), None) | 
					
						
							|  |  |  |         self.assertEqual(parse.parse_string("number ;", mode=0), None) | 
					
						
							|  |  |  |         with self.assertRaises(SyntaxError) as e: | 
					
						
							|  |  |  |             parse.parse_string("a", mode=0) | 
					
						
							|  |  |  |         self.assertIn("expected (':' | ';')", e.exception.args[0]) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         self.run_test(grammar_source, test_source) |