Problem
The AST nodes produced by the ClojureScript analyzer have a :children key to allow generic traversals. Unfortunately, this key is currently a denormalized view of child ast nodes.
For example, an :if node has :test, :then, and :else keys whose values are also contained in :children. This presents some difficulty when writing AST transformations because every transform function must be aware of this duplication. To correctly replace the :test of an :if node, you must also replace the first element of the :children vector.
Discussion
- https://groups.google.com/d/topic/clojure-dev/vZLVKmKX0oc/discussion
- https://docs.google.com/document/d/1DRN-tBIqhqVVyoHIDs7CMkduBFk-vqd_958ojeIBLHQ/edit
- http://dev.clojure.org/jira/browse/CLJS-289
Design
- Solution must retain "AST is just data" property. ie No API should be required to interpret it
- Idea: store :children as keys into the AST map
- would be nice: (defn children [ast] ((apply juxt (:children ast)) ast))
- but need to handle implicit do blocks: (defn children [ast](mapcat #(if (coll? %) % [%]) ((apply juxt (:children ast)) ast)))
- ticket: http://dev.clojure.org/jira/browse/CLJS-289
- outstanding issue: interleaved bindings
- would be nice: (defn children [ast] ((apply juxt (:children ast)) ast))
- Alternate idea: all child nodes are moved from the top level into a map in :children
- For "if" this would change {:op :if :env {env} :test test-expr :then then-expr :else else-expr :children [test-expr then-expr else-expr]} into {:op :if :env {env} :children {:test test-expr :then then-expr :else else-expr}}
Labels: