The parser is always expecting one of several patterns, based on what it has read so far, for example if it's at the top level and reads
def, then a name has to follow, and then
( and then comma-separated args, and then
) and then
: and as soon as something is read that doesn't match what's currently allowed, then a syntax error is raised.
A statement while there's an open
( doesn't match any valid pattern, so a syntax error is raised.
Here's the syntax specification for Python3:
And the syntax for a function is:
funcdef: 'def' NAME parameters ['->' test] ':' suite
Which should be recognizable,
suite are defined in a similar fashion and re-used. the stuff inside
[ ] is optional.
suite is required? That's why this is invalid:
If no suite follows.
And a suite is defined as:
suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
So a simple_stmt can follow immediately, or there can be a newline and the indentation level can be increased and then one or more (+) statements (stmt) and then the indentation level needs to return back to what it was.
.. A Python file is defined as:
file_input: (NEWLINE | stmt)* ENDMARKER
Which is any number of newlines or statements followed by end of file. Makes sense, right.