@@ -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 | ||||