Hi Nils, Thanks for the link, I hadn't seen that before. Happily, what you describe is pretty much exactly what Riddley does, in this case by accessing the compiler internals. An example of how macrolet or symbol-macrolet could be implemented using this is linked above in my response to Konrad. This means that macros which rely on the clojure.lang.Compiler$LocalBinding (which includes [1] and [2]) will still work. As far as I can tell, this is not the case in either tools.macro or core.async.
If you know of any ways to make the code-walking more complete, please let me know. Zach [1] https://github.com/ztellman/proteus/blob/master/src/proteus.clj#L60 [2] https://github.com/flatland/useful/blob/develop/src/flatland/useful/datatypes.clj#L62 On Thu, Sep 5, 2013 at 3:31 AM, bertschi <nils.bertschin...@googlemail.com>wrote: > Hi Zach, > > you might want to look at this paper explaining how to write a correct > macroexpand-all (which requires a code walker) in Common Lisp: > http://www.merl.com/publications/TR1993-017/ > > The compiler certainly has to do something like that, but might not do all > of the macroexpansion before starting any compilation as Konrad explained. > What the compiler needs to do is track the lexical environment while > walking down the source forms. When a code walker wants to introduce > additional bindings, such as macrolet (for local macros) or symbol-macrolet > (for new symbols) it needs to be able to extend the environment > accordingly. So, you either have to access the compiler internals, > especially its environment handling, or track the environment yourself (as > Konrad suggested). > As an aside: The problem in Common Lisp is mainly that the environment > handling is not exposed in the standard, thus you cannot write a portable > code walker without doing some environment handling yourself. > > You might also want to look at core.async, which uses a code walker to > transform go blocks into state machines. I have not (yet) checked its > restrictions (someone told me, that it cannot even look into anonymous fn > forms within its body!), but it is generally very hard to write a code > walker that can handle all special forms (in Common Lisp I don't know any). > > +10 for having a library that supports writing correct and (almost) > complete code walkers > > Best, > > Nils > > On Thursday, September 5, 2013 12:09:28 PM UTC+2, Konrad Hinsen wrote: >> >> Zach Tellman writes: >> >> > I guess I'm confused, then. You contrast "complete recursive >> > expansion" with what the compiler does, and then say it's recursive >> > prewalk expansion, which is exactly what the compiler does. Can >> > you clarify the difference between what you're doing and what the >> > compiler does? >> >> Here's an example: >> >> (defmacro foo [x] >> `(list ~x ~x)) >> >> (defmacro bar [x] >> `[~x ~x]) >> >> Now let's work on the form >> >> (foo (bar 'baz)) >> >> Plain macroexpand returns >> >> (list (bar 'baz) (bar 'baz)) >> >> whereas tools.macro/mexpand-all gives >> >> (list ['baz 'baz] ['baz 'baz]) >> >> It does this by first calling macroexpand, so foo gets called exactly >> as during Clojure compilation and returns >> >> (list (bar 'baz) (bar 'baz)) >> >> mexpand-all then goes through that form and expands the two subforms >> (bar 'baz). >> >> So mexpand-all does exactly what the compiler does, in particular it >> calls the macros with exactly the same arguments. But the compiler >> interleaves macro expansion with compilation, so it never gives you >> access to the fully expanded but uncompiled form which is >> >> (list ['baz 'baz] ['baz 'baz]) >> >> Konrad >> > -- > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to a topic in the > Google Groups "Clojure" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/clojure/a68aThpvP4o/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.