clementine 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +4 -2
  3. data/LICENSE.txt +22 -0
  4. data/README.md +11 -6
  5. data/Rakefile +22 -0
  6. data/clementine.gemspec +2 -1
  7. data/ext/clojure-clojurescript-bef56a7/.gitignore +13 -0
  8. data/ext/clojure-clojurescript-bef56a7/Clojurescript.iml +12 -0
  9. data/ext/clojure-clojurescript-bef56a7/README.md +29 -0
  10. data/ext/clojure-clojurescript-bef56a7/benchmark/cljs/benchmark_runner.cljs +155 -0
  11. data/ext/clojure-clojurescript-bef56a7/bin/cljsc +21 -0
  12. data/ext/clojure-clojurescript-bef56a7/bin/cljsc.bat +18 -0
  13. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/bin/cljsc.clj +0 -0
  14. data/ext/clojure-clojurescript-bef56a7/devnotes/README.org +35 -0
  15. data/ext/clojure-clojurescript-bef56a7/devnotes/bcrepl.org +13 -0
  16. data/ext/clojure-clojurescript-bef56a7/devnotes/cljs.org +500 -0
  17. data/ext/clojure-clojurescript-bef56a7/devnotes/corelib.org +583 -0
  18. data/ext/clojure-clojurescript-bef56a7/devnotes/day1.org +203 -0
  19. data/ext/clojure-clojurescript-bef56a7/devnotes/day2.org +44 -0
  20. data/ext/clojure-clojurescript-bef56a7/devnotes/talk.org +126 -0
  21. data/ext/clojure-clojurescript-bef56a7/devnotes/testing +13 -0
  22. data/ext/clojure-clojurescript-bef56a7/devnotes/todo.org +121 -0
  23. data/ext/clojure-clojurescript-bef56a7/epl-v10.html +261 -0
  24. data/ext/clojure-clojurescript-bef56a7/pom.template.xml +88 -0
  25. data/ext/clojure-clojurescript-bef56a7/samples/dom/.gitignore +2 -0
  26. data/ext/clojure-clojurescript-bef56a7/samples/dom/src/dom/test.cljs +48 -0
  27. data/ext/clojure-clojurescript-bef56a7/samples/dom/test.html +30 -0
  28. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/.gitignore +2 -0
  29. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/README.md +53 -0
  30. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externed-lib.js +7 -0
  31. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/externs.js +3 -0
  32. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-extern.html +14 -0
  33. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js-dev.html +18 -0
  34. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/hello-js.html +17 -0
  35. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/my-external-lib.js +3 -0
  36. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/core.cljs +9 -0
  37. data/ext/clojure-clojurescript-bef56a7/samples/hello-js/src/hello-js/extern-example.cljs +5 -0
  38. data/ext/clojure-clojurescript-bef56a7/samples/hello/.gitignore +2 -0
  39. data/ext/clojure-clojurescript-bef56a7/samples/hello/README.md +34 -0
  40. data/ext/clojure-clojurescript-bef56a7/samples/hello/hello-dev.html +18 -0
  41. data/ext/clojure-clojurescript-bef56a7/samples/hello/hello.html +13 -0
  42. data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/core.cljs +8 -0
  43. data/ext/clojure-clojurescript-bef56a7/samples/hello/src/hello/foo/bar.cljs +4 -0
  44. data/ext/clojure-clojurescript-bef56a7/samples/nodehello.cljs +18 -0
  45. data/ext/clojure-clojurescript-bef56a7/samples/nodels.cljs +17 -0
  46. data/ext/clojure-clojurescript-bef56a7/samples/repl/.gitignore +2 -0
  47. data/ext/clojure-clojurescript-bef56a7/samples/repl/README.md +101 -0
  48. data/ext/clojure-clojurescript-bef56a7/samples/repl/index.html +27 -0
  49. data/ext/clojure-clojurescript-bef56a7/samples/repl/src/repl/test.cljs +73 -0
  50. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/.gitignore +2 -0
  51. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/README.md +42 -0
  52. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index-advanced.html +80 -0
  53. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/index.html +88 -0
  54. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/reset.css +48 -0
  55. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/anneal.cljs +66 -0
  56. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/core.cljs +307 -0
  57. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/dom-helpers.cljs +95 -0
  58. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/layout.cljs +100 -0
  59. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/leaderboard.cljs +40 -0
  60. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/radial.cljs +91 -0
  61. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/showgraph.cljs +121 -0
  62. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/src/twitterbuzz/timeline.cljs +39 -0
  63. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/style.css +301 -0
  64. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/test_data.txt +1 -0
  65. data/ext/clojure-clojurescript-bef56a7/samples/twitterbuzz/tweet_maps.txt +1 -0
  66. data/ext/clojure-clojurescript-bef56a7/script/benchmark +30 -0
  67. data/ext/clojure-clojurescript-bef56a7/script/bootstrap +70 -0
  68. data/ext/clojure-clojurescript-bef56a7/script/browser-repl +16 -0
  69. data/ext/clojure-clojurescript-bef56a7/script/build +59 -0
  70. data/ext/clojure-clojurescript-bef56a7/script/clean +5 -0
  71. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library-third-party.pom.template +59 -0
  72. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/google-closure-library.pom.template +54 -0
  73. data/ext/clojure-clojurescript-bef56a7/script/closure-library-release/make-closure-library-jars.sh +87 -0
  74. data/ext/clojure-clojurescript-bef56a7/script/compile +41 -0
  75. data/ext/clojure-clojurescript-bef56a7/script/repl +13 -0
  76. data/ext/clojure-clojurescript-bef56a7/script/repl.bat +13 -0
  77. data/ext/clojure-clojurescript-bef56a7/script/repljs +15 -0
  78. data/ext/clojure-clojurescript-bef56a7/script/repljs.bat +14 -0
  79. data/ext/clojure-clojurescript-bef56a7/script/test +38 -0
  80. data/ext/clojure-clojurescript-bef56a7/script/test-compile +30 -0
  81. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/analyzer.clj +975 -0
  82. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/closure.clj +173 -73
  83. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/compiler.clj +1081 -0
  84. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/core.clj +1158 -0
  85. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl.clj +51 -25
  86. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/browser.clj +258 -0
  87. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/reflect.clj +75 -0
  88. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/clj/cljs/repl/rhino.clj +6 -5
  89. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/repl/server.clj +173 -0
  90. data/ext/clojure-clojurescript-bef56a7/src/clj/cljs/tagged_literals.clj +30 -0
  91. data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/core.cljs +7197 -0
  92. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs.cljs +1 -1
  93. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejs_externs.js +0 -0
  94. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/cljs/nodejscli.cljs +1 -1
  95. data/ext/clojure-clojurescript-bef56a7/src/cljs/cljs/reader.cljs +551 -0
  96. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/dom.cljs +59 -13
  97. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/event.cljs +0 -0
  98. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/net.cljs +8 -7
  99. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/browser/repl.cljs +2 -2
  100. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/core/reducers.cljs +298 -0
  101. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/data.cljs +162 -0
  102. data/ext/clojure-clojurescript-bef56a7/src/cljs/clojure/reflect.cljs +48 -0
  103. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/set.cljs +0 -0
  104. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/string.cljs +4 -10
  105. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/walk.cljs +0 -0
  106. data/{vendor/assets → ext/clojure-clojurescript-bef56a7}/src/cljs/clojure/zip.cljs +0 -0
  107. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test.cljs +7 -0
  108. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/binding_test_other_ns.cljs +3 -0
  109. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/core_test.cljs +1678 -0
  110. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test.cljs +11 -0
  111. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/import_test/foo.cljs +5 -0
  112. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/letfn_test.cljs +19 -0
  113. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test.cljs +6 -0
  114. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/macro_test/macros.clj +5 -0
  115. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test.cljs +14 -0
  116. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/bar.cljs +3 -0
  117. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/ns_test/foo.cljs +7 -0
  118. data/ext/clojure-clojurescript-bef56a7/test/cljs/cljs/reader_test.cljs +124 -0
  119. data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/data_test.cljs +22 -0
  120. data/ext/clojure-clojurescript-bef56a7/test/cljs/clojure/string_test.cljs +97 -0
  121. data/ext/clojure-clojurescript-bef56a7/test/cljs/foo/ns_shadow_test.cljs +9 -0
  122. data/ext/clojure-clojurescript-bef56a7/test/cljs/test_runner.cljs +26 -0
  123. data/lib/clementine.rb +3 -24
  124. data/lib/clementine/clojurescript_engine.rb +9 -48
  125. data/lib/clementine/clojurescript_engine/base.rb +15 -0
  126. data/lib/clementine/clojurescript_engine/jruby.rb +46 -0
  127. data/lib/clementine/{clojurescript_engine_mri.rb → clojurescript_engine/mri.rb} +17 -10
  128. data/lib/clementine/version.rb +1 -1
  129. data/test/clojurescript_engine_test.rb +36 -14
  130. metadata +177 -83
  131. data/vendor/assets/lib/clojure.jar +0 -0
  132. data/vendor/assets/lib/compiler.jar +0 -0
  133. data/vendor/assets/lib/goog.jar +0 -0
  134. data/vendor/assets/lib/js.jar +0 -0
  135. data/vendor/assets/src/clj/cljs/compiler.clj +0 -1341
  136. data/vendor/assets/src/clj/cljs/core.clj +0 -702
  137. data/vendor/assets/src/clj/cljs/repl/browser.clj +0 -341
  138. data/vendor/assets/src/cljs/cljs/core.cljs +0 -3330
  139. data/vendor/assets/src/cljs/cljs/reader.cljs +0 -360
@@ -34,6 +34,7 @@
34
34
  JavaScript or a deps file for use during development.
35
35
  "
36
36
  (:require [cljs.compiler :as comp]
37
+ [cljs.analyzer :as ana]
37
38
  [clojure.java.io :as io]
38
39
  [clojure.string :as string])
39
40
  (:import java.io.File
@@ -94,6 +95,55 @@
94
95
  (set-options opts compiler-options)
95
96
  compiler-options)))
96
97
 
98
+
99
+
100
+ (defn jar-entry-names* [jar-path]
101
+ (with-open [z (java.util.zip.ZipFile. jar-path)]
102
+ (doall (map #(.getName %) (enumeration-seq (.entries z))))))
103
+
104
+ (def jar-entry-names (memoize jar-entry-names*))
105
+
106
+ (defn find-js-jar
107
+ "finds js resources from a given path in a jar file"
108
+ [jar-path lib-path]
109
+ (doall
110
+ (map #(io/resource %)
111
+ (filter #(do
112
+ (and
113
+ (.startsWith % lib-path)
114
+ (.endsWith % ".js")))
115
+ (jar-entry-names jar-path)))))
116
+ (declare to-url)
117
+ (defn find-js-fs
118
+ "finds js resources from a path on the files system"
119
+ [path]
120
+ (let [file (io/file path)]
121
+ (when (.exists file)
122
+ (map to-url (filter #(.endsWith (.getName %) ".js") (file-seq (io/file path)))))))
123
+
124
+
125
+ (defn find-js-classpath
126
+ "finds all js files on the classpath matching the path provided"
127
+ [path]
128
+ (let [process-entry #(if (.endsWith % ".jar")
129
+ (find-js-jar % path)
130
+ (find-js-fs (str % "/" path)))
131
+ cpath-list (let [sysp (System/getProperty "java.class.path" )]
132
+ (if (.contains sysp ";")
133
+ (string/split sysp #";")
134
+ (string/split sysp #":")))]
135
+ (doall (reduce #(let [p (process-entry %2)]
136
+ (if p (concat %1 p) %1)) [] cpath-list))))
137
+
138
+ (defn find-js-resources [path]
139
+ "finds js resources in a given path on either the file system or
140
+ the classpath"
141
+ (let [file (io/file path)]
142
+ (if (.exists file)
143
+ (find-js-fs path)
144
+ (find-js-classpath path))))
145
+
146
+
97
147
  (defn load-externs
98
148
  "Externs are JavaScript files which contain empty definitions of
99
149
  functions which will be provided by the envorinment. Any function in
@@ -102,22 +152,24 @@
102
152
  Options may contain an :externs key with a list of file paths to
103
153
  load. The :use-only-custom-externs flag may be used to indicate that
104
154
  the default externs should be excluded."
105
- [{:keys [externs use-only-custom-externs target]}]
106
- (letfn [(filter-js [paths]
107
- (for [p paths f (file-seq (io/file p))
108
- :when (.endsWith (.toLowerCase (.getName f)) ".js")]
109
- (.getAbsolutePath f)))
110
- (add-target [ext]
111
- (if (= :nodejs target)
112
- (cons (.getFile (io/resource "cljs/nodejs_externs.js"))
113
- (or ext []))
114
- ext))
115
- (load-js [ext]
116
- (map #(js-source-file % (io/input-stream %)) ext))]
117
- (let [js-sources (-> externs filter-js add-target load-js)]
155
+ [{:keys [externs use-only-custom-externs target ups-externs]}]
156
+ (let [filter-cp-js (fn [paths]
157
+ (for [p paths u (find-js-classpath p)] u))
158
+ filter-js (fn [paths]
159
+ (for [p paths u (find-js-resources p)] u))
160
+ add-target (fn [ext]
161
+ (if (= :nodejs target)
162
+ (cons (io/resource "cljs/nodejs_externs.js")
163
+ (or ext []))
164
+ ext))
165
+ load-js (fn [ext]
166
+ (map #(js-source-file (.getFile %) (slurp %)) ext))]
167
+ (let [js-sources (-> externs filter-js add-target load-js)
168
+ ups-sources (-> ups-externs filter-cp-js load-js)
169
+ all-sources (concat js-sources ups-sources)]
118
170
  (if use-only-custom-externs
119
- js-sources
120
- (into js-sources (CommandLineRunner/getDefaultExterns))))))
171
+ all-sources
172
+ (into all-sources (CommandLineRunner/getDefaultExterns))))))
121
173
 
122
174
  (defn ^com.google.javascript.jscomp.Compiler make-closure-compiler []
123
175
  (let [compiler (com.google.javascript.jscomp.Compiler.)]
@@ -142,7 +194,7 @@
142
194
  (->> (for [line lines x (string/split line #";")] x)
143
195
  (map string/trim)
144
196
  (take-while #(not (re-matches #".*=[\s]*function\(.*\)[\s]*[{].*" %)))
145
- (map #(re-matches #".*goog\.(provide|require)\('(.*)'\)" %))
197
+ (map #(re-matches #".*goog\.(provide|require)\(['\"](.*)['\"]\)" %))
146
198
  (remove nil?)
147
199
  (map #(drop 1 %))
148
200
  (reduce (fn [m ns]
@@ -241,26 +293,36 @@
241
293
  state (reduce dependency-order-visit state deps)]
242
294
  (assoc state :order (conj (:order state) file))))))
243
295
 
296
+ (defn- pack-string [s]
297
+ (if (string? s)
298
+ {:provides (-provides s)
299
+ :requires (-requires s)
300
+ :file (str "from_source_" (gensym) ".clj")
301
+ ::original s}
302
+ s))
303
+
304
+ (defn- unpack-string [m]
305
+ (or (::original m) m))
306
+
244
307
  (defn dependency-order
245
308
  "Topologically sort a collection of dependencies."
246
309
  [coll]
247
- (let [state (build-index coll)]
248
- (distinct (:order (reduce dependency-order-visit (assoc state :order []) (keys state))))))
310
+ (let [state (build-index (map pack-string coll))]
311
+ (map unpack-string
312
+ (distinct
313
+ (:order (reduce dependency-order-visit (assoc state :order []) (keys state)))))))
249
314
 
250
315
  ;; Compile
251
316
  ;; =======
252
317
 
253
- (defn empty-env []
254
- {:ns (@comp/namespaces comp/*cljs-ns*) :context :statement :locals {}})
255
-
256
318
  (defn compile-form-seq
257
319
  "Compile a sequence of forms to a JavaScript source string."
258
320
  [forms]
259
321
  (comp/with-core-cljs
260
322
  (with-out-str
261
- (binding [comp/*cljs-ns* 'cljs.user]
323
+ (binding [ana/*cljs-ns* 'cljs.user]
262
324
  (doseq [form forms]
263
- (comp/emit (comp/analyze (empty-env) form)))))))
325
+ (comp/emit (ana/analyze (ana/empty-env) form)))))))
264
326
 
265
327
  (defn output-directory [opts]
266
328
  (or (:output-dir opts) "out"))
@@ -296,12 +358,11 @@
296
358
 
297
359
  (defn compile-dir
298
360
  "Recursively compile all cljs files under the given source
299
- directory. Return a list of JavaScriptFiles in dependency order."
361
+ directory. Return a list of JavaScriptFiles."
300
362
  [^File src-dir opts]
301
363
  (let [out-dir (output-directory opts)]
302
- (dependency-order
303
- (map compiled-file
304
- (comp/compile-root src-dir out-dir)))))
364
+ (map compiled-file
365
+ (comp/compile-root src-dir out-dir))))
305
366
 
306
367
  (defn path-from-jarfile
307
368
  "Given the URL of a file within a jar, return the path of the file
@@ -391,10 +452,11 @@
391
452
  "Given a library spec (a map containing the keys :file
392
453
  and :provides), returns a map containing :provides, :requires, :file
393
454
  and :url"
394
- [lib-spec]
395
- (merge lib-spec {:foreign true
396
- :requires nil
397
- :url (find-url (:file lib-spec))}))
455
+ ([lib-spec] (load-foreign-library* lib-spec false))
456
+ ([lib-spec cp-only?]
457
+ (let [find-func (if cp-only? io/resource find-url)]
458
+ (merge lib-spec {:foreign true
459
+ :url (find-func (:file lib-spec))}))))
398
460
 
399
461
  (def load-foreign-library (memoize load-foreign-library*))
400
462
 
@@ -402,20 +464,25 @@
402
464
  "Given a path to a JavaScript library, which is a directory
403
465
  containing Javascript files, return a list of maps
404
466
  containing :provides, :requires, :file and :url."
405
- [path]
406
- (letfn [(graph-node [f]
407
- (-> (io/reader f)
408
- line-seq
409
- parse-js-ns
410
- (assoc :file (.getPath f) :url (to-url f))))]
411
- (let [js-sources (filter #(.endsWith (.getName %) ".js") (file-seq (io/file path)))]
412
- (filter #(seq (:provides %)) (map graph-node js-sources)))))
467
+ ([path] (load-library* path false))
468
+ ([path cp-only?]
469
+ (let [find-func (if cp-only? find-js-classpath find-js-resources)
470
+ graph-node (fn [u]
471
+ (-> (io/reader u)
472
+ line-seq
473
+ parse-js-ns
474
+ (assoc :url u)))]
475
+ (let [js-sources (find-js-resources path)]
476
+ (filter #(seq (:provides %)) (map graph-node js-sources))))))
413
477
 
414
478
  (def load-library (memoize load-library*))
415
479
 
416
- (defn library-dependencies [{:keys [libs foreign-libs]}]
480
+ (defn library-dependencies [{libs :libs foreign-libs :foreign-libs
481
+ ups-libs :ups-libs ups-flibs :ups-foreign-libs}]
417
482
  (concat
483
+ (mapcat #(load-library % true) ups-libs) ;upstream deps
418
484
  (mapcat load-library libs)
485
+ (mapcat #(load-foreign-library % true) ups-flibs) ;upstream deps
419
486
  (map load-foreign-library foreign-libs)))
420
487
 
421
488
  (comment
@@ -457,8 +524,8 @@
457
524
 
458
525
  (defn js-dependencies
459
526
  "Given a sequence of Closure namespace strings, return the list of
460
- all dependencies in dependency order. The returned list includes all
461
- Google and third-party library dependencies.
527
+ all dependencies. The returned list includes all Google and
528
+ third-party library dependencies.
462
529
 
463
530
  Third-party libraries are configured using the :libs option where
464
531
  the value is a list of directories containing third-party
@@ -466,7 +533,7 @@
466
533
  [opts requires]
467
534
  (let [index (js-dependency-index opts)]
468
535
  (loop [requires requires
469
- visited requires
536
+ visited (set requires)
470
537
  deps #{}]
471
538
  (if (seq requires)
472
539
  (let [node (get index (first requires))
@@ -474,7 +541,7 @@
474
541
  (recur (into (rest requires) new-req)
475
542
  (into visited new-req)
476
543
  (conj deps node)))
477
- (cons (get index "goog/base.js") (dependency-order deps))))))
544
+ (remove nil? deps)))))
478
545
 
479
546
  (comment
480
547
  ;; find dependencies
@@ -492,11 +559,10 @@
492
559
 
493
560
  (defn cljs-dependencies
494
561
  "Given a list of all required namespaces, return a list of
495
- IJavaScripts which are the cljs dependencies in dependency
496
- order. The returned list will not only include the explicitly
497
- required files but any transitive depedencies as well. JavaScript
498
- files will be compiled to the working directory if they do not
499
- already exist.
562
+ IJavaScripts which are the cljs dependencies. The returned list will
563
+ not only include the explicitly required files but any transitive
564
+ depedencies as well. JavaScript files will be compiled to the
565
+ working directory if they do not already exist.
500
566
 
501
567
  Only load dependencies from the classpath."
502
568
  [opts requires]
@@ -517,7 +583,7 @@
517
583
  (recur (into (rest required-files) new-req)
518
584
  (into visited new-req)
519
585
  (conj js-deps js)))
520
- (dependency-order js-deps))))))
586
+ (remove nil? js-deps))))))
521
587
 
522
588
  (comment
523
589
  ;; only get cljs deps
@@ -534,15 +600,17 @@
534
600
  plus all dependencies in dependency order."
535
601
  [opts & inputs]
536
602
  (let [requires (mapcat -requires inputs)
537
- required-cljs (cljs-dependencies opts requires)
603
+ required-cljs (remove (set inputs) (cljs-dependencies opts requires))
538
604
  required-js (js-dependencies opts (set (concat (mapcat -requires required-cljs) requires)))]
539
- (concat (map #(-> (javascript-file (:foreign %)
540
- (or (:url %) (io/resource (:file %)))
541
- (:provides %)
542
- (:requires %))
543
- (assoc :group (:group %))) required-js)
544
- required-cljs
545
- inputs)))
605
+ (cons (javascript-file nil (io/resource "goog/base.js") ["goog"] nil)
606
+ (dependency-order
607
+ (concat (map #(-> (javascript-file (:foreign %)
608
+ (or (:url %) (io/resource (:file %)))
609
+ (:provides %)
610
+ (:requires %))
611
+ (assoc :group (:group %))) required-js)
612
+ required-cljs
613
+ inputs)))))
546
614
 
547
615
  (comment
548
616
  ;; add dependencies to literal js
@@ -600,6 +668,9 @@
600
668
  (let [closure-compiler (make-closure-compiler)
601
669
  externs (load-externs opts)
602
670
  compiler-options (make-options opts)
671
+ sources (if (= :whitespace (:optimizations opts))
672
+ (cons "var CLOSURE_NO_DEPS = true;" sources)
673
+ sources)
603
674
  inputs (map #(js-source-file (javascript-name %) %) sources)
604
675
  result ^Result (.compile closure-compiler externs inputs compiler-options)]
605
676
  (if (.success result)
@@ -771,31 +842,60 @@
771
842
  "goog.provide('test');\ngoog.require('cljs.core');\nalert('hello');\n")
772
843
  )
773
844
 
845
+
846
+ (defn get-upstream-deps*
847
+ "returns a merged map containing all upstream dependencies defined by libraries on the classpath"
848
+ []
849
+ (let [classloader (. (Thread/currentThread) (getContextClassLoader))
850
+ upstream-deps (map #(read-string (slurp %)) (enumeration-seq (. classloader (findResources "deps.cljs"))))]
851
+ (doseq [dep upstream-deps]
852
+ (println (str "Upstream deps.cljs found on classpath. " dep " This is an EXPERIMENTAL FEATURE and is not guarenteed to remain stable in future versions.")))
853
+ (apply merge-with concat upstream-deps)))
854
+
855
+ (def get-upstream-deps (memoize get-upstream-deps*))
856
+
774
857
  (defn add-header [{:keys [hashbang target]} js]
775
858
  (if (= :nodejs target)
776
- (str "#!" (or hashbang "/usr/bin/nodejs") "\n" js)
859
+ (str "#!" (or hashbang "/usr/bin/env node") "\n" js)
777
860
  js))
778
861
 
862
+ (defn add-wrapper [{:keys [output-wrapper] :as opts} js]
863
+ (if output-wrapper
864
+ (str ";(function(){\n" js "\n})();\n")
865
+ js))
866
+
779
867
  (defn build
780
868
  "Given a source which can be compiled, produce runnable JavaScript."
781
869
  [source opts]
870
+ (ana/reset-namespaces!)
782
871
  (let [opts (if (= :nodejs (:target opts))
783
872
  (merge {:optimizations :simple} opts)
784
873
  opts)
785
- compiled (-compile source opts)
786
- compiled (concat
787
- (if (coll? compiled) compiled [compiled])
788
- (when (= :nodejs (:target opts))
789
- [(-compile (io/resource "cljs/nodejscli.cljs") opts)]))
790
- js-sources (if (coll? compiled)
791
- (apply add-dependencies opts compiled)
792
- (add-dependencies opts compiled))]
793
- (if (:optimizations opts)
794
- (->> js-sources
795
- (apply optimize opts)
796
- (add-header opts)
797
- (output-one-file opts))
798
- (apply output-unoptimized opts js-sources))))
874
+ ups-deps (get-upstream-deps)
875
+ all-opts (assoc opts
876
+ :ups-libs (:libs ups-deps)
877
+ :ups-foreign-libs (:foreign-libs ups-deps)
878
+ :ups-externs (:externs ups-deps))]
879
+ (binding [ana/*cljs-static-fns*
880
+ (or (and (= (opts :optimizations) :advanced))
881
+ (:static-fns opts)
882
+ ana/*cljs-static-fns*)
883
+ ana/*cljs-warn-on-undeclared*
884
+ (true? (opts :warnings))]
885
+ (let [compiled (-compile source all-opts)
886
+ js-sources (concat
887
+ (apply add-dependencies all-opts
888
+ (if (coll? compiled) compiled [compiled]))
889
+ (when (= :nodejs (:target all-opts))
890
+ [(-compile (io/resource "cljs/nodejscli.cljs") all-opts)]))
891
+ optim (:optimizations all-opts)]
892
+ (if (and optim (not= optim :none))
893
+ (->> js-sources
894
+ (apply optimize all-opts)
895
+ (add-header all-opts)
896
+ (add-wrapper all-opts)
897
+ (output-one-file all-opts))
898
+ (apply output-unoptimized all-opts js-sources))))))
799
899
 
800
900
  (comment
801
901
 
@@ -0,0 +1,1081 @@
1
+ ; Copyright (c) Rich Hickey. All rights reserved.
2
+ ; The use and distribution terms for this software are covered by the
3
+ ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4
+ ; which can be found in the file epl-v10.html at the root of this distribution.
5
+ ; By using this software in any fashion, you are agreeing to be bound by
6
+ ; the terms of this license.
7
+ ; You must not remove this notice, or any other, from this software.
8
+
9
+ (set! *warn-on-reflection* true)
10
+
11
+ (ns cljs.compiler
12
+ (:refer-clojure :exclude [munge macroexpand-1])
13
+ (:require [clojure.java.io :as io]
14
+ [clojure.string :as string]
15
+ [cljs.tagged-literals :as tags]
16
+ [cljs.analyzer :as ana])
17
+ (:import java.lang.StringBuilder))
18
+
19
+ (declare munge)
20
+
21
+ (def js-reserved
22
+ #{"abstract" "boolean" "break" "byte" "case"
23
+ "catch" "char" "class" "const" "continue"
24
+ "debugger" "default" "delete" "do" "double"
25
+ "else" "enum" "export" "extends" "final"
26
+ "finally" "float" "for" "function" "goto" "if"
27
+ "implements" "import" "in" "instanceof" "int"
28
+ "interface" "let" "long" "native" "new"
29
+ "package" "private" "protected" "public"
30
+ "return" "short" "static" "super" "switch"
31
+ "synchronized" "this" "throw" "throws"
32
+ "transient" "try" "typeof" "var" "void"
33
+ "volatile" "while" "with" "yield" "methods"})
34
+
35
+ (def ^:dynamic *position* nil)
36
+ (def ^:dynamic *emitted-provides* nil)
37
+ (def cljs-reserved-file-names #{"deps.cljs"})
38
+
39
+ (defonce ns-first-segments (atom '#{"cljs" "clojure"}))
40
+
41
+ (defn munge
42
+ ([s] (munge s js-reserved))
43
+ ([s reserved]
44
+ (if (map? s)
45
+ ; Unshadowing
46
+ (let [{:keys [name field] :as info} s
47
+ depth (loop [d 0, {:keys [shadow]} info]
48
+ (cond
49
+ shadow (recur (inc d) shadow)
50
+ (@ns-first-segments (str name)) (inc d)
51
+ :else d))
52
+ name (if field
53
+ (str "self__." name)
54
+ name)]
55
+ (if (zero? depth)
56
+ (munge name reserved)
57
+ (symbol (str (munge name reserved) "__$" depth))))
58
+ ; String munging
59
+ (let [ss (string/replace (str s) #"\/(.)" ".$1") ; Division is special
60
+ ss (apply str (map #(if (reserved %) (str % "$") %)
61
+ (string/split ss #"(?<=\.)|(?=\.)")))
62
+ ms (clojure.lang.Compiler/munge ss)]
63
+ (if (symbol? s)
64
+ (symbol ms)
65
+ ms)))))
66
+
67
+ (defn- comma-sep [xs]
68
+ (interpose "," xs))
69
+
70
+ (defn- escape-char [^Character c]
71
+ (let [cp (.hashCode c)]
72
+ (case cp
73
+ ; Handle printable escapes before ASCII
74
+ 34 "\\\""
75
+ 92 "\\\\"
76
+ ; Handle non-printable escapes
77
+ 8 "\\b"
78
+ 12 "\\f"
79
+ 10 "\\n"
80
+ 13 "\\r"
81
+ 9 "\\t"
82
+ (if (< 31 cp 127)
83
+ c ; Print simple ASCII characters
84
+ (format "\\u%04X" cp))))) ; Any other character is Unicode
85
+
86
+ (defn- escape-string [^CharSequence s]
87
+ (let [sb (StringBuilder. (count s))]
88
+ (doseq [c s]
89
+ (.append sb (escape-char c)))
90
+ (.toString sb)))
91
+
92
+ (defn- wrap-in-double-quotes [x]
93
+ (str \" x \"))
94
+
95
+ (defmulti emit :op)
96
+
97
+ (defn emits [& xs]
98
+ (doseq [x xs]
99
+ (cond
100
+ (nil? x) nil
101
+ (map? x) (emit x)
102
+ (seq? x) (apply emits x)
103
+ (fn? x) (x)
104
+ :else (do
105
+ (let [s (print-str x)]
106
+ (when *position*
107
+ (swap! *position* (fn [[line column]]
108
+ [line (+ column (count s))])))
109
+ (print s)))))
110
+ nil)
111
+
112
+ (defn ^String emit-str [expr]
113
+ (with-out-str (emit expr)))
114
+
115
+ (defn emitln [& xs]
116
+ (apply emits xs)
117
+ ;; Prints column-aligned line number comments; good test of *position*.
118
+ ;(when *position*
119
+ ; (let [[line column] @*position*]
120
+ ; (print (apply str (concat (repeat (- 120 column) \space) ["// " (inc line)])))))
121
+ (println)
122
+ (when *position*
123
+ (swap! *position* (fn [[line column]]
124
+ [(inc line) 0])))
125
+ nil)
126
+
127
+ (defmulti emit-constant class)
128
+ (defmethod emit-constant nil [x] (emits "null"))
129
+ (defmethod emit-constant Long [x] (emits x))
130
+ (defmethod emit-constant Integer [x] (emits x)) ; reader puts Integers in metadata
131
+ (defmethod emit-constant Double [x] (emits x))
132
+ (defmethod emit-constant String [x]
133
+ (emits (wrap-in-double-quotes (escape-string x))))
134
+ (defmethod emit-constant Boolean [x] (emits (if x "true" "false")))
135
+ (defmethod emit-constant Character [x]
136
+ (emits (wrap-in-double-quotes (escape-char x))))
137
+
138
+ (defmethod emit-constant java.util.regex.Pattern [x]
139
+ (let [[_ flags pattern] (re-find #"^(?:\(\?([idmsux]*)\))?(.*)" (str x))]
140
+ (emits \/ (.replaceAll (re-matcher #"/" pattern) "\\\\/") \/ flags)))
141
+
142
+ (defmethod emit-constant clojure.lang.Keyword [x]
143
+ (emits \" "\\uFDD0" \'
144
+ (if (namespace x)
145
+ (str (namespace x) "/") "")
146
+ (name x)
147
+ \"))
148
+
149
+ (defmethod emit-constant clojure.lang.Symbol [x]
150
+ (emits \" "\\uFDD1" \'
151
+ (if (namespace x)
152
+ (str (namespace x) "/") "")
153
+ (name x)
154
+ \"))
155
+
156
+ (defn- emit-meta-constant [x & body]
157
+ (if (meta x)
158
+ (do
159
+ (emits "cljs.core.with_meta(" body ",")
160
+ (emit-constant (meta x))
161
+ (emits ")"))
162
+ (emits body)))
163
+
164
+ (defmethod emit-constant clojure.lang.PersistentList$EmptyList [x]
165
+ (emit-meta-constant x "cljs.core.List.EMPTY"))
166
+
167
+ (defmethod emit-constant clojure.lang.PersistentList [x]
168
+ (emit-meta-constant x
169
+ (concat ["cljs.core.list("]
170
+ (comma-sep (map #(fn [] (emit-constant %)) x))
171
+ [")"])))
172
+
173
+ (defmethod emit-constant clojure.lang.Cons [x]
174
+ (emit-meta-constant x
175
+ (concat ["cljs.core.list("]
176
+ (comma-sep (map #(fn [] (emit-constant %)) x))
177
+ [")"])))
178
+
179
+ (defmethod emit-constant clojure.lang.IPersistentVector [x]
180
+ (emit-meta-constant x
181
+ (concat ["cljs.core.vec(["]
182
+ (comma-sep (map #(fn [] (emit-constant %)) x))
183
+ ["])"])))
184
+
185
+ (defmethod emit-constant clojure.lang.IPersistentMap [x]
186
+ (emit-meta-constant x
187
+ (concat ["cljs.core.hash_map("]
188
+ (comma-sep (map #(fn [] (emit-constant %))
189
+ (apply concat x)))
190
+ [")"])))
191
+
192
+ (defmethod emit-constant clojure.lang.PersistentHashSet [x]
193
+ (emit-meta-constant x
194
+ (concat ["cljs.core.set(["]
195
+ (comma-sep (map #(fn [] (emit-constant %)) x))
196
+ ["])"])))
197
+
198
+ (defn emit-block
199
+ [context statements ret]
200
+ (when statements
201
+ (emits statements))
202
+ (emit ret))
203
+
204
+ (defmacro emit-wrap [env & body]
205
+ `(let [env# ~env]
206
+ (when (= :return (:context env#)) (emits "return "))
207
+ ~@body
208
+ (when-not (= :expr (:context env#)) (emitln ";"))))
209
+
210
+ (defmethod emit :no-op [m])
211
+
212
+ (defmethod emit :var
213
+ [{:keys [info env] :as arg}]
214
+ (let [n (:name info)
215
+ n (if (= (namespace n) "js")
216
+ (name n)
217
+ info)]
218
+ (emit-wrap env (emits (munge n)))))
219
+
220
+ (defmethod emit :meta
221
+ [{:keys [expr meta env]}]
222
+ (emit-wrap env
223
+ (emits "cljs.core.with_meta(" expr "," meta ")")))
224
+
225
+ (def ^:private array-map-threshold 16)
226
+ (def ^:private obj-map-threshold 32)
227
+
228
+ (defmethod emit :map
229
+ [{:keys [env simple-keys? keys vals]}]
230
+ (emit-wrap env
231
+ (cond
232
+ (zero? (count keys))
233
+ (emits "cljs.core.ObjMap.EMPTY")
234
+
235
+ (and simple-keys? (<= (count keys) obj-map-threshold))
236
+ (emits "cljs.core.ObjMap.fromObject(["
237
+ (comma-sep keys) ; keys
238
+ "],{"
239
+ (comma-sep (map (fn [k v]
240
+ (with-out-str (emit k) (print ":") (emit v)))
241
+ keys vals)) ; js obj
242
+ "})")
243
+
244
+ (<= (count keys) array-map-threshold)
245
+ (emits "cljs.core.PersistentArrayMap.fromArrays(["
246
+ (comma-sep keys)
247
+ "],["
248
+ (comma-sep vals)
249
+ "])")
250
+
251
+ :else
252
+ (emits "cljs.core.PersistentHashMap.fromArrays(["
253
+ (comma-sep keys)
254
+ "],["
255
+ (comma-sep vals)
256
+ "])"))))
257
+
258
+ (defmethod emit :vector
259
+ [{:keys [items env]}]
260
+ (emit-wrap env
261
+ (if (empty? items)
262
+ (emits "cljs.core.PersistentVector.EMPTY")
263
+ (emits "cljs.core.PersistentVector.fromArray(["
264
+ (comma-sep items) "], true)"))))
265
+
266
+ (defmethod emit :set
267
+ [{:keys [items env]}]
268
+ (emit-wrap env
269
+ (if (empty? items)
270
+ (emits "cljs.core.PersistentHashSet.EMPTY")
271
+ (emits "cljs.core.PersistentHashSet.fromArray(["
272
+ (comma-sep items) "])"))))
273
+
274
+ (defmethod emit :constant
275
+ [{:keys [form env]}]
276
+ (when-not (= :statement (:context env))
277
+ (emit-wrap env (emit-constant form))))
278
+
279
+ (defn get-tag [e]
280
+ (or (-> e :tag)
281
+ (-> e :info :tag)))
282
+
283
+ (defn infer-tag [e]
284
+ (if-let [tag (get-tag e)]
285
+ tag
286
+ (case (:op e)
287
+ :let (infer-tag (:ret e))
288
+ :if (let [then-tag (infer-tag (:then e))
289
+ else-tag (infer-tag (:else e))]
290
+ (when (= then-tag else-tag)
291
+ then-tag))
292
+ :constant (case (:form e)
293
+ true 'boolean
294
+ false 'boolean
295
+ nil)
296
+ nil)))
297
+
298
+ (defn safe-test? [e]
299
+ (let [tag (infer-tag e)]
300
+ (or (#{'boolean 'seq} tag)
301
+ (when (= (:op e) :constant)
302
+ (let [form (:form e)]
303
+ (not (or (and (string? form) (= form ""))
304
+ (and (number? form) (zero? form)))))))))
305
+
306
+ (defmethod emit :if
307
+ [{:keys [test then else env unchecked]}]
308
+ (let [context (:context env)
309
+ checked (not (or unchecked (safe-test? test)))]
310
+ (if (= :expr context)
311
+ (emits "(" (when checked "cljs.core.truth_") "(" test ")?" then ":" else ")")
312
+ (do
313
+ (if checked
314
+ (emitln "if(cljs.core.truth_(" test "))")
315
+ (emitln "if(" test ")"))
316
+ (emitln "{" then "} else")
317
+ (emitln "{" else "}")))))
318
+
319
+ (defmethod emit :throw
320
+ [{:keys [throw env]}]
321
+ (if (= :expr (:context env))
322
+ (emits "(function(){throw " throw "})()")
323
+ (emitln "throw " throw ";")))
324
+
325
+ (defn emit-comment
326
+ "Emit a nicely formatted comment string."
327
+ [doc jsdoc]
328
+ (let [docs (when doc [doc])
329
+ docs (if jsdoc (concat docs jsdoc) docs)
330
+ docs (remove nil? docs)]
331
+ (letfn [(print-comment-lines [e] (doseq [next-line (string/split-lines e)]
332
+ (emitln "* " (string/trim next-line))))]
333
+ (when (seq docs)
334
+ (emitln "/**")
335
+ (doseq [e docs]
336
+ (when e
337
+ (print-comment-lines e)))
338
+ (emitln "*/")))))
339
+
340
+ (defmethod emit :def
341
+ [{:keys [name init env doc export]}]
342
+ (when init
343
+ (let [mname (munge name)]
344
+ (emit-comment doc (:jsdoc init))
345
+ (emits mname)
346
+ (emits " = " init)
347
+ (when-not (= :expr (:context env)) (emitln ";"))
348
+ (when export
349
+ (emitln "goog.exportSymbol('" (munge export) "', " mname ");")))))
350
+
351
+ (defn emit-apply-to
352
+ [{:keys [name params env]}]
353
+ (let [arglist (gensym "arglist__")
354
+ delegate-name (str (munge name) "__delegate")
355
+ params (map munge params)]
356
+ (emitln "(function (" arglist "){")
357
+ (doseq [[i param] (map-indexed vector (butlast params))]
358
+ (emits "var " param " = cljs.core.first(")
359
+ (dotimes [_ i] (emits "cljs.core.next("))
360
+ (emits arglist ")")
361
+ (dotimes [_ i] (emits ")"))
362
+ (emitln ";"))
363
+ (if (< 1 (count params))
364
+ (do
365
+ (emits "var " (last params) " = cljs.core.rest(")
366
+ (dotimes [_ (- (count params) 2)] (emits "cljs.core.next("))
367
+ (emits arglist)
368
+ (dotimes [_ (- (count params) 2)] (emits ")"))
369
+ (emitln ");")
370
+ (emitln "return " delegate-name "(" (string/join ", " params) ");"))
371
+ (do
372
+ (emits "var " (last params) " = ")
373
+ (emits "cljs.core.seq(" arglist ");")
374
+ (emitln ";")
375
+ (emitln "return " delegate-name "(" (string/join ", " params) ");")))
376
+ (emits "})")))
377
+
378
+ (defn emit-fn-method
379
+ [{:keys [type name variadic params statements ret env recurs max-fixed-arity]}]
380
+ (emit-wrap env
381
+ (emitln "(function " (munge name) "(" (comma-sep (map munge params)) "){")
382
+ (when type
383
+ (emitln "var self__ = this;"))
384
+ (when recurs (emitln "while(true){"))
385
+ (emit-block :return statements ret)
386
+ (when recurs
387
+ (emitln "break;")
388
+ (emitln "}"))
389
+ (emits "})")))
390
+
391
+ (defn emit-variadic-fn-method
392
+ [{:keys [type name variadic params statements ret env recurs max-fixed-arity] :as f}]
393
+ (emit-wrap env
394
+ (let [name (or name (gensym))
395
+ mname (munge name)
396
+ params (map munge params)
397
+ delegate-name (str mname "__delegate")]
398
+ (emitln "(function() { ")
399
+ (emitln "var " delegate-name " = function (" (comma-sep params) "){")
400
+ (when recurs (emitln "while(true){"))
401
+ (emit-block :return statements ret)
402
+ (when recurs
403
+ (emitln "break;")
404
+ (emitln "}"))
405
+ (emitln "};")
406
+
407
+ (emitln "var " mname " = function (" (comma-sep
408
+ (if variadic
409
+ (concat (butlast params) ['var_args])
410
+ params)) "){")
411
+ (when type
412
+ (emitln "var self__ = this;"))
413
+ (when variadic
414
+ (emitln "var " (last params) " = null;")
415
+ (emitln "if (goog.isDef(var_args)) {")
416
+ (emitln " " (last params) " = cljs.core.array_seq(Array.prototype.slice.call(arguments, " (dec (count params)) "),0);")
417
+ (emitln "} "))
418
+ (emitln "return " delegate-name ".call(" (string/join ", " (cons "this" params)) ");")
419
+ (emitln "};")
420
+
421
+ (emitln mname ".cljs$lang$maxFixedArity = " max-fixed-arity ";")
422
+ (emits mname ".cljs$lang$applyTo = ")
423
+ (emit-apply-to (assoc f :name name))
424
+ (emitln ";")
425
+ (emitln mname ".cljs$lang$arity$variadic = " delegate-name ";")
426
+ (emitln "return " mname ";")
427
+ (emitln "})()"))))
428
+
429
+ (defmethod emit :fn
430
+ [{:keys [name env methods max-fixed-arity variadic recur-frames loop-lets]}]
431
+ ;;fn statements get erased, serve no purpose and can pollute scope if named
432
+ (when-not (= :statement (:context env))
433
+ (let [loop-locals (->> (concat (mapcat :params (filter #(and % @(:flag %)) recur-frames))
434
+ (mapcat :params loop-lets))
435
+ (map munge)
436
+ seq)]
437
+ (when loop-locals
438
+ (when (= :return (:context env))
439
+ (emits "return "))
440
+ (emitln "((function (" (comma-sep (map munge loop-locals)) "){")
441
+ (when-not (= :return (:context env))
442
+ (emits "return ")))
443
+ (if (= 1 (count methods))
444
+ (if variadic
445
+ (emit-variadic-fn-method (assoc (first methods) :name name))
446
+ (emit-fn-method (assoc (first methods) :name name)))
447
+ (let [has-name? (and name true)
448
+ name (or name (gensym))
449
+ mname (munge name)
450
+ maxparams (map munge (apply max-key count (map :params methods)))
451
+ mmap (into {}
452
+ (map (fn [method]
453
+ [(munge (symbol (str mname "__" (count (:params method)))))
454
+ method])
455
+ methods))
456
+ ms (sort-by #(-> % second :params count) (seq mmap))]
457
+ (when (= :return (:context env))
458
+ (emits "return "))
459
+ (emitln "(function() {")
460
+ (emitln "var " mname " = null;")
461
+ (doseq [[n meth] ms]
462
+ (emits "var " n " = ")
463
+ (if (:variadic meth)
464
+ (emit-variadic-fn-method meth)
465
+ (emit-fn-method meth))
466
+ (emitln ";"))
467
+ (emitln mname " = function(" (comma-sep (if variadic
468
+ (concat (butlast maxparams) ['var_args])
469
+ maxparams)) "){")
470
+ (when variadic
471
+ (emitln "var " (last maxparams) " = var_args;"))
472
+ (emitln "switch(arguments.length){")
473
+ (doseq [[n meth] ms]
474
+ (if (:variadic meth)
475
+ (do (emitln "default:")
476
+ (emitln "return " n ".cljs$lang$arity$variadic("
477
+ (comma-sep (butlast maxparams))
478
+ (when (> (count maxparams) 1) ", ")
479
+ "cljs.core.array_seq(arguments, " max-fixed-arity "));"))
480
+ (let [pcnt (count (:params meth))]
481
+ (emitln "case " pcnt ":")
482
+ (emitln "return " n ".call(this" (if (zero? pcnt) nil
483
+ (list "," (comma-sep (take pcnt maxparams)))) ");"))))
484
+ (emitln "}")
485
+ (emitln "throw(new Error('Invalid arity: ' + arguments.length));")
486
+ (emitln "};")
487
+ (when variadic
488
+ (emitln mname ".cljs$lang$maxFixedArity = " max-fixed-arity ";")
489
+ (emitln mname ".cljs$lang$applyTo = " (some #(let [[n m] %] (when (:variadic m) n)) ms) ".cljs$lang$applyTo;"))
490
+ (when has-name?
491
+ (doseq [[n meth] ms]
492
+ (let [c (count (:params meth))]
493
+ (if (:variadic meth)
494
+ (emitln mname ".cljs$lang$arity$variadic = " n ".cljs$lang$arity$variadic;")
495
+ (emitln mname ".cljs$lang$arity$" c " = " n ";")))))
496
+ (emitln "return " mname ";")
497
+ (emitln "})()")))
498
+ (when loop-locals
499
+ (emitln ";})(" (comma-sep loop-locals) "))")))))
500
+
501
+ (defmethod emit :do
502
+ [{:keys [statements ret env]}]
503
+ (let [context (:context env)]
504
+ (when (and statements (= :expr context)) (emits "(function (){"))
505
+ ;(when statements (emitln "{"))
506
+ (emit-block context statements ret)
507
+ ;(when statements (emits "}"))
508
+ (when (and statements (= :expr context)) (emits "})()"))))
509
+
510
+ (defmethod emit :try*
511
+ [{:keys [env try catch name finally]}]
512
+ (let [context (:context env)
513
+ subcontext (if (= :expr context) :return context)]
514
+ (if (or name finally)
515
+ (do
516
+ (when (= :expr context) (emits "(function (){"))
517
+ (emits "try{")
518
+ (let [{:keys [statements ret]} try]
519
+ (emit-block subcontext statements ret))
520
+ (emits "}")
521
+ (when name
522
+ (emits "catch (" (munge name) "){")
523
+ (when catch
524
+ (let [{:keys [statements ret]} catch]
525
+ (emit-block subcontext statements ret)))
526
+ (emits "}"))
527
+ (when finally
528
+ (let [{:keys [statements ret]} finally]
529
+ (assert (not= :constant (:op ret)) "finally block cannot contain constant")
530
+ (emits "finally {")
531
+ (emit-block subcontext statements ret)
532
+ (emits "}")))
533
+ (when (= :expr context) (emits "})()")))
534
+ (let [{:keys [statements ret]} try]
535
+ (when (and statements (= :expr context)) (emits "(function (){"))
536
+ (emit-block subcontext statements ret)
537
+ (when (and statements (= :expr context)) (emits "})()"))))))
538
+
539
+ (defmethod emit :let
540
+ [{:keys [bindings statements ret env loop]}]
541
+ (let [context (:context env)]
542
+ (when (= :expr context) (emits "(function (){"))
543
+ (doseq [{:keys [init] :as binding} bindings]
544
+ (emitln "var " (munge binding) " = " init ";"))
545
+ (when loop (emitln "while(true){"))
546
+ (emit-block (if (= :expr context) :return context) statements ret)
547
+ (when loop
548
+ (emitln "break;")
549
+ (emitln "}"))
550
+ ;(emits "}")
551
+ (when (= :expr context) (emits "})()"))))
552
+
553
+ (defmethod emit :recur
554
+ [{:keys [frame exprs env]}]
555
+ (let [temps (vec (take (count exprs) (repeatedly gensym)))
556
+ params (:params frame)]
557
+ (emitln "{")
558
+ (dotimes [i (count exprs)]
559
+ (emitln "var " (temps i) " = " (exprs i) ";"))
560
+ (dotimes [i (count exprs)]
561
+ (emitln (munge (params i)) " = " (temps i) ";"))
562
+ (emitln "continue;")
563
+ (emitln "}")))
564
+
565
+ (defmethod emit :letfn
566
+ [{:keys [bindings statements ret env]}]
567
+ (let [context (:context env)]
568
+ (when (= :expr context) (emits "(function (){"))
569
+ (doseq [{:keys [init] :as binding} bindings]
570
+ (emitln "var " (munge binding) " = " init ";"))
571
+ (emit-block (if (= :expr context) :return context) statements ret)
572
+ (when (= :expr context) (emits "})()"))))
573
+
574
+ (defn protocol-prefix [psym]
575
+ (symbol (str (-> (str psym) (.replace \. \$) (.replace \/ \$)) "$")))
576
+
577
+ (defmethod emit :invoke
578
+ [{:keys [f args env] :as expr}]
579
+ (let [info (:info f)
580
+ fn? (and ana/*cljs-static-fns*
581
+ (not (:dynamic info))
582
+ (:fn-var info))
583
+ protocol (:protocol info)
584
+ proto? (let [tag (infer-tag (first (:args expr)))]
585
+ (and protocol tag
586
+ (or ana/*cljs-static-fns*
587
+ (:protocol-inline env))
588
+ (or (= protocol tag)
589
+ (when-let [ps (:protocols (ana/resolve-existing-var (dissoc env :locals) tag))]
590
+ (ps protocol)))))
591
+ opt-not? (and (= (:name info) 'cljs.core/not)
592
+ (= (infer-tag (first (:args expr))) 'boolean))
593
+ ns (:ns info)
594
+ js? (= ns 'js)
595
+ goog? (when ns
596
+ (or (= ns 'goog)
597
+ (when-let [ns-str (str ns)]
598
+ (= (get (string/split ns-str #"\.") 0 nil) "goog"))))
599
+ keyword? (and (= (-> f :op) :constant)
600
+ (keyword? (-> f :form)))
601
+ [f variadic-invoke]
602
+ (if fn?
603
+ (let [arity (count args)
604
+ variadic? (:variadic info)
605
+ mps (:method-params info)
606
+ mfa (:max-fixed-arity info)]
607
+ (cond
608
+ ;; if only one method, no renaming needed
609
+ (and (not variadic?)
610
+ (= (count mps) 1))
611
+ [f nil]
612
+
613
+ ;; direct dispatch to variadic case
614
+ (and variadic? (> arity mfa))
615
+ [(update-in f [:info :name]
616
+ (fn [name] (symbol (str (munge name) ".cljs$lang$arity$variadic"))))
617
+ {:max-fixed-arity mfa}]
618
+
619
+ ;; direct dispatch to specific arity case
620
+ :else
621
+ (let [arities (map count mps)]
622
+ (if (some #{arity} arities)
623
+ [(update-in f [:info :name]
624
+ (fn [name] (symbol (str (munge name) ".cljs$lang$arity$" arity)))) nil]
625
+ [f nil]))))
626
+ [f nil])]
627
+ (emit-wrap env
628
+ (cond
629
+ opt-not?
630
+ (emits "!(" (first args) ")")
631
+
632
+ proto?
633
+ (let [pimpl (str (munge (protocol-prefix protocol))
634
+ (munge (name (:name info))) "$arity$" (count args))]
635
+ (emits (first args) "." pimpl "(" (comma-sep args) ")"))
636
+
637
+ keyword?
638
+ (emits "(new cljs.core.Keyword(" f ")).call(" (comma-sep (cons "null" args)) ")")
639
+
640
+ variadic-invoke
641
+ (let [mfa (:max-fixed-arity variadic-invoke)]
642
+ (emits f "(" (comma-sep (take mfa args))
643
+ (when-not (zero? mfa) ",")
644
+ "cljs.core.array_seq([" (comma-sep (drop mfa args)) "], 0))"))
645
+
646
+ (or fn? js? goog?)
647
+ (emits f "(" (comma-sep args) ")")
648
+
649
+ :else
650
+ (if (and ana/*cljs-static-fns* (= (:op f) :var))
651
+ (let [fprop (str ".cljs$lang$arity$" (count args))]
652
+ (emits "(" f fprop " ? " f fprop "(" (comma-sep args) ") : " f ".call(" (comma-sep (cons "null" args)) "))"))
653
+ (emits f ".call(" (comma-sep (cons "null" args)) ")"))))))
654
+
655
+ (defmethod emit :new
656
+ [{:keys [ctor args env]}]
657
+ (emit-wrap env
658
+ (emits "(new " ctor "("
659
+ (comma-sep args)
660
+ "))")))
661
+
662
+ (defmethod emit :set!
663
+ [{:keys [target val env]}]
664
+ (emit-wrap env (emits target " = " val)))
665
+
666
+ (defmethod emit :ns
667
+ [{:keys [name requires uses requires-macros env]}]
668
+ (swap! ns-first-segments conj (first (string/split (str name) #"\.")))
669
+ (emitln "goog.provide('" (munge name) "');")
670
+ (when-not (= name 'cljs.core)
671
+ (emitln "goog.require('cljs.core');"))
672
+ (doseq [lib (into (vals requires) (distinct (vals uses)))]
673
+ (emitln "goog.require('" (munge lib) "');")))
674
+
675
+ (defmethod emit :deftype*
676
+ [{:keys [t fields pmasks]}]
677
+ (let [fields (map munge fields)]
678
+ (when-not (or (nil? *emitted-provides*) (contains? @*emitted-provides* t))
679
+ (swap! *emitted-provides* conj t)
680
+ (emitln "")
681
+ (emitln "goog.provide('" (munge t) "');"))
682
+ (emitln "")
683
+ (emitln "/**")
684
+ (emitln "* @constructor")
685
+ (emitln "*/")
686
+ (emitln (munge t) " = (function (" (comma-sep fields) "){")
687
+ (doseq [fld fields]
688
+ (emitln "this." fld " = " fld ";"))
689
+ (doseq [[pno pmask] pmasks]
690
+ (emitln "this.cljs$lang$protocol_mask$partition" pno "$ = " pmask ";"))
691
+ (emitln "})")))
692
+
693
+ (defmethod emit :defrecord*
694
+ [{:keys [t fields pmasks]}]
695
+ (let [fields (concat (map munge fields) '[__meta __extmap])]
696
+ (when-not (or (nil? *emitted-provides*) (contains? @*emitted-provides* t))
697
+ (swap! *emitted-provides* conj t)
698
+ (emitln "")
699
+ (emitln "goog.provide('" (munge t) "');"))
700
+ (emitln "")
701
+ (emitln "/**")
702
+ (emitln "* @constructor")
703
+ (doseq [fld fields]
704
+ (emitln "* @param {*} " fld))
705
+ (emitln "* @param {*=} __meta ")
706
+ (emitln "* @param {*=} __extmap")
707
+ (emitln "*/")
708
+ (emitln (munge t) " = (function (" (comma-sep fields) "){")
709
+ (doseq [fld fields]
710
+ (emitln "this." fld " = " fld ";"))
711
+ (doseq [[pno pmask] pmasks]
712
+ (emitln "this.cljs$lang$protocol_mask$partition" pno "$ = " pmask ";"))
713
+ (emitln "if(arguments.length>" (- (count fields) 2) "){")
714
+ (emitln "this.__meta = __meta;")
715
+ (emitln "this.__extmap = __extmap;")
716
+ (emitln "} else {")
717
+ (emits "this.__meta=")
718
+ (emit-constant nil)
719
+ (emitln ";")
720
+ (emits "this.__extmap=")
721
+ (emit-constant nil)
722
+ (emitln ";")
723
+ (emitln "}")
724
+ (emitln "})")))
725
+
726
+ (defmethod emit :dot
727
+ [{:keys [target field method args env]}]
728
+ (emit-wrap env
729
+ (if field
730
+ (emits target "." (munge field #{}))
731
+ (emits target "." (munge method #{}) "("
732
+ (comma-sep args)
733
+ ")"))))
734
+
735
+ (defmethod emit :js
736
+ [{:keys [env code segs args]}]
737
+ (emit-wrap env
738
+ (if code
739
+ (emits code)
740
+ (emits (interleave (concat segs (repeat nil))
741
+ (concat args [nil]))))))
742
+
743
+ (defn forms-seq
744
+ "Seq of forms in a Clojure or ClojureScript file."
745
+ ([f]
746
+ (forms-seq f (clojure.lang.LineNumberingPushbackReader. (io/reader f))))
747
+ ([f ^java.io.PushbackReader rdr]
748
+ (if-let [form (binding [*ns* ana/*reader-ns*] (read rdr nil nil))]
749
+ (lazy-seq (cons form (forms-seq f rdr)))
750
+ (.close rdr))))
751
+
752
+ (defn rename-to-js
753
+ "Change the file extension from .cljs to .js. Takes a File or a
754
+ String. Always returns a String."
755
+ [file-str]
756
+ (clojure.string/replace file-str #"\.cljs$" ".js"))
757
+
758
+ (defn mkdirs
759
+ "Create all parent directories for the passed file."
760
+ [^java.io.File f]
761
+ (.mkdirs (.getParentFile (.getCanonicalFile f))))
762
+
763
+ (defmacro with-core-cljs
764
+ "Ensure that core.cljs has been loaded."
765
+ [& body]
766
+ `(do (when-not (:defs (get @ana/namespaces 'cljs.core))
767
+ (ana/analyze-file "cljs/core.cljs"))
768
+ ~@body))
769
+
770
+ (defn compile-file* [src dest]
771
+ (with-core-cljs
772
+ (with-open [out ^java.io.Writer (io/make-writer dest {})]
773
+ (binding [*out* out
774
+ ana/*cljs-ns* 'cljs.user
775
+ ana/*cljs-file* (.getPath ^java.io.File src)
776
+ *data-readers* tags/*cljs-data-readers*
777
+ *position* (atom [0 0])
778
+ *emitted-provides* (atom #{})]
779
+ (loop [forms (forms-seq src)
780
+ ns-name nil
781
+ deps nil]
782
+ (if (seq forms)
783
+ (let [env (ana/empty-env)
784
+ ast (ana/analyze env (first forms))]
785
+ (do (emit ast)
786
+ (if (= (:op ast) :ns)
787
+ (recur (rest forms) (:name ast) (merge (:uses ast) (:requires ast)))
788
+ (recur (rest forms) ns-name deps))))
789
+ {:ns (or ns-name 'cljs.user)
790
+ :provides [ns-name]
791
+ :requires (if (= ns-name 'cljs.core) (set (vals deps)) (conj (set (vals deps)) 'cljs.core))
792
+ :file dest}))))))
793
+
794
+ (defn requires-compilation?
795
+ "Return true if the src file requires compilation."
796
+ [^java.io.File src ^java.io.File dest]
797
+ (or (not (.exists dest))
798
+ (> (.lastModified src) (.lastModified dest))))
799
+
800
+ (defn compile-file
801
+ "Compiles src to a file of the same name, but with a .js extension,
802
+ in the src file's directory.
803
+
804
+ With dest argument, write file to provided location. If the dest
805
+ argument is a file outside the source tree, missing parent
806
+ directories will be created. The src file will only be compiled if
807
+ the dest file has an older modification time.
808
+
809
+ Both src and dest may be either a String or a File.
810
+
811
+ Returns a map containing {:ns .. :provides .. :requires .. :file ..}.
812
+ If the file was not compiled returns only {:file ...}"
813
+ ([src]
814
+ (let [dest (rename-to-js src)]
815
+ (compile-file src dest)))
816
+ ([src dest]
817
+ (let [src-file (io/file src)
818
+ dest-file (io/file dest)]
819
+ (if (.exists src-file)
820
+ (if (requires-compilation? src-file dest-file)
821
+ (do (mkdirs dest-file)
822
+ (compile-file* src-file dest-file))
823
+ {:file dest-file})
824
+ (throw (java.io.FileNotFoundException. (str "The file " src " does not exist.")))))))
825
+
826
+ (comment
827
+ ;; flex compile-file
828
+ (do
829
+ (compile-file "/tmp/hello.cljs" "/tmp/something.js")
830
+ (slurp "/tmp/hello.js")
831
+
832
+ (compile-file "/tmp/somescript.cljs")
833
+ (slurp "/tmp/somescript.js")))
834
+
835
+ (defn path-seq
836
+ [file-str]
837
+ (->> java.io.File/separator
838
+ java.util.regex.Pattern/quote
839
+ re-pattern
840
+ (string/split file-str)))
841
+
842
+ (defn to-path
843
+ ([parts]
844
+ (to-path parts java.io.File/separator))
845
+ ([parts sep]
846
+ (apply str (interpose sep parts))))
847
+
848
+ (defn to-target-file
849
+ "Given the source root directory, the output target directory and
850
+ file under the source root, produce the target file."
851
+ [^java.io.File dir ^String target ^java.io.File file]
852
+ (let [dir-path (path-seq (.getAbsolutePath dir))
853
+ file-path (path-seq (.getAbsolutePath file))
854
+ relative-path (drop (count dir-path) file-path)
855
+ parents (butlast relative-path)
856
+ parent-file (java.io.File. ^String (to-path (cons target parents)))]
857
+ (java.io.File. parent-file ^String (rename-to-js (last relative-path)))))
858
+
859
+ (defn cljs-files-in
860
+ "Return a sequence of all .cljs files in the given directory."
861
+ [dir]
862
+ (filter #(let [name (.getName ^java.io.File %)]
863
+ (and (.endsWith name ".cljs")
864
+ (not= \. (first name))
865
+ (not (contains? cljs-reserved-file-names name))))
866
+ (file-seq dir)))
867
+
868
+ (defn compile-root
869
+ "Looks recursively in src-dir for .cljs files and compiles them to
870
+ .js files. If target-dir is provided, output will go into this
871
+ directory mirroring the source directory structure. Returns a list
872
+ of maps containing information about each file which was compiled
873
+ in dependency order."
874
+ ([src-dir]
875
+ (compile-root src-dir "out"))
876
+ ([src-dir target-dir]
877
+ (let [src-dir-file (io/file src-dir)]
878
+ (loop [cljs-files (cljs-files-in src-dir-file)
879
+ output-files []]
880
+ (if (seq cljs-files)
881
+ (let [cljs-file (first cljs-files)
882
+ output-file ^java.io.File (to-target-file src-dir-file target-dir cljs-file)
883
+ ns-info (compile-file cljs-file output-file)]
884
+ (recur (rest cljs-files) (conj output-files (assoc ns-info :file-name (.getPath output-file)))))
885
+ output-files)))))
886
+
887
+ (comment
888
+ ;; compile-root
889
+ ;; If you have a standard project layout with all file in src
890
+ (compile-root "src")
891
+ ;; will produce a mirrored directory structure under "out" but all
892
+ ;; files will be compiled to js.
893
+ )
894
+
895
+ (comment
896
+
897
+ ;;the new way - use the REPL!!
898
+ (require '[cljs.compiler :as comp])
899
+ (def repl-env (comp/repl-env))
900
+ (comp/repl repl-env)
901
+ ;having problems?, try verbose mode
902
+ (comp/repl repl-env :verbose true)
903
+ ;don't forget to check for uses of undeclared vars
904
+ (comp/repl repl-env :warn-on-undeclared true)
905
+
906
+ (test-stuff)
907
+ (+ 1 2 3)
908
+ ([ 1 2 3 4] 2)
909
+ ({:a 1 :b 2} :a)
910
+ ({1 1 2 2} 1)
911
+ (#{1 2 3} 2)
912
+ (:b {:a 1 :b 2})
913
+ ('b '{:a 1 b 2})
914
+
915
+ (extend-type number ISeq (-seq [x] x))
916
+ (seq 42)
917
+ ;(aset cljs.core.ISeq "number" true)
918
+ ;(aget cljs.core.ISeq "number")
919
+ (satisfies? ISeq 42)
920
+ (extend-type nil ISeq (-seq [x] x))
921
+ (satisfies? ISeq nil)
922
+ (seq nil)
923
+
924
+ (extend-type default ISeq (-seq [x] x))
925
+ (satisfies? ISeq true)
926
+ (seq true)
927
+
928
+ (test-stuff)
929
+
930
+ (array-seq [])
931
+ (defn f [& etc] etc)
932
+ (f)
933
+
934
+ (in-ns 'cljs.core)
935
+ ;;hack on core
936
+
937
+
938
+ (deftype Foo [a] IMeta (-meta [_] (fn [] a)))
939
+ ((-meta (Foo. 42)))
940
+
941
+ ;;OLD way, don't you want to use the REPL?
942
+ (in-ns 'cljs.compiler)
943
+ (import '[javax.script ScriptEngineManager])
944
+ (def jse (-> (ScriptEngineManager.) (.getEngineByName "JavaScript")))
945
+ (.eval jse cljs.compiler/bootjs)
946
+ (def envx {:ns (@namespaces 'cljs.user) :context :expr :locals '{ethel {:name ethel__123 :init nil}}})
947
+ (analyze envx nil)
948
+ (analyze envx 42)
949
+ (analyze envx "foo")
950
+ (analyze envx 'fred)
951
+ (analyze envx 'fred.x)
952
+ (analyze envx 'ethel)
953
+ (analyze envx 'ethel.x)
954
+ (analyze envx 'my.ns/fred)
955
+ (analyze envx 'your.ns.fred)
956
+ (analyze envx '(if test then else))
957
+ (analyze envx '(if test then))
958
+ (analyze envx '(and fred ethel))
959
+ (analyze (assoc envx :context :statement) '(def test "fortytwo" 42))
960
+ (analyze (assoc envx :context :expr) '(fn* ^{::fields [a b c]} [x y] a y x))
961
+ (analyze (assoc envx :context :statement) '(let* [a 1 b 2] a))
962
+ (analyze (assoc envx :context :statement) '(defprotocol P (bar [a]) (baz [b c])))
963
+ (analyze (assoc envx :context :statement) '(. x y))
964
+ (analyze envx '(fn foo [x] (let [x 42] (js* "~{x}['foobar']"))))
965
+
966
+ (analyze envx '(ns fred (:require [your.ns :as yn]) (:require-macros [clojure.core :as core])))
967
+ (defmacro js [form]
968
+ `(emit (ana/analyze {:ns (@ana/namespaces 'cljs.user) :context :statement :locals {}} '~form)))
969
+
970
+ (defn jscapture [form]
971
+ "just grabs the js, doesn't print it"
972
+ (with-out-str
973
+ (emit (analyze {:ns (@namespaces 'cljs.user) :context :expr :locals {}} form))))
974
+
975
+ (defn jseval [form]
976
+ (let [js (jscapture form)]
977
+ ;;(prn js)
978
+ (.eval jse (str "print(" js ")"))))
979
+
980
+ ;; from closure.clj
981
+ (optimize (jscapture '(defn foo [x y] (if true 46 (recur 1 x)))))
982
+
983
+ (js (if a b c))
984
+ (js (def x 42))
985
+ (js (defn foo [a b] a))
986
+ (js (do 1 2 3))
987
+ (js (let [a 1 b 2 a b] a))
988
+
989
+ (js (ns fred (:require [your.ns :as yn]) (:require-macros [cljs.core :as core])))
990
+
991
+ (js (def foo? (fn* ^{::fields [a? b c]} [x y] (if true a? (recur 1 x)))))
992
+ (js (def foo (fn* ^{::fields [a b c]} [x y] (if true a (recur 1 x)))))
993
+ (js (defn foo [x y] (if true x y)))
994
+ (jseval '(defn foo [x y] (if true x y)))
995
+ (js (defn foo [x y] (if true 46 (recur 1 x))))
996
+ (jseval '(defn foo [x y] (if true 46 (recur 1 x))))
997
+ (jseval '(foo 1 2))
998
+ (js (and fred ethel))
999
+ (jseval '(ns fred (:require [your.ns :as yn]) (:require-macros [cljs.core :as core])))
1000
+ (js (def x 42))
1001
+ (jseval '(def x 42))
1002
+ (jseval 'x)
1003
+ (jseval '(if 42 1 2))
1004
+ (jseval '(or 1 2))
1005
+ (jseval '(fn* [x y] (if true 46 (recur 1 x))))
1006
+ (.eval jse "print(test)")
1007
+ (.eval jse "print(cljs.user.Foo)")
1008
+ (.eval jse "print(cljs.user.Foo = function (){\n}\n)")
1009
+ (js (def fred 42))
1010
+ (js (deftype* Foo [a b-foo c]))
1011
+ (jseval '(deftype* Foo [a b-foo c]))
1012
+ (jseval '(. (new Foo 1 2 3) b-foo))
1013
+ (js (. (new Foo 1 2 3) b))
1014
+ (.eval jse "print(new cljs.user.Foo(1, 42, 3).b)")
1015
+ (.eval jse "(function (x, ys){return Array.prototype.slice.call(arguments, 1);})(1,2)[0]")
1016
+
1017
+ (macroexpand-1 '(cljs.core/deftype Foo [a b c] Fred (fred [x] a) (fred [x y] b) (ethel [x] c) Ethel (foo [] d)))
1018
+ (-> (macroexpand-1 '(cljs.core/deftype Foo [a b c] Fred (fred [x] a) (fred [x y] b) (ethel [x] c) Ethel (foo [] d)))
1019
+ last last last first meta)
1020
+
1021
+ (macroexpand-1 '(cljs.core/extend-type Foo Fred (fred ([x] a) ([x y] b)) (ethel ([x] c)) Ethel (foo ([] d))))
1022
+ (js (new foo.Bar 65))
1023
+ (js (defprotocol P (bar [a]) (baz [b c])))
1024
+ (js (. x y))
1025
+ (js (. "fred" (y)))
1026
+ (js (. x y 42 43))
1027
+ (js (.. a b c d))
1028
+ (js (. x (y 42 43)))
1029
+ (js (fn [x] x))
1030
+ (js (fn ([t] t) ([x y] y) ([ a b & zs] b)))
1031
+
1032
+ (js (. (fn foo ([t] t) ([x y] y) ([a b & zs] b)) call nil 1 2))
1033
+ (js (fn foo
1034
+ ([t] t)
1035
+ ([x y] y)
1036
+ ([ a b & zs] b)))
1037
+
1038
+ (js ((fn foo
1039
+ ([t] (foo t nil))
1040
+ ([x y] y)
1041
+ ([ a b & zs] b)) 1 2 3))
1042
+
1043
+
1044
+ (jseval '((fn foo ([t] t) ([x y] y) ([ a b & zs] zs)) 12 13 14 15))
1045
+
1046
+ (js (defn foo [this] this))
1047
+
1048
+ (js (defn foo [a b c & ys] ys))
1049
+ (js ((fn [x & ys] ys) 1 2 3 4))
1050
+ (jseval '((fn [x & ys] ys) 1 2 3 4))
1051
+ (js (cljs.core/deftype Foo [a b c] Fred (fred [x] a) (fred [x y] a) (ethel [x] c) Ethel (foo [] d)))
1052
+ (jseval '(cljs.core/deftype Foo [a b c] Fred (fred [x] a) (fred [x y] a) (ethel [x] c) Ethel (foo [] d)))
1053
+
1054
+ (js (do
1055
+ (defprotocol Proto (foo [this]))
1056
+ (deftype Type [a] Proto (foo [this] a))
1057
+ (foo (new Type 42))))
1058
+
1059
+ (jseval '(do
1060
+ (defprotocol P-roto (foo? [this]))
1061
+ (deftype T-ype [a] P-roto (foo? [this] a))
1062
+ (foo? (new T-ype 42))))
1063
+
1064
+ (js (def x (fn foo [x] (let [x 42] (js* "~{x}['foobar']")))))
1065
+ (js (let [a 1 b 2 a b] a))
1066
+
1067
+ (doseq [e '[nil true false 42 "fred" fred ethel my.ns/fred your.ns.fred
1068
+ (if test then "fooelse")
1069
+ (def x 45)
1070
+ (do x y y)
1071
+ (fn* [x y] x y x)
1072
+ (fn* [x y] (if true 46 (recur 1 x)))
1073
+ (let* [a 1 b 2 a a] a b)
1074
+ (do "do1")
1075
+ (loop* [x 1 y 2] (if true 42 (do (recur 43 44))))
1076
+ (my.foo 1 2 3)
1077
+ (let* [a 1 b 2 c 3] (set! y.s.d b) (new fred.Ethel a b c))
1078
+ (let [x (do 1 2 3)] x)
1079
+ ]]
1080
+ (->> e (analyze envx) emit)
1081
+ (newline)))