[Python-ideas] In call grammar, replace primary with possible_call? (was Re: ...quote followed by a left parenthesis...?)

Terry Reedy tjreedy at udel.edu
Thu Jul 16 01:03:50 CEST 2015


On 7/15/2015 11:40 AM, Jacob Niehus wrote:
> I recently forgot the '%' between a format string and its tuple of
> values and got "TypeError: 'str' object is not callable." The error
> makes sense, of course, because function calling has higher precedence
> than anything else in the expression, so while:
>
>>>> '%s' 'abc'
>
> yields '%sabc',
>
>>>> '%s' ('abc')
>
> yields a TypeError.
>
> My question is whether this should be caught as a syntax error instead
> of a runtime error. I can't think of any possible case where a
> single/double quote followed by '(' (optionally separated by whitespace)
> would not raise an exception when the '(' is not in a string or comment.

The lexical (character) level is the wrong one for approaching this 
issue.  Python, like most formal language interpreters, first groups 
characters into tokens.  The above becomes 4 tokens: '%s', (, 'abc', and 
).  These tokens are parsed into an ast.Expr with an ast.Call object. 
The .fun attribute is an ast.Str and the .args attribute has the other 
string.

The simplified version of the current grammar for a call is
   call  ::= primary '(' args ')'
Your are, in effect, pointing out that 'primary' seems too broad, and 
asking whether it could sensibly be replaced by something narrower.

Lets see how we might define a new non-terminal 'possible_call(able)' by 
pulling apart 'primary':
   primary ::= atom | attributeref | subscription | slicing | call
Each of these is a possible callable, though a callable slicing would be 
unusual. The latter 4 are singular categories and must be included in 
possible_call.  But atom is itself a composite category:

   atom      ::=  identifier | literal | enclosure
   enclosure ::=  parenth_form | list_display | dict_display
                  | set_display | generator_expression | yield_atom

Identifiers are the most common form of callable.  Number and string 
literals never are. Parenth_forms include ( identifier ) and so possibly 
are*. Displays and G-Es never are (as noted by Ron Adam).  I believe a 
yield_atom could be with gen.send(callable).

* Parenth_forms include both tuples -- parentheses empty or include a 
comma -- and parenthesized expression -- everything else, which is to 
say, non-empty parentheses without a comma.  It seems that these could 
be separate grammatical categories, in which case tuples would be 
excluded and parenth_expr included.

So here is the proposal: in the call definition, change primary to
   possible_call ::= identifier | parenth_form | yield_atom
                     | attributeref | subscription | slicing | call

As for error messages, there is another thread suggesting that the 
messages for SyntexError might be vastly improved.

-- 
Terry Jan Reedy



More information about the Python-ideas mailing list