aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Grammar/python.gram
diff options
context:
space:
mode:
Diffstat (limited to 'Grammar/python.gram')
-rw-r--r--Grammar/python.gram667
1 files changed, 446 insertions, 221 deletions
diff --git a/Grammar/python.gram b/Grammar/python.gram
index 8219add9006..278ddfb2d1a 100644
--- a/Grammar/python.gram
+++ b/Grammar/python.gram
@@ -25,43 +25,89 @@ _PyPegen_parse(Parser *p)
return result;
}
-
-// The end
'''
+
+# ========================= START OF THE GRAMMAR =========================
+
+# General grammatical elements and rules:
+#
+# * Strings with double quotes (") denote SOFT KEYWORDS
+# * Strings with single quotes (') denote KEYWORDS
+# * Upper case names (NAME) denote tokens in the Grammar/Tokens file
+# * Rule names starting with "invalid_" are used for specialized syntax errors
+# - These rules are NOT used in the first pass of the parser.
+# - Only if the first pass fails to parse, a second pass including the invalid
+# rules will be executed.
+# - If the parser fails in the second phase with a generic syntax error, the
+# location of the generic failure of the first pass will be used (this avoids
+# reporting incorrect locations due to the invalid rules).
+# - The order of the alternatives involving invalid rules matter
+# (like any rule in PEG).
+#
+# Grammar Syntax (see PEP 617 for more information):
+#
+# rule_name: expression
+# Optionally, a type can be included right after the rule name, which
+# specifies the return type of the C or Python function corresponding to the
+# rule:
+# rule_name[return_type]: expression
+# If the return type is omitted, then a void * is returned in C and an Any in
+# Python.
+# e1 e2
+# Match e1, then match e2.
+# e1 | e2
+# Match e1 or e2.
+# The first alternative can also appear on the line after the rule name for
+# formatting purposes. In that case, a | must be used before the first
+# alternative, like so:
+# rule_name[return_type]:
+# | first_alt
+# | second_alt
+# ( e )
+# Match e (allows also to use other operators in the group like '(e)*')
+# [ e ] or e?
+# Optionally match e.
+# e*
+# Match zero or more occurrences of e.
+# e+
+# Match one or more occurrences of e.
+# s.e+
+# Match one or more occurrences of e, separated by s. The generated parse tree
+# does not include the separator. This is otherwise identical to (e (s e)*).
+# &e
+# Succeed if e can be parsed, without consuming any input.
+# !e
+# Fail if e can be parsed, without consuming any input.
+# ~
+# Commit to the current alternative, even if it fails to parse.
+#
+
+# STARTING RULES
+# ==============
+
file[mod_ty]: a=[statements] ENDMARKER { _PyPegen_make_module(p, a) }
interactive[mod_ty]: a=statement_newline { _PyAST_Interactive(a, p->arena) }
eval[mod_ty]: a=expressions NEWLINE* ENDMARKER { _PyAST_Expression(a, p->arena) }
func_type[mod_ty]: '(' a=[type_expressions] ')' '->' b=expression NEWLINE* ENDMARKER { _PyAST_FunctionType(a, b, p->arena) }
fstring[expr_ty]: star_expressions
-# type_expressions allow */** but ignore them
-type_expressions[asdl_expr_seq*]:
- | a=','.expression+ ',' '*' b=expression ',' '**' c=expression {
- (asdl_expr_seq*)_PyPegen_seq_append_to_end(
- p,
- CHECK(asdl_seq*, _PyPegen_seq_append_to_end(p, a, b)),
- c) }
- | a=','.expression+ ',' '*' b=expression { (asdl_expr_seq*)_PyPegen_seq_append_to_end(p, a, b) }
- | a=','.expression+ ',' '**' b=expression { (asdl_expr_seq*)_PyPegen_seq_append_to_end(p, a, b) }
- | '*' a=expression ',' '**' b=expression {
- (asdl_expr_seq*)_PyPegen_seq_append_to_end(
- p,
- CHECK(asdl_seq*, _PyPegen_singleton_seq(p, a)),
- b) }
- | '*' a=expression { (asdl_expr_seq*)_PyPegen_singleton_seq(p, a) }
- | '**' a=expression { (asdl_expr_seq*)_PyPegen_singleton_seq(p, a) }
- | a[asdl_expr_seq*]=','.expression+ {a}
+# GENERAL STATEMENTS
+# ==================
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) } | a[asdl_stmt_seq*]=simple_stmts { a }
+
statement_newline[asdl_stmt_seq*]:
| a=compound_stmt NEWLINE { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a) }
| simple_stmts
| NEWLINE { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, CHECK(stmt_ty, _PyAST_Pass(EXTRA))) }
| ENDMARKER { _PyPegen_interactive_exit(p) }
+
simple_stmts[asdl_stmt_seq*]:
| a=simple_stmt !';' NEWLINE { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a) } # Not needed, there for speedup
| a[asdl_stmt_seq*]=';'.simple_stmt+ [';'] NEWLINE { a }
+
# NOTE: assignment MUST precede expression, else parsing a simple assignment
# will throw a SyntaxError.
simple_stmt[stmt_ty] (memo):
@@ -78,6 +124,7 @@ simple_stmt[stmt_ty] (memo):
| 'continue' { _PyAST_Continue(EXTRA) }
| &'global' global_stmt
| &'nonlocal' nonlocal_stmt
+
compound_stmt[stmt_ty]:
| &('def' | '@' | ASYNC) function_def
| &'if' if_stmt
@@ -88,6 +135,9 @@ compound_stmt[stmt_ty]:
| &'while' while_stmt
| match_stmt
+# SIMPLE STATEMENTS
+# =================
+
# NOTE: annotated_rhs may start with 'yield'; yield_expr must start with 'yield'
assignment[stmt_ty]:
| a=NAME ':' b=expression c=['=' d=annotated_rhs { d }] {
@@ -106,6 +156,8 @@ assignment[stmt_ty]:
_PyAST_AugAssign(a, b->kind, c, EXTRA) }
| invalid_assignment
+annotated_rhs[expr_ty]: yield_expr | star_expressions
+
augassign[AugOperator*]:
| '+=' { _PyPegen_augoperator(p, Add) }
| '-=' { _PyPegen_augoperator(p, Sub) }
@@ -121,20 +173,32 @@ augassign[AugOperator*]:
| '**=' { _PyPegen_augoperator(p, Pow) }
| '//=' { _PyPegen_augoperator(p, FloorDiv) }
+return_stmt[stmt_ty]:
+ | 'return' a=[star_expressions] { _PyAST_Return(a, EXTRA) }
+
+raise_stmt[stmt_ty]:
+ | 'raise' a=expression b=['from' z=expression { z }] { _PyAST_Raise(a, b, EXTRA) }
+ | 'raise' { _PyAST_Raise(NULL, NULL, EXTRA) }
+
global_stmt[stmt_ty]: 'global' a[asdl_expr_seq*]=','.NAME+ {
_PyAST_Global(CHECK(asdl_identifier_seq*, _PyPegen_map_names_to_ids(p, a)), EXTRA) }
+
nonlocal_stmt[stmt_ty]: 'nonlocal' a[asdl_expr_seq*]=','.NAME+ {
_PyAST_Nonlocal(CHECK(asdl_identifier_seq*, _PyPegen_map_names_to_ids(p, a)), EXTRA) }
-yield_stmt[stmt_ty]: y=yield_expr { _PyAST_Expr(y, EXTRA) }
-
-assert_stmt[stmt_ty]: 'assert' a=expression b=[',' z=expression { z }] { _PyAST_Assert(a, b, EXTRA) }
-
del_stmt[stmt_ty]:
| 'del' a=del_targets &(';' | NEWLINE) { _PyAST_Delete(a, EXTRA) }
| invalid_del_stmt
+yield_stmt[stmt_ty]: y=yield_expr { _PyAST_Expr(y, EXTRA) }
+
+assert_stmt[stmt_ty]: 'assert' a=expression b=[',' z=expression { z }] { _PyAST_Assert(a, b, EXTRA) }
+
import_stmt[stmt_ty]: import_name | import_from
+
+# Import statements
+# -----------------
+
import_name[stmt_ty]: 'import' a=dotted_as_names { _PyAST_Import(a, EXTRA) }
# note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS
import_from[stmt_ty]:
@@ -163,6 +227,123 @@ dotted_name[expr_ty]:
| a=dotted_name '.' b=NAME { _PyPegen_join_names_with_dot(p, a, b) }
| NAME
+# COMPOUND STATEMENTS
+# ===================
+
+# Common elements
+# ---------------
+
+block[asdl_stmt_seq*] (memo):
+ | NEWLINE INDENT a=statements DEDENT { a }
+ | simple_stmts
+ | invalid_block
+
+decorators[asdl_expr_seq*]: a[asdl_expr_seq*]=('@' f=named_expression NEWLINE { f })+ { a }
+
+# Class definitions
+# -----------------
+
+class_def[stmt_ty]:
+ | a=decorators b=class_def_raw { _PyPegen_class_def_decorators(p, a, b) }
+ | class_def_raw
+
+class_def_raw[stmt_ty]:
+ | invalid_class_def_raw
+ | 'class' a=NAME b=['(' z=[arguments] ')' { z }] &&':' c=block {
+ _PyAST_ClassDef(a->v.Name.id,
+ (b) ? ((expr_ty) b)->v.Call.args : NULL,
+ (b) ? ((expr_ty) b)->v.Call.keywords : NULL,
+ c, NULL, EXTRA) }
+
+# Function definitions
+# --------------------
+
+function_def[stmt_ty]:
+ | d=decorators f=function_def_raw { _PyPegen_function_def_decorators(p, d, f) }
+ | function_def_raw
+
+function_def_raw[stmt_ty]:
+ | invalid_def_raw
+ | 'def' n=NAME '(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
+ _PyAST_FunctionDef(n->v.Name.id,
+ (params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)),
+ b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA) }
+ | ASYNC 'def' n=NAME '(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
+ CHECK_VERSION(
+ stmt_ty,
+ 5,
+ "Async functions are",
+ _PyAST_AsyncFunctionDef(n->v.Name.id,
+ (params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)),
+ b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA)
+ ) }
+
+# Function parameters
+# -------------------
+
+params[arguments_ty]:
+ | invalid_parameters
+ | parameters
+
+parameters[arguments_ty]:
+ | a=slash_no_default b[asdl_arg_seq*]=param_no_default* c=param_with_default* d=[star_etc] {
+ _PyPegen_make_arguments(p, a, NULL, b, c, d) }
+ | a=slash_with_default b=param_with_default* c=[star_etc] {
+ _PyPegen_make_arguments(p, NULL, a, NULL, b, c) }
+ | a[asdl_arg_seq*]=param_no_default+ b=param_with_default* c=[star_etc] {
+ _PyPegen_make_arguments(p, NULL, NULL, a, b, c) }
+ | a=param_with_default+ b=[star_etc] { _PyPegen_make_arguments(p, NULL, NULL, NULL, a, b)}
+ | a=star_etc { _PyPegen_make_arguments(p, NULL, NULL, NULL, NULL, a) }
+
+# Some duplication here because we can't write (',' | &')'),
+# which is because we don't support empty alternatives (yet).
+
+slash_no_default[asdl_arg_seq*]:
+ | a[asdl_arg_seq*]=param_no_default+ '/' ',' { a }
+ | a[asdl_arg_seq*]=param_no_default+ '/' &')' { a }
+slash_with_default[SlashWithDefault*]:
+ | a=param_no_default* b=param_with_default+ '/' ',' { _PyPegen_slash_with_default(p, (asdl_arg_seq *)a, b) }
+ | a=param_no_default* b=param_with_default+ '/' &')' { _PyPegen_slash_with_default(p, (asdl_arg_seq *)a, b) }
+
+star_etc[StarEtc*]:
+ | '*' a=param_no_default b=param_maybe_default* c=[kwds] {
+ _PyPegen_star_etc(p, a, b, c) }
+ | '*' ',' b=param_maybe_default+ c=[kwds] {
+ _PyPegen_star_etc(p, NULL, b, c) }
+ | a=kwds { _PyPegen_star_etc(p, NULL, NULL, a) }
+ | invalid_star_etc
+
+kwds[arg_ty]: '**' a=param_no_default { a }
+
+# One parameter. This *includes* a following comma and type comment.
+#
+# There are three styles:
+# - No default
+# - With default
+# - Maybe with default
+#
+# There are two alternative forms of each, to deal with type comments:
+# - Ends in a comma followed by an optional type comment
+# - No comma, optional type comment, must be followed by close paren
+# The latter form is for a final parameter without trailing comma.
+#
+
+param_no_default[arg_ty]:
+ | a=param ',' tc=TYPE_COMMENT? { _PyPegen_add_type_comment_to_arg(p, a, tc) }
+ | a=param tc=TYPE_COMMENT? &')' { _PyPegen_add_type_comment_to_arg(p, a, tc) }
+param_with_default[NameDefaultPair*]:
+ | a=param c=default ',' tc=TYPE_COMMENT? { _PyPegen_name_default_pair(p, a, c, tc) }
+ | a=param c=default tc=TYPE_COMMENT? &')' { _PyPegen_name_default_pair(p, a, c, tc) }
+param_maybe_default[NameDefaultPair*]:
+ | a=param c=default? ',' tc=TYPE_COMMENT? { _PyPegen_name_default_pair(p, a, c, tc) }
+ | a=param c=default? tc=TYPE_COMMENT? &')' { _PyPegen_name_default_pair(p, a, c, tc) }
+param[arg_ty]: a=NAME b=annotation? { _PyAST_arg(a->v.Name.id, b, NULL, EXTRA) }
+annotation[expr_ty]: ':' a=expression { a }
+default[expr_ty]: '=' a=expression { a }
+
+# If statement
+# ------------
+
if_stmt[stmt_ty]:
| invalid_if_stmt
| 'if' a=named_expression ':' b=block c=elif_stmt {
@@ -177,10 +358,16 @@ else_block[asdl_stmt_seq*]:
| invalid_else_stmt
| 'else' &&':' b=block { b }
+# While statement
+# ---------------
+
while_stmt[stmt_ty]:
| invalid_while_stmt
| 'while' a=named_expression ':' b=block c=[else_block] { _PyAST_While(a, b, c, EXTRA) }
+# For statement
+# -------------
+
for_stmt[stmt_ty]:
| invalid_for_stmt
| 'for' t=star_targets 'in' ~ ex=star_expressions &&':' tc=[TYPE_COMMENT] b=block el=[else_block] {
@@ -189,6 +376,9 @@ for_stmt[stmt_ty]:
CHECK_VERSION(stmt_ty, 5, "Async for loops are", _PyAST_AsyncFor(t, ex, b, el, NEW_TYPE_COMMENT(p, tc), EXTRA)) }
| invalid_for_target
+# With statement
+# --------------
+
with_stmt[stmt_ty]:
| invalid_with_stmt_indent
| 'with' '(' a[asdl_withitem_seq*]=','.with_item+ ','? ')' ':' b=block {
@@ -206,10 +396,17 @@ with_item[withitem_ty]:
| invalid_with_item
| e=expression { _PyAST_withitem(e, NULL, p->arena) }
+# Try statement
+# -------------
+
try_stmt[stmt_ty]:
| invalid_try_stmt
| 'try' &&':' b=block f=finally_block { _PyAST_Try(b, NULL, NULL, f, EXTRA) }
| 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_block+ el=[else_block] f=[finally_block] { _PyAST_Try(b, ex, el, f, EXTRA) }
+
+# Except statement
+# ----------------
+
except_block[excepthandler_ty]:
| invalid_except_stmt_indent
| 'except' e=expression t=['as' z=NAME { z }] ':' b=block {
@@ -220,34 +417,44 @@ finally_block[asdl_stmt_seq*]:
| invalid_finally_stmt
| 'finally' &&':' a=block { a }
+# Match statement
+# ---------------
+
match_stmt[stmt_ty]:
| "match" subject=subject_expr ':' NEWLINE INDENT cases[asdl_match_case_seq*]=case_block+ DEDENT {
CHECK_VERSION(stmt_ty, 10, "Pattern matching is", _PyAST_Match(subject, cases, EXTRA)) }
| invalid_match_stmt
+
subject_expr[expr_ty]:
| value=star_named_expression ',' values=star_named_expressions? {
_PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, value, values)), Load, EXTRA) }
| named_expression
+
case_block[match_case_ty]:
| invalid_case_block
| "case" pattern=patterns guard=guard? ':' body=block {
_PyAST_match_case(pattern, guard, body, p->arena) }
+
guard[expr_ty]: 'if' guard=named_expression { guard }
patterns[pattern_ty]:
| patterns[asdl_pattern_seq*]=open_sequence_pattern {
_PyAST_MatchSequence(patterns, EXTRA) }
| pattern
+
pattern[pattern_ty]:
| as_pattern
| or_pattern
+
as_pattern[pattern_ty]:
| pattern=or_pattern 'as' target=pattern_capture_target {
_PyAST_MatchAs(pattern, target->v.Name.id, EXTRA) }
| invalid_as_pattern
+
or_pattern[pattern_ty]:
| patterns[asdl_pattern_seq*]='|'.closed_pattern+ {
asdl_seq_LEN(patterns) == 1 ? asdl_seq_GET(patterns, 0) : _PyAST_MatchOr(patterns, EXTRA) }
+
closed_pattern[pattern_ty]:
| literal_pattern
| capture_pattern
@@ -308,9 +515,11 @@ wildcard_pattern[pattern_ty]:
value_pattern[pattern_ty]:
| attr=attr !('.' | '(' | '=') { _PyAST_MatchValue(attr, EXTRA) }
+
attr[expr_ty]:
| value=name_or_attr '.' attr=NAME {
_PyAST_Attribute(value, attr->v.Name.id, Load, EXTRA) }
+
name_or_attr[expr_ty]:
| attr
| NAME
@@ -321,14 +530,18 @@ group_pattern[pattern_ty]:
sequence_pattern[pattern_ty]:
| '[' patterns=maybe_sequence_pattern? ']' { _PyAST_MatchSequence(patterns, EXTRA) }
| '(' patterns=open_sequence_pattern? ')' { _PyAST_MatchSequence(patterns, EXTRA) }
+
open_sequence_pattern[asdl_seq*]:
| pattern=maybe_star_pattern ',' patterns=maybe_sequence_pattern? {
_PyPegen_seq_insert_in_front(p, pattern, patterns) }
+
maybe_sequence_pattern[asdl_seq*]:
| patterns=','.maybe_star_pattern+ ','? { patterns }
+
maybe_star_pattern[pattern_ty]:
| star_pattern
| pattern
+
star_pattern[pattern_ty]:
| '*' target=pattern_capture_target {
_PyAST_MatchStar(target->v.Name.id, EXTRA) }
@@ -352,11 +565,14 @@ mapping_pattern[pattern_ty]:
CHECK(asdl_pattern_seq*, _PyPegen_get_patterns(p, items)),
NULL,
EXTRA) }
+
items_pattern[asdl_seq*]:
| ','.key_value_pattern+
+
key_value_pattern[KeyPatternPair*]:
| key=(literal_expr | attr) ':' pattern=pattern {
_PyPegen_key_pattern_pair(p, key, pattern) }
+
double_star_pattern[expr_ty]:
| '**' target=pattern_capture_target { target }
@@ -381,137 +597,51 @@ class_pattern[pattern_ty]:
CHECK(asdl_pattern_seq*, _PyPegen_get_patterns(p, keywords)),
EXTRA) }
| invalid_class_pattern
+
positional_patterns[asdl_pattern_seq*]:
| args[asdl_pattern_seq*]=','.pattern+ { args }
+
keyword_patterns[asdl_seq*]:
| ','.keyword_pattern+
+
keyword_pattern[KeyPatternPair*]:
| arg=NAME '=' value=pattern { _PyPegen_key_pattern_pair(p, arg, value) }
-return_stmt[stmt_ty]:
- | 'return' a=[star_expressions] { _PyAST_Return(a, EXTRA) }
-
-raise_stmt[stmt_ty]:
- | 'raise' a=expression b=['from' z=expression { z }] { _PyAST_Raise(a, b, EXTRA) }
- | 'raise' { _PyAST_Raise(NULL, NULL, EXTRA) }
-
-function_def[stmt_ty]:
- | d=decorators f=function_def_raw { _PyPegen_function_def_decorators(p, d, f) }
- | function_def_raw
-
-function_def_raw[stmt_ty]:
- | invalid_def_raw
- | 'def' n=NAME '(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
- _PyAST_FunctionDef(n->v.Name.id,
- (params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)),
- b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA) }
- | ASYNC 'def' n=NAME '(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
- CHECK_VERSION(
- stmt_ty,
- 5,
- "Async functions are",
- _PyAST_AsyncFunctionDef(n->v.Name.id,
- (params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)),
- b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA)
- ) }
-func_type_comment[Token*]:
- | NEWLINE t=TYPE_COMMENT &(NEWLINE INDENT) { t } # Must be followed by indented block
- | invalid_double_type_comments
- | TYPE_COMMENT
-
-params[arguments_ty]:
- | invalid_parameters
- | parameters
+# EXPRESSIONS
+# -----------
-parameters[arguments_ty]:
- | a=slash_no_default b[asdl_arg_seq*]=param_no_default* c=param_with_default* d=[star_etc] {
- _PyPegen_make_arguments(p, a, NULL, b, c, d) }
- | a=slash_with_default b=param_with_default* c=[star_etc] {
- _PyPegen_make_arguments(p, NULL, a, NULL, b, c) }
- | a[asdl_arg_seq*]=param_no_default+ b=param_with_default* c=[star_etc] {
- _PyPegen_make_arguments(p, NULL, NULL, a, b, c) }
- | a=param_with_default+ b=[star_etc] { _PyPegen_make_arguments(p, NULL, NULL, NULL, a, b)}
- | a=star_etc { _PyPegen_make_arguments(p, NULL, NULL, NULL, NULL, a) }
-
-# Some duplication here because we can't write (',' | &')'),
-# which is because we don't support empty alternatives (yet).
-#
-slash_no_default[asdl_arg_seq*]:
- | a[asdl_arg_seq*]=param_no_default+ '/' ',' { a }
- | a[asdl_arg_seq*]=param_no_default+ '/' &')' { a }
-slash_with_default[SlashWithDefault*]:
- | a=param_no_default* b=param_with_default+ '/' ',' { _PyPegen_slash_with_default(p, (asdl_arg_seq *)a, b) }
- | a=param_no_default* b=param_with_default+ '/' &')' { _PyPegen_slash_with_default(p, (asdl_arg_seq *)a, b) }
-
-star_etc[StarEtc*]:
- | '*' a=param_no_default b=param_maybe_default* c=[kwds] {
- _PyPegen_star_etc(p, a, b, c) }
- | '*' ',' b=param_maybe_default+ c=[kwds] {
- _PyPegen_star_etc(p, NULL, b, c) }
- | a=kwds { _PyPegen_star_etc(p, NULL, NULL, a) }
- | invalid_star_etc
-
-kwds[arg_ty]: '**' a=param_no_default { a }
-
-# One parameter. This *includes* a following comma and type comment.
-#
-# There are three styles:
-# - No default
-# - With default
-# - Maybe with default
-#
-# There are two alternative forms of each, to deal with type comments:
-# - Ends in a comma followed by an optional type comment
-# - No comma, optional type comment, must be followed by close paren
-# The latter form is for a final parameter without trailing comma.
-#
-param_no_default[arg_ty]:
- | a=param ',' tc=TYPE_COMMENT? { _PyPegen_add_type_comment_to_arg(p, a, tc) }
- | a=param tc=TYPE_COMMENT? &')' { _PyPegen_add_type_comment_to_arg(p, a, tc) }
-param_with_default[NameDefaultPair*]:
- | a=param c=default ',' tc=TYPE_COMMENT? { _PyPegen_name_default_pair(p, a, c, tc) }
- | a=param c=default tc=TYPE_COMMENT? &')' { _PyPegen_name_default_pair(p, a, c, tc) }
-param_maybe_default[NameDefaultPair*]:
- | a=param c=default? ',' tc=TYPE_COMMENT? { _PyPegen_name_default_pair(p, a, c, tc) }
- | a=param c=default? tc=TYPE_COMMENT? &')' { _PyPegen_name_default_pair(p, a, c, tc) }
-param[arg_ty]: a=NAME b=annotation? { _PyAST_arg(a->v.Name.id, b, NULL, EXTRA) }
-
-annotation[expr_ty]: ':' a=expression { a }
-default[expr_ty]: '=' a=expression { a }
-
-decorators[asdl_expr_seq*]: a[asdl_expr_seq*]=('@' f=named_expression NEWLINE { f })+ { a }
+expressions[expr_ty]:
+ | a=expression b=(',' c=expression { c })+ [','] {
+ _PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)), Load, EXTRA) }
+ | a=expression ',' { _PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_singleton_seq(p, a)), Load, EXTRA) }
+ | expression
-class_def[stmt_ty]:
- | a=decorators b=class_def_raw { _PyPegen_class_def_decorators(p, a, b) }
- | class_def_raw
-class_def_raw[stmt_ty]:
- | invalid_class_def_raw
- | 'class' a=NAME b=['(' z=[arguments] ')' { z }] &&':' c=block {
- _PyAST_ClassDef(a->v.Name.id,
- (b) ? ((expr_ty) b)->v.Call.args : NULL,
- (b) ? ((expr_ty) b)->v.Call.keywords : NULL,
- c, NULL, EXTRA) }
+expression[expr_ty] (memo):
+ | invalid_expression
+ | a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
+ | disjunction
+ | lambdef
-block[asdl_stmt_seq*] (memo):
- | NEWLINE INDENT a=statements DEDENT { a }
- | simple_stmts
- | invalid_block
+yield_expr[expr_ty]:
+ | 'yield' 'from' a=expression { _PyAST_YieldFrom(a, EXTRA) }
+ | 'yield' a=[star_expressions] { _PyAST_Yield(a, EXTRA) }
star_expressions[expr_ty]:
| a=star_expression b=(',' c=star_expression { c })+ [','] {
_PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)), Load, EXTRA) }
| a=star_expression ',' { _PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_singleton_seq(p, a)), Load, EXTRA) }
| star_expression
+
star_expression[expr_ty] (memo):
| '*' a=bitwise_or { _PyAST_Starred(a, Load, EXTRA) }
| expression
star_named_expressions[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_named_expression+ [','] { a }
+
star_named_expression[expr_ty]:
| '*' a=bitwise_or { _PyAST_Starred(a, Load, EXTRA) }
| named_expression
-
assigment_expression[expr_ty]:
| a=NAME ':=' ~ b=expression { _PyAST_NamedExpr(CHECK(expr_ty, _PyPegen_set_expr_context(p, a, Store)), b, EXTRA) }
@@ -520,84 +650,27 @@ named_expression[expr_ty]:
| invalid_named_expression
| expression !':='
-annotated_rhs[expr_ty]: yield_expr | star_expressions
-
-expressions[expr_ty]:
- | a=expression b=(',' c=expression { c })+ [','] {
- _PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)), Load, EXTRA) }
- | a=expression ',' { _PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_singleton_seq(p, a)), Load, EXTRA) }
- | expression
-expression[expr_ty] (memo):
- | invalid_expression
- | a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
- | disjunction
- | lambdef
-
-lambdef[expr_ty]:
- | 'lambda' a=[lambda_params] ':' b=expression {
- _PyAST_Lambda((a) ? a : CHECK(arguments_ty, _PyPegen_empty_arguments(p)), b, EXTRA) }
-
-lambda_params[arguments_ty]:
- | invalid_lambda_parameters
- | lambda_parameters
-
-# lambda_parameters etc. duplicates parameters but without annotations
-# or type comments, and if there's no comma after a parameter, we expect
-# a colon, not a close parenthesis. (For more, see parameters above.)
-#
-lambda_parameters[arguments_ty]:
- | a=lambda_slash_no_default b[asdl_arg_seq*]=lambda_param_no_default* c=lambda_param_with_default* d=[lambda_star_etc] {
- _PyPegen_make_arguments(p, a, NULL, b, c, d) }
- | a=lambda_slash_with_default b=lambda_param_with_default* c=[lambda_star_etc] {
- _PyPegen_make_arguments(p, NULL, a, NULL, b, c) }
- | a[asdl_arg_seq*]=lambda_param_no_default+ b=lambda_param_with_default* c=[lambda_star_etc] {
- _PyPegen_make_arguments(p, NULL, NULL, a, b, c) }
- | a=lambda_param_with_default+ b=[lambda_star_etc] { _PyPegen_make_arguments(p, NULL, NULL, NULL, a, b)}
- | a=lambda_star_etc { _PyPegen_make_arguments(p, NULL, NULL, NULL, NULL, a) }
-
-lambda_slash_no_default[asdl_arg_seq*]:
- | a[asdl_arg_seq*]=lambda_param_no_default+ '/' ',' { a }
- | a[asdl_arg_seq*]=lambda_param_no_default+ '/' &':' { a }
-lambda_slash_with_default[SlashWithDefault*]:
- | a=lambda_param_no_default* b=lambda_param_with_default+ '/' ',' { _PyPegen_slash_with_default(p, (asdl_arg_seq *)a, b) }
- | a=lambda_param_no_default* b=lambda_param_with_default+ '/' &':' { _PyPegen_slash_with_default(p, (asdl_arg_seq *)a, b) }
-
-lambda_star_etc[StarEtc*]:
- | '*' a=lambda_param_no_default b=lambda_param_maybe_default* c=[lambda_kwds] {
- _PyPegen_star_etc(p, a, b, c) }
- | '*' ',' b=lambda_param_maybe_default+ c=[lambda_kwds] {
- _PyPegen_star_etc(p, NULL, b, c) }
- | a=lambda_kwds { _PyPegen_star_etc(p, NULL, NULL, a) }
- | invalid_lambda_star_etc
-
-lambda_kwds[arg_ty]: '**' a=lambda_param_no_default { a }
-
-lambda_param_no_default[arg_ty]:
- | a=lambda_param ',' { a }
- | a=lambda_param &':' { a }
-lambda_param_with_default[NameDefaultPair*]:
- | a=lambda_param c=default ',' { _PyPegen_name_default_pair(p, a, c, NULL) }
- | a=lambda_param c=default &':' { _PyPegen_name_default_pair(p, a, c, NULL) }
-lambda_param_maybe_default[NameDefaultPair*]:
- | a=lambda_param c=default? ',' { _PyPegen_name_default_pair(p, a, c, NULL) }
- | a=lambda_param c=default? &':' { _PyPegen_name_default_pair(p, a, c, NULL) }
-lambda_param[arg_ty]: a=NAME { _PyAST_arg(a->v.Name.id, NULL, NULL, EXTRA) }
-
disjunction[expr_ty] (memo):
| a=conjunction b=('or' c=conjunction { c })+ { _PyAST_BoolOp(
Or,
CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)),
EXTRA) }
| conjunction
+
conjunction[expr_ty] (memo):
| a=inversion b=('and' c=inversion { c })+ { _PyAST_BoolOp(
And,
CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)),
EXTRA) }
| inversion
+
inversion[expr_ty] (memo):
| 'not' a=inversion { _PyAST_UnaryOp(Not, a, EXTRA) }
| comparison
+
+# Comparisons operators
+# ---------------------
+
comparison[expr_ty]:
| a=bitwise_or b=compare_op_bitwise_or_pair+ {
_PyAST_Compare(
@@ -606,6 +679,7 @@ comparison[expr_ty]:
CHECK(asdl_expr_seq*, _PyPegen_get_exprs(p, b)),
EXTRA) }
| bitwise_or
+
compare_op_bitwise_or_pair[CmpopExprPair*]:
| eq_bitwise_or
| noteq_bitwise_or
@@ -617,6 +691,7 @@ compare_op_bitwise_or_pair[CmpopExprPair*]:
| in_bitwise_or
| isnot_bitwise_or
| is_bitwise_or
+
eq_bitwise_or[CmpopExprPair*]: '==' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, Eq, a) }
noteq_bitwise_or[CmpopExprPair*]:
| (tok='!=' { _PyPegen_check_barry_as_flufl(p, tok) ? NULL : tok}) a=bitwise_or {_PyPegen_cmpop_expr_pair(p, NotEq, a) }
@@ -629,24 +704,34 @@ in_bitwise_or[CmpopExprPair*]: 'in' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, I
isnot_bitwise_or[CmpopExprPair*]: 'is' 'not' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, IsNot, a) }
is_bitwise_or[CmpopExprPair*]: 'is' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, Is, a) }
+# Logical operators
+# -----------------
+
bitwise_or[expr_ty]:
| a=bitwise_or '|' b=bitwise_xor { _PyAST_BinOp(a, BitOr, b, EXTRA) }
| bitwise_xor
+
bitwise_xor[expr_ty]:
| a=bitwise_xor '^' b=bitwise_and { _PyAST_BinOp(a, BitXor, b, EXTRA) }
| bitwise_and
+
bitwise_and[expr_ty]:
| a=bitwise_and '&' b=shift_expr { _PyAST_BinOp(a, BitAnd, b, EXTRA) }
| shift_expr
+
shift_expr[expr_ty]:
| a=shift_expr '<<' b=sum { _PyAST_BinOp(a, LShift, b, EXTRA) }
| a=shift_expr '>>' b=sum { _PyAST_BinOp(a, RShift, b, EXTRA) }
| sum
+# Arithmetic operators
+# --------------------
+
sum[expr_ty]:
| a=sum '+' b=term { _PyAST_BinOp(a, Add, b, EXTRA) }
| a=sum '-' b=term { _PyAST_BinOp(a, Sub, b, EXTRA) }
| term
+
term[expr_ty]:
| a=term '*' b=factor { _PyAST_BinOp(a, Mult, b, EXTRA) }
| a=term '/' b=factor { _PyAST_BinOp(a, Div, b, EXTRA) }
@@ -654,17 +739,26 @@ term[expr_ty]:
| a=term '%' b=factor { _PyAST_BinOp(a, Mod, b, EXTRA) }
| a=term '@' b=factor { CHECK_VERSION(expr_ty, 5, "The '@' operator is", _PyAST_BinOp(a, MatMult, b, EXTRA)) }
| factor
+
factor[expr_ty] (memo):
| '+' a=factor { _PyAST_UnaryOp(UAdd, a, EXTRA) }
| '-' a=factor { _PyAST_UnaryOp(USub, a, EXTRA) }
| '~' a=factor { _PyAST_UnaryOp(Invert, a, EXTRA) }
| power
+
power[expr_ty]:
| a=await_primary '**' b=factor { _PyAST_BinOp(a, Pow, b, EXTRA) }
| await_primary
+
+# Primary elements
+# ----------------
+
+# Primary elements are things like "obj.something.something", "obj[something]", "obj(something)", "obj" ...
+
await_primary[expr_ty] (memo):
| AWAIT a=primary { CHECK_VERSION(expr_ty, 5, "Await expressions are", _PyAST_Await(a, EXTRA)) }
| primary
+
primary[expr_ty]:
| a=primary '.' b=NAME { _PyAST_Attribute(a, b->v.Name.id, Load, EXTRA) }
| a=primary b=genexp { _PyAST_Call(a, CHECK(asdl_expr_seq*, (asdl_expr_seq*)_PyPegen_singleton_seq(p, b)), NULL, EXTRA) }
@@ -679,9 +773,11 @@ primary[expr_ty]:
slices[expr_ty]:
| a=slice !',' { a }
| a[asdl_expr_seq*]=','.slice+ [','] { _PyAST_Tuple(a, Load, EXTRA) }
+
slice[expr_ty]:
| a=[expression] ':' b=[expression] c=[':' d=[expression] { d }] { _PyAST_Slice(a, b, c, EXTRA) }
| a=named_expression { a }
+
atom[expr_ty]:
| NAME
| 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) }
@@ -694,25 +790,81 @@ atom[expr_ty]:
| &'{' (dict | set | dictcomp | setcomp)
| '...' { _PyAST_Constant(Py_Ellipsis, NULL, EXTRA) }
+group[expr_ty]:
+ | '(' a=(yield_expr | named_expression) ')' { a }
+ | invalid_group
+
+# Lambda functions
+# ----------------
+
+lambdef[expr_ty]:
+ | 'lambda' a=[lambda_params] ':' b=expression {
+ _PyAST_Lambda((a) ? a : CHECK(arguments_ty, _PyPegen_empty_arguments(p)), b, EXTRA) }
+
+lambda_params[arguments_ty]:
+ | invalid_lambda_parameters
+ | lambda_parameters
+
+# lambda_parameters etc. duplicates parameters but without annotations
+# or type comments, and if there's no comma after a parameter, we expect
+# a colon, not a close parenthesis. (For more, see parameters above.)
+#
+lambda_parameters[arguments_ty]:
+ | a=lambda_slash_no_default b[asdl_arg_seq*]=lambda_param_no_default* c=lambda_param_with_default* d=[lambda_star_etc] {
+ _PyPegen_make_arguments(p, a, NULL, b, c, d) }
+ | a=lambda_slash_with_default b=lambda_param_with_default* c=[lambda_star_etc] {
+ _PyPegen_make_arguments(p, NULL, a, NULL, b, c) }
+ | a[asdl_arg_seq*]=lambda_param_no_default+ b=lambda_param_with_default* c=[lambda_star_etc] {
+ _PyPegen_make_arguments(p, NULL, NULL, a, b, c) }
+ | a=lambda_param_with_default+ b=[lambda_star_etc] { _PyPegen_make_arguments(p, NULL, NULL, NULL, a, b)}
+ | a=lambda_star_etc { _PyPegen_make_arguments(p, NULL, NULL, NULL, NULL, a) }
+
+lambda_slash_no_default[asdl_arg_seq*]:
+ | a[asdl_arg_seq*]=lambda_param_no_default+ '/' ',' { a }
+ | a[asdl_arg_seq*]=lambda_param_no_default+ '/' &':' { a }
+
+lambda_slash_with_default[SlashWithDefault*]:
+ | a=lambda_param_no_default* b=lambda_param_with_default+ '/' ',' { _PyPegen_slash_with_default(p, (asdl_arg_seq *)a, b) }
+ | a=lambda_param_no_default* b=lambda_param_with_default+ '/' &':' { _PyPegen_slash_with_default(p, (asdl_arg_seq *)a, b) }
+
+lambda_star_etc[StarEtc*]:
+ | '*' a=lambda_param_no_default b=lambda_param_maybe_default* c=[lambda_kwds] {
+ _PyPegen_star_etc(p, a, b, c) }
+ | '*' ',' b=lambda_param_maybe_default+ c=[lambda_kwds] {
+ _PyPegen_star_etc(p, NULL, b, c) }
+ | a=lambda_kwds { _PyPegen_star_etc(p, NULL, NULL, a) }
+ | invalid_lambda_star_etc
+
+lambda_kwds[arg_ty]: '**' a=lambda_param_no_default { a }
+
+lambda_param_no_default[arg_ty]:
+ | a=lambda_param ',' { a }
+ | a=lambda_param &':' { a }
+lambda_param_with_default[NameDefaultPair*]:
+ | a=lambda_param c=default ',' { _PyPegen_name_default_pair(p, a, c, NULL) }
+ | a=lambda_param c=default &':' { _PyPegen_name_default_pair(p, a, c, NULL) }
+lambda_param_maybe_default[NameDefaultPair*]:
+ | a=lambda_param c=default? ',' { _PyPegen_name_default_pair(p, a, c, NULL) }
+ | a=lambda_param c=default? &':' { _PyPegen_name_default_pair(p, a, c, NULL) }
+lambda_param[arg_ty]: a=NAME { _PyAST_arg(a->v.Name.id, NULL, NULL, EXTRA) }
+
+# LITERALS
+# ========
+
strings[expr_ty] (memo): a=STRING+ { _PyPegen_concatenate_strings(p, a) }
+
list[expr_ty]:
| '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) }
-listcomp[expr_ty]:
- | '[' a=named_expression b=for_if_clauses ']' { _PyAST_ListComp(a, b, EXTRA) }
- | invalid_comprehension
+
tuple[expr_ty]:
| '(' a=[y=star_named_expression ',' z=[star_named_expressions] { _PyPegen_seq_insert_in_front(p, y, z) } ] ')' {
_PyAST_Tuple(a, Load, EXTRA) }
-group[expr_ty]:
- | '(' a=(yield_expr | named_expression) ')' { a }
- | invalid_group
-genexp[expr_ty]:
- | '(' a=( assigment_expression | expression !':=') b=for_if_clauses ')' { _PyAST_GeneratorExp(a, b, EXTRA) }
- | invalid_comprehension
+
set[expr_ty]: '{' a=star_named_expressions '}' { _PyAST_Set(a, EXTRA) }
-setcomp[expr_ty]:
- | '{' a=named_expression b=for_if_clauses '}' { _PyAST_SetComp(a, b, EXTRA) }
- | invalid_comprehension
+
+# Dicts
+# -----
+
dict[expr_ty]:
| '{' a=[double_starred_kvpairs] '}' {
_PyAST_Dict(
@@ -721,16 +873,20 @@ dict[expr_ty]:
EXTRA) }
| '{' invalid_double_starred_kvpairs '}'
-dictcomp[expr_ty]:
- | '{' a=kvpair b=for_if_clauses '}' { _PyAST_DictComp(a->key, a->value, b, EXTRA) }
- | invalid_dict_comprehension
double_starred_kvpairs[asdl_seq*]: a=','.double_starred_kvpair+ [','] { a }
+
double_starred_kvpair[KeyValuePair*]:
| '**' a=bitwise_or { _PyPegen_key_value_pair(p, NULL, a) }
| kvpair
+
kvpair[KeyValuePair*]: a=expression ':' b=expression { _PyPegen_key_value_pair(p, a, b) }
+
+# Comprehensions & Generators
+# ---------------------------
+
for_if_clauses[asdl_comprehension_seq*]:
| a[asdl_comprehension_seq*]=for_if_clause+ { a }
+
for_if_clause[comprehension_ty]:
| ASYNC 'for' a=star_targets 'in' ~ b=disjunction c[asdl_expr_seq*]=('if' z=disjunction { z })* {
CHECK_VERSION(comprehension_ty, 6, "Async comprehensions are", _PyAST_comprehension(a, b, c, 1, p->arena)) }
@@ -738,13 +894,29 @@ for_if_clause[comprehension_ty]:
_PyAST_comprehension(a, b, c, 0, p->arena) }
| invalid_for_target
-yield_expr[expr_ty]:
- | 'yield' 'from' a=expression { _PyAST_YieldFrom(a, EXTRA) }
- | 'yield' a=[star_expressions] { _PyAST_Yield(a, EXTRA) }
+listcomp[expr_ty]:
+ | '[' a=named_expression b=for_if_clauses ']' { _PyAST_ListComp(a, b, EXTRA) }
+ | invalid_comprehension
+
+setcomp[expr_ty]:
+ | '{' a=named_expression b=for_if_clauses '}' { _PyAST_SetComp(a, b, EXTRA) }
+ | invalid_comprehension
+
+genexp[expr_ty]:
+ | '(' a=( assigment_expression | expression !':=') b=for_if_clauses ')' { _PyAST_GeneratorExp(a, b, EXTRA) }
+ | invalid_comprehension
+
+dictcomp[expr_ty]:
+ | '{' a=kvpair b=for_if_clauses '}' { _PyAST_DictComp(a->key, a->value, b, EXTRA) }
+ | invalid_dict_comprehension
+
+# FUNCTION CALL ARGUMENTS
+# =======================
arguments[expr_ty] (memo):
| a=args [','] &')' { a }
| invalid_arguments
+
args[expr_ty]:
| a[asdl_expr_seq*]=','.(starred_expression | ( assigment_expression | expression !':=') !'=')+ b=[',' k=kwargs {k}] {
_PyPegen_collect_call_seqs(p, a, b, EXTRA) }
@@ -757,36 +929,50 @@ kwargs[asdl_seq*]:
| a=','.kwarg_or_starred+ ',' b=','.kwarg_or_double_starred+ { _PyPegen_join_sequences(p, a, b) }
| ','.kwarg_or_starred+
| ','.kwarg_or_double_starred+
+
starred_expression[expr_ty]:
| '*' a=expression { _PyAST_Starred(a, Load, EXTRA) }
+
kwarg_or_starred[KeywordOrStarred*]:
| invalid_kwarg
| a=NAME '=' b=expression {
_PyPegen_keyword_or_starred(p, CHECK(keyword_ty, _PyAST_keyword(a->v.Name.id, b, EXTRA)), 1) }
| a=starred_expression { _PyPegen_keyword_or_starred(p, a, 0) }
+
kwarg_or_double_starred[KeywordOrStarred*]:
| invalid_kwarg
| a=NAME '=' b=expression {
_PyPegen_keyword_or_starred(p, CHECK(keyword_ty, _PyAST_keyword(a->v.Name.id, b, EXTRA)), 1) }
| '**' a=expression { _PyPegen_keyword_or_starred(p, CHECK(keyword_ty, _PyAST_keyword(NULL, a, EXTRA)), 1) }
+# ASSIGNMENT TARGETS
+# ==================
+
+# Generic targets
+# ---------------
+
# NOTE: star_targets may contain *bitwise_or, targets may not.
star_targets[expr_ty]:
| a=star_target !',' { a }
| a=star_target b=(',' c=star_target { c })* [','] {
_PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)), Store, EXTRA) }
+
star_targets_list_seq[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_target+ [','] { a }
+
star_targets_tuple_seq[asdl_expr_seq*]:
| a=star_target b=(',' c=star_target { c })+ [','] { (asdl_expr_seq*) _PyPegen_seq_insert_in_front(p, a, b) }
| a=star_target ',' { (asdl_expr_seq*) _PyPegen_singleton_seq(p, a) }
+
star_target[expr_ty] (memo):
| '*' a=(!'*' star_target) {
_PyAST_Starred(CHECK(expr_ty, _PyPegen_set_expr_context(p, a, Store)), Store, EXTRA) }
| target_with_star_atom
+
target_with_star_atom[expr_ty] (memo):
| a=t_primary '.' b=NAME !t_lookahead { _PyAST_Attribute(a, b->v.Name.id, Store, EXTRA) }
| a=t_primary '[' b=slices ']' !t_lookahead { _PyAST_Subscript(a, b, Store, EXTRA) }
| star_atom
+
star_atom[expr_ty]:
| a=NAME { _PyPegen_set_expr_context(p, a, Store) }
| '(' a=target_with_star_atom ')' { _PyPegen_set_expr_context(p, a, Store) }
@@ -797,21 +983,11 @@ single_target[expr_ty]:
| single_subscript_attribute_target
| a=NAME { _PyPegen_set_expr_context(p, a, Store) }
| '(' a=single_target ')' { a }
+
single_subscript_attribute_target[expr_ty]:
| a=t_primary '.' b=NAME !t_lookahead { _PyAST_Attribute(a, b->v.Name.id, Store, EXTRA) }
| a=t_primary '[' b=slices ']' !t_lookahead { _PyAST_Subscript(a, b, Store, EXTRA) }
-del_targets[asdl_expr_seq*]: a[asdl_expr_seq*]=','.del_target+ [','] { a }
-del_target[expr_ty] (memo):
- | a=t_primary '.' b=NAME !t_lookahead { _PyAST_Attribute(a, b->v.Name.id, Del, EXTRA) }
- | a=t_primary '[' b=slices ']' !t_lookahead { _PyAST_Subscript(a, b, Del, EXTRA) }
- | del_t_atom
-del_t_atom[expr_ty]:
- | a=NAME { _PyPegen_set_expr_context(p, a, Del) }
- | '(' a=del_target ')' { _PyPegen_set_expr_context(p, a, Del) }
- | '(' a=[del_targets] ')' { _PyAST_Tuple(a, Del, EXTRA) }
- | '[' a=[del_targets] ']' { _PyAST_List(a, Del, EXTRA) }
-
t_primary[expr_ty]:
| a=t_primary '.' b=NAME &t_lookahead { _PyAST_Attribute(a, b->v.Name.id, Load, EXTRA) }
| a=t_primary '[' b=slices ']' &t_lookahead { _PyAST_Subscript(a, b, Load, EXTRA) }
@@ -823,8 +999,57 @@ t_primary[expr_ty]:
(b) ? ((expr_ty) b)->v.Call.keywords : NULL,
EXTRA) }
| a=atom &t_lookahead { a }
+
t_lookahead: '(' | '[' | '.'
+# Targets for del statements
+# --------------------------
+
+del_targets[asdl_expr_seq*]: a[asdl_expr_seq*]=','.del_target+ [','] { a }
+
+del_target[expr_ty] (memo):
+ | a=t_primary '.' b=NAME !t_lookahead { _PyAST_Attribute(a, b->v.Name.id, Del, EXTRA) }
+ | a=t_primary '[' b=slices ']' !t_lookahead { _PyAST_Subscript(a, b, Del, EXTRA) }
+ | del_t_atom
+
+del_t_atom[expr_ty]:
+ | a=NAME { _PyPegen_set_expr_context(p, a, Del) }
+ | '(' a=del_target ')' { _PyPegen_set_expr_context(p, a, Del) }
+ | '(' a=[del_targets] ')' { _PyAST_Tuple(a, Del, EXTRA) }
+ | '[' a=[del_targets] ']' { _PyAST_List(a, Del, EXTRA) }
+
+# TYPING ELEMENTS
+# ---------------
+
+# type_expressions allow */** but ignore them
+type_expressions[asdl_expr_seq*]:
+ | a=','.expression+ ',' '*' b=expression ',' '**' c=expression {
+ (asdl_expr_seq*)_PyPegen_seq_append_to_end(
+ p,
+ CHECK(asdl_seq*, _PyPegen_seq_append_to_end(p, a, b)),
+ c) }
+ | a=','.expression+ ',' '*' b=expression { (asdl_expr_seq*)_PyPegen_seq_append_to_end(p, a, b) }
+ | a=','.expression+ ',' '**' b=expression { (asdl_expr_seq*)_PyPegen_seq_append_to_end(p, a, b) }
+ | '*' a=expression ',' '**' b=expression {
+ (asdl_expr_seq*)_PyPegen_seq_append_to_end(
+ p,
+ CHECK(asdl_seq*, _PyPegen_singleton_seq(p, a)),
+ b) }
+ | '*' a=expression { (asdl_expr_seq*)_PyPegen_singleton_seq(p, a) }
+ | '**' a=expression { (asdl_expr_seq*)_PyPegen_singleton_seq(p, a) }
+ | a[asdl_expr_seq*]=','.expression+ {a}
+
+func_type_comment[Token*]:
+ | NEWLINE t=TYPE_COMMENT &(NEWLINE INDENT) { t } # Must be followed by indented block
+ | invalid_double_type_comments
+ | TYPE_COMMENT
+
+# ========================= END OF THE GRAMMAR ===========================
+
+
+
+# ========================= START OF INVALID RULES =======================
+
# From here on, there are rules for invalid syntax with specialised error messages
invalid_arguments:
| a=args ',' '*' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "iterable argument unpacking follows keyword argument unpacking") }