macropy icon indicating copy to clipboard operation
macropy copied to clipboard

Named arguments for macros

Open Technologicat opened this issue 6 years ago • 6 comments

My kwargs hack related to issue #13, mainly for discussion for now.

In this version:

  • New magic is added to **kw, called kwargs.
  • kwargs gets the AST, as a list of ast.keyword objects, of named arguments passed to the macro invocation.
  • As a result of this change, full expr-macro invocation syntax (from normal run-time code) is now mac(a0, ..., an, k0=v0, ..., km=vm)[body]; the kj=vj pairs are new. Similarly for block and decorator macros (just the placement of body differs).

The named args are kept completely separate from the MacroPy **kw arguments, to protect MacroPy internals, and to prevent shadowing (in either direction). This captures only the user-given named args (e.g. x=1) in kwargs.

This complete separation is very important for the use of kwargs as syntax for binding constructs. Otherwise, e.g. a let construct might try to bind the name gen_sym (similarly for other MacroPy internals) because it happens to have an entry in **kw.

IMHO, the already existing args and the proposed kwargs together form one complete feature, namely the use of all the possibilities offered by Python's function call syntax, to provide extra slots for ASTs to be fed into the macro invocation beside the single body.

Also IMHO, this fixes an asymmetry in the MacroPy API. Already, macros can be given positional args, but no named args from the use site. (The existing implementation silently ignores named args, which I think is just an oversight; it should at least raise an error if we don't want to support named args. But that's really a separate issue.)

The body can of course already be a tuple, or really anything, so the whole feature does not add any fundamental capability - but it provides some flexibility for the syntax macros can offer to the user. For example, let constructs look more readable with a syntactically separate bindings block, which naturally takes one of the forms let((x, 1), (y, 2))[body] or let(x=1, y=2)[body]. I think the latter is more pythonic.

Thoughts?

Technologicat avatar Oct 09 '18 13:10 Technologicat

Tests? :P or later, after the discussion has been resolved? it just seems worth ensuring that existing implementation silently ignores named args, which I think is just an oversight is not true anymore

catb0t avatar Oct 09 '18 15:10 catb0t

Ah, very good point. I did my testing in the context of unpythonic, so I sort of forgot to add tests for this to MacroPy itself.

Yes, after discussion is the perfect time to add tests.

Technologicat avatar Oct 10 '18 07:10 Technologicat

So I'm going soon to publish a package for macropy, @Technologicat do you care to add a test or two for this?

azazel75 avatar May 14 '19 00:05 azazel75

Sure! I'll add some tests and push them, probably later today.

Technologicat avatar May 15 '19 07:05 Technologicat

Done, test added. It gets picked up by run_tests.py, and passes in Python 3.6.

While at it, I made the mechanism a bit more user-friendly: since the keyword arg name is always a string constant, the value is now automatically extracted from the keyword AST node.

The way the user macro implementation sees it, the parameter kwargs is now a dict of {argname_as_str: ast_node}. As mentioned before, it includes only the named args from the macro call site. Any MacroPy implicit args such as gen_sym and stop work exactly as before.

This separation is important when the kwargs feature is used for creating custom binding forms (e.g. let), and also to avoid clobbering the MacroPy implicit args if the user happens to name an arg e.g. as stop.

Inside the implementation, I changed the name kwargs to call_kwargs to match the existing naming scheme for call_args.

I'm not sure if the extrakws field is actually needed or not. It seems it's always empty (what gets passed in MacroPy's magic **kw is extrakws, plus the filevars that contain all the MacroPy implicit args). However, I did just a local analysis, so I may have missed something.

Anything else? :)

Technologicat avatar May 15 '19 12:05 Technologicat

Ping? Anything that still remains to be done?

Technologicat avatar Aug 18 '20 11:08 Technologicat