2020-06-11 20:51:44 -03:00
# PEG grammar for Python
2020-04-22 19:29:27 -03:00
@trailer '''
void *
_PyPegen_parse(Parser *p)
{
// Initialize keywords
p->keywords = reserved_keywords;
p->n_keyword_lists = n_keyword_lists;
2021-04-15 17:38:45 -03:00
p->soft_keywords = soft_keywords;
2020-04-22 19:29:27 -03:00
// Run parser
void *result = NULL;
if (p->start_rule == Py_file_input) {
result = file_rule(p);
} else if (p->start_rule == Py_single_input) {
result = interactive_rule(p);
} else if (p->start_rule == Py_eval_input) {
result = eval_rule(p);
2020-04-30 16:12:19 -03:00
} else if (p->start_rule == Py_func_type_input) {
result = func_type_rule(p);
2020-04-22 19:29:27 -03:00
}
return result;
}
'''
2021-07-31 09:04:37 -03:00
# ========================= 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
# ==============
2020-04-30 16:12:19 -03:00
file[mod_ty]: a=[statements] ENDMARKER { _PyPegen_make_module(p, a) }
2021-04-07 16:34:22 -03:00
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) }
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
# GENERAL STATEMENTS
# ==================
2020-09-16 15:42:00 -03:00
statements[asdl_stmt_seq*]: a=statement+ { (asdl_stmt_seq*)_PyPegen_seq_flatten(p, a) }
2021-07-31 09:04:37 -03:00
2020-11-30 15:42:38 -04:00
statement[asdl_stmt_seq*]: a=compound_stmt { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a) } | a[asdl_stmt_seq*]=simple_stmts { a }
2021-07-31 09:04:37 -03:00
2020-09-16 15:42:00 -03:00
statement_newline[asdl_stmt_seq*]:
| a=compound_stmt NEWLINE { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a) }
2020-11-30 15:42:38 -04:00
| simple_stmts
2021-04-07 16:34:22 -03:00
| NEWLINE { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, CHECK(stmt_ty, _PyAST_Pass(EXTRA))) }
2020-04-22 19:29:27 -03:00
| ENDMARKER { _PyPegen_interactive_exit(p) }
2021-07-31 09:04:37 -03:00
2020-11-30 15:42:38 -04:00
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 }
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
# NOTE: assignment MUST precede expression, else parsing a simple assignment
# will throw a SyntaxError.
2020-11-30 15:42:38 -04:00
simple_stmt[stmt_ty] (memo):
2020-04-22 19:29:27 -03:00
| assignment
2023-05-16 00:36:23 -03:00
| &"type" type_alias
2021-04-07 16:34:22 -03:00
| e=star_expressions { _PyAST_Expr(e, EXTRA) }
2020-04-22 19:29:27 -03:00
| &'return' return_stmt
| &('import' | 'from') import_stmt
| &'raise' raise_stmt
2021-04-07 16:34:22 -03:00
| 'pass' { _PyAST_Pass(EXTRA) }
2020-04-22 19:29:27 -03:00
| &'del' del_stmt
| &'yield' yield_stmt
| &'assert' assert_stmt
2021-04-07 16:34:22 -03:00
| 'break' { _PyAST_Break(EXTRA) }
| 'continue' { _PyAST_Continue(EXTRA) }
2020-04-22 19:29:27 -03:00
| &'global' global_stmt
| &'nonlocal' nonlocal_stmt
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
compound_stmt[stmt_ty]:
2023-11-20 09:27:53 -04:00
| invalid_compound_stmt
2023-07-26 12:34:15 -03:00
| &('def' | '@' | 'async') function_def
2020-04-22 19:29:27 -03:00
| &'if' if_stmt
| &('class' | '@') class_def
2023-07-26 12:34:15 -03:00
| &('with' | 'async') with_stmt
| &('for' | 'async') for_stmt
2020-04-22 19:29:27 -03:00
| &'try' try_stmt
| &'while' while_stmt
2021-02-26 18:51:55 -04:00
| match_stmt
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
# SIMPLE STATEMENTS
# =================
2020-04-22 19:29:27 -03:00
# NOTE: annotated_rhs may start with 'yield'; yield_expr must start with 'yield'
2020-05-06 15:11:04 -03:00
assignment[stmt_ty]:
2020-04-22 19:29:27 -03:00
| a=NAME ':' b=expression c=['=' d=annotated_rhs { d }] {
2020-05-01 00:27:52 -03:00
CHECK_VERSION(
2020-10-21 16:53:14 -03:00
stmt_ty,
2020-05-01 00:27:52 -03:00
6,
"Variable annotation syntax is",
2021-04-07 16:34:22 -03:00
_PyAST_AnnAssign(CHECK(expr_ty, _PyPegen_set_expr_context(p, a, Store)), b, c, 1, EXTRA)
2020-05-01 00:27:52 -03:00
) }
2020-05-14 17:13:50 -03:00
| a=('(' b=single_target ')' { b }
| single_subscript_attribute_target) ':' b=expression c=['=' d=annotated_rhs { d }] {
2021-04-07 16:34:22 -03:00
CHECK_VERSION(stmt_ty, 6, "Variable annotations syntax is", _PyAST_AnnAssign(a, b, c, 0, EXTRA)) }
2020-09-16 15:42:00 -03:00
| a[asdl_expr_seq*]=(z=star_targets '=' { z })+ b=(yield_expr | star_expressions) !'=' tc=[TYPE_COMMENT] {
2021-04-07 16:34:22 -03:00
_PyAST_Assign(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }
2020-06-18 20:10:43 -03:00
| a=single_target b=augassign ~ c=(yield_expr | star_expressions) {
2021-04-07 16:34:22 -03:00
_PyAST_AugAssign(a, b->kind, c, EXTRA) }
2020-04-22 19:29:27 -03:00
| invalid_assignment
2021-07-31 09:04:37 -03:00
annotated_rhs[expr_ty]: yield_expr | star_expressions
2020-04-22 19:29:27 -03:00
augassign[AugOperator*]:
2020-05-01 00:27:52 -03:00
| '+=' { _PyPegen_augoperator(p, Add) }
| '-=' { _PyPegen_augoperator(p, Sub) }
| '*=' { _PyPegen_augoperator(p, Mult) }
2020-10-21 16:53:14 -03:00
| '@=' { CHECK_VERSION(AugOperator*, 5, "The '@' operator is", _PyPegen_augoperator(p, MatMult)) }
2020-05-01 00:27:52 -03:00
| '/=' { _PyPegen_augoperator(p, Div) }
| '%=' { _PyPegen_augoperator(p, Mod) }
| '&=' { _PyPegen_augoperator(p, BitAnd) }
| '|=' { _PyPegen_augoperator(p, BitOr) }
| '^=' { _PyPegen_augoperator(p, BitXor) }
| '<<=' { _PyPegen_augoperator(p, LShift) }
| '>>=' { _PyPegen_augoperator(p, RShift) }
| '**=' { _PyPegen_augoperator(p, Pow) }
| '//=' { _PyPegen_augoperator(p, FloorDiv) }
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
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) }
2020-09-16 15:42:00 -03:00
global_stmt[stmt_ty]: 'global' a[asdl_expr_seq*]=','.NAME+ {
2021-04-07 16:34:22 -03:00
_PyAST_Global(CHECK(asdl_identifier_seq*, _PyPegen_map_names_to_ids(p, a)), EXTRA) }
2021-07-31 09:04:37 -03:00
2020-09-16 15:42:00 -03:00
nonlocal_stmt[stmt_ty]: 'nonlocal' a[asdl_expr_seq*]=','.NAME+ {
2021-04-07 16:34:22 -03:00
_PyAST_Nonlocal(CHECK(asdl_identifier_seq*, _PyPegen_map_names_to_ids(p, a)), EXTRA) }
2020-04-22 19:29:27 -03:00
2020-06-18 20:10:43 -03:00
del_stmt[stmt_ty]:
2021-04-07 16:34:22 -03:00
| 'del' a=del_targets &(';' | NEWLINE) { _PyAST_Delete(a, EXTRA) }
2020-06-18 20:10:43 -03:00
| invalid_del_stmt
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
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) }
2023-04-19 13:18:16 -03:00
import_stmt[stmt_ty]:
2022-11-01 10:01:20 -03:00
| invalid_import
| import_name
| import_from
2021-07-31 09:04:37 -03:00
# Import statements
# -----------------
2021-04-07 16:34:22 -03:00
import_name[stmt_ty]: 'import' a=dotted_as_names { _PyAST_Import(a, EXTRA) }
2020-04-22 19:29:27 -03:00
# note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS
import_from[stmt_ty]:
| 'from' a=('.' | '...')* b=dotted_name 'import' c=import_from_targets {
2021-04-07 16:34:22 -03:00
_PyAST_ImportFrom(b->v.Name.id, c, _PyPegen_seq_count_dots(a), EXTRA) }
2020-04-22 19:29:27 -03:00
| 'from' a=('.' | '...')+ 'import' b=import_from_targets {
2021-04-07 16:34:22 -03:00
_PyAST_ImportFrom(NULL, b, _PyPegen_seq_count_dots(a), EXTRA) }
2020-09-16 15:42:00 -03:00
import_from_targets[asdl_alias_seq*]:
2020-04-22 19:29:27 -03:00
| '(' a=import_from_as_names [','] ')' { a }
2020-05-21 17:41:58 -03:00
| import_from_as_names !','
2021-04-10 17:56:28 -03:00
| '*' { (asdl_alias_seq*)_PyPegen_singleton_seq(p, CHECK(alias_ty, _PyPegen_alias_for_star(p, EXTRA))) }
2020-05-21 17:41:58 -03:00
| invalid_import_from_targets
2020-09-16 15:42:00 -03:00
import_from_as_names[asdl_alias_seq*]:
| a[asdl_alias_seq*]=','.import_from_as_name+ { a }
2020-04-22 19:29:27 -03:00
import_from_as_name[alias_ty]:
2021-04-07 16:34:22 -03:00
| a=NAME b=['as' z=NAME { z }] { _PyAST_alias(a->v.Name.id,
2020-04-22 19:29:27 -03:00
(b) ? ((expr_ty) b)->v.Name.id : NULL,
2021-04-10 17:56:28 -03:00
EXTRA) }
2020-09-16 15:42:00 -03:00
dotted_as_names[asdl_alias_seq*]:
| a[asdl_alias_seq*]=','.dotted_as_name+ { a }
2020-04-22 19:29:27 -03:00
dotted_as_name[alias_ty]:
2021-04-07 16:34:22 -03:00
| a=dotted_name b=['as' z=NAME { z }] { _PyAST_alias(a->v.Name.id,
2020-04-22 19:29:27 -03:00
(b) ? ((expr_ty) b)->v.Name.id : NULL,
2021-04-10 17:56:28 -03:00
EXTRA) }
2020-04-22 19:29:27 -03:00
dotted_name[expr_ty]:
| a=dotted_name '.' b=NAME { _PyPegen_join_names_with_dot(p, a, b) }
| NAME
2021-07-31 09:04:37 -03:00
# 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
2023-05-16 00:36:23 -03:00
| 'class' a=NAME t=[type_params] b=['(' z=[arguments] ')' { z }] ':' c=block {
2023-05-26 09:54:37 -03:00
_PyAST_ClassDef(a->v.Name.id,
2021-07-31 09:04:37 -03:00
(b) ? ((expr_ty) b)->v.Call.args : NULL,
(b) ? ((expr_ty) b)->v.Call.keywords : NULL,
2023-05-26 09:54:37 -03:00
c, NULL, t, EXTRA) }
2021-07-31 09:04:37 -03:00
# 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
2023-05-16 00:36:23 -03:00
| 'def' n=NAME t=[type_params] &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
2023-05-26 09:54:37 -03:00
_PyAST_FunctionDef(n->v.Name.id,
2021-07-31 09:04:37 -03:00
(params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)),
2023-05-26 09:54:37 -03:00
b, NULL, a, NEW_TYPE_COMMENT(p, tc), t, EXTRA) }
2023-07-26 12:34:15 -03:00
| 'async' 'def' n=NAME t=[type_params] &&'(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
2021-07-31 09:04:37 -03:00
CHECK_VERSION(
stmt_ty,
5,
"Async functions are",
2023-05-26 09:54:37 -03:00
_PyAST_AsyncFunctionDef(n->v.Name.id,
2021-07-31 09:04:37 -03:00
(params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)),
2023-05-26 09:54:37 -03:00
b, NULL, a, NEW_TYPE_COMMENT(p, tc), t, EXTRA)
2021-07-31 09:04:37 -03:00
) }
# 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] {
2022-08-12 14:27:50 -03:00
CHECK_VERSION(arguments_ty, 8, "Positional-only parameters are", _PyPegen_make_arguments(p, a, NULL, b, c, d)) }
2021-07-31 09:04:37 -03:00
| a=slash_with_default b=param_with_default* c=[star_etc] {
2022-08-12 14:27:50 -03:00
CHECK_VERSION(arguments_ty, 8, "Positional-only parameters are", _PyPegen_make_arguments(p, NULL, a, NULL, b, c)) }
2021-07-31 09:04:37 -03:00
| 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*]:
2022-03-22 08:38:41 -03:00
| invalid_star_etc
2021-07-31 09:04:37 -03:00
| '*' a=param_no_default b=param_maybe_default* c=[kwds] {
_PyPegen_star_etc(p, a, b, c) }
2022-03-26 13:55:35 -03:00
| '*' a=param_no_default_star_annotation b=param_maybe_default* c=[kwds] {
_PyPegen_star_etc(p, a, b, c) }
2021-07-31 09:04:37 -03:00
| '*' ',' b=param_maybe_default+ c=[kwds] {
_PyPegen_star_etc(p, NULL, b, c) }
| a=kwds { _PyPegen_star_etc(p, NULL, NULL, a) }
2022-03-22 08:38:41 -03:00
kwds[arg_ty]:
| invalid_kwds
| '**' a=param_no_default { a }
2021-07-31 09:04:37 -03:00
# 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) }
2022-03-26 13:55:35 -03:00
param_no_default_star_annotation[arg_ty]:
| a=param_star_annotation ',' tc=TYPE_COMMENT? { _PyPegen_add_type_comment_to_arg(p, a, tc) }
| a=param_star_annotation tc=TYPE_COMMENT? &')' { _PyPegen_add_type_comment_to_arg(p, a, tc) }
2021-07-31 09:04:37 -03:00
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) }
2022-03-26 13:55:35 -03:00
param_star_annotation[arg_ty]: a=NAME b=star_annotation { _PyAST_arg(a->v.Name.id, b, NULL, EXTRA) }
2021-07-31 09:04:37 -03:00
annotation[expr_ty]: ':' a=expression { a }
2022-03-26 13:55:35 -03:00
star_annotation[expr_ty]: ':' a=star_expression { a }
2022-03-22 08:38:41 -03:00
default[expr_ty]: '=' a=expression { a } | invalid_default
2021-07-31 09:04:37 -03:00
# If statement
# ------------
2020-04-22 19:29:27 -03:00
if_stmt[stmt_ty]:
2021-04-21 11:28:21 -03:00
| invalid_if_stmt
2021-04-12 12:59:30 -03:00
| 'if' a=named_expression ':' b=block c=elif_stmt {
2021-04-07 16:34:22 -03:00
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
2021-04-12 12:59:30 -03:00
| 'if' a=named_expression ':' b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
2020-04-22 19:29:27 -03:00
elif_stmt[stmt_ty]:
2021-04-21 11:28:21 -03:00
| invalid_elif_stmt
2021-04-12 12:59:30 -03:00
| 'elif' a=named_expression ':' b=block c=elif_stmt {
2021-04-07 16:34:22 -03:00
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
2021-04-12 12:59:30 -03:00
| 'elif' a=named_expression ':' b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
2021-04-21 11:28:21 -03:00
else_block[asdl_stmt_seq*]:
| invalid_else_stmt
| 'else' &&':' b=block { b }
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
# While statement
# ---------------
2020-04-22 19:29:27 -03:00
while_stmt[stmt_ty]:
2021-04-12 12:59:30 -03:00
| invalid_while_stmt
2021-04-21 11:28:21 -03:00
| 'while' a=named_expression ':' b=block c=[else_block] { _PyAST_While(a, b, c, EXTRA) }
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
# For statement
# -------------
2020-04-22 19:29:27 -03:00
for_stmt[stmt_ty]:
2021-04-21 11:28:21 -03:00
| invalid_for_stmt
2022-06-23 13:31:09 -03:00
| 'for' t=star_targets 'in' ~ ex=star_expressions ':' tc=[TYPE_COMMENT] b=block el=[else_block] {
2021-04-07 16:34:22 -03:00
_PyAST_For(t, ex, b, el, NEW_TYPE_COMMENT(p, tc), EXTRA) }
2023-07-26 12:34:15 -03:00
| 'async' 'for' t=star_targets 'in' ~ ex=star_expressions ':' tc=[TYPE_COMMENT] b=block el=[else_block] {
2021-04-07 16:34:22 -03:00
CHECK_VERSION(stmt_ty, 5, "Async for loops are", _PyAST_AsyncFor(t, ex, b, el, NEW_TYPE_COMMENT(p, tc), EXTRA)) }
2020-06-18 20:10:43 -03:00
| invalid_for_target
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
# With statement
# --------------
2020-04-22 19:29:27 -03:00
with_stmt[stmt_ty]:
2021-04-21 11:28:21 -03:00
| invalid_with_stmt_indent
2023-10-31 18:02:42 -03:00
| 'with' '(' a[asdl_withitem_seq*]=','.with_item+ ','? ')' ':' tc=[TYPE_COMMENT] b=block {
2024-02-26 05:22:09 -04:00
_PyAST_With(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }
2020-09-16 15:42:00 -03:00
| 'with' a[asdl_withitem_seq*]=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {
2021-04-07 16:34:22 -03:00
_PyAST_With(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }
2023-07-26 12:34:15 -03:00
| 'async' 'with' '(' a[asdl_withitem_seq*]=','.with_item+ ','? ')' ':' b=block {
2021-04-07 16:34:22 -03:00
CHECK_VERSION(stmt_ty, 5, "Async with statements are", _PyAST_AsyncWith(a, b, NULL, EXTRA)) }
2023-07-26 12:34:15 -03:00
| 'async' 'with' a[asdl_withitem_seq*]=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {
2021-04-07 16:34:22 -03:00
CHECK_VERSION(stmt_ty, 5, "Async with statements are", _PyAST_AsyncWith(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA)) }
2021-02-02 15:54:22 -04:00
| invalid_with_stmt
2020-04-22 19:29:27 -03:00
with_item[withitem_ty]:
2021-04-07 16:34:22 -03:00
| e=expression 'as' t=star_target &(',' | ')' | ':') { _PyAST_withitem(e, t, p->arena) }
2020-06-18 20:10:43 -03:00
| invalid_with_item
2021-04-07 16:34:22 -03:00
| e=expression { _PyAST_withitem(e, NULL, p->arena) }
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
# Try statement
# -------------
2020-04-22 19:29:27 -03:00
try_stmt[stmt_ty]:
2021-04-21 11:28:21 -03:00
| invalid_try_stmt
2021-04-07 16:34:22 -03:00
| '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) }
2023-04-19 13:18:16 -03:00
| 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_star_block+ el=[else_block] f=[finally_block] {
CHECK_VERSION(stmt_ty, 11, "Exception groups are",
2022-09-05 13:54:09 -03:00
_PyAST_TryStar(b, ex, el, f, EXTRA)) }
2021-12-14 12:48:15 -04:00
2021-07-31 09:04:37 -03:00
# Except statement
# ----------------
2020-04-22 19:29:27 -03:00
except_block[excepthandler_ty]:
2021-04-21 11:28:21 -03:00
| invalid_except_stmt_indent
2021-02-07 14:42:21 -04:00
| 'except' e=expression t=['as' z=NAME { z }] ':' b=block {
2021-04-07 16:34:22 -03:00
_PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
| 'except' ':' b=block { _PyAST_ExceptHandler(NULL, NULL, b, EXTRA) }
2021-04-21 11:28:21 -03:00
| invalid_except_stmt
2021-12-14 12:48:15 -04:00
except_star_block[excepthandler_ty]:
| invalid_except_star_stmt_indent
| 'except' '*' e=expression t=['as' z=NAME { z }] ':' b=block {
_PyAST_ExceptHandler(e, (t) ? ((expr_ty) t)->v.Name.id : NULL, b, EXTRA) }
| invalid_except_stmt
2021-04-21 11:28:21 -03:00
finally_block[asdl_stmt_seq*]:
| invalid_finally_stmt
| 'finally' &&':' a=block { a }
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
# Match statement
# ---------------
2021-02-26 18:51:55 -04:00
match_stmt[stmt_ty]:
| "match" subject=subject_expr ':' NEWLINE INDENT cases[asdl_match_case_seq*]=case_block+ DEDENT {
2021-04-07 16:34:22 -03:00
CHECK_VERSION(stmt_ty, 10, "Pattern matching is", _PyAST_Match(subject, cases, EXTRA)) }
2021-03-17 22:03:11 -03:00
| invalid_match_stmt
2021-07-31 09:04:37 -03:00
2021-02-26 18:51:55 -04:00
subject_expr[expr_ty]:
| value=star_named_expression ',' values=star_named_expressions? {
2021-04-07 16:34:22 -03:00
_PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, value, values)), Load, EXTRA) }
2021-02-26 18:51:55 -04:00
| named_expression
2021-07-31 09:04:37 -03:00
2021-02-26 18:51:55 -04:00
case_block[match_case_ty]:
2021-04-21 11:28:21 -03:00
| invalid_case_block
2021-02-26 18:51:55 -04:00
| "case" pattern=patterns guard=guard? ':' body=block {
2021-04-07 16:34:22 -03:00
_PyAST_match_case(pattern, guard, body, p->arena) }
2021-07-31 09:04:37 -03:00
2021-02-26 18:51:55 -04:00
guard[expr_ty]: 'if' guard=named_expression { guard }
2021-04-29 02:58:44 -03:00
patterns[pattern_ty]:
| patterns[asdl_pattern_seq*]=open_sequence_pattern {
_PyAST_MatchSequence(patterns, EXTRA) }
2021-02-26 18:51:55 -04:00
| pattern
2021-07-31 09:04:37 -03:00
2021-04-29 02:58:44 -03:00
pattern[pattern_ty]:
2021-02-26 18:51:55 -04:00
| as_pattern
| or_pattern
2021-07-31 09:04:37 -03:00
2021-04-29 02:58:44 -03:00
as_pattern[pattern_ty]:
| pattern=or_pattern 'as' target=pattern_capture_target {
2021-04-07 16:34:22 -03:00
_PyAST_MatchAs(pattern, target->v.Name.id, EXTRA) }
2021-06-10 19:50:32 -03:00
| invalid_as_pattern
2021-07-31 09:04:37 -03:00
2021-04-29 02:58:44 -03:00
or_pattern[pattern_ty]:
| patterns[asdl_pattern_seq*]='|'.closed_pattern+ {
2021-04-07 16:34:22 -03:00
asdl_seq_LEN(patterns) == 1 ? asdl_seq_GET(patterns, 0) : _PyAST_MatchOr(patterns, EXTRA) }
2021-07-31 09:04:37 -03:00
2022-06-10 12:56:45 -03:00
closed_pattern[pattern_ty] (memo):
2021-02-26 18:51:55 -04:00
| literal_pattern
| capture_pattern
| wildcard_pattern
| value_pattern
| group_pattern
| sequence_pattern
| mapping_pattern
| class_pattern
2021-04-29 02:58:44 -03:00
# Literal patterns are used for equality and identity constraints
literal_pattern[pattern_ty]:
| value=signed_number !('+' | '-') { _PyAST_MatchValue(value, EXTRA) }
| value=complex_number { _PyAST_MatchValue(value, EXTRA) }
| value=strings { _PyAST_MatchValue(value, EXTRA) }
| 'None' { _PyAST_MatchSingleton(Py_None, EXTRA) }
| 'True' { _PyAST_MatchSingleton(Py_True, EXTRA) }
| 'False' { _PyAST_MatchSingleton(Py_False, EXTRA) }
# Literal expressions are used to restrict permitted mapping pattern keys
literal_expr[expr_ty]:
2021-02-26 18:51:55 -04:00
| signed_number !('+' | '-')
2021-04-29 02:58:44 -03:00
| complex_number
2021-02-26 18:51:55 -04:00
| strings
2021-04-07 16:34:22 -03:00
| 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) }
| 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) }
| 'False' { _PyAST_Constant(Py_False, NULL, EXTRA) }
2021-04-29 02:58:44 -03:00
complex_number[expr_ty]:
2021-04-29 21:19:28 -03:00
| real=signed_real_number '+' imag=imaginary_number {
_PyAST_BinOp(real, Add, imag, EXTRA) }
| real=signed_real_number '-' imag=imaginary_number {
_PyAST_BinOp(real, Sub, imag, EXTRA) }
2021-04-29 02:58:44 -03:00
2021-02-26 18:51:55 -04:00
signed_number[expr_ty]:
| NUMBER
2021-04-07 16:34:22 -03:00
| '-' number=NUMBER { _PyAST_UnaryOp(USub, number, EXTRA) }
2021-02-26 18:51:55 -04:00
2021-04-29 21:19:28 -03:00
signed_real_number[expr_ty]:
| real_number
| '-' real=real_number { _PyAST_UnaryOp(USub, real, EXTRA) }
real_number[expr_ty]:
| real=NUMBER { _PyPegen_ensure_real(p, real) }
2021-04-29 02:58:44 -03:00
imaginary_number[expr_ty]:
| imag=NUMBER { _PyPegen_ensure_imaginary(p, imag) }
capture_pattern[pattern_ty]:
| target=pattern_capture_target { _PyAST_MatchAs(NULL, target->v.Name.id, EXTRA) }
pattern_capture_target[expr_ty]:
2021-02-26 18:51:55 -04:00
| !"_" name=NAME !('.' | '(' | '=') {
_PyPegen_set_expr_context(p, name, Store) }
2021-04-29 02:58:44 -03:00
wildcard_pattern[pattern_ty]:
| "_" { _PyAST_MatchAs(NULL, NULL, EXTRA) }
2021-02-26 18:51:55 -04:00
2021-04-29 02:58:44 -03:00
value_pattern[pattern_ty]:
| attr=attr !('.' | '(' | '=') { _PyAST_MatchValue(attr, EXTRA) }
2021-07-31 09:04:37 -03:00
2021-02-26 18:51:55 -04:00
attr[expr_ty]:
| value=name_or_attr '.' attr=NAME {
2021-04-07 16:34:22 -03:00
_PyAST_Attribute(value, attr->v.Name.id, Load, EXTRA) }
2021-07-31 09:04:37 -03:00
2021-02-26 18:51:55 -04:00
name_or_attr[expr_ty]:
| attr
| NAME
2021-04-29 02:58:44 -03:00
group_pattern[pattern_ty]:
2021-02-26 18:51:55 -04:00
| '(' pattern=pattern ')' { pattern }
2021-04-29 02:58:44 -03:00
sequence_pattern[pattern_ty]:
| '[' patterns=maybe_sequence_pattern? ']' { _PyAST_MatchSequence(patterns, EXTRA) }
| '(' patterns=open_sequence_pattern? ')' { _PyAST_MatchSequence(patterns, EXTRA) }
2021-07-31 09:04:37 -03:00
2021-02-26 18:51:55 -04:00
open_sequence_pattern[asdl_seq*]:
2021-04-29 02:58:44 -03:00
| pattern=maybe_star_pattern ',' patterns=maybe_sequence_pattern? {
_PyPegen_seq_insert_in_front(p, pattern, patterns) }
2021-07-31 09:04:37 -03:00
2021-02-26 18:51:55 -04:00
maybe_sequence_pattern[asdl_seq*]:
2021-04-29 02:58:44 -03:00
| patterns=','.maybe_star_pattern+ ','? { patterns }
2021-07-31 09:04:37 -03:00
2021-04-29 02:58:44 -03:00
maybe_star_pattern[pattern_ty]:
2021-02-26 18:51:55 -04:00
| star_pattern
| pattern
2021-07-31 09:04:37 -03:00
2022-06-10 12:56:45 -03:00
star_pattern[pattern_ty] (memo):
2021-04-29 02:58:44 -03:00
| '*' target=pattern_capture_target {
_PyAST_MatchStar(target->v.Name.id, EXTRA) }
| '*' wildcard_pattern {
_PyAST_MatchStar(NULL, EXTRA) }
mapping_pattern[pattern_ty]:
| '{' '}' {
_PyAST_MatchMapping(NULL, NULL, NULL, EXTRA) }
| '{' rest=double_star_pattern ','? '}' {
_PyAST_MatchMapping(NULL, NULL, rest->v.Name.id, EXTRA) }
| '{' items=items_pattern ',' rest=double_star_pattern ','? '}' {
_PyAST_MatchMapping(
CHECK(asdl_expr_seq*, _PyPegen_get_pattern_keys(p, items)),
CHECK(asdl_pattern_seq*, _PyPegen_get_patterns(p, items)),
rest->v.Name.id,
EXTRA) }
| '{' items=items_pattern ','? '}' {
_PyAST_MatchMapping(
CHECK(asdl_expr_seq*, _PyPegen_get_pattern_keys(p, items)),
CHECK(asdl_pattern_seq*, _PyPegen_get_patterns(p, items)),
NULL,
EXTRA) }
2021-07-31 09:04:37 -03:00
2021-02-26 18:51:55 -04:00
items_pattern[asdl_seq*]:
2021-04-29 21:19:28 -03:00
| ','.key_value_pattern+
2021-07-31 09:04:37 -03:00
2021-04-29 02:58:44 -03:00
key_value_pattern[KeyPatternPair*]:
| key=(literal_expr | attr) ':' pattern=pattern {
_PyPegen_key_pattern_pair(p, key, pattern) }
2021-07-31 09:04:37 -03:00
2021-04-29 02:58:44 -03:00
double_star_pattern[expr_ty]:
| '**' target=pattern_capture_target { target }
class_pattern[pattern_ty]:
| cls=name_or_attr '(' ')' {
_PyAST_MatchClass(cls, NULL, NULL, NULL, EXTRA) }
| cls=name_or_attr '(' patterns=positional_patterns ','? ')' {
_PyAST_MatchClass(cls, patterns, NULL, NULL, EXTRA) }
| cls=name_or_attr '(' keywords=keyword_patterns ','? ')' {
_PyAST_MatchClass(
cls, NULL,
CHECK(asdl_identifier_seq*, _PyPegen_map_names_to_ids(p,
CHECK(asdl_expr_seq*, _PyPegen_get_pattern_keys(p, keywords)))),
CHECK(asdl_pattern_seq*, _PyPegen_get_patterns(p, keywords)),
EXTRA) }
| cls=name_or_attr '(' patterns=positional_patterns ',' keywords=keyword_patterns ','? ')' {
_PyAST_MatchClass(
cls,
patterns,
CHECK(asdl_identifier_seq*, _PyPegen_map_names_to_ids(p,
CHECK(asdl_expr_seq*, _PyPegen_get_pattern_keys(p, keywords)))),
CHECK(asdl_pattern_seq*, _PyPegen_get_patterns(p, keywords)),
EXTRA) }
2021-06-24 12:09:57 -03:00
| invalid_class_pattern
2021-07-31 09:04:37 -03:00
2021-04-29 02:58:44 -03:00
positional_patterns[asdl_pattern_seq*]:
| args[asdl_pattern_seq*]=','.pattern+ { args }
2021-07-31 09:04:37 -03:00
2021-04-29 02:58:44 -03:00
keyword_patterns[asdl_seq*]:
2021-04-29 21:19:28 -03:00
| ','.keyword_pattern+
2021-07-31 09:04:37 -03:00
2021-04-29 02:58:44 -03:00
keyword_pattern[KeyPatternPair*]:
| arg=NAME '=' value=pattern { _PyPegen_key_pattern_pair(p, arg, value) }
2021-02-26 18:51:55 -04:00
2023-05-16 00:36:23 -03:00
# Type statement
# ---------------
type_alias[stmt_ty]:
| "type" n=NAME t=[type_params] '=' b=expression {
CHECK_VERSION(stmt_ty, 12, "Type statement is",
_PyAST_TypeAlias(CHECK(expr_ty, _PyPegen_set_expr_context(p, n, Store)), t, b, EXTRA)) }
# Type parameter declaration
# --------------------------
2023-05-22 01:25:09 -03:00
type_params[asdl_type_param_seq*]: '[' t=type_param_seq ']' {
CHECK_VERSION(asdl_type_param_seq *, 12, "Type parameter lists are", t) }
2023-05-16 00:36:23 -03:00
2023-05-22 01:25:09 -03:00
type_param_seq[asdl_type_param_seq*]: a[asdl_type_param_seq*]=','.type_param+ [','] { a }
2023-05-16 00:36:23 -03:00
2023-05-22 01:25:09 -03:00
type_param[type_param_ty] (memo):
2023-05-16 00:36:23 -03:00
| a=NAME b=[type_param_bound] { _PyAST_TypeVar(a->v.Name.id, b, EXTRA) }
2023-09-22 15:03:23 -03:00
| '*' a=NAME colon=':' e=expression {
2023-05-16 00:36:23 -03:00
RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind
? "cannot use constraints with TypeVarTuple"
: "cannot use bound with TypeVarTuple")
}
| '*' a=NAME { _PyAST_TypeVarTuple(a->v.Name.id, EXTRA) }
2023-09-22 15:03:23 -03:00
| '**' a=NAME colon=':' e=expression {
2023-05-16 00:36:23 -03:00
RAISE_SYNTAX_ERROR_STARTING_FROM(colon, e->kind == Tuple_kind
? "cannot use constraints with ParamSpec"
: "cannot use bound with ParamSpec")
}
| '**' a=NAME { _PyAST_ParamSpec(a->v.Name.id, EXTRA) }
2023-09-22 15:03:23 -03:00
type_param_bound[expr_ty]: ':' e=expression { e }
2023-05-16 00:36:23 -03:00
2021-07-31 09:04:37 -03:00
# EXPRESSIONS
# -----------
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
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
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
expression[expr_ty] (memo):
| invalid_expression
2021-11-19 19:11:57 -04:00
| invalid_legacy_expression
2021-07-31 09:04:37 -03:00
| a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
| disjunction
| lambdef
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
yield_expr[expr_ty]:
| 'yield' 'from' a=expression { _PyAST_YieldFrom(a, EXTRA) }
| 'yield' a=[star_expressions] { _PyAST_Yield(a, EXTRA) }
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
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
2020-04-30 16:12:19 -03:00
2021-07-31 09:04:37 -03:00
star_expression[expr_ty] (memo):
| '*' a=bitwise_or { _PyAST_Starred(a, Load, EXTRA) }
| expression
2020-04-30 16:12:19 -03:00
2021-07-31 09:04:37 -03:00
star_named_expressions[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_named_expression+ [','] { a }
2020-04-30 16:12:19 -03:00
2020-04-22 19:29:27 -03:00
star_named_expression[expr_ty]:
2021-04-07 16:34:22 -03:00
| '*' a=bitwise_or { _PyAST_Starred(a, Load, EXTRA) }
2020-04-22 19:29:27 -03:00
| named_expression
2021-04-12 12:59:30 -03:00
2021-11-03 17:57:40 -03:00
assignment_expression[expr_ty]:
2022-07-18 06:20:12 -03:00
| a=NAME ':=' ~ b=expression {
CHECK_VERSION(expr_ty, 8, "Assignment expressions are",
_PyAST_NamedExpr(CHECK(expr_ty, _PyPegen_set_expr_context(p, a, Store)), b, EXTRA)) }
2021-05-21 14:34:54 -03:00
named_expression[expr_ty]:
2021-11-03 17:57:40 -03:00
| assignment_expression
2021-05-21 14:34:54 -03:00
| invalid_named_expression
2021-04-12 22:32:33 -03:00
| expression !':='
2020-04-22 19:29:27 -03:00
disjunction[expr_ty] (memo):
2021-04-07 16:34:22 -03:00
| a=conjunction b=('or' c=conjunction { c })+ { _PyAST_BoolOp(
2020-04-22 19:29:27 -03:00
Or,
2020-10-21 16:53:14 -03:00
CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)),
2020-04-22 19:29:27 -03:00
EXTRA) }
| conjunction
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
conjunction[expr_ty] (memo):
2021-04-07 16:34:22 -03:00
| a=inversion b=('and' c=inversion { c })+ { _PyAST_BoolOp(
2020-04-22 19:29:27 -03:00
And,
2020-10-21 16:53:14 -03:00
CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)),
2020-04-22 19:29:27 -03:00
EXTRA) }
| inversion
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
inversion[expr_ty] (memo):
2021-04-07 16:34:22 -03:00
| 'not' a=inversion { _PyAST_UnaryOp(Not, a, EXTRA) }
2020-04-22 19:29:27 -03:00
| comparison
2021-07-31 09:04:37 -03:00
2022-01-09 12:22:54 -04:00
# Comparison operators
# --------------------
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
comparison[expr_ty]:
| a=bitwise_or b=compare_op_bitwise_or_pair+ {
2021-04-07 16:34:22 -03:00
_PyAST_Compare(
2020-10-21 16:53:14 -03:00
a,
CHECK(asdl_int_seq*, _PyPegen_get_cmpops(p, b)),
CHECK(asdl_expr_seq*, _PyPegen_get_exprs(p, b)),
EXTRA) }
2020-04-22 19:29:27 -03:00
| bitwise_or
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
compare_op_bitwise_or_pair[CmpopExprPair*]:
| eq_bitwise_or
| noteq_bitwise_or
| lte_bitwise_or
| lt_bitwise_or
| gte_bitwise_or
| gt_bitwise_or
| notin_bitwise_or
| in_bitwise_or
| isnot_bitwise_or
| is_bitwise_or
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
eq_bitwise_or[CmpopExprPair*]: '==' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, Eq, a) }
2020-04-27 14:02:07 -03:00
noteq_bitwise_or[CmpopExprPair*]:
2020-10-30 20:48:42 -03:00
| (tok='!=' { _PyPegen_check_barry_as_flufl(p, tok) ? NULL : tok}) a=bitwise_or {_PyPegen_cmpop_expr_pair(p, NotEq, a) }
2020-04-22 19:29:27 -03:00
lte_bitwise_or[CmpopExprPair*]: '<=' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, LtE, a) }
lt_bitwise_or[CmpopExprPair*]: '<' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, Lt, a) }
gte_bitwise_or[CmpopExprPair*]: '>=' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, GtE, a) }
gt_bitwise_or[CmpopExprPair*]: '>' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, Gt, a) }
notin_bitwise_or[CmpopExprPair*]: 'not' 'in' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, NotIn, a) }
in_bitwise_or[CmpopExprPair*]: 'in' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, In, a) }
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) }
2022-01-09 12:22:54 -04:00
# Bitwise operators
2021-07-31 09:04:37 -03:00
# -----------------
2020-04-22 19:29:27 -03:00
bitwise_or[expr_ty]:
2021-04-07 16:34:22 -03:00
| a=bitwise_or '|' b=bitwise_xor { _PyAST_BinOp(a, BitOr, b, EXTRA) }
2020-04-22 19:29:27 -03:00
| bitwise_xor
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
bitwise_xor[expr_ty]:
2021-04-07 16:34:22 -03:00
| a=bitwise_xor '^' b=bitwise_and { _PyAST_BinOp(a, BitXor, b, EXTRA) }
2020-04-22 19:29:27 -03:00
| bitwise_and
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
bitwise_and[expr_ty]:
2021-04-07 16:34:22 -03:00
| a=bitwise_and '&' b=shift_expr { _PyAST_BinOp(a, BitAnd, b, EXTRA) }
2020-04-22 19:29:27 -03:00
| shift_expr
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
shift_expr[expr_ty]:
2021-04-07 16:34:22 -03:00
| a=shift_expr '<<' b=sum { _PyAST_BinOp(a, LShift, b, EXTRA) }
| a=shift_expr '>>' b=sum { _PyAST_BinOp(a, RShift, b, EXTRA) }
2024-03-26 06:30:46 -03:00
| invalid_arithmetic
2020-04-22 19:29:27 -03:00
| sum
2021-07-31 09:04:37 -03:00
# Arithmetic operators
# --------------------
2020-04-22 19:29:27 -03:00
sum[expr_ty]:
2021-04-07 16:34:22 -03:00
| a=sum '+' b=term { _PyAST_BinOp(a, Add, b, EXTRA) }
| a=sum '-' b=term { _PyAST_BinOp(a, Sub, b, EXTRA) }
2020-04-22 19:29:27 -03:00
| term
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
term[expr_ty]:
2021-04-07 16:34:22 -03:00
| a=term '*' b=factor { _PyAST_BinOp(a, Mult, b, EXTRA) }
| a=term '/' b=factor { _PyAST_BinOp(a, Div, b, EXTRA) }
| a=term '//' b=factor { _PyAST_BinOp(a, FloorDiv, b, EXTRA) }
| 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)) }
2024-03-26 06:30:46 -03:00
| invalid_factor
2020-04-22 19:29:27 -03:00
| factor
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
factor[expr_ty] (memo):
2021-04-07 16:34:22 -03:00
| '+' a=factor { _PyAST_UnaryOp(UAdd, a, EXTRA) }
| '-' a=factor { _PyAST_UnaryOp(USub, a, EXTRA) }
| '~' a=factor { _PyAST_UnaryOp(Invert, a, EXTRA) }
2020-04-22 19:29:27 -03:00
| power
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
power[expr_ty]:
2021-04-07 16:34:22 -03:00
| a=await_primary '**' b=factor { _PyAST_BinOp(a, Pow, b, EXTRA) }
2020-04-22 19:29:27 -03:00
| await_primary
2021-07-31 09:04:37 -03:00
# Primary elements
# ----------------
# Primary elements are things like "obj.something.something", "obj[something]", "obj(something)", "obj" ...
2020-04-22 19:29:27 -03:00
await_primary[expr_ty] (memo):
2023-07-26 12:34:15 -03:00
| 'await' a=primary { CHECK_VERSION(expr_ty, 5, "Await expressions are", _PyAST_Await(a, EXTRA)) }
2020-04-22 19:29:27 -03:00
| primary
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
primary[expr_ty]:
2021-04-07 16:34:22 -03:00
| 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) }
2020-04-22 19:29:27 -03:00
| a=primary '(' b=[arguments] ')' {
2021-04-07 16:34:22 -03:00
_PyAST_Call(a,
2020-04-22 19:29:27 -03:00
(b) ? ((expr_ty) b)->v.Call.args : NULL,
(b) ? ((expr_ty) b)->v.Call.keywords : NULL,
EXTRA) }
2021-04-07 16:34:22 -03:00
| a=primary '[' b=slices ']' { _PyAST_Subscript(a, b, Load, EXTRA) }
2020-04-22 19:29:27 -03:00
| atom
slices[expr_ty]:
| a=slice !',' { a }
2022-03-26 13:55:35 -03:00
| a[asdl_expr_seq*]=','.(slice | starred_expression)+ [','] { _PyAST_Tuple(a, Load, EXTRA) }
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
slice[expr_ty]:
2021-04-07 16:34:22 -03:00
| a=[expression] ':' b=[expression] c=[':' d=[expression] { d }] { _PyAST_Slice(a, b, c, EXTRA) }
2020-11-16 19:09:35 -04:00
| a=named_expression { a }
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
atom[expr_ty]:
| NAME
2021-04-07 16:34:22 -03:00
| 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) }
| 'False' { _PyAST_Constant(Py_False, NULL, EXTRA) }
| 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) }
2023-04-19 13:18:16 -03:00
| &(STRING|FSTRING_START) strings
2020-04-22 19:29:27 -03:00
| NUMBER
| &'(' (tuple | group | genexp)
| &'[' (list | listcomp)
| &'{' (dict | set | dictcomp | setcomp)
2021-04-07 16:34:22 -03:00
| '...' { _PyAST_Constant(Py_Ellipsis, NULL, EXTRA) }
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
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] {
2022-08-12 15:41:02 -03:00
CHECK_VERSION(arguments_ty, 8, "Positional-only parameters are", _PyPegen_make_arguments(p, a, NULL, b, c, d)) }
2021-07-31 09:04:37 -03:00
| a=lambda_slash_with_default b=lambda_param_with_default* c=[lambda_star_etc] {
2022-08-12 15:41:02 -03:00
CHECK_VERSION(arguments_ty, 8, "Positional-only parameters are", _PyPegen_make_arguments(p, NULL, a, NULL, b, c)) }
2021-07-31 09:04:37 -03:00
| 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*]:
2022-03-22 08:38:41 -03:00
| invalid_lambda_star_etc
2021-07-31 09:04:37 -03:00
| '*' 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) }
2022-03-22 08:38:41 -03:00
lambda_kwds[arg_ty]:
| invalid_lambda_kwds
| '**' a=lambda_param_no_default { a }
2021-07-31 09:04:37 -03:00
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
# ========
2023-04-19 13:18:16 -03:00
fstring_middle[expr_ty]:
| fstring_replacement_field
| t=FSTRING_MIDDLE { _PyPegen_constant_from_token(p, t) }
fstring_replacement_field[expr_ty]:
2023-09-22 15:03:23 -03:00
| '{' a=(yield_expr | star_expressions) debug_expr='='? conversion=[fstring_conversion] format=[fstring_full_format_spec] rbrace='}' {
2023-04-26 22:33:31 -03:00
_PyPegen_formatted_value(p, a, debug_expr, conversion, format, rbrace, EXTRA) }
2023-04-19 13:18:16 -03:00
| invalid_replacement_field
2023-04-26 22:33:31 -03:00
fstring_conversion[ResultTokenWithMetadata*]:
2023-04-19 13:18:16 -03:00
| conv_token="!" conv=NAME { _PyPegen_check_fstring_conversion(p, conv_token, conv) }
2023-04-26 22:33:31 -03:00
fstring_full_format_spec[ResultTokenWithMetadata*]:
| colon=':' spec=fstring_format_spec* { _PyPegen_setup_full_format_spec(p, colon, (asdl_expr_seq *) spec, EXTRA) }
2023-04-19 13:18:16 -03:00
fstring_format_spec[expr_ty]:
2023-06-02 08:33:26 -03:00
| t=FSTRING_MIDDLE { _PyPegen_decoded_constant_from_token(p, t) }
2023-04-19 13:18:16 -03:00
| fstring_replacement_field
fstring[expr_ty]:
| a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) }
string[expr_ty]: s[Token*]=STRING { _PyPegen_constant_from_string(p, s) }
strings[expr_ty] (memo): a[asdl_expr_seq*]=(fstring|string)+ { _PyPegen_concatenate_strings(p, a, EXTRA) }
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
list[expr_ty]:
2021-04-07 16:34:22 -03:00
| '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) }
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
tuple[expr_ty]:
| '(' a=[y=star_named_expression ',' z=[star_named_expressions] { _PyPegen_seq_insert_in_front(p, y, z) } ] ')' {
2021-04-07 16:34:22 -03:00
_PyAST_Tuple(a, Load, EXTRA) }
2021-07-31 09:04:37 -03:00
2021-04-07 16:34:22 -03:00
set[expr_ty]: '{' a=star_named_expressions '}' { _PyAST_Set(a, EXTRA) }
2021-07-31 09:04:37 -03:00
# Dicts
# -----
2020-04-22 19:29:27 -03:00
dict[expr_ty]:
2020-05-21 19:39:56 -03:00
| '{' a=[double_starred_kvpairs] '}' {
2021-04-07 16:34:22 -03:00
_PyAST_Dict(
2020-10-21 16:53:14 -03:00
CHECK(asdl_expr_seq*, _PyPegen_get_keys(p, a)),
CHECK(asdl_expr_seq*, _PyPegen_get_values(p, a)),
EXTRA) }
2021-04-15 10:06:39 -03:00
| '{' invalid_double_starred_kvpairs '}'
2020-05-21 19:39:56 -03:00
double_starred_kvpairs[asdl_seq*]: a=','.double_starred_kvpair+ [','] { a }
2021-07-31 09:04:37 -03:00
2020-05-21 19:39:56 -03:00
double_starred_kvpair[KeyValuePair*]:
2020-04-22 19:29:27 -03:00
| '**' a=bitwise_or { _PyPegen_key_value_pair(p, NULL, a) }
2020-05-21 19:39:56 -03:00
| kvpair
2021-07-31 09:04:37 -03:00
2020-05-21 19:39:56 -03:00
kvpair[KeyValuePair*]: a=expression ':' b=expression { _PyPegen_key_value_pair(p, a, b) }
2021-07-31 09:04:37 -03:00
# Comprehensions & Generators
# ---------------------------
2020-09-16 15:42:00 -03:00
for_if_clauses[asdl_comprehension_seq*]:
| a[asdl_comprehension_seq*]=for_if_clause+ { a }
2021-07-31 09:04:37 -03:00
2020-05-01 00:27:52 -03:00
for_if_clause[comprehension_ty]:
2023-07-26 12:34:15 -03:00
| 'async' 'for' a=star_targets 'in' ~ b=disjunction c[asdl_expr_seq*]=('if' z=disjunction { z })* {
2021-04-07 16:34:22 -03:00
CHECK_VERSION(comprehension_ty, 6, "Async comprehensions are", _PyAST_comprehension(a, b, c, 1, p->arena)) }
2020-09-16 15:42:00 -03:00
| 'for' a=star_targets 'in' ~ b=disjunction c[asdl_expr_seq*]=('if' z=disjunction { z })* {
2021-04-07 16:34:22 -03:00
_PyAST_comprehension(a, b, c, 0, p->arena) }
2024-01-06 06:27:49 -04:00
| 'async'? 'for' (bitwise_or (',' bitwise_or)* [',']) !'in' {
RAISE_SYNTAX_ERROR("'in' expected after for-loop variables") }
2020-06-18 20:10:43 -03:00
| invalid_for_target
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
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]:
2021-11-03 17:57:40 -03:00
| '(' a=( assignment_expression | expression !':=') b=for_if_clauses ')' { _PyAST_GeneratorExp(a, b, EXTRA) }
2021-07-31 09:04:37 -03:00
| 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
# =======================
2020-04-22 19:29:27 -03:00
arguments[expr_ty] (memo):
| a=args [','] &')' { a }
2020-10-26 19:42:04 -03:00
| invalid_arguments
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
args[expr_ty]:
2021-11-03 17:57:40 -03:00
| a[asdl_expr_seq*]=','.(starred_expression | ( assignment_expression | expression !':=') !'=')+ b=[',' k=kwargs {k}] {
2021-05-21 14:34:54 -03:00
_PyPegen_collect_call_seqs(p, a, b, EXTRA) }
2021-04-07 16:34:22 -03:00
| a=kwargs { _PyAST_Call(_PyPegen_dummy_name(p),
2020-10-21 16:53:14 -03:00
CHECK_NULL_ALLOWED(asdl_expr_seq*, _PyPegen_seq_extract_starred_exprs(p, a)),
CHECK_NULL_ALLOWED(asdl_keyword_seq*, _PyPegen_seq_delete_starred_exprs(p, a)),
2020-04-22 19:29:27 -03:00
EXTRA) }
2021-05-21 14:34:54 -03:00
2020-04-22 19:29:27 -03:00
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+
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
starred_expression[expr_ty]:
2022-11-20 19:15:05 -04:00
| invalid_starred_expression
2021-04-07 16:34:22 -03:00
| '*' a=expression { _PyAST_Starred(a, Load, EXTRA) }
2024-04-02 07:42:58 -03:00
| '*' { RAISE_SYNTAX_ERROR("Invalid star expression") }
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
kwarg_or_starred[KeywordOrStarred*]:
2021-05-21 14:34:54 -03:00
| invalid_kwarg
2020-04-22 19:29:27 -03:00
| a=NAME '=' b=expression {
2021-04-07 16:34:22 -03:00
_PyPegen_keyword_or_starred(p, CHECK(keyword_ty, _PyAST_keyword(a->v.Name.id, b, EXTRA)), 1) }
2020-04-22 19:29:27 -03:00
| a=starred_expression { _PyPegen_keyword_or_starred(p, a, 0) }
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
kwarg_or_double_starred[KeywordOrStarred*]:
2021-05-21 14:34:54 -03:00
| invalid_kwarg
2020-04-22 19:29:27 -03:00
| a=NAME '=' b=expression {
2021-04-07 16:34:22 -03:00
_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) }
2020-04-22 19:29:27 -03:00
2021-07-31 09:04:37 -03:00
# ASSIGNMENT TARGETS
# ==================
# Generic targets
# ---------------
2020-04-22 19:29:27 -03:00
# 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 })* [','] {
2021-04-07 16:34:22 -03:00
_PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)), Store, EXTRA) }
2021-07-31 09:04:37 -03:00
2021-01-02 19:14:21 -04:00
star_targets_list_seq[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_target+ [','] { a }
2021-07-31 09:04:37 -03:00
2021-01-02 19:14:21 -04:00
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) }
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
star_target[expr_ty] (memo):
| '*' a=(!'*' star_target) {
2021-04-07 16:34:22 -03:00
_PyAST_Starred(CHECK(expr_ty, _PyPegen_set_expr_context(p, a, Store)), Store, EXTRA) }
2021-01-02 19:14:21 -04:00
| target_with_star_atom
2021-07-31 09:04:37 -03:00
2021-01-02 19:14:21 -04:00
target_with_star_atom[expr_ty] (memo):
2021-04-07 16:34:22 -03:00
| 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) }
2020-04-22 19:29:27 -03:00
| star_atom
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
star_atom[expr_ty]:
| a=NAME { _PyPegen_set_expr_context(p, a, Store) }
2021-01-02 19:14:21 -04:00
| '(' a=target_with_star_atom ')' { _PyPegen_set_expr_context(p, a, Store) }
2021-04-07 16:34:22 -03:00
| '(' a=[star_targets_tuple_seq] ')' { _PyAST_Tuple(a, Store, EXTRA) }
| '[' a=[star_targets_list_seq] ']' { _PyAST_List(a, Store, EXTRA) }
2020-04-22 19:29:27 -03:00
2020-05-14 17:13:50 -03:00
single_target[expr_ty]:
| single_subscript_attribute_target
2020-04-22 19:29:27 -03:00
| a=NAME { _PyPegen_set_expr_context(p, a, Store) }
2020-05-14 17:13:50 -03:00
| '(' a=single_target ')' { a }
2021-07-31 09:04:37 -03:00
2020-05-14 17:13:50 -03:00
single_subscript_attribute_target[expr_ty]:
2021-04-07 16:34:22 -03:00
| 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) }
2020-04-22 19:29:27 -03:00
t_primary[expr_ty]:
2021-04-07 16:34:22 -03:00
| 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) }
2020-10-21 16:53:14 -03:00
| a=t_primary b=genexp &t_lookahead {
2021-04-07 16:34:22 -03:00
_PyAST_Call(a, CHECK(asdl_expr_seq*, (asdl_expr_seq*)_PyPegen_singleton_seq(p, b)), NULL, EXTRA) }
2020-04-22 19:29:27 -03:00
| a=t_primary '(' b=[arguments] ')' &t_lookahead {
2021-04-07 16:34:22 -03:00
_PyAST_Call(a,
2020-04-22 19:29:27 -03:00
(b) ? ((expr_ty) b)->v.Call.args : NULL,
(b) ? ((expr_ty) b)->v.Call.keywords : NULL,
EXTRA) }
| a=atom &t_lookahead { a }
2021-07-31 09:04:37 -03:00
2020-04-22 19:29:27 -03:00
t_lookahead: '(' | '[' | '.'
2021-07-31 09:04:37 -03:00
# 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 =======================
2020-04-22 19:29:27 -03:00
# From here on, there are rules for invalid syntax with specialised error messages
2020-10-26 19:42:04 -03:00
invalid_arguments:
2024-04-02 07:42:58 -03:00
| ((','.(starred_expression | ( assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) a=',' ','.(starred_expression !'=')+ {
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "iterable argument unpacking follows keyword argument unpacking") }
bpo-43914: Highlight invalid ranges in SyntaxErrors (#25525)
To improve the user experience understanding what part of the error messages associated with SyntaxErrors is wrong, we can highlight the whole error range and not only place the caret at the first character. In this way:
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^
SyntaxError: Generator expression must be parenthesized
becomes
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized
2021-04-23 10:27:05 -03:00
| a=expression b=for_if_clauses ',' [args | expression for_if_clauses] {
2022-04-05 10:47:13 -03:00
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, _PyPegen_get_last_comprehension_item(PyPegen_last_item(b, comprehension_ty)), "Generator expression must be parenthesized") }
2021-05-21 14:34:54 -03:00
| a=NAME b='=' expression for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Maybe you meant '==' or ':=' instead of '='?")}
2022-11-20 19:15:05 -04:00
| (args ',')? a=NAME b='=' &(',' | ')') {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "expected argument value expression")}
2021-09-27 10:37:43 -03:00
| a=args b=for_if_clauses { _PyPegen_nonparen_genexp_in_call(p, a, b) }
bpo-43914: Highlight invalid ranges in SyntaxErrors (#25525)
To improve the user experience understanding what part of the error messages associated with SyntaxErrors is wrong, we can highlight the whole error range and not only place the caret at the first character. In this way:
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^
SyntaxError: Generator expression must be parenthesized
becomes
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized
2021-04-23 10:27:05 -03:00
| args ',' a=expression b=for_if_clauses {
2022-04-05 10:47:13 -03:00
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, _PyPegen_get_last_comprehension_item(PyPegen_last_item(b, comprehension_ty)), "Generator expression must be parenthesized") }
2020-04-22 19:29:27 -03:00
| a=args ',' args { _PyPegen_arguments_parsing_error(p, a) }
2020-05-07 07:44:06 -03:00
invalid_kwarg:
2021-11-05 10:54:55 -03:00
| a[Token*]=('True'|'False'|'None') b='=' {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot assign to %s", PyBytes_AS_STRING(a->bytes)) }
2021-05-21 14:34:54 -03:00
| a=NAME b='=' expression for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Maybe you meant '==' or ':=' instead of '='?")}
2021-05-19 15:03:04 -03:00
| !(NAME '=') a=expression b='=' {
bpo-43914: Highlight invalid ranges in SyntaxErrors (#25525)
To improve the user experience understanding what part of the error messages associated with SyntaxErrors is wrong, we can highlight the whole error range and not only place the caret at the first character. In this way:
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^
SyntaxError: Generator expression must be parenthesized
becomes
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized
2021-04-23 10:27:05 -03:00
RAISE_SYNTAX_ERROR_KNOWN_RANGE(
a, b, "expression cannot contain assignment, perhaps you meant \"==\"?") }
2022-11-20 19:15:05 -04:00
| a='**' expression '=' b=expression {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot assign to keyword argument unpacking") }
2021-04-15 17:38:45 -03:00
2022-02-10 09:12:14 -04:00
# IMPORTANT: Note that the "_without_invalid" suffix causes the rule to not call invalid rules under it
2021-05-21 14:34:54 -03:00
expression_without_invalid[expr_ty]:
| a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
| disjunction
| lambdef
2021-07-27 13:19:22 -03:00
invalid_legacy_expression:
2021-07-31 22:10:50 -03:00
| a=NAME !'(' b=star_expressions {
2021-07-27 17:30:32 -03:00
_PyPegen_check_legacy_stmt(p, a) ? RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b,
"Missing parentheses in call to '%U'. Did you mean %U(...)?", a->v.Name.id, a->v.Name.id) : NULL}
2021-04-15 17:38:45 -03:00
invalid_expression:
# !(NAME STRING) is not matched so we don't show this error with some invalid string prefixes like: kf"dsfsdf"
# Soft keywords need to also be ignored because they can be parsed as NAME NAME
2021-07-27 13:19:22 -03:00
| !(NAME STRING | SOFT_KEYWORD) a=disjunction b=expression_without_invalid {
2021-11-24 18:21:23 -04:00
_PyPegen_check_legacy_stmt(p, a) ? NULL : p->tokens[p->mark-1]->level == 0 ? NULL :
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Perhaps you forgot a comma?") }
2021-08-05 14:28:57 -03:00
| a=disjunction 'if' b=disjunction !('else'|':') { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "expected 'else' after 'if' expression") }
2023-09-08 14:00:23 -03:00
| a='lambda' [lambda_params] b=':' &FSTRING_MIDDLE {
2023-04-19 13:18:16 -03:00
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "f-string: lambda expressions are not allowed without parentheses") }
2021-04-15 17:38:45 -03:00
2022-02-10 09:12:14 -04:00
invalid_named_expression(memo):
2020-04-22 19:29:27 -03:00
| a=expression ':=' expression {
2020-05-13 16:36:27 -03:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
a, "cannot use assignment expressions with %s", _PyPegen_get_expr_name(a)) }
2021-05-21 14:34:54 -03:00
| a=NAME '=' b=bitwise_or !('='|':=') {
2022-02-10 09:12:14 -04:00
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Maybe you meant '==' or ':=' instead of '='?") }
| !(list|tuple|genexp|'True'|'None'|'False') a=bitwise_or b='=' bitwise_or !('='|':=') {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot assign to %s here. Maybe you meant '==' instead of '='?",
2021-04-12 12:59:30 -03:00
_PyPegen_get_expr_name(a)) }
2020-04-22 19:29:27 -03:00
invalid_assignment:
2020-06-27 15:33:08 -03:00
| a=invalid_ann_assign_target ':' expression {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
a,
"only single target (not %s) can be annotated",
_PyPegen_get_expr_name(a)
)}
2020-06-25 20:22:36 -03:00
| a=star_named_expression ',' star_named_expressions* ':' expression {
2020-05-13 16:36:27 -03:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "only single target (not tuple) can be annotated") }
2020-06-25 20:22:36 -03:00
| a=expression ':' expression {
2020-05-13 16:36:27 -03:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "illegal target for annotation") }
2020-06-07 22:57:00 -03:00
| (star_targets '=')* a=star_expressions '=' {
2020-06-20 23:18:01 -03:00
RAISE_SYNTAX_ERROR_INVALID_TARGET(STAR_TARGETS, a) }
2020-06-07 22:57:00 -03:00
| (star_targets '=')* a=yield_expr '=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "assignment to yield expression not possible") }
2020-05-14 22:04:52 -03:00
| a=star_expressions augassign (yield_expr | star_expressions) {
2021-02-26 18:51:55 -04:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
2020-06-25 20:22:36 -03:00
a,
2020-05-14 22:04:52 -03:00
"'%s' is an illegal expression for augmented assignment",
_PyPegen_get_expr_name(a)
)}
2020-06-27 15:33:08 -03:00
invalid_ann_assign_target[expr_ty]:
| list
| tuple
| '(' a=invalid_ann_assign_target ')' { a }
2020-06-18 20:10:43 -03:00
invalid_del_stmt:
| 'del' a=star_expressions {
2020-06-20 23:18:01 -03:00
RAISE_SYNTAX_ERROR_INVALID_TARGET(DEL_TARGETS, a) }
2020-04-22 19:29:27 -03:00
invalid_block:
| NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block") }
invalid_comprehension:
2020-05-13 16:36:27 -03:00
| ('[' | '(' | '{') a=starred_expression for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "iterable unpacking cannot be used in comprehension") }
bpo-43914: Highlight invalid ranges in SyntaxErrors (#25525)
To improve the user experience understanding what part of the error messages associated with SyntaxErrors is wrong, we can highlight the whole error range and not only place the caret at the first character. In this way:
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^
SyntaxError: Generator expression must be parenthesized
becomes
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized
2021-04-23 10:27:05 -03:00
| ('[' | '{') a=star_named_expression ',' b=star_named_expressions for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, PyPegen_last_item(b, expr_ty),
"did you forget parentheses around the comprehension target?") }
| ('[' | '{') a=star_named_expression b=',' for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "did you forget parentheses around the comprehension target?") }
2020-05-21 19:39:56 -03:00
invalid_dict_comprehension:
| '{' a='**' bitwise_or for_if_clauses '}' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "dict unpacking cannot be used in dict comprehension") }
2020-04-22 19:29:27 -03:00
invalid_parameters:
2022-03-22 08:38:41 -03:00
| a="/" ',' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "at least one argument must precede /") }
| (slash_no_default | slash_with_default) param_maybe_default* a='/' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "/ may appear only once") }
2022-09-17 14:09:28 -03:00
| slash_no_default? param_no_default* invalid_parameters_helper a=param_no_default {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "parameter without a default follows parameter with a default") }
| param_no_default* a='(' param_no_default+ ','? b=')' {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "Function parameters cannot be parenthesized") }
2022-03-22 08:38:41 -03:00
| (slash_no_default | slash_with_default)? param_maybe_default* '*' (',' | param_no_default) param_maybe_default* a='/' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "/ must be ahead of *") }
| param_maybe_default+ '/' a='*' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expected comma between / and *") }
invalid_default:
| a='=' &(')'|',') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expected default value expression") }
invalid_star_etc:
| a='*' (')' | ',' (')' | '**')) { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "named arguments must follow bare *") }
| '*' ',' TYPE_COMMENT { RAISE_SYNTAX_ERROR("bare * has associated type comment") }
| '*' param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-positional argument cannot have default value") }
| '*' (param_no_default | ',') param_maybe_default* a='*' (param_no_default | ',') {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "* argument may appear only once") }
invalid_kwds:
| '**' param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-keyword argument cannot have default value") }
| '**' param ',' a=param { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "arguments cannot follow var-keyword argument") }
| '**' param ',' a[Token*]=('*'|'**'|'/') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "arguments cannot follow var-keyword argument") }
2021-01-07 18:31:25 -04:00
invalid_parameters_helper: # This is only there to avoid type errors
| a=slash_with_default { _PyPegen_singleton_seq(p, a) }
| param_with_default+
2020-06-10 10:07:06 -03:00
invalid_lambda_parameters:
2022-03-22 08:38:41 -03:00
| a="/" ',' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "at least one argument must precede /") }
| (lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* a='/' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "/ may appear only once") }
2022-09-17 14:09:28 -03:00
| lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper a=lambda_param_no_default {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "parameter without a default follows parameter with a default") }
| lambda_param_no_default* a='(' ','.lambda_param+ ','? b=')' {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "Lambda expression parameters cannot be parenthesized") }
2022-03-22 08:38:41 -03:00
| (lambda_slash_no_default | lambda_slash_with_default)? lambda_param_maybe_default* '*' (',' | lambda_param_no_default) lambda_param_maybe_default* a='/' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "/ must be ahead of *") }
| lambda_param_maybe_default+ '/' a='*' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expected comma between / and *") }
2021-01-07 18:31:25 -04:00
invalid_lambda_parameters_helper:
| a=lambda_slash_with_default { _PyPegen_singleton_seq(p, a) }
| lambda_param_with_default+
2020-05-04 07:58:31 -03:00
invalid_lambda_star_etc:
| '*' (':' | ',' (':' | '**')) { RAISE_SYNTAX_ERROR("named arguments must follow bare *") }
2022-03-22 08:38:41 -03:00
| '*' lambda_param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-positional argument cannot have default value") }
| '*' (lambda_param_no_default | ',') lambda_param_maybe_default* a='*' (lambda_param_no_default | ',') {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "* argument may appear only once") }
invalid_lambda_kwds:
| '**' lambda_param a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "var-keyword argument cannot have default value") }
| '**' lambda_param ',' a=lambda_param { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "arguments cannot follow var-keyword argument") }
| '**' lambda_param ',' a[Token*]=('*'|'**'|'/') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "arguments cannot follow var-keyword argument") }
2020-04-30 16:12:19 -03:00
invalid_double_type_comments:
| TYPE_COMMENT NEWLINE TYPE_COMMENT NEWLINE INDENT {
RAISE_SYNTAX_ERROR("Cannot have two type comments on def") }
2020-06-18 20:10:43 -03:00
invalid_with_item:
2021-02-02 15:54:22 -04:00
| expression 'as' a=expression &(',' | ')' | ':') {
2020-06-20 23:18:01 -03:00
RAISE_SYNTAX_ERROR_INVALID_TARGET(STAR_TARGETS, a) }
2020-06-18 20:10:43 -03:00
invalid_for_target:
2023-07-26 12:34:15 -03:00
| 'async'? 'for' a=star_expressions {
2020-06-20 23:18:01 -03:00
RAISE_SYNTAX_ERROR_INVALID_TARGET(FOR_TARGETS, a) }
2020-06-18 20:10:43 -03:00
invalid_group:
| '(' a=starred_expression ')' {
2021-04-12 12:59:30 -03:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use starred expression here") }
2021-03-24 16:34:17 -03:00
| '(' a='**' expression ')' {
2021-04-12 12:59:30 -03:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use double starred expression here") }
2022-11-01 10:01:20 -03:00
invalid_import:
2023-06-22 12:56:40 -03:00
| a='import' ','.dotted_name+ 'from' dotted_name {
2022-11-01 10:01:20 -03:00
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "Did you mean to use 'from ... import ...' instead?") }
2023-04-19 13:18:16 -03:00
2020-05-21 17:41:58 -03:00
invalid_import_from_targets:
2021-08-18 17:09:21 -03:00
| import_from_as_names ',' NEWLINE {
2020-05-21 17:41:58 -03:00
RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") }
2021-02-02 15:54:22 -04:00
2023-11-20 09:27:53 -04:00
invalid_compound_stmt:
| a='elif' named_expression ':' { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "'elif' must match an if-statement here") }
| a='else' ':' { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "'else' must match a valid statement here") }
2021-02-02 15:54:22 -04:00
invalid_with_stmt:
2023-07-26 12:34:15 -03:00
| ['async'] 'with' ','.(expression ['as' star_target])+ NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
| ['async'] 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
2021-04-21 11:28:21 -03:00
invalid_with_stmt_indent:
2023-07-26 12:34:15 -03:00
| ['async'] a='with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT {
2021-04-21 11:28:21 -03:00
RAISE_INDENTATION_ERROR("expected an indented block after 'with' statement on line %d", a->lineno) }
2023-07-26 12:34:15 -03:00
| ['async'] a='with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT {
2021-04-21 11:28:21 -03:00
RAISE_INDENTATION_ERROR("expected an indented block after 'with' statement on line %d", a->lineno) }
invalid_try_stmt:
| a='try' ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'try' statement on line %d", a->lineno) }
2021-06-03 19:52:12 -03:00
| 'try' ':' block !('except' | 'finally') { RAISE_SYNTAX_ERROR("expected 'except' or 'finally' block") }
2022-11-20 13:11:02 -04:00
| 'try' ':' block* except_block+ a='except' b='*' expression ['as' NAME] ':' {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot have both 'except' and 'except*' on the same 'try'") }
| 'try' ':' block* except_star_block+ a='except' [expression ['as' NAME]] ':' {
2022-11-06 11:36:19 -04:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot have both 'except' and 'except*' on the same 'try'") }
2021-04-21 11:28:21 -03:00
invalid_except_stmt:
2021-12-14 12:48:15 -04:00
| 'except' '*'? a=expression ',' expressions ['as' NAME ] ':' {
2021-05-08 15:24:41 -03:00
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized") }
2021-12-14 12:48:15 -04:00
| a='except' '*'? expression ['as' NAME ] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
2021-04-21 11:28:21 -03:00
| a='except' NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
2021-12-14 12:48:15 -04:00
| a='except' '*' (NEWLINE | ':') { RAISE_SYNTAX_ERROR("expected one or more exception types") }
2021-04-21 11:28:21 -03:00
invalid_finally_stmt:
| a='finally' ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'finally' statement on line %d", a->lineno) }
invalid_except_stmt_indent:
2021-04-29 21:19:28 -03:00
| a='except' expression ['as' NAME ] ':' NEWLINE !INDENT {
2021-04-21 11:28:21 -03:00
RAISE_INDENTATION_ERROR("expected an indented block after 'except' statement on line %d", a->lineno) }
2022-04-05 10:47:13 -03:00
| a='except' ':' NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block after 'except' statement on line %d", a->lineno) }
2021-12-14 12:48:15 -04:00
invalid_except_star_stmt_indent:
| a='except' '*' expression ['as' NAME ] ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'except*' statement on line %d", a->lineno) }
2021-03-17 22:03:11 -03:00
invalid_match_stmt:
2022-06-23 13:31:09 -03:00
| "match" subject_expr NEWLINE { CHECK_VERSION(void*, 10, "Pattern matching is", RAISE_SYNTAX_ERROR("expected ':'") ) }
2021-04-29 21:19:28 -03:00
| a="match" subject=subject_expr ':' NEWLINE !INDENT {
2021-04-21 11:28:21 -03:00
RAISE_INDENTATION_ERROR("expected an indented block after 'match' statement on line %d", a->lineno) }
2021-03-17 22:03:11 -03:00
invalid_case_block:
2022-06-23 13:31:09 -03:00
| "case" patterns guard? NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
2021-04-21 11:28:21 -03:00
| a="case" patterns guard? ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'case' statement on line %d", a->lineno) }
2021-06-10 19:50:32 -03:00
invalid_as_pattern:
| or_pattern 'as' a="_" { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use '_' as a target") }
| or_pattern 'as' !NAME a=expression { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "invalid pattern target") }
2021-06-24 12:09:57 -03:00
invalid_class_pattern:
| name_or_attr '(' a=invalid_class_argument_pattern { RAISE_SYNTAX_ERROR_KNOWN_RANGE(
PyPegen_first_item(a, pattern_ty),
PyPegen_last_item(a, pattern_ty),
"positional patterns follow keyword patterns") }
invalid_class_argument_pattern[asdl_pattern_seq*]:
| [positional_patterns ','] keyword_patterns ',' a=positional_patterns { a }
2021-04-12 12:59:30 -03:00
invalid_if_stmt:
| 'if' named_expression NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
2021-04-21 11:28:21 -03:00
| a='if' a=named_expression ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'if' statement on line %d", a->lineno) }
2021-04-12 12:59:30 -03:00
invalid_elif_stmt:
| 'elif' named_expression NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
2021-04-21 11:28:21 -03:00
| a='elif' named_expression ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'elif' statement on line %d", a->lineno) }
invalid_else_stmt:
| a='else' ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'else' statement on line %d", a->lineno) }
2021-04-12 12:59:30 -03:00
invalid_while_stmt:
| 'while' named_expression NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
2021-04-21 11:28:21 -03:00
| a='while' named_expression ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'while' statement on line %d", a->lineno) }
invalid_for_stmt:
2023-07-26 12:34:15 -03:00
| ['async'] 'for' star_targets 'in' star_expressions NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
| ['async'] a='for' star_targets 'in' star_expressions ':' NEWLINE !INDENT {
2021-04-21 11:28:21 -03:00
RAISE_INDENTATION_ERROR("expected an indented block after 'for' statement on line %d", a->lineno) }
invalid_def_raw:
2023-10-17 09:45:13 -03:00
| ['async'] a='def' NAME [type_params] '(' [params] ')' ['->' expression] ':' NEWLINE !INDENT {
2021-04-21 11:28:21 -03:00
RAISE_INDENTATION_ERROR("expected an indented block after function definition on line %d", a->lineno) }
invalid_class_def_raw:
2023-10-17 09:45:13 -03:00
| 'class' NAME [type_params] ['(' [arguments] ')'] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
| a='class' NAME [type_params] ['(' [arguments] ')'] ':' NEWLINE !INDENT {
2021-04-21 11:28:21 -03:00
RAISE_INDENTATION_ERROR("expected an indented block after class definition on line %d", a->lineno) }
2021-04-15 10:06:39 -03:00
invalid_double_starred_kvpairs:
| ','.double_starred_kvpair+ ',' invalid_kvpair
bpo-43914: Highlight invalid ranges in SyntaxErrors (#25525)
To improve the user experience understanding what part of the error messages associated with SyntaxErrors is wrong, we can highlight the whole error range and not only place the caret at the first character. In this way:
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^
SyntaxError: Generator expression must be parenthesized
becomes
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized
2021-04-23 10:27:05 -03:00
| expression ':' a='*' bitwise_or { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "cannot use a starred expression in a dictionary value") }
2021-04-15 10:06:39 -03:00
| expression a=':' &('}'|',') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") }
invalid_kvpair:
2021-04-15 20:45:42 -03:00
| a=expression !(':') {
bpo-43914: Highlight invalid ranges in SyntaxErrors (#25525)
To improve the user experience understanding what part of the error messages associated with SyntaxErrors is wrong, we can highlight the whole error range and not only place the caret at the first character. In this way:
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^
SyntaxError: Generator expression must be parenthesized
becomes
>>> foo(x, z for z in range(10), t, w)
File "<stdin>", line 1
foo(x, z for z in range(10), t, w)
^^^^^^^^^^^^^^^^^^^^
SyntaxError: Generator expression must be parenthesized
2021-04-23 10:27:05 -03:00
RAISE_ERROR_KNOWN_LOCATION(p, PyExc_SyntaxError, a->lineno, a->end_col_offset - 1, a->end_lineno, -1, "':' expected after dictionary key") }
| expression ':' a='*' bitwise_or { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "cannot use a starred expression in a dictionary value") }
2022-06-26 15:42:47 -03:00
| expression a=':' &('}'|',') {RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") }
2022-11-20 19:15:05 -04:00
invalid_starred_expression:
| a='*' expression '=' b=expression { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot assign to iterable argument unpacking") }
2024-04-02 07:42:58 -03:00
2023-04-19 13:18:16 -03:00
invalid_replacement_field:
| '{' a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '='") }
| '{' a='!' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '!'") }
| '{' a=':' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before ':'") }
| '{' a='}' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '}'") }
| '{' !(yield_expr | star_expressions) { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting a valid expression after '{'")}
| '{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}') {
PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '=', or '!', or ':', or '}'") }
| '{' (yield_expr | star_expressions) '=' !('!' | ':' | '}') {
PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '!', or ':', or '}'") }
| '{' (yield_expr | star_expressions) '='? invalid_conversion_character
| '{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}') {
PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting ':' or '}'") }
| '{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}' {
PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '}', or format specs") }
| '{' (yield_expr | star_expressions) '='? ['!' NAME] !'}' {
PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '}'") }
invalid_conversion_character:
| '!' &(':' | '}') { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: missing conversion character") }
| '!' !NAME { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: invalid conversion character") }
2024-03-26 06:30:46 -03:00
invalid_arithmetic:
| sum ('+'|'-'|'*'|'/'|'%'|'//'|'@') a='not' b=inversion { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "'not' after an operator must be parenthesized") }
invalid_factor:
| ('+' | '-' | '~') a='not' b=factor { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "'not' after an operator must be parenthesized") }