2020-06-12 00:51:44 +01:00
# PEG grammar for Python
2020-04-22 23:29:27 +01:00
@trailer '''
void *
_PyPegen_parse(Parser *p)
{
// Initialize keywords
p->keywords = reserved_keywords;
p->n_keyword_lists = n_keyword_lists;
2021-04-15 21:38:45 +01:00
p->soft_keywords = soft_keywords;
2020-04-22 23:29:27 +01: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 12:12:19 -07:00
} else if (p->start_rule == Py_func_type_input) {
result = func_type_rule(p);
2020-04-22 23:29:27 +01:00
} else if (p->start_rule == Py_fstring_input) {
result = fstring_rule(p);
}
return result;
}
// The end
'''
2020-04-30 12:12:19 -07:00
file[mod_ty]: a=[statements] ENDMARKER { _PyPegen_make_module(p, a) }
2021-04-07 21:34:22 +02: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 23:29:27 +01:00
fstring[expr_ty]: star_expressions
2020-04-30 12:12:19 -07:00
# type_expressions allow */** but ignore them
2020-09-16 19:42:00 +01:00
type_expressions[asdl_expr_seq*]:
2020-04-30 12:12:19 -07:00
| a=','.expression+ ',' '*' b=expression ',' '**' c=expression {
2020-10-21 22:53:14 +03:00
(asdl_expr_seq*)_PyPegen_seq_append_to_end(
p,
CHECK(asdl_seq*, _PyPegen_seq_append_to_end(p, a, b)),
c) }
2020-09-16 19:42:00 +01:00
| 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) }
2020-05-03 22:08:14 -07:00
| '*' a=expression ',' '**' b=expression {
2020-10-21 22:53:14 +03:00
(asdl_expr_seq*)_PyPegen_seq_append_to_end(
p,
CHECK(asdl_seq*, _PyPegen_singleton_seq(p, a)),
b) }
2020-09-16 19:42:00 +01:00
| '*' 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}
statements[asdl_stmt_seq*]: a=statement+ { (asdl_stmt_seq*)_PyPegen_seq_flatten(p, a) }
2020-11-30 19:42:38 +00:00
statement[asdl_stmt_seq*]: a=compound_stmt { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a) } | a[asdl_stmt_seq*]=simple_stmts { a }
2020-09-16 19:42:00 +01:00
statement_newline[asdl_stmt_seq*]:
| a=compound_stmt NEWLINE { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, a) }
2020-11-30 19:42:38 +00:00
| simple_stmts
2021-04-07 21:34:22 +02:00
| NEWLINE { (asdl_stmt_seq*)_PyPegen_singleton_seq(p, CHECK(stmt_ty, _PyAST_Pass(EXTRA))) }
2020-04-22 23:29:27 +01:00
| ENDMARKER { _PyPegen_interactive_exit(p) }
2020-11-30 19:42:38 +00: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 }
2020-04-22 23:29:27 +01:00
# NOTE: assignment MUST precede expression, else parsing a simple assignment
# will throw a SyntaxError.
2020-11-30 19:42:38 +00:00
simple_stmt[stmt_ty] (memo):
2020-04-22 23:29:27 +01:00
| assignment
2021-04-07 21:34:22 +02:00
| e=star_expressions { _PyAST_Expr(e, EXTRA) }
2020-04-22 23:29:27 +01:00
| &'return' return_stmt
| &('import' | 'from') import_stmt
| &'raise' raise_stmt
2021-04-07 21:34:22 +02:00
| 'pass' { _PyAST_Pass(EXTRA) }
2020-04-22 23:29:27 +01:00
| &'del' del_stmt
| &'yield' yield_stmt
| &'assert' assert_stmt
2021-04-07 21:34:22 +02:00
| 'break' { _PyAST_Break(EXTRA) }
| 'continue' { _PyAST_Continue(EXTRA) }
2020-04-22 23:29:27 +01:00
| &'global' global_stmt
| &'nonlocal' nonlocal_stmt
compound_stmt[stmt_ty]:
| &('def' | '@' | ASYNC) function_def
| &'if' if_stmt
| &('class' | '@') class_def
| &('with' | ASYNC) with_stmt
| &('for' | ASYNC) for_stmt
| &'try' try_stmt
| &'while' while_stmt
2021-02-26 14:51:55 -08:00
| match_stmt
2020-04-22 23:29:27 +01:00
# NOTE: annotated_rhs may start with 'yield'; yield_expr must start with 'yield'
2020-05-06 21:11:04 +03:00
assignment[stmt_ty]:
2020-04-22 23:29:27 +01:00
| a=NAME ':' b=expression c=['=' d=annotated_rhs { d }] {
2020-05-01 06:27:52 +03:00
CHECK_VERSION(
2020-10-21 22:53:14 +03:00
stmt_ty,
2020-05-01 06:27:52 +03:00
6,
"Variable annotation syntax is",
2021-04-07 21:34:22 +02:00
_PyAST_AnnAssign(CHECK(expr_ty, _PyPegen_set_expr_context(p, a, Store)), b, c, 1, EXTRA)
2020-05-01 06:27:52 +03:00
) }
2020-05-14 23:13:50 +03:00
| a=('(' b=single_target ')' { b }
| single_subscript_attribute_target) ':' b=expression c=['=' d=annotated_rhs { d }] {
2021-04-07 21:34:22 +02:00
CHECK_VERSION(stmt_ty, 6, "Variable annotations syntax is", _PyAST_AnnAssign(a, b, c, 0, EXTRA)) }
2020-09-16 19:42:00 +01:00
| a[asdl_expr_seq*]=(z=star_targets '=' { z })+ b=(yield_expr | star_expressions) !'=' tc=[TYPE_COMMENT] {
2021-04-07 21:34:22 +02:00
_PyAST_Assign(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }
2020-06-19 02:10:43 +03:00
| a=single_target b=augassign ~ c=(yield_expr | star_expressions) {
2021-04-07 21:34:22 +02:00
_PyAST_AugAssign(a, b->kind, c, EXTRA) }
2020-04-22 23:29:27 +01:00
| invalid_assignment
augassign[AugOperator*]:
2020-05-01 06:27:52 +03:00
| '+=' { _PyPegen_augoperator(p, Add) }
| '-=' { _PyPegen_augoperator(p, Sub) }
| '*=' { _PyPegen_augoperator(p, Mult) }
2020-10-21 22:53:14 +03:00
| '@=' { CHECK_VERSION(AugOperator*, 5, "The '@' operator is", _PyPegen_augoperator(p, MatMult)) }
2020-05-01 06: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 23:29:27 +01:00
2020-09-16 19:42:00 +01:00
global_stmt[stmt_ty]: 'global' a[asdl_expr_seq*]=','.NAME+ {
2021-04-07 21:34:22 +02:00
_PyAST_Global(CHECK(asdl_identifier_seq*, _PyPegen_map_names_to_ids(p, a)), EXTRA) }
2020-09-16 19:42:00 +01:00
nonlocal_stmt[stmt_ty]: 'nonlocal' a[asdl_expr_seq*]=','.NAME+ {
2021-04-07 21:34:22 +02:00
_PyAST_Nonlocal(CHECK(asdl_identifier_seq*, _PyPegen_map_names_to_ids(p, a)), EXTRA) }
2020-04-22 23:29:27 +01:00
2021-04-07 21:34:22 +02:00
yield_stmt[stmt_ty]: y=yield_expr { _PyAST_Expr(y, EXTRA) }
2020-04-22 23:29:27 +01:00
2021-04-07 21:34:22 +02:00
assert_stmt[stmt_ty]: 'assert' a=expression b=[',' z=expression { z }] { _PyAST_Assert(a, b, EXTRA) }
2020-04-22 23:29:27 +01:00
2020-06-19 02:10:43 +03:00
del_stmt[stmt_ty]:
2021-04-07 21:34:22 +02:00
| 'del' a=del_targets &(';' | NEWLINE) { _PyAST_Delete(a, EXTRA) }
2020-06-19 02:10:43 +03:00
| invalid_del_stmt
2020-04-22 23:29:27 +01:00
import_stmt[stmt_ty]: import_name | import_from
2021-04-07 21:34:22 +02:00
import_name[stmt_ty]: 'import' a=dotted_as_names { _PyAST_Import(a, EXTRA) }
2020-04-22 23:29:27 +01: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 21:34:22 +02:00
_PyAST_ImportFrom(b->v.Name.id, c, _PyPegen_seq_count_dots(a), EXTRA) }
2020-04-22 23:29:27 +01:00
| 'from' a=('.' | '...')+ 'import' b=import_from_targets {
2021-04-07 21:34:22 +02:00
_PyAST_ImportFrom(NULL, b, _PyPegen_seq_count_dots(a), EXTRA) }
2020-09-16 19:42:00 +01:00
import_from_targets[asdl_alias_seq*]:
2020-04-22 23:29:27 +01:00
| '(' a=import_from_as_names [','] ')' { a }
2020-05-21 23:41:58 +03:00
| import_from_as_names !','
2021-04-10 16:56:28 -04:00
| '*' { (asdl_alias_seq*)_PyPegen_singleton_seq(p, CHECK(alias_ty, _PyPegen_alias_for_star(p, EXTRA))) }
2020-05-21 23:41:58 +03:00
| invalid_import_from_targets
2020-09-16 19:42:00 +01:00
import_from_as_names[asdl_alias_seq*]:
| a[asdl_alias_seq*]=','.import_from_as_name+ { a }
2020-04-22 23:29:27 +01:00
import_from_as_name[alias_ty]:
2021-04-07 21:34:22 +02:00
| a=NAME b=['as' z=NAME { z }] { _PyAST_alias(a->v.Name.id,
2020-04-22 23:29:27 +01:00
(b) ? ((expr_ty) b)->v.Name.id : NULL,
2021-04-10 16:56:28 -04:00
EXTRA) }
2020-09-16 19:42:00 +01:00
dotted_as_names[asdl_alias_seq*]:
| a[asdl_alias_seq*]=','.dotted_as_name+ { a }
2020-04-22 23:29:27 +01:00
dotted_as_name[alias_ty]:
2021-04-07 21:34:22 +02:00
| a=dotted_name b=['as' z=NAME { z }] { _PyAST_alias(a->v.Name.id,
2020-04-22 23:29:27 +01:00
(b) ? ((expr_ty) b)->v.Name.id : NULL,
2021-04-10 16:56:28 -04:00
EXTRA) }
2020-04-22 23:29:27 +01:00
dotted_name[expr_ty]:
| a=dotted_name '.' b=NAME { _PyPegen_join_names_with_dot(p, a, b) }
| NAME
if_stmt[stmt_ty]:
2021-04-21 15:28:21 +01:00
| invalid_if_stmt
2021-04-12 16:59:30 +01:00
| 'if' a=named_expression ':' b=block c=elif_stmt {
2021-04-07 21:34:22 +02:00
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
2021-04-12 16:59:30 +01:00
| 'if' a=named_expression ':' b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
2020-04-22 23:29:27 +01:00
elif_stmt[stmt_ty]:
2021-04-21 15:28:21 +01:00
| invalid_elif_stmt
2021-04-12 16:59:30 +01:00
| 'elif' a=named_expression ':' b=block c=elif_stmt {
2021-04-07 21:34:22 +02:00
_PyAST_If(a, b, CHECK(asdl_stmt_seq*, _PyPegen_singleton_seq(p, c)), EXTRA) }
2021-04-12 16:59:30 +01:00
| 'elif' a=named_expression ':' b=block c=[else_block] { _PyAST_If(a, b, c, EXTRA) }
2021-04-21 15:28:21 +01:00
else_block[asdl_stmt_seq*]:
| invalid_else_stmt
| 'else' &&':' b=block { b }
2020-04-22 23:29:27 +01:00
while_stmt[stmt_ty]:
2021-04-12 16:59:30 +01:00
| invalid_while_stmt
2021-04-21 15:28:21 +01:00
| 'while' a=named_expression ':' b=block c=[else_block] { _PyAST_While(a, b, c, EXTRA) }
2020-04-22 23:29:27 +01:00
for_stmt[stmt_ty]:
2021-04-21 15:28:21 +01:00
| invalid_for_stmt
2021-02-02 19:54:22 +00:00
| 'for' t=star_targets 'in' ~ ex=star_expressions &&':' tc=[TYPE_COMMENT] b=block el=[else_block] {
2021-04-07 21:34:22 +02:00
_PyAST_For(t, ex, b, el, NEW_TYPE_COMMENT(p, tc), EXTRA) }
2021-02-02 19:54:22 +00:00
| ASYNC 'for' t=star_targets 'in' ~ ex=star_expressions &&':' tc=[TYPE_COMMENT] b=block el=[else_block] {
2021-04-07 21:34:22 +02:00
CHECK_VERSION(stmt_ty, 5, "Async for loops are", _PyAST_AsyncFor(t, ex, b, el, NEW_TYPE_COMMENT(p, tc), EXTRA)) }
2020-06-19 02:10:43 +03:00
| invalid_for_target
2020-04-22 23:29:27 +01:00
with_stmt[stmt_ty]:
2021-04-21 15:28:21 +01:00
| invalid_with_stmt_indent
2020-09-16 19:42:00 +01:00
| 'with' '(' a[asdl_withitem_seq*]=','.with_item+ ','? ')' ':' b=block {
2021-04-07 21:34:22 +02:00
_PyAST_With(a, b, NULL, EXTRA) }
2020-09-16 19:42:00 +01:00
| 'with' a[asdl_withitem_seq*]=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {
2021-04-07 21:34:22 +02:00
_PyAST_With(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA) }
2020-09-16 19:42:00 +01:00
| ASYNC 'with' '(' a[asdl_withitem_seq*]=','.with_item+ ','? ')' ':' b=block {
2021-04-07 21:34:22 +02:00
CHECK_VERSION(stmt_ty, 5, "Async with statements are", _PyAST_AsyncWith(a, b, NULL, EXTRA)) }
2020-09-16 19:42:00 +01:00
| ASYNC 'with' a[asdl_withitem_seq*]=','.with_item+ ':' tc=[TYPE_COMMENT] b=block {
2021-04-07 21:34:22 +02:00
CHECK_VERSION(stmt_ty, 5, "Async with statements are", _PyAST_AsyncWith(a, b, NEW_TYPE_COMMENT(p, tc), EXTRA)) }
2021-02-02 19:54:22 +00:00
| invalid_with_stmt
2020-04-22 23:29:27 +01:00
with_item[withitem_ty]:
2021-04-07 21:34:22 +02:00
| e=expression 'as' t=star_target &(',' | ')' | ':') { _PyAST_withitem(e, t, p->arena) }
2020-06-19 02:10:43 +03:00
| invalid_with_item
2021-04-07 21:34:22 +02:00
| e=expression { _PyAST_withitem(e, NULL, p->arena) }
2020-04-22 23:29:27 +01:00
try_stmt[stmt_ty]:
2021-04-21 15:28:21 +01:00
| invalid_try_stmt
2021-04-07 21:34:22 +02: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) }
2020-04-22 23:29:27 +01:00
except_block[excepthandler_ty]:
2021-04-21 15:28:21 +01:00
| invalid_except_stmt_indent
2021-02-07 18:42:21 +00:00
| 'except' e=expression t=['as' z=NAME { z }] ':' b=block {
2021-04-07 21:34:22 +02: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 15:28:21 +01:00
| invalid_except_stmt
finally_block[asdl_stmt_seq*]:
| invalid_finally_stmt
| 'finally' &&':' a=block { a }
2020-04-22 23:29:27 +01:00
2021-02-26 14:51:55 -08:00
match_stmt[stmt_ty]:
| "match" subject=subject_expr ':' NEWLINE INDENT cases[asdl_match_case_seq*]=case_block+ DEDENT {
2021-04-07 21:34:22 +02:00
CHECK_VERSION(stmt_ty, 10, "Pattern matching is", _PyAST_Match(subject, cases, EXTRA)) }
2021-03-18 01:03:11 +00:00
| invalid_match_stmt
2021-02-26 14:51:55 -08:00
subject_expr[expr_ty]:
| value=star_named_expression ',' values=star_named_expressions? {
2021-04-07 21:34:22 +02:00
_PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, value, values)), Load, EXTRA) }
2021-02-26 14:51:55 -08:00
| named_expression
case_block[match_case_ty]:
2021-04-21 15:28:21 +01:00
| invalid_case_block
2021-02-26 14:51:55 -08:00
| "case" pattern=patterns guard=guard? ':' body=block {
2021-04-07 21:34:22 +02:00
_PyAST_match_case(pattern, guard, body, p->arena) }
2021-02-26 14:51:55 -08:00
guard[expr_ty]: 'if' guard=named_expression { guard }
2021-04-29 15:58:44 +10:00
patterns[pattern_ty]:
| patterns[asdl_pattern_seq*]=open_sequence_pattern {
_PyAST_MatchSequence(patterns, EXTRA) }
2021-02-26 14:51:55 -08:00
| pattern
2021-04-29 15:58:44 +10:00
pattern[pattern_ty]:
2021-02-26 14:51:55 -08:00
| as_pattern
| or_pattern
2021-04-29 15:58:44 +10:00
as_pattern[pattern_ty]:
| pattern=or_pattern 'as' target=pattern_capture_target {
2021-04-07 21:34:22 +02:00
_PyAST_MatchAs(pattern, target->v.Name.id, EXTRA) }
2021-06-18 22:15:57 +01:00
| invalid_as_pattern
2021-04-29 15:58:44 +10:00
or_pattern[pattern_ty]:
| patterns[asdl_pattern_seq*]='|'.closed_pattern+ {
2021-04-07 21:34:22 +02:00
asdl_seq_LEN(patterns) == 1 ? asdl_seq_GET(patterns, 0) : _PyAST_MatchOr(patterns, EXTRA) }
2021-04-29 15:58:44 +10:00
closed_pattern[pattern_ty]:
2021-02-26 14:51:55 -08:00
| literal_pattern
| capture_pattern
| wildcard_pattern
| value_pattern
| group_pattern
| sequence_pattern
| mapping_pattern
| class_pattern
2021-04-29 15:58:44 +10: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 14:51:55 -08:00
| signed_number !('+' | '-')
2021-04-29 15:58:44 +10:00
| complex_number
2021-02-26 14:51:55 -08:00
| strings
2021-04-07 21:34:22 +02: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 15:58:44 +10:00
complex_number[expr_ty]:
2021-04-29 17:19:28 -07: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 15:58:44 +10:00
2021-02-26 14:51:55 -08:00
signed_number[expr_ty]:
| NUMBER
2021-04-07 21:34:22 +02:00
| '-' number=NUMBER { _PyAST_UnaryOp(USub, number, EXTRA) }
2021-02-26 14:51:55 -08:00
2021-04-29 17:19:28 -07: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 15:58:44 +10: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 14:51:55 -08:00
| !"_" name=NAME !('.' | '(' | '=') {
_PyPegen_set_expr_context(p, name, Store) }
2021-04-29 15:58:44 +10:00
wildcard_pattern[pattern_ty]:
| "_" { _PyAST_MatchAs(NULL, NULL, EXTRA) }
2021-02-26 14:51:55 -08:00
2021-04-29 15:58:44 +10:00
value_pattern[pattern_ty]:
| attr=attr !('.' | '(' | '=') { _PyAST_MatchValue(attr, EXTRA) }
2021-02-26 14:51:55 -08:00
attr[expr_ty]:
| value=name_or_attr '.' attr=NAME {
2021-04-07 21:34:22 +02:00
_PyAST_Attribute(value, attr->v.Name.id, Load, EXTRA) }
2021-02-26 14:51:55 -08:00
name_or_attr[expr_ty]:
| attr
| NAME
2021-04-29 15:58:44 +10:00
group_pattern[pattern_ty]:
2021-02-26 14:51:55 -08:00
| '(' pattern=pattern ')' { pattern }
2021-04-29 15:58:44 +10:00
sequence_pattern[pattern_ty]:
| '[' patterns=maybe_sequence_pattern? ']' { _PyAST_MatchSequence(patterns, EXTRA) }
| '(' patterns=open_sequence_pattern? ')' { _PyAST_MatchSequence(patterns, EXTRA) }
2021-02-26 14:51:55 -08:00
open_sequence_pattern[asdl_seq*]:
2021-04-29 15:58:44 +10:00
| pattern=maybe_star_pattern ',' patterns=maybe_sequence_pattern? {
_PyPegen_seq_insert_in_front(p, pattern, patterns) }
2021-02-26 14:51:55 -08:00
maybe_sequence_pattern[asdl_seq*]:
2021-04-29 15:58:44 +10:00
| patterns=','.maybe_star_pattern+ ','? { patterns }
maybe_star_pattern[pattern_ty]:
2021-02-26 14:51:55 -08:00
| star_pattern
| pattern
2021-04-29 15:58:44 +10:00
star_pattern[pattern_ty]:
| '*' 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-02-26 14:51:55 -08:00
items_pattern[asdl_seq*]:
2021-04-29 17:19:28 -07:00
| ','.key_value_pattern+
2021-04-29 15:58:44 +10:00
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 }
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 08:34:28 -07:00
| invalid_class_pattern
2021-04-29 15:58:44 +10:00
positional_patterns[asdl_pattern_seq*]:
| args[asdl_pattern_seq*]=','.pattern+ { args }
keyword_patterns[asdl_seq*]:
2021-04-29 17:19:28 -07:00
| ','.keyword_pattern+
2021-04-29 15:58:44 +10:00
keyword_pattern[KeyPatternPair*]:
| arg=NAME '=' value=pattern { _PyPegen_key_pattern_pair(p, arg, value) }
2021-02-26 14:51:55 -08:00
2020-04-22 23:29:27 +01:00
return_stmt[stmt_ty]:
2021-04-07 21:34:22 +02:00
| 'return' a=[star_expressions] { _PyAST_Return(a, EXTRA) }
2020-04-22 23:29:27 +01:00
raise_stmt[stmt_ty]:
2021-04-07 21:34:22 +02:00
| 'raise' a=expression b=['from' z=expression { z }] { _PyAST_Raise(a, b, EXTRA) }
| 'raise' { _PyAST_Raise(NULL, NULL, EXTRA) }
2020-04-22 23:29:27 +01:00
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]:
2021-04-21 15:28:21 +01:00
| invalid_def_raw
2021-02-02 19:54:22 +00:00
| 'def' n=NAME '(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
2021-04-07 21:34:22 +02:00
_PyAST_FunctionDef(n->v.Name.id,
2020-10-21 22:53:14 +03:00
(params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)),
2020-05-01 06:27:52 +03:00
b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA) }
2021-02-02 19:54:22 +00:00
| ASYNC 'def' n=NAME '(' params=[params] ')' a=['->' z=expression { z }] &&':' tc=[func_type_comment] b=block {
2020-05-01 06:27:52 +03:00
CHECK_VERSION(
2020-10-21 22:53:14 +03:00
stmt_ty,
2020-05-01 06:27:52 +03:00
5,
"Async functions are",
2021-04-07 21:34:22 +02:00
_PyAST_AsyncFunctionDef(n->v.Name.id,
2020-10-21 22:53:14 +03:00
(params) ? params : CHECK(arguments_ty, _PyPegen_empty_arguments(p)),
2020-05-01 06:27:52 +03:00
b, NULL, a, NEW_TYPE_COMMENT(p, tc), EXTRA)
) }
2020-05-01 16:32:09 +01:00
func_type_comment[Token*]:
2020-04-30 12:12:19 -07:00
| NEWLINE t=TYPE_COMMENT &(NEWLINE INDENT) { t } # Must be followed by indented block
| invalid_double_type_comments
| TYPE_COMMENT
2020-04-22 23:29:27 +01:00
params[arguments_ty]:
| invalid_parameters
| parameters
2020-04-30 12:12:19 -07:00
2020-04-22 23:29:27 +01:00
parameters[arguments_ty]:
2020-09-16 19:42:00 +01:00
| a=slash_no_default b[asdl_arg_seq*]=param_no_default* c=param_with_default* d=[star_etc] {
2020-04-22 23:29:27 +01:00
_PyPegen_make_arguments(p, a, NULL, b, c, d) }
2020-04-30 12:12:19 -07:00
| a=slash_with_default b=param_with_default* c=[star_etc] {
2020-04-22 23:29:27 +01:00
_PyPegen_make_arguments(p, NULL, a, NULL, b, c) }
2020-09-16 19:42:00 +01:00
| a[asdl_arg_seq*]=param_no_default+ b=param_with_default* c=[star_etc] {
2020-04-22 23:29:27 +01:00
_PyPegen_make_arguments(p, NULL, NULL, a, b, c) }
2020-04-30 12:12:19 -07:00
| a=param_with_default+ b=[star_etc] { _PyPegen_make_arguments(p, NULL, NULL, NULL, a, b)}
2020-04-22 23:29:27 +01:00
| a=star_etc { _PyPegen_make_arguments(p, NULL, NULL, NULL, NULL, a) }
2020-04-30 12:12:19 -07:00
# Some duplication here because we can't write (',' | &')'),
# which is because we don't support empty alternatives (yet).
#
2020-09-16 19:42:00 +01:00
slash_no_default[asdl_arg_seq*]:
| a[asdl_arg_seq*]=param_no_default+ '/' ',' { a }
| a[asdl_arg_seq*]=param_no_default+ '/' &')' { a }
2020-04-30 12:12:19 -07:00
slash_with_default[SlashWithDefault*]:
2020-09-16 19:42:00 +01:00
| 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) }
2020-04-30 12:12:19 -07:00
2020-04-22 23:29:27 +01:00
star_etc[StarEtc*]:
2020-04-30 12:12:19 -07:00
| '*' a=param_no_default b=param_maybe_default* c=[kwds] {
2020-04-22 23:29:27 +01:00
_PyPegen_star_etc(p, a, b, c) }
2020-04-30 12:12:19 -07:00
| '*' ',' b=param_maybe_default+ c=[kwds] {
2020-04-22 23:29:27 +01:00
_PyPegen_star_etc(p, NULL, b, c) }
2020-04-30 12:12:19 -07:00
| a=kwds { _PyPegen_star_etc(p, NULL, NULL, a) }
2020-05-04 13:58:31 +03:00
| invalid_star_etc
2020-04-30 12:12:19 -07:00
2020-05-01 09:42:03 -07:00
kwds[arg_ty]: '**' a=param_no_default { a }
2020-04-30 12:12:19 -07: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) }
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) }
2021-04-07 21:34:22 +02:00
param[arg_ty]: a=NAME b=annotation? { _PyAST_arg(a->v.Name.id, b, NULL, EXTRA) }
2020-04-30 12:12:19 -07:00
annotation[expr_ty]: ':' a=expression { a }
default[expr_ty]: '=' a=expression { a }
2020-04-22 23:29:27 +01:00
2020-09-16 19:42:00 +01:00
decorators[asdl_expr_seq*]: a[asdl_expr_seq*]=('@' f=named_expression NEWLINE { f })+ { a }
2020-04-22 23:29:27 +01:00
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]:
2021-04-21 15:28:21 +01:00
| invalid_class_def_raw
2021-02-02 19:54:22 +00:00
| 'class' a=NAME b=['(' z=[arguments] ')' { z }] &&':' c=block {
2021-04-07 21:34:22 +02:00
_PyAST_ClassDef(a->v.Name.id,
2020-04-22 23:29:27 +01:00
(b) ? ((expr_ty) b)->v.Call.args : NULL,
(b) ? ((expr_ty) b)->v.Call.keywords : NULL,
c, NULL, EXTRA) }
2020-09-16 19:42:00 +01:00
block[asdl_stmt_seq*] (memo):
2020-04-22 23:29:27 +01:00
| NEWLINE INDENT a=statements DEDENT { a }
2020-11-30 19:42:38 +00:00
| simple_stmts
2020-04-22 23:29:27 +01:00
| invalid_block
star_expressions[expr_ty]:
| a=star_expression b=(',' c=star_expression { c })+ [','] {
2021-04-07 21:34:22 +02:00
_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) }
2020-04-22 23:29:27 +01:00
| star_expression
star_expression[expr_ty] (memo):
2021-04-07 21:34:22 +02:00
| '*' a=bitwise_or { _PyAST_Starred(a, Load, EXTRA) }
2020-04-22 23:29:27 +01:00
| expression
2020-09-16 19:42:00 +01:00
star_named_expressions[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_named_expression+ [','] { a }
2020-04-22 23:29:27 +01:00
star_named_expression[expr_ty]:
2021-04-07 21:34:22 +02:00
| '*' a=bitwise_or { _PyAST_Starred(a, Load, EXTRA) }
2020-04-22 23:29:27 +01:00
| named_expression
2021-04-12 16:59:30 +01:00
2020-04-22 23:29:27 +01:00
2021-11-04 23:19:27 +00:00
assignment_expression[expr_ty]:
2021-04-13 02:32:33 +01:00
| a=NAME ':=' ~ b=expression { _PyAST_NamedExpr(CHECK(expr_ty, _PyPegen_set_expr_context(p, a, Store)), b, EXTRA) }
2021-05-21 11:20:43 -07:00
named_expression[expr_ty]:
2021-11-04 23:19:27 +00:00
| assignment_expression
2021-05-21 11:20:43 -07:00
| invalid_named_expression
2021-04-13 02:32:33 +01:00
| expression !':='
2020-04-22 23:29:27 +01:00
annotated_rhs[expr_ty]: yield_expr | star_expressions
expressions[expr_ty]:
| a=expression b=(',' c=expression { c })+ [','] {
2021-04-07 21:34:22 +02:00
_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) }
2020-04-22 23:29:27 +01:00
| expression
expression[expr_ty] (memo):
2021-04-15 21:38:45 +01:00
| invalid_expression
2021-11-20 17:39:17 +00:00
| invalid_legacy_expression
2021-04-07 21:34:22 +02:00
| a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
2020-04-22 23:29:27 +01:00
| disjunction
| lambdef
lambdef[expr_ty]:
2020-10-21 22:53:14 +03:00
| 'lambda' a=[lambda_params] ':' b=expression {
2021-04-07 21:34:22 +02:00
_PyAST_Lambda((a) ? a : CHECK(arguments_ty, _PyPegen_empty_arguments(p)), b, EXTRA) }
2020-06-10 14:07:06 +01:00
lambda_params[arguments_ty]:
| invalid_lambda_parameters
| lambda_parameters
2020-05-01 09:42:03 -07:00
# 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.)
#
2020-04-22 23:29:27 +01:00
lambda_parameters[arguments_ty]:
2020-09-16 19:42:00 +01:00
| a=lambda_slash_no_default b[asdl_arg_seq*]=lambda_param_no_default* c=lambda_param_with_default* d=[lambda_star_etc] {
2020-04-22 23:29:27 +01:00
_PyPegen_make_arguments(p, a, NULL, b, c, d) }
2020-05-01 09:42:03 -07:00
| a=lambda_slash_with_default b=lambda_param_with_default* c=[lambda_star_etc] {
2020-04-22 23:29:27 +01:00
_PyPegen_make_arguments(p, NULL, a, NULL, b, c) }
2020-09-16 19:42:00 +01:00
| a[asdl_arg_seq*]=lambda_param_no_default+ b=lambda_param_with_default* c=[lambda_star_etc] {
2020-04-22 23:29:27 +01:00
_PyPegen_make_arguments(p, NULL, NULL, a, b, c) }
2020-05-01 09:42:03 -07:00
| a=lambda_param_with_default+ b=[lambda_star_etc] { _PyPegen_make_arguments(p, NULL, NULL, NULL, a, b)}
2020-04-22 23:29:27 +01:00
| a=lambda_star_etc { _PyPegen_make_arguments(p, NULL, NULL, NULL, NULL, a) }
2020-05-01 09:42:03 -07:00
2020-09-16 19:42:00 +01:00
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 }
2020-05-01 09:42:03 -07:00
lambda_slash_with_default[SlashWithDefault*]:
2020-09-16 19:42:00 +01:00
| 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) }
2020-05-01 09:42:03 -07:00
2020-04-22 23:29:27 +01:00
lambda_star_etc[StarEtc*]:
2020-05-01 09:42:03 -07:00
| '*' a=lambda_param_no_default b=lambda_param_maybe_default* c=[lambda_kwds] {
2020-04-22 23:29:27 +01:00
_PyPegen_star_etc(p, a, b, c) }
2020-05-01 09:42:03 -07:00
| '*' ',' b=lambda_param_maybe_default+ c=[lambda_kwds] {
2020-04-22 23:29:27 +01:00
_PyPegen_star_etc(p, NULL, b, c) }
2020-05-01 09:42:03 -07:00
| a=lambda_kwds { _PyPegen_star_etc(p, NULL, NULL, a) }
2020-05-04 13:58:31 +03:00
| invalid_lambda_star_etc
2020-05-01 09:42:03 -07:00
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) }
2021-04-07 21:34:22 +02:00
lambda_param[arg_ty]: a=NAME { _PyAST_arg(a->v.Name.id, NULL, NULL, EXTRA) }
2020-04-22 23:29:27 +01:00
disjunction[expr_ty] (memo):
2021-04-07 21:34:22 +02:00
| a=conjunction b=('or' c=conjunction { c })+ { _PyAST_BoolOp(
2020-04-22 23:29:27 +01:00
Or,
2020-10-21 22:53:14 +03:00
CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)),
2020-04-22 23:29:27 +01:00
EXTRA) }
| conjunction
conjunction[expr_ty] (memo):
2021-04-07 21:34:22 +02:00
| a=inversion b=('and' c=inversion { c })+ { _PyAST_BoolOp(
2020-04-22 23:29:27 +01:00
And,
2020-10-21 22:53:14 +03:00
CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)),
2020-04-22 23:29:27 +01:00
EXTRA) }
| inversion
inversion[expr_ty] (memo):
2021-04-07 21:34:22 +02:00
| 'not' a=inversion { _PyAST_UnaryOp(Not, a, EXTRA) }
2020-04-22 23:29:27 +01:00
| comparison
comparison[expr_ty]:
| a=bitwise_or b=compare_op_bitwise_or_pair+ {
2021-04-07 21:34:22 +02:00
_PyAST_Compare(
2020-10-21 22: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 23:29:27 +01:00
| bitwise_or
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
eq_bitwise_or[CmpopExprPair*]: '==' a=bitwise_or { _PyPegen_cmpop_expr_pair(p, Eq, a) }
2020-04-27 18:02:07 +01:00
noteq_bitwise_or[CmpopExprPair*]:
2020-10-30 23:48:42 +00:00
| (tok='!=' { _PyPegen_check_barry_as_flufl(p, tok) ? NULL : tok}) a=bitwise_or {_PyPegen_cmpop_expr_pair(p, NotEq, a) }
2020-04-22 23:29:27 +01: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) }
bitwise_or[expr_ty]:
2021-04-07 21:34:22 +02:00
| a=bitwise_or '|' b=bitwise_xor { _PyAST_BinOp(a, BitOr, b, EXTRA) }
2020-04-22 23:29:27 +01:00
| bitwise_xor
bitwise_xor[expr_ty]:
2021-04-07 21:34:22 +02:00
| a=bitwise_xor '^' b=bitwise_and { _PyAST_BinOp(a, BitXor, b, EXTRA) }
2020-04-22 23:29:27 +01:00
| bitwise_and
bitwise_and[expr_ty]:
2021-04-07 21:34:22 +02:00
| a=bitwise_and '&' b=shift_expr { _PyAST_BinOp(a, BitAnd, b, EXTRA) }
2020-04-22 23:29:27 +01:00
| shift_expr
shift_expr[expr_ty]:
2021-04-07 21:34:22 +02:00
| a=shift_expr '<<' b=sum { _PyAST_BinOp(a, LShift, b, EXTRA) }
| a=shift_expr '>>' b=sum { _PyAST_BinOp(a, RShift, b, EXTRA) }
2020-04-22 23:29:27 +01:00
| sum
sum[expr_ty]:
2021-04-07 21:34:22 +02:00
| a=sum '+' b=term { _PyAST_BinOp(a, Add, b, EXTRA) }
| a=sum '-' b=term { _PyAST_BinOp(a, Sub, b, EXTRA) }
2020-04-22 23:29:27 +01:00
| term
term[expr_ty]:
2021-04-07 21:34:22 +02: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)) }
2020-04-22 23:29:27 +01:00
| factor
factor[expr_ty] (memo):
2021-04-07 21:34:22 +02: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 23:29:27 +01:00
| power
power[expr_ty]:
2021-04-07 21:34:22 +02:00
| a=await_primary '**' b=factor { _PyAST_BinOp(a, Pow, b, EXTRA) }
2020-04-22 23:29:27 +01:00
| await_primary
await_primary[expr_ty] (memo):
2021-04-07 21:34:22 +02:00
| AWAIT a=primary { CHECK_VERSION(expr_ty, 5, "Await expressions are", _PyAST_Await(a, EXTRA)) }
2020-04-22 23:29:27 +01:00
| primary
primary[expr_ty]:
2021-04-07 21:34:22 +02: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 23:29:27 +01:00
| a=primary '(' b=[arguments] ')' {
2021-04-07 21:34:22 +02:00
_PyAST_Call(a,
2020-04-22 23:29:27 +01:00
(b) ? ((expr_ty) b)->v.Call.args : NULL,
(b) ? ((expr_ty) b)->v.Call.keywords : NULL,
EXTRA) }
2021-04-07 21:34:22 +02:00
| a=primary '[' b=slices ']' { _PyAST_Subscript(a, b, Load, EXTRA) }
2020-04-22 23:29:27 +01:00
| atom
slices[expr_ty]:
| a=slice !',' { a }
2021-04-07 21:34:22 +02:00
| a[asdl_expr_seq*]=','.slice+ [','] { _PyAST_Tuple(a, Load, EXTRA) }
2020-04-22 23:29:27 +01:00
slice[expr_ty]:
2021-04-07 21:34:22 +02:00
| a=[expression] ':' b=[expression] c=[':' d=[expression] { d }] { _PyAST_Slice(a, b, c, EXTRA) }
2020-11-17 01:09:35 +02:00
| a=named_expression { a }
2020-04-22 23:29:27 +01:00
atom[expr_ty]:
| NAME
2021-04-07 21:34:22 +02:00
| 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) }
| 'False' { _PyAST_Constant(Py_False, NULL, EXTRA) }
| 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) }
2020-04-22 23:29:27 +01:00
| &STRING strings
| NUMBER
| &'(' (tuple | group | genexp)
| &'[' (list | listcomp)
| &'{' (dict | set | dictcomp | setcomp)
2021-04-07 21:34:22 +02:00
| '...' { _PyAST_Constant(Py_Ellipsis, NULL, EXTRA) }
2020-04-22 23:29:27 +01:00
strings[expr_ty] (memo): a=STRING+ { _PyPegen_concatenate_strings(p, a) }
list[expr_ty]:
2021-04-07 21:34:22 +02:00
| '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) }
2020-04-22 23:29:27 +01:00
listcomp[expr_ty]:
2021-04-07 21:34:22 +02:00
| '[' a=named_expression b=for_if_clauses ']' { _PyAST_ListComp(a, b, EXTRA) }
2020-04-22 23:29:27 +01:00
| invalid_comprehension
tuple[expr_ty]:
| '(' a=[y=star_named_expression ',' z=[star_named_expressions] { _PyPegen_seq_insert_in_front(p, y, z) } ] ')' {
2021-04-07 21:34:22 +02:00
_PyAST_Tuple(a, Load, EXTRA) }
2020-06-19 02:10:43 +03:00
group[expr_ty]:
| '(' a=(yield_expr | named_expression) ')' { a }
| invalid_group
2020-04-22 23:29:27 +01:00
genexp[expr_ty]:
2021-11-04 23:19:27 +00:00
| '(' a=( assignment_expression | expression !':=') b=for_if_clauses ')' { _PyAST_GeneratorExp(a, b, EXTRA) }
2020-04-22 23:29:27 +01:00
| invalid_comprehension
2021-04-07 21:34:22 +02:00
set[expr_ty]: '{' a=star_named_expressions '}' { _PyAST_Set(a, EXTRA) }
2020-04-22 23:29:27 +01:00
setcomp[expr_ty]:
2021-04-07 21:34:22 +02:00
| '{' a=named_expression b=for_if_clauses '}' { _PyAST_SetComp(a, b, EXTRA) }
2020-04-22 23:29:27 +01:00
| invalid_comprehension
dict[expr_ty]:
2020-05-22 01:39:56 +03:00
| '{' a=[double_starred_kvpairs] '}' {
2021-04-07 21:34:22 +02:00
_PyAST_Dict(
2020-10-21 22: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 14:06:39 +01:00
| '{' invalid_double_starred_kvpairs '}'
2020-04-22 23:29:27 +01:00
dictcomp[expr_ty]:
2021-04-07 21:34:22 +02:00
| '{' a=kvpair b=for_if_clauses '}' { _PyAST_DictComp(a->key, a->value, b, EXTRA) }
2020-05-22 01:39:56 +03:00
| invalid_dict_comprehension
double_starred_kvpairs[asdl_seq*]: a=','.double_starred_kvpair+ [','] { a }
double_starred_kvpair[KeyValuePair*]:
2020-04-22 23:29:27 +01:00
| '**' a=bitwise_or { _PyPegen_key_value_pair(p, NULL, a) }
2020-05-22 01:39:56 +03:00
| kvpair
kvpair[KeyValuePair*]: a=expression ':' b=expression { _PyPegen_key_value_pair(p, a, b) }
2020-09-16 19:42:00 +01:00
for_if_clauses[asdl_comprehension_seq*]:
| a[asdl_comprehension_seq*]=for_if_clause+ { a }
2020-05-01 06:27:52 +03:00
for_if_clause[comprehension_ty]:
2020-09-16 19:42:00 +01:00
| ASYNC 'for' a=star_targets 'in' ~ b=disjunction c[asdl_expr_seq*]=('if' z=disjunction { z })* {
2021-04-07 21:34:22 +02:00
CHECK_VERSION(comprehension_ty, 6, "Async comprehensions are", _PyAST_comprehension(a, b, c, 1, p->arena)) }
2020-09-16 19:42:00 +01:00
| 'for' a=star_targets 'in' ~ b=disjunction c[asdl_expr_seq*]=('if' z=disjunction { z })* {
2021-04-07 21:34:22 +02:00
_PyAST_comprehension(a, b, c, 0, p->arena) }
2020-06-19 02:10:43 +03:00
| invalid_for_target
2020-04-22 23:29:27 +01:00
yield_expr[expr_ty]:
2021-04-07 21:34:22 +02:00
| 'yield' 'from' a=expression { _PyAST_YieldFrom(a, EXTRA) }
| 'yield' a=[star_expressions] { _PyAST_Yield(a, EXTRA) }
2020-04-22 23:29:27 +01:00
arguments[expr_ty] (memo):
| a=args [','] &')' { a }
2020-10-27 00:42:04 +02:00
| invalid_arguments
2020-04-22 23:29:27 +01:00
args[expr_ty]:
2021-11-04 23:19:27 +00:00
| a[asdl_expr_seq*]=','.(starred_expression | ( assignment_expression | expression !':=') !'=')+ b=[',' k=kwargs {k}] {
2021-05-21 11:20:43 -07:00
_PyPegen_collect_call_seqs(p, a, b, EXTRA) }
2021-04-07 21:34:22 +02:00
| a=kwargs { _PyAST_Call(_PyPegen_dummy_name(p),
2020-10-21 22: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 23:29:27 +01:00
EXTRA) }
2021-05-21 11:20:43 -07:00
2020-04-22 23:29:27 +01: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+
starred_expression[expr_ty]:
2021-04-07 21:34:22 +02:00
| '*' a=expression { _PyAST_Starred(a, Load, EXTRA) }
2020-04-22 23:29:27 +01:00
kwarg_or_starred[KeywordOrStarred*]:
2021-05-21 11:20:43 -07:00
| invalid_kwarg
2020-04-22 23:29:27 +01:00
| a=NAME '=' b=expression {
2021-04-07 21:34:22 +02:00
_PyPegen_keyword_or_starred(p, CHECK(keyword_ty, _PyAST_keyword(a->v.Name.id, b, EXTRA)), 1) }
2020-04-22 23:29:27 +01:00
| a=starred_expression { _PyPegen_keyword_or_starred(p, a, 0) }
kwarg_or_double_starred[KeywordOrStarred*]:
2021-05-21 11:20:43 -07:00
| invalid_kwarg
2020-04-22 23:29:27 +01:00
| a=NAME '=' b=expression {
2021-04-07 21:34:22 +02: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 23:29:27 +01: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 21:34:22 +02:00
_PyAST_Tuple(CHECK(asdl_expr_seq*, _PyPegen_seq_insert_in_front(p, a, b)), Store, EXTRA) }
2021-01-03 01:14:21 +02:00
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) }
2020-04-22 23:29:27 +01:00
star_target[expr_ty] (memo):
| '*' a=(!'*' star_target) {
2021-04-07 21:34:22 +02:00
_PyAST_Starred(CHECK(expr_ty, _PyPegen_set_expr_context(p, a, Store)), Store, EXTRA) }
2021-01-03 01:14:21 +02:00
| target_with_star_atom
target_with_star_atom[expr_ty] (memo):
2021-04-07 21:34:22 +02: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 23:29:27 +01:00
| star_atom
star_atom[expr_ty]:
| a=NAME { _PyPegen_set_expr_context(p, a, Store) }
2021-01-03 01:14:21 +02:00
| '(' a=target_with_star_atom ')' { _PyPegen_set_expr_context(p, a, Store) }
2021-04-07 21:34:22 +02:00
| '(' a=[star_targets_tuple_seq] ')' { _PyAST_Tuple(a, Store, EXTRA) }
| '[' a=[star_targets_list_seq] ']' { _PyAST_List(a, Store, EXTRA) }
2020-04-22 23:29:27 +01:00
2020-05-14 23:13:50 +03:00
single_target[expr_ty]:
| single_subscript_attribute_target
2020-04-22 23:29:27 +01:00
| a=NAME { _PyPegen_set_expr_context(p, a, Store) }
2020-05-14 23:13:50 +03:00
| '(' a=single_target ')' { a }
single_subscript_attribute_target[expr_ty]:
2021-04-07 21:34:22 +02: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 23:29:27 +01:00
2020-09-16 19:42:00 +01:00
del_targets[asdl_expr_seq*]: a[asdl_expr_seq*]=','.del_target+ [','] { a }
2020-04-22 23:29:27 +01:00
del_target[expr_ty] (memo):
2021-04-07 21:34:22 +02:00
| 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) }
2020-04-22 23:29:27 +01:00
| del_t_atom
del_t_atom[expr_ty]:
2020-06-19 02:10:43 +03:00
| a=NAME { _PyPegen_set_expr_context(p, a, Del) }
2020-04-22 23:29:27 +01:00
| '(' a=del_target ')' { _PyPegen_set_expr_context(p, a, Del) }
2021-04-07 21:34:22 +02:00
| '(' a=[del_targets] ')' { _PyAST_Tuple(a, Del, EXTRA) }
| '[' a=[del_targets] ']' { _PyAST_List(a, Del, EXTRA) }
2020-04-22 23:29:27 +01:00
t_primary[expr_ty]:
2021-04-07 21:34:22 +02: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 22:53:14 +03:00
| a=t_primary b=genexp &t_lookahead {
2021-04-07 21:34:22 +02:00
_PyAST_Call(a, CHECK(asdl_expr_seq*, (asdl_expr_seq*)_PyPegen_singleton_seq(p, b)), NULL, EXTRA) }
2020-04-22 23:29:27 +01:00
| a=t_primary '(' b=[arguments] ')' &t_lookahead {
2021-04-07 21:34:22 +02:00
_PyAST_Call(a,
2020-04-22 23:29:27 +01:00
(b) ? ((expr_ty) b)->v.Call.args : NULL,
(b) ? ((expr_ty) b)->v.Call.keywords : NULL,
EXTRA) }
| a=atom &t_lookahead { a }
t_lookahead: '(' | '[' | '.'
# From here on, there are rules for invalid syntax with specialised error messages
2020-10-27 00:42:04 +02:00
invalid_arguments:
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 14:27:05 +01:00
| a=args ',' '*' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "iterable argument unpacking follows keyword argument unpacking") }
| a=expression b=for_if_clauses ',' [args | expression for_if_clauses] {
2022-04-05 18:21:49 +02: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 11:20:43 -07:00
| a=NAME b='=' expression for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Maybe you meant '==' or ':=' instead of '='?")}
2021-09-27 07:05:20 -07: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 14:27:05 +01:00
| args ',' a=expression b=for_if_clauses {
2022-04-05 18:21:49 +02: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 23:29:27 +01:00
| a=args ',' args { _PyPegen_arguments_parsing_error(p, a) }
2020-05-07 13:44:06 +03:00
invalid_kwarg:
2021-11-16 22:31:16 +00: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 11:20:43 -07: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 11:28:31 -07: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 14:27:05 +01:00
RAISE_SYNTAX_ERROR_KNOWN_RANGE(
a, b, "expression cannot contain assignment, perhaps you meant \"==\"?") }
2021-04-15 21:38:45 +01:00
2022-02-10 14:38:31 +00:00
# IMPORTANT: Note that the "_without_invalid" suffix causes the rule to not call invalid rules under it
2021-05-21 11:20:43 -07: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 18:52:32 +01:00
invalid_legacy_expression:
2021-07-31 18:31:44 -07:00
| a=NAME !'(' b=star_expressions {
2021-07-27 14:19:18 -07: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 21:38:45 +01: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 18:52:32 +01:00
| !(NAME STRING | SOFT_KEYWORD) a=disjunction b=expression_without_invalid {
2021-11-25 01:01:40 +00: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 19:00:19 +01:00
| a=disjunction 'if' b=disjunction !('else'|':') { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "expected 'else' after 'if' expression") }
2021-04-15 21:38:45 +01:00
2022-02-10 14:38:31 +00:00
invalid_named_expression(memo):
2020-04-22 23:29:27 +01:00
| a=expression ':=' expression {
2020-05-13 22:36:27 +03:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
a, "cannot use assignment expressions with %s", _PyPegen_get_expr_name(a)) }
2021-05-21 11:20:43 -07:00
| a=NAME '=' b=bitwise_or !('='|':=') {
2022-02-10 14:38:31 +00: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 16:59:30 +01:00
_PyPegen_get_expr_name(a)) }
2020-04-22 23:29:27 +01:00
invalid_assignment:
2020-06-27 21: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-26 02:22:36 +03:00
| a=star_named_expression ',' star_named_expressions* ':' expression {
2020-05-13 22:36:27 +03:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "only single target (not tuple) can be annotated") }
2020-06-26 02:22:36 +03:00
| a=expression ':' expression {
2020-05-13 22:36:27 +03:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "illegal target for annotation") }
2020-06-08 02:57:00 +01:00
| (star_targets '=')* a=star_expressions '=' {
2020-06-21 05:18:01 +03:00
RAISE_SYNTAX_ERROR_INVALID_TARGET(STAR_TARGETS, a) }
2020-06-08 02:57:00 +01:00
| (star_targets '=')* a=yield_expr '=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "assignment to yield expression not possible") }
2020-05-15 02:04:52 +01:00
| a=star_expressions augassign (yield_expr | star_expressions) {
2021-02-26 14:51:55 -08:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
2020-06-26 02:22:36 +03:00
a,
2020-05-15 02:04:52 +01:00
"'%s' is an illegal expression for augmented assignment",
_PyPegen_get_expr_name(a)
)}
2020-06-27 21:33:08 +03:00
invalid_ann_assign_target[expr_ty]:
| list
| tuple
| '(' a=invalid_ann_assign_target ')' { a }
2020-06-19 02:10:43 +03:00
invalid_del_stmt:
| 'del' a=star_expressions {
2020-06-21 05:18:01 +03:00
RAISE_SYNTAX_ERROR_INVALID_TARGET(DEL_TARGETS, a) }
2020-04-22 23:29:27 +01:00
invalid_block:
| NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block") }
invalid_comprehension:
2020-05-13 22: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 14:27:05 +01: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-22 01: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 23:29:27 +01:00
invalid_parameters:
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 14:27:05 +01:00
| param_no_default* invalid_parameters_helper a=param_no_default {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "non-default argument follows default argument") }
2021-01-08 00:31:25 +02: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 14:07:06 +01:00
invalid_lambda_parameters:
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 14:27:05 +01:00
| lambda_param_no_default* invalid_lambda_parameters_helper a=lambda_param_no_default {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "non-default argument follows default argument") }
2021-01-08 00:31:25 +02:00
invalid_lambda_parameters_helper:
| a=lambda_slash_with_default { _PyPegen_singleton_seq(p, a) }
| lambda_param_with_default+
2020-05-04 13:58:31 +03:00
invalid_star_etc:
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 14:27:05 +01:00
| a='*' (')' | ',' (')' | '**')) { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "named arguments must follow bare *") }
2020-05-18 22:14:47 +03:00
| '*' ',' TYPE_COMMENT { RAISE_SYNTAX_ERROR("bare * has associated type comment") }
2020-05-04 13:58:31 +03:00
invalid_lambda_star_etc:
| '*' (':' | ',' (':' | '**')) { RAISE_SYNTAX_ERROR("named arguments must follow bare *") }
2020-04-30 12:12:19 -07:00
invalid_double_type_comments:
| TYPE_COMMENT NEWLINE TYPE_COMMENT NEWLINE INDENT {
RAISE_SYNTAX_ERROR("Cannot have two type comments on def") }
2020-06-19 02:10:43 +03:00
invalid_with_item:
2021-02-02 19:54:22 +00:00
| expression 'as' a=expression &(',' | ')' | ':') {
2020-06-21 05:18:01 +03:00
RAISE_SYNTAX_ERROR_INVALID_TARGET(STAR_TARGETS, a) }
2020-06-19 02:10:43 +03:00
invalid_for_target:
| ASYNC? 'for' a=star_expressions {
2020-06-21 05:18:01 +03:00
RAISE_SYNTAX_ERROR_INVALID_TARGET(FOR_TARGETS, a) }
2020-06-19 02:10:43 +03:00
invalid_group:
| '(' a=starred_expression ')' {
2021-04-12 16:59:30 +01:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use starred expression here") }
2021-03-24 19:34:17 +00:00
| '(' a='**' expression ')' {
2021-04-12 16:59:30 +01:00
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use double starred expression here") }
2020-05-21 23:41:58 +03:00
invalid_import_from_targets:
2021-08-18 13:32:01 -07:00
| import_from_as_names ',' NEWLINE {
2020-05-21 23:41:58 +03:00
RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") }
2021-02-02 19:54:22 +00:00
invalid_with_stmt:
| [ASYNC] 'with' ','.(expression ['as' star_target])+ &&':'
| [ASYNC] 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' &&':'
2021-04-21 15:28:21 +01:00
invalid_with_stmt_indent:
| [ASYNC] a='with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'with' statement on line %d", a->lineno) }
| [ASYNC] a='with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT {
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-04 00:11:43 +01:00
| 'try' ':' block !('except' | 'finally') { RAISE_SYNTAX_ERROR("expected 'except' or 'finally' block") }
2021-04-21 15:28:21 +01:00
invalid_except_stmt:
2021-02-07 18:42:21 +00:00
| 'except' a=expression ',' expressions ['as' NAME ] ':' {
2021-05-09 14:13:50 -07:00
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "multiple exception types must be parenthesized") }
2021-04-21 15:28:21 +01:00
| a='except' expression ['as' NAME ] NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
| a='except' NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
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 17:19:28 -07:00
| a='except' expression ['as' NAME ] ':' NEWLINE !INDENT {
2021-04-21 15:28:21 +01:00
RAISE_INDENTATION_ERROR("expected an indented block after 'except' statement on line %d", a->lineno) }
2022-04-05 18:21:49 +02:00
| a='except' ':' NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block after 'except' statement on line %d", a->lineno) }
2021-03-18 01:03:11 +00:00
invalid_match_stmt:
| "match" subject_expr !':' { CHECK_VERSION(void*, 10, "Pattern matching is", RAISE_SYNTAX_ERROR("expected ':'") ) }
2021-04-29 17:19:28 -07:00
| a="match" subject=subject_expr ':' NEWLINE !INDENT {
2021-04-21 15:28:21 +01:00
RAISE_INDENTATION_ERROR("expected an indented block after 'match' statement on line %d", a->lineno) }
2021-03-18 01:03:11 +00:00
invalid_case_block:
| "case" patterns guard? !':' { RAISE_SYNTAX_ERROR("expected ':'") }
2021-04-21 15:28:21 +01:00
| a="case" patterns guard? ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'case' statement on line %d", a->lineno) }
2021-06-18 22:15:57 +01: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 08:34:28 -07: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 16:59:30 +01:00
invalid_if_stmt:
| 'if' named_expression NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
2021-04-21 15:28:21 +01: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 16:59:30 +01:00
invalid_elif_stmt:
| 'elif' named_expression NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
2021-04-21 15:28:21 +01: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 16:59:30 +01:00
invalid_while_stmt:
| 'while' named_expression NEWLINE { RAISE_SYNTAX_ERROR("expected ':'") }
2021-04-21 15:28:21 +01: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:
| [ASYNC] a='for' star_targets 'in' star_expressions ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after 'for' statement on line %d", a->lineno) }
invalid_def_raw:
| [ASYNC] a='def' NAME '(' [params] ')' ['->' expression] ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after function definition on line %d", a->lineno) }
invalid_class_def_raw:
| a='class' NAME ['('[arguments] ')'] ':' NEWLINE !INDENT {
RAISE_INDENTATION_ERROR("expected an indented block after class definition on line %d", a->lineno) }
2021-04-15 14:06:39 +01: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 14:27:05 +01:00
| expression ':' a='*' bitwise_or { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "cannot use a starred expression in a dictionary value") }
2021-04-15 14:06:39 +01:00
| expression a=':' &('}'|',') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") }
invalid_kvpair:
2021-04-16 00:45:42 +01: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 14:27:05 +01: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") }
2021-04-15 14:06:39 +01:00
| expression a=':' {RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") }