LiveScript icon indicating copy to clipboard operation
LiveScript copied to clipboard

Macros - working proof of concept implementation

Open bartosz-m opened this issue 8 years ago • 6 comments

I recently cleaned up my little side project that I made some time ago - proof of concept "implementation" of macros for livescript. It is build as a hack on top of compiler and do not modify any single existing file.
It threats macros as normal functions that return valid livescript code which is compiled and injected back into AST.

Right now it can transform this code:

swap! = (a,b) -> """
    tmp = #a
    #a = #b
    #b = tmp
"""
define! = (x) -> "var #x"

import-all! = (_module) ->
    module-url = if _module.0 == "'"
        then _module
        else "\"#_module\""
    "``import * from #module-url``"


esm-export! = (a,b) ->
    if b?
      if a != "'default'"
          throw Error "Cannot rename export #b to #a. Renaming exports is not supported yet"
      "``export default #b``"
    else
        "export #a"

define! d
x = 12
y = 1
swap! x, y
console.log x, y
import-all! os
esm-export! \default, d

into this one:

var d, x, y, tmp;
x = 12;
y = 1;
tmp = x;
x = y;
y = tmp;;
console.log(x, y);
import * from "os";
export default d;

In coming days I won't have much time to spend (need to find job and other stuff), so I hope maybe someone from community would be interested in transforming this little project into something really usable e.g. implementing working es6 modules as macros shouldn't be much hassle

If anyone is interested, code is on branch macros of my fork

bartosz-m avatar Oct 17 '17 01:10 bartosz-m

This is interesting. Did you take a look at BlackCoffee? I'm really interested in dealing with AST, not text (codeToNode).

vendethiel avatar Oct 17 '17 17:10 vendethiel

I wasn't aware of BlackCoffe, it looks really cool, if I knew about it earlier I would be very interested. Now I'm pursuing something rather different (building programs using a high-level graph-like structures - RDF, hyper-graph etc.)
About AST, simple thinks are quite easy accomplished - I used AST manipulation to add top level await and implicit async functions through addons to livescript - but more complex stuff is not so pleasant without comprehensive documentation - tried to add es6 classes to livescript but gave up.

bartosz-m avatar Oct 17 '17 18:10 bartosz-m

This is a neat experiment. I'm sure you know this, but for anyone else who stumbles upon this thread: these macros aren't ‘hygenic’, and are thus more like C macros than Scheme, Racket, Rust, etc. macros. That means that, for example, if you use the swap! macro defined above but you also have a variable named tmp, it will get clobbered by the code inserted by swap!. That said, it is indeed an interesting proof of concept.

rhendric avatar Oct 22 '17 15:10 rhendric

Like you said those are not 'higenic' macros, but problems with variables names can easily be bypass by generating unique names

swap! = (a,b) ->
    probably-unique = -> performance.now!to-string!replace '.' ''
    tmp = "tmp_#{probably-unique!}"
    """
        #tmp = #a
        #a = #b
        #b = tmp
    """

or creating new scope


swap! = (a,b) ->"""
    do !->
        tmp = #a
        #a := #b
        #b := tmp
"""

Of course it would be better to provide a way to lookup identifiers used in current scope to be sure that there is no collision.

bartosz-m avatar Oct 22 '17 16:10 bartosz-m

It'd be useful to expose a "gensym" facility (a term from the Lisp world).

vendethiel avatar Oct 22 '17 19:10 vendethiel

Cool PoC!

ozra avatar Oct 25 '17 18:10 ozra