Index of all namespaces
code-walking without caveats
Walker is my name and I am the same. Riddley Walker. Walking my riddels where ever theyve took me and walking them now on this paper the same.
from Riddley Walker by Russell Hoban
Code may be data, but only some of that data is executable. If we want to perform a pervasive code transformation, using something like
clojure.walk presents a few problems:
- binding forms are treated the same as actual expressions
clojure.walk/macroexpand-allwill pass in a nil
&envto all macros
- macroexpansion doesn’t expand inlined functions
This means that transforms that we intend to apply to expressions may have unintended consequences on a
case form. It also means that any macro which relies on
&env will not compose with our transformation. Finally, if inlined functions aren’t expanded, certain transformations will break.
Riddley provides a correct
riddley.walk/macroexpand-all, which preserves the binding information in
&env and expands inlined functions, and
riddley.walk/walk-exprs, which is a general mechanism for code walking and transformation.
walk-exprs takes two arguments, a
predicate for whether it should transform the sub-form, and a
handler for doing the transformation.
riddley.walk> (walk-exprs number? inc '(let [n 1] (+ n 1))) (let* [n 2] (. clojure.lang.Numbers (add n 2)))
walk-exprs implicitly macroexpands the form, including the inline form for
handler is called, sub-forms will not be walked. The handler function is responsible for recursively calling
walk-exprs on the form it’s handed.
&env is available via
(riddley.compiler/locals) if you need it as part of your transformation.
Full documentation can be found here.
Copyright © 2013 Zachary Tellman
Distributed under the MIT License.