Arc Forumnew | comments | leaders | submitlogin
1 point by almkglor 5862 days ago | link | parent

Arc's macros are not perfectly first-class: they expand only if they're defined in the global namespace at the time the code is compiled. Try this:

  (mac my-mac () t)
  (def foo ()
     (my-mac))
  (mac my-mac () nil)
  (foo)
or even this:

  (def foo ()
    (my-mac))
  (mac my-mac ()
       '(prn "foo!"))
  (foo) ;this last will also depend on whether you're on Anarki or ArcN
So basically, you need to determine if a global would be assigned with a macro somehow, save the macro-code, and at macro-expansion time detect the macros and execute the macro-code in, say, an Arc interpreter.


1 point by binx 5862 days ago | link

In principle, whether a global variable will be assigned with a macro is impossible to detemine. Arc doesn't distinguish the run-time global environment and the expand-time global environment, so you still have to carry the source information to keep the semantics of Arc-n...

-----

3 points by almkglor 5862 days ago | link

Yes you can - remember that macros must be assigned to global variables before they are used.

So what we do is, we use our own 'eval (this should be easy, this is a lisp after all). However, this 'eval's 'set must determine if it's assigning to a global or a local (again, this should be easy, since it has to know what to write where). Then it checks if a global assign is that of a macro.

For each top-level form, we 'eval the form and check if any global assign is a macro assign. Now we know if a macro has been assigned to a global. Then we compile the form.

The alternative is simply to check if a form has 'mac anywhere in it. If it has (mac ...) or (annotate 'mac ...) anywhere, we run this in 'eval instead of compiling that form.

Really, though, we don't need to keep the semantics of Arc completely. We can add a few rules for macro writers: Always use 'mac. Don't use anything other than the built-in functions, or if you really need a non-builtin function for your macro, then put it in a 'let form together with your macro, and put two copies of the 'let form.

Alternatively, we could just make a REPL for Arc, in Arc, write it in a form suitable for compilation, and then write the compiler in a form compatible with the REPL and arcN.

      ___
     v   \
  REPL    compiler
     \___^
Besides: having some macros is better than having no macros.

-----

1 point by binx 5862 days ago | link

You can't eval each top-level form in compile-time. They may have side-effects, may expect user inputs, and may terminate in weeks(for example, a program doing ray-tracing or nuclear-explosion simulation).

Explicitely distinguish expand-time and run-time is necessary for real static compilation. If you don't want to distinguish them, you are inevitably forced to do compilation in run-time.

-----

1 point by almkglor 5862 days ago | link

> You can't eval each top-level form in compile-time. They may have side-effects, may expect user inputs, and may terminate in weeks(for example, a program doing ray-tracing or nuclear-explosion simulation).

And you're compiling (not executing) a top-level form that does those things?

All right then - make the limitation that macros must be defined in their own top-level forms, and if a top-level form ever contains 'mac in a function position, or (annotate 'mac ...), then it's executed and any macros it assigns to globals are treated as such: macros. If it terminates in weeks, too bad.

Alternatively just write an interpreted REPL and include the ability to compile code, but not include macros in compilation - macros must be loaded into the REPL, then the actual runnable code is compiled (and the compiled code's macros are ignored).

Anything just to get macros.

-----