Arc Forumnew | comments | leaders | submitlogin
3 points by fallintothis 4984 days ago | link | parent

I finally looked over your code a bit. Thoughts:

- Harumph. Looking back, I notice my ssexpand-all doesn't strictly work right. Instead of considering the actual cases, I just special-cased quotes and quoted unquotes. Technically, these are wrong.

  arc> (ssexpand-all '`(a:b:c d))
  (quasiquote ((compose a b c) d))
  arc> (ssexpand-all '(fn (x:y) x:y))
  (fn ((compose x y)) (compose x y))
  arc> (ssexpand-all '(assign x:y z))
  (assign (compose x y) z)
ssexpand-all should have a similar shape to macex-all, though it's more complicated and probably doesn't help much.

  (def imap (f xs)
    (when xs
      (if (acons xs)
          (cons (f (car xs)) (imap f (cdr xs)))
          (f xs))))

  (def on-qq (f expr)
    (list 'quasiquote
          ((afn (level x)
             (if (is level 0)
                  (f x)
                 (atom x)
                  x
                 (is (car x) 'quasiquote)
                  (list car.x (self (+ level 1) cadr.x))
                 (in (car x) 'unquote 'unquote-splicing)
                  (list car.x (self (- level 1) cadr.x))
                  (imap [self level _] x)))
           1 (cadr expr))))

  (def ssexpand-all (expr)
    (if (ssyntax expr)
        (let expanded (ssexpand expr)
          (if (is expanded expr)
              expr
              (ssexpand-all expanded)))
        (check expr
               atom
               (case (car expr)
                 quasiquote (on-qq ssexpand-all expr)
                 fn         `(fn ,(cadr expr) ,@(imap ssexpand-all (cddr expr)))
                 assign     `(assign ,(expr 1) ,(ssexpand-all (expr 2)))
                 quote      expr
                            (imap ssexpand-all expr)))))
Bah. It feels like I've written this code about a million times. Gross.

- I notice you wind up copy/pasting a lot of arc.arc definitions, particularly for macros. Couldn't it be more general? I.e., add a clause like

  (isa (car s) 'mac)   (js (macex1 s))
to js1. I figure I'd want any ol' macro to expand, just so I could reuse existing code. Plus, this gives you all those verbatim arc.arc definitions for free. But you'd still want js-macs, since there are certain macros that shouldn't "spill over". E.g., the non-verbatim arc.arc definitions need to be tweaked for Javascript, but shouldn't be globally overwritten. You could make js-macs take priority over regular macros by checking for them first in js1, and still reduce copy/paste work. Would anything break from this?

- Really, the point about macros expands into a broader one. My first inclination is to model the compiler on ac.scm; once that's working, you get arc.arc & libs.arc for free just by cranking the compiler over them. Keyword collisions could be mitigated as in ac.scm, which prepends underscores to variable names.

  arc> x
  Error: "reference to undefined identifier: _x"
But this "compiler-oriented" approach might not work well. There are the Javascript keywords that you want to use from Arc without them getting treated like variables (mainly the reserved words). It's interesting because this project isn't just an Arc-to-Javascript compiler, but also a DSL for Javascript in Arc. So there needs to be some sort of balance.

There are more "overlap-y" examples like while. It's implemented as a macro in arc.arc, but you'd probably want to compile it down to Javascript's while instead of tail-recursive function calls. Also, some features don't line up quite right, like first-class continuations. Though you could compile them into Javascript (that'd be cool!), a big use for them is simply

  (catch
    (while t
      (throw)))
which in more idiomatic (and probably more efficient) Javascript would be a while/break. So it isn't just calls to something specific like while, but also entire patterns of code that overlap. In the limit, you have Arc compile to complex Javascript, but I don't know how well Javascript handles as a target language for some of the crazier features like continuations.

I'm curious if you've tried this approach at all and, if so, how it panned out (I've never tried anything like it myself, so I wouldn't know).

Good work so far!



1 point by evanrmurphy 4984 days ago | link

As I was going through copy-pasting and tweaking definitions from arc.arc, I thought several times that there should be a smart way to automate the process. (And it is true that a large portion of the defs and macs are verbatim.)

For a long time I didn't have js-mac and wasn't using js-def. Each macro got a handwritten js-<insert name> function and its own branch in js1's if; each function was handwritten in Javascript. [http://arclanguage.org/item?id=11918] I finally got smart enough to start using the partially bootstrapped compiler, and abstracting away the verbatim definitions should follow from that.

You could make js-macs take priority over regular macros by checking for them first in js1, and still reduce copy/paste work. Would anything break from this?

I do think that will be the way to do it, and it shouldn't break anything.

It's interesting because this project isn't just an Arc-to-Javascript compiler, but also a DSL for Javascript in Arc.

I knew this was true but hadn't yet found a way to articulate it. Thanks for the good choice of words.

There are more "overlap-y" examples like while. It's implemented as a macro in arc.arc, but you'd probably want to compile it down to Javascript's while instead of tail-recursive function calls.

Yes. Since resources are so precious in the browser and Javascript doesn't optimize tail calls, this will probably be an important refinement. As a bonus, it may make the compiled js more readable, since (while foo bar) would be generating something like while(foo){bar;}, rather than:

  (function(g3701){
    return g3701=(function(g3702){
      return (g3702?function(){bar;return g3701(foo);})['call'](this):nil);
    });
  })['call'](this,nil)(foo);
Also, some features don't line up quite right, like first-class continuations...

Your idea of compiling the common case to while/break sounds fine, but wouldn't try/catch be suitable as well? (I haven't made enough use of either first-class continuations or Javascript's try/catch to know yet.) There have been some cases I've dealt with already where the features didn't quite line up: rest/optional parms for functions, conses/lists vs. arrays and nil vs. false/null/undefined.

Thanks for the valuable feedback.

-----

1 point by rocketnia 4984 days ago | link

(fallintothis) It's interesting because this project isn't just an Arc-to-Javascript compiler, but also a DSL for Javascript in Arc.

(evanrmurphy) I knew this was true but hadn't yet found a way to articulate it. Thanks for the good choice of words.

I was also impressed by that choice of words. XD

-

wouldn't try/catch be suitable as well?

That's what I would use. That way a continuation could be called from within a (do ...) boundary.

-----