<< Back to previous view

[CLJS-1389] Support Override of Custom Closure Defines w/ :none/:whitespace Created: 02/Aug/15  Updated: 02/Aug/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Martin Klepsch Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

When creating "uncompiled" builds (:none, :whitespace) it is not possible to override a custom Closure @define by passing a different value to the compiler option `:closure-defines`.

Closure provides `CLOSURE_UNCOMPILED_DEFINES` and `CLOSURE_DEFINES` [1] which can be set before loading any other code.
Overriding defines this way only works for Defines with done with `goog.define`.
Using `goog.define` however introduces other problems:
1) The name passed to `goog/define` must match the name in compiled JS. E.g. `(goog/define "hello_world.core.DBG" true)`.
2) This produces no var in CLJS which causes an undeclared var warning if the defined var is used.
3) There is nothing to be annotated causing `ERROR: JSC_INVALID_MISSING_DEFINE_ANNOTATION.`

Getting the `CLOSURE_UNCOMPILED_DEFINES` into the build is straightforward, just not sure how to deal with those other complexities.

[1] http://google.github.io/closure-library/api/source/closure/goog/base.js.src.html#l147






[CLJS-1388] Stacktrace element handling for :output-dir w/o file/line/column Created: 02/Aug/15  Updated: 02/Aug/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

If parsing stacktraces when :host and :port are supplied, elements that have no file/line/column are properly accommodated.

For example:

https://github.com/clojure/clojurescript/blob/v1.7/src/main/cljs/cljs/stacktrace.cljc#L266

But, an attempt to process a similar stacktrace when :output-dir is being used, an error will be thrown. (This can occur when using :output-dir for embedded JavaScriptCore.)

Here is a simple repro:

(parse-stacktrace {}
"cljs$core$seq@out/cljs/core.js:3999:17
cljs$core$first@out/core.js:4018:22
cljs$core$ffirst@out/cljs/core.js:5161:39
global code"
{:ua-product :safari} 
{:output-dir "out"})





[CLJS-1387] support for Closure libraries that conform to classpath conventions does not work for local libraries Created: 01/Aug/15  Updated: 01/Aug/15  Resolved: 01/Aug/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Only works for libs in JARs.



 Comments   
Comment by David Nolen [ 01/Aug/15 10:50 AM ]

fixed https://github.com/clojure/clojurescript/commit/f14b561640cd5da3aa52d5425943734635ee749e





[CLJS-1386] Symbols should be added to the constants table Created: 01/Aug/15  Updated: 01/Aug/15  Resolved: 01/Aug/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Now that optional bootstrap is a thing, this is a significant optimization.



 Comments   
Comment by David Nolen [ 01/Aug/15 6:11 AM ]

fixed https://github.com/clojure/clojurescript/commit/d92b3004046d1f83ab76a2b94f4129cb16e47848





[CLJS-1385] cljs.js/compile-str does not correctly track the current ns Created: 31/Jul/15  Updated: 31/Jul/15  Resolved: 31/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Macros are not correctly expanded. Instead macro calls resolve to cljs.user.



 Comments   
Comment by David Nolen [ 31/Jul/15 10:22 AM ]

fixed https://github.com/clojure/clojurescript/commit/f3cf45d745af5e63500375d084dd0d7b19c40dac





[CLJS-1384] cljs.js/eval-str doc that :ns returned upon success Created: 31/Jul/15  Updated: 31/Jul/15  Resolved: 31/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

If eval-str is called and it succeeds with a `:value`, the resulting `:ns` is also passed back, but the doctoring hasn't been updated to reflect this fact.



 Comments   
Comment by David Nolen [ 31/Jul/15 8:38 AM ]

fixed https://github.com/clojure/clojurescript/commit/86f8255d4536e4e2022adb467db46293c7616f74





[CLJS-1383] cljs.js/eval in a specific ns does not work Created: 30/Jul/15  Updated: 30/Jul/15  Resolved: 30/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Not Reproducible Votes: 0
Labels: None


 Description   
(cljs/eval (cljs/empty-state)
           '(def x 1)
           {:eval cljs/js-eval
            :context :expr
            :def-emits-var true
            :ns cells.core
            }
           #(pprint %))


 Comments   
Comment by David Nolen [ 30/Jul/15 3:05 PM ]

Cannot repro on master





[CLJS-1382] Macros time and case use unqualified core/str in syntax quote (breaks bootstrap) Created: 30/Jul/15  Updated: 30/Jul/15  Resolved: 30/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Joel Martin Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: bootstrap
Environment:

cljs-bootstrap


Attachments: Text File time-case-fix.patch    
Patch: Code

 Description   

The following are broken in bootstrapped clojurescript because they call unqualified versions of core/str within syntax quote:

(time (reduce #(+ %1 %2) 0 (range 1000000)))

(case :constant false "nope")


 Comments   
Comment by David Nolen [ 30/Jul/15 11:36 AM ]

fixed https://github.com/clojure/clojurescript/commit/cf0374cfe9e85ae77f26c062190241f09caa5544





[CLJS-1381] cljs.js: Memory perf on JSC for first defn evaluation Created: 30/Jul/15  Updated: 30/Jul/15  Resolved: 30/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: None

Attachments: PNG File memory.png    

 Description   

If you evaluate something like (defn f []) via cljs.js/eval-str with JavaScriptCore, a spike in memory will occur and it will take several seconds to complete the evaluation. After this, subsequent evaluations don't exhibit this behavior. Also, this doesn't occur for Firefox or Chrome.

Additionally, it did not occur previously with bootstrapped ClojureScript when we were building things outside of `cljs.js` (it doesn't occur in Replete, for example, nor the earlier versions of Planck: https://youtu.be/AMT63rxK4E8).

You can see it for yourself at http://ClojureScript.net (you can see the slowness in desktop Safari, and on an iPhone it exhausts memory).



 Comments   
Comment by Mike Fikes [ 30/Jul/15 10:58 AM ]

Attached memory.png, which shows what happens in Planck when you do (defn f [])

Comment by Mike Fikes [ 30/Jul/15 5:06 PM ]

This is the same as CLJS-910. An easy workaround is :static-fns true.





[CLJS-1380] Hashing is broken when using iphone 4 Created: 30/Jul/15  Updated: 31/Jul/15  Resolved: 31/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Jean-Louis Giordano Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: bug
Environment:

iphone 4 running iOS 7.1.2



 Description   

On a physical iPhone 4 running iOS 7.1.2, when running the `hash` function too many times at the top level, the result becomes inconsistent.

This only happens when not using the safari webinspector.

I have setup a minimal failing spec here: https://github.com/Jell/iphone-bug

Instructions to reproduce in the README.

I must confess, this took me a very long time to debug! I hope someone can take it from here.



 Comments   
Comment by Jean-Louis Giordano [ 30/Jul/15 7:23 AM ]

With the help of my colleague, we narrowed it down further to this:

(ns iphone-bug.core)

(def yyyy (hash "yyyy"))

(dotimes [i 1000] (hash "yyyy"))

(js/alert (str "Before: " yyyy " After: " (hash "yyyy")))
Comment by Jean-Louis Giordano [ 30/Jul/15 7:36 AM ]

Note: the bug only appears on iPhone 4, not iPhone 4S!

Comment by David Nolen [ 30/Jul/15 10:58 AM ]

I believe this is something to do with 32bit vs. 64bit JavaScriptCore. Super low priority but happy to take a patch if someone can devise one.

Comment by Thomas Heller [ 30/Jul/15 11:34 AM ]

Sounds like something which was fixed a long time ago and I haven't personally seen since. Maybe a recent change reverted the Math.imul fix?

http://dev.clojure.org/jira/browse/CLJS-839
http://dev.clojure.org/jira/browse/CLJS-830

Comment by David Nolen [ 30/Jul/15 11:53 AM ]

Thomas I'm not sure we solved this for older phones only relatively newer ones with specific versions of Safari. iPhone 4 was ARM Cortex A8, and the 4S was an ARM Cortex A9. Turns out both are 32bit, but I still suspect this is a JITing issue if it disappears with a debugger attached.

Comment by Thomas Heller [ 31/Jul/15 3:33 AM ]

Just saying that the description exactly matched what I saw when investigating the keyword hashing issue. The problem never appeared with the devtools running and sometimes produced the correct hash without. After adding the imul.js the issue disappeared and clients stopped sending invalid maps. See CLJS-830 for a list of user agents [1] that were problematic before, the issue was with a specific webkit version and seemingly not hardware related (iOS 7.1.2 was the version at the time, user agents don't identify the device though).

Not claiming that this is the same issue, just saying that it sounds very very similar.

[1] https://gist.github.com/thheller/8cae79cabd9ac74958ca

Comment by Jean-Louis Giordano [ 31/Jul/15 9:32 AM ]

We found a fix that works for us!

We redefine the imul polyfill (cljs/imul.js) with the following:

if(typeof Math.imul == "undefined" || (Math.imul(0xffffffff,5) == 0)) {
    Math.imul = function (a, b) {
      try {
        var ah  = (a >>> 16) & 0xffff;
        var al = a & 0xffff;
        var bh  = (b >>> 16) & 0xffff;
        var bl = b & 0xffff;
        // the shift by 0 fixes the sign on the high part
        // the final |0 converts the unsigned value into a signed value
        return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0);
      } catch(err) { throw err; }
    }
}

The error is not really coming from inside this function, but adding the try/catch disables JIT optimisation for callers of imul as far as we understand, which solves the hashing issues we saw on Iphone 4.

The errors seems to come from bit operations, in particular the `x|0` operations (corresponding to (int x) calls or bit-or in CLJS).

Infuriating to pin the bug down, because observing intermediate variables will prevent the bug from happening!

Comment by Francis Avila [ 31/Jul/15 9:59 AM ]

This is going to cause an enormous performance regression.

Comment by Jean-Louis Giordano [ 31/Jul/15 10:05 AM ]

Well a perf regression for the browsers that do not have a built-in or broken Math/imul, which might not be that big of a deal?

This is good enough for us at least, so we will probably not be investigating this further.

Comment by David Nolen [ 31/Jul/15 10:20 AM ]

Thanks for the bug report good to have monkey-path solution for those that need it. Closing this one.





[CLJS-1379] cljs.js: Macroexpansion defeated when calling helper Created: 29/Jul/15  Updated: 30/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Mike Fikes
Resolution: Unresolved Votes: 0
Labels: None
Environment:

1.7.10



 Description   

If you have a namespace:

(ns foo.macros
  (:require foo.helper))

(defmacro my-inc [n]
  `(foo.helper/my-inc ~n))

That makes use of a helper namespace:

(ns foo.helper)

(defn my-inc [x]
  (inc x))

Then things will work properly for non-bootstrapped ClojureScript. Here is an example use in Ambly:

cljs.user=> (require 'foo.helper)
nil
cljs.user=> (require-macros 'foo.macros)
nil
cljs.user=> (defn f [] (foo.macros/my-inc 3))
#'cljs.user/f
cljs.user=> f
#<function cljs$user$f() {
return foo.helper.my_inc.call(null,(3));
}>
cljs.user=> (f)
4

But, the same sequence in bootstrapped ClojureScript fails:

cljs.user=> (require 'foo.helper)
nil
cljs.user=> (require-macros 'foo.macros)
nil
cljs.user=> (defn f [] (foo.macros/my-inc 3))
#'cljs.user/f
cljs.user=> f
#<function cljs$user$f() {
return foo.macros.my_inc.call(null,3);
}>
cljs.user=> (f)
Error occurred
cljs$user$f

Note that the emitted JavaScript in this second case treats the macro as a function.

Also, I've seen that if you eliminate the call to a helper, but instead, say make direct use of say, inc, then macro expansion works properly in bootstrapped ClojureScript (and for the example above you end up with JavaScript code that adds 1 and 3.)

Of course, these are with downstream REPLs. Let me know if a minimal repro without any downstream stuff is desired and I'm sure I can scratch one together involving the same calls Planck is making to cljs.js.



 Comments   
Comment by David Nolen [ 30/Jul/15 3:18 PM ]

The second case is only possible if for some reason the macros could not get loaded.

Comment by Mike Fikes [ 30/Jul/15 5:12 PM ]

As discussed in IRC, Mike to add minimal repro to this ticket.





[CLJS-1378] JARs that end in .exe are problematic Created: 29/Jul/15  Updated: 30/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

compile-from-jar cannot handle the later form

{{jar:file:/Users/candera/cognitect/walmart/walsim/deploy/walsim-v0.3.5.jar!/cljs/com/walmart/test/app.cljs}}
{{jar:file:/Users/candera/cognitect/walmart/walsim/deploy/walsim-v0.3.5.exe!/cljs/com/walmart/test/app.cljs}}






[CLJS-1377] om-tools.core fails to compile Created: 29/Jul/15  Updated: 30/Jul/15  Resolved: 30/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Sean Grove Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

Any file with a ns declaration that requires om-tools.core will throw an exception:

(ns example.core (:require [om-tools.core]))

=>

clojure.lang.ExceptionInfo: failed compiling file:src/cljs/example/core.cljs {:file #object[java.io.File 0x37f37699 "src/cljs/example/core.cljs"]}
at clojure.core$ex_info.invoke(core.clj:4593)
at cljs.compiler$compile_file$fn__2999.invoke(compiler.cljc:1249)
at cljs.compiler$compile_file.invoke(compiler.cljc:1211)
at cljs.compiler$compile_root.invoke(compiler.cljc:1286)
at cljs.closure$compile_dir.invoke(closure.clj:430)
at cljs.closure$eval3382$fn__3383.invoke(closure.clj:470)
at cljs.closure$eval3334$fn_3335$G3325_3342.invoke(closure.clj:375)
at cljs.closure$eval3395$fn__3396.invoke(closure.clj:484)
at cljs.closure$eval3334$fn_3335$G3325_3342.invoke(closure.clj:375)
at cljsbuild.compiler.SourcePaths$fn__3862.invoke(compiler.clj:67)
at clojure.core$map$fn__4553.invoke(core.clj:2622)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:507)
at clojure.core$seq__4128.invoke(core.clj:137)
at clojure.core$apply.invoke(core.clj:630)
at clojure.core$mapcat.doInvoke(core.clj:2660)
at clojure.lang.RestFn.invoke(RestFn.java:423)
at cljsbuild.compiler.SourcePaths._compile(compiler.clj:67)
at cljs.closure$build.invoke(closure.clj:1634)
at cljs.closure$build.invoke(closure.clj:1590)
at cljsbuild.compiler$compile_cljs$fn__3873.invoke(compiler.clj:81)
at cljsbuild.compiler$compile_cljs.invoke(compiler.clj:80)
at cljsbuild.compiler$run_compiler.invoke(compiler.clj:187)
at user$eval4007$iter_40434047$fn4048$fn_4066.invoke(form-init7604443915532456796.clj:1)
at user$eval4007$iter_40434047$fn_4048.invoke(form-init7604443915532456796.clj:1)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:507)
at clojure.core$seq__4128.invoke(core.clj:137)
at clojure.core$dorun.invoke(core.clj:3009)
at clojure.core$doall.invoke(core.clj:3025)
at user$eval4007.invoke(form-init7604443915532456796.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6772)
at clojure.lang.Compiler.load(Compiler.java:7227)
at clojure.lang.Compiler.loadFile(Compiler.java:7165)
at clojure.main$load_script.invoke(main.clj:275)
at clojure.main$init_opt.invoke(main.clj:280)
at clojure.main$initialize.invoke(main.clj:308)
at clojure.main$null_opt.invoke(main.clj:343)
at clojure.main$main.doInvoke(main.clj:421)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: clojure.lang.ExceptionInfo: Don't know how to create ISeq from: clojure.lang.Symbol {:tag :cljs/analysis-error}
at clojure.core$ex_info.invoke(core.clj:4593)
at cljs.analyzer$error.invoke(analyzer.cljc:525)
at cljs.analyzer$analyze_seq_STAR__wrap.invoke(analyzer.cljc:2363)
at cljs.analyzer$analyze_seq.invoke(analyzer.cljc:2381)
at cljs.analyzer$analyze_form.invoke(analyzer.cljc:2490)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:2536)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2552)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2547)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2546)
at cljs.analyzer$analyze_do_statements_STAR_$fn__1522.invoke(analyzer.cljc:1370)
at clojure.core$map$fn__4553.invoke(core.clj:2622)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:507)
at clojure.core$seq__4128.invoke(core.clj:137)
at cljs.analyzer$analyze_do_statements_STAR_.invoke(analyzer.cljc:1370)
at cljs.analyzer$analyze_do_statements.invoke(analyzer.cljc:1373)
at cljs.analyzer$eval1526$fn__1528.invoke(analyzer.cljc:1377)
at clojure.lang.MultiFn.invoke(MultiFn.java:251)
at cljs.analyzer$analyze_seq_STAR_.invoke(analyzer.cljc:2359)
at cljs.analyzer$analyze_seq_STAR__wrap.invoke(analyzer.cljc:2364)
at cljs.analyzer$analyze_seq.invoke(analyzer.cljc:2381)
at cljs.analyzer$analyze_form.invoke(analyzer.cljc:2490)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:2536)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2552)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2547)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2546)
at cljs.analyzer$analyze_let_body_STAR_.invoke(analyzer.cljc:1456)
at cljs.analyzer$analyze_let_body.invoke(analyzer.cljc:1461)
at cljs.analyzer$analyze_let.invoke(analyzer.cljc:1477)
at cljs.analyzer$eval1545$fn__1546.invoke(analyzer.cljc:1489)
at clojure.lang.MultiFn.invoke(MultiFn.java:251)
at cljs.analyzer$analyze_seq_STAR_.invoke(analyzer.cljc:2359)
at cljs.analyzer$analyze_seq_STAR__wrap.invoke(analyzer.cljc:2364)
at cljs.analyzer$analyze_seq.invoke(analyzer.cljc:2381)
at cljs.analyzer$analyze_form.invoke(analyzer.cljc:2490)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:2536)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2552)
at cljs.analyzer$analyze_seq.invoke(analyzer.cljc:2382)
at cljs.analyzer$analyze_form.invoke(analyzer.cljc:2490)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:2536)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2552)
at cljs.analyzer$analyze_seq.invoke(analyzer.cljc:2382)
at cljs.analyzer$analyze_form.invoke(analyzer.cljc:2490)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:2536)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2552)
at cljs.analyzer$analyze_file$fn__2031.invoke(analyzer.cljc:2796)
at cljs.analyzer$analyze_file.invoke(analyzer.cljc:2791)
at cljs.analyzer$analyze_deps.invoke(analyzer.cljc:1625)
at cljs.analyzer$ns_side_effects.invoke(analyzer.cljc:2457)
at cljs.analyzer$analyze_STAR_$fn__1980.invoke(analyzer.cljc:2537)
at clojure.lang.PersistentVector.reduce(PersistentVector.java:333)
at clojure.core$reduce.invoke(core.clj:6518)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:2537)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2552)
at cljs.analyzer$analyze_file$fn__2031.invoke(analyzer.cljc:2796)
at cljs.analyzer$analyze_file.invoke(analyzer.cljc:2791)
at cljs.analyzer$analyze_deps.invoke(analyzer.cljc:1625)
at cljs.analyzer$ns_side_effects.invoke(analyzer.cljc:2457)
at cljs.analyzer$analyze_STAR_$fn__1980.invoke(analyzer.cljc:2537)
at clojure.lang.PersistentVector.reduce(PersistentVector.java:333)
at clojure.core$reduce.invoke(core.clj:6518)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:2537)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2552)
at cljs.analyzer$analyze_file$fn__2031.invoke(analyzer.cljc:2796)
at cljs.analyzer$analyze_file.invoke(analyzer.cljc:2791)
at cljs.analyzer$analyze_deps.invoke(analyzer.cljc:1625)
at cljs.analyzer$ns_side_effects.invoke(analyzer.cljc:2457)
at cljs.analyzer$analyze_STAR_$fn__1980.invoke(analyzer.cljc:2537)
at clojure.lang.PersistentVector.reduce(PersistentVector.java:333)
at clojure.core$reduce.invoke(core.clj:6518)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:2537)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2552)
at cljs.analyzer$analyze_file$fn__2031.invoke(analyzer.cljc:2796)
at cljs.analyzer$analyze_file.invoke(analyzer.cljc:2791)
at cljs.analyzer$analyze_deps.invoke(analyzer.cljc:1625)
at cljs.analyzer$ns_side_effects.invoke(analyzer.cljc:2457)
at cljs.analyzer$analyze_STAR_$fn__1980.invoke(analyzer.cljc:2537)
at clojure.lang.PersistentVector.reduce(PersistentVector.java:333)
at clojure.core$reduce.invoke(core.clj:6518)
at cljs.analyzer$analyze_STAR_.invoke(analyzer.cljc:2537)
at cljs.analyzer$analyze.invoke(analyzer.cljc:2552)
at cljs.compiler$compile_file_STAR_$fn__2958.invoke(compiler.cljc:1120)
at cljs.compiler$with_core_cljs.invoke(compiler.cljc:1048)
at cljs.compiler$compile_file_STAR_.invoke(compiler.cljc:1071)
at cljs.compiler$compile_file$fn__2999.invoke(compiler.cljc:1232)
... 45 more
Caused by: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
at clojure.lang.RT.seqFrom(RT.java:528)
at clojure.lang.RT.seq(RT.java:509)
at clojure.core$seq__4128.invoke(core.clj:137)
at clojure.core.protocols$seq_reduce.invoke(protocols.clj:30)
at clojure.core.protocols$fn__6500.invoke(protocols.clj:84)
at clojure.core.protocols$fn_6452$G6447_6465.invoke(protocols.clj:13)
at clojure.core$reduce.invoke(core.clj:6519)
at cljs.analyzer$parse_type.invoke(analyzer.cljc:1943)
at cljs.analyzer$eval1766$fn__1767.invoke(analyzer.cljc:1972)
at clojure.lang.MultiFn.invoke(MultiFn.java:251)
at cljs.analyzer$analyze_seq_STAR_.invoke(analyzer.cljc:2359)
at cljs.analyzer$analyze_seq_STAR__wrap.invoke(analyzer.cljc:2364)
... 128 more
Subprocess failed



 Comments   
Comment by David Nolen [ 30/Jul/15 7:33 AM ]

already fixed in master.





[CLJS-1376] Printing in a tagged literal data form Created: 28/Jul/15  Updated: 30/Jul/15  Resolved: 30/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Task Priority: Major
Reporter: Ewen Grosjean Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1376.patch    

 Description   

Since Clojure 1.7, objects, functions, atoms and volatiles print in a tagged literal data form.

(atom {})
#object[clojure.lang.Atom 0x349c1daf {:status :ready, :val {}}]

Clojurescript format is different

(atom {})
#<Atom: {}>


 Comments   
Comment by Ewen Grosjean [ 30/Jul/15 3:52 PM ]

patch attached.

(fn [] nil)
#object ["function" "function (){\nreturn null;\n}"]
(js/AnimationEvent. 1)
#object ["object" "[object AnimationEvent]"]
(atom {})
#object [cljs.core.Atom {:status :ready, :val {}}]
(volatile! 1)
#object [cljs.core.Volatile 1]

I have also made undefined printing to nil.

I hope that helps.

Comment by David Nolen [ 30/Jul/15 4:01 PM ]

fixed https://github.com/clojure/clojurescript/commit/34c3b8985ed8197d90f441c46d168c4024a20eb8

Comment by David Nolen [ 30/Jul/15 4:03 PM ]

Ewen you need to submit a CA if you want to submit patches. Once you've done that you should assign tickets to yourself if you decide to work on them so people are aware of progress.

Comment by Ewen Grosjean [ 30/Jul/15 4:26 PM ]

Thanks for the fix.

I think there are still a few things missing.
Atom and volatile are still printed the old way: https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L9053
As is "undefined", even though undefined is printed as nil because it is catched by the nil? clause:
https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L8776





[CLJS-1375] cljs.js/require does not conj to *loaded* Created: 28/Jul/15  Updated: 28/Jul/15  Resolved: 28/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

Master "0.0-3664"


Attachments: Text File CLJS-1375.patch    
Patch: Code

 Description   

While :reload and :reload-all remove from *loaded*, nothing adds to it.

Steps to reproduce.

(do (set! js/window js/global) nil)

(require 'cljs.js)

(defn load [spec cb]
  (prn spec)
  (cb {:lang   :clj
       :source (case (:path spec)
                 "test/alpha" "(ns test.alpha)")}))

(defn eval [{:keys [source]}]
  (js/eval source))

(cljs.js/require 
  'test.alpha
  {:load load
   :eval eval} 
  (fn [res] (prn res)))
; {:name test.alpha, :macros nil, :path "test/alpha"}
; {:value true}

@cljs.js/*loaded*
; #{}

(cljs.js/require 
  'test.alpha
  {:load load
   :eval eval} 
  (fn [res] (prn res)))
; {:name test.alpha, :macros nil, :path "test/alpha"}
; {:value true}


 Comments   
Comment by David Nolen [ 28/Jul/15 4:30 PM ]

fixed https://github.com/clojure/clojurescript/commit/a1dca29d3ba248062de055a7c951512949515b9b





[CLJS-1374] cljs.js/require doesn't supply good defaults Created: 28/Jul/15  Updated: 28/Jul/15  Resolved: 28/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

Master 0.0-3664



 Description   

Here is a case where cljs.js/require works properly with respect to loading transitive namespaces:

(ns test.alpha
  (:require test.beta))

(defn f [] 
  test.beta/x)
(ns test.beta)

(def x 3)

For the above, a require for test.alpha causes *load-fn* to be called with this sequence:

{:name test.alpha, :macros nil, :path "test/alpha"}
{:name test.beta, :macros nil, :path "test/beta"}

calling back with this result:

{:value true}

On the other hand, here is an example where an ns form works but require fails:

(ns foo.core
  (#?(:clj  :require 
      :cljs :require-macros)
    [foo.macros]))

(defn str->int [s]
  #?(:clj  (Integer/parseInt s)
     :cljs (js/parseInt s)))

(defn add-five [s]
  (+ (str->int s) 
     (foo.macros/str->int "5")))
(ns foo.macros)

(defmacro str->int [s]
  #?(:clj  (Integer/parseInt s)
     :cljs (js/parseInt s)))

In this case, require results in this sequence:

{:name foo.core, :macros nil, :path "foo/core"}

calling back with this result:

{:value true}

Starting with a fresh REPL, here is what (ns cljs.user (:require foo.core)) results in:

{:name foo.core, :macros nil, :path "foo/core"}
{:name foo.macros, :macros true, :path "foo/macros"}


 Comments   
Comment by Mike Fikes [ 28/Jul/15 12:13 PM ]

Minimal repro:

Set up a ClojureScript REPL with access to

[org.clojure/tools.reader "0.10.0-SNAPSHOT" :exclusions [org.clojure/clojure]]

Then run the following forms in the REPL (I did this in Ambly Demo, but apart from the need to do the js/window bit, it probably reproduces in any ClojureScript REPL):

(do (set! js/window js/global) nil)

(require 'cljs.js)
(require 'cljs.tagged-literals)

(def st (cljs.js/empty-state))

(defn load [spec cb]
  (prn spec)
  (cb {:lang   :clj
       :source (case (:path spec)
                 "test/alpha" "(ns test.alpha (:require test.beta))"
                 "test/beta" "(ns test.beta)"
                 "foo/core" "(ns foo.core (:require-macros foo.macros))"
                 "foo/macros" "(ns foo.macros)")}))

(defn eval [{:keys [source]}]
  (js/eval source))

(defn test-require [sym]
  (cljs.js/require
    {:*compiler*     st
     :*data-readers* cljs.tagged-literals/*cljs-data-readers*
     :*load-fn*      load
     :*eval-fn*      eval}
    sym
    nil
    (fn [res]
      (prn res))))

(test-require 'test.alpha)
; {:name test.alpha, :macros nil, :path "test/alpha"}
; {:name test.beta, :macros nil, :path "test/beta"}
; {:value true}

(test-require 'foo.core)
; {:name foo.core, :macros nil, :path "foo/core"}
; {:value true}
Comment by Mike Fikes [ 28/Jul/15 5:16 PM ]

With {:verbose true}

cljs.user=> *clojurescript-version*
"0.0-3670"
cljs.user=> (test-require 'test.alpha)
Loading test.alpha namespace
{:name test.alpha, :macros nil, :path "test/alpha"}
Evaluating test.alpha
Namespace side effects for test.alpha
Loading dependencies for test.alpha
Loading test.beta namespace
{:name test.beta, :macros nil, :path "test/beta"}
Evaluating test.beta
Namespace side effects for test.beta
goog.provide("test.beta");

Loading dependencies for test.alpha
goog.provide("test.alpha");

{:value true}
nil
cljs.user=> (test-require 'foo.core)
Loading foo.core namespace
{:name foo.core, :macros nil, :path "foo/core"}
Evaluating foo.core
Namespace side effects for foo.core
goog.provide("foo.core");

{:value true}
nil
Comment by David Nolen [ 28/Jul/15 5:40 PM ]

fixed https://github.com/clojure/clojurescript/commit/078f207884304dd39c61775345505d4da7ca9b64

Comment by Mike Fikes [ 28/Jul/15 5:53 PM ]

Confirmed fixed using the minimal repro. I now see:

cljs.user=> (test-require 'foo.core)
{:name foo.core, :macros nil, :path "foo/core"}
{:name foo.macros, :macros true, :path "foo/macros"}
{:value true}
nil




[CLJS-1373] Generalize CLJS-1324, check invokes of all IFn implementors Created: 28/Jul/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

We currently track all IFn implementors but in order to do arity checking of statically analyzeable invokes of keywords, vector, etc. we need to do a bit more. extend-type should update the type in the compiler state with :method-params :max-fixed-arity and :variadic. Then we can just reuse the existing checks in cljs.analyzer/parse-invoke.






[CLJS-1372] cljs.stacktrace: Unconditional File reference in :nashorn section Created: 27/Jul/15  Updated: 27/Jul/15  Resolved: 27/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Mike Fikes
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1372.patch    

 Description   

In the :nashorn impl there is a platform-dependent line referring to Java File/separator

https://github.com/clojure/clojurescript/blob/fa0da846e6f30eec330fac9e2ac8aced2660d20f/src/main/cljs/cljs/stacktrace.cljc#L414

Perhaps the entire (defmethod parse-stacktrace :nashorn should be conditional on :clj?



 Comments   
Comment by Mike Fikes [ 27/Jul/15 11:33 AM ]

Attached patch copies approach taken for :rhino.

Passes unit tests and this smoke test:

orion:clojurescript mfikes$ script/nashornrepljs 
To quit, type: :cljs/quit
cljs.user=> (ffirst 1)
Error: 1 is not ISeqable
	 cljs$core$seq (.cljs_nashorn_repl/cljs/core.cljs:1067:36)
	 cljs.core/first (.cljs_nashorn_repl/cljs/core.cljs:1076:13)
	 cljs$core$ffirst (.cljs_nashorn_repl/cljs/core.cljs:1514:4)
	 (NO_SOURCE_FILE <eval>:1:0)
	 (NO_SOURCE_FILE <eval>:1:0)
	 (NO_SOURCE_FILE <eval>:1:0)
Comment by David Nolen [ 27/Jul/15 2:00 PM ]

fixed https://github.com/clojure/clojurescript/commit/d7db622e4eecf305bbf24c107e3b05d926fd916a





[CLJS-1371] cljs.js: Core functions in required namespaces Created: 27/Jul/15  Updated: 27/Jul/15  Resolved: 27/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

Like CLJS-1362, but for required namespaces.

I have a namespace that uses map:

(ns foo.bar)

(defn test-me []
  (map inc [1 2 3]))

(defn test-me-2 []
  (cljs.core/map inc [1 2 3]))

Here is a transcript from Planck illustrating an issue with map being used in test-me:

cljs.user=> *clojurescript-version*
"0.0-3654"
cljs.user=> (map inc [1 2 3])
(2 3 4)
cljs.user=> (require 'foo.bar)
cljs.user=> (foo.bar/test-me-2)
(2 3 4)
cljs.user=> (foo.bar/test-me)
undefined is not an object (evaluating 'foo.bar.map.call') 
 foo$bar$test_me
cljs.user=>


 Comments   
Comment by Mike Fikes [ 27/Jul/15 9:52 AM ]

Defect in Planck not cljs.js: I was passing an empty compiler environment into cljs.js/require instead of my atom.





[CLJS-1370] cljs.js: Path for goog off Created: 27/Jul/15  Updated: 30/Jul/15  Resolved: 30/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: bootstrap


 Description   

I have a namespace that indirectly uses goog.

(ns foo.bar
  (:require clojure.string))

(def a 4)

When I use cljs.js to require this source, ultimately the path "goog/string" is passed to *load-fn*. The transcript here shows the argument sequence passed to *load-fn*.

cljs.user=> (require 'foo.bar)
{:name foo.bar, :macros nil, :path "foo/bar"}
{:name clojure.string, :macros nil, :path "clojure/string"}
{:name goog.string, :macros nil, :path "goog/string"}

My *load-fn* implementation successfully loads clojure/string.cljs which contains

(:require [goog.string :as gstring])

as one of its namespace specs, which triggers the last path "goog/string".

On disk, there is actually "goog/string/string.js" that could be loaded, but before trying any hacking surrounding that, figured I'd submit a ticket regarding this case.



 Comments   
Comment by David Nolen [ 30/Jul/15 3:24 PM ]

We're not going to address this one at all. REPLs will have to provide their own Google Closure Library index to make this work.





[CLJS-1369] eval-str should support compilation output caching Created: 27/Jul/15  Updated: 27/Jul/15  Resolved: 27/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: bootstrap


 Description   

This is the only place for people to run side effects (like writing compilation output to disk).



 Comments   
Comment by David Nolen [ 27/Jul/15 9:12 AM ]

fixed https://github.com/clojure/clojurescript/commit/de8bc1c4cce44e9c6de07bbf79411463138939ee





[CLJS-1368] cljs.analyzer tests broken, undeclared-var warning doesn't work Created: 26/Jul/15  Updated: 27/Jul/15  Resolved: 27/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: Juho Teperi Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

A test in `cljs.analyzer-tests` is failing because undeclared-var test doesn't produce warning: https://github.com/clojure/clojurescript/blob/bf643dbbb06eb7ae5ec27cb9feaa9aa41960862f/src/test/clojure/cljs/analyzer_tests.clj#L31

I bisected the problem to this commit: https://github.com/clojure/clojurescript/commit/f46db8f693b7337cdc095819e412ee3e154d9e83



 Comments   
Comment by David Nolen [ 27/Jul/15 7:40 AM ]

fixed https://github.com/clojure/clojurescript/commit/8b70d7541ffd61789c6e95b1d58e471e12d310e0





[CLJS-1367] cljs.analyzer.api warning handler utilities Created: 26/Jul/15  Updated: 28/Jul/15  Resolved: 28/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Enhancement Priority: Major
Reporter: Juho Teperi Assignee: Juho Teperi
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File cljs-1367-1.patch     Text File cljs-1367-2.patch     Text File cljs-1367-3.patch    

 Description   

To see if warnings happened during the compilation process build tooling has to currently use cljs.analyzer ns directly.

In boot-cljs we currently use cljs.analyzer/with-warning-handlers to append our own warning-handler to default handlers to count number of warnings.

I propose adding with-warning-handlers to cljs.analyzer.api. Also there should be a way to modify existing warning-handlers binding without overwriting the default handlers, my idea is to provide vary-warning-handlers macro which would use given function to create new handlers collection.

The default warning handler uses cljs.analyzer/*cljs-warnings* to check if warning was enabled, this should be exposed also.

I have implemented the changes already, but I have some problems testing them as I can't get {[analyze}} to generate any warnings.



 Comments   
Comment by Juho Teperi [ 26/Jul/15 12:58 PM ]

I noticed it's undeclared-var warning which is not working, so I used another warning to test these utilities.

Comment by Juho Teperi [ 26/Jul/15 3:58 PM ]

Here is the code in boot-cljs which uses warning handlers: https://github.com/adzerk-oss/boot-cljs/blob/31732b3d723c6f0a0f9d60384fb27d893976c5c5/src/adzerk/boot_cljs/impl.clj#L36-L52

The number of warnings in interesting because Boot can for example play notification sound if warning count in non-zero.

If others think number of warnings is common use case, perhaps that should be directly exposed in the api? Though I'm not sure how that would look like.

Comment by David Nolen [ 27/Jul/15 4:43 AM ]

There's no need to expose the dynamic binding aspect of the underlying implementation. Instead this should be configurable via opts.

Comment by Juho Teperi [ 27/Jul/15 10:53 AM ]

This version adds code to any api function which takes opts argument and uses `:warning-handlers` key to set the dynamic binding.

Not sure if using with-bindings is the best approach, but this version should show where the opts need to be handled.

Comment by David Nolen [ 27/Jul/15 2:03 PM ]

Have you confirmed this approach works under AOT? I'm always very wary of var-centric code like this.

Comment by Juho Teperi [ 28/Jul/15 12:54 PM ]

New version with bindings inline. Also adds state as first argument to any api call which uses compiler-env.

env/with-compiler-env throws error if compiler-env is nil which changes functionality in some cases which previously could work without compiler-env (analyze).

I can think of two fixes for this:

  • Setting compiler-env directly using binding
  • Instead of calling state-version of function from other arities, call the implementation directly thus working exactly like before
Comment by David Nolen [ 28/Jul/15 4:39 PM ]

fixed https://github.com/clojure/clojurescript/commit/9e662c3ea5b9f536f303e9084415e988bf5d0878





[CLJS-1366] Warnings from bootstrap use of defrecord Created: 24/Jul/15  Updated: 24/Jul/15  Resolved: 24/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Joel Martin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: bootstrap
Environment:

cljs-bootstrap


Attachments: Text File 1366.patch    

 Description   

Currently, use of defrecord with a value field generates non-fatal warnings because core/list is not fully qualified:

cljs.user> (defprotocol IFoo (foo [this]))
nil
cljs.user> (defrecord Baz [b] IFoo (foo [this] (prn "some baz:" b)))
WARNING: No such namespace: core, could not locate core.cljs, core.cljc, or Closure namespace ""
WARNING: Use of undeclared Var core/list
cljs.user/Baz


 Comments   
Comment by David Nolen [ 24/Jul/15 7:15 PM ]

fixed https://github.com/clojure/clojurescript/commit/0a15c1b829712939f29913cbbaf8f16fe144d8d9





[CLJS-1365] cljs.js: :context :expr propagates down into ns loading Created: 23/Jul/15  Updated: 27/Jul/15  Resolved: 27/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: bootstrap
Environment:

Master, with downstream Planck



 Description   

Planck sets :context :expr to evaluate a form in the REPL (via this feature http://dev.clojure.org/jira/browse/CLJS-1357)

If it turns out that the expression being evaluated in the REPL is actually an ns form that causes another namespace to be :require d (and loaded via *load-fn*) then only the first form after the ns form in that namespace is loaded. This doesn't occur if I omit the :context :expr opt.



 Comments   
Comment by Mike Fikes [ 23/Jul/15 8:40 PM ]

I'll work on a repro for cljs-bootstrap.

Comment by David Nolen [ 27/Jul/15 7:54 AM ]

fixed https://github.com/clojure/clojurescript/commit/478eb80c3f1bd9aa896bf925b535f9a52bf7b8d4





[CLJS-1364] cljs.js: Update default *load-fn* args to reflect docstring Created: 23/Jul/15  Updated: 23/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

The default *load-fn* :

(fn [name cb]
    (throw (js/Error. "No *load-fn* set")))

But the name arg reflects an older impl, with the new arg actually being a map.

To avoid confusion for anyone reading this code, perhaps

(fn [_ _]
    (throw (js/Error. "No *load-fn* set")))

or maybe name the first argument something meaningful?






[CLJS-1363] cljs.js: eval-str: Allow client to eval in ns other than cljs.user Created: 23/Jul/15  Updated: 27/Jul/15  Resolved: 27/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None
Environment:

Master clojurescript-version
"0.0-3620"



 Description   

If implementing a REPL, to easily support the REPL special in-ns, or even honor the side effects of ns, it would be nice to somehow indicate the namespace to evaluate in when processing eval-str.

The final namespace resulting from eval-str is passed to the cb... this ticket is asking for the opposite: the ability to pass that, or some other namespace in (via opts or some such).



 Comments   
Comment by David Nolen [ 27/Jul/15 8:20 AM ]

fixed https://github.com/clojure/clojurescript/commit/d516268c65251b79a0bd8480c74402b8b89895ba





[CLJS-1362] cljs.js: eval-str: Some core fns not aliased Created: 23/Jul/15  Updated: 25/Jul/15  Resolved: 25/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: bootstrap
Environment:

Master clojurescript-version "0.0-3620", downstream Planck



 Description   

If I eval-str inc I'll get back the core fn, but not so with "map" unless I fully qualify it.

So (inc 1) works but not (map inc [1 2 3]) but, (cljs.core/map inc [1 2 3]) works just fine.

Will see if I can repo with cljs-bootstrap.



 Comments   
Comment by David Nolen [ 24/Jul/15 7:07 PM ]

I see this as well thanks for the report.

Comment by David Nolen [ 25/Jul/15 1:39 PM ]

So I believe this is happening only because the analysis cache for core has not yet been loaded.

Comment by David Nolen [ 25/Jul/15 1:56 PM ]

Closing this one. This only happens when cljs.core has not been analyzed. I do not currently see an easy to solve this problem for users as it either means analyzing cljs.core before doing anything (very slow) or I/O to load a cached analysis. I think this should be just covered by good documentation when we get there.

Comment by David Nolen [ 25/Jul/15 3:26 PM ]

needs fixing

Comment by David Nolen [ 25/Jul/15 3:26 PM ]

fixed https://github.com/clojure/clojurescript/commit/72e01962bfeae9c24b37d6c27a86fd12412e7f07

Comment by Mike Fikes [ 25/Jul/15 8:51 PM ]

Confirmed fixed in master (0.0-3632) with downstream Planck.

I did time ./planck -e '(map inc [1 2 3])' with the cljs.js and previous non-cljs.js versions of Planck and it is slower than I think we expected. Here is what I get:

$ time ./planck -e '(map inc [1 2 3])'
(2 3 4)

real	0m6.883s
user	0m5.168s
sys	0m2.038s

vs.

$ time ./planck -e '(map inc [1 2 3])'
(2 3 4)

real	0m0.956s
user	0m0.964s
sys	0m0.196s

To eliminate any potential noise introduced by the subsequent commits related to source map stuff, I checked out the commit with this fix and got similar numbers:

$ time ./planck -e '(map inc [1 2 3])'
(2 3 4)

real	0m6.884s
user	0m5.135s
sys	0m2.058s

And, to see what this commit alone does to the timings I went to the commit immediately prior and got

$ time ./planck -e '(map inc [1 2 3])'
undefined is not an object (evaluating 'cljs.user.map') 
 
real	0m6.125s
user	0m4.517s
sys	0m1.855s

Summary conclusion: This commit fixes the issue by only adding about 0.75 seconds to startup!

There is obviously something else I'll want to dig into in order to isolate where the 6-second numbers are coming from relative to the 1-second numbers (perhaps it's a Planck thing; I promise to get back with that info, but wanted to at least record what I measured here.)

Comment by Mike Fikes [ 25/Jul/15 9:36 PM ]

Isolated it: With cljs.js, something related to defn is very slow the first time called. Planck has a couple of those in it during startup. If I eliminate those, then very comparable numbers result:

$ time ./planck -e '(map inc [1 2 3])'
(2 3 4)

real	0m1.220s
user	0m1.118s
sys	0m0.252s

Whatever it is with defn perf is clearly not related to this ticket. Just wanted to comment so this ticket is not "left hanging", and whatever it is with defn perf can be pursued separately.





[CLJS-1361] invert compiler state source maps generated by cljsjs.js ns Created: 23/Jul/15  Updated: 27/Jul/15  Resolved: 27/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Task Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

Current the in memory source maps are in a form useful for encoding but not for actually source mapping. We should just store the inverted thing.



 Comments   
Comment by David Nolen [ 27/Jul/15 8:22 AM ]

fixed in master





[CLJS-1360] Refactor JS module processing to work with recent Google Closure compiler changes Created: 22/Jul/15  Updated: 28/Jul/15  Resolved: 28/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: GSoC
Fix Version/s: GSoC

Type: Task Priority: Major
Reporter: Maria Geller Assignee: Maria Geller
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1360.patch    

 Description   

The ES6ModuleLoader has been rewritten. Changes that affect us are:

  • the ES6ModuleLoader constructor has been changed
  • the method toModuleName has been moved from ProcessCommonJSModules to the ES6ModuleLoader
  • multiple module roots are allowed

We need to rewrite some parts of the JS module processing to work with both versions.

"ES6ModuleLoader rewrite" PR: https://github.com/google/closure-compiler/pull/1043
Discussion about this change on the Google Closure compiler mailing list: https://groups.google.com/forum/#!topic/closure-compiler-discuss/gI5Pwoz4Upc



 Comments   
Comment by Maria Geller [ 28/Jul/15 10:48 AM ]

This change supports both versions of the ES6ModuleLoader for now. We now need to pass all modules of the same type at once to the Google Closure compiler so that dependencies will be resolved properly when converting modules. Once a new version of the Google Closure compiler gets released, we can probably remove support for the older version

Comment by Maria Geller [ 28/Jul/15 1:23 PM ]

Found a bug with this. Will attach a second version of this soon.

Comment by Maria Geller [ 28/Jul/15 2:19 PM ]

Attached a new version of the patch. There was an issue when trying to get the module name for a foreign library with a path that wasn't relative. Instead of using the toModuleName method, we are now just getting the module name from the converted file. This way we don't get any mismatches.

Comment by David Nolen [ 28/Jul/15 4:32 PM ]

fixed https://github.com/clojure/clojurescript/commit/70d940558b5f7f9d271a0b546e42c4348d768761





[CLJS-1359] cljs.js error handling Created: 22/Jul/15  Updated: 23/Jul/15  Resolved: 23/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Task Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

Due to asynchronous loads we cannot simply throw an exception, the user cannot catch it. We should introduce disciplined short circuiting and error value propagation.



 Comments   
Comment by David Nolen [ 23/Jul/15 3:30 PM ]

fixed https://github.com/clojure/clojurescript/commit/d1499deaa7461fe30b6b0d35e36c64ef93047722





[CLJS-1358] In cljs.js/eval-str accept an option to turn on :def-emits-var Created: 21/Jul/15  Updated: 21/Jul/15  Resolved: 21/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Mike Fikes Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

In cljs.js/eval-str, clients implementing a REPL may want to have :def-emits-var true assoc}}ed onto {{aenv so that https://github.com/clojure/clojurescript/wiki/REPL-options#def-emits-var works



 Comments   
Comment by David Nolen [ 21/Jul/15 5:28 PM ]

fixed https://github.com/clojure/clojurescript/commit/5284c2d7b7cfe7b83f225c1e7e16db24a8788aa0





[CLJS-1357] In cljs.js/eval-str accept a :context option in support of REPLs Created: 21/Jul/15  Updated: 21/Jul/15  Resolved: 21/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Mike Fikes Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

If you modify cljs.js/eval-str* to assoc :context :expr onto aenv (in addition to the existing :ns key) then things like 1 and :a evaluate properly (when implementing a REPL).

This ticket asks for an opts option for :context so that client code can indicate an :expr is being evaluated



 Comments   
Comment by David Nolen [ 21/Jul/15 5:28 PM ]

fixed https://github.com/clojure/clojurescript/commit/5284c2d7b7cfe7b83f225c1e7e16db24a8788aa0





[CLJS-1356] cljs.js/*load-fn* should take the original library name Created: 20/Jul/15  Updated: 21/Jul/15  Resolved: 21/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Task Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: bootstrap


 Description   

More information the better.



 Comments   
Comment by David Nolen [ 21/Jul/15 5:26 AM ]

fixed https://github.com/clojure/clojurescript/commit/8e484959fbb5e6f8184b9183e096aaddc271005d





[CLJS-1355] cljs.js/*eval-fn* should take cljs.js/*load-fn*'s return value, a map Created: 20/Jul/15  Updated: 21/Jul/15  Resolved: 21/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 0.0-3308

Type: Task Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: bootstrap


 Description   

Rhino, Nashorn, JavaScriptCore, and Node.js all have good support for evaluating an arbitrary string as source and associating it with a file name. For this reason we should just pass the map with :source, :name, and :lang received from cljs.js/load-fn.



 Comments   
Comment by David Nolen [ 21/Jul/15 5:26 AM ]

fixed https://github.com/clojure/clojurescript/commit/8e484959fbb5e6f8184b9183e096aaddc271005d





[CLJS-1354] bootstrapped ClojureScript should support inline source maps Created: 20/Jul/15  Updated: 21/Jul/15  Resolved: 21/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Task Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: bootstrap


 Comments   
Comment by David Nolen [ 21/Jul/15 5:29 PM ]

fixed https://github.com/clojure/clojurescript/commit/6235833cb398510bd62bfc33da1345dc6316259e





[CLJS-1353] range inconsistent with Clojure if step is 0 Created: 20/Jul/15  Updated: 30/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   
cljs.user=> (range 3 9 0)
()

With CLJ-1018 Clojure behaves this way and docstring for Clojure updated:

user=> (take 10 (range 3 9 0))
(3 3 3 3 3 3 3 3 3 3)





[CLJS-1352] cljs.js: Allow conditional readers Created: 20/Jul/15  Updated: 20/Jul/15  Resolved: 20/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Mike Fikes Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1352-2.patch     Text File CLJS-1352.patch    
Patch: Code

 Description   

For cljs.tools.reader usage in the cljs.js namespace, allow conditional reading, supporting :cljs.



 Comments   
Comment by Mike Fikes [ 20/Jul/15 8:59 AM ]

Updated patch to cleanly apply.

Comment by David Nolen [ 20/Jul/15 2:32 PM ]

fixed https://github.com/clojure/clojurescript/commit/ad2c509672d3d67e7b0001ae9e4157971a717f1c





[CLJS-1351] cljs.js: typo, need to evaluate string buffer Created: 20/Jul/15  Updated: 20/Jul/15  Resolved: 20/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1351.patch    
Patch: Code

 Description   

The last line of eval-str* has a typo, where cb is used in a place where sb should be.



 Comments   
Comment by Mike Fikes [ 20/Jul/15 8:45 AM ]

Was fixed by David with https://github.com/clojure/clojurescript/commit/2ab9309f3a1e66b2a3bb8f0cb16df7f71f02187f





[CLJS-1350] Compiler support for browser REPL Created: 19/Jul/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None


 Description   

Currently the browser REPL experience could be considerably enhanced just by eliminating manual configuration in source. Instead REPL configuration could happen via a compiler option. This would make REPL support considerably more robust in the face of user errors while developing.






[CLJS-1349] cljs.build.api tests are broken due to cljs.util/to-target-file behavior Created: 19/Jul/15  Updated: 27/Jul/15  Resolved: 27/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Sebastian Bensusan Assignee: David Nolen
Resolution: Completed Votes: 1
Labels: None


 Description   

The cljs.build-api-tests/test-target-file-for-cljs-ns is failing. The first failing commit was 125f1ce6fbb7977d7f7ac30bfbd240585817075b, were cljs.util/to-target-file was changed to require the source-file, so it could get the extension (cljs vs cljc|clj), and munge the file dependently on the extension. To reproduce this, run lein test on any commit after that one.

The point of cljs.build.api/target-file-for-cljs-ns is to find a file path from a ns but there is no longer a one-to-one mapping between ns and file path. target-file-for-cljs-ns is only called by cljs.build.api/mark-cljs-ns-for-recompile but it is in the api namespace.

I see the following alternatives:

1. At some point in the chain cljs.build.api/target-file-for-cljs-ns -> cljs.util/to-target-file -> cljs.util/ext make js the default extension (i.e when the source-file is not provided).
2. Restrict cljs.build.api/target-file-for-cljs-ns to cljs files only.
3. Acknowledge that target-file-for-cljs-ns is not actually part of the api namespace but a subordinate to mark-cljs-ns-for-recompile. Then, we could try to find the path for all three extensions, returning only the path that contains a file.

I lack the birds eye view to judge what's desirable and I can experiment with any of those.

Hope this helps.



 Comments   
Comment by David Nolen [ 27/Jul/15 9:41 AM ]

fixed https://github.com/clojure/clojurescript/commit/c499b2af68f02bd68b054b3aa01ef0573a54005d





[CLJS-1348] meta is printing for def at REPL Created: 18/Jul/15  Updated: 19/Jul/15  Resolved: 19/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

master, nodejs REPL


Attachments: Text File CLJS-1348-2.patch     Text File CLJS-1348.patch    

 Description   
cljs.user=> (def x 3)
^{:ns cljs.user, :name x, :file "<cljs repl>", :end-column 7, :source "x", :column nil, :line nil, :end-line 1, :arglists (), :doc nil, :test nil} #'cljs.user/x


 Comments   
Comment by Mike Fikes [ 18/Jul/15 6:29 PM ]

Looks like overly aggressive optimization of pr-writer-impl. Patch restores functionality. (Hopefully preserving some of the optimality.)

Comment by Mike Fikes [ 18/Jul/15 6:33 PM ]

Hey David, while the attached patch fixes the issue, I haven't a clue regarding the performance. Perhaps (get opts :meta) needs to be called once and bound in a let and the tested for nil or false, or perhaps it is just as well to let the first part of the and be (get opts :meta) and letting the truthyness check occur.

Comment by David Nolen [ 19/Jul/15 11:05 AM ]

Use boolean coercion instead then you can have one test instead of checking for both false and nil - (not (boolean (get opts :meta))).

Comment by Mike Fikes [ 19/Jul/15 11:32 AM ]

Hey David, I can make the change. For my edification, I did a little digging. (We need to get rid of the not for the correct logic.)

The question then boils down to the speed of the original (prior to the first optimization) (and x ..) and (and (boolean x) ...).

Below are expansions of that stuff. Statically looking at it as a human, it looks like they are so close that clever VMs might reduce them to the same machine code if JIT is at play.

If you already know the answer, or don't think it is worth digging further then I can make the revision go with one or the other. Otherwise, if you'd like me to profile things, maybe this is a learning opportunity on how to do so. (Could lead to a good new Wiki page describing the details.)

cljs.user=> (defn foo [x] (and x true))
cljs.user.foo = (function cljs$user$foo(x){
  var and__4700__auto__ = x;
  if(cljs.core.truth_(and__4700__auto__)){
    return true;
  } else {
    return and__4700__auto__;
  }
})
#'cljs.user/foo

cljs.user=> cljs.core.truth_
cljs.core.truth_
#<function cljs$core$truth_(x){
  return (x != null && x !== false);
}>
cljs.user=> (defn foo [x] (and (boolean x) true))
cljs.user.foo = (function cljs$user$foo(x){
  return (cljs.core.boolean$.call(null,x)) && (true);
})
#'cljs.user/foo

cljs.user=> cljs.core.boolean
cljs.core.boolean$
#<function cljs$core$boolean(x){
  if((x == null)){
    return false;
  } else {
  if(x === false){
    return false;
  } else {
    return true;
  }
}
}>
Comment by Mike Fikes [ 19/Jul/15 1:18 PM ]

The attached patch combines both checks that were in CLJS-1348, and, if I'm understanding David correctly (IRC), is correct, where dropping the coersion leads to unsoundness if perchance something like 0 were returned which is truthy, but would not be at the JS level.

Comment by David Nolen [ 19/Jul/15 1:47 PM ]

fixed https://github.com/clojure/clojurescript/commit/0c2ad96a62899afe9629040673537fbdb344ab61





[CLJS-1347] records don't satisfy IReduce or IKVReduce Created: 18/Jul/15  Updated: 19/Jul/15  Resolved: 19/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Duplicate Votes: 0
Labels: None
Environment:

Master clojurescript-version => "0.0-3540" Node.js REPL



 Description   

Records should support IReduce and IKVReduce.

cljs.user=> (defrecord R [x y])     
cljs.user/R
cljs.user=> (satisfies? IKVReduce (R. 1 2))
false
cljs.user=> (satisfies? IReduce (R. 1 2))
false


 Comments   
Comment by Sebastian Bensusan [ 19/Jul/15 10:15 AM ]

This is a duplicate of CLJS-1297





[CLJS-1346] Support require outside of ns Created: 18/Jul/15  Updated: 18/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Jonathan Boston Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Makes http://dev.clojure.org/jira/browse/CLJS-1277 useful.






[CLJS-1345] Analyzer tests are broken due to new error messages Created: 17/Jul/15  Updated: 18/Jul/15  Resolved: 18/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: 0.0-3308

Type: Defect Priority: Minor
Reporter: Sebastian Bensusan Assignee: Sebastian Bensusan
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File cljs_1345.patch    

 Comments   
Comment by Sebastian Bensusan [ 17/Jul/15 6:01 PM ]

The issue was resolved by correcting the messages in the tests to reflect the new ones.

Comment by David Nolen [ 18/Jul/15 11:10 AM ]

fixed https://github.com/clojure/clojurescript/commit/bf643dbbb06eb7ae5ec27cb9feaa9aa41960862f





[CLJS-1344] port Clojure tuples commit Created: 17/Jul/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Task Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-CLJS-1344-port-Clojure-tuples-commit-of-16-July-2015.patch     Text File 0002-CLJS-1344-port-Clojure-tuples-commit-of-16-July-2015.patch     Text File 0003-CLJS-1344-port-Clojure-tuples-commit-of-16-July-2015.patch    

 Description   

See https://github.com/clojure/clojure/commit/36d665793b43f62cfd22354aced4c6892088abd6



 Comments   
Comment by Michał Marczyk [ 18/Jul/15 11:38 AM ]

Patch based on current master.

Comment by Michał Marczyk [ 18/Jul/15 11:50 AM ]

In absence of abstract bases macros seemed like the most straightforward way to keep things DRY. Anything involving transients or metadata still uses PV, as in Clojure.

Comment by Michał Marczyk [ 18/Jul/15 12:04 PM ]

The 0002 patch is the same, except it does NOT change PV's -equiv to check satisfies? IVector rather than instance? PersistentVector. (The 0001 patch does make this change.)

Haven't made up my mind as to whether it's better to switch or not, so I thought I'd prepare both versions.

Comment by Michał Marczyk [ 18/Jul/15 12:25 PM ]

Some benchmark results, for now obtained using SpiderMonkey (I've just realized that I don't have a working V8 setup on this box – which is not the one I normally use for CLJS dev – I'll have to look into fixing that).

On the subject of -equiv, script benchmark says 0002 patch is very slightly faster than 0001 patch, which itself is noticeably faster than master: 633 ms vs 660 ms vs 781 ms in the vector equality benchmark.

The reason both patches are faster than master is undoubtedly their choice to call -count rather than count on the "other thing"; that is 100% justified in the 0002 patch (with instance?) and slightly less justified in the 0001 patch (who could implement IVector without ICounted though?).

Full script/benchmark results:

master
======

Benchmarking with SpiderMonkey
[x 1], (identity x), 1000000 runs, 0 msecs
;; symbol construction
[], (symbol (quote foo)), 1000000 runs, 585 msecs

;; array-reduce & ci-reduce
[coll (seq arr)], (ci-reduce coll + 0), 1 runs, 137 msecs
[coll (seq arr)], (ci-reduce coll sum 0), 1 runs, 735 msecs
[coll arr], (array-reduce coll + 0), 1 runs, 3 msecs
[coll arr], (array-reduce coll sum 0), 1 runs, 297 msecs
;;; instance?
[coll []], (instance? PersistentVector coll), 1000000 runs, 23 msecs
;;; satisfies?
[coll (list 1 2 3)], (satisfies? ISeq coll), 1000000 runs, 21 msecs
[coll [1 2 3]], (satisfies? ISeq coll), 1000000 runs, 32 msecs

;;; array & string ops
[coll (array 1 2 3)], (seq coll), 1000000 runs, 524 msecs
[coll "foobar"], (seq coll), 1000000 runs, 1879 msecs
[coll (array 1 2 3)], (first coll), 1000000 runs, 789 msecs
[coll "foobar"], (first coll), 1000000 runs, 1762 msecs
[coll (array 1 2 3)], (nth coll 2), 1000000 runs, 150 msecs
[coll "foobar"], (nth coll 2), 1000000 runs, 1297 msecs

;;; cloning & specify
[coll [1 2 3]], (clone coll), 1000000 runs, 587 msecs
[coll [1 2 3]], (specify coll IFoo (foo [_] :bar)), 1000000 runs, 1486 msecs
[coll (specify [1 2 3] IFoo (foo [_] :bar))], (foo coll), 1000000 runs, 105 msecs

;;; list ops
[coll (list 1 2 3)], (first coll), 1000000 runs, 214 msecs
[coll (list 1 2 3)], (-first coll), 1000000 runs, 114 msecs
[coll (list 1 2 3)], (rest coll), 1000000 runs, 111 msecs
[coll (list 1 2 3)], (-rest coll), 1000000 runs, 88 msecs
[], (list), 1000000 runs, 13 msecs
[], (list 1 2 3), 1000000 runs, 1691 msecs

;;; vector ops
[], [], 1000000 runs, 9 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count [a b c]), 1000000 runs, 715 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vec #object[cljs.tagged_literals.JSValue 0xd0fabc8 "cljs.tagged_literals.JSValue@d0fabc8"])), 1000000 runs, 972 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vector a b c)), 1000000 runs, 638 msecs
[coll [1 2 3]], (transient coll), 100000 runs, 161 msecs
[coll [1 2 3]], (nth coll 0), 1000000 runs, 323 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 361 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 238 msecs
[coll [1 2 3]], (coll 0), 1000000 runs, 211 msecs
[coll [1 2 3]], (conj coll 4), 1000000 runs, 1284 msecs
[coll [1 2 3]], (-conj coll 4), 1000000 runs, 1071 msecs
[coll []], (-conj coll 1), 1000000 runs, 1067 msecs
[coll [1]], (-conj coll 2), 1000000 runs, 1133 msecs
[coll [1 2]], (-conj coll 3), 1000000 runs, 835 msecs
[coll [1 2 3]], (seq coll), 1000000 runs, 472 msecs
[coll [1 2 3]], (-seq coll), 1000000 runs, 557 msecs
[coll (seq [1 2 3])], (first coll), 1000000 runs, 91 msecs
[coll (seq [1 2 3])], (-first coll), 1000000 runs, 104 msecs
[coll (seq [1 2 3])], (rest coll), 1000000 runs, 690 msecs
[coll (seq [1 2 3])], (-rest coll), 1000000 runs, 435 msecs
[coll (seq [1 2 3])], (next coll), 1000000 runs, 425 msecs

;;; large vector ops
[], (reduce conj [] (range 40000)), 10 runs, 251 msecs
[coll (reduce conj [] (range (+ 32768 32)))], (conj coll :foo), 100000 runs, 160 msecs
[coll (reduce conj [] (range 40000))], (assoc coll 123 :foo), 100000 runs, 213 msecs
[coll (reduce conj [] (range (+ 32768 33)))], (pop coll), 100000 runs, 184 msecs

;;; chunked seqs
[], (-first v), 1000000 runs, 207 msecs
[], (-next v), 1000000 runs, 768 msecs
[], (-rest v), 1000000 runs, 326 msecs

;;; transients
transient vector, conj! 1000000 items
"Elapsed time: 679 msecs"


;;; vector equality
[a (into [] (range 1000000)) b (into [] (range 1000000))], (= a b), 1 runs, 781 msecs

;;; keyword compare
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed)))))], (.sort arr compare), 100 runs, 672 msecs
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed) (rand-nth seed)))))], (.sort arr compare), 100 runs, 965 msecs

;;; reduce lazy-seqs, vectors, ranges
[coll (take 100000 (iterate inc 0))], (reduce + 0 coll), 1 runs, 403 msecs
[coll (range 1000000)], (reduce + 0 coll), 1 runs, 20 msecs
[coll (into [] (range 1000000))], (reduce + 0 coll), 1 runs, 267 msecs

;; apply
[coll (into [] (range 1000000))], (apply + coll), 1 runs, 675 msecs
[], (list 1 2 3 4 5), 1000000 runs, 639 msecs
[xs (array-seq (array 1 2 3 4 5))], (apply list xs), 1000000 runs, 2422 msecs
[xs (list 1 2 3 4 5)], (apply list xs), 1000000 runs, 1725 msecs
[xs [1 2 3 4 5]], (apply list xs), 1000000 runs, 1620 msecs
[f (fn [a b & more])], (apply f (range 32)), 1000000 runs, 3240 msecs
[f (fn [a b c d e f g h i j & more])], (apply f (range 32)), 1000000 runs, 2525 msecs

;; update-in
[coll {:foo 1} ks [:foo]], (update-in coll ks inc), 1000000 runs, 2980 msecs
[coll (array-map :foo 1) ks [:foo]], (update-in coll ks inc), 1000000 runs, 453 msecs

;;; obj-map
[coll (obj-map)], (assoc coll :foo :bar), 1000000 runs, 549 msecs
[coll (obj-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 265 msecs
[coll (obj-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 1695 msecs
[coll (obj-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 276 msecs
[coll (obj-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 252 msecs

;;; array-map
[], {[1] true, [2] true, [3] true}, 1000000 runs, 2831 msecs
[coll (array-map)], (assoc coll :foo :bar), 1000000 runs, 373 msecs
[coll (array-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 276 msecs
[coll (array-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 515 msecs
[coll (array-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 320 msecs
[coll (array-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 355 msecs

;;; array-map w/ symbols
[coll (array-map)], (assoc coll a b), 1000000 runs, 322 msecs
[coll (array-map a b)], (-lookup coll a), 1000000 runs, 297 msecs
[coll (array-map a b)], (assoc coll c d), 1000000 runs, 416 msecs
[coll (array-map a b c d)], (-lookup coll c), 1000000 runs, 360 msecs
[coll (array-map a b c d e f)], (-lookup coll e), 1000000 runs, 331 msecs

;;; array-map w/ inline symbols
[coll (array-map)], (assoc coll (quote foo) (quote bar)), 1000000 runs, 894 msecs
[coll (array-map (quote foo) (quote bar))], (-lookup coll (quote foo)), 1000000 runs, 732 msecs
[coll (array-map (quote foo) (quote bar))], (assoc coll (quote baz) (quote woz)), 1000000 runs, 1027 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz))], (-lookup coll (quote baz)), 1000000 runs, 699 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz) (quote lol) (quote rofl))], (-lookup coll (quote lol)), 1000000 runs, 589 msecs

;;; map / record ops
[coll {:foo 1, :bar 2}], (get coll :foo), 1000000 runs, 330 msecs
[coll {(quote foo) 1, (quote bar) 2}], (get coll (quote foo)), 1000000 runs, 523 msecs
[coll {:foo 1, :bar 2}], (-lookup coll :foo nil), 1000000 runs, 307 msecs
[coll {(quote foo) 1, (quote bar) 2}], (-lookup coll (quote foo) nil), 1000000 runs, 530 msecs
[coll {:foo 1, :bar 2}], (:foo coll), 1000000 runs, 295 msecs
[coll {(quote foo) 1, (quote bar) 2}], ((quote foo) coll), 1000000 runs, 574 msecs
[coll {:foo 1, :bar 2}], (kw coll), 1000000 runs, 291 msecs
[coll {(quote foo) 1, (quote bar) 2}], (sym coll), 1000000 runs, 280 msecs
[coll {:foo 1, :bar 2}], (loop [i 0 m coll] (if (< i 100000) (recur (inc i) (assoc m :foo 2)) m)), 1 runs, 9 msecs
[coll (Foo. 1 2)], (:bar coll), 1000000 runs, 251 msecs
[coll (Foo. 1 2)], (-lookup coll :bar), 1000000 runs, 253 msecs
[coll (Foo. 1 2)], (assoc coll :bar 2), 1000000 runs, 322 msecs
[coll (Foo. 1 2)], (assoc coll :baz 3), 1000000 runs, 336 msecs
[coll (Foo. 1 2)], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :bar 2)) m)), 1 runs, 373 msecs

;;; zipmap
[m {:a 1, :b 2, :c 3}], (zipmap (keys m) (map inc (vals m))), 100000 runs, 626 msecs

;;; persistent hash maps
[key :f0], (hash key), 1000000 runs, 266 msecs
[key "f0"], (m3-hash-unencoded-chars key), 1000000 runs, 244 msecs
[key :unsynchronized-mutable], (hash key), 1000000 runs, 267 msecs
[coll hash-coll-test], (hash-coll coll), 100 runs, 340 msecs
[coll hash-coll-test], (hash-ordered-coll coll), 100 runs, 128 msecs
[coll hash-imap-test], (hash-imap coll), 100 runs, 111 msecs
[coll hash-imap-test], (hash-unordered-coll coll), 100 runs, 361 msecs
[coll pmap], (:f0 coll), 1000000 runs, 385 msecs
[coll pmap], (get coll :f0), 1000000 runs, 370 msecs
[coll pmap], (-lookup coll :f0 nil), 1000000 runs, 324 msecs
[coll pmap], (-lookup hash-imap-test :foo500 nil), 1000000 runs, 364 msecs
[coll pmap], (-lookup hash-imap-int-test 500 nil), 1000000 runs, 3598 msecs
[coll pmap], (assoc coll :g0 32), 1000000 runs, 657 msecs
[coll pmap], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :a 1)) m)), 1 runs, 565 msecs
[coll cljs.core.PersistentHashMap.EMPTY], (assoc coll :f0 1), 1000000 runs, 421 msecs

transient map, conj! 100000 items
"Elapsed time: 539 msecs"


;;; set ops
[], #{}, 1000000 runs, 217 msecs
[], #{1 3 2}, 1000000 runs, 0 msecs
[v [1 2 3]], (set v), 1000000 runs, 587 msecs
[], (hash-set 1 2 3), 1000000 runs, 0 msecs
[coll #{1 3 2}], (conj coll 4), 1000000 runs, 477 msecs
[coll #{1 3 2}], (get coll 2), 1000000 runs, 304 msecs
[coll #{1 3 2}], (contains? coll 2), 1000000 runs, 267 msecs
[coll #{1 3 2}], (coll 2), 1000000 runs, 289 msecs

;;; seq ops
[coll (range 500000)], (reduce + coll), 1 runs, 21 msecs

;;; reader
[s "{:foo [1 2 3]}"], (reader/read-string s), 1000 runs, 85 msecs
[s big-str-data], (reader/read-string s), 1000 runs, 1060 msecs

;;; range
[r (range 1000000)], (last r), 1 runs, 77 msecs

;;; lazy-seq
;;; first run
[r r], (last r), 1 runs, 369 msecs
;;; second run
[r r], (last r), 1 runs, 94 msecs

;;; comprehensions
[xs (range 512)], (last (for [x xs y xs] (+ x y))), 1 runs, 233 msecs
[xs (vec (range 512))], (last (for [x xs y xs] (+ x y))), 4 runs, 473 msecs
[a (Box. 0) xs (range 512)], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 1233 msecs
[a (Box. 0) xs (vec (range 512))], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 688 msecs

;; reducers
[xs (into [] (range 1000000))], (r/reduce + (r/map inc (r/map inc (r/map inc xs)))), 1 runs, 53 msecs
;; transducers
[xs (into [] (range 1000000))], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 52 msecs
;; primitive array reduce 1000000 many ops
[xs (into-array (range 1000000))], (-> xs (.map inc) (.map inc) (.map inc) (.reduce (fn [a b] (+ a b)) 0)), 1 runs, 177 msecs
;; reduce range 1000000 many ops
[xs (range 1000000)], (reduce + 0 (map inc (map inc (map inc xs)))), 1 runs, 1298 msecs
;; transduce range 1000000 many ops 
[xs (range 1000000)], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 57 msecs


;; multimethods
[], (simple-multi :foo), 1000000 runs, 569 msecs


;; higher-order variadic function calls
[f array], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 67 msecs
[f vector], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 82 msecs
[], (= 1 1 1 1 1 1 1 1 1 0), 100000 runs, 134 msecs

0001 patch
==========

Benchmarking with SpiderMonkey
[x 1], (identity x), 1000000 runs, 0 msecs
;; symbol construction
[], (symbol (quote foo)), 1000000 runs, 585 msecs

;; array-reduce & ci-reduce
[coll (seq arr)], (ci-reduce coll + 0), 1 runs, 137 msecs
[coll (seq arr)], (ci-reduce coll sum 0), 1 runs, 735 msecs
[coll arr], (array-reduce coll + 0), 1 runs, 3 msecs
[coll arr], (array-reduce coll sum 0), 1 runs, 297 msecs
;;; instance?
[coll []], (instance? PersistentVector coll), 1000000 runs, 23 msecs
;;; satisfies?
[coll (list 1 2 3)], (satisfies? ISeq coll), 1000000 runs, 21 msecs
[coll [1 2 3]], (satisfies? ISeq coll), 1000000 runs, 32 msecs

;;; array & string ops
[coll (array 1 2 3)], (seq coll), 1000000 runs, 524 msecs
[coll "foobar"], (seq coll), 1000000 runs, 1879 msecs
[coll (array 1 2 3)], (first coll), 1000000 runs, 789 msecs
[coll "foobar"], (first coll), 1000000 runs, 1762 msecs
[coll (array 1 2 3)], (nth coll 2), 1000000 runs, 150 msecs
[coll "foobar"], (nth coll 2), 1000000 runs, 1297 msecs

;;; cloning & specify
[coll [1 2 3]], (clone coll), 1000000 runs, 587 msecs
[coll [1 2 3]], (specify coll IFoo (foo [_] :bar)), 1000000 runs, 1486 msecs
[coll (specify [1 2 3] IFoo (foo [_] :bar))], (foo coll), 1000000 runs, 105 msecs

;;; list ops
[coll (list 1 2 3)], (first coll), 1000000 runs, 214 msecs
[coll (list 1 2 3)], (-first coll), 1000000 runs, 114 msecs
[coll (list 1 2 3)], (rest coll), 1000000 runs, 111 msecs
[coll (list 1 2 3)], (-rest coll), 1000000 runs, 88 msecs
[], (list), 1000000 runs, 13 msecs
[], (list 1 2 3), 1000000 runs, 1691 msecs

;;; vector ops
[], [], 1000000 runs, 9 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count [a b c]), 1000000 runs, 715 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vec #object[cljs.tagged_literals.JSValue 0xd0fabc8 "cljs.tagged_literals.JSValue@d0fabc8"])), 1000000 runs, 972 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vector a b c)), 1000000 runs, 638 msecs
[coll [1 2 3]], (transient coll), 100000 runs, 161 msecs
[coll [1 2 3]], (nth coll 0), 1000000 runs, 323 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 361 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 238 msecs
[coll [1 2 3]], (coll 0), 1000000 runs, 211 msecs
[coll [1 2 3]], (conj coll 4), 1000000 runs, 1284 msecs
[coll [1 2 3]], (-conj coll 4), 1000000 runs, 1071 msecs
[coll []], (-conj coll 1), 1000000 runs, 1067 msecs
[coll [1]], (-conj coll 2), 1000000 runs, 1133 msecs
[coll [1 2]], (-conj coll 3), 1000000 runs, 835 msecs
[coll [1 2 3]], (seq coll), 1000000 runs, 472 msecs
[coll [1 2 3]], (-seq coll), 1000000 runs, 557 msecs
[coll (seq [1 2 3])], (first coll), 1000000 runs, 91 msecs
[coll (seq [1 2 3])], (-first coll), 1000000 runs, 104 msecs
[coll (seq [1 2 3])], (rest coll), 1000000 runs, 690 msecs
[coll (seq [1 2 3])], (-rest coll), 1000000 runs, 435 msecs
[coll (seq [1 2 3])], (next coll), 1000000 runs, 425 msecs

;;; large vector ops
[], (reduce conj [] (range 40000)), 10 runs, 251 msecs
[coll (reduce conj [] (range (+ 32768 32)))], (conj coll :foo), 100000 runs, 160 msecs
[coll (reduce conj [] (range 40000))], (assoc coll 123 :foo), 100000 runs, 213 msecs
[coll (reduce conj [] (range (+ 32768 33)))], (pop coll), 100000 runs, 184 msecs

;;; chunked seqs
[], (-first v), 1000000 runs, 207 msecs
[], (-next v), 1000000 runs, 768 msecs
[], (-rest v), 1000000 runs, 326 msecs

;;; transients
transient vector, conj! 1000000 items
"Elapsed time: 679 msecs"


;;; vector equality
[a (into [] (range 1000000)) b (into [] (range 1000000))], (= a b), 1 runs, 781 msecs

;;; keyword compare
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed)))))], (.sort arr compare), 100 runs, 672 msecs
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed) (rand-nth seed)))))], (.sort arr compare), 100 runs, 965 msecs

;;; reduce lazy-seqs, vectors, ranges
[coll (take 100000 (iterate inc 0))], (reduce + 0 coll), 1 runs, 403 msecs
[coll (range 1000000)], (reduce + 0 coll), 1 runs, 20 msecs
[coll (into [] (range 1000000))], (reduce + 0 coll), 1 runs, 267 msecs

;; apply
[coll (into [] (range 1000000))], (apply + coll), 1 runs, 675 msecs
[], (list 1 2 3 4 5), 1000000 runs, 639 msecs
[xs (array-seq (array 1 2 3 4 5))], (apply list xs), 1000000 runs, 2422 msecs
[xs (list 1 2 3 4 5)], (apply list xs), 1000000 runs, 1725 msecs
[xs [1 2 3 4 5]], (apply list xs), 1000000 runs, 1620 msecs
[f (fn [a b & more])], (apply f (range 32)), 1000000 runs, 3240 msecs
[f (fn [a b c d e f g h i j & more])], (apply f (range 32)), 1000000 runs, 2525 msecs

;; update-in
[coll {:foo 1} ks [:foo]], (update-in coll ks inc), 1000000 runs, 2980 msecs
[coll (array-map :foo 1) ks [:foo]], (update-in coll ks inc), 1000000 runs, 453 msecs

;;; obj-map
[coll (obj-map)], (assoc coll :foo :bar), 1000000 runs, 549 msecs
[coll (obj-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 265 msecs
[coll (obj-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 1695 msecs
[coll (obj-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 276 msecs
[coll (obj-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 252 msecs

;;; array-map
[], {[1] true, [2] true, [3] true}, 1000000 runs, 2831 msecs
[coll (array-map)], (assoc coll :foo :bar), 1000000 runs, 373 msecs
[coll (array-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 276 msecs
[coll (array-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 515 msecs
[coll (array-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 320 msecs
[coll (array-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 355 msecs

;;; array-map w/ symbols
[coll (array-map)], (assoc coll a b), 1000000 runs, 322 msecs
[coll (array-map a b)], (-lookup coll a), 1000000 runs, 297 msecs
[coll (array-map a b)], (assoc coll c d), 1000000 runs, 416 msecs
[coll (array-map a b c d)], (-lookup coll c), 1000000 runs, 360 msecs
[coll (array-map a b c d e f)], (-lookup coll e), 1000000 runs, 331 msecs

;;; array-map w/ inline symbols
[coll (array-map)], (assoc coll (quote foo) (quote bar)), 1000000 runs, 894 msecs
[coll (array-map (quote foo) (quote bar))], (-lookup coll (quote foo)), 1000000 runs, 732 msecs
[coll (array-map (quote foo) (quote bar))], (assoc coll (quote baz) (quote woz)), 1000000 runs, 1027 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz))], (-lookup coll (quote baz)), 1000000 runs, 699 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz) (quote lol) (quote rofl))], (-lookup coll (quote lol)), 1000000 runs, 589 msecs

;;; map / record ops
[coll {:foo 1, :bar 2}], (get coll :foo), 1000000 runs, 330 msecs
[coll {(quote foo) 1, (quote bar) 2}], (get coll (quote foo)), 1000000 runs, 523 msecs
[coll {:foo 1, :bar 2}], (-lookup coll :foo nil), 1000000 runs, 307 msecs
[coll {(quote foo) 1, (quote bar) 2}], (-lookup coll (quote foo) nil), 1000000 runs, 530 msecs
[coll {:foo 1, :bar 2}], (:foo coll), 1000000 runs, 295 msecs
[coll {(quote foo) 1, (quote bar) 2}], ((quote foo) coll), 1000000 runs, 574 msecs
[coll {:foo 1, :bar 2}], (kw coll), 1000000 runs, 291 msecs
[coll {(quote foo) 1, (quote bar) 2}], (sym coll), 1000000 runs, 280 msecs
[coll {:foo 1, :bar 2}], (loop [i 0 m coll] (if (< i 100000) (recur (inc i) (assoc m :foo 2)) m)), 1 runs, 9 msecs
[coll (Foo. 1 2)], (:bar coll), 1000000 runs, 251 msecs
[coll (Foo. 1 2)], (-lookup coll :bar), 1000000 runs, 253 msecs
[coll (Foo. 1 2)], (assoc coll :bar 2), 1000000 runs, 322 msecs
[coll (Foo. 1 2)], (assoc coll :baz 3), 1000000 runs, 336 msecs
[coll (Foo. 1 2)], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :bar 2)) m)), 1 runs, 373 msecs

;;; zipmap
[m {:a 1, :b 2, :c 3}], (zipmap (keys m) (map inc (vals m))), 100000 runs, 626 msecs

;;; persistent hash maps
[key :f0], (hash key), 1000000 runs, 266 msecs
[key "f0"], (m3-hash-unencoded-chars key), 1000000 runs, 244 msecs
[key :unsynchronized-mutable], (hash key), 1000000 runs, 267 msecs
[coll hash-coll-test], (hash-coll coll), 100 runs, 340 msecs
[coll hash-coll-test], (hash-ordered-coll coll), 100 runs, 128 msecs
[coll hash-imap-test], (hash-imap coll), 100 runs, 111 msecs
[coll hash-imap-test], (hash-unordered-coll coll), 100 runs, 361 msecs
[coll pmap], (:f0 coll), 1000000 runs, 385 msecs
[coll pmap], (get coll :f0), 1000000 runs, 370 msecs
[coll pmap], (-lookup coll :f0 nil), 1000000 runs, 324 msecs
[coll pmap], (-lookup hash-imap-test :foo500 nil), 1000000 runs, 364 msecs
[coll pmap], (-lookup hash-imap-int-test 500 nil), 1000000 runs, 3598 msecs
[coll pmap], (assoc coll :g0 32), 1000000 runs, 657 msecs
[coll pmap], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :a 1)) m)), 1 runs, 565 msecs
[coll cljs.core.PersistentHashMap.EMPTY], (assoc coll :f0 1), 1000000 runs, 421 msecs

transient map, conj! 100000 items
"Elapsed time: 539 msecs"


;;; set ops
[], #{}, 1000000 runs, 217 msecs
[], #{1 3 2}, 1000000 runs, 0 msecs
[v [1 2 3]], (set v), 1000000 runs, 587 msecs
[], (hash-set 1 2 3), 1000000 runs, 0 msecs
[coll #{1 3 2}], (conj coll 4), 1000000 runs, 477 msecs
[coll #{1 3 2}], (get coll 2), 1000000 runs, 304 msecs
[coll #{1 3 2}], (contains? coll 2), 1000000 runs, 267 msecs
[coll #{1 3 2}], (coll 2), 1000000 runs, 289 msecs

;;; seq ops
[coll (range 500000)], (reduce + coll), 1 runs, 21 msecs

;;; reader
[s "{:foo [1 2 3]}"], (reader/read-string s), 1000 runs, 85 msecs
[s big-str-data], (reader/read-string s), 1000 runs, 1060 msecs

;;; range
[r (range 1000000)], (last r), 1 runs, 77 msecs

;;; lazy-seq
;;; first run
[r r], (last r), 1 runs, 369 msecs
;;; second run
[r r], (last r), 1 runs, 94 msecs

;;; comprehensions
[xs (range 512)], (last (for [x xs y xs] (+ x y))), 1 runs, 233 msecs
[xs (vec (range 512))], (last (for [x xs y xs] (+ x y))), 4 runs, 473 msecs
[a (Box. 0) xs (range 512)], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 1233 msecs
[a (Box. 0) xs (vec (range 512))], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 688 msecs

;; reducers
[xs (into [] (range 1000000))], (r/reduce + (r/map inc (r/map inc (r/map inc xs)))), 1 runs, 53 msecs
;; transducers
[xs (into [] (range 1000000))], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 52 msecs
;; primitive array reduce 1000000 many ops
[xs (into-array (range 1000000))], (-> xs (.map inc) (.map inc) (.map inc) (.reduce (fn [a b] (+ a b)) 0)), 1 runs, 177 msecs
;; reduce range 1000000 many ops
[xs (range 1000000)], (reduce + 0 (map inc (map inc (map inc xs)))), 1 runs, 1298 msecs
;; transduce range 1000000 many ops 
[xs (range 1000000)], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 57 msecs


;; multimethods
[], (simple-multi :foo), 1000000 runs, 569 msecs


;; higher-order variadic function calls
[f array], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 67 msecs
[f vector], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 82 msecs
[], (= 1 1 1 1 1 1 1 1 1 0), 100000 runs, 134 msecs

0002 patch
==========

Benchmarking with SpiderMonkey
[x 1], (identity x), 1000000 runs, 0 msecs
;; symbol construction
[], (symbol (quote foo)), 1000000 runs, 645 msecs

;; array-reduce & ci-reduce
[coll (seq arr)], (ci-reduce coll + 0), 1 runs, 95 msecs
[coll (seq arr)], (ci-reduce coll sum 0), 1 runs, 557 msecs
[coll arr], (array-reduce coll + 0), 1 runs, 2 msecs
[coll arr], (array-reduce coll sum 0), 1 runs, 460 msecs
;;; instance?
[coll []], (instance? PersistentVector coll), 1000000 runs, 18 msecs
;;; satisfies?
[coll (list 1 2 3)], (satisfies? ISeq coll), 1000000 runs, 32 msecs
[coll [1 2 3]], (satisfies? ISeq coll), 1000000 runs, 36 msecs

;;; array & string ops
[coll (array 1 2 3)], (seq coll), 1000000 runs, 613 msecs
[coll "foobar"], (seq coll), 1000000 runs, 1658 msecs
[coll (array 1 2 3)], (first coll), 1000000 runs, 834 msecs
[coll "foobar"], (first coll), 1000000 runs, 1934 msecs
[coll (array 1 2 3)], (nth coll 2), 1000000 runs, 219 msecs
[coll "foobar"], (nth coll 2), 1000000 runs, 1371 msecs

;;; cloning & specify
[coll [1 2 3]], (clone coll), 1000000 runs, 444 msecs
[coll [1 2 3]], (specify coll IFoo (foo [_] :bar)), 1000000 runs, 351 msecs
[coll (specify [1 2 3] IFoo (foo [_] :bar))], (foo coll), 1000000 runs, 125 msecs

;;; list ops
[coll (list 1 2 3)], (first coll), 1000000 runs, 138 msecs
[coll (list 1 2 3)], (-first coll), 1000000 runs, 97 msecs
[coll (list 1 2 3)], (rest coll), 1000000 runs, 109 msecs
[coll (list 1 2 3)], (-rest coll), 1000000 runs, 80 msecs
[], (list), 1000000 runs, 10 msecs
[], (list 1 2 3), 1000000 runs, 1387 msecs

;;; vector ops
[], [], 1000000 runs, 10 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count [a b c]), 1000000 runs, 316 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vec #object[cljs.tagged_literals.JSValue 0x57b33c29 "cljs.tagged_literals.JSValue@57b33c29"])), 1000000 runs, 732 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vector a b c)), 1000000 runs, 281 msecs
[coll [1 2 3]], (transient coll), 100000 runs, 484 msecs
[coll [1 2 3]], (nth coll 0), 1000000 runs, 112 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 162 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 194 msecs
[coll [1 2 3]], (coll 0), 1000000 runs, 125 msecs
[coll [1 2 3]], (conj coll 4), 1000000 runs, 756 msecs
[coll [1 2 3]], (-conj coll 4), 1000000 runs, 606 msecs
[coll []], (-conj coll 1), 1000000 runs, 515 msecs
[coll [1]], (-conj coll 2), 1000000 runs, 648 msecs
[coll [1 2]], (-conj coll 3), 1000000 runs, 422 msecs
[coll [1 2 3]], (seq coll), 1000000 runs, 566 msecs
[coll [1 2 3]], (-seq coll), 1000000 runs, 89 msecs
[coll (seq [1 2 3])], (first coll), 1000000 runs, 154 msecs
[coll (seq [1 2 3])], (-first coll), 1000000 runs, 89 msecs
[coll (seq [1 2 3])], (rest coll), 1000000 runs, 631 msecs
[coll (seq [1 2 3])], (-rest coll), 1000000 runs, 450 msecs
[coll (seq [1 2 3])], (next coll), 1000000 runs, 547 msecs

;;; large vector ops
[], (reduce conj [] (range 40000)), 10 runs, 589 msecs
[coll (reduce conj [] (range (+ 32768 32)))], (conj coll :foo), 100000 runs, 204 msecs
[coll (reduce conj [] (range 40000))], (assoc coll 123 :foo), 100000 runs, 177 msecs
[coll (reduce conj [] (range (+ 32768 33)))], (pop coll), 100000 runs, 143 msecs

;;; chunked seqs
[], (-first v), 1000000 runs, 141 msecs
[], (-next v), 1000000 runs, 529 msecs
[], (-rest v), 1000000 runs, 236 msecs

;;; transients
transient vector, conj! 1000000 items
"Elapsed time: 924 msecs"


;;; vector equality
[a (into [] (range 1000000)) b (into [] (range 1000000))], (= a b), 1 runs, 633 msecs

;;; keyword compare
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed)))))], (.sort arr compare), 100 runs, 610 msecs
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed) (rand-nth seed)))))], (.sort arr compare), 100 runs, 1138 msecs

;;; reduce lazy-seqs, vectors, ranges
[coll (take 100000 (iterate inc 0))], (reduce + 0 coll), 1 runs, 545 msecs
[coll (range 1000000)], (reduce + 0 coll), 1 runs, 121 msecs
[coll (into [] (range 1000000))], (reduce + 0 coll), 1 runs, 281 msecs

;; apply
[coll (into [] (range 1000000))], (apply + coll), 1 runs, 597 msecs
[], (list 1 2 3 4 5), 1000000 runs, 560 msecs
[xs (array-seq (array 1 2 3 4 5))], (apply list xs), 1000000 runs, 2573 msecs
[xs (list 1 2 3 4 5)], (apply list xs), 1000000 runs, 1927 msecs
[xs [1 2 3 4 5]], (apply list xs), 1000000 runs, 6163 msecs
[f (fn [a b & more])], (apply f (range 32)), 1000000 runs, 3149 msecs
[f (fn [a b c d e f g h i j & more])], (apply f (range 32)), 1000000 runs, 1883 msecs

;; update-in
[coll {:foo 1} ks [:foo]], (update-in coll ks inc), 1000000 runs, 659 msecs
[coll (array-map :foo 1) ks [:foo]], (update-in coll ks inc), 1000000 runs, 611 msecs

;;; obj-map
[coll (obj-map)], (assoc coll :foo :bar), 1000000 runs, 556 msecs
[coll (obj-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 368 msecs
[coll (obj-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 1707 msecs
[coll (obj-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 280 msecs
[coll (obj-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 266 msecs

;;; array-map
[], {[1] true, [2] true, [3] true}, 1000000 runs, 2862 msecs
[coll (array-map)], (assoc coll :foo :bar), 1000000 runs, 356 msecs
[coll (array-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 391 msecs
[coll (array-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 439 msecs
[coll (array-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 363 msecs
[coll (array-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 321 msecs

;;; array-map w/ symbols
[coll (array-map)], (assoc coll a b), 1000000 runs, 405 msecs
[coll (array-map a b)], (-lookup coll a), 1000000 runs, 328 msecs
[coll (array-map a b)], (assoc coll c d), 1000000 runs, 444 msecs
[coll (array-map a b c d)], (-lookup coll c), 1000000 runs, 330 msecs
[coll (array-map a b c d e f)], (-lookup coll e), 1000000 runs, 353 msecs

;;; array-map w/ inline symbols
[coll (array-map)], (assoc coll (quote foo) (quote bar)), 1000000 runs, 1427 msecs
[coll (array-map (quote foo) (quote bar))], (-lookup coll (quote foo)), 1000000 runs, 589 msecs
[coll (array-map (quote foo) (quote bar))], (assoc coll (quote baz) (quote woz)), 1000000 runs, 1087 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz))], (-lookup coll (quote baz)), 1000000 runs, 674 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz) (quote lol) (quote rofl))], (-lookup coll (quote lol)), 1000000 runs, 719 msecs

;;; map / record ops
[coll {:foo 1, :bar 2}], (get coll :foo), 1000000 runs, 287 msecs
[coll {(quote foo) 1, (quote bar) 2}], (get coll (quote foo)), 1000000 runs, 841 msecs
[coll {:foo 1, :bar 2}], (-lookup coll :foo nil), 1000000 runs, 327 msecs
[coll {(quote foo) 1, (quote bar) 2}], (-lookup coll (quote foo) nil), 1000000 runs, 625 msecs
[coll {:foo 1, :bar 2}], (:foo coll), 1000000 runs, 294 msecs
[coll {(quote foo) 1, (quote bar) 2}], ((quote foo) coll), 1000000 runs, 630 msecs
[coll {:foo 1, :bar 2}], (kw coll), 1000000 runs, 314 msecs
[coll {(quote foo) 1, (quote bar) 2}], (sym coll), 1000000 runs, 312 msecs
[coll {:foo 1, :bar 2}], (loop [i 0 m coll] (if (< i 100000) (recur (inc i) (assoc m :foo 2)) m)), 1 runs, 10 msecs
[coll (Foo. 1 2)], (:bar coll), 1000000 runs, 269 msecs
[coll (Foo. 1 2)], (-lookup coll :bar), 1000000 runs, 268 msecs
[coll (Foo. 1 2)], (assoc coll :bar 2), 1000000 runs, 309 msecs
[coll (Foo. 1 2)], (assoc coll :baz 3), 1000000 runs, 440 msecs
[coll (Foo. 1 2)], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :bar 2)) m)), 1 runs, 404 msecs

;;; zipmap
[m {:a 1, :b 2, :c 3}], (zipmap (keys m) (map inc (vals m))), 100000 runs, 756 msecs

;;; persistent hash maps
[key :f0], (hash key), 1000000 runs, 290 msecs
[key "f0"], (m3-hash-unencoded-chars key), 1000000 runs, 326 msecs
[key :unsynchronized-mutable], (hash key), 1000000 runs, 279 msecs
[coll hash-coll-test], (hash-coll coll), 100 runs, 338 msecs
[coll hash-coll-test], (hash-ordered-coll coll), 100 runs, 138 msecs
[coll hash-imap-test], (hash-imap coll), 100 runs, 177 msecs
[coll hash-imap-test], (hash-unordered-coll coll), 100 runs, 385 msecs
[coll pmap], (:f0 coll), 1000000 runs, 411 msecs
[coll pmap], (get coll :f0), 1000000 runs, 439 msecs
[coll pmap], (-lookup coll :f0 nil), 1000000 runs, 336 msecs
[coll pmap], (-lookup hash-imap-test :foo500 nil), 1000000 runs, 457 msecs
[coll pmap], (-lookup hash-imap-int-test 500 nil), 1000000 runs, 4330 msecs
[coll pmap], (assoc coll :g0 32), 1000000 runs, 831 msecs
[coll pmap], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :a 1)) m)), 1 runs, 490 msecs
[coll cljs.core.PersistentHashMap.EMPTY], (assoc coll :f0 1), 1000000 runs, 474 msecs

transient map, conj! 100000 items
"Elapsed time: 565 msecs"


;;; set ops
[], #{}, 1000000 runs, 225 msecs
[], #{1 3 2}, 1000000 runs, 0 msecs
[v [1 2 3]], (set v), 1000000 runs, 711 msecs
[], (hash-set 1 2 3), 1000000 runs, 0 msecs
[coll #{1 3 2}], (conj coll 4), 1000000 runs, 608 msecs
[coll #{1 3 2}], (get coll 2), 1000000 runs, 353 msecs
[coll #{1 3 2}], (contains? coll 2), 1000000 runs, 322 msecs
[coll #{1 3 2}], (coll 2), 1000000 runs, 335 msecs

;;; seq ops
[coll (range 500000)], (reduce + coll), 1 runs, 22 msecs

;;; reader
[s "{:foo [1 2 3]}"], (reader/read-string s), 1000 runs, 99 msecs
[s big-str-data], (reader/read-string s), 1000 runs, 1538 msecs

;;; range
[r (range 1000000)], (last r), 1 runs, 37 msecs

;;; lazy-seq
;;; first run
[r r], (last r), 1 runs, 348 msecs
;;; second run
[r r], (last r), 1 runs, 71 msecs

;;; comprehensions
[xs (range 512)], (last (for [x xs y xs] (+ x y))), 1 runs, 433 msecs
[xs (vec (range 512))], (last (for [x xs y xs] (+ x y))), 4 runs, 287 msecs
[a (Box. 0) xs (range 512)], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 1191 msecs
[a (Box. 0) xs (vec (range 512))], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 831 msecs

;; reducers
[xs (into [] (range 1000000))], (r/reduce + (r/map inc (r/map inc (r/map inc xs)))), 1 runs, 52 msecs
;; transducers
[xs (into [] (range 1000000))], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 81 msecs
;; primitive array reduce 1000000 many ops
[xs (into-array (range 1000000))], (-> xs (.map inc) (.map inc) (.map inc) (.reduce (fn [a b] (+ a b)) 0)), 1 runs, 207 msecs
;; reduce range 1000000 many ops
[xs (range 1000000)], (reduce + 0 (map inc (map inc (map inc xs)))), 1 runs, 1375 msecs
;; transduce range 1000000 many ops 
[xs (range 1000000)], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 73 msecs


;; multimethods
[], (simple-multi :foo), 1000000 runs, 429 msecs


;; higher-order variadic function calls
[f array], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 51 msecs
[f vector], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 73 msecs
[], (= 1 1 1 1 1 1 1 1 1 0), 100000 runs, 133 msecs
Comment by David Nolen [ 19/Jul/15 11:06 AM ]

Thanks will review.

Comment by David Nolen [ 20/Jul/15 2:33 PM ]

This ticket should probably be updated with the latest equiv changes in Clojure master no?

Comment by Michał Marczyk [ 20/Jul/15 2:49 PM ]

Right, will do (plus a rebase on top of current master while I'm at it).

Comment by Michał Marczyk [ 20/Jul/15 6:43 PM ]

New 0003 patch superseding the previous ones attached.

See some new benchmark results below. There are some apparent substantial speedups where I would expect them, there's the somewhat expected slowdown for transient with small vectors.

Freak result: most large vector ops stay around their original spots as expected, except for reduce conj [] over a long range, which becomes weirdly slow. This I find hard to explain, particularly since ranges are used in other benchmarks as well, and those behave sensibly.

I tried compiling the benchmark suite with :optimizations :simple to see if the freak result was something obvious maybe. Oddly enough, all/most timings are significantly better under :simple. Am I missing something obvious here…?

1. master:

Benchmarking with SpiderMonkey
[x 1], (identity x), 1000000 runs, 0 msecs
;; symbol construction
[], (symbol (quote foo)), 1000000 runs, 506 msecs

;; array-reduce & ci-reduce
[coll (seq arr)], (ci-reduce coll + 0), 1 runs, 70 msecs
[coll (seq arr)], (ci-reduce coll sum 0), 1 runs, 554 msecs
[coll arr], (array-reduce coll + 0), 1 runs, 3 msecs
[coll arr], (array-reduce coll sum 0), 1 runs, 313 msecs
;;; instance?
[coll []], (instance? PersistentVector coll), 1000000 runs, 15 msecs
;;; satisfies?
[coll (list 1 2 3)], (satisfies? ISeq coll), 1000000 runs, 19 msecs
[coll [1 2 3]], (satisfies? ISeq coll), 1000000 runs, 33 msecs

;;; array & string ops
[coll (array 1 2 3)], (seq coll), 1000000 runs, 401 msecs
[coll "foobar"], (seq coll), 1000000 runs, 1202 msecs
[coll (array 1 2 3)], (first coll), 1000000 runs, 563 msecs
[coll "foobar"], (first coll), 1000000 runs, 1307 msecs
[coll (array 1 2 3)], (nth coll 2), 1000000 runs, 161 msecs
[coll "foobar"], (nth coll 2), 1000000 runs, 949 msecs

;;; cloning & specify
[coll [1 2 3]], (clone coll), 1000000 runs, 379 msecs
[coll [1 2 3]], (specify coll IFoo (foo [_] :bar)), 1000000 runs, 1025 msecs
[coll (specify [1 2 3] IFoo (foo [_] :bar))], (foo coll), 1000000 runs, 59 msecs

;;; list ops
[coll (list 1 2 3)], (first coll), 1000000 runs, 88 msecs
[coll (list 1 2 3)], (-first coll), 1000000 runs, 67 msecs
[coll (list 1 2 3)], (rest coll), 1000000 runs, 80 msecs
[coll (list 1 2 3)], (-rest coll), 1000000 runs, 62 msecs
[], (list), 1000000 runs, 10 msecs
[], (list 1 2 3), 1000000 runs, 1132 msecs

;;; vector ops
[], [], 1000000 runs, 10 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count [a b c]), 1000000 runs, 495 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vec #object[cljs.tagged_literals.JSValue 0x56b66a26 "cljs.tagged_literals.JSValue@56b66a26"])), 1000000 runs, 547 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vector a b c)), 1000000 runs, 435 msecs
[coll [1 2 3]], (transient coll), 100000 runs, 120 msecs
[coll [1 2 3]], (nth coll 0), 1000000 runs, 197 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 95 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 199 msecs
[coll [1 2 3]], (coll 0), 1000000 runs, 209 msecs
[coll [1 2 3]], (conj coll 4), 1000000 runs, 893 msecs
[coll [1 2 3]], (-conj coll 4), 1000000 runs, 842 msecs
[coll []], (-conj coll 1), 1000000 runs, 765 msecs
[coll [1]], (-conj coll 2), 1000000 runs, 854 msecs
[coll [1 2]], (-conj coll 3), 1000000 runs, 631 msecs
[coll [1 2 3]], (seq coll), 1000000 runs, 413 msecs
[coll [1 2 3]], (-seq coll), 1000000 runs, 668 msecs
[coll (seq [1 2 3])], (first coll), 1000000 runs, 163 msecs
[coll (seq [1 2 3])], (-first coll), 1000000 runs, 89 msecs
[coll (seq [1 2 3])], (rest coll), 1000000 runs, 497 msecs
[coll (seq [1 2 3])], (-rest coll), 1000000 runs, 319 msecs
[coll (seq [1 2 3])], (next coll), 1000000 runs, 316 msecs

;;; large vector ops
[], (reduce conj [] (range 40000)), 10 runs, 172 msecs
[coll (reduce conj [] (range (+ 32768 32)))], (conj coll :foo), 100000 runs, 240 msecs
[coll (reduce conj [] (range 40000))], (assoc coll 123 :foo), 100000 runs, 128 msecs
[coll (reduce conj [] (range (+ 32768 33)))], (pop coll), 100000 runs, 80 msecs

;;; chunked seqs
[], (-first v), 1000000 runs, 105 msecs
[], (-next v), 1000000 runs, 460 msecs
[], (-rest v), 1000000 runs, 166 msecs

;;; transients
transient vector, conj! 1000000 items
"Elapsed time: 746 msecs"


;;; vector equality
[a (into [] (range 1000000)) b (into [] (range 1000000))], (= a b), 1 runs, 557 msecs

;;; keyword compare
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed)))))], (.sort arr compare), 100 runs, 437 msecs
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed) (rand-nth seed)))))], (.sort arr compare), 100 runs, 820 msecs

;;; reduce lazy-seqs, vectors, ranges
[coll (take 100000 (iterate inc 0))], (reduce + 0 coll), 1 runs, 308 msecs
[coll (range 1000000)], (reduce + 0 coll), 1 runs, 20 msecs
[coll (into [] (range 1000000))], (reduce + 0 coll), 1 runs, 250 msecs

;; apply
[coll (into [] (range 1000000))], (apply + coll), 1 runs, 471 msecs
[], (list 1 2 3 4 5), 1000000 runs, 410 msecs
[xs (array-seq (array 1 2 3 4 5))], (apply list xs), 1000000 runs, 1898 msecs
[xs (list 1 2 3 4 5)], (apply list xs), 1000000 runs, 1506 msecs
[xs [1 2 3 4 5]], (apply list xs), 1000000 runs, 954 msecs
[f (fn [a b & more])], (apply f (range 32)), 1000000 runs, 2495 msecs
[f (fn [a b c d e f g h i j & more])], (apply f (range 32)), 1000000 runs, 1864 msecs

;; update-in
[coll {:foo 1} ks [:foo]], (update-in coll ks inc), 1000000 runs, 2799 msecs
[coll (array-map :foo 1) ks [:foo]], (update-in coll ks inc), 1000000 runs, 2367 msecs

;;; obj-map
[coll (obj-map)], (assoc coll :foo :bar), 1000000 runs, 465 msecs
[coll (obj-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 268 msecs
[coll (obj-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 1228 msecs
[coll (obj-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 251 msecs
[coll (obj-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 270 msecs

;;; array-map
[], {[1] true, [2] true, [3] true}, 1000000 runs, 3502 msecs
[coll (array-map)], (assoc coll :foo :bar), 1000000 runs, 330 msecs
[coll (array-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 294 msecs
[coll (array-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 528 msecs
[coll (array-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 282 msecs
[coll (array-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 333 msecs

;;; array-map w/ symbols
[coll (array-map)], (assoc coll a b), 1000000 runs, 318 msecs
[coll (array-map a b)], (-lookup coll a), 1000000 runs, 286 msecs
[coll (array-map a b)], (assoc coll c d), 1000000 runs, 409 msecs
[coll (array-map a b c d)], (-lookup coll c), 1000000 runs, 341 msecs
[coll (array-map a b c d e f)], (-lookup coll e), 1000000 runs, 353 msecs

;;; array-map w/ inline symbols
[coll (array-map)], (assoc coll (quote foo) (quote bar)), 1000000 runs, 878 msecs
[coll (array-map (quote foo) (quote bar))], (-lookup coll (quote foo)), 1000000 runs, 589 msecs
[coll (array-map (quote foo) (quote bar))], (assoc coll (quote baz) (quote woz)), 1000000 runs, 972 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz))], (-lookup coll (quote baz)), 1000000 runs, 582 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz) (quote lol) (quote rofl))], (-lookup coll (quote lol)), 1000000 runs, 850 msecs

;;; map / record ops
[coll {:foo 1, :bar 2}], (get coll :foo), 1000000 runs, 269 msecs
[coll {(quote foo) 1, (quote bar) 2}], (get coll (quote foo)), 1000000 runs, 793 msecs
[coll {:foo 1, :bar 2}], (-lookup coll :foo nil), 1000000 runs, 269 msecs
[coll {(quote foo) 1, (quote bar) 2}], (-lookup coll (quote foo) nil), 1000000 runs, 596 msecs
[coll {:foo 1, :bar 2}], (:foo coll), 1000000 runs, 311 msecs
[coll {(quote foo) 1, (quote bar) 2}], ((quote foo) coll), 1000000 runs, 586 msecs
[coll {:foo 1, :bar 2}], (kw coll), 1000000 runs, 321 msecs
[coll {(quote foo) 1, (quote bar) 2}], (sym coll), 1000000 runs, 280 msecs
[coll {:foo 1, :bar 2}], (loop [i 0 m coll] (if (< i 100000) (recur (inc i) (assoc m :foo 2)) m)), 1 runs, 10 msecs
[coll (Foo. 1 2)], (:bar coll), 1000000 runs, 254 msecs
[coll (Foo. 1 2)], (-lookup coll :bar), 1000000 runs, 250 msecs
[coll (Foo. 1 2)], (assoc coll :bar 2), 1000000 runs, 288 msecs
[coll (Foo. 1 2)], (assoc coll :baz 3), 1000000 runs, 322 msecs
[coll (Foo. 1 2)], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :bar 2)) m)), 1 runs, 305 msecs

;;; zipmap
[m {:a 1, :b 2, :c 3}], (zipmap (keys m) (map inc (vals m))), 100000 runs, 537 msecs

;;; persistent hash maps
[key :f0], (hash key), 1000000 runs, 257 msecs
[key "f0"], (m3-hash-unencoded-chars key), 1000000 runs, 250 msecs
[key :unsynchronized-mutable], (hash key), 1000000 runs, 238 msecs
[coll hash-coll-test], (hash-coll coll), 100 runs, 338 msecs
[coll hash-coll-test], (hash-ordered-coll coll), 100 runs, 123 msecs
[coll hash-imap-test], (hash-imap coll), 100 runs, 114 msecs
[coll hash-imap-test], (hash-unordered-coll coll), 100 runs, 342 msecs
[coll pmap], (:f0 coll), 1000000 runs, 368 msecs
[coll pmap], (get coll :f0), 1000000 runs, 356 msecs
[coll pmap], (-lookup coll :f0 nil), 1000000 runs, 274 msecs
[coll pmap], (-lookup hash-imap-test :foo500 nil), 1000000 runs, 290 msecs
[coll pmap], (-lookup hash-imap-int-test 500 nil), 1000000 runs, 3028 msecs
[coll pmap], (assoc coll :g0 32), 1000000 runs, 641 msecs
[coll pmap], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :a 1)) m)), 1 runs, 412 msecs
[coll cljs.core.PersistentHashMap.EMPTY], (assoc coll :f0 1), 1000000 runs, 411 msecs

transient map, conj! 100000 items
"Elapsed time: 505 msecs"


;;; set ops
[], #{}, 1000000 runs, 215 msecs
[], #{1 3 2}, 1000000 runs, 0 msecs
[v [1 2 3]], (set v), 1000000 runs, 460 msecs
[], (hash-set 1 2 3), 1000000 runs, 0 msecs
[coll #{1 3 2}], (conj coll 4), 1000000 runs, 516 msecs
[coll #{1 3 2}], (get coll 2), 1000000 runs, 293 msecs
[coll #{1 3 2}], (contains? coll 2), 1000000 runs, 269 msecs
[coll #{1 3 2}], (coll 2), 1000000 runs, 290 msecs

;;; seq ops
[coll (range 500000)], (reduce + coll), 1 runs, 18 msecs

;;; reader
[s "{:foo [1 2 3]}"], (reader/read-string s), 1000 runs, 77 msecs
[s big-str-data], (reader/read-string s), 1000 runs, 957 msecs

;;; range
[r (range 1000000)], (last r), 1 runs, 42 msecs

;;; lazy-seq
;;; first run
[r r], (last r), 1 runs, 310 msecs
;;; second run
[r r], (last r), 1 runs, 71 msecs

;;; comprehensions
[xs (range 512)], (last (for [x xs y xs] (+ x y))), 1 runs, 234 msecs
[xs (vec (range 512))], (last (for [x xs y xs] (+ x y))), 4 runs, 416 msecs
[a (Box. 0) xs (range 512)], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 981 msecs
[a (Box. 0) xs (vec (range 512))], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 699 msecs

;; reducers
[xs (into [] (range 1000000))], (r/reduce + (r/map inc (r/map inc (r/map inc xs)))), 1 runs, 50 msecs
;; transducers
[xs (into [] (range 1000000))], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 52 msecs
;; primitive array reduce 1000000 many ops
[xs (into-array (range 1000000))], (-> xs (.map inc) (.map inc) (.map inc) (.reduce (fn [a b] (+ a b)) 0)), 1 runs, 184 msecs
;; reduce range 1000000 many ops
[xs (range 1000000)], (reduce + 0 (map inc (map inc (map inc xs)))), 1 runs, 1278 msecs
;; transduce range 1000000 many ops 
[xs (range 1000000)], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 46 msecs


;; multimethods
[], (simple-multi :foo), 1000000 runs, 333 msecs


;; higher-order variadic function calls
[f array], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 216 msecs
[f vector], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 71 msecs
[], (= 1 1 1 1 1 1 1 1 1 0), 100000 runs, 142 msecs

2. 0003 patch:

Benchmarking with SpiderMonkey
[x 1], (identity x), 1000000 runs, 0 msecs
;; symbol construction
[], (symbol (quote foo)), 1000000 runs, 480 msecs

;; array-reduce & ci-reduce
[coll (seq arr)], (ci-reduce coll + 0), 1 runs, 71 msecs
[coll (seq arr)], (ci-reduce coll sum 0), 1 runs, 476 msecs
[coll arr], (array-reduce coll + 0), 1 runs, 3 msecs
[coll arr], (array-reduce coll sum 0), 1 runs, 621 msecs
;;; instance?
[coll []], (instance? PersistentVector coll), 1000000 runs, 28 msecs
;;; satisfies?
[coll (list 1 2 3)], (satisfies? ISeq coll), 1000000 runs, 30 msecs
[coll [1 2 3]], (satisfies? ISeq coll), 1000000 runs, 54 msecs

;;; array & string ops
[coll (array 1 2 3)], (seq coll), 1000000 runs, 542 msecs
[coll "foobar"], (seq coll), 1000000 runs, 1209 msecs
[coll (array 1 2 3)], (first coll), 1000000 runs, 564 msecs
[coll "foobar"], (first coll), 1000000 runs, 1257 msecs
[coll (array 1 2 3)], (nth coll 2), 1000000 runs, 140 msecs
[coll "foobar"], (nth coll 2), 1000000 runs, 913 msecs

;;; cloning & specify
[coll [1 2 3]], (clone coll), 1000000 runs, 424 msecs
[coll [1 2 3]], (specify coll IFoo (foo [_] :bar)), 1000000 runs, 170 msecs
[coll (specify [1 2 3] IFoo (foo [_] :bar))], (foo coll), 1000000 runs, 58 msecs

;;; list ops
[coll (list 1 2 3)], (first coll), 1000000 runs, 89 msecs
[coll (list 1 2 3)], (-first coll), 1000000 runs, 69 msecs
[coll (list 1 2 3)], (rest coll), 1000000 runs, 80 msecs
[coll (list 1 2 3)], (-rest coll), 1000000 runs, 61 msecs
[], (list), 1000000 runs, 10 msecs
[], (list 1 2 3), 1000000 runs, 1142 msecs

;;; vector ops
[], [], 1000000 runs, 10 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count [a b c]), 1000000 runs, 272 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vec #object[cljs.tagged_literals.JSValue 0x3ff26c9 "cljs.tagged_literals.JSValue@3ff26c9"])), 1000000 runs, 585 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vector a b c)), 1000000 runs, 240 msecs
[coll [1 2 3]], (transient coll), 100000 runs, 273 msecs
[coll [1 2 3]], (nth coll 0), 1000000 runs, 101 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 102 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 102 msecs
[coll [1 2 3]], (coll 0), 1000000 runs, 38 msecs
[coll [1 2 3]], (conj coll 4), 1000000 runs, 429 msecs
[coll [1 2 3]], (-conj coll 4), 1000000 runs, 392 msecs
[coll []], (-conj coll 1), 1000000 runs, 368 msecs
[coll [1]], (-conj coll 2), 1000000 runs, 395 msecs
[coll [1 2]], (-conj coll 3), 1000000 runs, 364 msecs
[coll [1 2 3]], (seq coll), 1000000 runs, 383 msecs
[coll [1 2 3]], (-seq coll), 1000000 runs, 75 msecs
[coll (seq [1 2 3])], (first coll), 1000000 runs, 142 msecs
[coll (seq [1 2 3])], (-first coll), 1000000 runs, 79 msecs
[coll (seq [1 2 3])], (rest coll), 1000000 runs, 395 msecs
[coll (seq [1 2 3])], (-rest coll), 1000000 runs, 408 msecs
[coll (seq [1 2 3])], (next coll), 1000000 runs, 383 msecs

;;; large vector ops
[], (reduce conj [] (range 40000)), 10 runs, 406 msecs
[coll (reduce conj [] (range (+ 32768 32)))], (conj coll :foo), 100000 runs, 269 msecs
[coll (reduce conj [] (range 40000))], (assoc coll 123 :foo), 100000 runs, 131 msecs
[coll (reduce conj [] (range (+ 32768 33)))], (pop coll), 100000 runs, 80 msecs

;;; chunked seqs
[], (-first v), 1000000 runs, 104 msecs
[], (-next v), 1000000 runs, 461 msecs
[], (-rest v), 1000000 runs, 171 msecs

;;; transients
transient vector, conj! 1000000 items
"Elapsed time: 592 msecs"


;;; vector equality
[a (into [] (range 1000000)) b (into [] (range 1000000))], (= a b), 1 runs, 562 msecs

;;; keyword compare
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed)))))], (.sort arr compare), 100 runs, 467 msecs
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed) (rand-nth seed)))))], (.sort arr compare), 100 runs, 830 msecs

;;; reduce lazy-seqs, vectors, ranges
[coll (take 100000 (iterate inc 0))], (reduce + 0 coll), 1 runs, 426 msecs
[coll (range 1000000)], (reduce + 0 coll), 1 runs, 15 msecs
[coll (into [] (range 1000000))], (reduce + 0 coll), 1 runs, 265 msecs

;; apply
[coll (into [] (range 1000000))], (apply + coll), 1 runs, 580 msecs
[], (list 1 2 3 4 5), 1000000 runs, 386 msecs
[xs (array-seq (array 1 2 3 4 5))], (apply list xs), 1000000 runs, 1885 msecs
[xs (list 1 2 3 4 5)], (apply list xs), 1000000 runs, 1362 msecs
[xs [1 2 3 4 5]], (apply list xs), 1000000 runs, 4564 msecs
[f (fn [a b & more])], (apply f (range 32)), 1000000 runs, 2536 msecs
[f (fn [a b c d e f g h i j & more])], (apply f (range 32)), 1000000 runs, 1940 msecs

;; update-in
[coll {:foo 1} ks [:foo]], (update-in coll ks inc), 1000000 runs, 1948 msecs
[coll (array-map :foo 1) ks [:foo]], (update-in coll ks inc), 1000000 runs, 452 msecs

;;; obj-map
[coll (obj-map)], (assoc coll :foo :bar), 1000000 runs, 484 msecs
[coll (obj-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 264 msecs
[coll (obj-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 1540 msecs
[coll (obj-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 294 msecs
[coll (obj-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 251 msecs

;;; array-map
[], {[1] true, [2] true, [3] true}, 1000000 runs, 3150 msecs
[coll (array-map)], (assoc coll :foo :bar), 1000000 runs, 378 msecs
[coll (array-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 278 msecs
[coll (array-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 507 msecs
[coll (array-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 288 msecs
[coll (array-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 339 msecs

;;; array-map w/ symbols
[coll (array-map)], (assoc coll a b), 1000000 runs, 324 msecs
[coll (array-map a b)], (-lookup coll a), 1000000 runs, 301 msecs
[coll (array-map a b)], (assoc coll c d), 1000000 runs, 533 msecs
[coll (array-map a b c d)], (-lookup coll c), 1000000 runs, 355 msecs
[coll (array-map a b c d e f)], (-lookup coll e), 1000000 runs, 309 msecs

;;; array-map w/ inline symbols
[coll (array-map)], (assoc coll (quote foo) (quote bar)), 1000000 runs, 757 msecs
[coll (array-map (quote foo) (quote bar))], (-lookup coll (quote foo)), 1000000 runs, 514 msecs
[coll (array-map (quote foo) (quote bar))], (assoc coll (quote baz) (quote woz)), 1000000 runs, 844 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz))], (-lookup coll (quote baz)), 1000000 runs, 622 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz) (quote lol) (quote rofl))], (-lookup coll (quote lol)), 1000000 runs, 765 msecs

;;; map / record ops
[coll {:foo 1, :bar 2}], (get coll :foo), 1000000 runs, 271 msecs
[coll {(quote foo) 1, (quote bar) 2}], (get coll (quote foo)), 1000000 runs, 521 msecs
[coll {:foo 1, :bar 2}], (-lookup coll :foo nil), 1000000 runs, 276 msecs
[coll {(quote foo) 1, (quote bar) 2}], (-lookup coll (quote foo) nil), 1000000 runs, 515 msecs
[coll {:foo 1, :bar 2}], (:foo coll), 1000000 runs, 314 msecs
[coll {(quote foo) 1, (quote bar) 2}], ((quote foo) coll), 1000000 runs, 534 msecs
[coll {:foo 1, :bar 2}], (kw coll), 1000000 runs, 324 msecs
[coll {(quote foo) 1, (quote bar) 2}], (sym coll), 1000000 runs, 327 msecs
[coll {:foo 1, :bar 2}], (loop [i 0 m coll] (if (< i 100000) (recur (inc i) (assoc m :foo 2)) m)), 1 runs, 10 msecs
[coll (Foo. 1 2)], (:bar coll), 1000000 runs, 290 msecs
[coll (Foo. 1 2)], (-lookup coll :bar), 1000000 runs, 254 msecs
[coll (Foo. 1 2)], (assoc coll :bar 2), 1000000 runs, 301 msecs
[coll (Foo. 1 2)], (assoc coll :baz 3), 1000000 runs, 347 msecs
[coll (Foo. 1 2)], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :bar 2)) m)), 1 runs, 365 msecs

;;; zipmap
[m {:a 1, :b 2, :c 3}], (zipmap (keys m) (map inc (vals m))), 100000 runs, 496 msecs

;;; persistent hash maps
[key :f0], (hash key), 1000000 runs, 242 msecs
[key "f0"], (m3-hash-unencoded-chars key), 1000000 runs, 254 msecs
[key :unsynchronized-mutable], (hash key), 1000000 runs, 262 msecs
[coll hash-coll-test], (hash-coll coll), 100 runs, 319 msecs
[coll hash-coll-test], (hash-ordered-coll coll), 100 runs, 128 msecs
[coll hash-imap-test], (hash-imap coll), 100 runs, 124 msecs
[coll hash-imap-test], (hash-unordered-coll coll), 100 runs, 368 msecs
[coll pmap], (:f0 coll), 1000000 runs, 446 msecs
[coll pmap], (get coll :f0), 1000000 runs, 511 msecs
[coll pmap], (-lookup coll :f0 nil), 1000000 runs, 328 msecs
[coll pmap], (-lookup hash-imap-test :foo500 nil), 1000000 runs, 319 msecs
[coll pmap], (-lookup hash-imap-int-test 500 nil), 1000000 runs, 4954 msecs
[coll pmap], (assoc coll :g0 32), 1000000 runs, 963 msecs
[coll pmap], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :a 1)) m)), 1 runs, 425 msecs
[coll cljs.core.PersistentHashMap.EMPTY], (assoc coll :f0 1), 1000000 runs, 421 msecs

transient map, conj! 100000 items
"Elapsed time: 531 msecs"


;;; set ops
[], #{}, 1000000 runs, 230 msecs
[], #{1 3 2}, 1000000 runs, 0 msecs
[v [1 2 3]], (set v), 1000000 runs, 679 msecs
[], (hash-set 1 2 3), 1000000 runs, 0 msecs
[coll #{1 3 2}], (conj coll 4), 1000000 runs, 605 msecs
[coll #{1 3 2}], (get coll 2), 1000000 runs, 295 msecs
[coll #{1 3 2}], (contains? coll 2), 1000000 runs, 273 msecs
[coll #{1 3 2}], (coll 2), 1000000 runs, 321 msecs

;;; seq ops
[coll (range 500000)], (reduce + coll), 1 runs, 22 msecs

;;; reader
[s "{:foo [1 2 3]}"], (reader/read-string s), 1000 runs, 73 msecs
[s big-str-data], (reader/read-string s), 1000 runs, 934 msecs

;;; range
[r (range 1000000)], (last r), 1 runs, 33 msecs

;;; lazy-seq
;;; first run
[r r], (last r), 1 runs, 310 msecs
;;; second run
[r r], (last r), 1 runs, 60 msecs

;;; comprehensions
[xs (range 512)], (last (for [x xs y xs] (+ x y))), 1 runs, 230 msecs
[xs (vec (range 512))], (last (for [x xs y xs] (+ x y))), 4 runs, 400 msecs
[a (Box. 0) xs (range 512)], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 865 msecs
[a (Box. 0) xs (vec (range 512))], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 627 msecs

;; reducers
[xs (into [] (range 1000000))], (r/reduce + (r/map inc (r/map inc (r/map inc xs)))), 1 runs, 49 msecs
;; transducers
[xs (into [] (range 1000000))], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 55 msecs
;; primitive array reduce 1000000 many ops
[xs (into-array (range 1000000))], (-> xs (.map inc) (.map inc) (.map inc) (.reduce (fn [a b] (+ a b)) 0)), 1 runs, 197 msecs
;; reduce range 1000000 many ops
[xs (range 1000000)], (reduce + 0 (map inc (map inc (map inc xs)))), 1 runs, 1296 msecs
;; transduce range 1000000 many ops 
[xs (range 1000000)], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 48 msecs


;; multimethods
[], (simple-multi :foo), 1000000 runs, 502 msecs


;; higher-order variadic function calls
[f array], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 50 msecs
[f vector], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 434 msecs
[], (= 1 1 1 1 1 1 1 1 1 0), 100000 runs, 132 msecs
Comment by David Nolen [ 20/Jul/15 10:35 PM ]

Michal it might be a GC thing? Not sure. These tests need to be run on more engines, kinda wish we had something a bit more visual by now

Comment by Michał Marczyk [ 20/Jul/15 11:32 PM ]

Indeed… I got the V8 situation sorted in the meantime and benchmarked master vs 0003 with a fresh build; I thought the results were pretty encouraging, particularly the 2x speedup for "small vector conj".

1. master:

Benchmarking with V8
[x 1], (identity x), 1000000 runs, 0 msecs
;; symbol construction
[], (symbol (quote foo)), 1000000 runs, 63 msecs

;; array-reduce & ci-reduce
[coll (seq arr)], (ci-reduce coll + 0), 1 runs, 24 msecs
[coll (seq arr)], (ci-reduce coll sum 0), 1 runs, 21 msecs
[coll arr], (array-reduce coll + 0), 1 runs, 14 msecs
[coll arr], (array-reduce coll sum 0), 1 runs, 14 msecs
;;; instance?
[coll []], (instance? PersistentVector coll), 1000000 runs, 6 msecs
;;; satisfies?
[coll (list 1 2 3)], (satisfies? ISeq coll), 1000000 runs, 12 msecs
[coll [1 2 3]], (satisfies? ISeq coll), 1000000 runs, 21 msecs

;;; array & string ops
[coll (array 1 2 3)], (seq coll), 1000000 runs, 26 msecs
[coll "foobar"], (seq coll), 1000000 runs, 31 msecs
[coll (array 1 2 3)], (first coll), 1000000 runs, 39 msecs
[coll "foobar"], (first coll), 1000000 runs, 59 msecs
[coll (array 1 2 3)], (nth coll 2), 1000000 runs, 37 msecs
[coll "foobar"], (nth coll 2), 1000000 runs, 139 msecs

;;; cloning & specify
[coll [1 2 3]], (clone coll), 1000000 runs, 26 msecs
[coll [1 2 3]], (specify coll IFoo (foo [_] :bar)), 1000000 runs, 61 msecs
[coll (specify [1 2 3] IFoo (foo [_] :bar))], (foo coll), 1000000 runs, 20 msecs

;;; list ops
[coll (list 1 2 3)], (first coll), 1000000 runs, 16 msecs
[coll (list 1 2 3)], (-first coll), 1000000 runs, 13 msecs
[coll (list 1 2 3)], (rest coll), 1000000 runs, 10 msecs
[coll (list 1 2 3)], (-rest coll), 1000000 runs, 11 msecs
[], (list), 1000000 runs, 5 msecs
[], (list 1 2 3), 1000000 runs, 67 msecs

;;; vector ops
[], [], 1000000 runs, 4 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count [a b c]), 1000000 runs, 71 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vec #object[cljs.tagged_literals.JSValue 0x158e6fc2 "cljs.tagged_literals.JSValue@158e6fc2"])), 1000000 runs, 56 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vector a b c)), 1000000 runs, 83 msecs
[coll [1 2 3]], (transient coll), 100000 runs, 28 msecs
[coll [1 2 3]], (nth coll 0), 1000000 runs, 23 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 25 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 22 msecs
[coll [1 2 3]], (coll 0), 1000000 runs, 27 msecs
[coll [1 2 3]], (conj coll 4), 1000000 runs, 64 msecs
[coll [1 2 3]], (-conj coll 4), 1000000 runs, 60 msecs
[coll []], (-conj coll 1), 1000000 runs, 53 msecs
[coll [1]], (-conj coll 2), 1000000 runs, 54 msecs
[coll [1 2]], (-conj coll 3), 1000000 runs, 53 msecs
[coll [1 2 3]], (seq coll), 1000000 runs, 26 msecs
[coll [1 2 3]], (-seq coll), 1000000 runs, 25 msecs
[coll (seq [1 2 3])], (first coll), 1000000 runs, 19 msecs
[coll (seq [1 2 3])], (-first coll), 1000000 runs, 16 msecs
[coll (seq [1 2 3])], (rest coll), 1000000 runs, 24 msecs
[coll (seq [1 2 3])], (-rest coll), 1000000 runs, 22 msecs
[coll (seq [1 2 3])], (next coll), 1000000 runs, 26 msecs

;;; large vector ops
[], (reduce conj [] (range 40000)), 10 runs, 56 msecs
[coll (reduce conj [] (range (+ 32768 32)))], (conj coll :foo), 100000 runs, 27 msecs
[coll (reduce conj [] (range 40000))], (assoc coll 123 :foo), 100000 runs, 64 msecs
[coll (reduce conj [] (range (+ 32768 33)))], (pop coll), 100000 runs, 23 msecs

;;; chunked seqs
[], (-first v), 1000000 runs, 14 msecs
[], (-next v), 1000000 runs, 32 msecs
[], (-rest v), 1000000 runs, 33 msecs

;;; transients
transient vector, conj! 1000000 items
"Elapsed time: 41 msecs"


;;; vector equality
[a (into [] (range 1000000)) b (into [] (range 1000000))], (= a b), 1 runs, 36 msecs

;;; keyword compare
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed)))))], (.sort arr compare), 100 runs, 327 msecs
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed) (rand-nth seed)))))], (.sort arr compare), 100 runs, 974 msecs

;;; reduce lazy-seqs, vectors, ranges
[coll (take 100000 (iterate inc 0))], (reduce + 0 coll), 1 runs, 74 msecs
[coll (range 1000000)], (reduce + 0 coll), 1 runs, 16 msecs
[coll (into [] (range 1000000))], (reduce + 0 coll), 1 runs, 28 msecs

;; apply
[coll (into [] (range 1000000))], (apply + coll), 1 runs, 61 msecs
[], (list 1 2 3 4 5), 1000000 runs, 146 msecs
[xs (array-seq (array 1 2 3 4 5))], (apply list xs), 1000000 runs, 121 msecs
[xs (list 1 2 3 4 5)], (apply list xs), 1000000 runs, 809 msecs
[xs [1 2 3 4 5]], (apply list xs), 1000000 runs, 141 msecs
[f (fn [a b & more])], (apply f (range 32)), 1000000 runs, 201 msecs
[f (fn [a b c d e f g h i j & more])], (apply f (range 32)), 1000000 runs, 483 msecs

;; update-in
[coll {:foo 1} ks [:foo]], (update-in coll ks inc), 1000000 runs, 290 msecs
[coll (array-map :foo 1) ks [:foo]], (update-in coll ks inc), 1000000 runs, 295 msecs

;;; obj-map
[coll (obj-map)], (assoc coll :foo :bar), 1000000 runs, 271 msecs
[coll (obj-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 27 msecs
[coll (obj-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 711 msecs
[coll (obj-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 23 msecs
[coll (obj-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 24 msecs

;;; array-map
[], {[1] true, [2] true, [3] true}, 1000000 runs, 1284 msecs
[coll (array-map)], (assoc coll :foo :bar), 1000000 runs, 66 msecs
[coll (array-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 43 msecs
[coll (array-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 72 msecs
[coll (array-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 52 msecs
[coll (array-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 56 msecs

;;; array-map w/ symbols
[coll (array-map)], (assoc coll a b), 1000000 runs, 79 msecs
[coll (array-map a b)], (-lookup coll a), 1000000 runs, 57 msecs
[coll (array-map a b)], (assoc coll c d), 1000000 runs, 87 msecs
[coll (array-map a b c d)], (-lookup coll c), 1000000 runs, 61 msecs
[coll (array-map a b c d e f)], (-lookup coll e), 1000000 runs, 70 msecs

;;; array-map w/ inline symbols
[coll (array-map)], (assoc coll (quote foo) (quote bar)), 1000000 runs, 142 msecs
[coll (array-map (quote foo) (quote bar))], (-lookup coll (quote foo)), 1000000 runs, 91 msecs
[coll (array-map (quote foo) (quote bar))], (assoc coll (quote baz) (quote woz)), 1000000 runs, 171 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz))], (-lookup coll (quote baz)), 1000000 runs, 99 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz) (quote lol) (quote rofl))], (-lookup coll (quote lol)), 1000000 runs, 106 msecs

;;; map / record ops
[coll {:foo 1, :bar 2}], (get coll :foo), 1000000 runs, 34 msecs
[coll {(quote foo) 1, (quote bar) 2}], (get coll (quote foo)), 1000000 runs, 84 msecs
[coll {:foo 1, :bar 2}], (-lookup coll :foo nil), 1000000 runs, 32 msecs
[coll {(quote foo) 1, (quote bar) 2}], (-lookup coll (quote foo) nil), 1000000 runs, 82 msecs
[coll {:foo 1, :bar 2}], (:foo coll), 1000000 runs, 40 msecs
[coll {(quote foo) 1, (quote bar) 2}], ((quote foo) coll), 1000000 runs, 119 msecs
[coll {:foo 1, :bar 2}], (kw coll), 1000000 runs, 47 msecs
[coll {(quote foo) 1, (quote bar) 2}], (sym coll), 1000000 runs, 70 msecs
[coll {:foo 1, :bar 2}], (loop [i 0 m coll] (if (< i 100000) (recur (inc i) (assoc m :foo 2)) m)), 1 runs, 9 msecs
[coll (Foo. 1 2)], (:bar coll), 1000000 runs, 36 msecs
[coll (Foo. 1 2)], (-lookup coll :bar), 1000000 runs, 29 msecs
[coll (Foo. 1 2)], (assoc coll :bar 2), 1000000 runs, 60 msecs
[coll (Foo. 1 2)], (assoc coll :baz 3), 1000000 runs, 69 msecs
[coll (Foo. 1 2)], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :bar 2)) m)), 1 runs, 47 msecs

;;; zipmap
[m {:a 1, :b 2, :c 3}], (zipmap (keys m) (map inc (vals m))), 100000 runs, 257 msecs

;;; persistent hash maps
[key :f0], (hash key), 1000000 runs, 13 msecs
[key "f0"], (m3-hash-unencoded-chars key), 1000000 runs, 24 msecs
[key :unsynchronized-mutable], (hash key), 1000000 runs, 13 msecs
[coll hash-coll-test], (hash-coll coll), 100 runs, 80 msecs
[coll hash-coll-test], (hash-ordered-coll coll), 100 runs, 75 msecs
[coll hash-imap-test], (hash-imap coll), 100 runs, 91 msecs
[coll hash-imap-test], (hash-unordered-coll coll), 100 runs, 83 msecs
[coll pmap], (:f0 coll), 1000000 runs, 64 msecs
[coll pmap], (get coll :f0), 1000000 runs, 56 msecs
[coll pmap], (-lookup coll :f0 nil), 1000000 runs, 45 msecs
[coll pmap], (-lookup hash-imap-test :foo500 nil), 1000000 runs, 78 msecs
[coll pmap], (-lookup hash-imap-int-test 500 nil), 1000000 runs, 224 msecs
[coll pmap], (assoc coll :g0 32), 1000000 runs, 405 msecs
[coll pmap], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :a 1)) m)), 1 runs, 83 msecs
[coll cljs.core.PersistentHashMap.EMPTY], (assoc coll :f0 1), 1000000 runs, 155 msecs

transient map, conj! 100000 items
"Elapsed time: 48 msecs"


;;; set ops
[], #{}, 1000000 runs, 5 msecs
[], #{1 3 2}, 1000000 runs, 0 msecs
[v [1 2 3]], (set v), 1000000 runs, 355 msecs
[], (hash-set 1 2 3), 1000000 runs, 0 msecs
[coll #{1 3 2}], (conj coll 4), 1000000 runs, 243 msecs
[coll #{1 3 2}], (get coll 2), 1000000 runs, 48 msecs
[coll #{1 3 2}], (contains? coll 2), 1000000 runs, 38 msecs
[coll #{1 3 2}], (coll 2), 1000000 runs, 54 msecs

;;; seq ops
[coll (range 500000)], (reduce + coll), 1 runs, 24 msecs

;;; reader
[s "{:foo [1 2 3]}"], (reader/read-string s), 1000 runs, 23 msecs
[s big-str-data], (reader/read-string s), 1000 runs, 654 msecs

;;; range
[r (range 1000000)], (last r), 1 runs, 42 msecs

;;; lazy-seq
;;; first run
[r r], (last r), 1 runs, 319 msecs
;;; second run
[r r], (last r), 1 runs, 87 msecs

;;; comprehensions
[xs (range 512)], (last (for [x xs y xs] (+ x y))), 1 runs, 246 msecs
[xs (vec (range 512))], (last (for [x xs y xs] (+ x y))), 4 runs, 163 msecs
[a (Box. 0) xs (range 512)], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 134 msecs
[a (Box. 0) xs (vec (range 512))], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 22 msecs

;; reducers
[xs (into [] (range 1000000))], (r/reduce + (r/map inc (r/map inc (r/map inc xs)))), 1 runs, 85 msecs
;; transducers
[xs (into [] (range 1000000))], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 105 msecs
;; primitive array reduce 1000000 many ops
[xs (into-array (range 1000000))], (-> xs (.map inc) (.map inc) (.map inc) (.reduce (fn [a b] (+ a b)) 0)), 1 runs, 359 msecs
;; reduce range 1000000 many ops
[xs (range 1000000)], (reduce + 0 (map inc (map inc (map inc xs)))), 1 runs, 1413 msecs
;; transduce range 1000000 many ops 
[xs (range 1000000)], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 80 msecs


;; multimethods
[], (simple-multi :foo), 1000000 runs, 134 msecs


;; higher-order variadic function calls
[f array], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 8 msecs
[f vector], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 30 msecs
[], (= 1 1 1 1 1 1 1 1 1 0), 100000 runs, 95 msecs

2. 0003:

Benchmarking with V8
[x 1], (identity x), 1000000 runs, 0 msecs
;; symbol construction
[], (symbol (quote foo)), 1000000 runs, 51 msecs

;; array-reduce & ci-reduce
[coll (seq arr)], (ci-reduce coll + 0), 1 runs, 23 msecs
[coll (seq arr)], (ci-reduce coll sum 0), 1 runs, 19 msecs
[coll arr], (array-reduce coll + 0), 1 runs, 13 msecs
[coll arr], (array-reduce coll sum 0), 1 runs, 11 msecs
;;; instance?
[coll []], (instance? PersistentVector coll), 1000000 runs, 6 msecs
;;; satisfies?
[coll (list 1 2 3)], (satisfies? ISeq coll), 1000000 runs, 12 msecs
[coll [1 2 3]], (satisfies? ISeq coll), 1000000 runs, 22 msecs

;;; array & string ops
[coll (array 1 2 3)], (seq coll), 1000000 runs, 27 msecs
[coll "foobar"], (seq coll), 1000000 runs, 39 msecs
[coll (array 1 2 3)], (first coll), 1000000 runs, 34 msecs
[coll "foobar"], (first coll), 1000000 runs, 44 msecs
[coll (array 1 2 3)], (nth coll 2), 1000000 runs, 35 msecs
[coll "foobar"], (nth coll 2), 1000000 runs, 137 msecs

;;; cloning & specify
[coll [1 2 3]], (clone coll), 1000000 runs, 23 msecs
[coll [1 2 3]], (specify coll IFoo (foo [_] :bar)), 1000000 runs, 69 msecs
[coll (specify [1 2 3] IFoo (foo [_] :bar))], (foo coll), 1000000 runs, 20 msecs

;;; list ops
[coll (list 1 2 3)], (first coll), 1000000 runs, 16 msecs
[coll (list 1 2 3)], (-first coll), 1000000 runs, 13 msecs
[coll (list 1 2 3)], (rest coll), 1000000 runs, 10 msecs
[coll (list 1 2 3)], (-rest coll), 1000000 runs, 10 msecs
[], (list), 1000000 runs, 4 msecs
[], (list 1 2 3), 1000000 runs, 67 msecs

;;; vector ops
[], [], 1000000 runs, 4 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count [a b c]), 1000000 runs, 40 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vec #object[cljs.tagged_literals.JSValue 0x3e5ebdfe "cljs.tagged_literals.JSValue@3e5ebdfe"])), 1000000 runs, 55 msecs
[[a b c] (take 3 (repeatedly (fn* [] (rand-int 10))))], (-count (vector a b c)), 1000000 runs, 46 msecs
[coll [1 2 3]], (transient coll), 100000 runs, 31 msecs
[coll [1 2 3]], (nth coll 0), 1000000 runs, 16 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 16 msecs
[coll [1 2 3]], (-nth coll 0), 1000000 runs, 16 msecs
[coll [1 2 3]], (coll 0), 1000000 runs, 24 msecs
[coll [1 2 3]], (conj coll 4), 1000000 runs, 31 msecs
[coll [1 2 3]], (-conj coll 4), 1000000 runs, 29 msecs
[coll []], (-conj coll 1), 1000000 runs, 25 msecs
[coll [1]], (-conj coll 2), 1000000 runs, 22 msecs
[coll [1 2]], (-conj coll 3), 1000000 runs, 26 msecs
[coll [1 2 3]], (seq coll), 1000000 runs, 26 msecs
[coll [1 2 3]], (-seq coll), 1000000 runs, 26 msecs
[coll (seq [1 2 3])], (first coll), 1000000 runs, 28 msecs
[coll (seq [1 2 3])], (-first coll), 1000000 runs, 24 msecs
[coll (seq [1 2 3])], (rest coll), 1000000 runs, 30 msecs
[coll (seq [1 2 3])], (-rest coll), 1000000 runs, 26 msecs
[coll (seq [1 2 3])], (next coll), 1000000 runs, 29 msecs

;;; large vector ops
[], (reduce conj [] (range 40000)), 10 runs, 60 msecs
[coll (reduce conj [] (range (+ 32768 32)))], (conj coll :foo), 100000 runs, 32 msecs
[coll (reduce conj [] (range 40000))], (assoc coll 123 :foo), 100000 runs, 63 msecs
[coll (reduce conj [] (range (+ 32768 33)))], (pop coll), 100000 runs, 22 msecs

;;; chunked seqs
[], (-first v), 1000000 runs, 14 msecs
[], (-next v), 1000000 runs, 36 msecs
[], (-rest v), 1000000 runs, 33 msecs

;;; transients
transient vector, conj! 1000000 items
"Elapsed time: 44 msecs"


;;; vector equality
[a (into [] (range 1000000)) b (into [] (range 1000000))], (= a b), 1 runs, 37 msecs

;;; keyword compare
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed)))))], (.sort arr compare), 100 runs, 281 msecs
[arr (into-array (repeatedly 10000 (fn* [] (keyword (rand-nth seed) (rand-nth seed)))))], (.sort arr compare), 100 runs, 1025 msecs

;;; reduce lazy-seqs, vectors, ranges
[coll (take 100000 (iterate inc 0))], (reduce + 0 coll), 1 runs, 75 msecs
[coll (range 1000000)], (reduce + 0 coll), 1 runs, 17 msecs
[coll (into [] (range 1000000))], (reduce + 0 coll), 1 runs, 25 msecs

;; apply
[coll (into [] (range 1000000))], (apply + coll), 1 runs, 69 msecs
[], (list 1 2 3 4 5), 1000000 runs, 206 msecs
[xs (array-seq (array 1 2 3 4 5))], (apply list xs), 1000000 runs, 121 msecs
[xs (list 1 2 3 4 5)], (apply list xs), 1000000 runs, 757 msecs
[xs [1 2 3 4 5]], (apply list xs), 1000000 runs, 924 msecs
[f (fn [a b & more])], (apply f (range 32)), 1000000 runs, 184 msecs
[f (fn [a b c d e f g h i j & more])], (apply f (range 32)), 1000000 runs, 453 msecs

;; update-in
[coll {:foo 1} ks [:foo]], (update-in coll ks inc), 1000000 runs, 320 msecs
[coll (array-map :foo 1) ks [:foo]], (update-in coll ks inc), 1000000 runs, 301 msecs

;;; obj-map
[coll (obj-map)], (assoc coll :foo :bar), 1000000 runs, 267 msecs
[coll (obj-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 27 msecs
[coll (obj-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 727 msecs
[coll (obj-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 24 msecs
[coll (obj-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 25 msecs

;;; array-map
[], {[1] true, [2] true, [3] true}, 1000000 runs, 762 msecs
[coll (array-map)], (assoc coll :foo :bar), 1000000 runs, 66 msecs
[coll (array-map :foo :bar)], (-lookup coll :foo), 1000000 runs, 50 msecs
[coll (array-map :foo :bar)], (assoc coll :baz :woz), 1000000 runs, 74 msecs
[coll (array-map :foo :bar :baz :woz)], (-lookup coll :baz), 1000000 runs, 56 msecs
[coll (array-map :foo :bar :baz :woz :lol :rofl)], (-lookup coll :lol), 1000000 runs, 62 msecs

;;; array-map w/ symbols
[coll (array-map)], (assoc coll a b), 1000000 runs, 82 msecs
[coll (array-map a b)], (-lookup coll a), 1000000 runs, 61 msecs
[coll (array-map a b)], (assoc coll c d), 1000000 runs, 90 msecs
[coll (array-map a b c d)], (-lookup coll c), 1000000 runs, 65 msecs
[coll (array-map a b c d e f)], (-lookup coll e), 1000000 runs, 72 msecs

;;; array-map w/ inline symbols
[coll (array-map)], (assoc coll (quote foo) (quote bar)), 1000000 runs, 142 msecs
[coll (array-map (quote foo) (quote bar))], (-lookup coll (quote foo)), 1000000 runs, 92 msecs
[coll (array-map (quote foo) (quote bar))], (assoc coll (quote baz) (quote woz)), 1000000 runs, 163 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz))], (-lookup coll (quote baz)), 1000000 runs, 102 msecs
[coll (array-map (quote foo) (quote bar) (quote baz) (quote woz) (quote lol) (quote rofl))], (-lookup coll (quote lol)), 1000000 runs, 105 msecs

;;; map / record ops
[coll {:foo 1, :bar 2}], (get coll :foo), 1000000 runs, 35 msecs
[coll {(quote foo) 1, (quote bar) 2}], (get coll (quote foo)), 1000000 runs, 86 msecs
[coll {:foo 1, :bar 2}], (-lookup coll :foo nil), 1000000 runs, 31 msecs
[coll {(quote foo) 1, (quote bar) 2}], (-lookup coll (quote foo) nil), 1000000 runs, 80 msecs
[coll {:foo 1, :bar 2}], (:foo coll), 1000000 runs, 42 msecs
[coll {(quote foo) 1, (quote bar) 2}], ((quote foo) coll), 1000000 runs, 116 msecs
[coll {:foo 1, :bar 2}], (kw coll), 1000000 runs, 47 msecs
[coll {(quote foo) 1, (quote bar) 2}], (sym coll), 1000000 runs, 67 msecs
[coll {:foo 1, :bar 2}], (loop [i 0 m coll] (if (< i 100000) (recur (inc i) (assoc m :foo 2)) m)), 1 runs, 5 msecs
[coll (Foo. 1 2)], (:bar coll), 1000000 runs, 35 msecs
[coll (Foo. 1 2)], (-lookup coll :bar), 1000000 runs, 30 msecs
[coll (Foo. 1 2)], (assoc coll :bar 2), 1000000 runs, 52 msecs
[coll (Foo. 1 2)], (assoc coll :baz 3), 1000000 runs, 61 msecs
[coll (Foo. 1 2)], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :bar 2)) m)), 1 runs, 44 msecs

;;; zipmap
[m {:a 1, :b 2, :c 3}], (zipmap (keys m) (map inc (vals m))), 100000 runs, 230 msecs

;;; persistent hash maps
[key :f0], (hash key), 1000000 runs, 13 msecs
[key "f0"], (m3-hash-unencoded-chars key), 1000000 runs, 22 msecs
[key :unsynchronized-mutable], (hash key), 1000000 runs, 11 msecs
[coll hash-coll-test], (hash-coll coll), 100 runs, 70 msecs
[coll hash-coll-test], (hash-ordered-coll coll), 100 runs, 65 msecs
[coll hash-imap-test], (hash-imap coll), 100 runs, 73 msecs
[coll hash-imap-test], (hash-unordered-coll coll), 100 runs, 96 msecs
[coll pmap], (:f0 coll), 1000000 runs, 64 msecs
[coll pmap], (get coll :f0), 1000000 runs, 52 msecs
[coll pmap], (-lookup coll :f0 nil), 1000000 runs, 47 msecs
[coll pmap], (-lookup hash-imap-test :foo500 nil), 1000000 runs, 79 msecs
[coll pmap], (-lookup hash-imap-int-test 500 nil), 1000000 runs, 216 msecs
[coll pmap], (assoc coll :g0 32), 1000000 runs, 405 msecs
[coll pmap], (loop [i 0 m coll] (if (< i 1000000) (recur (inc i) (assoc m :a 1)) m)), 1 runs, 80 msecs
[coll cljs.core.PersistentHashMap.EMPTY], (assoc coll :f0 1), 1000000 runs, 156 msecs

transient map, conj! 100000 items
"Elapsed time: 53 msecs"


;;; set ops
[], #{}, 1000000 runs, 5 msecs
[], #{1 3 2}, 1000000 runs, 0 msecs
[v [1 2 3]], (set v), 1000000 runs, 515 msecs
[], (hash-set 1 2 3), 1000000 runs, 0 msecs
[coll #{1 3 2}], (conj coll 4), 1000000 runs, 266 msecs
[coll #{1 3 2}], (get coll 2), 1000000 runs, 50 msecs
[coll #{1 3 2}], (contains? coll 2), 1000000 runs, 38 msecs
[coll #{1 3 2}], (coll 2), 1000000 runs, 62 msecs

;;; seq ops
[coll (range 500000)], (reduce + coll), 1 runs, 23 msecs

;;; reader
[s "{:foo [1 2 3]}"], (reader/read-string s), 1000 runs, 30 msecs
[s big-str-data], (reader/read-string s), 1000 runs, 636 msecs

;;; range
[r (range 1000000)], (last r), 1 runs, 44 msecs

;;; lazy-seq
;;; first run
[r r], (last r), 1 runs, 322 msecs
;;; second run
[r r], (last r), 1 runs, 90 msecs

;;; comprehensions
[xs (range 512)], (last (for [x xs y xs] (+ x y))), 1 runs, 229 msecs
[xs (vec (range 512))], (last (for [x xs y xs] (+ x y))), 4 runs, 196 msecs
[a (Box. 0) xs (range 512)], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 133 msecs
[a (Box. 0) xs (vec (range 512))], (doseq [x xs y xs] (set! a -val (+ (.-val a) x))), 4 runs, 23 msecs

;; reducers
[xs (into [] (range 1000000))], (r/reduce + (r/map inc (r/map inc (r/map inc xs)))), 1 runs, 85 msecs
;; transducers
[xs (into [] (range 1000000))], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 108 msecs
;; primitive array reduce 1000000 many ops
[xs (into-array (range 1000000))], (-> xs (.map inc) (.map inc) (.map inc) (.reduce (fn [a b] (+ a b)) 0)), 1 runs, 349 msecs
;; reduce range 1000000 many ops
[xs (range 1000000)], (reduce + 0 (map inc (map inc (map inc xs)))), 1 runs, 1387 msecs
;; transduce range 1000000 many ops 
[xs (range 1000000)], (transduce (comp (map inc) (map inc) (map inc)) + 0 xs), 1 runs, 79 msecs


;; multimethods
[], (simple-multi :foo), 1000000 runs, 122 msecs


;; higher-order variadic function calls
[f array], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 8 msecs
[f vector], (f 1 2 3 4 5 6 7 8 9 0), 100000 runs, 154 msecs
[], (= 1 1 1 1 1 1 1 1 1 0), 100000 runs, 94 msecs
Comment by Michał Marczyk [ 20/Jul/15 11:35 PM ]

(No rebase this time, as 0003 still applies cleanly and all tests pass.)





[CLJS-1343] Investigate performance impact of using records over maps during compilation Created: 17/Jul/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Task Priority: Major
Reporter: David Nolen Assignee: Sebastian Bensusan
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Profiles in Chrome DevTools reveal that a considerable amount of time is spent in PersistentArrayMap and PersistentHashMap. It would be worth considering coverting all maps into records with a protocol to extract the pure data form of the AST.






[CLJS-1342] cljs.reader/read-string should throw Error when not called with string Created: 16/Jul/15  Updated: 17/Jul/15  Resolved: 17/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Michiel Borkent Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1342.patch    
Patch: Code and Test

 Comments   
Comment by David Nolen [ 17/Jul/15 5:22 AM ]

Please remove the changes to .gitignore and squash the patch into a single commit. Thanks!

Comment by Michiel Borkent [ 17/Jul/15 5:42 AM ]

Hopefully this is better.

Comment by David Nolen [ 17/Jul/15 6:54 AM ]

fixed https://github.com/clojure/clojurescript/commit/047af0965c6760483aca94b55666563e0857629d





[CLJS-1341] NON_TOP_LEVEL_STATEMENT_DEFINE error when trying to process a CommonJS module Created: 15/Jul/15  Updated: 17/Jul/15  Resolved: 17/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: GSoC
Fix Version/s: GSoC

Type: Defect Priority: Major
Reporter: Maria Geller Assignee: Maria Geller
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1341.patch    
Patch: Code

 Description   

The process for converting CommonJS and AMD modules is the same except for one step. We forgot to add a module type check for this one step, meaning that AMD and CommonJS are currently processed exactly the same, which results in the following error:

ERROR: NON_TOP_LEVEL_STATEMENT_DEFINE. The define function must be called as a top-level statement. at libs/d3.js line 9501 : 50



 Comments   
Comment by Maria Geller [ 16/Jul/15 8:37 AM ]

Uploaded patch. Fixed this by checking module type before attempting to convert from AMD to CommonJS.

Comment by David Nolen [ 17/Jul/15 5:38 AM ]

fixed https://github.com/clojure/clojurescript/commit/eef613f492ccdd4e2e4bd825fd0a7570ea6b85c1





[CLJS-1340] Add Clojure dependency version checks and error messages Created: 13/Jul/15  Updated: 18/Jul/15  Resolved: 18/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Anna Pawlicka Assignee: Anna Pawlicka
Resolution: Declined Votes: 0
Labels: None


 Description   

ClojureScript requires a specific version of Clojure and if the user uses the latest ClojureScript with Clojure <= 1.7.0-beta2, the ns form will try load namespaces it can't load and will throw an exception without letting the user know the reason. We should add a version check to namespaces that the user might load, e.g. cljs.closure and cljs.repl.



 Comments   
Comment by David Nolen [ 13/Jul/15 4:32 PM ]

The fundamental issue is that we now have .cljc files which cannot be loaded by earlier versions of Clojure. Fortunately there are only a few proper entry points into the compiler. We are only concerned about users following the techniques and conventions of the Quick Start. Dealing with 3rd party tools is out of scope, since they often tap into the implementation details we would have to add checks to all namespaces. Instead we should probably punt on this issue and recommend that 3rd party tools implement their own check.

We need only two checks. One before the cljs.closure ns form. REPLs are also a common entry point. We should rename `cljs/repl.cljc` back to `cljs/repl.clj`. This namespace isn't portable to a bootstrapped environment anyway due to an over reliance on synchronous I/O. We should then put a check before the cljs.repl ns form.

We should confirm that these checks work in the presence of AOT.

Comment by Anna Pawlicka [ 18/Jul/15 5:26 PM ]

Unfortunately it doesn't work with AOT compilation resulting in NPE when trying to call a function from another namespace, before current namespace form. Copying and pasting the same code all over the place sounds bad and we should add those types of checks to build tools instead (boot, cljsbuild).





[CLJS-1339] Destructuring vector results in stack overflow error Created: 12/Jul/15  Updated: 13/Jul/15  Resolved: 13/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Shriphani Palakodety Assignee: Unassigned
Resolution: Not Reproducible Votes: 0
Labels: destructuring
Environment:

OS X, Chrome stable.



 Description   

Given this function:

Unable to find source-code formatter for language: clojure. Available languages are: javascript, sql, xhtml, actionscript, none, html, xml, java
(defn ^:export rectangle-diff
  "Returns the un-superposed area of 2 rectangles."
  [rect1 rect2]
  (let [[left top right bottom] rect1]
    left))

Running this in the chrome console returns this:

coord1 = [[1, 1], [1000, 1000]]
[Array[2], Array[2]]
coord2 = [[8, 8], [359, 670]]
[Array[2], Array[2]]
borte.tables.rectangle_diff(coord1, coord2)
tables.min.js:17 Uncaught RangeError: Maximum call stack size exceeded
    at ya (http://localhost:9000/out-adv/borte.min.js:17:893)
    at ya (http://localhost:9000/out-adv/borte.min.js:17:893)
    at ya (http://localhost:9000/out-adv/borte.min.js:17:893)
    at ya (http://localhost:9000/out-adv/borte.min.js:17:893)
    at ya (http://localhost:9000/out-adv/borte.min.js:17:893)
    at ya (http://localhost:9000/out-adv/borte.min.js:17:893)
    at ya (http://localhost:9000/out-adv/borte.min.js:17:893)
    at ya (http://localhost:9000/out-adv/borte.min.js:17:893)
    at ya (http://localhost:9000/out-adv/borte.min.js:17:893)
    at ya (http://localhost:9000/out-adv/borte.min.js:17:893)

This error disappears if I use 0.0-2755



 Comments   
Comment by David Nolen [ 13/Jul/15 5:54 AM ]

There's not enough information here to reproduce anything. I tried this at REPL and did not encounter the issue.





[CLJS-1338] NPE in confirm-var-exists if suffix is ".." Created: 12/Jul/15  Updated: 12/Jul/15  Resolved: 12/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: bootstrap
Environment:

Master, :clj mode



 Description   

When compiling out/cljs/core.cljc for bootstrap purposes (with ClojureScript JVM), `cljs.analyzer/confirm-var-exists` ends up being called with prefix of "cljs.core$macros" and suffix of "..". This causes suffix-str to take on the value nil which is passed to `symbol`, causing an NPE.

This regression occurred with this commit: https://github.com/clojure/clojurescript/commit/8bb3b1ddc28bb773dcd3acd74f6e35c50015246b



 Comments   
Comment by David Nolen [ 12/Jul/15 3:07 PM ]

fixed https://github.com/clojure/clojurescript/commit/8600c7cb88414ec91faf5cb22e3c4ee3be649b0d





[CLJS-1337] Move parse ns side-effects into a separate compiler pass Created: 12/Jul/15  Updated: 15/Jul/15  Resolved: 15/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: bootstrap


 Description   

Originally suggested by Thomas Heller there's now an immediate need to pursue this - bootstrapping. Currently the ns side-effects assume I/O can happen synchronously. This assumption falls apart in many JS environments.



 Comments   
Comment by David Nolen [ 15/Jul/15 5:47 PM ]

fixed https://github.com/clojure/clojurescript/commit/ae39482364227076a86e786e2c2bca5996f6893d





[CLJS-1336] Create bootstrapping namespace Created: 12/Jul/15  Updated: 31/Jul/15  Resolved: 31/Jul/15

Status: Resolved
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

This namespace should provide basic analyze, emit, eval functionality along with necessary helpers for establishing the compilation environment. *load-file* or something similar must be bound by the user. One open question is how to handle async versus sync file loading. In the browser context only the former is really realistic, while in Node.js/iOS/Android we have considerably more flexibility.



 Comments   
Comment by David Nolen [ 12/Jul/15 2:05 PM ]

CLJS-1337 must be addressed first.

Comment by David Nolen [ 31/Jul/15 8:12 PM ]

fixed in master





[CLJS-1335] resolve-macro-var: information missing for macros Created: 12/Jul/15  Updated: 12/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bootstrap
Environment:

https://github.com/swannodette/cljs-bootstrap



 Description   

In bootstrapped ClojureScript, if you resolve-var on a function, you get lots of information, but resolve-macro-var doesn't work for macros. (The only reason I have any expectation for this to work is that it appears to do so in ClojureScript JVM).

cljs-bootstrap.core=> (with-compiler-env cenv (ana/resolve-macro-var (ana/empty-env) 'or)))
nil

But:

cljs-bootstrap.core=> (with-compiler-env cenv (ana/resolve-var (ana/empty-env) 'map)))
{:protocol-inline nil, :meta {:file "cljs/core.cljs", :end-column 10, :top-fn {:variadic true, :method-params ([f] [f coll] [f c1 c2] [f c1 c2 c3]), :arglists-meta (nil nil nil nil nil), :max-fixed-arity 4, :arglists ([f] [f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])}, :column 7, :line 4128, :end-line 4128, :arglists (quote ([f] [f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])), :doc "Returns a lazy sequence consisting of the result of applying f to\n  the set of first items of each coll, followed by applying f to the\n  set of second items in each coll, until any one of the colls is\n  exhausted.  Any remaining items in other colls are ignored. Function\n  f should accept number-of-colls arguments. Returns a transducer when\n  no collection is provided."}, :ns cljs.core, :name cljs.core/map, :variadic true, :file "cljs/core.cljs", :end-column 10, :top-fn {:variadic true, :method-params ([f] [f coll] [f c1 c2] [f c1 c2 c3]), :arglists-meta (nil nil nil nil nil), :max-fixed-arity 4, :arglists ([f] [f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls])}, :method-params ([f] [f coll] [f c1 c2] [f c1 c2 c3]), :protocol-impl nil, :arglists-meta (nil nil nil nil nil), :column 1, :line 4128, :end-line 4128, :max-fixed-arity 4, :fn-var true, :arglists ([f] [f coll] [f c1 c2] [f c1 c2 c3] [f c1 c2 c3 & colls]), :doc "Returns a lazy sequence consisting of the result of applying f to\n  the set of first items of each coll, followed by applying f to the\n  set of second items in each coll, until any one of the colls is\n  exhausted.  Any remaining items in other colls are ignored. Function\n  f should accept number-of-colls arguments. Returns a transducer when\n  no collection is provided."}

As an aside:

cljs-bootstrap.core=> (with-compiler-env cenv (ana/resolve-var (ana/empty-env) 'or)))
{:name cljs.core/or, :ns cljs.core}





[CLJS-1334] Bootstrap 2-binding for can't recur here Created: 11/Jul/15  Updated: 15/Jul/15  Resolved: 15/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: bootstrap

Attachments: Text File cljs-1334-for-macro-v2.patch    

 Description   

A form like {{(for [x [1] y [2]] y)}} causes a Can't recur here error diagnostic.

With https://github.com/swannodette/cljs-bootstrap

cljs-bootstrap.core=> *clojurescript-version*
"0.0-3464"
cljs-bootstrap.core=> (for [x [1] y [2]] y)
(2)
cljs-bootstrap.core=> (with-out-str
      (c/emit
        (ensure
          (ana/analyze
            (assoc (ana/empty-env) :context :expr)
             '(for [x [1] y [2]] y))))))
Error: Can't recur here
    at new cljs$core$ExceptionInfo (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/core.cljs:9688:9)
    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/core.cljs:9720:14)
    at Function.cljs.analyzer.error.cljs$core$IFn$_invoke$arity$3 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:514:5)
    at Function.cljs.analyzer.error.cljs$core$IFn$_invoke$arity$2 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:512:13)
    at /Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:1364:15
    at [object Object].cljs.core.MultiFn.cljs$core$IFn$_invoke$arity$5 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/core.cljs:9445:8)
    at Object.cljs$analyzer$analyze_seq_STAR_ [as analyze_seq_STAR_] (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:2174:6)
    at Object.cljs$analyzer$analyze_seq_STAR__wrap [as analyze_seq_STAR__wrap] (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:2179:6)
    at Function.cljs.analyzer.analyze_seq.cljs$core$IFn$_invoke$arity$4 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:2196:15)
    at Object.cljs$analyzer$analyze_form [as analyze_form] (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:2294:43)


 Comments   
Comment by Andy Sheldon [ 12/Jul/15 8:43 PM ]

The cljs-1334-for-macro.patch did not fix the issue, so I deleted it. Maybe a problem with recur-frames is more likely.

Comment by Mike Fikes [ 12/Jul/15 9:25 PM ]

I tested with Andy's cljs-1334-for-macro.patch and the issue went away.

I got a different slew of errors that perhaps warrant separate tickets:

cljs-bootstrap.core=> (with-out-str
      (c/emit
        (ensure
          (ana/analyze
            (assoc (ana/empty-env) :context :expr)
             '(for [x [1] y [2]] y))))))

repl:42
throw e__4257__auto__;
      ^
Error: Cannot read property 'cljs$core$IFn$_invoke$arity$2' of undefined
    at new cljs$core$ExceptionInfo (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/core.cljs:9688:9)
    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/core.cljs:9720:14)
    at Function.cljs.analyzer.error.cljs$core$IFn$_invoke$arity$3 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:514:5)
    at Object.cljs$analyzer$macroexpand_1 [as macroexpand_1] (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:2355:52)
    at Function.cljs.analyzer.analyze_seq.cljs$core$IFn$_invoke$arity$4 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:2381:23)
    at Object.cljs$analyzer$analyze_form [as analyze_form] (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:2481:43)
    at Object.cljs$analyzer$analyze_STAR_ [as analyze_STAR_] (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:2504:17)
    at Function.cljs.analyzer.analyze.cljs$core$IFn$_invoke$arity$4 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:2520:11)
    at Function.cljs.analyzer.analyze.cljs$core$IFn$_invoke$arity$3 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:2515:21)
    at Function.cljs.analyzer.analyze.cljs$core$IFn$_invoke$arity$2 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.cljc:2514:16)
Comment by David Nolen [ 13/Jul/15 5:50 AM ]

The ticket and patch needs more information. Currently there's no rationale at all for the change.

Comment by Andy Sheldon [ 15/Jul/15 7:00 AM ]

If you look at a macro expansion in the bootstrap node repl, for the multi-binding for in the bootstrap, you see a

clojure.core/when-first
reference, instead of
cljs.core/when-first
.

Copying the core.cljc as-is and running a modified '(for) test generates the error:

cljs-bootstrap.core=>   (js/eval
    (with-out-str
      (ensure
        (c/emit
          (no-warn
            (ana/analyze
              (assoc (ana/empty-env) :context :expr)
              `(for [x# [1 2 3] y# [2 3 4]] 1)))))))

repl:48
throw e__4275__auto__;
      ^
Error: Can't recur here

Modifying the copied resources/cljs/core.cljc file, changing

defmacro for
to generate
(when-first [~bind ~gxs])
instead of
(core/when-first [~bind ~gxs])
, I can get a result:

cljs-bootstrap.core=>   (js/eval
    (with-out-str
      (ensure
        (c/emit
          (no-warn
            (ana/analyze
              (assoc (ana/empty-env) :context :expr)
              `(for [x# [1 2 3] y# [2 3 4]] x#)))))))
(1 1 1 2 2 2 3 3 3)
Comment by Andy Sheldon [ 15/Jul/15 7:02 AM ]

Attaching patch for core.cljc defmacro for

Comment by Mike Fikes [ 15/Jul/15 7:17 AM ]

I can confirm that cljs-1334-for-macro-v2.patch works for me downstream for ClojureScript JS (via Replete) and ClojureScript JVM (via Ambly) for the form (for [x [1] y [2]] y).

I can also confirm that the ClojureScript unit tests pass for me for V8, SpiderMonkey and JavaScriptCore (I don't have Nashorn configured).

Comment by David Nolen [ 15/Jul/15 11:29 AM ]

fixed https://github.com/clojure/clojurescript/commit/da2e53800fb3aa4a7bf937843035e8ff1dfbbaf5





[CLJS-1333] keyword reader macro meta in quoted vector Created: 11/Jul/15  Updated: 14/Jul/15  Resolved: 14/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Mike Fikes
Resolution: Completed Votes: 0
Labels: None
Environment:

shipping node REPL


Attachments: Text File CLJS-1333.patch    
Patch: Code and Test

 Description   

Node ClojureScript REPL:

cljs.user=> (meta (first '[^:m x]))
nil

Clojure REPL:

user=> (meta (first '[^:m x]))
{:m true}

If you enable :repo-verbose true,

cljs.user=> (meta (first '[^:m x]))
cljs.core.meta.call(null,cljs.core.first.call(null,new cljs.core.PersistentVector(null, 1, 5, cljs.core.PersistentVector.EMPTY_NODE, [new cljs.core.Symbol(null,"x","x",-555367584,null)], null)))
nil

If you start up a Clojure REPL, this appears to not be a problem with the reader used by the ClojureScript Node REPL

user=> (require 'clojure.tools.reader)
nil
user=> (meta (last (last (clojure.tools.reader/read-string "'[^:m x]"))))
{:m true}

See also CLJS-1325 where this appears to affect bootstrapped ClojureScript without the issue being in cljs.tools.reader, as far as I can tell.



 Comments   
Comment by Mike Fikes [ 12/Jul/15 2:09 PM ]

The attached patch addresses the issue.

I've additionally confirmed that it addresses the issue in CLJS-1325.

Comment by Mike Fikes [ 14/Jul/15 8:31 AM ]

I've additionally confirmed that this patch works in bootstrapped ClojureScript (using downstream Replete REPL).

Comment by David Nolen [ 14/Jul/15 10:43 AM ]

fixed https://github.com/clojure/clojurescript/commit/be0a8a801234e779640fdeaf255b329159df9040





[CLJS-1332] investigate inlining version of cljs.core/get Created: 10/Jul/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None





[CLJS-1331] Regex literal emits invalid JS Created: 08/Jul/15  Updated: 13/Jul/15  Resolved: 13/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Mike Fikes
Resolution: Completed Votes: 0
Labels: bootstrap
Environment:

https://github.com/swannodette/cljs-bootstrap


Attachments: Text File CLJS-1331.patch    

 Description   
(with-out-str
  (c/emit
    (ensure
      (ana/analyze
        (assoc (ana/empty-env) :context :expr)
        '#"foo"))))) 
"/\\\\/foo\\\\//"

Non-bootstrap, for this case, using :repo-verbose emits \foo.

If you take this JS and eval it in Node you'll get

> /\\\\/foo\\\\//
SyntaxError: Unexpected token ILLEGAL
    at Object.exports.createScript (vm.js:44:10)
    at REPLServer.defaultEval (repl.js:117:23)
    at bound (domain.js:254:14)
    at REPLServer.runBound [as eval] (domain.js:267:12)
    at REPLServer.<anonymous> (repl.js:279:12)
    at REPLServer.emit (events.js:107:17)
    at REPLServer.Interface._onLine (readline.js:214:10)
    at REPLServer.Interface._line (readline.js:553:8)
    at REPLServer.Interface._ttyWrite (readline.js:830:14)
    at ReadStream.onkeypress (readline.js:109:10)

and in JSC

>>> /\\\\/foo\\\\//
Invalid escape in identifier: '\':1


 Comments   
Comment by Mike Fikes [ 12/Jul/15 7:03 PM ]

The attached patch passes manually-run regex tests taken from the test suite plus some additional tests I found online for JavaScript regexs (in particular, those involving the backslash character).

Comment by David Nolen [ 13/Jul/15 5:58 AM ]

fixed https://github.com/clojure/clojurescript/commit/6920b62be188809fcab97a593415cf0a72a39baa





[CLJS-1330] .toString on int needs parens and has dollar-sign Created: 08/Jul/15  Updated: 08/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bootstrap
Environment:

https://github.com/swannodette/cljs-bootstrap



 Description   
cljs-bootstrap.core=> (with-out-str
      (c/emit
        (ensure
          (ana/analyze
            (assoc (ana/empty-env) :context :expr)
            '(.toString 1)))))) 
"1.toString$()"





[CLJS-1329] Support for reading #js tagged literals in bootstrap Created: 07/Jul/15  Updated: 08/Jul/15  Resolved: 08/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: bootstrap

Attachments: Text File CLJS-1329-v1.patch    

 Description   

If you attempt to analyze a form like {{# [1 2]}} then cljs.analyzer/analyze-form, when in :cljs mode, lacks a cond case for JSValue, and it will drop through to the default, treating the form as a constant.

I haven't yet sorted out how to reproduce this with https://github.com/swannodette/cljs-bootstrap. My attempt so far is when I get to

cljs-bootstrap.core=> (r/read-string "#js [1 2]")    
Error: No reader function for tag js
...

Joel Martin's bootstrap Node and Replete, you will see the compiler attempting to handle the :constant AST:

cljs-bootstrap.repl> #js [1 2]
Error: No method in multimethod 'cljs.compiler/emit-constant' for dispatch value: function (val) {
  this.val = val;
}


 Comments   
Comment by Mike Fikes [ 07/Jul/15 10:43 PM ]

The attached CLJS-1329-v1.patch appears to address the issue, but with two notes:

It uses :require instead of :import to get the JSValue tagged literal symbol for :cljs (not sure if this is the right approach).

It appears to emit the correct JS, and works in Replete, but for the map form, say if you issue

#js {:a 1}

then this JavaScript is emitted:

{"a": 1}

and then something will then indicate

Unexpected token ':'. Parse error.

Also, for both the map and vector forms, the individual values don't end up being surrounded with parenthesis like they do on ClojureScript JVM.

So, at best, this patch is a first stab, perhaps suitable for inspiration or refinement.

Comment by David Nolen [ 08/Jul/15 11:55 AM ]

fixed https://github.com/clojure/clojurescript/commit/2924c4880c05208beb0f321e8e4e63b4cb1c45f3





[CLJS-1328] Support defrecord reader tags Created: 04/Jul/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Enhancement Priority: Major
Reporter: Herwig Hochleitner Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: reader, readertags


 Description   

Currently, defrecord instances print similar to how they do in clojure

> (pr-str (garden.units/px 5))
#garden.types.CSSUnit{:unit :px, :magnitude 5}

This representation cannot be read by the compiler, nor at runtime by cljs.reader/read-string

> #garden.types.CSSUnit{:unit :px, :magnitude 5}
clojure.lang.ExceptionInfo: garden.types.CSSUnit {:type :reader-exception, :line 1, :column 22, :file "NO_SOURCE_FILE"}
...
> (cljs.reader/read-string "#garden.types.CSSUnit{:unit :px, :magnitude 5}")
#<Error: Could not find tag parser for garden.types.CSSUnit in ("inst" "uuid" "queue" "js")>
...

Analysis

The two requirements - using record literals in cljs source code and supporting runtime reading - can be addressed by using the analyzer to find defrecords and registering them with the two respective reader libraries.

Record literals

Since clojurescript reads and compiles a file at a time, clojure's behavior for literals is hard to exactly mimic. That is, to be able to use the literal in the same file where the record is defined.
A reasonable compromise might be to update the record tag table after each file has been analyzed. Thus the literal form of a record could be used only in requiring files.

EDIT: Record literals can also go into the constant pool

cljs.reader

To play well with minification, the ^:export annotation could be reused on defrecords, to publish the corresponding reader tag to cljs.reader.

Related Tickets



 Comments   
Comment by David Nolen [ 08/Jul/15 12:00 PM ]

It's preferred that we avoid exporting. Instead we can adopt the same approach as the constant literal optimization for keywords under advanced optimizations. We can make a lookup table (which won't pollute the global namespace like exporting does) which maps a string to its type.

I'm all for this enhancement.





[CLJS-1327] Support Transit JSON for analysis caches Created: 03/Jul/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Task Priority: Minor
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

A significant amount of time is spent reading caches both during cold builds and REPL start. Switching to Transit for the analysis cache format should deliver a very large performance boost. Having a direct dep on Transit is undesirable since it is a critical part of existing applications. Instead we could allow users to provide analysis cache encoder/decoder functions to the compiler options. This does mean we cannot use the AoTed analysis for cljs.core if these are provided.






[CLJS-1326] In bootstrapped cljs, read-number of "0" gives "invalid number format" Created: 03/Jul/15  Updated: 12/Jul/15  Resolved: 03/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Joel Martin Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: bootstrap
Environment:

cljs-bootstrap REPL (https://github.com/kanaka/cljs-bootstrap)



 Description   

tools.reader/read-number (https://github.com/swannodette/tools.reader) of "0" throws an error. The same for "1" works fine.

cljs-bootstrap.repl> 0
Error: Invalid number format [0]
    at new cljs$core$ExceptionInfo (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:33157:10)
    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:33219:9)
    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$2 (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:33215:26)
    at cljs$core$ex_info (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:33201:26)
    at Function.cljs.tools.reader.reader_types.reader_error.cljs$core$IFn$_invoke$arity$variadic (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/tools/reader/reader_types.js:802:25)
    at cljs$tools$reader$reader_types$reader_error (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/tools/reader/reader_types.js:798:52)
    at cljs$tools$reader$read_number (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/tools/reader.js:446:52)
    at /home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/tools/reader.js:1550:38
    at cljs$tools$reader$reader_types$log_source (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/tools/reader/reader_types.js:873:16)
    at cljs$tools$reader$target (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/tools/reader.js:1528:50)

This is because reader/read-number has:

(or (match-number s) (reader-error rdr "Invalid number format [" s "]")))

which compiled to this JS:

var or__4073__auto__ = cljs.tools.reader.impl.commons.match_number.call(null,s);
if(or__4073__auto__){
return or__4073__auto__;
} else {
return cljs.tools.reader.reader_types.reader_error.call(null,rdr,"Invalid number format [",s,"]");
}

Since match_number returns a JS number, or_4073auto_ is 0, therefore falsey.



 Comments   
Comment by Joel Martin [ 03/Jul/15 9:31 AM ]

FYI, to reproduce, run this in https://github.com/kanaka/cljs-bootstrap

lein run -m clojure.main script/build.clj
node repl.js
cljs-bootstrap.repl> 0
Error: Invalid number format [0]
...
Comment by David Nolen [ 03/Jul/15 2:55 PM ]

This ticket doesn't have nearly enough information. I checked the output of tools.reader and I don't see this generated code at all. The test is wrapped in the required call to truth_.

Comment by Mike Fikes [ 12/Jul/15 7:10 AM ]

FWIW, if this helps anyone else who might encounter this:

In Replete, this was occurring and was address by revising its build to compile macros after the main Replete namespace. The root cause was not determined, but this was tried based on a theory that *unchecked-if* was being set! but somehow left true.

Reference Replete commit: https://github.com/mfikes/replete/commit/e21c59b5f595fb8a10c25cae98a67dee7d0db013





[CLJS-1325] defrecord broken in bootstrapped cljs (error during set!) Created: 03/Jul/15  Updated: 14/Jul/15  Resolved: 14/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Joel Martin Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: bootstrap
Environment:

cljs-bootstrap node.js RELP (https://github.com/kanaka/cljs-bootstrap)


Attachments: Text File CLJS-1325.patch    

 Description   

This is a follow-on to http://dev.clojure.org/jira/browse/CLJS-1321 for getting defrecord to work in the bootstrap node REPL.

cljs-bootstrap.repl> (defprotocol IFoo (foo [this]))
nil
cljs-bootstrap.repl> (defrecord Baz [b] IFoo (foo [this] (prn "some baz:" b)))
Error: Can't set! local var or non-mutable field
    at new cljs$core$ExceptionInfo (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:33157:10)
    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:33219:9)
    at cljs$core$ex_info (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:33205:26)
    at Function.cljs.analyzer.error.cljs$core$IFn$_invoke$arity$3 (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:699:26)
    at cljs$analyzer$error (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:685:28)
    at Function.cljs.analyzer.error.cljs$core$IFn$_invoke$arity$2 (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:695:28)
    at cljs$analyzer$error (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:681:28)
    at /home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:2311:27
    at /home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:2315:3
    at cljs.core.MultiFn.call.G__11387__6 (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:31419:149)

The same as above but with debug added to the analyzer set! method to print the form:

cljs-bootstrap.repl> (defprotocol IFoo (foo [this]))
DEBUG set! p__9852: (set! *unchecked-if* true)
DEBUG set! p__9852: (set! *unchecked-if* false)
nil
cljs-bootstrap.repl> (defrecord Baz [b] IFoo (foo [this] (prn "some baz:" b)))
DEBUG set! p__9852: (set! (.. Baz -prototype -cljs$core$ILookup$-lookup$arity$2) (cljs.core$macros/fn ([this__7850__auto__ k__7851__auto__] (cljs.core$macros/this-as this__7850__auto__ (cljs.core/-lookup this__7850__auto__ k__7851__auto__ nil)))))
DEBUG set! p__9852: (set! (.. Baz -prototype -cljs$core$ICollection$-conj$arity$2) (cljs.core$macros/fn ([this__7855__auto__ entry__7856__auto__] (cljs.core$macros/this-as this__7855__auto__ (if (cljs.core/vector? entry__7856__auto__) (cljs.core/-assoc this__7855__auto__ (cljs.core/-nth entry__7856__auto__ 0) (cljs.core/-nth entry__7856__auto__ 1)) (cljs.core/reduce cljs.core/-conj this__7855__auto__ entry__7856__auto__))))))
DEBUG set! p__9852: (set! (.. Baz -prototype -cljs$core$ILookup$-lookup$arity$3) (cljs.core$macros/fn ([this__7852__auto__ k25 else__7853__auto__] (cljs.core$macros/this-as this__7852__auto__ (cljs.core$macros/case k25 :b b (cljs.core/get __extmap k25 else__7853__auto__))))))
DEBUG set! p__9852: (set! (.. Baz -prototype -cljs$core$IPrintWithWriter$-pr-writer$arity$3) (cljs.core$macros/fn ([this__7864__auto__ writer__7865__auto__ opts__7866__auto__] (cljs.core$macros/this-as this__7864__auto__ (cljs.core$macros/let [pr-pair__7867__auto__ (cljs.core$macros/fn [keyval__7868__auto__] (cljs.core/pr-sequential-writer writer__7865__auto__ cljs.core/pr-writer "" " " "" opts__7866__auto__ keyval__7868__auto__))] (cljs.core/pr-sequential-writer writer__7865__auto__ pr-pair__7867__auto__ "#cljs-bootstrap.repl.Baz{" ", " "}" opts__7866__auto__ (cljs.core/concat [(cljs.core/vector :b b)] __extmap)))))))
DEBUG set! p__9852: (set! (.. Baz -prototype -cljs$core$IMeta$-meta$arity$1) (cljs.core$macros/fn ([this__7848__auto__] (cljs.core$macros/this-as this__7848__auto__ __meta))))
DEBUG set! p__9852: (set! (.. Baz -prototype -cljs$core$ICloneable$-clone$arity$1) (cljs.core$macros/fn ([this__7844__auto__] (cljs.core$macros/this-as this__7844__auto__ (new Baz b __meta __extmap __hash)))))
DEBUG set! p__9852: (set! (.. Baz -prototype -cljs$core$ICounted$-count$arity$1) (cljs.core$macros/fn ([this__7854__auto__] (cljs.core$macros/this-as this__7854__auto__ (cljs.core$macros/+ 1 (cljs.core/count __extmap))))))
DEBUG set! p__9852: (set! (.. Baz -prototype -cljs$core$IHash$-hash$arity$1) (cljs.core$macros/fn ([this__7845__auto__] (cljs.core$macros/this-as this__7845__auto__ (cljs.core$macros/caching-hash this__7845__auto__ hash-imap __hash)))))
DEBUG set! p__9852: (set! __hash h__7674__auto__)
Error: Can't set! local var or non-mutable field
    at new cljs$core$ExceptionInfo (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:33157:10)
    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:33219:9)
    at cljs$core$ex_info (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:33205:26)
    at Function.cljs.analyzer.error.cljs$core$IFn$_invoke$arity$3 (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:699:26)
    at cljs$analyzer$error (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:685:28)
    at Function.cljs.analyzer.error.cljs$core$IFn$_invoke$arity$2 (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:695:28)
    at cljs$analyzer$error (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:681:28)
    at /home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:2312:27
    at /home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/analyzer.js:2316:3
    at cljs.core.MultiFn.call.G__11387__6 (/home/joelm/scratch/cljs-bootstrap/.cljs_bootstrap/cljs/core.js:31419:149)


 Comments   
Comment by Joel Martin [ 03/Jul/15 9:31 AM ]

FYI, to reproduce, run this in https://github.com/kanaka/cljs-bootstrap

lein run -m clojure.main script/build.clj
node repl.js
cljs-bootstrap.repl> (defprotocol IFoo (foo [this]))
cljs-bootstrap.repl> (defrecord Baz [b] IFoo (foo [this] (prn "some baz:" b)))
Error: Can't set! local var or non-mutable field
...
Comment by Mike Fikes [ 08/Jul/15 1:23 PM ]

To reproduce with https://github.com/swannodette/cljs-bootstrap

cljs-bootstrap.core=> (with-out-str
      (c/emit
        (ensure
          (ana/analyze
            (assoc (ana/empty-env) :context :expr)
             '(defrecord R []))))))

repl:42
throw e__4277__auto__;
      ^
Error: Can't set! local var or non-mutable field
    at new cljs$core$ExceptionInfo (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/core.js:32007:10)
    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/core.js:32084:9)
    at Function.cljs.analyzer.error.cljs$core$IFn$_invoke$arity$3 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.js:715:26)
    at Function.cljs.analyzer.error.cljs$core$IFn$_invoke$arity$2 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.js:711:28)
    at /Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.js:2411:27
    at /Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.js:2415:3
    at cljs.core.MultiFn.cljs$core$IFn$_invoke$arity$5 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/core.js:31494:114)
    at Object.cljs$analyzer$analyze_seq_STAR_ [as analyze_seq_STAR_] (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.js:3882:81)
    at Function.cljs.analyzer.analyze_seq.cljs$core$IFn$_invoke$arity$4 (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.js:3925:26)
    at Object.cljs$analyzer$analyze_form [as analyze_form] (/Users/mfikes/Projects/cljs-bootstrap/.cljs_node_repl/cljs/analyzer.js:4069:34)
Comment by David Nolen [ 09/Jul/15 12:16 PM ]

The thing to investigate here is why the compiler thinks it's setting a local. If you're using cljs-bootstrap make sure to run lein npm install to get source map support. It makes it pretty easy to figure out what's going wrong in the analyzer. It's what I've been using to pinpoint bugs.

Comment by Mike Fikes [ 09/Jul/15 5:34 PM ]

Results of partial investigation: If you macroexpand-1 the (defrecord R []) form, and then take those results and attempt to evaluate them, you will get the error regarding set!. Then eliminating sub-forms from that expansion, you can reduce it down to

(defrecord* R [] nil (extend-type R IHash (-hash [this] (caching-hash this hash-imap __hash))))

So, there is a set! in the expansion of caching-hash, which would mutate the __hash field

https://github.com/clojure/clojurescript/blob/6b590f2fdf898e94a65153f8059ebdf0e3ec0952/src/main/clojure/cljs/core.cljc#L1592

which is set to be ^:mutable

https://github.com/clojure/clojurescript/blob/6b590f2fdf898e94a65153f8059ebdf0e3ec0952/src/main/clojure/cljs/core.cljc#L1583

A theory would be that either the meta is not conveyed properly, or, perhaps this is simply going down the wrong path, with perhaps a limitation of macroexpand-1 not being capable of processing meta, in which case the above analysis is wrong.

Comment by David Nolen [ 10/Jul/15 9:01 AM ]

The places to look now are much narrower. Something is wrong with parse-type or parse 'set! cases in cljs.analyzer. I would add some printlns using :cljs reader conditionals to make it more readily apparent what is going on. Another option would be to use the browser based setup in cljs-bootstrap and set some breakpoints.

Comment by Mike Fikes [ 11/Jul/15 6:19 PM ]

If you examine the local in parse 'set!, you will see

{:name __hash, :field true, :column nil, :unsynchronized-mutable nil, :line nil, :tag nil, :mutable nil, :volatile-mutable nil, :shadow nil}

Experimenting with the (released) Node.js REPL, shows that ^:mutable doesn't work as intended in ClojureScript within a quoted vector:

cljs.user=> (map meta '[x y ^:mutable z])
(nil nil nil)

But, this can be worked around:

cljs.user=> (map meta ['x 'y (with-meta 'z {:mutable true})])
(nil nil {:mutable true})

Both of the above work in Clojure, while only the second evidently works in ClojureScript.

So this patch fixes the problem by employing this technique. (Perhaps there is a deeper ClojureScript bug; if so, it is not a regression since 0.0-3308.)

With this, defrecord doesn't quite work fully. (Separate tickets can be opened for it.) But, the mutability of the __hash field is properly established.

Comment by Mike Fikes [ 11/Jul/15 6:43 PM ]

The attached patch is arguably working around something that should work (even in 0.0-3308), and perhaps it was only just now discovered via the bootstrap effort.

Is it a defect in cljs.tools.reader? This was done with the version being used within https://github.com/swannodette/cljs-bootstrap

cljs-bootstrap.core=> (meta (last (last (cljs.tools.reader/read-string "'[x y ^:mutable z]"))))
{:mutable true}
Comment by Mike Fikes [ 11/Jul/15 7:43 PM ]

See CLJS-1333. Perhaps this is a defect in ClojureScript.

Comment by David Nolen [ 14/Jul/15 10:43 AM ]

fixed https://github.com/clojure/clojurescript/commit/be0a8a801234e779640fdeaf255b329159df9040





[CLJS-1324] Compiler fails to raise warning/error when invoking a keyword without arguments Created: 02/Jul/15  Updated: 28/Jul/15  Resolved: 28/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Sean Grove Assignee: Sean Grove
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File cljs_1324.patch     File warn_on_argumentless_keywords.diff    

 Description   

Invoking a keyword with no arguments doesn't raise a warning/error in the compiler, but it likely should, e.g `(:any-key)`

It raises an error in the browser: "Uncaught TypeError: (intermediate value).cljs$core$IFn$_invoke$arity$0 is not a function".



 Comments   
Comment by Sean Grove [ 17/Jul/15 11:50 AM ]

Patch for fix + test attached

Comment by David Nolen [ 17/Jul/15 12:20 PM ]

The patch is not correctly formatted. Please make sure to follow the instructions on creating patches - https://github.com/clojure/clojurescript/wiki/Patches

Comment by David Nolen [ 28/Jul/15 6:04 AM ]

fixed https://github.com/clojure/clojurescript/commits/master





[CLJS-1323] possible to reload cljs.core in browser REPL Created: 01/Jul/15  Updated: 02/Jul/15  Resolved: 02/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Not Reproducible Votes: 0
Labels: None


 Description   

Accidentally doing so will wreck havoc on the browser REPL as all the core types will get redefined. For some reason cljs.core is the only namespace that is not on the goog.dependencies_.written list, once as the relative path and once again as the absolute path. Uncovered while attempting to test the bootstrap support in browser environments.



 Comments   
Comment by David Nolen [ 02/Jul/15 6:02 PM ]

Misinterpreted the issue. Was loading the macros ns which shares the same name. Needed to rewrite in to a macro ns instead.





[CLJS-1322] Investigate why Babel cannot load into JDK 8 Nashorn Created: 01/Jul/15  Updated: 01/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: GSoC
Fix Version/s: None

Type: Task Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

It appears neither the developer browser.js file nor the browser.min.js file can be loaded into Nashorn due to a method size limit exception. The code appears to originate around the lodash include. This may be a red herring but this is a good starting point for investigation.






[CLJS-1321] defrecord broken in bootstrapped cljs Created: 01/Jul/15  Updated: 02/Jul/15  Resolved: 02/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Joel Martin Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: bootstrap
Environment:

cljs-bootstrap REPL (https://github.com/swannodette/cljs-bootstrap)



 Description   

First problem that I run into is that emit-defrecord makes use of .getNamespace and .getName on rname. That should probably be (namespace rname) and (name rname). After that change is made the next error is "Can't set! local var or non-mutable field" somewhere in defrecord. Not sure what the cause of that one is.



 Comments   
Comment by David Nolen [ 02/Jul/15 6:03 PM ]

fixed https://github.com/clojure/clojurescript/commit/8a5023b849cfc509931b3ff509a9f7ee48dd03ec

Comment by David Nolen [ 02/Jul/15 6:04 PM ]

I did not look into the set! issue. Separate ticket should be opened for that if it persists.

Comment by Mike Fikes [ 02/Jul/15 6:46 PM ]

Confirmed fixed downstream (https://github.com/mfikes/replete/issues/25), apart from other Can't set! local var or non-mutable field error, which needs a separate ticket.





[CLJS-1320] clojure.string/split adds separator matches & failed matches (nil) when the separator is a regex with alternation Created: 26/Jun/15  Updated: 27/Jun/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: lvh Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

I want to split a string on "; ", and optionally discard a final ";". So, I tried:

(clojure.string/split "ab; ab;" #"(; )|(;$)")

In Clojure, this does what I want:

["ab" "ab"]

In ClojureScript, I get:

["ab" "; " nil "ab" nil ";"]

I'm not sure to what extent this is a platform distinction and to what extent it's a bug. Returning nils and seperators from clojure.string/split's output seems like it's against string.split's contract?






[CLJS-1319] Cannot locate module namespace when filename contains dash Created: 22/Jun/15  Updated: 24/Jun/15  Resolved: 24/Jun/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: GSoC
Fix Version/s: GSoC

Type: Defect Priority: Major
Reporter: Maria Geller Assignee: Maria Geller
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1319.patch    
Patch: Code

 Description   

When the filename contains a dash, for example foo-bar, the compiler can't find the namespace for the module, e.g.

No such namespace: module$libs$foo_bar, could not locate module$libs$foo_bar.cljs, module$libs$foo_bar.cljc, or Closure namespace "module$libs$foo_bar" at line 1 src/hello_world/core.cljs {:file "src/hello_world/core.cljs", :line 1, :column 1, :tag :cljs/analysis-error}



 Comments   
Comment by Maria Geller [ 22/Jun/15 5:04 PM ]

Attached a fix for this. The problem was, that we didn't munge the new module-name that is generated by the Google Closure compiler, meaning we didn't replace underscores with dashes.

Comment by David Nolen [ 24/Jun/15 5:43 AM ]

fixed https://github.com/clojure/clojurescript/commit/73117d5a451bca5ab1a5aa8c7fa8cbce67ab98d0





[CLJS-1318] Fix typo in documentation of `specify` Created: 22/Jun/15  Updated: 22/Jun/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Yehonathan Sharvit Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File patch.txt    
Patch: Code

 Description   

Fix typo in documentation of `specify`



 Comments   
Comment by Yehonathan Sharvit [ 22/Jun/15 6:27 AM ]

here is a patch that fixes the doc of `specify`





[CLJS-1317] Incremental compilation issues for :nodejs target Created: 21/Jun/15  Updated: 21/Jun/15  Resolved: 21/Jun/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

When using the :nodejs target, files which do not require recompilation trigger recompilation anyway. This is simple to replicate by making a trivial Node.js ClojureScript project which simply requires pprint for example and supplying a watch script and running it.



 Comments   
Comment by David Nolen [ 21/Jun/15 4:59 PM ]

The issue is that under :nodejs cljs.core will get recompiled trigger recompilation of dependent namespaces which includes cljs.pprint.

Comment by David Nolen [ 21/Jun/15 6:16 PM ]

fixed https://github.com/clojure/clojurescript/commit/e1e190569f8588fa6e1e30c0e4a4686d08b57eed





[CLJS-1316] let does not detect invalid binding vector when it contains destructuring Created: 19/Jun/15  Updated: 30/Jul/15  Resolved: 30/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: Justin Glenn Smith Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1319-29-July-15.patch    

 Description   

The presence of destructuring in a `let` binding vector prevents detection of basic errors.

cljs.user=> *clojurescript-version*
"0.0-3308"
cljs.user=> (let [{a :a} {:a 0} b] a)
0
cljs.user=> (let [a 0 b] a)
clojure.lang.ExceptionInfo: bindings must be vector of even number of elements at line 1 <cljs repl> {:file "<cljs repl>", :line 1, :column 1, :tag :cljs/analysis-error}

David Nolen mentions that this looks like something busted with the cljs.core/assert-args macro



 Comments   
Comment by Samuel Miller [ 29/Jul/15 8:27 PM ]

I have a solution for this but I don't completely understand why the solution I have works.

In core.cljc you have assert-args(used by let, loop, for, doseq) and core/assert-args(used by if-let, when-first, when-let, if-some...). This problem also exist in loop but not in for and doseq. This is because the marco's arguments are [fnname & pairs] and when you use non-core assert-args you need to supply the fnname. I am not sure why this exploded only with destructing... Also not sure where to add tests for this.

Comment by David Nolen [ 30/Jul/15 3:13 PM ]

fixed https://github.com/clojure/clojurescript/commit/32e7559afab7b8b6620481ef44932697d3dd81d4





[CLJS-1315] Warning on Google Closure enum property access with / Created: 18/Jun/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Edge case in / usage, EventType/CLICK does not trigger a warning. Foo/bar always means that Foo is a namespace, it cannot be used for the static field access pattern common in Java as there's no reflection information in JavaScript to determine this.






[CLJS-1314] Node REPL can't load :libs Created: 17/Jun/15  Updated: 18/Jun/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Node REPL with the latest CommonJS loading impl


Attachments: Text File 0001-Illustration-of-fix.patch    

 Description   

I've been trying the CommonJS support and have been failing to get it to work in Node, and likewise so has Maria Neise. This is in the case of invoking build prior to launching the REPL as well as trying a new suggestion in CLJS-1313.

I cranked up the verbosity to see what is going on and ultimately hit upon the idea that

goog.require('module$libs$german');

isn't going to work in Node and instead needs the same alternative logic that is employed for :foreign-libs in cljs.compiler/load-libs, in particular this needs to be emitted.

cljs.core.load_file("out/german.js");

I hacked the code a bit and got the "german" CommonJS module to load in Node and be useable:

To quit, type: :cljs/quit
cljs.user=> (require '[german :refer [hello]])
Compiling out/cljs/core.cljs
Using cached cljs.core out/cljs/core.cljs
Compiling out/cljs/core.cljs
Using cached cljs.core out/cljs/core.cljs
goog.provide('cljs.user');
goog.require('cljs.core');
goog.require('cljs.repl');
goog.require('cljs.pprint');
cljs.core.load_file("out/german.js");

nil
cljs.user=> (hello)
module$libs$german.hello.call(null)
"Hallo"

The attached patch illustrates the hack to get the above to work. The real fix would be a generalization of this.



 Comments   
Comment by Mike Fikes [ 17/Jun/15 8:44 PM ]

(Sorry for the overly generalized ticket title; it should probably be weakened to just talk about foreign libs that have been converted to native libs.)

Comment by Mike Fikes [ 17/Jun/15 8:59 PM ]

Reproduction steps (note all of this is also in a repo at https://github.com/mfikes/test-commonjs ):

Set up a node_repl.clj:

(require 'cljs.repl)
(require 'cljs.build.api)
(require 'cljs.repl.node)

(def foreign-libs [{:file "libs/greeting.js"
       :provides ["greeting"]
       :module-type :commonjs}
      {:file "libs/german.js"
       :provides ["german"]
       :module-type :commonjs}])

(cljs.build.api/build "src"
  {:main 'foo.bar
   :output-to "out/main.js"
   :verbose true
   :foreign-libs foreign-libs})

(cljs.repl/repl (cljs.repl.node/repl-env)
  :watch "src"
  :output-dir "out"
  :foreign-libs foreign-libs)

Make a libs directory with german.js:

exports.hello = function() {
    return "Hallo";
};

and greeting.js:

var german = require("german");

exports.hello = function(name) {
    return german.hello() + ", " + name;
};

create a src/foo/bar.cljs with

(ns foo.bar
  (:require [greeting :refer [hello]]))

(enable-console-print!)

(println (hello "Welt!"))

Make a QuickStart cljs.jar uberjar and place it at root of tree and then

rlwrap java -cp cljs.jar:src clojure.main node_repl.clj

followed by

(require 'foo.bar)

You should see:

../out/foo/bar.js:6
cljs.core.println.call(null,module$libs$greeting.hello.call(null,"Welt!"));
                                                      ^
TypeError: Cannot read property 'call' of undefined
    at Object.<anonymous> (/Users/mfikes/Projects/test-commonjs/out/foo/bar.js:6:55)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Module.require (module.js:365:17)
    at require (module.js:384:17)
    at global.CLOSURE_IMPORT_SCRIPT (repl:75:16)
    at Object.goog.require (repl:19:60)
    at repl:5:6
Comment by Mike Fikes [ 17/Jun/15 9:29 PM ]

Another comment: My "hack" works, but to be honest, I don't appreciate why the code doesn't work without the hack. And I couldn't defend it if you asked me to. Node can evidently load Closure modules that were produced by CLJS, so why would they fail for Closure modules produced by CommonJS processing? I bet there is more behind this and my hack may be papering over some deeper more fundamental problem.

For reference, in Node, my :js-dependency-index has

{nil {:requires [], :provides ["module$libs$german"], :url #object[java.net.URL 0x37d3d232 "file:/Users/mfikes/Projects/test-commonjs/out/german.js"], :closure-lib true, :lib-path "out/german.js"}

while in Ambly, the same has

{nil {:requires [], :provides ["module$libs$german"], :url #object[java.net.URL 0x34652065 "file:/Volumes/Ambly-81C53995/german.js"], :closure-lib true, :lib-path "/Volumes/Ambly-81C53995/german.js"}

(To clarfy, the above two :js-dependency-index bits are only part of the index... there is also all of the normal goog stuff.)





[CLJS-1313] REPL support for libs compiler opts Created: 17/Jun/15  Updated: 17/Jun/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File CLJS-1313-v1.patch    

 Description   

Today, module processing and the lib dependency index setup occurs only when cljs.closure/build is invoked. This ticket asks for the same setup to occur if either :libs or :foreign-libs options are passed when a REPL is launched (without an explicit build step occurring first, as is done in the Quick Start examples involving cljs.repl/repl).

An example:

(cljs.repl/repl (cljs.repl.node/repl-env)
  :foreign-libs [{:file "libs/greeting.js"
                  :provides ["greeting"]
                  :module-type :commonjs}
                 {:file "libs/german.js"
                  :provides ["german"]
                  :module-type :commonjs}])

The above would be sufficient to cause, for example, CommonJS module processing to occur, and the results to be available within the REPL.

Additionally, the implementation should defer processing to after REPL -setup has been called, in case the REPL establishes an :output-dir for :merge-opts during -setup, thereby ensuring that any module processing output goes to the correct :output-dir.



 Comments   
Comment by Mike Fikes [ 17/Jun/15 6:51 PM ]

The attached CLJS-1313-v1.patch is working fine for Ambly, but it fails for the Node REPL. Interestingly, Maria Neise was finding that CommonJS processing was not quite working properly under Node, even with an explicit build step, when compared to Nashorn. Apart from general discussion that could be had about suitability of such a patch, there is a specific concern with Node that needs to be sorted.

Comment by Mike Fikes [ 17/Jun/15 8:45 PM ]

So, with further investigation, it looks like the issue with using this patch with Node is actually a separate problem with Node: CLJS-1314

Additionally, I can confirm that the patch functions properly for Nashorn.





[CLJS-1312] JS module support: Properly convert UMD pattern Created: 15/Jun/15  Updated: 22/Jul/15  Due: 21/Aug/15

Status: In Progress
Project: ClojureScript
Component/s: None
Affects Version/s: GSoC
Fix Version/s: GSoC

Type: Enhancement Priority: Major
Reporter: Maria Geller Assignee: Maria Geller
Resolution: Unresolved Votes: 1
Labels: None


 Description   

Many popular libraries use the following or a similar idiom:

if (typeof define == "function" && define.amd) {
    define(function() {
        return greeting;
    });
} else if (typeof module != "undefined" &&
           module.exports) {
    module.exports = greeting;
} else {
    window["greeting"] = greeting;
}

The ProcessCommonJSModules class converts this to the following:

if (typeof define == "function" && define.amd) {
    define(function() {
        return greeting;
    });
} else {
    if (typeof module != "undefined" && module$greeting) {
        module$greeting = greeting;
    } else {
        window["greeting"] = greeting;
    }
}

module will not be defined, so the greeting object will not be assigned to the new module namespace. We need to check with the Google Closure compiler mailing list if we can submit a patch that replaces module so that the condition succeeds.



 Comments   
Comment by Maria Geller [ 15/Jun/15 1:35 PM ]

Asked about this on Google Closure compiler mailing list: https://groups.google.com/forum/#!topic/closure-compiler-discuss/-M1HBUn35fs

Comment by Maria Geller [ 22/Jul/15 8:52 PM ]

PR: https://github.com/google/closure-compiler/pull/1048





[CLJS-1311] Improve error reporting when converting JavaScript modules Created: 15/Jun/15  Updated: 02/Aug/15  Due: 21/Aug/15  Resolved: 02/Aug/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: GSoC
Fix Version/s: GSoC

Type: Enhancement Priority: Major
Reporter: Maria Geller Assignee: Maria Geller
Resolution: Completed Votes: 2
Labels: None

Attachments: Text File CLJS-1311.patch    
Patch: Code

 Description   

When using the Google Closure compiler via the command line and trying to convert a JavaScript module which has trailing commas, the compiler throws a parse error, e.g.:

chance.js:1109: ERROR - Parse error. IE8 (and below) will parse trailing commas in array and object literals incorrectly. If you are targeting newer versions of JS, set the appropriate language_in option.
                        '09' + self.string({ pool: '0123456789', length: 8}),

At the moment, we don't throw any errors when converting a module and an error occurs. Instead, just the following gets emitted by the Google Closure compiler:

goog.provide("module$libs$chance");var module$libs$chance={}

We need to change this behaviour to show the warnings and errors the Google Closure compiler is emitting.



 Comments   
Comment by Kristian Mandrup [ 16/Jun/15 10:53 PM ]

Yes, by default don't convert the CommonJS module, unless perhaps if you set a specific --force compile option.

Comment by Maria Geller [ 01/Aug/15 3:34 PM ]

Show Google Closure compiler warnings when converting JS modules and set :closure-warnings, :closure-extra-annotations and :pretty-print options. We cannot use the make-options functions for this, since it requires an optimizations level. Instead pull options that we want to use into set-options function.

Comment by David Nolen [ 02/Aug/15 8:37 AM ]

fixed https://github.com/clojure/clojurescript/commit/d946a58153ec5132063f1ac29acd8d4bcd1bdeb2





[CLJS-1310] ns libspec error message misses :import Created: 14/Jun/15  Updated: 14/Jul/15  Resolved: 14/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: errormsgs
Environment:

node repl


Attachments: Text File CLJS-1310.patch    
Patch: Code

 Description   

Let's say you misspell :import in an ns form. You will get an error message that doesn't indicate that :import is a supported libspec:

cljs.user=> (ns foo.bar (:impert [goog Timer]))
clojure.lang.ExceptionInfo: Only :refer-clojure, :require, :require-macros, :use and :use-macros libspecs supported at line 1 <cljs repl> {:file "<cljs repl>", :line 1, :column 1, :tag :cljs/analysis-error}
	at clojure.core$ex_info.invoke(core.clj:4591)
	at cljs.analyzer$error.invoke(analyzer.cljc:405)
	at cljs.analyzer$error.invoke(analyzer.cljc:403)
	at cljs.analyzer$eval1819$fn__1821$fn__1825.invoke(analyzer.cljc:1569)
	at clojure.core.protocols$fn__6519.invoke(protocols.clj:148)
	at clojure.core.protocols$fn__6476$G__6471__6485.invoke(protocols.clj:19)
	at clojure.core.protocols$seq_reduce.invoke(protocols.clj:31)
	at clojure.core.protocols$fn__6502.invoke(protocols.clj:81)
	at clojure.core.protocols$fn__6450$G__6445__6463.invoke(protocols.clj:13)
	at clojure.core$reduce.invoke(core.clj:6515)
	at cljs.analyzer$eval1819$fn__1821.invoke(analyzer.cljc:1566)
	at clojure.lang.MultiFn.invoke(MultiFn.java:251)
	at cljs.analyzer$analyze_seq.invoke(analyzer.cljc:1943)
	at cljs.analyzer$analyze$fn__2069.invoke(analyzer.cljc:2035)
	at cljs.analyzer$analyze.invoke(analyzer.cljc:2028)
	at cljs.repl$evaluate_form.invoke(repl.cljc:429)
	at cljs.repl$eval_cljs.invoke(repl.cljc:548)
	at cljs.repl$repl_STAR_$read_eval_print__4305.invoke(repl.cljc:823)
	at cljs.repl$repl_STAR_$fn__4311$fn__4318.invoke(repl.cljc:860)
	at cljs.repl$repl_STAR_$fn__4311.invoke(repl.cljc:859)
	at cljs.compiler$with_core_cljs.invoke(compiler.cljc:982)
	at cljs.repl$repl_STAR_.invoke(repl.cljc:825)
	at cljs.repl$repl.doInvoke(repl.cljc:941)
	at clojure.lang.RestFn.invoke(RestFn.java:410)
	at user$eval4488.invoke(NO_SOURCE_FILE:3)
	at clojure.lang.Compiler.eval(Compiler.java:6792)
	at clojure.lang.Compiler.eval(Compiler.java:6755)
	at clojure.core$eval.invoke(core.clj:3079)
	at clojure.main$eval_opt.invoke(main.clj:289)
	at clojure.main$initialize.invoke(main.clj:308)
	at clojure.main$null_opt.invoke(main.clj:343)
	at clojure.main$main.doInvoke(main.clj:421)
	at clojure.lang.RestFn.invoke(RestFn.java:421)
	at clojure.lang.Var.invoke(Var.java:383)
	at clojure.lang.AFn.applyToHelper(AFn.java:156)
	at clojure.lang.Var.applyTo(Var.java:700)
	at clojure.main.main(main.java:37)


 Comments   
Comment by David Nolen [ 14/Jul/15 5:46 AM ]

fixed https://github.com/clojure/clojurescript/commit/8d53b008cc60c622f6b4280b38dd96fbd1517ace





[CLJS-1309] get-expander declared twice in analyzer impl Created: 14/Jun/15  Updated: 14/Jul/15  Resolved: 14/Jul/15

Status: Resolved
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None
Environment:

N/A


Attachments: Text File CLJS-1309.patch    

 Description   

(declare get-expander) appears twice in analyzer.cljc. Second declare can be removed.



 Comments   
Comment by David Nolen [ 14/Jul/15 5:44 AM ]

fixed https://github.com/clojure/clojurescript/commit/dd6ee009d7e24e4176f18d659bbb19c12914dd64





[CLJS-1308] :analyze-path should be extended to take a vector of paths Created: 11/Jun/15  Updated: 16/Jun/15  Resolved: 16/Jun/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 1
Labels: newbie

Attachments: Text File CLJS-1308.patch    

 Description   

Currently limited to analyzing only a single directory.



 Comments   
Comment by Antony Woods [ 11/Jun/15 9:47 AM ]

Some information about this feature:
http://blog.fikesfarm.com/posts/2015-06-10-analyze-path-ftw.html

Source:
https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/repl.cljc#L742
https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/repl.cljc#L828

Comment by Antony Woods [ 11/Jun/15 9:59 AM ]

Is the desired behavior to take 'either a vector of paths or a single path', or to take 'only a vector'?

Comment by David Nolen [ 11/Jun/15 10:17 AM ]

It needs to be either otherwise it will break existing uses.

Comment by David Nolen [ 16/Jun/15 2:23 PM ]

fixed https://github.com/clojure/clojurescript/commit/06a7944927cb0dee91ea681739fa290d9fb4016b





[CLJS-1307] Doc for ns missing Created: 10/Jun/15  Updated: 11/Jun/15  Resolved: 11/Jun/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None
Environment:

script/noderepljs on OS X


Attachments: Text File CLJS-1307.patch    

 Description   

(doc ns) yields no doc string

$ script/noderepljs 
ClojureScript Node.js REPL server listening on 58122
To quit, type: :cljs/quit
cljs.user=> (doc ns)

nil


 Comments   
Comment by Mike Fikes [ 10/Jun/15 12:06 PM ]

The attached CLJS-1307.patch assumes that ns is a special form in ClojureScript, and takes the current documentation from the Wiki as at least a starting point:

cljs.user=> (doc ns)
-------------------------
ns
   (name docstring? attr-map? references*)
Special Form
  You must currently use the ns form only with the following caveats

    * You must use the :only form of :use
    * :require supports :as and :refer
      - both options can be skipped
      - in this case a symbol can be used as a libspec directly
        - that is, (:require lib.foo) and (:require [lib.foo]) are both
          supported and mean the same thing
      - prefix lists are not supported
    * The only option for :refer-clojure is :exclude
    * :import is available for importing Google Closure classes
      - ClojureScript types and records should be brought in with :use
        or :require :refer, not :import ed
    * Macros are written in Clojure, and are referenced via the new
      :require-macros / :use-macros options to ns
      - :require-macros and :use-macros support the same forms that
        :require and :use do

  Implicit macro loading: If a namespace is required or used, and that
  namespace itself requires or uses macros from its own namespace, then
  the macros will be implicitly required or used using the same
  specifications. This oftentimes leads to simplified library usage,
  such that the consuming namespace need not be concerned about
  explicitly distinguishing between whether certain vars are functions
  or macros.

  Inline macro specification: As a convenience, :require can be given
  either :include-macros true or :refer-macros [syms...]. Both desugar
  into forms which explicitly load the matching Clojure file containing
  macros. (This works independently of whether the namespace being
  required internally requires or uses its own macros.) For example:

  (ns testme.core
  (:require [foo.core :as foo :refer [foo-fn] :include-macros true]
            [woz.core :as woz :refer [woz-fn] :refer-macros [app jx]]))

  is sugar for

  (ns testme.core
  (:require [foo.core :as foo :refer [foo-fn]]
            [woz.core :as woz :refer [woz-fn]])
  (:require-macros [foo.core :as foo]
                   [woz.core :as woz :refer [app jx]]))

  Please see http://clojure.org/special_forms#ns
Comment by David Nolen [ 11/Jun/15 9:20 AM ]

fixed https://github.com/clojure/clojurescript/commit/48d50bfbba31a80586c89916f8c28a4f09481a25





[CLJS-1306] Browser REPL :asset-path with leading slash breaks source map support Created: 09/Jun/15  Updated: 14/Jun/15  Resolved: 14/Jun/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Comments   
Comment by David Nolen [ 14/Jun/15 10:04 AM ]

fixed https://github.com/clojure/clojurescript/commit/3cf3098d7e183a02d290e5b7eaf1f5cca1508ecb





[CLJS-1305] Node.js REPL load-file regression Created: 09/Jun/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Appears to be the same as the one we encountered in browser REPL due to the Closure Library dep bump.






[CLJS-1304] Behavior of clojure.string/replace differs from Clojure Created: 09/Jun/15  Updated: 13/Jun/15

Status: In Progress
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Luke VanderHart Assignee: Andrew Rosa
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File CLJS-1304.patch    

 Description   

When using clojure.string/replace with a function as the replacement value, and using a regular expression with capturing groups, the behavior differs between Clojure and ClojureScript. In Clojure, the replacement fn is passed a tuple of the match and capturing group. In ClojureScript, it is only passed the match value.

In Clojure:

=> (println (str/replace "foobar" #"f(o)o" #(do (println %) "X")))
[foo o]
"Xbar"

In ClojureScript:

=> (println (str/replace "foobar" #"f(o)o" #(do (println %) "X")))
foo
Xbar


 Comments   
Comment by Daniel Woelfel [ 11/Jun/15 3:31 AM ]

If you're looking for a workaround, you can still get the match result from the 2nd arg:

=> (println (clojure.string/replace "foobar" #"f(o)o" (fn [& args] (do (println args) "X"))))
(foo o 0 foobar)
Xbar
Comment by Andrew Rosa [ 13/Jun/15 12:40 PM ]

Implementation and tests for the requested behaviour. Despite of the `vec` not being strictly necessary, I stick with it so the behaviour will be identical on both implementations.

Comment by David Nolen [ 13/Jun/15 5:07 PM ]

Is there any reason here to not just copy the Clojure implementation?

Comment by Andrew Rosa [ 13/Jun/15 5:25 PM ]

Hi David,

Clojure's impl was the first place that I look for, but this feature in special is written against the underlaying Java libraries. You can check it here.

Studying the Clojure implementation I found that there are some of re-* family of functions missing on ClojureScript side, and unfortunately they are heavily inspired on Java's Regex structure (return matchers, find and extract groups). MAYBE we can something like them to ClojureScript, but I don't know the real value there. Anyway, I think that port them or not is subject for another ticket - if you want that I investigate more, I could create it.

Comment by Francis Avila [ 13/Jun/15 5:47 PM ]

I made a proposal some time ago to bring clj and cljs re handling closer together: CLJS-776

Comment by David Nolen [ 13/Jun/15 8:51 PM ]

Andrew, was just looking for rationale. What you've done looks OK to me. People should try the patch and give feedback. Thanks!

Comment by Andrew Rosa [ 13/Jun/15 10:41 PM ]

Hi David, I understand and appreciate your concerns I just want to make clear what I've search and done, sorry if I sound rude - maybe I stepped on my language limitations.

Francis, really this re-* thing is tricky to deal with. I will take a closer look onto your ticket and see if I can add any idea.

Thanks everyone!





[CLJS-1303] runtime namespaces support for cljs.tools.reader Created: 09/Jun/15  Updated: 17/Jul/15  Resolved: 17/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

We should just piggieback on goog.dependencies_. This has all of the known namespaces. We should add the usual namespace helpers ns-map etc. but we should throw if COMPILED is false. This stuff can only work under :optimizations :none.



 Comments   
Comment by David Nolen [ 17/Jul/15 5:40 AM ]

fixed in master





[CLJS-1302] (js/goog.base (js* "this")) no longer works Created: 09/Jun/15  Updated: 01/Aug/15

Status: In Progress
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None


 Description   
(defn Foo
  []
  (goog/base (js* "this")))
(goog/inherits Foo js/Object)

(defn Foo
  []
  (this-as this
    (goog/base this)))
(goog/inherits Foo js/Object)


 Comments   
Comment by David Nolen [ 01/Aug/15 6:12 AM ]

90% sure this is because of the SSA bit for fn invokes under advanced optimizations.





[CLJS-1301] local :foreign-libs are not picked up the first time browser REPL is started Created: 05/Jun/15  Updated: 06/Jun/15  Resolved: 06/Jun/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3308
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

Attempting to use local CodeMirror addons surfaced the issue. After the first REPL run load-file appears to work. However the the first REPL run returns an error from cljs.analyzer/analyze-deps about not being able to find the deps.



 Comments   
Comment by David Nolen [ 06/Jun/15 12:47 PM ]

fixed https://github.com/clojure/clojurescript/commit/b73595e26f3f45f1fd8ab4d97fb3f9ab941ff696





[CLJS-1300] REPLs do no write out updated deps.js when compiling files Created: 05/Jun/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

For example a user may edit a file including a new dependency. This will work at the REPL but if a browser refresh is made the emitted goog.require will fail due to the initial deps.js file being stale.






[CLJS-1299] reader/read-string does not handle \space literal Created: 05/Jun/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: Ray Huang Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

OSX


Attachments: Text File CLJS1299-0001.patch     Text File CLJS1299-0002.patch    

 Description   

I notice that in Clojure Script, it doesn't know how to interpret \space using reader/read-string

In Clojure:

entangle.single=> (pr-str {:foo \space})
    "{:foo \\space}"

Then, attempting to deserialize in ClojureScript:

entangle.client => (reader/read-string "{:foo \\space}")
    #<Error: Map literal must contain an even number of forms>
    Error: Map literal must contain an even number of forms
        at Function.cljs.reader.reader_error.cljs$core$IFn$_invoke$arity$variadic (http://localhost:10000/public/js/out/cljs/reader.js:156:8)
        at cljs$reader$reader_error (http://localhost:10000/public/js/out/cljs/reader.js:152:33)
        at cljs$reader$read_map (http://localhost:10000/public/js/out/cljs/reader.js:436:26)
        at cljs$reader$read (http://localhost:10000/public/js/out/cljs/reader.js:810:34)
        at cljs$reader$read_string (http://localhost:10000/public/js/out/cljs/reader.js:837:25)


 Comments   
Comment by Ray Huang [ 04/Jul/15 11:07 AM ]

I've created a patch to support these literals. This based on the JVM's `CharacterReader` class. I've added a test case as well and it passes all the tests.

Comment by David Nolen [ 08/Jul/15 11:57 AM ]

I reviewed the patch. Please use identical? not = for the char equality tests. Thanks.

Comment by Ray Huang [ 09/Jul/15 3:32 AM ]

Good catch. Thanks, I've attached the 2nd version with the additional fix.





[CLJS-1298] source-on-disk conditional should include :source-url Created: 05/Jun/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: Bruce Hauman Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

All



 Description   

cljs.closure/source-on-disk is conditional on having the IJavaScript having a :source-url. Currently this conditional is exercised after the call to util/ext. But util/ext has a precondition that will fail on a nil :source-url.

Solution: protect util/ext by checking for :source-url before calling util/ext.

(defn source-on-disk
  "Ensure that the given IJavaScript exists on disk in the output directory.
  Return updated IJavaScript with the new location if necessary."
  [opts js]
  (if (write-js? js)
    (write-javascript opts js)
    ;; always copy original ClojureScript sources to the output directory
    ;; when source maps enabled
    (let [out-file (when-let [ns (and (:source-map opts)
                                      (:source-url js) ;;<--- ADD THIS HERE
                                      (first (:provides js)))]
                     (io/file (io/file (util/output-directory opts))
                       (util/ns->relpath ns (util/ext (:source-url js)))))
          source-url (:source-url js)]
      (when (and out-file source-url
                 (or (not (.exists ^File out-file))
                     (> (.lastModified (io/file source-url))
                        (.lastModified out-file))))
        (spit out-file (slurp source-url)))
      js)))

Or some refactoring of the above.



 Comments   
Comment by David Nolen [ 05/Jun/15 2:20 PM ]

In what cases will an IJavaScript not have a :source-url? Just trying to get some context.

Comment by Bruce Hauman [ 05/Jun/15 2:42 PM ]

Good question. When the sources are already output javascript and they have an output dir relative :url but not a :source-url, this doesn't seem like it should happen.

I'm getting a situation like this

:url #object[java.net.URL 0x5f921081 "file:/Users/brucehauman/workspace/temp/hello-world/resources/goog/uri/utils.js"]
:source-url nil

Comment by David Nolen [ 05/Jun/15 2:58 PM ]

Ok that seems like the real underlying issue. Do you have a small reproducer by chance?

Comment by Bruce Hauman [ 05/Jun/15 3:08 PM ]

It seems like its when the :asset-path is "". And :output-dir is at the root of a resource path like :output-dir "resources".





[CLJS-1297] defrecord does not emit IKVReduce protocol Created: 03/Jun/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: Daniel Skarda Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: newbie

Attachments: Text File CLJS-1297-19-July-2015.patch    

 Description   

Records are maps and in Clojure they support reduce-kv (IKVReduce protocol).
This is not true in ClojureScript:

(defrecord Foobar [x y])
 (reduce-kv assoc {} (Foobar. 1 2))

Fails wit Error: No protocol method IKVReduce.-kv-reduce defined for type : [object Object]



 Comments   
Comment by David Nolen [ 03/Jun/15 7:25 PM ]

Just seems like an oversight. Patch welcome, this one is a relatively easy one.

Comment by Daniel Skarda [ 04/Jun/15 2:53 AM ]

OK

I checked Clojure implementation. Records do not implement any reduce protocol on their own. For IKVReduce records use default implementation using reduce and destructuring. Is this approach OK?

Recently Alex Miller implemented many optimizations of reduce protocols in Clojure. Eg range returns an object which implements IReduce protocol so reduce (and transducers in general) can take advantage of it. Any plans for such optimizations in ClojureScript?

;;clojure/src/clj/clojure/core.clj:6523
;;slow path default
clojure.lang.IPersistentMap
(kv-reduce 
  [amap f init]
  (reduce (fn [ret [k v]] (f ret k v)) init amap))
Comment by David Nolen [ 04/Jun/15 9:05 AM ]

Going with the Clojure implementation is fine. Yes all of the optimizations in 1.7.0 are on the table for ClojureScript but these are separate issues from this one.

Comment by Samuel Miller [ 16/Jul/15 10:39 PM ]

Mind if I take this as my first cljs bug? Poking around quickly I think I know what needs to happen.

Comment by David Nolen [ 17/Jul/15 5:21 AM ]

Sure! Have you submitted your CA yet?

Comment by Samuel Miller [ 17/Jul/15 7:13 PM ]

Yes, I did yesterday.

Comment by Samuel Miller [ 20/Jul/15 9:52 PM ]

Here is a potential patch. I implemented a basic IKVreduce based on Daniel Skarda's comment. Note: I am a little fuzzy on macros still so please look over what I have. There is probably a better way. Also added a test for reduce-kv on records.

I ran the test on Linux on V8 and SpiderMonkey. I plan to get JSC and Nashorn working and tested this week but if someone wants to test them out before that would be great.

Comment by Sebastian Bensusan [ 23/Jul/15 6:45 PM ]

Experience report:

I just tested the patch in the Node Repl and it seems to work:

cljs.user=> (defrecord A [a b])
cljs.user/A
cljs.user=> (reduce-kv (fn [m k v] (assoc m k (inc v))) {} (A. 1 2))
{:a 2, :b 3}

and the provided tests passed in Spidermonkey, V8, and Nashorn (I don't have JSC installed).

For completeness: before applying the patch the same code fails with:

Error: No protocol method IKVReduce.-kv-reduce defined for type : [object Object]




[CLJS-1296] browser REPL should queue prints before connection then flush after connection Created: 01/Jun/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

If the page loads and attempts to print before the connection is made the application will unintuitively error out.






[CLJS-1295] Improve doc for instance Created: 01/Jun/15  Updated: 01/Jun/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Trivial
Reporter: Julien Eluard Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File CLJS-1295.patch    

 Description   

Doc for instance? does not reflect argument names.






[CLJS-1294] Macroexpand only accept quoted lists Created: 01/Jun/15  Updated: 14/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Julien Eluard Assignee: Julien Eluard
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File CLJS-1294.patch    

 Description   

In Clojure macroexpand and macroexpand-1 accept any quoted argument while in ClojureScript anything but quoted seq will throw an exception.



 Comments   
Comment by Julien Eluard [ 01/Jun/15 2:16 PM ]

In Clojure some special forms are handled specifically i.e. (macroexpand '(Boolean true)) => (new Boolean true).

I am not sure if/how it applies to ClojureScript.

Comment by David Nolen [ 14/Jul/15 5:58 AM ]

This patch needs to be rebased to master. Thanks!





[CLJS-1293] Warning settings not conveyed via REPL Created: 31/May/15  Updated: 01/Jun/15  Resolved: 01/Jun/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: 0.0-3308

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

QuickStart node


Attachments: Text File CLJS-1293.patch    

 Description   

Create a node_repl.clj file with contents:

(require 'cljs.repl)
(require 'cljs.repl.node)

(cljs.repl/repl (cljs.repl.node/repl-env)
  :output-dir "out"
  :warnings {:fn-arity false})

Note the :warnings setting above.

With cljs.jar in the same directory, start up Node REPL with rlwrap java -cp cljs.jar:src clojure.main node_repl.clj. Then observe that the warnings map doesn't appear to have any effect:

ClojureScript Node.js REPL server listening on 50469
To quit, type: :cljs/quit
cljs.user=> (defn x [])
#<function cljs$user$x(){
return null;
}>
cljs.user=> (x 3)
WARNING: Wrong number of args (1) passed to cljs.user/x at line 1 <cljs repl>
nil
cljs.user=>

(I suspect that this is a defect in that ana/cljs-warnings binding is not modified to merge in :warnings.)



 Comments   
Comment by David Nolen [ 01/Jun/15 12:28 PM ]

fixed https://github.com/clojure/clojurescript/commit/dfad0d2c08f83c176602b89ad7e79e251c5f3d05





[CLJS-1292] Add IPrintWithWriter implementation for TaggedLiteral Created: 28/May/15  Updated: 29/May/15  Resolved: 29/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Major
Reporter: Nicola Mometto Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-CLJS-1292-Add-IPrintWithWriter-implementation-for-Ta.patch    

 Comments   
Comment by David Nolen [ 29/May/15 12:07 PM ]

fixed https://github.com/clojure/clojurescript/commit/8537ef4d7682ce29066c48e49062bd57c8d4ee92





[CLJS-1291] pprint whitespace/letter checks are incomplete Created: 28/May/15  Updated: 28/May/15  Resolved: 28/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Jonathan Boston Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1291.patch    

 Description   

pprint uses a simple is-whitespace? and is-letter? check that doesn't cover all cases (e.g. unicode chars). Using Google Closure fns are a better choice.



 Comments   
Comment by Jonathan Boston [ 28/May/15 9:36 AM ]

Patch added.

Comment by David Nolen [ 28/May/15 10:17 AM ]

fixed https://github.com/clojure/clojurescript/commit/25e4945cb5c7f0ed4322a377d0e12a62ffea3087





[CLJS-1290] :refer does not work with Closure JS namespaces Created: 27/May/15  Updated: 12/Jun/15  Resolved: 12/Jun/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: 1.7.28

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Maria Geller
Resolution: Completed Votes: 0
Labels: newbie

Attachments: Text File CLJS-1290.patch    

 Description   
(require '[goog.string :refer [startsWith]])

fails due to attempted var checking. We just need to disable var existence checks if we don't have a ClojureScript namespace.



 Comments   
Comment by Maria Geller [ 11/Jun/15 10:46 AM ]

Instead of disabling the check for non-ClojureScript namespaces, I thought we maybe could check if we have a Google Closure module. Attached patch CLJS-1290.patch.

Comment by David Nolen [ 12/Jun/15 10:55 AM ]

Wow awesome thanks! A much better solution!

Comment by David Nolen [ 12/Jun/15 10:56 AM ]

fixed https://github.com/clojure/clojurescript/commit/59a04ebffade090281d976fb7cd9033ab85db691





[CLJS-1289] Revert clj->cljc file conversion Created: 26/May/15  Updated: 26/May/15  Resolved: 26/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Critical
Reporter: Thomas Heller Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Commit [1] changed some .clj files over to .cljc files but no other changes were made to actually make these "common" files. Most of the files are not actually compatible (and probably never will be, eg. assuming sync streaming IO) and some even cause conflicts src/clj/cljs/repl.cljc vs. src/main/cljs/cljs/repl.cljs both trying to provide cljs.repl namespaces.

Any objections to changing these back as they provide no gain as of now?

I know other build tools are not a concern but these "faulty" files cause "issues" in shadow-build.

[1] https://github.com/clojure/clojurescript/commit/11113cea2f599d685b60f8fbdcb56d944240ea25



 Comments   
Comment by David Nolen [ 26/May/15 1:13 PM ]

The change was intentionally made now that Clojure has reader conditionals. The intent is for portions of these ClojureScript files to be made so that we can compile to Node.js gradually over time.





[CLJS-1288] compiler doesn't emit "goog.require" for foreign library when optimization level is not set Created: 25/May/15  Updated: 28/May/15  Resolved: 28/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Maria Geller Assignee: Maria Geller
Resolution: Completed Votes: 0
Labels: bug, foreign-libs

Attachments: Text File CLJS-1288-2.patch     Text File CLJS-1288.patch    
Patch: Code

 Description   

When the optimization level is not set explicitly, meaning that :none will be used as a default, the compiler doesn't emit a goog.require for foreign libraries. An example project reproducing the problem can be found here: https://github.com/MNeise/hello_world.

From my understanding of the code, the compiler environment gets created with the initial options and doesn't get updated with the default optimization level when the options don't include an optimization level. The following check in the load-libs function in the compiler.cljc file then fails, because optimizations is nil.

compiler.cljc
(cond
        (ana/foreign-dep? lib)
        (let [{:keys [target optimizations]} (get @env/*compiler* :options)]
          ;; we only load foreign libraries under optimizations :none
          (when (= :none optimizations)
            (if (= :nodejs target)
              ;; under node.js we load foreign libs globally
              (let [{:keys [js-dependency-index options]} @env/*compiler*
                    ijs-url (get-in js-dependency-index [(name lib) :url])]
                (emitln "cljs.core.load_file(\""
                  (str (io/file (util/output-directory options) (util/get-name ijs-url)))
                  "\");"))
              (emitln "goog.require('" (munge lib) "');"))))


 Comments   
Comment by Maria Geller [ 25/May/15 11:23 PM ]

I've attached a possible patch for this.

Comment by David Nolen [ 26/May/15 5:16 PM ]

The patch looks OK but I think we should just merge all-opts with :options in the compiler-env otherwise later there will be some other case missed

Comment by Maria Geller [ 26/May/15 6:43 PM ]

That makes sense I've update the patch (CLJS-1288.patch).

I was also wondering, if it would make sense to pull emit-constants into add-implicit-options, maybe similar to CLJS-1288-2.patch?

Comment by David Nolen [ 28/May/15 10:09 AM ]

fixed https://github.com/clojure/clojurescript/commit/f75da4ec93add6030ab57d4e2b3e1ad4a1cf9d4d





[CLJS-1287] CLJS exceptions should use same format as Clojure 1.7 (#exception {...}) Created: 25/May/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: Daniel Skarda Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Recent Clojure 1.7-RC adds new print format compatible with EDN syntax:

(ex-info "foobar" {:bar :baz})
#error {
 :cause "foobar"
 :data {:bar :baz}
 :via
 [{:type clojure.lang.ExceptionInfo
   :message "foobar"
   :data {:bar :baz}
   :at [clojure.core$ex_info invoke "core.clj" 4591]}]
 ...
}

(try (.indexOf 0 "baz") (catch Throwable e e))
#error {
 :cause "No matching method found: indexOf for class java.lang.Long"
 :via
 [{:type java.lang.IllegalArgumentException
   :message "No matching method found: indexOf for class java.lang.Long"
   :at [clojure.lang.Reflector invokeMatchingMethod "Reflector.java" 53]}]
 ...
}

Unfortunatelly ClojureScript format is different (and sometimes even not compatible with EDN):

(ex-info "foobar" {:bar :baz})
#ExceptionInfo{:message "foobar", :data {:bar :baz}}

(try (.indexOf 0  "baz") (catch js/Error e e))
#<TypeError: Object 0 has no method 'indexOf'>

The request to unify the output of exceptions might sound like "nitpicking".

However please consider applications, which share (lots of) code between server and client.
Any arbitrary difference between Clojure and ClojureScript adds future accidental complexity.

Hint: looking for green light and answer patches welcome

Last thing to consider is how to deal with stacktraces in the patch. Recent CLJS parses have a parser implemented on server side in Clojure. Should the patch move parsing to ClojureScript?



 Comments   
Comment by David Nolen [ 25/May/15 10:14 AM ]

Yes patch welcome. Thanks!





[CLJS-1286] REPL environment should be able to provide advice if source mapping fails Created: 23/May/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Minor
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

For example browser REPL will often need users to supply :host-port, :host, and :asset-path in order to correctly parse files from stacktraces.






[CLJS-1285] load-file regression Created: 23/May/15  Updated: 23/May/15  Resolved: 23/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: 0.0-3308

Type: Defect Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

We need to make load-file more robust. Currently we don't properly check goog.dependencies.written_ for the sourcePath, we always delete the basePath + source path.



 Comments   
Comment by David Nolen [ 23/May/15 5:12 PM ]

fixed https://github.com/clojure/clojurescript/commit/22ba5a6d0b780183d21bd69a64492e2216a7b379





[CLJS-1284] IndexedSeq -seq implementation incorrect for i >= alength internal array Created: 23/May/15  Updated: 23/May/15  Resolved: 23/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: 0.0-3308

Type: Defect Priority: Major
Reporter: Daniel Skarda Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None
Environment:

ClojureScript 0.0-3291



 Description   
(defn foo-ok
  ([x0 & xs] [x0 xs]))

(defn foo-fail
  ([] nil)
  ([x0 & xs] [x0 xs]))


(foo-ok 0) => [0 nil]     ;; OK
(foo-ok 0 1) => [0 (1)]   ;; OK

(foo-fail) => nil         ;; OK
(foo-fail 0) => [0 (nil)] ;; INCORRECT
(foo-fail 0 1) => [0 (1)] ;; OK


 Comments   
Comment by David Nolen [ 23/May/15 1:53 PM ]

This is a bug with IndexedSeq, not fn arities.

Comment by David Nolen [ 23/May/15 2:10 PM ]

fixed https://github.com/clojure/clojurescript/commit/f165420d2b25008924d6655ca4e79bf9901c2125

Comment by David Nolen [ 23/May/15 2:15 PM ]

I cut a 0.0-3297 interim release with this fix.

Comment by Daniel Skarda [ 23/May/15 5:33 PM ]

David, thank you for very fast analysis, fix and release!





[CLJS-1283] (long \7) produces different result on Clojure/ClojureScript Created: 22/May/15  Updated: 17/Jul/15  Resolved: 17/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Sean Corfield Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

In Clojure (long \7) produces 55 which is the ASCII code value for the character 7.

In ClojureScript, it seems this just converts the single character string "7" to a number and you get 7 as the answer. This might make writing portable string manipulation code rather hazardous?

(reported by irctc_ on IRC)



 Comments   
Comment by David Nolen [ 22/May/15 11:23 PM ]

Coercions like long only exist to simplify porting code. In general such things should be replaced.

Comment by Sean Corfield [ 25/May/15 4:24 PM ]

What would be your recommended, portable, way to turn characters into ASCII then? (that would work in both CLJS and CLJ)

Comment by David Nolen [ 25/May/15 10:27 PM ]

I don't have any recommendation. It seems intractable to me.

Comment by David Nolen [ 17/Jul/15 5:42 AM ]

We're not going to fix this.





[CLJS-1282] Add a :pprint option to the default reporter in cljs.test Created: 22/May/15  Updated: 14/Jul/15  Resolved: 14/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Sebastian Bensusan Assignee: Sebastian Bensusan
Resolution: Completed Votes: 0
Labels: test

Attachments: Text File cljs_1282.patch     Text File cljs_1282_v02.patch     Text File cljs_1282_v03.patch    

 Description   

Now that cljs.pprint has landed, cljs.test could report failures and exceptions with it. The exact API is TBD.



 Comments   
Comment by Sebastian Bensusan [ 22/Jun/15 4:00 PM ]

The :cljs.test/pprint reporter is implemented as a small deviation from the :cljs.test/default reporter.

The API is equivalent to that of custom reporters:

(run-tests
  (empty-env :cljs.test/pprint)
  'my-test.namespace)
Comment by David Nolen [ 24/Jun/15 5:51 AM ]

Looks good mostly but small typo: `print-comparisson` instead of `print-comparison`.

Comment by Sebastian Bensusan [ 28/Jun/15 5:13 PM ]

Added the rebased file with the typo corrected.

Comment by Sebastian Bensusan [ 13/Jul/15 5:10 PM ]

Rebased the patch.

Comment by David Nolen [ 14/Jul/15 5:41 AM ]

fixed https://github.com/clojure/clojurescript/commit/2fbcefa23eead389d24ce198271ceac7d4a13436





[CLJS-1281] preserve test order Created: 21/May/15  Updated: 22/Jun/15  Resolved: 22/Jun/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: 1.7.28

Type: Enhancement Priority: Minor
Reporter: David Nolen Assignee: Sebastian Bensusan
Resolution: Completed Votes: 0
Labels: newbie

Attachments: Text File cljs_1281.patch    

 Description   

We can keep tests sorted by :line var meta information.



 Comments   
Comment by Sebastian Bensusan [ 22/Jun/15 11:48 AM ]

Took David's suggestion and added a (sort-by :line) when creating the ns test-block.

Comment by David Nolen [ 22/Jun/15 12:08 PM ]

fixed





[CLJS-1280] double analysis warnings when using cljs.repl/load-file special fn Created: 21/May/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None





[CLJS-1279] Node.js REPL does not flush process out and err immediately Created: 20/May/15  Updated: 20/May/15  Resolved: 20/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: 0.0-3308

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Comments   
Comment by David Nolen [ 20/May/15 2:49 PM ]

fixed https://github.com/clojure/clojurescript/commit/03529c47f9c38f3923a827166699f511f5ec0356





[CLJS-1278] Asserts still fail while :require-ing .js file (either in :libs or in :source-paths) (same as CLJS-1196) Created: 20/May/15  Updated: 14/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Michal Till Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File cljs_1278.patch    

 Description   

Following on CLJS-1196, I can't get it to work.

In version 0.0-3264 lein-cljsbuild crashed on weird eception `Caused by: java.lang.IllegalArgumentException: No implementation of method: :make-reader of protocol: #'clojure.java.io/IOFactory found for class: nil"` but the current version 0.0-3269 gives the same failed assertion as previously.

I've put up a sample project to illustrate the issue.

Steps to reproduce:

`git clone https://github.com/tillda/stackone`
`cd stackone`
`git checkout 537e5c69b844bc53c159e85cafc24310543cc918`
`lein clean && lein cljsbuild once temp`

Expected behaviour: cljs compiled successfully with src/vendor/client/closure.js and env/stackone/helpersjs.js being included.

Actual behaviour:

```
Compiling "resources/public/lein-cljsbuild-temp/dev-mode-deps.js" failed.
Exception in thread "main" java.lang.AssertionError: Assert failed: (or (file? x) (url? x) (string? x)), compiling/private/var/folders/ym/l2qxd7l97kzfzftrdpqsclm40000gn/T/form-init3642888309490821030.clj:1:125)
at clojure.lang.Compiler.load(Compiler.java:7249)
at clojure.lang.Compiler.loadFile(Compiler.java:7175)
at clojure.main$load_script.invoke(main.clj:275)
at clojure.main$init_opt.invoke(main.clj:280)
at clojure.main$initialize.invoke(main.clj:308)
at clojure.main$null_opt.invoke(main.clj:343)
at clojure.main$main.doInvoke(main.clj:421)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: java.lang.AssertionError: Assert failed: (or (file? x) (url? x) (string? x))
at cljs.util$ext.invoke(util.cljc:115)
at cljs.closure$source_on_disk.invoke(closure.clj:1206)
at cljs.closure$output_unoptimized$fn__3708.invoke(closure.clj:1235)
at clojure.core$map$fn__4551.invoke(core.clj:2622)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:507)
at clojure.core$seq__4126.invoke(core.clj:135)
at clojure.core$filter$fn__4578.invoke(core.clj:2677)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:507)
at clojure.core$seq__4126.invoke(core.clj:135)
at clojure.core$map$fn__4551.invoke(core.clj:2614)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.next(RT.java:674)
at clojure.core$next__4110.invoke(core.clj:64)
at clojure.core$str$fn__4186.invoke(core.clj:528)
at clojure.core$str.doInvoke(core.clj:526)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invoke(core.clj:628)
at cljs.closure$deps_file.invoke(closure.clj:1040)
at cljs.closure$output_deps_file.invoke(closure.clj:1060)
at cljs.closure$output_unoptimized.doInvoke(closure.clj:1243)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invoke(core.clj:630)
at cljs.closure$build.invoke(closure.clj:1514)
at cljs.closure$build.invoke(closure.clj:1426)
at cljsbuild.compiler$compile_cljs$fn__3884.invoke(compiler.clj:81)
at cljsbuild.compiler$compile_cljs.invoke(compiler.clj:80)
at cljsbuild.compiler$run_compiler.invoke(compiler.clj:187)
at user$eval4018$iter_40544058$fn4059$fn_4077.invoke(form-init3642888309490821030.clj:1)
at user$eval4018$iter_40544058$fn_4059.invoke(form-init3642888309490821030.clj:1)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:507)
at clojure.core$seq__4126.invoke(core.clj:135)
at clojure.core$dorun.invoke(core.clj:3007)
at clojure.core$doall.invoke(core.clj:3023)
at user$eval4018.invoke(form-init3642888309490821030.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6792)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.load(Compiler.java:7237)
... 11 more
Subprocess failed
```



 Comments   
Comment by David Nolen [ 20/May/15 10:21 AM ]

This issue is in danger of being closed. Please supply minimal steps to reproduce that do not involve anything other than the ClojureScript compiler. We no longer have time to wade through the indirection introduced by cljsbuild or any other downstream tooling. Thanks.

Comment by Michal Till [ 20/May/15 11:14 AM ]

@David Nolen: I have created a failing minimal testcase based on the Quick Start document. Here it is: https://github.com/tillda/cljs-testcase/

Comment by David Nolen [ 20/May/15 11:27 AM ]

Michal the failing example is not correct. You are not supplying any :libs option.

Comment by Michal Till [ 20/May/15 11:45 AM ]

Ah! Thank you very much! This additional issue was therefore my error. Now it seems to work even in my "big" example.

However it would be cool if there was a meaningful error message stating that a file path can't be resolved. If one is not an expert in the cljs compiler this is almost impossible to figure out. After all the error message in the CLJS-1196 issue and in this wrongfully reported one are exactly the same.

You may close this issue.

Comment by David Nolen [ 20/May/15 11:55 AM ]

We'll leave it open for the improving the error message.

Comment by Sebastian Bensusan [ 22/May/15 7:16 AM ]

Added the check in cljs.closure/source-on-disk where there is info for the error message.

For the supplied case, the error message is:

java.lang.IllegalArgumentException: The file file:/home/carlos/Playground/cljs-testcase/src/hello_world/closure.js 
lacks an associated source file. If it is a JavaScript library please add it to :libs}}

If a different wording or location of the check is needed, I'll submit a new patch with corrections.

Notes:

  • Changed:(:provides js) to (-provides js) in order to be consistent with IJavaScript.
  • cljs.clojure/source-on-disk takes a js argument that should satisfy with IJavaScript and ISourceMap if :source-map is enabled but the implementation is hardcoded to maps because :source-map and :source-url are used instead of ISourceMap methods -source-map and -source-url. I propose to extend PersistentMap and PersistentArrayMap to ISourceMap to make source-on-disk compliant with both protocols.




[CLJS-1277] relax requirement that files must declare a namespace, default to cljs.user Created: 19/May/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

This aligns better with Clojure itself supports.



 Comments   
Comment by David Nolen [ 14/Jun/15 10:30 AM ]

There are a few hurdles in order to make progress on this ticket. The first is that in order to be useful something like require etc. outside the ns needs to be supported in order to be useful.

Comment by Jonathan Boston [ 18/Jul/15 12:17 PM ]

Needs http://dev.clojure.org/jira/browse/CLJS-1346 to be useful.





[CLJS-1276] var equality differs from Clojure Created: 18/May/15  Updated: 14/Jul/15  Resolved: 14/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: 1.7.28

Type: Defect Priority: Minor
Reporter: David Nolen Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

(= #'x #'x) and (identical? #'x #'x) both fail. One solution would be to implement IEquiv and add var-identical? a la keyword-identical?.



 Comments   
Comment by David Nolen [ 14/Jul/15 5:57 AM ]

fixed https://github.com/clojure/clojurescript/commit/bf89165ddc8078aa416d507d20aeae8820d5ca71





[CLJS-1275] lein test configuration is broken Created: 18/May/15  Updated: 18/May/15  Resolved: 18/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Sebastian Bensusan Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File cljs_1275.patch    

 Description   

When running lein test on a fresh copy of master it fails to find the tests. The :test-paths in project.clj is pointing to an old location.



 Comments   
Comment by Sebastian Bensusan [ 18/May/15 7:35 AM ]

This patch redirects :test-paths to the current directory of the tests: src/test/clojure.

Comment by David Nolen [ 18/May/15 8:39 AM ]

fixed https://github.com/clojure/clojurescript/commit/08398b25400b363ca22db885b7ed2460c92bd5fa





[CLJS-1274] Allow assignment to namespace-qualified names in current namespace Created: 17/May/15  Updated: 17/May/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3211
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: lvh Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

In Clojure, you can def to a namespace-qualified name as long as it's in the current namespace. You can't do that in Clojurescript. This makes writing some macros that def to a local name a bit more annoying, since the syntax-quote will automatically namespace-qualify any symbols, so you have to write the somewhat unsightly and not super obvious ~'sym.






[CLJS-1273] clojure.lang.Symbol cannot be cast to clojure.lang.Namespace on macro expansion Created: 17/May/15  Updated: 17/May/15  Resolved: 17/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3211
Fix Version/s: None

Type: Defect Priority: Major
Reporter: lvh Assignee: Unassigned
Resolution: Not Reproducible Votes: 0
Labels: None


 Description   

Following macro & macro call:

{{
(defmacro defroutes
[routes]
(let [route-defs (for [{:keys [path view]} routes]
`(secretary/defroute ~path []
(session/put! :current-page ~view)))]
`(do (def ~'routes ~routes) ~@route-defs)))

(defroutes
[{:name "Home"
:path "/"
:view #'home-page}
{:name "Foo bar"
:path "/foo-bar"
:view #'foo-bar-page}
{:name "Baz quux"
:path "/baz-quux"
:view #'baz-quux-page}])
}}

... results in following compile-time exception:

{{
clojure.lang.ExceptionInfo : failed compiling file:src/cljs/shrieker/core.cljs
clojure.lang.ExceptionInfo : clojure.lang.Symbol cannot be cast to clojure.lang.Namespace
java.lang.ClassCastException : clojure.lang.Symbol cannot be cast to clojure.lang.Namespace
Error on file /Users/lvh/Projects/rackspace/shrieker/src/cljs/shrieker/core.cljs, line 106, column 60
}}

I believe this to be a bug, because replacing that macro call with its expansion works fine:

{{
(do
(def routes
[{:name "Home"
:path "/"
:view #'home-page}
{:name "Foo bar"
:path "/foo-bar"
:view #'foo-bar-page}
{:name "baz quux"
:path "/baz-quux"
:view #'baz-quux-page}])
(secretary/defroute "/" []
(session/put! :current-page #'home-page))
(secretary/defroute "/foo-bar" []
(session/put! :current-page #'foo-bar-page))
(secretary/defroute "/endpoint-quux" []
(session/put! :current-page #'baz-quux-page)))
}}

I was unable to repeat the experiment on more recent Clojurescripts, as some of my dependencies don't quite agree with it.



 Comments   
Comment by lvh [ 17/May/15 7:14 PM ]

JIRA doesn't appear to like my markup. Sorry about that

Comment by David Nolen [ 17/May/15 10:59 PM ]

You need to verify that this affects a released version of ClojureScript in a reproducible way (minimal case). Thanks.





[CLJS-1272] :include-macros description inaccurate in require Created: 17/May/15  Updated: 17/May/15  Resolved: 17/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: docstring

Attachments: Text File CLJS-1272.patch    

 Description   

The description for :include-macros in the docstring for require indicates

:include-macros takes a list of macro symbols to refer from the namespace.

when really the spec only takes true as an argument, where the semantics are "causes macros to be required"



 Comments   
Comment by David Nolen [ 17/May/15 6:46 PM ]

fixed https://github.com/clojure/clojurescript/commit/721ba892892d7aa000460c45a6eb1afecd33eff5





[CLJS-1271] Missing warning when assigning namespaces via def Created: 17/May/15  Updated: 31/Jul/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.28
Fix Version/s: Next

Type: Defect Priority: Minor
Reporter: Sebastian Bensusan Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Currently you can assign a Closure namespace to a var without getting a warning.

Minimal sample:

(ns import-names.core
  (:import [goog debug]))

(def debug goog.debug)


 Comments   
Comment by David Nolen [ 29/May/15 12:30 PM ]

The example case is a bit complected. Besides importing a name that matches a def you are also assigning a google closure namespace to a local. This will likely cause problems on its own. We need more information.

Comment by Sebastian Bensusan [ 29/May/15 12:46 PM ]

We should check that :require ed and :import ed namespaces are not used as values and then warn about it.





[CLJS-1270] Docstring for delay not printed by cljs.repl/doc Created: 16/May/15  Updated: 17/May/15  Resolved: 17/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1270.patch    

 Description   
cljs.user=> (doc delay)
-------------------------
cljs.core/delay
([& body])
Macro
  nil

nil
cljs.user=> (source delay)
(defmacro delay [& body]
  "Takes a body of expressions and yields a Delay object that will
  invoke the body only the first time it is forced (with force or deref/@), and
  will cache the result and return it on all subsequent force
  calls."
  `(new cljs.core/Delay (fn [] ~@body) nil))
nil


 Comments   
Comment by Mike Fikes [ 16/May/15 8:12 PM ]

Attached CLJS-1270.patch

Comment by David Nolen [ 17/May/15 10:28 AM ]

fixed https://github.com/clojure/clojurescript/commit/264eb2b5153d6d1c3b6fcf0a42aad31956297cc5





[CLJS-1269] realized? docstring refers to promise and future Created: 16/May/15  Updated: 17/May/15  Resolved: 17/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: None

Type: Defect Priority: Trivial
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: docstring

Attachments: Text File CLJS-1269.patch    

 Description   

The docstring for realized? refers to nonexistent promise and future.

Likely copied over verbatim from Clojure:

cljs.user=> (doc realized?)
-------------------------
cljs.core/realized?
([d])
  Returns true if a value has been produced for a promise, delay, future or lazy sequence.

nil


 Comments   
Comment by Mike Fikes [ 16/May/15 7:57 PM ]

Added CLJS-1269.patch

Comment by David Nolen [ 17/May/15 10:27 AM ]

fixed https://github.com/clojure/clojurescript/commit/27ad78bb3f7fdfe64b4041bf60532489c2847105





[CLJS-1268] cljc support for cljs.closure/compile-file Created: 13/May/15  Updated: 14/May/15  Resolved: 14/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: 0.0-3308

Type: Defect Priority: Major
Reporter: Robert Krahn Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None


 Description   

When calling cljs.closure/compile-file on a cljc file I get

ExceptionInfo Conditional read not allowed {:type :reader-exception, :line 5, :column 5, :file nil}
clojure.core/ex-info (core.clj:4591)
clojure.tools.reader/read* (reader.clj:896)
clojure.tools.reader/read-delimited (reader.clj:189)
clojure.tools.reader/read-list (reader.clj:202)
clojure.tools.reader/read* (reader.clj:878)
clojure.tools.reader/read (reader.clj:927)
cljs.analyzer/forms-seq*/forms-seq--124424/fn124425/fn-124426 (analyzer.cljc:24)
cljs.analyzer/forms-seq*/forms-seq--124424/fn-124425 (analyzer.cljc:18)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.Cons.next (Cons.java:39)
clojure.lang.RT.next (RT.java:674)
clojure.core/next--4109 (core.clj:64)
cljs.closure/compile-form-seq/fn-7854/fn-7855 (closure.clj:341)
cljs.closure/compile-form-seq/fn--7854 (closure.clj:340)
cljs.compiler/with-core-cljs (compiler.cljc:968)
cljs.closure/compile-form-seq (closure.clj:337)
cljs.closure/compile-file (closure.clj:376)

The issue is that forms-seq* is already called with a reader and the cljc check in there is not getting a file. Checking for ana/cljs-file is probably a solution.



 Comments   
Comment by David Nolen [ 14/May/15 9:36 PM ]

fixed https://github.com/clojure/clojurescript/commit/98ed0f4a08dfe757b7c647dbce22e235ef45b0a3





[CLJS-1267] New :end-run-tests event not present in all public cljs.test functions Created: 13/May/15  Updated: 17/Jul/15  Resolved: 17/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Sebastian Bensusan Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File cljs_1267.patch     Text File cljs_1267_v01.patch     Text File cljs_1267_v02.patch    

 Description   

After CLJS-1226, cljs.test API is inconsistent since only one of its public functions (run-tests) emits the new :end-run-tests event. The event should be added to test-all-vars, test-ns, test-var, and test-vars, making sure it is only fired once.



 Comments   
Comment by Leon Grapenthin [ 13/May/15 3:13 AM ]

To my knowledge all four are not reused within cljs.test, only the -block versions are, so there should be no worries about the event fired twice.

Comment by Sebastian Bensusan [ 17/May/15 12:37 PM ]

The patch includes the :end-run-tests event to test-ns, test-all-vars, test-vars, and test-var. I didn't add the event to the block functions since those can be reused and composed.

Notes:

  • If any of those functions are used sequentially in a script the event will be fired multiple times.
  • On each function the map passed to cljs.test/report contains different information besides {:type :end-run-tests}. test-var passes :var, test-vars passes :vars, test-ns and test-all-vars pass :ns.
Comment by David Nolen [ 14/Jul/15 6:04 AM ]

I question the desirability of firing this event multiple times. While it may be inconvenient it seems far simpler to just emit different kinds of end events that you must listen for in each case.

Comment by Sebastian Bensusan [ 14/Jul/15 6:31 PM ]

Updated according to David's suggestion: have an "end" event for all cljs.tets api functions. The missing ones were :end-test-all-vars and :end-test-vars and are added in the rebased cljs_1267_v01.patch

Comment by David Nolen [ 17/Jul/15 7:06 AM ]

It looks like this patch needs to be rebased to master. Please assign to me when this has been done. Thanks.

Comment by Sebastian Bensusan [ 17/Jul/15 7:16 AM ]

Rebased on master, last commit, 047af0965c6760483aca94b55666563e0857629d

Comment by Sebastian Bensusan [ 17/Jul/15 7:17 AM ]

Patch rebased, thanks!

Comment by David Nolen [ 17/Jul/15 7:25 AM ]

fixed https://github.com/clojure/clojurescript/commit/be864bcb598b5e60f77f6629045bec5d80caf605





[CLJS-1266] Node: Rename .cljs to .cljc -> old filenames in stacktrace Created: 12/May/15  Updated: 12/May/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Using QuickStart, set up Node REPL.

Manually add a foo/bar.cljs to filesystem with

(ns foo.bar)

(defn throw-ex [] (ffirst 1))

(defn call-me [] (throw-ex))

Check that it works:

cljs.user=> (require 'foo.bar)
nil
cljs.user=> (foo.bar/call-me)
repl:13
throw e__4210__auto__;
      ^
Error: 1 is not ISeqable
    at Object.cljs$core$seq [as seq] (/Users/mfikes/Desktop/hello_world-node/out/cljs/core.cljs:956:20)
    at Object.cljs$core$first [as first] (/Users/mfikes/Desktop/hello_world-node/out/cljs/core.cljs:965:16)
    at cljs$core$ffirst (/Users/mfikes/Desktop/hello_world-node/out/cljs/core.cljs:1398:11)
    at foo$bar$throw_ex (/Users/mfikes/Desktop/hello_world-node/out/foo/bar.cljs:3:20)
    at foo$bar$call_me (/Users/mfikes/Desktop/hello_world-node/out/foo/bar.cljs:5:19)
    at repl:1:105
    at repl:9:3
    at repl:14:4
    at Object.exports.runInThisContext (vm.js:74:17)
    at Domain.<anonymous> ([stdin]:41:34)

Then manually move bar.cljs to bar.cljc and add a new symbol so it looks like:

(ns foo.bar)

(defn throw-ex [] (ffirst 1))

(defn call-me [] (throw-ex))

(defn call-again [] (call-me))

Then reload the ns and use the new symbol:

cljs.user=> (require 'foo.bar :reload)
nil
cljs.user=> (foo.bar/call-again)
repl:13
throw e__4210__auto__;
      ^
Error: 1 is not ISeqable
    at Object.cljs$core$seq [as seq] (/Users/mfikes/Desktop/hello_world-node/out/cljs/core.cljs:956:20)
    at Object.cljs$core$first [as first] (/Users/mfikes/Desktop/hello_world-node/out/cljs/core.cljs:965:16)
    at cljs$core$ffirst (/Users/mfikes/Desktop/hello_world-node/out/cljs/core.cljs:1398:11)
    at foo$bar$throw_ex (/Users/mfikes/Desktop/hello_world-node/out/foo/bar.cljs:3:20)
    at foo$bar$call_me (/Users/mfikes/Desktop/hello_world-node/out/foo/bar.cljs:5:19)
    at foo$bar$call_again (/Users/mfikes/Desktop/hello_world-node/out/foo/bar.cljs:5:19)
    at repl:1:108
    at repl:9:3
    at repl:14:4
    at Object.exports.runInThisContext (vm.js:74:17)

This illustrates the defect. call_again and the other symbols are shown as being in the old filename.

Stop the REPL and restart it to see correct behavior:

cljs.user=> :cljs/quit
orion:hello_world-node mfikes$ rlwrap java -cp cljs.jar:src clojure.main node_repl.clj
Reading analysis cache for jar:file:/Users/mfikes/Desktop/hello_world-node/cljs.jar!/cljs/core.cljs
Compiling src/foo/bar.cljc
ClojureScript Node.js REPL server listening on 49397
Watch compilation log available at: out/watch.log
To quit, type: :cljs/quit
cljs.user=> (require 'foo.bar)
nil
cljs.user=> (foo.bar/call-again)
repl:13
throw e__4210__auto__;
      ^
Error: 1 is not ISeqable
    at Object.cljs$core$seq [as seq] (/Users/mfikes/Desktop/hello_world-node/out/cljs/core.cljs:956:20)
    at Object.cljs$core$first [as first] (/Users/mfikes/Desktop/hello_world-node/out/cljs/core.cljs:965:16)
    at cljs$core$ffirst (/Users/mfikes/Desktop/hello_world-node/out/cljs/core.cljs:1398:11)
    at foo$bar$throw_ex (/Users/mfikes/Desktop/hello_world-node/out/foo/bar.cljc:3:20)
    at foo$bar$call_me (/Users/mfikes/Desktop/hello_world-node/out/foo/bar.cljc:5:19)
    at foo$bar$call_again (/Users/mfikes/Desktop/hello_world-node/out/foo/bar.cljc:7:22)
    at repl:1:108
    at repl:9:3
    at repl:14:4
    at Object.exports.runInThisContext (vm.js:74:17)


 Comments   
Comment by Mike Fikes [ 12/May/15 2:04 PM ]

FWIW as a comparison, the same use case works properly with Clojure 1.7.0-beta2.





[CLJS-1265] Rename from .cljs to .cljc results in :reload failing Created: 12/May/15  Updated: 14/Jul/15  Resolved: 14/Jul/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Mike Fikes Assignee: Mike Fikes
Resolution: Completed Votes: 0
Labels: None


 Description   

Set up QuickStart browser REPL.

1. On disk, create a new file in src, say foo/bar.cljs and define a symbol in it.
2. In the REPL (require 'foo.bar) and then make use of the symbol.
3. On disk, rename the file to bar.cljc, and then edit the file to introduce a new symbol.
4. In the REPL (require 'foo.bar :reload) and then try to make use of the new symbol.

For a function defnition, at this point I get an error

TypeError: undefined is not an object (evaluating 'foo.bar.call_me.call')


 Comments   
Comment by Mike Fikes [ 12/May/15 2:05 PM ]

FWIW as a comparison, the same use case works properly with Clojure 1.7.0-beta2 (in regular lein repl).

Comment by David Nolen [ 14/Jul/15 6:06 AM ]

Is this still a problem today?

Comment by Mike Fikes [ 14/Jul/15 8:20 AM ]

This no longer occurs with master 0.0-3490.





[CLJS-1264] ClojureScript 0.0-3255 breaks compatibility with Clojure 1.6.0 Created: 11/May/15  Updated: 12/May/15  Resolved: 12/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3255, 0.0-3269
Fix Version/s: None

Type: Defect Priority: Major
Reporter: Stephen Nelson Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

ClojureScript 0.0-3255 renamed several core files from clj to cljc. This breaks compatibility with Clojure 1.6.0, which is significant because Clojure 1.7.0 hasn't been released yet. This change forces any projects that bundle ClojureScript to switch to an unreleased Clojure or fall behind ClojureScript.

Falling behind ClojureScript is a significant problem as most development tools and libraries follow CLJS head, so a project that uses an old CLJS must use old libraries and build tools too, or maintain forks for pulling in bug fixes.

It would be good if this change could be reverted until CLJ 1.7 lands. If this is not possible, please consider maintaining a CLJ 1.6 branch and back porting bug fixes.



 Comments   
Comment by David Nolen [ 12/May/15 3:08 PM ]

There are stable releases of ClojureScript that work with Clojure 1.6.0. Use them if you need to. We're not going to maintain a 1.6.0 branch.





[CLJS-1263] :libs regression, can no longer specify specific files Created: 11/May/15  Updated: 11/May/15  Resolved: 11/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3269
Fix Version/s: 0.0-3308

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

:libs currently works great for directories but the support for individual files specified by the user is broken.



 Comments   
Comment by David Nolen [ 11/May/15 3:43 PM ]

fixed https://github.com/clojure/clojurescript/commit/e9de8c70de99cedb67e6bde7c3a9f65a716b6e35





[CLJS-1262] Write to compiler out before :merge-opts Created: 10/May/15  Updated: 19/May/15  Resolved: 19/May/15

Status: Closed
Project: ClojureScript
Component/s: None
Affects Version/s: 0.0-3255
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None


 Description   

cljs.repl/repl* supports a :merge-opts, allowing derived REPLs, for example to specify :output-dir as a result of -setup.

A recent change in with_core_