Skip to content

Commit 9581fb2

Browse files
author
Yannick Scherer
committed
fix conversion of :fn node to sexpr.
1 parent 274d7ca commit 9581fb2

File tree

3 files changed

+97
-6
lines changed

3 files changed

+97
-6
lines changed

src/rewrite_clj/node.clj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
(:require [rewrite-clj.node
55
coerce
66
comment
7+
fn
78
forms
89
integer
910
keyword
@@ -39,6 +40,9 @@
3940
comment-node
4041
comment?]
4142

43+
[rewrite-clj.node.fn
44+
fn-node]
45+
4246
[rewrite-clj.node.forms
4347
forms-node]
4448

@@ -55,7 +59,6 @@
5559
[rewrite-clj.node.reader-macro
5660
deref-node
5761
eval-node
58-
fn-node
5962
reader-macro-node
6063
uneval-node
6164
var-node]

src/rewrite_clj/node/fn.clj

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
(ns ^:no-doc rewrite-clj.node.fn
2+
(:require [rewrite-clj.node.protocols :as node]
3+
[clojure.walk :as w]))
4+
5+
;; ## Conversion
6+
7+
(defn- construct-fn
8+
"Construct function form."
9+
[syms vararg body]
10+
(list
11+
'fn*
12+
(vec
13+
(concat
14+
syms
15+
(if vararg
16+
(list '& vararg))))
17+
body))
18+
19+
(defn- sym-index
20+
"Get index based on the substring following the parameter's `%`.
21+
Zero means vararg."
22+
[^String n]
23+
(cond (= n "&") 0
24+
(= n "") 1
25+
(re-matches #"\d+" n) (Long/parseLong n)
26+
:else (throw (Exception. "arg literal must be %, %& or %integer."))))
27+
28+
(defn- symbol->gensym
29+
"If symbol starting with `%`, convert to respective gensym."
30+
[sym-seq vararg? max-n sym]
31+
(if (symbol? sym)
32+
(let [nm (name sym)]
33+
(if (.startsWith nm "%")
34+
(let [i (sym-index (subs nm 1))]
35+
(if (and (= i 0) (not (realized? vararg?)))
36+
(deliver vararg? true))
37+
(swap! max-n max i)
38+
(nth sym-seq i))))))
39+
40+
(defn- fn-walk
41+
"Walk the form and create an expand function form."
42+
[form]
43+
(let [syms (for [i (range)
44+
:let [base (if (= i 0)
45+
"rest__"
46+
(str "p" i "__"))
47+
s (name (gensym base))]]
48+
(symbol (str s "#")))
49+
vararg? (promise)
50+
max-n (atom 0)
51+
body (w/prewalk
52+
#(or (symbol->gensym syms vararg? max-n %) %)
53+
form)]
54+
(construct-fn
55+
(take @max-n (rest syms))
56+
(if (deref vararg? 0 nil)
57+
(first syms))
58+
body)))
59+
60+
;; ## Node
61+
62+
(defrecord FnNode [children]
63+
node/Node
64+
(tag [_] :fn)
65+
(printable-only? [_]
66+
false)
67+
(sexpr [_]
68+
(fn-walk (node/sexprs children)))
69+
(length [_]
70+
(+ 3 (node/sum-lengths children)))
71+
(string [_]
72+
(str "#(" (node/concat-strings children) ")"))
73+
74+
node/InnerNode
75+
(inner? [_]
76+
true)
77+
(children [_]
78+
children)
79+
(replace-children [this children']
80+
(assoc this :children children'))
81+
82+
Object
83+
(toString [this]
84+
(node/string this)))
85+
86+
(node/make-printable! FnNode)
87+
88+
;; ## Constructor
89+
90+
(defn fn-node
91+
"Create node representing an anonymous function."
92+
[children]
93+
(->FnNode children))

src/rewrite_clj/node/reader_macro.clj

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,6 @@
107107
(->node :var "'" "" #(list* 'var %) 1 children)
108108
(recur [children])))
109109

110-
(defn fn-node
111-
"Create node representing an anonymous function."
112-
[children]
113-
(->node :fn "(" ")" nil nil children))
114-
115110
(defn eval-node
116111
"Create node representing an inline evaluation. (`#=...`)
117112
Takes either a seq of nodes or a single one."

0 commit comments

Comments
 (0)