<< Back to previous view

[CLJS-1433] self-host: cljs.js/*eval-fn* passed nil :cache Created: 24/Aug/15  Updated: 26/Aug/15  Resolved: 26/Aug/15

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

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

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

 Description   

If you load some ClojureScript source that implements a namespace, the cljs.js/*eval-fn* will always be passed a :cache value of nil



 Comments   
Comment by Mike Fikes [ 24/Aug/15 12:24 PM ]

Simple defect—simply need to deref the atom.

Comment by David Nolen [ 26/Aug/15 10:28 PM ]

fixed https://github.com/clojure/clojurescript/commit/5f3c494ce4274177e8e9cb71adcb87b5f9394423





[CLJS-1432] 1.7.48 assigns same value for '$ and '. symbols under advanced Created: 24/Aug/15  Updated: 27/Aug/15  Resolved: 27/Aug/15

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

Type: Defect Priority: Minor
Reporter: Nikita Prokopov Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File cljs-1432-symbols-collision-2.patch     Text File cljs-1432-symbols-collision.patch    

 Description   
(println :+ :a :$ :. :a$b :a.b :z)
      => :+ :a :. :. :a$b :a$b :z

(println '+ 'a '$ '. 'a$b 'a.b 'z)
      =>  +  a  .  .  a$b  a$b  z

expected:
(not= :$ :.)
(not= '$ '.)

Related:
CLJS-1105
https://github.com/clojure/clojurescript/commit/d92b3004046d1f83ab76a2b94f4129cb16e47848
https://github.com/tonsky/datascript/issues/108



 Comments   
Comment by Nikita Prokopov [ 26/Aug/15 12:09 AM ]

Just wanted to add that this issue breaks DataScript to the point it’s impossible to use (because it relies on both '$ and '.). DataScript cannot be used at all with 1.7.48, 1.7.58, 1.7.107

Comment by David Nolen [ 26/Aug/15 10:38 PM ]

Why not just special case '. here?

Comment by Nikita Prokopov [ 27/Aug/15 3:34 AM ]

David, I’m not sure what is the purpose of this code, e.g. why it transforms symbol/keyword name at all. If this is going to constants table as a key, it can be any string, right?

My solution just eliminates other possible collisions (e.g. :a$b vs :a.b) because I think it is not fun to encounter stuff like this. It takes really huge effort to debug, because it comes from the most unexpected place: on the one hand, language guarantees keywords are only equal to themselves, on the other, it silently treats different keywords/symbols as the same.

If you think my solution is an overkill, or if there are technical reasons it can’t be applied, as I’m not aware of all the nuances, I leave this decision to you.

Other possible solution might be, if encountered kw/sym that might conflict, do not apply this optimization to them at all. We would probably lose some performance, but keep the guarantees.

Comment by David Nolen [ 27/Aug/15 6:22 AM ]

Emitting strings for the constants table defeats minification and dead code elimination.

The bug is a simple source code generation symbol clash that can be avoided with special casing '.. If you can come up with other problematic cases then I'll consider an alternative. Otherwise this is the only patch we will take.

Comment by Nikita Prokopov [ 27/Aug/15 1:10 PM ]

Attached second patch, as you suggested

Comment by David Nolen [ 27/Aug/15 3:31 PM ]

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

Comment by Nikita Prokopov [ 27/Aug/15 3:40 PM ]

Thanks David!





[CLJS-1431] load-file doc output missing arglists Created: 21/Aug/15  Updated: 26/Aug/15  Resolved: 26/Aug/15

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

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

noderepljs


Attachments: Text File CLJS-1431-8-21-15.patch    
Patch: Code

 Description   

The output for `(doc load-file)` is missing the arglists:

$ script/noderepljs 
ClojureScript Node.js REPL server listening on 52087
To quit, type: :cljs/quit
cljs.user=> (doc load-file)
-------------------------
load-file
REPL Special Function
  Sequentially read and evaluate the set of forms contained in the file.

nil

A line reading ([name]) should appear between load-file and REPL Special Function



 Comments   
Comment by Mike Fikes [ 21/Aug/15 7:50 PM ]

Root cause is the use of :arglist instead of :arglists here:
https://github.com/clojure/clojurescript/blob/v1.7/src/main/clojure/cljs/repl.cljc#L1113

Comment by Chris Pickard [ 21/Aug/15 8:44 PM ]

I've attached a patch (CLJS-1431-8-21-15.patch) that address the issue Mike reported

Comment by Mike Fikes [ 21/Aug/15 9:00 PM ]

For me, Chris Pickard's CLJS-1431-8-21-15.patch applies cleanly to master, produces the correct behavior in script/noderepljs, and unit tests pass for V8, SpiderMonkey, and JavaScriptCore (Nashorn skipped).

Comment by David Nolen [ 26/Aug/15 10:31 PM ]

fixed https://github.com/clojure/clojurescript/commit/19bcf10ccedf63f0e3bf0abfb7481f9c347895fc





[CLJS-1430] self-host: .toString is emitted as .toString$ (munged) Created: 18/Aug/15  Updated: 27/Aug/15  Resolved: 27/Aug/15

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

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

Attachments: Text File CLJS-1430-2.patch     Text File CLJS-1430-3.patch     Text File CLJS-1430-4.patch     Text File CLJS-1430.patch    
Patch: Code and Test

 Description   

If you evaluate a form like (.toString "a") in bootstrapped mode, the emitted JavaScript will end up with a dollar-sign: "a".toString$().

This can be reproduced via a compile-str unit test involving the form.



 Comments   
Comment by Mike Fikes [ 18/Aug/15 11:29 PM ]

This is because, even though the compiler indicates that there are no reserved words (the empty set for second argument here):

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

cljs.core/munge is called here

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

to imitate Clojure's munge. But cljs.core/munge introduces the dollar-sign for reserved JavaScript keywords:

https://github.com/clojure/clojurescript/blob/v1.7/src/main/cljs/cljs/core.cljs#L9898

The direct ClojureScript imitation of Clojure's munge is munge-str here

https://github.com/clojure/clojurescript/blob/v1.7/src/main/cljs/cljs/core.cljs#L9882

Calling that (private) method instead fixes the problem.

Comment by Mike Fikes [ 18/Aug/15 11:37 PM ]

The attached file fixes the issue.

On problem with it, though it it has the compiler calling a private function in cljs.core namespace.

Comment by Mike Fikes [ 18/Aug/15 11:44 PM ]

Attaching a 2nd patch which properly updates the latch count in the unit test.

Comment by David Nolen [ 26/Aug/15 10:37 PM ]

This ticket does not explain why toString would get munged - it's not on the reserved list.

Comment by Mike Fikes [ 26/Aug/15 11:04 PM ]

You are right, David. The root cause actually has to do with (js-reserved? "toString") returning true when it should not do so. I suspect this has to do with the use of gobject/containsKey giving a false positive for things in the Object prototype, viz:

cljs.user=> (require '[goog.object :as gobject])
nil
cljs.user=> (gobject/containsKey #js {} "toString")
true

So, I retract my patch which completely glosses over the aspect that js-reserved? is probably the culprit.

Comment by Mike Fikes [ 26/Aug/15 11:53 PM ]

David, based on your feedback, attached a CLJS-1430-3.patch which might be closer to a correct approach in that it fundamentally revises js-reserved? to not return true for things like "toString".

My JavaScript is not strong enough for a feel as to whether the actual implementation in the patch is up to muster, nor whether munging is in the critical path for perf.

Comment by David Nolen [ 27/Aug/15 6:27 AM ]

Ah ok, revise the patch to remove the two tests, instead just use (.hasOwnProperty js-reserved foo)

Comment by Mike Fikes [ 27/Aug/15 7:56 AM ]

CLJS-1430-4.patch updated to use .hasOwnProperty, and ran all tests except Nashorn. Also ran self-host tests.

Comment by David Nolen [ 27/Aug/15 8:23 AM ]

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





[CLJS-1429] self-host: Load dependent namespaces when client calls back with :cache Created: 17/Aug/15  Updated: 17/Aug/15  Resolved: 17/Aug/15

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

Type: Enhancement Priority: Minor
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Not Reproducible Votes: 0
Labels: bootstrap


 Description   

If cljs.js/*load-fn*'s callback is called with :cache, load dependent namespaces. Otherwise, the cached JavaScript will be loaded but not its dependencies.



 Comments   
Comment by Mike Fikes [ 17/Aug/15 9:45 AM ]

FWIW, I've worked around this downstream by making use of Google Closure's dependency management to actually do the load along with dependent namespaces, combined with simply returning an empty string for the source: https://github.com/mfikes/planck/blob/5dcc56c28732e79436fd9cc37dfd6cd42e0d076c/planck-cljs/src/planck/repl.cljs#L314

Comment by Mike Fikes [ 17/Aug/15 9:55 AM ]

I apologize for the ticket noise. This issue is invalid; it actually works.





[CLJS-1428] Add a cljs.core/*command-line-args* var Created: 16/Aug/15  Updated: 16/Aug/15

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

Type: Enhancement Priority: Minor
Reporter: Mike Fikes Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None


 Description   

Add a cljs.core/*command-line-args* var that mimics Clojure's:

https://github.com/clojure/clojure/blob/4bb1dbd596f032621c00a670b1609a94acfcfcab/src/clj/clojure/core.clj#L6148

Rationale:
1) Simplifies writing command-line scripts in ClojureScript if this var is universally available.
2) Consistency with Clojure.

Existing tooling can ignore the var (it would be initialized with nil).

Command-line REPLs or other command-line environments can bind a sequence to this var when launched.






[CLJS-1427] Add a cljs.core/ICloseable protocol definition Created: 16/Aug/15  Updated: 16/Aug/15

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

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


 Description   

Add protocol definition that abstracts over the concept of entities that can be closed.

Rationale: It naturally goes with IWriter and the proposed IReader (CLJS-1426), making it easy to define closable writers or readers.

(defprotocol IClosable
  "Protocol for closable entities."
  (-close [this] "Closes this entity."))





[CLJS-1426] Add a cljs.core/IReader protocol definition Created: 16/Aug/15  Updated: 16/Aug/15

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

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


 Description   

There is a cljs.core/IWriter

https://github.com/clojure/clojurescript/blob/a741cd4a3d0683f9dcfd08822343abcfa477d951/src/main/cljs/cljs/core.cljs#L618

The addition of cljs.core/IReader would be useful to projects that wish abstract over the concept of reading.

Perhaps a definition along the following lines:

(defprotocol IReader
  "Protocol for reading."
  (-read [this] "Returns available characters as a string or nil if EOF."))





[CLJS-1425] self-host: cljs.js/eval cb argument inconsistent with docstring Created: 14/Aug/15  Updated: 14/Aug/15

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

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


 Description   

The docstring for cljs.js/eval indicates a map (containing either an :error or :value key).

This is the case for :error: Here is an example:

https://github.com/clojure/clojurescript/blob/r1.7.48/src/main/cljs/cljs/js.cljs#L489

But for :value the value is returned without being wrapped in a map; instead the result of applying *eval-fn* is directly returned (and *eval-fn* is supposed to return the value). Here is an example:

https://github.com/clojure/clojurescript/blob/r1.7.48/src/main/cljs/cljs/js.cljs#L499






[CLJS-1424] (def) or (defn) will throw an obscure exception Created: 14/Aug/15  Updated: 14/Aug/15

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

Type: Defect Priority: Minor
Reporter: Sean Grove Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: cljs


 Description   

Simply trying to compile `(def)` will throw an exception: "Caused by: clojure.lang.ArityException: Wrong number of args (1) passed to: analyzer/eval1440/fn-1441/pfn-1442"

While obviously not a valid construct, the error could be significantly more descriptive, and also show the line number where it happened.

A similar issue happens with `(defn)`: "Caused by: clojure.lang.ExceptionInfo: Wrong number of args (2) passed to: core/defn--12230"






[CLJS-1423] self-host: Requiring analyzer/compiler breaks unchecked Boolean Created: 14/Aug/15  Updated: 14/Aug/15

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

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

Quick Start



 Description   

Grab the Quick Start cljs.jar, and make a src/foo/core.cljs file with

(ns foo.core)

(if 0 
  (prn 1) 
  (prn 2))

Build it using java -cp cljs.jar:src clojure.main build.clj where build.clj contains:

(require 'cljs.build.api)

(cljs.build.api/build "src" 
  {})

Inspect out/foo/core.js:

// Compiled by ClojureScript 1.7.48 {}
goog.provide('foo.core');
goog.require('cljs.core');
if(cljs.core.truth_((0))){
cljs.core.prn.call(null,(1));
} else {
cljs.core.prn.call(null,(2));
}

//# sourceMappingURL=core.js.map

Now revise src/foo/core.cljs to require the analyzer namespace:

(ns foo.core
  (:require cljs.analyzer))

(if 0 
  (prn 1) 
  (prn 2))

Build again and inspect out/foo/core.js:

// Compiled by ClojureScript 1.7.48 {}
goog.provide('foo.core');
goog.require('cljs.core');
goog.require('cljs.analyzer');
if((0)){
cljs.core.prn.call(null,(1));
} else {
cljs.core.prn.call(null,(2));
}

//# sourceMappingURL=core.js.map

Note the lack of cljs.core.truth_



 Comments   
Comment by Mike Fikes [ 14/Aug/15 3:41 PM ]

Speculation: The intent of this line

https://github.com/clojure/clojurescript/blob/r1.7.48/src/main/clojure/cljs/analyzer.cljc#L1565

is to provide *unchecked-if* capability in bootstrapped environments. But, perhaps it additionally acts as a meta-circular gateway allowing cljs.analyzer/*unchecked-if* to be set in new scenarios while compiling ClojureScript using the JVM-based compiler. (That line was not there previously.)

Fact: If you remove this line, it works. Additionally, if you revise it to set a literal false, things work. Neither are satisfying as they would defeat the original intent of that bit of code.

I have a much more complicated downstream usage of bootstrap that exhibits similar behavior with respect to the minimal repro above (https://github.com/mfikes/planck/issues/84).





[CLJS-1422] cljs.js/eval-str fails for ns form on node.js with simple optimizations Created: 14/Aug/15  Updated: 27/Aug/15

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

Type: Defect Priority: Major
Reporter: Michael Ballantyne Assignee: Michael Ballantyne
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File CLJS_1422.patch     Text File CLJS_1422-v2.patch    
Patch: Code and Test
Approval: Accepted

 Description   

find-ns-obj has a special case for node.js under simple optimizations that uses eval to find the namespace object. If the object does not already exist this produces an exception; on other platforms find-ns-obj returns nil for a non-existant namespace.

As a result eval-str produces an error when evaluating a ns form for a new namespace.

There's a commented out test for this already in the source at https://github.com/clojure/clojurescript/blob/master/src/test/self/self_host/test.cljs#L121



 Comments   
Comment by Michael Ballantyne [ 14/Aug/15 1:17 PM ]

Added a patch with a fix and uncomment the existing test.

The special case of find-ns-obj for node.js under optimizations now checks each path segment with an eval of typeof to see if it exists, returning nil if the namespace object is absent.

Comment by David Nolen [ 26/Aug/15 10:47 PM ]

The overall idea is sound but the patch needs work. Just use goog.isObject instead of the needless js/eval call.

Comment by Michael Ballantyne [ 27/Aug/15 12:36 AM ]

I believe we need at least one `js/eval` of `typeof` in order to establish whether the object for the initial namespace segment exists, as there is no parent object to examine and referencing an undefined variable throws `ReferenceError`. `goog.isObject(thing)` where `thing` is a reference to an undefined variable throws `ReferenceError`; `typeof thing` returns `"undefined"`.

However, after obtaining the initial namespace segment we can use the normal `find-ns-obj*`. I've attached an updated patch using this strategy.

Comment by David Nolen [ 27/Aug/15 6:33 AM ]

Just a small code review thing to clarify the intent, why not just remove the multiple js/evals and lean on try/catch? The only possible error is attempting to use an undefined var which in that case we just want to bail anyway.





[CLJS-1421] Enable Asynchronous cljs.js/*eval-fn* Created: 14/Aug/15  Updated: 16/Aug/15

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

Type: Enhancement Priority: Minor
Reporter: Matthew Molloy Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: asynchronous, bootstrap


 Description   

In bootstrapped ClojureScript cljs.js/eval-fn receives javascript source and evaluates it, returning a result. In some contexts it is necessary to evaluate the js asynchronously, can we add this functionality?



 Comments   
Comment by David Nolen [ 14/Aug/15 7:49 PM ]

This ticket needs more rationale. Can you elaborate on the usecase?

Comment by Matthew Molloy [ 14/Aug/15 10:08 PM ]

My usecase is an asynchronous eval function

(fn *eval-fn*
  [{:keys [source]}]
  (js/chrome.devtools.inspectedWindow.eval source
    (fn [result err]
      (if result
        (callback result)
        (callback err))))

There must be other people who have situations like this.

Comment by David Nolen [ 16/Aug/15 12:16 AM ]

Interesting. I don't think this is a common use case, most JS engines provide synchronous eval. Not interested in any breaking changes but would be happy to take a patch that gives you the behavior you want via an option flag, :async-eval.





[CLJS-1420] get-in behavior differs from Clojure by always deferring to the 3 arity fn Created: 12/Aug/15  Updated: 14/Aug/15

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

Type: Defect Priority: Minor
Reporter: Kevin Webster Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File cljs_1420.patch    

 Description   

CLJS-464 should be reverted since the commit changes how get-in is handled by types that implement ILookup.

Since get-in always defers to the 3 arity function, the 2 arity ILookup -lookup fn never gets called. This behavior is inconsistent with how Clojure behaves.

clj:

(get-in
  (reify
    clojure.lang.ILookup
    (valAt [o k] :2-arity)
    (valAt [o k not-found] :3-arity))
  [:foo])
=> :2-arity

cljs:

(get-in
  (reify
    ILookup
    (-lookup [o k] :2-arity)
    (-lookup [o k not-found] :3-arity))
  [:foo])
=> :3-arity


 Comments   
Comment by Kevin Webster [ 12/Aug/15 3:30 PM ]

Tested patch in both V8 & Nashorn

Comment by David Nolen [ 14/Aug/15 7:51 PM ]

Please modify the patch to include a test case. The patch should be squashed into a single commit.





[CLJS-1419] enhance numeric inference, if + number? test on local var should tag local var in the successful branch Created: 12/Aug/15  Updated: 12/Aug/15

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

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


 Comments   
Comment by David Nolen [ 12/Aug/15 6:44 AM ]

One small complication is dealing with and as it has an optimizing case.





[CLJS-1418] self-host: defprotocol regressed with arity error Created: 10/Aug/15  Updated: 10/Aug/15  Resolved: 10/Aug/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

Attachments: Text File 0001-Exhibit-defprotocol-failure.patch     Text File CLJS-1481.patch    

 Description   

There is a regression in the ability to evaluate (defprotocol Foo) in master.

The attached patch exhibits the problem with a unit test that triggers the issue, causing the following to be emitted:

FAIL in (test-eval-str) (at /Users/mfikes/Projects/clojurescript/builds/out-self/core-self-test.js:10969:98)
expected: (nil? error)
  actual: (not (nil? #error {:message "Could not eval ", :data {:tag :cljs/analysis-error}, :cause #error {:message "Invalid arity: 4 at line 1 ", :data {:file nil, :line 1, :column 1, :tag :cljs/analysis-error}, :cause #object[Error Error: Invalid arity: 4]}}))


 Comments   
Comment by Mike Fikes [ 10/Aug/15 4:00 PM ]

Regression occurred with this commit: https://github.com/clojure/clojurescript/commit/d435b4395c719644a4a16f0277ae912f61db42a6

Comment by David Nolen [ 10/Aug/15 7:28 PM ]

fixed https://github.com/clojure/clojurescript/commit/04d0b92da513c8e7129e06bc34b19b1801207c32





[CLJS-1417] cljs.js: require macros failure error message pertains to non-macros Created: 10/Aug/15  Updated: 10/Aug/15  Resolved: 10/Aug/15

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

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

Shipping Node REPL


Attachments: Text File CLJS-1417.patch    

 Description   

Repro, via script/noderepljs:

(require 'cljs.js)

(binding [cljs.js/*load-fn* (fn [x cb] (prn x) (cb nil))]
 (cljs.js/require 'foo.bar {:macros-ns true} prn))

this prints

{:name foo.bar, :macros true, :path "foo/bar"}
{:error #error {:message "No such namespace: foo.bar, could not locate foo/bar.cljs, foo/bar.cljc, or Closure namespace \"foo.bar\"", :data {:tag :cljs/analysis-error}}}


 Comments   
Comment by Mike Fikes [ 10/Aug/15 2:07 PM ]

The attached patch adds a new error message which is careful to list the files off in the order specified here (as is done for the non-macros ns error): https://github.com/clojure/clojurescript/blob/v1.7/src/main/cljs/cljs/js.cljs#L61

This patch is effectively adding an error message that would only be used by bootstrapped environments. It could be further revised so that the same error message is emitted if require-macros is called in a regular ClojureScript REPL for a unlocatable namespace. (This patch doesn't revise that behavior, which results in Clojure complaining about __init.class and clj files, but not cljc---perhaps Clojure itself in the future will be revised to mention cljc.

Comment by Mike Fikes [ 10/Aug/15 2:17 PM ]

I created CLJ-1797 covering the 2nd paragraph in the previous comment about require-macros in non-bootstrapped ClojureScript REPLs.

Comment by David Nolen [ 10/Aug/15 10:14 PM ]

fixed https://github.com/clojure/clojurescript/commit/637e247dc57695b153f3deb27b9999f77c2fa015





[CLJS-1416] cljs.util/last-modified leaks files Created: 10/Aug/15  Updated: 10/Aug/15  Resolved: 10/Aug/15

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

Type: Defect Priority: Major
Reporter: Erik Dannenberg Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: newbie
Environment:

windows 8.1



 Description   

Using boot[1] on Windows we run into "could not delete file.." errors as described in #CLJ-1659.

File leak detector[2] suggests the culprit is cljs.util/last-modified:

1 descriptors are open
#1 C:\Users\ed\.boot\cache\tmp\Users\ed\projekte\sente-system\5ho\-c4hx1l\adzerk\boot_reload.cljs by thread:clojure-agent-send-off-pool-0 on Mon Aug 10 17:54:39 CEST 2015
	at java.io.FileInputStream.<init>(FileInputStream.java:139)
	at java.io.FileInputStream.<init>(FileInputStream.java:93)
	at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:90)
	at sun.net.www.protocol.file.FileURLConnection.initializeHeaders(FileURLConnection.java:110)
	at sun.net.www.protocol.file.FileURLConnection.getLastModified(FileURLConnection.java:178)
	at cljs.util$last_modified.invokeStatic(util.cljc:136)
	at cljs.util$last_modified.invoke(util.cljc)
	at cljs.analyzer$requires_analysis_QMARK_.invokeStatic(analyzer.cljc:2179)
	at cljs.analyzer$requires_analysis_QMARK_.invoke(analyzer.cljc)
	at cljs.analyzer$requires_analysis_QMARK_.invokeStatic(analyzer.cljc:2164)
	at cljs.analyzer$requires_analysis_QMARK_.invoke(analyzer.cljc)
	at cljs.analyzer$analyze_file.invokeStatic(analyzer.cljc:2220)
	at cljs.analyzer$analyze_file.invoke(analyzer.cljc)
	at cljs.analyzer$analyze_deps.invokeStatic(analyzer.cljc:1291)
	at cljs.analyzer$analyze_deps.invoke(analyzer.cljc)
	at cljs.analyzer$eval1868$fn__1870.invoke(analyzer.cljc:1545)
	at clojure.lang.MultiFn.invoke(MultiFn.java:251)
	at cljs.analyzer$analyze_seq.invokeStatic(analyzer.cljc:1900)
	at cljs.analyzer$analyze_seq.invoke(analyzer.cljc)
	at cljs.analyzer$analyze$fn__2118.invoke(analyzer.cljc:1992)
	at cljs.analyzer$analyze.invokeStatic(analyzer.cljc:1985)
	at cljs.analyzer$analyze.invoke(analyzer.cljc)
	at cljs.compiler$compile_file_STAR_$fn__3216.invoke(compiler.cljc:1027)
	at cljs.compiler$with_core_cljs.invokeStatic(compiler.cljc:968)
	at cljs.compiler$with_core_cljs.invoke(compiler.cljc)
	at cljs.compiler$compile_file_STAR_.invokeStatic(compiler.cljc:988)
	at cljs.compiler$compile_file_STAR_.invoke(compiler.cljc)
	at cljs.compiler$compile_file$fn__3248.invoke(compiler.cljc:1129)
	at cljs.compiler$compile_file.invokeStatic(compiler.cljc:1109)
	at cljs.compiler$compile_file.invoke(compiler.cljc)
	at cljs.compiler$compile_root.invokeStatic(compiler.cljc:1181)
	at cljs.compiler$compile_root.invoke(compiler.cljc)
	at cljs.closure$compile_dir.invokeStatic(closure.clj:385)
	at cljs.closure$compile_dir.invoke(closure.clj)
	at cljs.closure$eval3614$fn__3615.invoke(closure.clj:425)
	at cljs.closure$eval3567$fn__3568$G__3558__3575.invoke(closure.clj:331)
	at cljs.closure$eval3627$fn__3628.invoke(closure.clj:439)
	at cljs.closure$eval3567$fn__3568$G__3558__3575.invoke(closure.clj:331)
	at adzerk.boot_cljs.impl.CljsSourcePaths$fn__4011.invoke(impl.clj:14)

Example app that should reproduce the error: https://github.com/danielsz/sente-boot

clone, run boot dev, change a source file => file exists errors

[1] http://boot-clj.com/
[2] http://file-leak-detector.kohsuke.org/



 Comments   
Comment by Alex Miller [ 10/Aug/15 1:52 PM ]

The patch at http://dev.clojure.org/jira/secure/attachment/14273/clj-1659-v3.patch for CLJ-1659 may be helpful in creating a patch.

Comment by David Nolen [ 10/Aug/15 10:07 PM ]

fixed https://github.com/clojure/clojurescript/commit/7f29513de3ace7a14df220f4d0be1a8faeb92723





[CLJS-1415] Handling JSDoc param name [x] optional syntax Created: 10/Aug/15  Updated: 11/Aug/15

Status: In Progress
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.48
Fix Version/s: Next

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: David Nolen
Resolution: Unresolved Votes: 0
Labels: type-check





[CLJS-1414] Only munge @param @return if type checking Created: 10/Aug/15  Updated: 10/Aug/15  Resolved: 10/Aug/15

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

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


 Comments   
Comment by David Nolen [ 10/Aug/15 12:34 PM ]

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





[CLJS-1413] Why can't I access goog.math.Long.ONE? Created: 10/Aug/15  Updated: 10/Aug/15  Resolved: 10/Aug/15

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

Type: Defect Priority: Minor
Reporter: Gary Fredericks Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Not sure if this is a bug or misuse, just creating this ticket so it doesn't get lost.

When I upgraded from 1.7.28 to 1.7.48 I had to stop referencing the ONE constant in the Long class (and use .fromNumber(1) as a workaround), and I don't know why. Forcing the old version of GCL fixes the problem. More details in this commit.



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

We periodically bump Google Closure. Are you sure this constant has not been removed?

Comment by Gary Fredericks [ 10/Aug/15 1:32 PM ]

Yep, that's it. I had checked the commit history for that file but did not look closely enough. Removing the constant seemed like such an unlikely thing to happen, but apparently they got some worthwhile dead code removal stuff from it: https://github.com/google/closure-library/commit/f05646269a08e81810ae1b4f921f9a857049a33c.

Sorry for the noise.





[CLJS-1412] Add JSDoc type information to individual IFn methods Created: 10/Aug/15  Updated: 11/Aug/15

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

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: type-check


 Description   

Propagate user supplied docstring type information to the various fn arities so that more code may be checked.






[CLJS-1411] make-array signature differs from clojure Created: 10/Aug/15  Updated: 10/Aug/15

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

Type: Defect Priority: Minor
Reporter: Lars Andersen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: newbie


 Description   

When I was porting clj code using a two-dimensional array I noticed the cljs version only accepts size, instead of dim & more-dims.

Signature in cljs: ([size] [type size])
signature int clj: ([type len] [type dim & more-dims])



 Comments   
Comment by David Nolen [ 10/Aug/15 7:28 AM ]

Unlike on the JVM there's no efficient way to allocate multi-dimensional arrays. An enhancement patch that includes a modification to the docstring that warns about the computational cost is welcome.

Comment by Lars Andersen [ 10/Aug/15 8:00 AM ]

What I want is for the signatures to be the same, so I don't have to use reader conditionals to get the same behavior on the two platforms.

When I'm asking for a two-dimensional array, I'm presumably going to do work that is O(m*n), so even though the pre-allocation is O(m*n) too it won't affect the runtime of the program significantly.

Comment by David Nolen [ 10/Aug/15 8:13 AM ]

Lars, yes I understood As I said patch welcome. This is a very ClojureScript newbie friendly ticket.





[CLJS-1410] Support source maps in deps.cljs Created: 09/Aug/15  Updated: 09/Aug/15

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

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


 Description   

There should be support to package source maps with a foreign-lib using deps.cljs






[CLJS-1409] Allow type checking of protocols Created: 09/Aug/15  Updated: 09/Aug/15  Resolved: 09/Aug/15

Status: Resolved
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.48
Fix Version/s: Next

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


 Comments   
Comment by David Nolen [ 09/Aug/15 10:27 AM ]

fixed https://github.com/clojure/clojurescript/commit/27af25a3e43e4b61ba924f77ed5068717613e026





[CLJS-1408] goog-define docstring wrong Created: 09/Aug/15  Updated: 09/Aug/15  Resolved: 09/Aug/15

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

Type: Defect Priority: Minor
Reporter: Martin Klepsch Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File 0001-fix-goog-define-docstring.patch    
Patch: Code

 Description   

add-implicit-options only munges symbol keys are untouched.
Thus the example given in the docstring is wrong.



 Comments   
Comment by David Nolen [ 09/Aug/15 10:29 AM ]

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





[CLJS-1407] Exposing output file depdenency graph in API Created: 09/Aug/15  Updated: 11/Aug/15

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

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


 Description   

Use case for boot-cljs and boot-reload:

After compilation boot-reload reloads the changed JS files. So that the files can be reloaded in correct order, boot-cljs uses dependency graph to sort the files. Currently boot-cljs accesses compiler state directly and uses data from :js-dependency-index to build the graph: https://github.com/adzerk-oss/boot-cljs/blob/0.0-3308/src/adzerk/boot_cljs/impl.clj#L17-L36

Simple solution:

If dependencies (requires) of namespace are exposed through API it is easy to build graph of cljs namespace dependencies: https://github.com/adzerk-oss/boot-cljs/blob/d479f10935be321232e2363e2ae3e9cc515a81af/src/adzerk/boot_cljs/impl.clj#L12-L32

Problem with this solution is that all-ns, ns-dependencies or target-file-for-cljs-ns do not work with foreign-deps. While foreign-dep files don't usually change and thus aren't reloaded, it's possible that user has local JS files in the project using foreign-deps and those can change.

Questions, notes and issues

  • Should cljs-dependency-graph be exposed in the API or is it enough to provide ns-dependencies and such which user can use to create dependency graph?
  • cljs.build.api/parse-js-ns can also be used to read provides and requires from compiled JS files, but this doesn't work with foreign-deps either
  • Perhaps there is some way in Closure library to reload files in correct order?
  • Supporting foreign-deps is not perhaps necessary, but if there is good way it would be nice to have.


 Comments   
Comment by Juho Teperi [ 11/Aug/15 3:18 AM ]

I would add the call to cljs.compiler.api and it could be called output-dependency-graph.

Creating the graph requires list of all the nodes and dependencies for each node. For Cljs namespaces
these are accessible through all-ns and ns analysis map :requires. Data about foreign-deps
and closure libs is available in the compiler state under :js-dependency-index key. To create the
graph we need to:

1. Get list of all nodes
2. Get dependencies for given node
3. Get output file for given node

Because steps 2 and 3 depend on the type of node, it would probably be easiest to collect those
values in step 1. So step 1 would do something like this:

{{(get-nodes ...) => {:provides "goog.net" :file "out/goog/net.js" :dependencies #{"goog.foo"}} {:provides "frontend.core" :file "out/frontend/core.js" :dependencies #{"cljs.core"}}}}

That could be implemented by concatenating data from cljs namespaces retrieved from all-ns etc. with
data from :js-dependency-index. The next and last step would be to construct the graph using reduce.

Using this implementation there would be just one new API call: output-dependency-graph.

I was thinking alternative approach with all-ns, find-ns etc. versions which would work also with foreign-deps and closure libs, but I don't think it's very easy (or efficient) e.g. to retrieve data for foreign-dep with just a name as they are indexed by file paths.





[CLJS-1406] macroexpand munging goog.string.StringBuffer Created: 09/Aug/15  Updated: 14/Aug/15

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

Type: Defect Priority: Minor
Reporter: Matthew Molloy Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bootstrap
Environment:

Bootstrapped Planck REPL


Attachments: Text File cljs_1406.patch     Text File cljs_1406_test.patch    

 Description   

(macroexpand '(with-out-str)) on bootstrapped ClojureScript gives (let* [sb__13582__auto__ (string.StringBuffer.)]...
on JVM compiled ClojureScript it is (let* [sb__1155__auto__ (goog.string.StringBuffer.)]...

goog.string.StringBuffer has been incorrectly munged to string.StringBuffer when the cljs.js compiler is used.



 Comments   
Comment by Joel Martin [ 13/Aug/15 7:28 PM ]

I ran into this today. Here is a test case for the self host tests that reproduces the problem.

Comment by Joel Martin [ 13/Aug/15 7:50 PM ]

Fix the test. Propose a fix that just puts "js/" in front to prevent the broken name resolution. Probably not the correct solution, but it does work.

Comment by David Nolen [ 14/Aug/15 7:50 PM ]

Not going to take the current patches. The underlying resolution issue needs to be fixed.





[CLJS-1405] type resolution needs to handle modifiers like leading !, trailing =, object syntax Created: 08/Aug/15  Updated: 08/Aug/15  Resolved: 08/Aug/15

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

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


 Comments   
Comment by David Nolen [ 08/Aug/15 3:12 PM ]

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





[CLJS-1404] var resolution for @param and @return type Created: 08/Aug/15  Updated: 10/Aug/15  Resolved: 10/Aug/15

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

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


 Description   

Adding typing information is tedious due to namespacing. We should resolve @param and @return to avoid the boilerplate.



 Comments   
Comment by David Nolen [ 10/Aug/15 10:10 PM ]

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





[CLJS-1403] Add script/bootstrap capability for Windows Created: 08/Aug/15  Updated: 26/Aug/15  Resolved: 26/Aug/15

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

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

All versions of Windows


Attachments: Text File cljs-1403-v2.patch     Text File cljs-1403-v3.patch    

 Description   

Implement a Windows shell script to download and unpack the correct versions of various ClojureScript dependencies.

Proposal: Implement a PowerShell script to do this work. PowerShell has been pre-installed on Windows since version 7 and is available (in various flavors) on Windows down to XP.

1. Downloading of files from the web is a proper command (Invoke-RestMethod) in PowerShell since version 3. Earlier versions of PowerShell could be supported by using Dotnet's WebClient.DownloadFile method.

2. Unzipping files is a little more difficult. But the GUI shell's capability is exposed through COM and this appears to work well from PowerShell.

3. The current dependency versions can be extracted from the /bin/sh script using regex.

See https://gist.github.com/pstephens/b260b1ad8b166489b562 for a rough draft of this script.



 Comments   
Comment by Peter Stephens [ 08/Aug/15 1:15 PM ]

Related issues: CLJS-24 and CLJS-66, both closed.

Comment by Peter Stephens [ 08/Aug/15 9:05 PM ]

Almost have a patch ready to submit... but lot's of the Windows shell wrappers are also broken. Working through the problems so I can hopefully get through the test suite on Windows.

Comment by David Nolen [ 09/Aug/15 10:25 AM ]

Thanks for working on this!

Comment by Peter Stephens [ 11/Aug/15 9:28 PM ]

This patch includes some basic Windows support scripts.
1. A port of script/bootstrap to PowerShell
2. A port of script/test to PowerShell
3. Updated bin/cljsc.bat to match bin/cljsc
4. And a minor tweak to bin/cljsc.clj to write exceptions to stderr and describe the nature of the exception.

Comment by Peter Stephens [ 11/Aug/15 9:46 PM ]

Tested on Windows 10 w/fresh clojurescript clone.

Bootstrap pulled down required dependencies.

Ran the test suite through Nashorn with two (apparently known) failing tests:
FAIL in (test-919-generic-cas) (at <anonymous> (builds/out-adv/core-advanced-test.js:NaN:963)
testing CLJS-919, CAS should on custom atom types
expected: (== (clojure.core/deref a0) 10)
actual: (not (== nil 10))

FAIL in (test-919-generic-cas) (at <anonymous> (builds/out-adv/core-advanced-test.js:NaN:963)
testing CLJS-919, CAS should on custom atom types
expected: (== (clojure.core/deref a1) 20)
actual: (not (== nil 20))

I couldn't find a Jira issue describing these failures but some work was done by Sebastian Bensusan on this: http://www.raynes.me/logs/irc.freenode.net/clojurescript/2015-04-20.txt and https://gist.github.com/bensu/c6302a33e56d5d7eae9e

Comment by David Nolen [ 12/Aug/15 6:49 AM ]

Patch looks good but I could not apply with git am. Did you following the patch instructions here https://github.com/clojure/clojurescript/wiki/Patches?

Also please submit only squashed patches. Thanks!

Comment by Peter Stephens [ 12/Aug/15 9:18 PM ]

Apparently there are encoding and and line ending issues from Windows generated patches using the linked patching instructions. I'll squash the commits and work out the encoding issues. Then I'll test-apply the patch to a fresh clone of master before resubmitting.

Comment by Peter Stephens [ 16/Aug/15 9:59 PM ]

1. Squished the patch. There is now only one commit.
2. Created the patch with Windows git bash shell. So the encoding is in proper ASCII without extra fluff.

NOTE: The batch and PowerShell files are encoded with CRLF... so special care needs to be taken when applying this patch. Here is the command I used:

git am --keep-cr --whitespace=nowarn < cljs-1403-v3.patch

The patch will not apply without keep-cr because the CR characters will be stripped out. The whitespace=nowarn option suppresses warnings but the patch will still apply without this option.

Comment by David Nolen [ 26/Aug/15 10:24 PM ]

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





[CLJS-1402] Source Mapping Closure Error Logger Created: 08/Aug/15  Updated: 11/Aug/15

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

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: type-check


 Description   

Current error reports generated by Google Closure point back to the generated JavaScript sources. For JavaScript source that originated from ClojureScript we should generated source mapped reports.






[CLJS-1401] Unify runtime & compile time UUID hash calculation Created: 08/Aug/15  Updated: 08/Aug/15  Resolved: 08/Aug/15

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

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


 Comments   
Comment by David Nolen [ 08/Aug/15 10:06 AM ]

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





[CLJS-1400] self-host: doseq stuck on first item Created: 07/Aug/15  Updated: 12/Aug/15

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

Type: Defect Priority: Major
Reporter: Chris Truter Assignee: Chris Truter
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 1400.patch     Text File infinite_loop2.patch     Text File infinite_loop.patch    
Approval: Vetted

 Description   

When a doseq appears in non-terminal position inside a do block, it "iterates" repeatedly over the first element only.

This only affects bootstrapped clojurescript, but can be supported with a vanilla cljs.js setup and the last example below.

Correctly prints 1 and then 2:

(do :before (doseq [x [1 2]] (println x)))

Correctly does not iterate, and returns :after

(do (doseq [x []] (println x)) :after)

Incorrectly prints 1 ad infinitum

(do (doseq [x [1 2]] (println x)) :after)

Example code including bootstrapping:

(def source "(do (doseq [e [1 2]] (println e)) 3)")

(cljs/eval-str
  (cljs/empty-state)
  source
  source
  {:eval       cljs/js-eval
   :source-map false
   :verbose    true}
  prn)

For convenience a repo to run this example is here:

https://github.com/crisptrutski/do-doseq-bootstrapped



 Comments   
Comment by David Nolen [ 07/Aug/15 6:38 AM ]

We do not take issues that involve 3rd party projects. This ticket needs to reproduced with ClojureScript only before proceeding any further.

Comment by David Nolen [ 07/Aug/15 7:14 AM ]

Reproduced. The patch should include a test case addition to src/test/self/self_host/test.cljs.

Comment by Joel Martin [ 07/Aug/15 9:55 AM ]

Here is a patch that adds a test which reproduces the problem.

Comment by Joel Martin [ 07/Aug/15 10:00 AM ]

Update patch with corrected success condition.

Comment by Chris Truter [ 12/Aug/15 8:18 AM ]

Added slightly more minimal test, that excludes do (still not a great test), and solve the issue by partially reverting this optimization

Perhaps

(-hash (select-keys binding [:name :shadow]))
is sufficient and more performant?

Comment by David Nolen [ 12/Aug/15 8:46 AM ]

If you're are going to mention commits, please link to them thanks.





[CLJS-1399] Unnecessarily escaped forward-slash in regex produces invalid JS Created: 07/Aug/15  Updated: 07/Aug/15  Resolved: 07/Aug/15

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

Type: Defect Priority: Minor
Reporter: Chris Truter Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

When compiling an escaped forward slash in a regex literal (muscle memory from Javascript syntax), ClojureScript will emit invalid Javascript, ie. it will emit an escaped back slash instead, and a terminating forward slash.

In bare node repl:

(re-find #"\/" "a/b")

generates the invalid expression:

(function (){var ret__3746__auto__ = cljs.core.re_find.call(null,/\\//,"a/b");

Interestingly both this and the unescaped variation (#"/") work correctly in Planck (and regular Clojure).

Creating the regex manually throws a reader error, because the string literal is illegal:

cljs.user=> "\/"
clojure.lang.ExceptionInfo: Unsupported escape character: \/ {:type :reader-exception, ...}

Unsure of whether a reader error or "we know what you meant" behaviour is preferable.



 Comments   
Comment by David Nolen [ 07/Aug/15 6:36 AM ]

Wary of "we know what you meant". I suspect there will be many cases like this. By the same token wary of specific error messages here, how many cases will we need to cover?

Comment by Chris Truter [ 07/Aug/15 8:00 AM ]

Thanks for the help David, I've confirmed this is an issue in tools.reader.





[CLJS-1398] (update-in {} [] assoc :a 1) yields {nil {:a 1}} Created: 07/Aug/15  Updated: 07/Aug/15  Resolved: 07/Aug/15

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

Type: Defect Priority: Major
Reporter: Mike Longworth Assignee: Unassigned
Resolution: Declined Votes: 0
Labels: None


 Description   

Current behaviour:

(update-in {} [:x :y] assoc :a 1)
{:x {:y {:a 1}}}

(update-in {} [:x] assoc :a 1)
{:x {:a 1}}

(update-in {} [] assoc :a 1)
{nil {:a 1}}

I would expect: (update-in {} [] assoc :a 1)
to yield: {:a 1}



 Comments   
Comment by Francis Avila [ 07/Aug/15 4:01 AM ]

Clojure has the same behavior, and assoc-in also behaves similarly.

This is a long-standing bug (or wart, or at least personal pet-peeve) that is probably never going to be fixed for unknown reasons. Related tickets:

CLJ-373 CLJ-1520 CLJ-1064 CLJ-1623

Comment by Mike Longworth [ 07/Aug/15 4:29 AM ]

Ok thanks Francis, I should have dug deeper myself on this one; an easy local fix but it was the cause of some less than obvious issues.





[CLJS-1397] Honor :def-emits-var for def w/o init and declare Created: 06/Aug/15  Updated: 10/Aug/15  Resolved: 10/Aug/15

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

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

Approval: Vetted

 Description   

Currently :def-emits-var works only if there is an init form. (In particular, the change for CLJS-934 did not revise the when init aspect of emit* def.) This ticket asks that :def-emits-var be extended to cover this case as well.

Additionally, this ticket asks that the same be made to hold true for declare (if it is not already implicitly take care of the def without init case.

Rationale:

  1. It is justifiable in and of itself. (:def-emits-var should work unconditionally whether a def has an init).
  2. A consequence for normal REPL use would be that init-less def forms would work at the REPL and declare would work at the REPL without complaining.

The second issue above (REPL use) wouldn't be taken care of if :def-emits-var is explicitly turned off.



 Comments   
Comment by Mike Fikes [ 10/Aug/15 2:37 PM ]

No longer reproducible in master (for both def and declare), likely as a result of surrounding Google Closure type stuff: https://github.com/clojure/clojurescript/commit/5800cfba697c8c261d8a3ff4c22a49fb749a827b





[CLJS-1396] Allow starting Node.js with debug port set Created: 06/Aug/15  Updated: 06/Aug/15  Resolved: 06/Aug/15

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

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


 Description   

Currently this is not configurable. Should be able to supply :debug-port.



 Comments   
Comment by David Nolen [ 06/Aug/15 2:38 PM ]

fixed https://github.com/clojure/clojurescript/commit/139da195125110646f8d5550fc753fdbf63f565c





[CLJS-1395] closure won't compile goog-define output Created: 06/Aug/15  Updated: 06/Aug/15  Resolved: 06/Aug/15

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

Type: Defect Priority: Major
Reporter: Michael Ballantyne Assignee: Unassigned
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1395-no-trailing-semicolons-after-JS-comments.patch    

 Description   

The goog-define macro translates a declaration like

(goog-define "myvar" 5)

to

/** @define {number} */;

goog.define("cljs_bootstrap.core.myvar",(5));}}

Compiling with :optimizations :simple leads to an error like this:

WARNING: /Users/michaelb/Desktop/nodebuild/goog-define-bug/test/out/goog_define_test/core.js:5: WARNING - Misplaced type annotation. Type annotations are not allowed here. Are you missing parentheses?
/** @define {number} */;

Closure doesn't seem to like the semicolon between the comment and the goog.define().



 Comments   
Comment by Michael Ballantyne [ 06/Aug/15 1:24 PM ]

I should've provided the complete error:

Reading analysis cache for jar:file:/Users/michaelb/.m2/repository/org/clojure/clojurescript/1.7.61/clojurescript-1.7.61.jar!/cljs/core.cljs
Compiling src/goog-define-test/core.cljs
Compiling out/cljs/core.cljs
Applying optimizations :simple to 13 sources
Aug 06, 2015 12:06:33 PM com.google.javascript.jscomp.LoggerErrorManager println
WARNING: /Users/michaelb/Desktop/nodebuild/goog-define-bug/test/out/goog_define_test/core.js:5: WARNING - Misplaced type annotation. Type annotations are not allowed here. Are you missing parentheses?
/** @define {number} */;
                       ^

Aug 06, 2015 12:06:33 PM com.google.javascript.jscomp.LoggerErrorManager println
SEVERE: /Users/michaelb/Desktop/nodebuild/goog-define-bug/test/out/goog_define_test/core.js:7: ERROR - Missing @define annotation
goog.define("goog_define_test.core.myvar",(5));
^

Aug 06, 2015 12:06:33 PM com.google.javascript.jscomp.LoggerErrorManager printSummary
WARNING: 1 error(s), 1 warning(s)
ERROR: JSC_INVALID_MISSING_DEFINE_ANNOTATION. Missing @define annotation at /Users/michaelb/Desktop/nodebuild/goog-define-bug/test/out/goog_define_test/core.js line 7 : 0
WARNING: JSC_MISPLACED_ANNOTATION. Misplaced type annotation. Type annotations are not allowed here. Are you missing parentheses? at /Users/michaelb/Desktop/nodebuild/goog-define-bug/test/out/goog_define_test/core.js line 5 : 23
Comment by Martin Klepsch [ 06/Aug/15 2:36 PM ]

Attached a patch with rudimentary checking if a comment is being emitted.
If a comment is emitted it's not emitted via emit-wrap but plain emits.

Comment by David Nolen [ 06/Aug/15 6:17 PM ]

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





[CLJS-1394] reify gensyms can clash Created: 05/Aug/15  Updated: 05/Aug/15  Resolved: 05/Aug/15

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

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


 Description   

The gensym is naive, should be namespaced.



 Comments   
Comment by David Nolen [ 05/Aug/15 7:27 PM ]

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





[CLJS-1393] *target* is not overridden by :target :nodejs when :optimizations :none Created: 05/Aug/15  Updated: 08/Aug/15  Resolved: 08/Aug/15

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

Type: Defect Priority: Major
Reporter: Michael Ballantyne Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: newbie

Attachments: Text File 0001-CLJS-1393-turn-target-into-goog-define.patch    

 Description   

target at https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L20 is an @define variable, but doesn't use the goog-define macro. When configuring a build with :target :nodejs :optimizations :none, target still dereferences to the value "default".

Can this be made a goog-define?



 Comments   
Comment by Martin Klepsch [ 08/Aug/15 6:20 AM ]

Seems that simply changing the def to goog-define is enough

Comment by David Nolen [ 08/Aug/15 10:07 AM ]

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





[CLJS-1392] cljs.repl/source regression Created: 05/Aug/15  Updated: 05/Aug/15  Resolved: 05/Aug/15

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

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


 Description   

cljs.repl/source no longer works in the builtin REPLs.



 Comments   
Comment by David Nolen [ 05/Aug/15 5:39 PM ]

fixed https://github.com/clojure/clojurescript/commit/18d2cce8fabfc90732f7502ba3460fe168d3f2bc





[CLJS-1391] Error when building for target :nodejs Created: 04/Aug/15  Updated: 05/Aug/15  Resolved: 05/Aug/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-1391.patch    

 Description   

I introduced this one with the last patch for js transforms (CLJS-1177). I get the following error when building for target nodejs:

Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.Associative
at clojure.lang.RT.assoc(RT.java:778)
at clojure.core$assoc__4142.invoke(core.clj:191)
at cljs.closure$write_javascript.invoke(closure.clj:1353)



 Comments   
Comment by Maria Geller [ 04/Aug/15 1:58 PM ]

Attached patch for this one. When writing out javascript, check for map before assigning javascript source to :source key.

Comment by David Nolen [ 05/Aug/15 10:59 AM ]

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





[CLJS-1390] clojure.walk treats vectors diffently from Clojure version Created: 03/Aug/15  Updated: 03/Aug/15

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

Type: Defect Priority: Minor
Reporter: Leon Grapenthin Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

The latest patch to clojure.walk (https://github.com/clojure/clojurescript/commit/f706fabfd5f952c4dfb4dc2caeea92f9e00d8287) ports the line of the Clojure version

(instance? clojure.lang.IMapEntry form) (outer (vec (map inner form)))

with the line

(satisfies? IMapEntry form) (outer (vec (map inner form)))

ClojureScript implements IMapEntry on any vector which I assume is intended.

In Clojure, for vectors this case falls:

(coll? form) (outer (into (empty form) (map inner form)))

This makes a difference because empty preserves metadata.
I. e.

(meta (prewalk (fn [form]
                  (vary-meta form assoc :foo true))
               []))

gives {:foo true} on earlier ClojureScript versions and Clojure, but nil on the latest version.

I have relied on this which has likely not been a very good idea, but others might have too - Hence I created this ticket for consideration.






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

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

Type: Enhancement Priority: Minor
Reporter: Martin Klepsch Assignee: David Nolen
Resolution: Completed Votes: 0
Labels: None

Attachments: Text File CLJS-1389-provide-define-macro-to-support-proper-use.patch     Text File CLJS-1389-provide-define-macro-to-support-proper-use.patch    

 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



 Comments   
Comment by David Nolen [ 03/Aug/15 5:14 AM ]

Why can't we just emit CLOSURE_DEFINES under :none? If user supplies :main this is simple to do here https://github.com/clojure/clojurescript/blob/d946a58153ec5132063f1ac29acd8d4bcd1bdeb2/src/main/clojure/cljs/closure.clj#L1124-L1143

If this cannot work there should be documentation on this ticket as to why. Thanks!

Comment by Martin Klepsch [ 03/Aug/15 6:06 AM ]

I created a sample in the Clojurescript repo to illustrate this: https://github.com/martinklepsch/clojurescript/tree/defines-in-none/samples/defines

TLDR; goog.define is not just sugar and is required to look things up at runtime from CLOSURE_DEFINES and CLOSURE_UNCOMPILED_DEFINES.

Copy of the README:

Custom Defines in :none

See CLJS-1389.

Most straightforward solution would be to prepend CLOSURE_UNCOMPILED_DEFINES or CLOSURE_DEFINES to the main file as
done in 9962889. Unfortunately
this won't work. Values in these globals are only looked up at runtime when something has been defined with

/** @define {boolean} */
goog.define('my.thing.DEBUG', false)

See source of goog.define.
In comparison defining something through CLJS will result in the following

(def ^{:jsdoc ["@define {boolean}"]}
  DEBUG true)

compiles to:

/**
 * @define {boolean}
 */
my.thing.DEBUG = true;

The @define JSDoc tag is appropriately set but since there is no runtime lookup no values from CLOSURE_DEFINES or CLOSURE_UNCOMPILED_DEFINES will be used.
In comparison goog.define does the runtime lookup.

There is an example in this directory where you can see that modifying the :closure-defines passed to the compiler will not have any effect on the compiled core.js.

Docstrings for CLOSURE_DEFINES and CLOSURE_UNCOMPILED_DEFINES are also interesting.

Possible solution

Using goog.define instead of just the :jsdoc metadata would allow
overriding in all optimization modes. Emitting goog.define properly without
causing warnings or errors requires the following:

1. The goog.define call needs to be annotated with the JSDoc @define tag.
2. We need to declare the var defined, otherwise there will be undeclared Var warnings

There's a macro in samples/defines/src/hello_world/core.clj that I
wrote while experimenting what's required to make this work.

Comment by Martin Klepsch [ 03/Aug/15 11:19 AM ]

Patch introducing cljs.core/define macro and prepending :closure-defines to main file.

EDIT: I settled on using CLOSURE_UNCOMPILED_DEFINES because it seemed most appropriate given
that it's only ever used in "uncompiled" mode.

Comment by Martin Klepsch [ 03/Aug/15 12:16 PM ]

Please review/give feedback.

Comment by David Nolen [ 03/Aug/15 1:49 PM ]

This patch needs to be rebased to master.

Comment by Martin Klepsch [ 03/Aug/15 1:53 PM ]

rebased patch on master

Comment by David Nolen [ 03/Aug/15 2:01 PM ]

fixed https://github.com/clojure/clojurescript/commit/5ef5f10ab87b8cafbb13ce5b55e81d5b4fd655d9

Comment by Martin Klepsch [ 04/Aug/15 8:20 AM ]

cljs.core/define has been renamed to cljs.core/goog-define.
https://github.com/clojure/clojurescript/commit/37ce674742f2969597cbb3b5e25dfa0cc77bd619





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

Status: Resolved
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: Completed 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"})


 Comments   
Comment by David Nolen [ 03/Aug/15 5:50 AM ]

fixed https://github.com/clojure/clojurescript/commit/49f3ea9c1e5064bacb3e13d29f5f3f18af1f4bc1





[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: 1.7.48

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: 1.7.48

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] self-host: Macroexpansion defeated when calling helper Created: 29/Jul/15  Updated: 11/Aug/15  Resolved: 11/Aug/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:

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.

Comment by David Nolen [ 10/Aug/15 10:09 PM ]

If we can't get a reproducer for this will close soon

Comment by Mike Fikes [ 11/Aug/15 10:30 AM ]

The root cause is that cljs.tools.reader/resolve-symbol is not bound.

Adding the binding pair r/resolve-symbol ana/resolve-symbol to cljs.js/eval-str* resolves the issue, but the correct fix may involve binding this in other entry points as well.

Still working on trying to put together a good repro. An ideal place would be self-host.test test-eval-str-with-require, but something is preventing those tests from running under Node.js (it looks like the ns form that creates foo.bar derails because the outer foo object is not created. Interestingly, if I use JavaScriptCore (via Planck, pointed at clojurescript/src/test/self as its source directory), and I also rename helper.clj -> helper.cljc, I am able to make a lot of progress (repro the issue and have augmented test cases pass, with the right changes).

So, I think the key to progress on this one is to get these tests to run under Node.js. I'll see if I can get them to work.

Comment by David Nolen [ 11/Aug/15 4:03 PM ]

possible fix on master that needs testing.

Comment by Mike Fikes [ 11/Aug/15 4:53 PM ]

Confirmed fixed using downstream Planck REPL.

As an aside, even though regular ClojureScript REPLs (like Ambly) need the additional (require 'foo.helper) prior to (require-macros 'foo.macros) in order for this code to work, Planck (and probably all bootstrapped REPLs), can simply issue (require-macros 'foo.macros) and have the code work. (In other words, bootstrapped ClojureScript appears to be capable of loading the transitive dependency for this case.)

Comment by David Nolen [ 11/Aug/15 5:20 PM ]

fixed https://github.com/clojure/clojurescript/commit/2677ff7a595e872d9393237818894d84a0214083





[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: 05/Aug/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.48
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: 26/Aug/15  Resolved: 26/Aug/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: None

Attachments: Text File CLJS-1353-14-Aug-15.patch     Text File CLJS-1353-15-Aug-15.patch    
Patch: Code and Test

 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)


 Comments   
Comment by Samuel Miller [ 14/Aug/15 9:57 PM ]

Uploaded potential patch with updated tests.

Clojures implementation can be seen here...

https://github.com/clojure/clojure/blob/41af6b24dd5be8bd62dc2b463bc53b55e18cd1e5/src/jvm/clojure/lang/Range.java#L89

Basically what is boils down to is as long as the start and end are not equal give back the start number if the step is 0 (effectively repeat). Tried to keep the previous code for range the same and added a case for zero that checks for the equality of start and end.

Ran tests on Linux against SpiderMonkey, V8, and Nashorn they passed. Played around in the repl and compared against Clojure and seems to be equivalent.

Comment by Mike Fikes [ 14/Aug/15 11:51 PM ]

With CLJS-1353-14-Aug-15.patch, tests pass for me on OS X for V8, SpiderMonkey, and JavaScriptCore.

I also tried it in bootstrapped ClojureScript in JavaScriptCore on OS X, manually running the tests successfully.

Thinking about perf, it looks like it doesn't really affect the (probably common) code path for positive steps, and only adds one more necessary check to distinguish between negative and zero (which wasn't being done before). In the zero-step branch (which is probably not common at all), there is perhaps a tiny benefit in using == over = since we can assume numeric arguments. (You end up with a direct start === end as opposed to cljs.core._EQ_ being applied.)

There is one other bit of code that employs that pattern: https://github.com/clojure/clojurescript/blob/r1.7.48/src/main/cljs/cljs/core.cljs#L5058

Comment by David Nolen [ 15/Aug/15 5:22 PM ]

Yes the test should be changed to ==. Thanks.

Comment by Samuel Miller [ 15/Aug/15 11:19 PM ]

Thanks for the reviews. I updated the patch to use == instead of =

Comment by David Nolen [ 26/Aug/15 10:41 PM ]

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





[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: 05/Aug/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.48
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: 05/Aug/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.48
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: 05/Aug/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.48
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: 05/Aug/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.48
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] self-host: .toString on int needs parens Created: 08/Jul/15  Updated: 18/Aug/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$()"
  • Note the lack of parens CLJS-715
  • Note the dollar sign after fn name is covered by separate ticket CLJS-1430





[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: 05/Aug/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.48
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: 05/Aug/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.48
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: 05/Aug/15

Status: Open
Project: ClojureScript
Component/s: None
Affects Version/s: 1.7.48
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 converted JS modules Created: 17/Jun/15  Updated: 17/Aug/15  Resolved: 17/Aug/15

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

Type: Defect Priority: Major
Reporter: Mike Fikes Assignee: Maria Geller
Resolution: Completed 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.)

Comment by Maria Geller [ 12/Aug/15 6:15 PM ]

We are making progress with this one. A PR has just been merged into the Google Closure compiler that fixes the problem for CommonJS and AMD modules: https://github.com/google/closure-compiler/pull/1071. We will need to make a second PR for ECMAScript 6.

The reason that this failed before is, that when the JS modules are converted to Google Closure modules the new namespaces are declared as local, which is different from "normal" Google Closure modules. Since the Node REPL runs scripts in a separate context, the namespace functionality will not be seen outside this context.

Comment by Maria Geller [ 17/Aug/15 1:48 PM ]

The fix for converted ES6 modules has been merged into the Google Closure compiler: https://github.com/google/closure-compiler/pull/1081.

This should work now for all three module types. I think, this can be closed

Comment by David Nolen [ 17/Aug/15 6:07 PM ]

fixed





[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: 14/Aug/15  Due: 21/Aug/15  Resolved: 14/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: 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

Comment by Maria Geller [ 13/Aug/15 1:49 PM ]

This has been merged into the Google Closure compiler and seems to work: https://github.com/google/closure-compiler/commit/aa0a99cf380b05b2185156735d023b6fa78ec4ac

Should be good to close now





[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: