/
macroexpand.clj
57 lines (50 loc) · 1.81 KB
/
macroexpand.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
(ns clj-kondo.impl.macroexpand
(:require
[clj-kondo.impl.utils :refer [some-call filter-children]]
[clojure.walk :refer [prewalk]]
[rewrite-clj.node.protocols :as node :refer [tag]]
[rewrite-clj.node.seq :refer [vector-node list-node]]
[rewrite-clj.node.token :refer [token-node]]))
;;;; macro expand
(defn expand-> [{:keys [:children] :as expr}]
(let [children (rest children)]
(loop [[child1 child2 & children :as all-children] children]
(if child2
(if (= :list (node/tag child2))
(recur
(let [res (into
[(with-meta
(list-node (reduce into
[[(first (:children child2))]
[child1] (rest (:children child2))]))
(meta child2))] children)]
res))
(recur (into [(with-meta (list-node [child2 child1])
(meta child2))] children)))
child1))))
(defn find-fn-args [children]
(filter-children #(and (= :token (tag %))
(:string-value %)
(re-matches #"%\d?\d?" (:string-value %)))
children))
(defn expand-fn [{:keys [:children] :as expr}]
(let [fn-body (list-node children)
args (find-fn-args children)
arg-list (vector-node args)]
(list-node [(token-node 'fn) arg-list fn-body])))
(defn expand-all [expr]
(clojure.walk/prewalk
#(if (:children %)
(assoc % :children
(map (fn [n]
(cond (some-call n ->)
(expand-> n)
(= :fn (node/tag n))
(expand-fn n)
:else n))
(:children %)))
%)
expr))
;;;; Scratch
(comment
)