|
- """
- Python 3 to Python 2 converter (tree templates)
- ===============================================
-
- This example demonstrates how to translate between two trees using tree templates.
- It parses Python 3, translates it to a Python 2 AST, and then outputs the result as Python 2 code.
-
- Uses reconstruct_python.py for generating the final Python 2 code.
- """
-
-
- from lark import Lark
- from lark.tree_templates import TemplateConf, TemplateTranslator
-
- from lark.indenter import PythonIndenter
- from reconstruct_python import PythonReconstructor
-
-
- #
- # 1. Define a Python parser that also accepts template vars in the code (in the form of $var)
- #
- TEMPLATED_PYTHON = r"""
- %import python (single_input, file_input, eval_input, atom, var, stmt, expr, testlist_star_expr, _NEWLINE, _INDENT, _DEDENT, COMMENT, NAME)
-
- %extend atom: TEMPLATE_NAME -> var
-
- TEMPLATE_NAME: "$" NAME
-
- ?template_start: (stmt | testlist_star_expr _NEWLINE)
-
- %ignore /[\t \f]+/ // WS
- %ignore /\\[\t \f]*\r?\n/ // LINE_CONT
- %ignore COMMENT
- """
-
- parser = Lark(TEMPLATED_PYTHON, parser='lalr', start=['single_input', 'file_input', 'eval_input', 'template_start'], postlex=PythonIndenter(), maybe_placeholders=False)
-
-
- def parse_template(s):
- return parser.parse(s + '\n', start='template_start')
-
- def parse_code(s):
- return parser.parse(s + '\n', start='file_input')
-
-
- #
- # 2. Define translations using templates (each template code is parsed to a template tree)
- #
-
- pytemplate = TemplateConf(parse=parse_template)
-
- translations_3to2 = {
- 'yield from $a':
- 'for _tmp in $a: yield _tmp',
-
- 'raise $e from $x':
- 'raise $e',
-
- '$a / $b':
- 'float($a) / $b',
- }
- translations_3to2 = {pytemplate(k): pytemplate(v) for k, v in translations_3to2.items()}
-
- #
- # 3. Translate and reconstruct Python 3 code into valid Python 2 code
- #
-
- python_reconstruct = PythonReconstructor(parser)
-
- def translate_py3to2(code):
- tree = parse_code(code)
- tree = TemplateTranslator(translations_3to2).translate(tree)
- return python_reconstruct.reconstruct(tree)
-
-
- #
- # Test Code
- #
-
- _TEST_CODE = '''
- if a / 2 > 1:
- yield from [1,2,3]
- else:
- raise ValueError(a) from e
-
- '''
-
- def test():
- print(_TEST_CODE)
- print(' -----> ')
- print(translate_py3to2(_TEST_CODE))
-
- if __name__ == '__main__':
- test()
|