masak / alma

ALgoloid with MAcros -- a language with Algol-family syntax where macros take center stage
Artistic License 2.0
137 stars 14 forks source link

Implement succinct macros #479

Open masak opened 5 years ago

masak commented 5 years ago

Currently, examples/swap.007 is implemented like this:

macro swap(a, b) {
    return quasi {
        my t = {{{a}}};
        {{{a}}} = {{{b}}};
        {{{b}}} = t;
    };
}

That's insufficient, because (yadda yadda yadda) #214. So a proper implementation that takes this into account should be something like this:

macro swap(a, b) {
    return quasi {
        my t = location({{{a}}}).get();
        location({{{a}}}).set(location({{{b}}}).get());
        location({{{b}}}).set(t);
    };
}

(Wait, is that even a legal implementation? I think it'd be OK and not breaking the SER to take the location of the same unquoted expression several times... but, to be honest, I'm not sure. Maybe it'd have to be written like this:)

macro swap(a, b) {
    return quasi {
        my locA = location({{{a}}});
        my locB = location({{{b}}});
        my t = locA.get();
        locA.set(locB.get());
        locB.set(t);
    };
}

But now we're pretty far from a simple, clear, understandable implementation of swap. We're getting bogged down by irrelevant implementation details — kind of what macros are there to solve.

Enter succinct macros: macros "as people intuitively want them to work".

@succinct
macro swap(a, b) {
    my t = a;
    a = b;
    b = t;
}

Several things are at work here:

It's hard to argue with the simplicity of the @succinct macro. We like simple. In order for it not to be a double-edged sword, though, the rules for the transformation need to err on the side of being simple/predictable also. I suppose that can mean that sometimes those transformations prefer to give up because the source end of the code is doing stuff that's too fancy. But clearly swap and infix:<//> should be fine.

masak commented 5 years ago

Since unquotes are no longer made of stuff but are holes (#334), I'm left wondering how to go about creating them programmatically. (Manually is easy; just use the unquote syntax.)

In this instance, we want to

The result is no longer a Qtree, mind. But the process above is hard to even describe without pretending that unquotes are things and quasis aren't opaque.

So here's what I propose: a kind of visitor-y thing where we get to traverse the nodes and act, maybe both going down and coming up (but that's not necessary here). In this particular createQuasi visitor, there's also a replaceByUnquote method that accepts the interpolation expression (which, it seems, could be either a quasi object, or a normal function returning a value).

I think this built-in is a good idea. It could be an issue on its own; we could build it today. Macro-generating macros like @succinct are likely to want to generate quasis.

masak commented 5 years ago

I think it'd be OK and not breaking the SER to take the location of the same unquoted expression several times... but, to be honest, I'm not sure.

It's not. Even taking the location of something triggers the side effects of the lookup parts before the final one.

vendethiel commented 5 years ago

Clearly there should be a macro-defining macro that makes sure params are only eval ‘d once

masak commented 5 years ago

@vendethiel cf. #234. 😉

masak commented 5 years ago

I just slapped the currently-needs-more-design label on this issue, because I would like for it to be spelled out in a small spec how the code generation handles control flow such as if statements and loops.

vendethiel commented 5 years ago

Without the need to squint too hard at it, this really seems to have a lot in common with scheme/racket template macros. And with multi-dispatch, even more so...

masak commented 5 years ago

Bumping this because @vendethiel and I started a skunkworks implementation of the is succinct processor yesterday. Hoping to be able to put up a PR with it later today.

The "needs more design" label is still relevant; I don't know exactly yet how control flow interacts with locations. (Also, we don't yet have locations.)

We floated the idea yesterday that the is succinct processing might be implemented in 007. Preferably also using a built-in walker to do its job. But that'll be a second step, after we have the Perl 6 version working.