Open gilch opened 3 years ago
This actually seems a bit more difficult than I first thought. We're relying on Python's parser in bracketed expressions, but the macro character ! probably shouldn't be valid inside of a string literal. We can probably recognize literal strings with the lexing regex though. Hmm. It does still seem doable.
F-strings though. We'd want to be able to turn the macro back on in those.
As convenient as this would be, it kind of doesn't seem worth it.
The thing I miss the most in bracketed expressions so far is the module literals. It would be nice if we could at least preprocess those, but it seems about as difficult to do as the full expression macros. One can certainly write __import__
calls by hand, but that's so much longer it doesn't seem worth it compared to using !let
.
Python is capable of abbreviating this kind of thing.
class Importer:
def __init__(self, module_path=()):
self.mpath = module_path
def __getattribute__(self, attr):
return Importer(object.__getattribute__(self,'mpath') + (attr,))
def __call__(self):
return import_module('.'.join(object.__getattribute__(self,'mpath')))
>>> M = Importer()
>>> M.collections.abc().Iterable
<class 'collections.abc.Iterable'>
That's almost as good. You need a prefix like the M.
, and ().
instead of ..
. There's also slightly more runtime overhead, which could add up.
Given f-strings, !
isn't a good macro character choice, because it does have meaning there. ;
might be the best option. I'm pretty sure it's not in format specifiers. Normally, it would end a statement, so it can't be in an expression either, except in string literals, which would have to be dealt with somehow anyway.
A macro like this wouldn't be too hard to write:
!where: (spam+eggs) spam macro:spam eggs macro:eggs
It feels more compact than the !let
anyway.
It could also be done positionally with an anaphor.
!where: (X[0]+X[1]) macro:spam macro:eggs
Or both at once.
This seems like the 80% solution. Getting the parser to handle this properly seems a lot more difficult.
Hissp has the mix
macro now, which would serve this role. It depends on fragment tokens to work, but a macro could theoretically strip brackets.
Usage might end up looking something like the following:
!mix: macro:spam (+) macro:eggs
You couldn't simply inject unbalanced parentheses this way, but a text macro could expand to an arbitrary fragment. Macros operate on the Hissp level. There's no need to change the parser here.
While parsing a bracketed expression, we could recursively switch back to the base Hebigo parser when encountering a macro character that Python doesn't use, like
!
, until we finish the next Hebigo expression, then place the result of compiling that back into the Python string we're building. This would effectively be a builtin reader macro. For example,Maybe a bad example, since Python's expression syntax can handle this part fine.
But suppose we needed a macro.
We'd currently have to do something like
or
On the other hand, we might want to encourage using hotword expressions instead of Python expressions, because it's much easier to write macros to work with those.