clementine 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/.gitignore +7 -0
  2. data/Gemfile +4 -0
  3. data/README.md +52 -0
  4. data/Rakefile +1 -0
  5. data/clementine.gemspec +23 -0
  6. data/lib/clementine.rb +27 -0
  7. data/lib/clementine/clementine_rails.rb +8 -0
  8. data/lib/clementine/clojurescript_engine.rb +49 -0
  9. data/lib/clementine/clojurescript_engine_mri.rb +65 -0
  10. data/lib/clementine/clojurescript_template.rb +21 -0
  11. data/lib/clementine/options.rb +9 -0
  12. data/lib/clementine/version.rb +3 -0
  13. data/test/clojurescript_engine_test.rb +46 -0
  14. data/test/options_test.rb +22 -0
  15. data/vendor/assets/bin/cljsc.clj +21 -0
  16. data/vendor/assets/lib/clojure.jar +0 -0
  17. data/vendor/assets/lib/compiler.jar +0 -0
  18. data/vendor/assets/lib/goog.jar +0 -0
  19. data/vendor/assets/lib/js.jar +0 -0
  20. data/vendor/assets/src/clj/cljs/closure.clj +823 -0
  21. data/vendor/assets/src/clj/cljs/compiler.clj +1341 -0
  22. data/vendor/assets/src/clj/cljs/core.clj +702 -0
  23. data/vendor/assets/src/clj/cljs/repl.clj +162 -0
  24. data/vendor/assets/src/clj/cljs/repl/browser.clj +341 -0
  25. data/vendor/assets/src/clj/cljs/repl/rhino.clj +170 -0
  26. data/vendor/assets/src/cljs/cljs/core.cljs +3330 -0
  27. data/vendor/assets/src/cljs/cljs/nodejs.cljs +11 -0
  28. data/vendor/assets/src/cljs/cljs/nodejs_externs.js +2 -0
  29. data/vendor/assets/src/cljs/cljs/nodejscli.cljs +9 -0
  30. data/vendor/assets/src/cljs/cljs/reader.cljs +360 -0
  31. data/vendor/assets/src/cljs/clojure/browser/dom.cljs +106 -0
  32. data/vendor/assets/src/cljs/clojure/browser/event.cljs +100 -0
  33. data/vendor/assets/src/cljs/clojure/browser/net.cljs +182 -0
  34. data/vendor/assets/src/cljs/clojure/browser/repl.cljs +109 -0
  35. data/vendor/assets/src/cljs/clojure/set.cljs +162 -0
  36. data/vendor/assets/src/cljs/clojure/string.cljs +160 -0
  37. data/vendor/assets/src/cljs/clojure/walk.cljs +94 -0
  38. data/vendor/assets/src/cljs/clojure/zip.cljs +291 -0
  39. metadata +103 -0
@@ -0,0 +1,702 @@
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
+ (ns cljs.core
10
+ (:refer-clojure :exclude [-> ->> .. amap and areduce assert binding bound-fn case comment cond condp
11
+ declare definline definterface defmethod defmulti defn defn- defonce
12
+ defprotocol defrecord defstruct deftype delay doseq dosync dotimes doto
13
+ extend-protocol extend-type fn for future gen-class gen-interface
14
+ if-let if-not import io! lazy-cat lazy-seq let letfn locking loop
15
+ memfn ns or proxy proxy-super pvalues refer-clojure reify sync time
16
+ when when-first when-let when-not while with-bindings with-in-str
17
+ with-loading-context with-local-vars with-open with-out-str with-precision with-redefs
18
+ satisfies?
19
+
20
+ aget aset
21
+ + - * / < <= > >= == zero? pos? neg? inc dec max min mod
22
+ bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set
23
+ bit-test bit-shift-left bit-shift-right bit-xor]))
24
+
25
+ (alias 'core 'clojure.core)
26
+
27
+ (defmacro import-macros [ns [& vars]]
28
+ (core/let [ns (find-ns ns)
29
+ vars (map #(ns-resolve ns %) vars)
30
+ syms (map (core/fn [^clojure.lang.Var v] (core/-> v .sym (with-meta {:macro true}))) vars)
31
+ defs (map (core/fn [sym var]
32
+ `(def ~sym (deref ~var))) syms vars)]
33
+ `(do ~@defs
34
+ :imported)))
35
+
36
+ (import-macros clojure.core
37
+ [-> ->> .. and assert comment cond
38
+ declare defn defn-
39
+ doto
40
+ extend-protocol fn for
41
+ if-let if-not let letfn loop
42
+ or
43
+ when when-first when-let when-not while])
44
+
45
+ (defmacro aget [a i]
46
+ (list 'js* "(~{}[~{}])" a i))
47
+
48
+ (defmacro aset [a i v]
49
+ (list 'js* "(~{}[~{}] = ~{})" a i v))
50
+
51
+ (defmacro +
52
+ ([] 0)
53
+ ([x] x)
54
+ ([x y] (list 'js* "(~{} + ~{})" x y))
55
+ ([x y & more] `(+ (+ ~x ~y) ~@more)))
56
+
57
+ (defmacro -
58
+ ([] 0)
59
+ ([x] (list 'js* "(- ~{})" x))
60
+ ([x y] (list 'js* "(~{} - ~{})" x y))
61
+ ([x y & more] `(- (- ~x ~y) ~@more)))
62
+
63
+ (defmacro *
64
+ ([] 1)
65
+ ([x] x)
66
+ ([x y] (list 'js* "(~{} * ~{})" x y))
67
+ ([x y & more] `(* (* ~x ~y) ~@more)))
68
+
69
+ (defmacro /
70
+ ([] 1)
71
+ ([x] `(/ 1 x))
72
+ ([x y] (list 'js* "(~{} / ~{})" x y))
73
+ ([x y & more] `(/ (/ ~x ~y) ~@more)))
74
+
75
+ (defmacro <
76
+ ([x] true)
77
+ ([x y] (list 'js* "(~{} < ~{})" x y))
78
+ ([x y & more] `(and (< ~x ~y) (< ~y ~@more))))
79
+
80
+ (defmacro <=
81
+ ([x] true)
82
+ ([x y] (list 'js* "(~{} <= ~{})" x y))
83
+ ([x y & more] `(and (<= ~x ~y) (<= ~y ~@more))))
84
+
85
+ (defmacro >
86
+ ([x] true)
87
+ ([x y] (list 'js* "(~{} > ~{})" x y))
88
+ ([x y & more] `(and (> ~x ~y) (> ~y ~@more))))
89
+
90
+ (defmacro >=
91
+ ([x] true)
92
+ ([x y] (list 'js* "(~{} >= ~{})" x y))
93
+ ([x y & more] `(and (>= ~x ~y) (>= ~y ~@more))))
94
+
95
+ (defmacro ==
96
+ ([x] true)
97
+ ([x y] (list 'js* "(~{} === ~{})" x y))
98
+ ([x y & more] `(and (== ~x ~y) (== ~y ~@more))))
99
+
100
+ (defmacro dec [x]
101
+ `(- ~x 1))
102
+
103
+ (defmacro inc [x]
104
+ `(+ ~x 1))
105
+
106
+ (defmacro zero? [x]
107
+ `(== ~x 0))
108
+
109
+ (defmacro pos? [x]
110
+ `(> ~x 0))
111
+
112
+ (defmacro neg? [x]
113
+ `(< ~x 0))
114
+
115
+ (defmacro max
116
+ ([x] x)
117
+ ([x y] (list 'js* "((~{} > ~{}) ? ~{} : ~{})" x y x y))
118
+ ([x y & more] `(max (max ~x ~y) ~@more)))
119
+
120
+ (defmacro min
121
+ ([x] x)
122
+ ([x y] (list 'js* "((~{} < ~{}) ? ~{} : ~{})" x y x y))
123
+ ([x y & more] `(min (min ~x ~y) ~@more)))
124
+
125
+ (defmacro mod [num div]
126
+ (list 'js* "(~{} % ~{})" num div))
127
+
128
+ (defmacro bit-not [x]
129
+ (list 'js* "(~ ~{})" x))
130
+
131
+ (defmacro bit-and
132
+ ([x y] (list 'js* "(~{} & ~{})" x y))
133
+ ([x y & more] `(bit-and (bit-and ~x ~y) ~@more)))
134
+
135
+ (defmacro bit-or
136
+ ([x y] (list 'js* "(~{} | ~{})" x y))
137
+ ([x y & more] `(bit-or (bit-or ~x ~y) ~@more)))
138
+
139
+ (defmacro bit-xor
140
+ ([x y] (list 'js* "(~{} ^ ~{})" x y))
141
+ ([x y & more] `(bit-xor (bit-xor ~x ~y) ~@more)))
142
+
143
+ (defmacro bit-and-not
144
+ ([x y] (list 'js* "(~{} & ~~{})" x y))
145
+ ([x y & more] `(bit-and-not (bit-and-not ~x ~y) ~@more)))
146
+
147
+ (defmacro bit-clear [x n]
148
+ (list 'js* "(~{} & ~(1 << ~{}))" x n))
149
+
150
+ (defmacro bit-flip [x n]
151
+ (list 'js* "(~{} ^ (1 << ~{}))" x n))
152
+
153
+ (defmacro bit-test [x n]
154
+ (list 'js* "((~{} & (1 << ~{})) != 0)" x n))
155
+
156
+ (defmacro bit-shift-left [x n]
157
+ (list 'js* "(~{} << ~{})" x n))
158
+
159
+ (defmacro bit-shift-right [x n]
160
+ (list 'js* "(~{} >> ~{})" x n))
161
+
162
+ (defn- protocol-prefix [psym]
163
+ (str (.replace (str psym) \. \$) "$"))
164
+
165
+ (def #^:private base-type
166
+ {nil "null"
167
+ 'object "object"
168
+ 'string "string"
169
+ 'number "number"
170
+ 'array "array"
171
+ 'function "function"
172
+ 'boolean "boolean"
173
+ 'default "_"})
174
+
175
+ (defmacro reify [& impls]
176
+ (let [t (gensym "t")
177
+ locals (keys (:locals &env))]
178
+ `(do
179
+ (when (undefined? ~t)
180
+ (deftype ~t [~@locals]
181
+ ~@impls))
182
+ (new ~t ~@locals))))
183
+
184
+ (defmacro this-as
185
+ "Defines a scope where JavaScript's implicit \"this\" is bound to the name provided."
186
+ [name & body]
187
+ `(let [~name (~'js* "this")]
188
+ ~@body))
189
+
190
+ (defmacro extend-type [tsym & impls]
191
+ (let [resolve #(let [ret (:name (cljs.compiler/resolve-var (dissoc &env :locals) %))]
192
+ (assert ret (str "Can't resolve: " %))
193
+ ret)
194
+ impl-map (loop [ret {} s impls]
195
+ (if (seq s)
196
+ (recur (assoc ret (first s) (take-while seq? (next s)))
197
+ (drop-while seq? (next s)))
198
+ ret))]
199
+ (if (base-type tsym)
200
+ (let [t (base-type tsym)
201
+ assign-impls (fn [[p sigs]]
202
+ (let [psym (resolve p)
203
+ pfn-prefix (subs (str psym) 0 (clojure.core/inc (.lastIndexOf (str psym) ".")))]
204
+ (cons `(aset ~psym ~t true)
205
+ (map (fn [[f & meths]]
206
+ `(aset ~(symbol (str pfn-prefix f)) ~t (fn* ~@meths)))
207
+ sigs))))]
208
+ `(do ~@(mapcat assign-impls impl-map)))
209
+ (let [t (resolve tsym)
210
+ prototype-prefix (str t ".prototype.")
211
+ assign-impls (fn [[p sigs]]
212
+ (let [psym (resolve p)
213
+ pprefix (protocol-prefix psym)]
214
+ (if (= p 'Object)
215
+ (let [adapt-params (fn [[sig & body]]
216
+ (let [[tname & args] sig]
217
+ (list (with-meta (vec args) (meta sig))
218
+ (list* 'this-as tname body))))]
219
+ (map (fn [[f & meths]]
220
+ `(set! ~(symbol (str prototype-prefix f)) (fn* ~@(map adapt-params meths))))
221
+ sigs))
222
+ (cons `(set! ~(symbol (str prototype-prefix pprefix)) true)
223
+ (map (fn [[f & meths]]
224
+ `(set! ~(symbol (str prototype-prefix pprefix f)) (fn* ~@meths)))
225
+ sigs)))))]
226
+ `(do ~@(mapcat assign-impls impl-map))))))
227
+
228
+ (defmacro deftype [t fields & impls]
229
+ (let [adorn-params (fn [sig]
230
+ (cons (vary-meta (second sig) assoc :cljs.compiler/fields fields)
231
+ (nnext sig)))
232
+ ;;reshape for extend-type
233
+ dt->et (fn [specs]
234
+ (loop [ret [] s specs]
235
+ (if (seq s)
236
+ (recur (-> ret
237
+ (conj (first s))
238
+ (into
239
+ (reduce (fn [v [f sigs]]
240
+ (conj v (cons f (map adorn-params sigs))))
241
+ []
242
+ (group-by first (take-while seq? (next s))))))
243
+ (drop-while seq? (next s)))
244
+ ret)))]
245
+ (if (seq impls)
246
+ `(do
247
+ (deftype* ~t ~fields)
248
+ (extend-type ~t ~@(dt->et impls)))
249
+ `(deftype* ~t ~fields))))
250
+
251
+ (defn- emit-defrecord
252
+ "Do not use this directly - use defrecord"
253
+ [tagname rname fields impls]
254
+ (let [hinted-fields fields
255
+ fields (vec (map #(with-meta % nil) fields))
256
+ base-fields fields
257
+ fields (conj fields '__meta '__extmap)
258
+ adorn-params (fn [sig]
259
+ (cons (vary-meta (second sig) assoc :cljs.compiler/fields fields)
260
+ (nnext sig)))
261
+ ;;reshape for extend-type
262
+ dt->et (fn [specs]
263
+ (loop [ret [] s specs]
264
+ (if (seq s)
265
+ (recur (-> ret
266
+ (conj (first s))
267
+ (into
268
+ (reduce (fn [v [f sigs]]
269
+ (conj v (cons f (map adorn-params sigs))))
270
+ []
271
+ (group-by first (take-while seq? (next s))))))
272
+ (drop-while seq? (next s)))
273
+ ret)))]
274
+ (let [gs (gensym)
275
+ impls (concat
276
+ impls
277
+ ['IRecord
278
+ 'IHash
279
+ `(~'-hash [this#] (hash-coll this#))
280
+ 'IEquiv
281
+ `(~'-equiv [this# other#] (equiv-map this# other#))
282
+ 'IMeta
283
+ `(~'-meta [this#] ~'__meta)
284
+ 'IWithMeta
285
+ `(~'-with-meta [this# ~gs] (new ~tagname ~@(replace {'__meta gs} fields)))
286
+ 'ILookup
287
+ `(~'-lookup [this# k#] (-lookup this# k# nil))
288
+ `(~'-lookup [this# k# else#]
289
+ (get (merge (hash-map ~@(mapcat (fn [fld] [(keyword fld) fld])
290
+ base-fields))
291
+ ~'__extmap)
292
+ k# else#))
293
+ 'ICounted
294
+ `(~'-count [this#] (+ ~(count base-fields) (count ~'__extmap)))
295
+ 'ICollection
296
+ `(~'-conj [this# entry#]
297
+ (if (vector? entry#)
298
+ (-assoc this# (-nth entry# 0) (-nth entry# 1))
299
+ (reduce -conj
300
+ this#
301
+ entry#)))
302
+ 'IAssociative
303
+ `(~'-assoc [this# k# ~gs]
304
+ (condp identical? k#
305
+ ~@(mapcat (fn [fld]
306
+ [(keyword fld) (list* `new tagname (replace {fld gs} fields))])
307
+ base-fields)
308
+ (new ~tagname ~@(remove #{'__extmap} fields) (assoc ~'__extmap k# ~gs))))
309
+ 'IMap
310
+ `(~'-dissoc [this# k#] (if (contains? #{~@(map keyword base-fields)} k#)
311
+ (dissoc (with-meta (into {} this#) ~'__meta) k#)
312
+ (new ~tagname ~@(remove #{'__extmap} fields)
313
+ (not-empty (dissoc ~'__extmap k#)))))
314
+ 'ISeqable
315
+ `(~'-seq [this#] (seq (concat [~@(map #(list `vector (keyword %) %) base-fields)]
316
+ ~'__extmap)))
317
+ 'IPrintable
318
+ `(~'-pr-seq [this# opts#]
319
+ (let [pr-pair# (fn [keyval#] (pr-sequential pr-seq "" " " "" opts# keyval#))]
320
+ (pr-sequential
321
+ pr-pair# (str "#" ~(name rname) "{") ", " "}" opts#
322
+ (concat [~@(map #(list `vector (keyword %) %) base-fields)]
323
+ ~'__extmap))))
324
+ ])]
325
+ `(do
326
+ (~'defrecord* ~tagname ~hinted-fields)
327
+ (extend-type ~tagname ~@(dt->et impls))))))
328
+
329
+ (defn- build-positional-factory
330
+ [rsym rname fields]
331
+ (let [fn-name (symbol (str '-> rsym))]
332
+ `(defn ~fn-name
333
+ [~@fields]
334
+ (new ~rname ~@fields))))
335
+
336
+ (defn- build-map-factory
337
+ [rsym rname fields]
338
+ (let [fn-name (symbol (str 'map-> rsym))
339
+ ms (gensym)
340
+ ks (map keyword fields)
341
+ getters (map (fn [k] `(~k ~ms)) ks)]
342
+ `(defn ~fn-name
343
+ [~ms]
344
+ (new ~rname ~@getters nil (dissoc ~ms ~@ks)))))
345
+
346
+ (defmacro defrecord [rsym fields & impls]
347
+ (let [r (:name (cljs.compiler/resolve-var (dissoc &env :locals) rsym))]
348
+ `(let []
349
+ ~(emit-defrecord rsym r fields impls)
350
+ ~(build-positional-factory rsym r fields)
351
+ ~(build-map-factory rsym r fields))))
352
+
353
+ (defmacro defprotocol [psym & doc+methods]
354
+ (let [p (:name (cljs.compiler/resolve-var (dissoc &env :locals) psym))
355
+ ns-name (-> &env :ns :name)
356
+ fqn (fn [n] (symbol (str ns-name "." n)))
357
+ prefix (protocol-prefix p)
358
+ methods (if (string? (first doc+methods)) (next doc+methods) doc+methods)
359
+ expand-sig (fn [fname slot sig]
360
+ `(~sig
361
+ (if (and ~(first sig) (. ~(first sig) ~slot))
362
+ (. ~(first sig) ~slot ~@sig)
363
+ ((or
364
+ (aget ~(fqn fname) (goog.typeOf ~(first sig)))
365
+ (aget ~(fqn fname) "_")
366
+ (throw (missing-protocol
367
+ ~(str psym "." fname) ~(first sig))))
368
+ ~@sig))))
369
+ method (fn [[fname & sigs]]
370
+ (let [sigs (take-while vector? sigs)
371
+ slot (symbol (str prefix (name fname)))]
372
+ `(defn ~fname ~@(map #(expand-sig fname slot %) sigs))))]
373
+ `(do
374
+ (def ~psym (~'js* "{}"))
375
+ ~@(map method methods))))
376
+
377
+ (defmacro satisfies?
378
+ "Returns true if x satisfies the protocol"
379
+ [psym x]
380
+ (let [p (:name (cljs.compiler/resolve-var (dissoc &env :locals) psym))
381
+ prefix (protocol-prefix p)]
382
+ `(let [x# ~x]
383
+ (if (and x# (. x# ~(symbol prefix)) (not (. x# (~'hasOwnProperty ~prefix))))
384
+ true
385
+ (cljs.core/type_satisfies_ ~psym x#)))))
386
+
387
+ (defmacro lazy-seq [& body]
388
+ `(new cljs.core.LazySeq nil false (fn [] ~@body)))
389
+
390
+ (defmacro binding
391
+ "binding => var-symbol init-expr
392
+
393
+ Creates new bindings for the (already-existing) vars, with the
394
+ supplied initial values, executes the exprs in an implicit do, then
395
+ re-establishes the bindings that existed before. The new bindings
396
+ are made in parallel (unlike let); all init-exprs are evaluated
397
+ before the vars are bound to their new values."
398
+ [bindings & body]
399
+ (let [names (take-nth 2 bindings)
400
+ vals (take-nth 2 (drop 1 bindings))
401
+ tempnames (map gensym names)
402
+ binds (map vector names vals)
403
+ resets (reverse (map vector names tempnames))]
404
+ `(let [~@(interleave tempnames names)]
405
+ (try
406
+ ~@(map
407
+ (fn [[k v]] (list 'set! k v))
408
+ binds)
409
+ ~@body
410
+ (finally
411
+ ~@(map
412
+ (fn [[k v]] (list 'set! k v))
413
+ resets))))))
414
+
415
+ (defmacro condp
416
+ "Takes a binary predicate, an expression, and a set of clauses.
417
+ Each clause can take the form of either:
418
+
419
+ test-expr result-expr
420
+
421
+ test-expr :>> result-fn
422
+
423
+ Note :>> is an ordinary keyword.
424
+
425
+ For each clause, (pred test-expr expr) is evaluated. If it returns
426
+ logical true, the clause is a match. If a binary clause matches, the
427
+ result-expr is returned, if a ternary clause matches, its result-fn,
428
+ which must be a unary function, is called with the result of the
429
+ predicate as its argument, the result of that call being the return
430
+ value of condp. A single default expression can follow the clauses,
431
+ and its value will be returned if no clause matches. If no default
432
+ expression is provided and no clause matches, an
433
+ IllegalArgumentException is thrown."
434
+ {:added "1.0"}
435
+
436
+ [pred expr & clauses]
437
+ (let [gpred (gensym "pred__")
438
+ gexpr (gensym "expr__")
439
+ emit (fn emit [pred expr args]
440
+ (let [[[a b c :as clause] more]
441
+ (split-at (if (= :>> (second args)) 3 2) args)
442
+ n (count clause)]
443
+ (cond
444
+ (= 0 n) `(throw (js/Error. (str "No matching clause: " ~expr)))
445
+ (= 1 n) a
446
+ (= 2 n) `(if (~pred ~a ~expr)
447
+ ~b
448
+ ~(emit pred expr more))
449
+ :else `(if-let [p# (~pred ~a ~expr)]
450
+ (~c p#)
451
+ ~(emit pred expr more)))))
452
+ gres (gensym "res__")]
453
+ `(let [~gpred ~pred
454
+ ~gexpr ~expr]
455
+ ~(emit gpred gexpr clauses))))
456
+
457
+ (defmacro try
458
+ "(try expr* catch-clause* finally-clause?)
459
+
460
+ Special Form
461
+
462
+ catch-clause => (catch protoname name expr*)
463
+ finally-clause => (finally expr*)
464
+
465
+ Catches and handles JavaScript exceptions."
466
+ [& forms]
467
+ (let [catch? #(and (list? %) (= (first %) 'catch))
468
+ [body catches] (split-with (complement catch?) forms)
469
+ [catches fin] (split-with catch? catches)
470
+ e (gensym "e")]
471
+ (assert (every? #(clojure.core/> (count %) 2) catches) "catch block must specify a prototype and a name")
472
+ (if (seq catches)
473
+ `(~'try*
474
+ ~@body
475
+ (catch ~e
476
+ (cond
477
+ ~@(mapcat
478
+ (fn [[_ type name & cb]]
479
+ `[(instance? ~type ~e) (let [~name ~e] ~@cb)])
480
+ catches)
481
+ :else (throw ~e)))
482
+ ~@fin)
483
+ `(~'try*
484
+ ~@body
485
+ ~@fin))))
486
+
487
+ (defmacro assert
488
+ "Evaluates expr and throws an exception if it does not evaluate to
489
+ logical true."
490
+ ([x]
491
+ (when *assert*
492
+ `(when-not ~x
493
+ (throw (js/Error.
494
+ (cljs.core/str "Assert failed: " (cljs.core/pr-str '~x)))))))
495
+ ([x message]
496
+ (when *assert*
497
+ `(when-not ~x
498
+ (throw (js/Error.
499
+ (cljs.core/str "Assert failed: " ~message "\n" (cljs.core/pr-str '~x))))))))
500
+
501
+ (defmacro ^{:private true} assert-args [fnname & pairs]
502
+ `(do (when-not ~(first pairs)
503
+ (throw (IllegalArgumentException.
504
+ ~(str fnname " requires " (second pairs)))))
505
+ ~(let [more (nnext pairs)]
506
+ (when more
507
+ (list* `assert-args fnname more)))))
508
+
509
+ (defmacro for
510
+ "List comprehension. Takes a vector of one or more
511
+ binding-form/collection-expr pairs, each followed by zero or more
512
+ modifiers, and yields a lazy sequence of evaluations of expr.
513
+ Collections are iterated in a nested fashion, rightmost fastest,
514
+ and nested coll-exprs can refer to bindings created in prior
515
+ binding-forms. Supported modifiers are: :let [binding-form expr ...],
516
+ :while test, :when test.
517
+
518
+ (take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))"
519
+ [seq-exprs body-expr]
520
+ (assert-args for
521
+ (vector? seq-exprs) "a vector for its binding"
522
+ (even? (count seq-exprs)) "an even number of forms in binding vector")
523
+ (let [to-groups (fn [seq-exprs]
524
+ (reduce (fn [groups [k v]]
525
+ (if (keyword? k)
526
+ (conj (pop groups) (conj (peek groups) [k v]))
527
+ (conj groups [k v])))
528
+ [] (partition 2 seq-exprs)))
529
+ err (fn [& msg] (throw (apply str msg)))
530
+ emit-bind (fn emit-bind [[[bind expr & mod-pairs]
531
+ & [[_ next-expr] :as next-groups]]]
532
+ (let [giter (gensym "iter__")
533
+ gxs (gensym "s__")
534
+ do-mod (fn do-mod [[[k v :as pair] & etc]]
535
+ (cond
536
+ (= k :let) `(let ~v ~(do-mod etc))
537
+ (= k :while) `(when ~v ~(do-mod etc))
538
+ (= k :when) `(if ~v
539
+ ~(do-mod etc)
540
+ (recur (rest ~gxs)))
541
+ (keyword? k) (err "Invalid 'for' keyword " k)
542
+ next-groups
543
+ `(let [iterys# ~(emit-bind next-groups)
544
+ fs# (seq (iterys# ~next-expr))]
545
+ (if fs#
546
+ (concat fs# (~giter (rest ~gxs)))
547
+ (recur (rest ~gxs))))
548
+ :else `(cons ~body-expr
549
+ (~giter (rest ~gxs)))))]
550
+ `(fn ~giter [~gxs]
551
+ (lazy-seq
552
+ (loop [~gxs ~gxs]
553
+ (when-first [~bind ~gxs]
554
+ ~(do-mod mod-pairs)))))))]
555
+ `(let [iter# ~(emit-bind (to-groups seq-exprs))]
556
+ (iter# ~(second seq-exprs)))))
557
+
558
+ (defmacro doseq
559
+ "Repeatedly executes body (presumably for side-effects) with
560
+ bindings and filtering as provided by \"for\". Does not retain
561
+ the head of the sequence. Returns nil."
562
+ [seq-exprs & body]
563
+ (assert-args doseq
564
+ (vector? seq-exprs) "a vector for its binding"
565
+ (even? (count seq-exprs)) "an even number of forms in binding vector")
566
+ (let [step (fn step [recform exprs]
567
+ (if-not exprs
568
+ [true `(do ~@body)]
569
+ (let [k (first exprs)
570
+ v (second exprs)
571
+
572
+ seqsym (when-not (keyword? k) (gensym))
573
+ recform (if (keyword? k) recform `(recur (first ~seqsym) ~seqsym))
574
+ steppair (step recform (nnext exprs))
575
+ needrec (steppair 0)
576
+ subform (steppair 1)]
577
+ (cond
578
+ (= k :let) [needrec `(let ~v ~subform)]
579
+ (= k :while) [false `(when ~v
580
+ ~subform
581
+ ~@(when needrec [recform]))]
582
+ (= k :when) [false `(if ~v
583
+ (do
584
+ ~subform
585
+ ~@(when needrec [recform]))
586
+ ~recform)]
587
+ :else [true `(let [~seqsym (seq ~v)]
588
+ (when ~seqsym
589
+ (loop [~k (first ~seqsym) ~seqsym ~seqsym]
590
+ ~subform
591
+ (when-let [~seqsym (next ~seqsym)]
592
+ ~@(when needrec [recform])))))]))))]
593
+ (nth (step nil (seq seq-exprs)) 1)))
594
+
595
+ (defmacro amap
596
+ "Maps an expression across an array a, using an index named idx, and
597
+ return value named ret, initialized to a clone of a, then setting
598
+ each element of ret to the evaluation of expr, returning the new
599
+ array ret."
600
+ [a idx ret expr]
601
+ `(let [a# ~a
602
+ ~ret (aclone a#)]
603
+ (loop [~idx 0]
604
+ (if (< ~idx (alength a#))
605
+ (do
606
+ (aset ~ret ~idx ~expr)
607
+ (recur (inc ~idx)))
608
+ ~ret))))
609
+
610
+ (defmacro areduce
611
+ "Reduces an expression across an array a, using an index named idx,
612
+ and return value named ret, initialized to init, setting ret to the
613
+ evaluation of expr at each step, returning ret."
614
+ [a idx ret init expr]
615
+ `(let [a# ~a]
616
+ (loop [~idx 0 ~ret ~init]
617
+ (if (< ~idx (alength a#))
618
+ (recur (inc ~idx) ~expr)
619
+ ~ret))))
620
+
621
+ (defmacro dotimes
622
+ "bindings => name n
623
+
624
+ Repeatedly executes body (presumably for side-effects) with name
625
+ bound to integers from 0 through n-1."
626
+ [bindings & body]
627
+ (let [i (first bindings)
628
+ n (second bindings)]
629
+ `(let [n# ~n]
630
+ (loop [~i 0]
631
+ (when (< ~i n#)
632
+ ~@body
633
+ (recur (inc ~i)))))))
634
+
635
+ (defn ^:private check-valid-options
636
+ "Throws an exception if the given option map contains keys not listed
637
+ as valid, else returns nil."
638
+ [options & valid-keys]
639
+ (when (seq (apply disj (apply hash-set (keys options)) valid-keys))
640
+ (throw
641
+ (apply str "Only these options are valid: "
642
+ (first valid-keys)
643
+ (map #(str ", " %) (rest valid-keys))))))
644
+
645
+ (defmacro defmulti
646
+ "Creates a new multimethod with the associated dispatch function.
647
+ The docstring and attribute-map are optional.
648
+
649
+ Options are key-value pairs and may be one of:
650
+ :default the default dispatch value, defaults to :default
651
+ :hierarchy the isa? hierarchy to use for dispatching
652
+ defaults to the global hierarchy"
653
+ [mm-name & options]
654
+ (let [docstring (if (string? (first options))
655
+ (first options)
656
+ nil)
657
+ options (if (string? (first options))
658
+ (next options)
659
+ options)
660
+ m (if (map? (first options))
661
+ (first options)
662
+ {})
663
+ options (if (map? (first options))
664
+ (next options)
665
+ options)
666
+ dispatch-fn (first options)
667
+ options (next options)
668
+ m (if docstring
669
+ (assoc m :doc docstring)
670
+ m)
671
+ m (if (meta mm-name)
672
+ (conj (meta mm-name) m)
673
+ m)]
674
+ (when (= (count options) 1)
675
+ (throw "The syntax for defmulti has changed. Example: (defmulti name dispatch-fn :default dispatch-value)"))
676
+ (let [options (apply hash-map options)
677
+ default (get options :default :default)
678
+ ;; hierarchy (get options :hierarchy #'cljs.core.global-hierarchy)
679
+ ]
680
+ (check-valid-options options :default :hierarchy)
681
+ `(def ~(with-meta mm-name m)
682
+ (let [method-table# (atom {})
683
+ prefer-table# (atom {})
684
+ method-cache# (atom {})
685
+ cached-hierarchy# (atom {})
686
+ hierarchy# (get ~options :hierarchy cljs.core/global-hierarchy)
687
+ ]
688
+ (cljs.core.MultiFn. ~(name mm-name) ~dispatch-fn ~default hierarchy#
689
+ method-table# prefer-table# method-cache# cached-hierarchy#))))))
690
+
691
+ (defmacro defmethod
692
+ "Creates and installs a new method of multimethod associated with dispatch-value. "
693
+ [multifn dispatch-val & fn-tail]
694
+ `(-add-method ~(with-meta multifn {:tag 'cljs.core.MultiFn}) ~dispatch-val (fn ~@fn-tail)))
695
+
696
+ (defmacro time
697
+ "Evaluates expr and prints the time it took. Returns the value of expr."
698
+ [expr]
699
+ `(let [start# (.getTime (js/Date.) ())
700
+ ret# ~expr]
701
+ (prn (str "Elapsed time: " (- (.getTime (js/Date.) ()) start#) " msecs"))
702
+ ret#))