Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added match stmt support to python.lark #1016

Merged
merged 2 commits into from
Mar 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions examples/advanced/python_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ def _read(fn, *args):
def _get_lib_path():
if os.name == 'nt':
if 'PyPy' in sys.version:
return os.path.join(sys.prefix, 'lib-python', sys.winver)
return os.path.join(sys.base_prefix, 'lib-python', sys.winver)
else:
return os.path.join(sys.prefix, 'Lib')
return os.path.join(sys.base_prefix, 'Lib')
else:
return [x for x in sys.path if x.endswith('%s.%s' % sys.version_info[:2])][0]

Expand Down Expand Up @@ -84,5 +84,4 @@ def test_earley_equals_lalr():
if __name__ == '__main__':
test_python_lib()
# test_earley_equals_lalr()
# python_parser3.parse(_read(sys.argv[1]) + '\n')

# python_parser3.parse(_read(sys.argv[1]) + '\n')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# python_parser3.parse(_read(sys.argv[1]) + '\n')
# python_parser3.parse(_read(sys.argv[1]) + '\n')

87 changes: 69 additions & 18 deletions lark/grammars/python.lark
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ decorators: decorator+
decorated: decorators (classdef | funcdef | async_funcdef)

async_funcdef: "async" funcdef
funcdef: "def" NAME "(" [parameters] ")" ["->" test] ":" suite
funcdef: "def" name "(" [parameters] ")" ["->" test] ":" suite

parameters: paramvalue ("," paramvalue)* ["," SLASH] ["," [starparams | kwparams]]
| starparams
Expand All @@ -31,17 +31,17 @@ starparams: "*" typedparam? ("," paramvalue)* ["," kwparams]
kwparams: "**" typedparam ","?

?paramvalue: typedparam ("=" test)?
?typedparam: NAME (":" test)?
?typedparam: name (":" test)?


lambdef: "lambda" [lambda_params] ":" test
lambdef_nocond: "lambda" [lambda_params] ":" test_nocond
lambda_params: lambda_paramvalue ("," lambda_paramvalue)* ["," [lambda_starparams | lambda_kwparams]]
| lambda_starparams
| lambda_kwparams
?lambda_paramvalue: NAME ("=" test)?
lambda_starparams: "*" [NAME] ("," lambda_paramvalue)* ["," [lambda_kwparams]]
lambda_kwparams: "**" NAME ","?
?lambda_paramvalue: name ("=" test)?
lambda_starparams: "*" [name] ("," lambda_paramvalue)* ["," [lambda_kwparams]]
lambda_kwparams: "**" name ","?


?stmt: simple_stmt | compound_stmt
Expand Down Expand Up @@ -72,16 +72,17 @@ import_name: "import" dotted_as_names
// note below: the ("." | "...") is necessary because "..." is tokenized as ELLIPSIS
import_from: "from" (dots? dotted_name | dots) "import" ("*" | "(" import_as_names ")" | import_as_names)
!dots: "."+
import_as_name: NAME ["as" NAME]
dotted_as_name: dotted_name ["as" NAME]
import_as_name: name ["as" name]
dotted_as_name: dotted_name ["as" name]
import_as_names: import_as_name ("," import_as_name)* [","]
dotted_as_names: dotted_as_name ("," dotted_as_name)*
dotted_name: NAME ("." NAME)*
global_stmt: "global" NAME ("," NAME)*
nonlocal_stmt: "nonlocal" NAME ("," NAME)*
dotted_name: name ("." name)*
global_stmt: "global" name ("," name)*
nonlocal_stmt: "nonlocal" name ("," name)*
assert_stmt: "assert" test ["," test]

?compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt
?compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | match_stmt
| with_stmt | funcdef | classdef | decorated | async_stmt
async_stmt: "async" (funcdef | with_stmt | for_stmt)
if_stmt: "if" test ":" suite elifs ["else" ":" suite]
elifs: elif_*
Expand All @@ -92,12 +93,61 @@ try_stmt: "try" ":" suite except_clauses ["else" ":" suite] [finally]
| "try" ":" suite finally -> try_finally
finally: "finally" ":" suite
except_clauses: except_clause+
except_clause: "except" [test ["as" NAME]] ":" suite
except_clause: "except" [test ["as" name]] ":" suite
// NB compile.c makes sure that the default except clause is last


with_stmt: "with" with_items ":" suite
with_items: with_item ("," with_item)*
with_item: test ["as" expr]
// NB compile.c makes sure that the default except clause is last
with_item: test ["as" name]

match_stmt: "match" test ":" _NEWLINE _INDENT case+ _DEDENT

case: "case" pattern ["if" test] ":" suite

?pattern: sequence_item_pattern "," _sequence_pattern -> sequence_pattern
| as_pattern
?as_pattern: or_pattern ("as" NAME)?
?or_pattern: closed_pattern ("|" closed_pattern)*
?closed_pattern: literal_pattern
| NAME -> capture_pattern
| "_" -> any_pattern
| attr_pattern
| "(" as_pattern ")"
| "[" _sequence_pattern "]" -> sequence_pattern
| "(" (sequence_item_pattern "," _sequence_pattern)? ")" -> sequence_pattern
| "{" (mapping_item_pattern ("," mapping_item_pattern)* ","?)?"}" -> mapping_pattern
| "{" (mapping_item_pattern ("," mapping_item_pattern)* ",")? "**" NAME ","? "}" -> mapping_star_pattern
| class_pattern

literal_pattern: inner_literal_pattern

?inner_literal_pattern: "None" -> const_none
| "True" -> const_true
| "False" -> const_false
| STRING -> string
| number

attr_pattern: NAME ("." NAME)+ -> value

name_or_attr_pattern: NAME ("." NAME)* -> value

mapping_item_pattern: (literal_pattern|attr_pattern) ":" as_pattern

_sequence_pattern: (sequence_item_pattern ("," sequence_item_pattern)* ","?)?
?sequence_item_pattern: as_pattern
| "*" NAME -> star_pattern

class_pattern: name_or_attr_pattern "(" [arguments_pattern ","?] ")"
arguments_pattern: pos_arg_pattern ["," keyws_arg_pattern]
| keyws_arg_pattern -> no_pos_arguments

pos_arg_pattern: as_pattern ("," as_pattern)*
keyws_arg_pattern: keyw_arg_pattern ("," keyw_arg_pattern)*
keyw_arg_pattern: NAME "=" as_pattern



suite: simple_stmt | _NEWLINE _INDENT stmt+ _DEDENT

?test: or_test ("if" or_test "else" test)?
Expand Down Expand Up @@ -134,7 +184,7 @@ AWAIT: "await"

?atom_expr: atom_expr "(" [arguments] ")" -> funccall
| atom_expr "[" subscriptlist "]" -> getitem
| atom_expr "." NAME -> getattr
| atom_expr "." name -> getattr
| atom

?atom: "(" yield_expr ")"
Expand All @@ -146,7 +196,7 @@ AWAIT: "await"
| "{" comprehension{key_value} "}" -> dict_comprehension
| "{" _set_exprlist "}" -> set
| "{" comprehension{test} "}" -> set_comprehension
| NAME -> var
| name -> var
| number
| string_concat
| "(" test ")"
Expand Down Expand Up @@ -179,7 +229,7 @@ key_value: test ":" test

_set_exprlist: test_or_star_expr ("," test_or_star_expr)* [","]

classdef: "class" NAME ["(" [arguments] ")"] ":" suite
classdef: "class" name ["(" [arguments] ")"] ":" suite



Expand All @@ -202,7 +252,7 @@ ASYNC: "async"
?comp_if: "if" test_nocond

// not used in grammar, but may appear in "node" passed from Parser to Compiler
encoding_decl: NAME
encoding_decl: name

yield_expr: "yield" [testlist]
| "yield" "from" test -> yield_from
Expand All @@ -222,6 +272,7 @@ _NEWLINE: ( /\r?\n[\t ]*/ | COMMENT )+

// Python terminals

!name: NAME | "match" | "case"
NAME: /[a-zA-Z_]\w*/
COMMENT: /#[^\n]*/

Expand Down