| @@ -0,0 +1,46 @@ | |||||
| """ | |||||
| Extend the Python Grammar | |||||
| ============================== | |||||
| This example demonstrates how to use the `%extend` statement, | |||||
| to add new syntax to the example Python grammar. | |||||
| """ | |||||
| from lark.lark import Lark | |||||
| from python_parser import PythonIndenter | |||||
| GRAMMAR = r""" | |||||
| %import .python3 (compound_stmt, single_input, file_input, eval_input, test, suite, _NEWLINE, _INDENT, _DEDENT, COMMENT) | |||||
| %extend compound_stmt: match_stmt | |||||
| match_stmt: "match" test ":" cases | |||||
| cases: _NEWLINE _INDENT case+ _DEDENT | |||||
| case: "case" test ":" suite // test is not quite correct. | |||||
| %ignore /[\t \f]+/ // WS | |||||
| %ignore /\\[\t \f]*\r?\n/ // LINE_CONT | |||||
| %ignore COMMENT | |||||
| """ | |||||
| parser = Lark(GRAMMAR, parser='lalr', start=['single_input', 'file_input', 'eval_input'], postlex=PythonIndenter()) | |||||
| tree = parser.parse(r""" | |||||
| def name(n): | |||||
| match n: | |||||
| case 1: | |||||
| print("one") | |||||
| case 2: | |||||
| print("two") | |||||
| case _: | |||||
| print("number is too big") | |||||
| """, start='file_input') | |||||
| # Remove the 'python3__' prefix that was add to the implicitely imported rules. | |||||
| for t in tree.iter_subtrees(): | |||||
| t.data = t.data.rsplit('__', 1)[-1] | |||||
| print(tree.pretty()) | |||||
| @@ -1,59 +0,0 @@ | |||||
| from pathlib import Path | |||||
| from lark.indenter import Indenter | |||||
| from lark.lark import Lark | |||||
| from lark.load_grammar import GrammarBuilder | |||||
| MATCH_GRAMMAR = ('match', """ | |||||
| %extend compound_stmt: match_stmt | |||||
| match_stmt: "match" test ":" cases | |||||
| cases: _NEWLINE _INDENT case+ _DEDENT | |||||
| case: "case" test ":" suite // test is not quite correct. | |||||
| """, ('compound_stmt', 'test', 'suite', '_DEDENT', '_INDENT', '_NEWLINE')) | |||||
| EXTENSIONS = (MATCH_GRAMMAR,) | |||||
| builder = GrammarBuilder() | |||||
| builder.load_grammar((Path(__file__).with_name('python3.lark')).read_text(), 'python3') | |||||
| for name, ext_grammar, needed_names in EXTENSIONS: | |||||
| mangle = builder.get_mangle(name, dict(zip(needed_names, needed_names))) | |||||
| builder.load_grammar(ext_grammar, name, mangle) | |||||
| grammar = builder.build() | |||||
| class PythonIndenter(Indenter): | |||||
| NL_type = '_NEWLINE' | |||||
| OPEN_PAREN_types = ['LPAR', 'LSQB', 'LBRACE'] | |||||
| CLOSE_PAREN_types = ['RPAR', 'RSQB', 'RBRACE'] | |||||
| INDENT_type = '_INDENT' | |||||
| DEDENT_type = '_DEDENT' | |||||
| tab_len = 8 | |||||
| parser = Lark(grammar, parser='lalr', start=['single_input', 'file_input', 'eval_input'], postlex=PythonIndenter()) | |||||
| tree = parser.parse(r""" | |||||
| a = 5 | |||||
| def name(n): | |||||
| match n: | |||||
| case 1: | |||||
| print("one") | |||||
| case 2: | |||||
| print("two") | |||||
| case _: | |||||
| print("number is to big") | |||||
| name(a) | |||||
| """, start='file_input') | |||||
| print(tree.pretty()) | |||||
| @@ -977,6 +977,9 @@ class GrammarBuilder: | |||||
| aliases = dict(zip(names, names)) # Can't have aliased multi import, so all aliases will be the same as names | aliases = dict(zip(names, names)) # Can't have aliased multi import, so all aliases will be the same as names | ||||
| else: # Single import | else: # Single import | ||||
| dotted_path = tuple(path_node.children[:-1]) | dotted_path = tuple(path_node.children[:-1]) | ||||
| if not dotted_path: | |||||
| name ,= path_node.children | |||||
| raise GrammarError("Nothing was imported from grammar `%s`" % name) | |||||
| name = path_node.children[-1] # Get name from dotted path | name = path_node.children[-1] # Get name from dotted path | ||||
| aliases = {name.value: (arg1 or name).value} # Aliases if exist | aliases = {name.value: (arg1 or name).value} # Aliases if exist | ||||