10. Full Grammar specification (original) (raw)

This is the full Python grammar, derived directly from the grammar used to generate the CPython parser (see Grammar/python.gram). The version here omits details related to code generation and error recovery.

The notation used here is the same as in the preceding docs, and is described in the notation section, except for a few extra complications:

PEG grammar for Python

========================= 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.

&&e

Eager parse e. The parser will not backtrack and will immediately

fail with SyntaxError if e cannot be parsed.

STARTING RULES

==============

file: [statements] ENDMARKER interactive: statement_newline eval: expressions NEWLINE* ENDMARKER func_type: '(' [type_expressions] ')' '->' expression NEWLINE* ENDMARKER

GENERAL STATEMENTS

==================

statements: statement+

statement: | compound_stmt | simple_stmts

single_compound_stmt: | compound_stmt

statement_newline: | single_compound_stmt NEWLINE | simple_stmts | NEWLINE | ENDMARKER

simple_stmts: | simple_stmt !';' NEWLINE # Not needed, there for speedup | ';'.simple_stmt+ [';'] NEWLINE

NOTE: assignment MUST precede expression, else parsing a simple assignment

will throw a SyntaxError.

simple_stmt: | assignment | type_alias | star_expressions | return_stmt | import_stmt | raise_stmt | pass_stmt | del_stmt | yield_stmt | assert_stmt | break_stmt | continue_stmt | global_stmt | nonlocal_stmt

compound_stmt: | function_def | if_stmt | class_def | with_stmt | for_stmt | try_stmt | while_stmt | match_stmt

SIMPLE STATEMENTS

=================

NOTE: annotated_rhs may start with 'yield'; yield_expr must start with 'yield'

assignment: | NAME ':' expression ['=' annotated_rhs ] | ('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs ] | (star_targets '=' )+ annotated_rhs !'=' [TYPE_COMMENT] | single_target augassign ~ annotated_rhs

annotated_rhs: yield_expr | star_expressions

augassign: | '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='

return_stmt: | 'return' [star_expressions]

raise_stmt: | 'raise' expression ['from' expression ] | 'raise'

pass_stmt: | 'pass'

break_stmt: | 'break'

continue_stmt: | 'continue'

global_stmt: 'global' ','.NAME+

nonlocal_stmt: 'nonlocal' ','.NAME+

del_stmt: | 'del' del_targets &(';' | NEWLINE)

yield_stmt: yield_expr

assert_stmt: 'assert' expression [',' expression ]

import_stmt: | import_name | import_from

Import statements

-----------------

import_name: 'import' dotted_as_names

note below: the ('.' | '...') is necessary because '...' is tokenized as ELLIPSIS

import_from: | 'from' ('.' | '...')* dotted_name 'import' import_from_targets | 'from' ('.' | '...')+ 'import' import_from_targets import_from_targets: | '(' import_from_as_names [','] ')' | import_from_as_names !',' | '*' import_from_as_names: | ','.import_from_as_name+ import_from_as_name: | NAME ['as' NAME ]

dotted_as_names: | ','.dotted_as_name+ dotted_as_name: | dotted_name ['as' NAME ]

dotted_name: | dotted_name '.' NAME | NAME

COMPOUND STATEMENTS

===================

Common elements

---------------

block: | NEWLINE INDENT statements DEDENT | simple_stmts

decorators: ('@' named_expression NEWLINE )+

Class definitions

-----------------

class_def: | decorators class_def_raw | class_def_raw

class_def_raw: | 'class' NAME [type_params] ['(' [arguments] ')' ] ':' block

Function definitions

--------------------

function_def: | decorators function_def_raw | function_def_raw

function_def_raw: | 'def' NAME [type_params] '(' [params] ')' ['->' expression ] ':' [func_type_comment] block | 'async' 'def' NAME [type_params] '(' [params] ')' ['->' expression ] ':' [func_type_comment] block

Function parameters

-------------------

params: | parameters

parameters: | slash_no_default param_no_default* param_with_default* [star_etc] | slash_with_default param_with_default* [star_etc] | param_no_default+ param_with_default* [star_etc] | param_with_default+ [star_etc] | star_etc

Some duplication here because we can't write (',' | &')'),

which is because we don't support empty alternatives (yet).

slash_no_default: | param_no_default+ '/' ',' | param_no_default+ '/' &')' slash_with_default: | param_no_default* param_with_default+ '/' ',' | param_no_default* param_with_default+ '/' &')'

star_etc: | '' param_no_default param_maybe_default [kwds] | '' param_no_default_star_annotation param_maybe_default [kwds] | '*' ',' param_maybe_default+ [kwds] | kwds

kwds: | '**' param_no_default

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: | param ',' TYPE_COMMENT? | param TYPE_COMMENT? &')' param_no_default_star_annotation: | param_star_annotation ',' TYPE_COMMENT? | param_star_annotation TYPE_COMMENT? &')' param_with_default: | param default ',' TYPE_COMMENT? | param default TYPE_COMMENT? &')' param_maybe_default: | param default? ',' TYPE_COMMENT? | param default? TYPE_COMMENT? &')' param: NAME annotation? param_star_annotation: NAME star_annotation annotation: ':' expression star_annotation: ':' star_expression default: '=' expression | invalid_default

If statement

------------

if_stmt: | 'if' named_expression ':' block elif_stmt | 'if' named_expression ':' block [else_block] elif_stmt: | 'elif' named_expression ':' block elif_stmt | 'elif' named_expression ':' block [else_block] else_block: | 'else' ':' block

While statement

---------------

while_stmt: | 'while' named_expression ':' block [else_block]

For statement

-------------

for_stmt: | 'for' star_targets 'in' ~ star_expressions ':' [TYPE_COMMENT] block [else_block] | 'async' 'for' star_targets 'in' ~ star_expressions ':' [TYPE_COMMENT] block [else_block]

With statement

--------------

with_stmt: | 'with' '(' ','.with_item+ ','? ')' ':' [TYPE_COMMENT] block | 'with' ','.with_item+ ':' [TYPE_COMMENT] block | 'async' 'with' '(' ','.with_item+ ','? ')' ':' block | 'async' 'with' ','.with_item+ ':' [TYPE_COMMENT] block

with_item: | expression 'as' star_target &(',' | ')' | ':') | expression

Try statement

-------------

try_stmt: | 'try' ':' block finally_block | 'try' ':' block except_block+ [else_block] [finally_block] | 'try' ':' block except_star_block+ [else_block] [finally_block]

Except statement

----------------

except_block: | 'except' expression ':' block | 'except' expression 'as' NAME ':' block | 'except' expressions ':' block | 'except' ':' block except_star_block: | 'except' '' expression ':' block | 'except' '' expression 'as' NAME ':' block | 'except' '*' expressions ':' block finally_block: | 'finally' ':' block

Match statement

---------------

match_stmt: | "match" subject_expr ':' NEWLINE INDENT case_block+ DEDENT

subject_expr: | star_named_expression ',' star_named_expressions? | named_expression

case_block: | "case" patterns guard? ':' block

guard: 'if' named_expression

patterns: | open_sequence_pattern | pattern

pattern: | as_pattern | or_pattern

as_pattern: | or_pattern 'as' pattern_capture_target

or_pattern: | '|'.closed_pattern+

closed_pattern: | literal_pattern | capture_pattern | wildcard_pattern | value_pattern | group_pattern | sequence_pattern | mapping_pattern | class_pattern

Literal patterns are used for equality and identity constraints

literal_pattern: | signed_number !('+' | '-') | complex_number | strings | 'None' | 'True' | 'False'

Literal expressions are used to restrict permitted mapping pattern keys

literal_expr: | signed_number !('+' | '-') | complex_number | strings | 'None' | 'True' | 'False'

complex_number: | signed_real_number '+' imaginary_number | signed_real_number '-' imaginary_number

signed_number: | NUMBER | '-' NUMBER

signed_real_number: | real_number | '-' real_number

real_number: | NUMBER

imaginary_number: | NUMBER

capture_pattern: | pattern_capture_target

pattern_capture_target: | !"_" NAME !('.' | '(' | '=')

wildcard_pattern: | "_"

value_pattern: | attr !('.' | '(' | '=')

attr: | name_or_attr '.' NAME

name_or_attr: | attr | NAME

group_pattern: | '(' pattern ')'

sequence_pattern: | '[' maybe_sequence_pattern? ']' | '(' open_sequence_pattern? ')'

open_sequence_pattern: | maybe_star_pattern ',' maybe_sequence_pattern?

maybe_sequence_pattern: | ','.maybe_star_pattern+ ','?

maybe_star_pattern: | star_pattern | pattern

star_pattern: | '' pattern_capture_target | '' wildcard_pattern

mapping_pattern: | '{' '}' | '{' double_star_pattern ','? '}' | '{' items_pattern ',' double_star_pattern ','? '}' | '{' items_pattern ','? '}'

items_pattern: | ','.key_value_pattern+

key_value_pattern: | (literal_expr | attr) ':' pattern

double_star_pattern: | '**' pattern_capture_target

class_pattern: | name_or_attr '(' ')' | name_or_attr '(' positional_patterns ','? ')' | name_or_attr '(' keyword_patterns ','? ')' | name_or_attr '(' positional_patterns ',' keyword_patterns ','? ')'

positional_patterns: | ','.pattern+

keyword_patterns: | ','.keyword_pattern+

keyword_pattern: | NAME '=' pattern

Type statement

---------------

type_alias: | "type" NAME [type_params] '=' expression

Type parameter declaration

--------------------------

type_params: | '[' type_param_seq ']'

type_param_seq: ','.type_param+ [',']

type_param: | NAME [type_param_bound] [type_param_default] | '*' NAME [type_param_starred_default] | '**' NAME [type_param_default]

type_param_bound: ':' expression type_param_default: '=' expression type_param_starred_default: '=' star_expression

EXPRESSIONS

-----------

expressions: | expression (',' expression )+ [','] | expression ',' | expression

expression: | disjunction 'if' disjunction 'else' expression | disjunction | lambdef

yield_expr: | 'yield' 'from' expression | 'yield' [star_expressions]

star_expressions: | star_expression (',' star_expression )+ [','] | star_expression ',' | star_expression

star_expression: | '*' bitwise_or | expression

star_named_expressions: ','.star_named_expression+ [',']

star_named_expression: | '*' bitwise_or | named_expression

assignment_expression: | NAME ':=' ~ expression

named_expression: | assignment_expression | expression !':='

disjunction: | conjunction ('or' conjunction )+ | conjunction

conjunction: | inversion ('and' inversion )+ | inversion

inversion: | 'not' inversion | comparison

Comparison operators

--------------------

comparison: | bitwise_or compare_op_bitwise_or_pair+ | bitwise_or

compare_op_bitwise_or_pair: | 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: '==' bitwise_or noteq_bitwise_or: | ('!=' ) bitwise_or lte_bitwise_or: '<=' bitwise_or lt_bitwise_or: '<' bitwise_or gte_bitwise_or: '>=' bitwise_or gt_bitwise_or: '>' bitwise_or notin_bitwise_or: 'not' 'in' bitwise_or in_bitwise_or: 'in' bitwise_or isnot_bitwise_or: 'is' 'not' bitwise_or is_bitwise_or: 'is' bitwise_or

Bitwise operators

-----------------

bitwise_or: | bitwise_or '|' bitwise_xor | bitwise_xor

bitwise_xor: | bitwise_xor '^' bitwise_and | bitwise_and

bitwise_and: | bitwise_and '&' shift_expr | shift_expr

shift_expr: | shift_expr '<<' sum | shift_expr '>>' sum | sum

Arithmetic operators

--------------------

sum: | sum '+' term | sum '-' term | term

term: | term '*' factor | term '/' factor | term '//' factor | term '%' factor | term '@' factor | factor

factor: | '+' factor | '-' factor | '~' factor | power

power: | await_primary '**' factor | await_primary

Primary elements

----------------

Primary elements are things like "obj.something.something", "obj[something]", "obj(something)", "obj" ...

await_primary: | 'await' primary | primary

primary: | primary '.' NAME | primary genexp | primary '(' [arguments] ')' | primary '[' slices ']' | atom

slices: | slice !',' | ','.(slice | starred_expression)+ [',']

slice: | [expression] ':' [expression] [':' [expression] ] | named_expression

atom: | NAME | 'True' | 'False' | 'None' | strings | NUMBER | (tuple | group | genexp) | (list | listcomp) | (dict | set | dictcomp | setcomp) | '...'

group: | '(' (yield_expr | named_expression) ')'

Lambda functions

----------------

lambdef: | 'lambda' [lambda_params] ':' expression

lambda_params: | 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: | lambda_slash_no_default lambda_param_no_default* lambda_param_with_default* [lambda_star_etc] | lambda_slash_with_default lambda_param_with_default* [lambda_star_etc] | lambda_param_no_default+ lambda_param_with_default* [lambda_star_etc] | lambda_param_with_default+ [lambda_star_etc] | lambda_star_etc

lambda_slash_no_default: | lambda_param_no_default+ '/' ',' | lambda_param_no_default+ '/' &':'

lambda_slash_with_default: | lambda_param_no_default* lambda_param_with_default+ '/' ',' | lambda_param_no_default* lambda_param_with_default+ '/' &':'

lambda_star_etc: | '' lambda_param_no_default lambda_param_maybe_default [lambda_kwds] | '*' ',' lambda_param_maybe_default+ [lambda_kwds] | lambda_kwds

lambda_kwds: | '**' lambda_param_no_default

lambda_param_no_default: | lambda_param ',' | lambda_param &':' lambda_param_with_default: | lambda_param default ',' | lambda_param default &':' lambda_param_maybe_default: | lambda_param default? ',' | lambda_param default? &':' lambda_param: NAME

LITERALS

========

fstring_middle: | fstring_replacement_field | FSTRING_MIDDLE fstring_replacement_field: | '{' annotated_rhs '='? [fstring_conversion] [fstring_full_format_spec] '}' fstring_conversion: | "!" NAME fstring_full_format_spec: | ':' fstring_format_spec* fstring_format_spec: | FSTRING_MIDDLE | fstring_replacement_field fstring: | FSTRING_START fstring_middle* FSTRING_END

tstring_format_spec_replacement_field: | '{' annotated_rhs '='? [fstring_conversion] [tstring_full_format_spec] '}' tstring_format_spec: | TSTRING_MIDDLE | tstring_format_spec_replacement_field tstring_full_format_spec: | ':' tstring_format_spec* tstring_replacement_field: | '{' annotated_rhs '='? [fstring_conversion] [tstring_full_format_spec] '}' tstring_middle: | tstring_replacement_field | TSTRING_MIDDLE tstring: | TSTRING_START tstring_middle* TSTRING_END

string: STRING strings: (fstring|string|tstring)+

list: | '[' [star_named_expressions] ']'

tuple: | '(' [star_named_expression ',' [star_named_expressions] ] ')'

set: '{' star_named_expressions '}'

Dicts

-----

dict: | '{' [double_starred_kvpairs] '}'

double_starred_kvpairs: ','.double_starred_kvpair+ [',']

double_starred_kvpair: | '**' bitwise_or | kvpair

kvpair: expression ':' expression

Comprehensions & Generators

---------------------------

for_if_clauses: | for_if_clause+

for_if_clause: | 'async' 'for' star_targets 'in' ~ disjunction ('if' disjunction )* | 'for' star_targets 'in' ~ disjunction ('if' disjunction )*

listcomp: | '[' named_expression for_if_clauses ']'

setcomp: | '{' named_expression for_if_clauses '}'

genexp: | '(' ( assignment_expression | expression !':=') for_if_clauses ')'

dictcomp: | '{' kvpair for_if_clauses '}'

FUNCTION CALL ARGUMENTS

=======================

arguments: | args [','] &')'

args: | ','.(starred_expression | ( assignment_expression | expression !':=') !'=')+ [',' kwargs ] | kwargs

kwargs: | ','.kwarg_or_starred+ ',' ','.kwarg_or_double_starred+ | ','.kwarg_or_starred+ | ','.kwarg_or_double_starred+

starred_expression: | '*' expression

kwarg_or_starred: | NAME '=' expression | starred_expression

kwarg_or_double_starred: | NAME '=' expression | '**' expression

ASSIGNMENT TARGETS

==================

Generic targets

---------------

NOTE: star_targets may contain *bitwise_or, targets may not.

star_targets: | star_target !',' | star_target (',' star_target )* [',']

star_targets_list_seq: ','.star_target+ [',']

star_targets_tuple_seq: | star_target (',' star_target )+ [','] | star_target ','

star_target: | '' (!'' star_target) | target_with_star_atom

target_with_star_atom: | t_primary '.' NAME !t_lookahead | t_primary '[' slices ']' !t_lookahead | star_atom

star_atom: | NAME | '(' target_with_star_atom ')' | '(' [star_targets_tuple_seq] ')' | '[' [star_targets_list_seq] ']'

single_target: | single_subscript_attribute_target | NAME | '(' single_target ')'

single_subscript_attribute_target: | t_primary '.' NAME !t_lookahead | t_primary '[' slices ']' !t_lookahead

t_primary: | t_primary '.' NAME &t_lookahead | t_primary '[' slices ']' &t_lookahead | t_primary genexp &t_lookahead | t_primary '(' [arguments] ')' &t_lookahead | atom &t_lookahead

t_lookahead: '(' | '[' | '.'

Targets for del statements

--------------------------

del_targets: ','.del_target+ [',']

del_target: | t_primary '.' NAME !t_lookahead | t_primary '[' slices ']' !t_lookahead | del_t_atom

del_t_atom: | NAME | '(' del_target ')' | '(' [del_targets] ')' | '[' [del_targets] ']'

TYPING ELEMENTS

---------------

type_expressions allow /* but ignore them

type_expressions: | ','.expression+ ',' '' expression ',' '**' expression | ','.expression+ ',' '' expression | ','.expression+ ',' '' expression | '*' expression ',' '' expression | '*' expression | '**' expression | ','.expression+

func_type_comment: | NEWLINE TYPE_COMMENT &(NEWLINE INDENT) # Must be followed by indented block | TYPE_COMMENT

========================= END OF THE GRAMMAR ===========================

========================= START OF INVALID RULES =======================