Skip to content

Commit 4bd3bcc

Browse files
arrdembronsa
authored andcommitted
Implement write-class and wire it into eval, load
This commit implements a write-class function (extracted from Oxcart) and wires it into the eval and load implementations as appropriate creating :compile-files kw options on both functions the default value for which is false. Fixes TEMJVM-15 Default to false iff *compile-files* isn't bound This changes the behavior of the :compile-files keyword option so that rather than defaulting to false if unset, if *compile-files* is bound that value will be propigated. Only if :compile-files is not provided and *compile-files* is unbound will the default value of false occur.
1 parent 7c8ade5 commit 4bd3bcc

File tree

1 file changed

+55
-16
lines changed
  • src/main/clojure/clojure/tools/emitter

1 file changed

+55
-16
lines changed

src/main/clojure/clojure/tools/emitter/jvm.clj

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,29 @@
3131
[clojure.tools.reader.reader-types :as readers])
3232
(:import (clojure.lang IFn DynamicClassLoader Atom)))
3333

34+
(defn write-class
35+
"(λ ClassName → Bytecode) → Nil
36+
37+
Writes the given bytecode to a file named by the ClassName and
38+
*compile-path*. Requires that *compile-path* be set. Returns Nil."
39+
[name bytecode]
40+
{:pre [(bound? #'clojure.core/*compile-path*)]}
41+
(let [path (str *compile-path* "/" name ".class")
42+
file (io/file path)]
43+
(.mkdirs (io/file (.getParent file)))
44+
(with-open [w (java.io.FileOutputStream. path)]
45+
(.write w bytecode)))
46+
nil)
47+
3448
(defn compile-and-load
3549
([class-ast]
3650
(compile-and-load class-ast (clojure.lang.RT/makeClassLoader)))
3751
([{:keys [class-name] :as class-ast} class-loader]
38-
(.defineClass ^DynamicClassLoader class-loader class-name (t/-compile class-ast) nil)))
52+
(let [bytecode (t/-compile class-ast)]
53+
(when (and (bound? #'clojure.core/*compile-files*)
54+
*compile-files*)
55+
(write-class class-name bytecode))
56+
(.defineClass ^DynamicClassLoader class-loader class-name bytecode nil))))
3957

4058

4159
(def passes (into (disj a/default-passes #'trim)
@@ -77,15 +95,27 @@
7795
:analyze-opts :- (Option analyze-options-map)
7896
An options map that will be passed to the analyzer. The keys which
7997
are significant in this map are documented in the t.a.jvm/analyze
80-
docstring."
98+
docstring.
99+
100+
:class-loader :- (Option ClassLoader)
101+
An optional classloader into which compiled functions will be
102+
injected. If not provided, a new Clojure classloader will be
103+
used. If a class loader is provided here, one need not be provided
104+
in eval-opts.
105+
106+
:compile-files :- (Option Bool)
107+
Enables or disables writing classfiles for generated classes. False
108+
by default."
81109

82110
([form]
83111
(eval form {}))
84-
([form {:keys [debug? emit-opts class-loader analyze-opts]
85-
:or {debug? false
86-
emit-opts {}
87-
analyze-opts a/default-passes-opts
88-
class-loader (clojure.lang.RT/makeClassLoader)}
112+
([form {:keys [debug? emit-opts class-loader analyze-opts compile-files]
113+
:or {debug? false
114+
emit-opts {}
115+
analyze-opts a/default-passes-opts
116+
compile-files (if (bound? #'clojure.core/*compile-files*)
117+
*compile-files* false)
118+
class-loader (clojure.lang.RT/makeClassLoader)}
89119
:as options}]
90120
{:pre [(instance? DynamicClassLoader class-loader)]}
91121
(let [mform (binding [macroexpand-1 a/macroexpand-1]
@@ -98,7 +128,8 @@
98128
(doseq [expr statements]
99129
(eval expr options))
100130
(eval ret options))
101-
(binding [a/run-passes run-passes]
131+
(binding [a/run-passes run-passes
132+
*compile-files* compile-files]
102133
(let [cs (-> (a/analyze `(^:once fn* [] ~mform) (a/empty-env) analyze-opts)
103134
(e/emit-classes (merge {:debug? debug?} emit-opts)))
104135
classes (mapv #(compile-and-load % class-loader) cs)]
@@ -130,14 +161,20 @@
130161
An optional classloader into which compiled functions will be
131162
injected. If not provided, a new Clojure classloader will be
132163
used. If a class loader is provided here, one need not be provided
133-
in eval-opts."
164+
in eval-opts.
165+
166+
:compile-files :- (Option Bool)
167+
Enables or disables writing classfiles for generated classes. False
168+
by default."
134169

135170
([res]
136171
(load res {}))
137-
([res {:keys [debug? eval-opts class-loader]
138-
:or {debug? false
139-
eval-opts {}
140-
class-loader (clojure.lang.RT/makeClassLoader)}
172+
([res {:keys [debug? eval-opts class-loader compile-files]
173+
:or {debug? false
174+
eval-opts {}
175+
compile-files (if (bound? #'clojure.core/*compile-files*)
176+
*compile-files* false)
177+
class-loader (clojure.lang.RT/makeClassLoader)}
141178
:as options}]
142179
(let [p (str (apply str (replace {\. \/ \- \_} res)) ".clj")
143180
eof (Object.)
@@ -146,13 +183,15 @@
146183
(subs (str (root-directory (ns-name *ns*)) "/" p) 1))
147184
file (-> p io/resource io/reader slurp)
148185
reader (readers/indexing-push-back-reader file 1 p)]
149-
(binding [*ns* *ns*
150-
*file* p]
186+
(binding [*ns* *ns*
187+
*file* p
188+
*compile-files* compile-files]
151189
(loop []
152190
(let [form (r/read reader false eof)]
153191
(when (not= eof form)
154192
(eval form (merge eval-opts
155193
(when class-loader
156-
{:class-loader class-loader})))
194+
{:class-loader class-loader
195+
:compile-files compile-files})))
157196
(recur))))
158197
nil))))

0 commit comments

Comments
 (0)