Inspired by PEP 638 Ive written my own version of a macro processor. It avoids changing the interpreter by using source encoding. Macros are
[x =] name!<delineter>Some Text<delimiter>[:
Some Body
]
Expression and statement macros with or without bodies.
The Text or Body need not be valid python and the delimeters are very flexible. The Body just needs to be indented. Here are some working examples
# super switch, match with addons
switch! x with logic:
case! Y == 'abc' capture Y:
print('match and case', Y)
case! _:
print('Default')
# inspired by Rust
macro_rules! abc as EXPRESSION:
case! _0:
_0 + 7
case! _0, _1:
_0 + _1
case! _0, _1, _2:
(_0 + _1) * _2
case! _0, _1, _2, _3:
_0 + _1 + _2 + _3
x = 4
y = abc!(1, 2, 3)
y = abc![1, x/2]
y = abc!{7}
# lisp s-expression to list.
l = lisp!$1 2 3 4 5 6
In the final exampe the delimiters are $ and \n. The case macro is never defined. All the examples in the PEP work. Ive also used it to write multi-line lambda functions.
Ive not published it as I regard it as a toy and learning experience for me, some bits are fragile and its not properly tested.
It has limitations,
- errors refer to locations in generated code, not source code which makes deuging difficult.
- comments are best avoided.
- using macros in other macros may not always work.
However it does allow non valid python to be mixed with valid python.
I havnt tried the OPs idea but see no reason for it not to work.
For expresion macros the processor works by
- simple text processing to turn name! into unique_name(name, delimeter, paramater, delimiter) where all arguments are strings. This is a fool proof as I can make it. The result compiles to a single AST node.
- convert all code to AST tree.
- process macro in AST tree and replace AST function node and define any necessary new functions.
- convert back to python.
- pass to compiler
Statement macros resort to some different tricks to capture the body.
It should be built into the compiler but I gave up trying to understand and modify the parser.
All the hard work is done by manipulating the AST tree which makes it all possible.
Its tested with 3.11 on Windows 10.