I'm excited about the potential introduction of Lisp-style syntactic macros 
into Python. 😁

It's unclear to me whether PEP 638 ("Syntactic Macros") is still being actively 
developed, since the last activity I see on it is over a year ago (Sep & Oct 
2020), but I thought I'd leave some initial comments I have anyway.

Quoting from the PEP text...

(1)

> Lexical analysis
> ~~~~~~~~~~~~~~~~
> 
> Any sequence of identifier characters followed by an exclamation point
> (exclamation mark, UK English) will be tokenized as a ``MACRO_NAME``.

+1 to using the ! character to mark macros explicitly and loudly, since they 
are very powerful and can completely customize the syntax used inside them.

I like the postfix syntax myself (as proposed) - so `macro_name!` is cool. I 
wouldn't be a fan of prefix syntax; `!macro_name` looks ugly.

(2)

> Statement form
> ~~~~~~~~~~~~~~
> 
> macro_stmt = MACRO_NAME testlist [ "import" NAME ] [ "as"  NAME ] [ ":" 
> NEWLINE suite ]

(2.1)

What is `testlist`? It is not defined in this PEP, nor is it defined in the 
Python Grammar Specification [1].

Also, the `[ "import" NAME ]` and `[ "as"  NAME ]` parts appear to be 
special-purpose syntax only useful for supporting the `from!` and `with!` 
macros mentioned later in the PEP. It feels odd that this syntax isn't more 
general-purpose. 

Perhaps the grammar could be made more general with something like:

> macro_stmt = MACRO_NAME macro_expr_parameters ( NEWLINE | ":" NEWLINE suite )
> macro_expr_parameters = ( expression | <keyword> )*

That would allow a statement macro to take some number of expressions and 
keywords as arguments, in addition to a suite.

(2.2) +0 to the idea of prefixing a @ to a MACRO_NAME that is intended to be 
used as a sibling-macro. That would look like:

> @do_nothing_marker!
> def foo(...):
>     ...

(3)

> Expression form
> ~~~~~~~~~~~~~~~
> 
> macro_expr = MACRO_NAME "(" testlist ")"

Again, what is `testlist`? Perhaps you're looking for something more like:

> macro_expr = MACRO_NAME "(" macro_parameters ")"
> macro_parameters = ( expression ( "," expression )* ","? )?

(4)

> Resolving ambiguity
> ~~~~~~~~~~~~~~~~~~~
> 
> The statement form of a macro takes precedence, so that the code
> ``macro_name!(x)`` will be parsed as a macro statement,
> not as an expression statement containing a macro expression.

It seems to me that if you were to define an expression macro - like `cast!(T, 
expression)` - that users would expect to be able to call such an expression 
macro on a line by itself. The rule stated here suggests that the parser would 
get confused by such a call, incorrectly treating the call as a call of a macro 
*statement* rather than a macro *expression*.

(5)

> Compilation
> ~~~~~~~~~~~
> 
> For macros with multiple names, [...]

Nit: "Multiple names"? I think you meant macros with "additional names", as 
described later in the PEP.

(6)

> Defining macro processors
> ~~~~~~~~~~~~~~~~~~~~~~~~~
> 
> A macro processor is defined by a four-tuple, consisting of
> ``(func, kind, version, additional_names)``:
> 
> * [...]
> * ``additional_names`` are the names of the additional parts of the macro, 
> and must be a tuple of strings.

Seems to me that "additional_names" might make more sense to call "additional 
clause names" or just "clause names". That would be consistent with the 
following "anatomy of a statement-macro" sketch:

try_!:  # begin try_ statement; is try_ clause header
    ...  # is try_ clause body
finally_!:  # is finally_ clause header
    ...  # is finally_ clause body; end of try_ statement

(7)

> Hygiene and debugging
> ~~~~~~~~~~~~~~~~~~~~~
> 
> [...] No rules for naming will be enforced, but to ensure hygiene and help 
> debugging, the following naming scheme is recommended: [...]

This appears to imply that it is up to the macro processor author to take 
special care that their macro is hygenic. That is, *unhygenic* macros are the 
default. Wouldn't it be safer to define a system where *hygenic* macros would 
be the default instead? Seems like if we can head off the introduction of 
Command Injection by default at the design level then we should do so.

(8)

> Examples
> ''''''''

Not a single example in this section defines an actual macro processor 
function. Recommend implementing at least a toy macro end-to-end (including the 
macro processor function) for full clarity, for each type of macro (i.e. 
statements, sibling, and expression).

(9)

> Backwards Compatibility
> =======================
> 
> This PEP is fully backwards compatible.

Nit: In the §"Implementation" section below, it is mentioned that nodes in 
the`_ast` module would be made immutable. That sounds like a 
backward-incompatible change to me.

(10)

> Currently, all AST nodes are allocated using an arena allocator.
> Changing to use the standard allocator might slow compilation down a little,
> but has advantages in terms of maintenance, as much code can be deleted.

I presume the arena allocator was introduced in the first place for a reason. 
Perhaps to improve performance? By removing the arena allocator are there 
potential downsides other than a performance regression?

(11)

> Reference Implementation
> ''''''''''''''''''''''''
> 
> None as yet.

Seems like you could get a prototype off the ground by implementing an initial 
version as a fake Python source file text encoding.

Then you could put something like `# coding=macros` at the top of a source file 
to have it preprocessed by a prototype macro system.

(12)

Thanks for taking the time to read my comments.

-- 
David Foster | Seattle, WA, USA
Contributor to mypy, TypedDict, and Python's type system


[1]: https://docs.python.org/3/reference/grammar.html
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/AW6KOQ2V3TS6TQUHS4VGFIKSR3SOLJCJ/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to