masak / alma

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

Introduce listops #178

Open masak opened 8 years ago

masak commented 8 years ago
macro term:listop(term: Q::Term, arguments: Q::ArgumentList)
    is parsed(/<term> <.ws> <argumentlist>/) {
    return quasi { {{{term}}}({{{arguments @ Q::ArgumentList}}}) };
}

Instead of fighting them as in #49, why not joining them?

masak commented 8 years ago

Though we have to take into account the risk of suddenly gobbling blocks:

use listops;    # or whatever we end up calling the pragma
sub foo(x) {}
if foo {
    # whatever statement's in here will cause a parsefail
}

The if block will parse as an object literal under listops.

Don't know what the correct fix is — make an exception for expressions inside xblocks (ugh), or just provide a really good error message (sigh)?

masak commented 5 years ago

Given the way #300 is heading, maybe we'll even end up with "listops", aka a "list prefix" precedence level, a precedence level looser than the usual infixes.

I dunno. It's worth trying, I think.

One difficulty we'll run into with that is that right now infix:<,> isn't an operator, but it'd probably need to be, maybe? (Or should we prefer the above is parsed approach and expect an argumentlist?)

Introducing an infix:<,> operator is fraught, as JavaScript has gone ahead and shown. It definitely needs to come with "unused" linter warnings, or even compiler warnings. Also, it heads out in a direction not really compatible with #430. So, on balance, maybe go with the is parsed approach.

masak commented 5 years ago

Oh! One big change that this will entail:

say(say)

With current (master) semantics, this prints <func say(...args)>. With listops implemented, the inner say will run (because it parses as a listop), and so the output will be an empty line and then none (the return value of the inner say call).

More generally, the mere presence of listops would turn a simple "mention" of any function fn into a call fn(). Any term directly after that would start parsing as an argumentlist. (Aside: it'd be interesting to just try to change the parser to do this in a branch, and see how big of a fraction of the current 007 code base breaks.)

I suggest &fn as the syntax for getting the current behavior back, of referring to a function without calling it. Of course, this syntax is borrowed from Perl 6, even though 007 doesn't consider &fn to be the "real name" of fn. I'll also note that I'm sad about this change, because I feel it's very natural the way JavaScript and Python just refer to a function by name. So I'm not at all convinced.

vendethiel commented 5 years ago

I'll also note that I'm sad about this change, because I feel it's very natural the way JavaScript and Python just refer to a function by name. So I'm not at all convinced.

So am I. I think CoffeeScript made the right call here, as opposed to Perl/Ruby.

masak commented 5 years ago

This is also the main reason I rejected listops from the get-go with 007.

It seems that there are language design pressures that apply in both directions, so to speak. #300 paints an attractive picture with and, or, and not. It's maybe not immediately clear that that leads to having to drop the fn syntax for function references, but it does seem inevitable. So either we like that syntax more than we like #300, or we like #300 more than we like that syntax.