<< Back to previous view

[CLJS-112] clojure.data.json -- Read and write JSON strings to/from clojure data structures Created: 16/Dec/11  Updated: 16/Dec/11  Due: 31/Dec/11

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

Type: Enhancement Priority: Minor
Reporter: Bobby Calderwood Assignee: Bobby Calderwood
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-Added-clojure.data.json.patch    
Patch: Code

 Description   

Reading and writing JSON is a common requirement in both server- and client-side applications. ClojureScript needs a way to transform ClojureScript data into JSON, and vice-versa.






[CLJS-150] Regular expressions don't support Javascript mode flags Created: 16/Feb/12  Updated: 16/Feb/12  Due: 24/Feb/12

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

Type: Defect Priority: Major
Reporter: Bobby Calderwood Assignee: Bobby Calderwood
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Currently, the compiler and cljs.core allow for Java mode flags. Javascript doesn't support many of these, and supports one flag not supported by Java - 'g'.

ClojureScript regular expressions should support only Javascript regex mode flags: 'i', 'm', and 'g'. This applies to Regex literals in the compiler as well as (re-pattern).

This is a defect in the implementation of CLJS-116.



 Comments   
Comment by David Nolen [ 16/Feb/12 3:33 PM ]

The defect existed prior to CLJS-116. The problem is that we're using the Clojure reader and g is not a valid flag for a Java RegexPattern.





[CLJS-27] Conditional compilation (or reading) Created: 22/Jul/11  Updated: 27/Jul/12

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

Type: Enhancement Priority: Major
Reporter: Rich Hickey Assignee: Unassigned
Resolution: Unresolved Votes: 9
Labels: None

Attachments: File conditional-compilation-clojure.diff     File conditional-compilation-clojurescript.diff    
Patch: Code and Test
Approval: Vetted

 Description   

As people start trying to write libs that are portable between Clojure and ClojureScript they might need to have a bit of branching on target. N.B. supporting this means a change to Clojure, although it has general utility there as well.

Consider CL #+ #- reader macros - http://www.lispworks.com/documentation/lw50/CLHS/Body/02_dhq.htm



 Comments   
Comment by Roman Scherer [ 19/Jul/12 8:52 AM ]

The following patches include an implementation of Common Lisp's #+
and #- reader macros to allow conditional compilation/reading for
Clojure and ClojureScript.

The patches add a dynamic variable called features to the
clojure.core and cljs.core namespaces, that should contain the
supported features of the platform in question as keywords.

Unlike in Common Lisp, the variable is a Clojure set and not a list.
In Clojure the set contains at the moment the :clojure keyword, and in
ClojureScript the :clojurescript keyword.

I would like to get feedback on the names that are added to this
variable. Are those ok? Is :jvm for Clojure and :js for ClojureScript
better? Should ClojureScript add something like :rhino, :v8 or
:browser as well?

To run the ClojureScript tests, drop a JAR named "clojure.jar" that
has the Clojure patch applied into ClojureScript's lib directory.

Comment by David Nolen [ 19/Jul/12 12:18 PM ]

This is an enhancement so it probably requires a design page and extended discussion before it will go anywhere. Until that happens I'm marking this is as low priority.

Comment by Roman Scherer [ 19/Jul/12 1:45 PM ]

Ok. If someone could give me write access to the Clojure Dev Wiki I would be happy to start such a design page.

Comment by David Nolen [ 19/Jul/12 5:50 PM ]

If you've sent in your CA request permissions on the clojure-dev mailing list.

Comment by Roman Scherer [ 21/Jul/12 5:45 AM ]

I started a design page for this ticket in the Clojure Dev wiki:
http://dev.clojure.org/display/design/Feature+Expressions

Comment by Stuart Halloway [ 27/Jul/12 1:48 PM ]

Posting my comments over on the design page...





[CLJS-77] Add support for Closure defines Created: 18/Sep/11  Updated: 31/May/12

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

Type: Enhancement Priority: Major
Reporter: John Li Assignee: Unassigned
Resolution: Unresolved Votes: 2
Labels: None

Attachments: File define.diff    
Patch: Code

 Description   

The Closure compiler has "--define" which allows you to set some library values at compile time. The settable values are annotated with "@define": https://code.google.com/closure/compiler/docs/js-for-compiler.html

The particular values I was interested in were goog.dom.ASSUME_{QUIRKS,STANDARDS}_MODE because it would save some code and runtime computation if the rendering mode is known at compile time. (It turns out to be very minor for my tiny test program, but probably more substantial for things that use more of the Closure library.) goog.DEBUG also seems useful to tweak.

The attached patch supports a new compile option :define, along with a map from keys/strings to values. The Closure compiler takes a -define option like: "-define='goog.DEBUG=false'". In ClojureScript, this would be {:define {"goog.DEBUG" false}} or {:define {:goog.DEBUG false}}.



 Comments   
Comment by Rafal Babinicz [ 26/Jan/12 11:26 AM ]

Benefits:
Better support for mobile (Android, iOS, iPad) development in ClojureScript.

Problem:
Please add support for passing "--define" option to compiler.jar.
With this we can optimize code performance where only mobile browsers are our target.

Resources:
goog.userAgent global props: http://closure-library.googlecode.com/svn/docs/closure_goog_useragent_useragent.js.html
goog.userAgent.product global props: http://closure-library.googlecode.com/svn/docs/closure_goog_useragent_product.js.html
"java -jar compiler.jar --help" for all available options
Google Closure Definitive Guide at Google Books: http://books.google.pl/books?id=p7uyWPcVGZsC

clojurescript/src/clj/cljs/closure.clj: functions "make-options" and "set-options"

"TODO: Add any other options that we would like to support."
(defn set-options
"TODO: Add any other options that we would like to support."
[opts ^CompilerOptions compiler-options]
(when (contains? opts :pretty-print)
(set! (.prettyPrint compiler-options) (:pretty-print opts)))
(when (contains? opts :print-input-delimiter)
(set! (.printInputDelimiter compiler-options)
(:print-input-delimiter opts))))
(defn make-options
"Create a CompilerOptions object and set options from opts map."
[opts]
(let [level (case (:optimizations opts)
:advanced CompilationLevel/ADVANCED_OPTIMIZATIONS
:whitespace CompilationLevel/WHITESPACE_ONLY
:simple CompilationLevel/SIMPLE_OPTIMIZATIONS)
compiler-options (doto (CompilerOptions.)
(.setCodingConvention (ClosureCodingConvention.)))]
(do (.setOptionsForCompilationLevel level compiler-options)
(set-options opts compiler-options)
compiler-options)))

Comment by Sergei Lebedev [ 31/May/12 3:22 PM ]

One more usecase, I've stumbled upon, while wrapping goog.i18n, here's a line from goog/base.js:59:

/**
 * @define {string} LOCALE defines the locale being used for compilation. It is
 * used to select locale specific data to be compiled in js binary. BUILD rule
 * can specify this value by "--define goog.LOCALE=<locale_name>" as JSCompiler
 * option.

So, without --define it's simply impossible to create i18n apps with ClojureScript and Closure Library.

Comment by Sergei Lebedev [ 31/May/12 4:32 PM ]

Attached patch doesn't work with the latest master.





[CLJS-109] Compiler errors/warnings should be displayed when cljs namespace 'package' names start with an unacceptable javascript symbol. Created: 29/Nov/11  Updated: 31/Aug/12

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

Type: Defect Priority: Major
Reporter: Benjamin Conlan Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None
Environment:

OSX 10.7



 Description   

Clojurescript namespaces are extremely flexible. The generated javascript symbol names are not. ie:

cljs:
[code]
(ns canvas.context.2d)

(defn ^:export create-image-data
([canvas image-data] (.createImageData image-data))
([canvas sw sh] (.createImageData canvas sw sh)))
[/code]

generated js:
[code]
goog.provide('canvas.context.2d');
goog.require('cljs.core');
canvas.context.2d.create_image_data = (function() {
var create_image_data = null;
var create_image_data__2432 = (function (canvas,image_data){ return image_data.createImageData(); });
var create_image_data__2433 = (function (canvas,sw,sh){ return canvas.createImageData(sw,sh); });
create_image_data = function(canvas,sw,sh){
switch(arguments.length){ case 2 : return create_image_data__2432.call(this,canvas,sw); case 3 : return create_image_data__2433.call(this,canvas,sw,sh); }
throw('Invalid arity: ' + arguments.length);
};
return create_image_data;
})()
;
goog.exportSymbol('canvas.context.2d.create_image_data', canvas.context.2d.create_image_data);[/code]

Note the symbol name "canvas.context.2d.create_image_data". Because of the "2d" namespace name, the javascript generated is invalid.

This can simply be resolved by renaming the namespace but some notification to the developer during the compilation stage should help avoid unnecessary problems.



 Comments   
Comment by Jozef Wagner [ 09/Jan/12 2:59 PM ]

I had a similar problem when my namespace contained a word class, e.g. in namespace:

(ns foo.bar.class)

Advanced closure compiler produced an error treating class as a JS keyword.





[CLJS-113] Allow colon as whitespace in map literals Created: 18/Dec/11  Updated: 24/Apr/12

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

Type: Enhancement Priority: Major
Reporter: Stuart Halloway Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Comments   
Comment by Gary Fredericks [ 24/Apr/12 7:40 AM ]

Will this change cause strings like "{\"foo\" :true}" to have ambiguous parses? And if we want CLJS to be a superset of JSON do we need to parse "null" as well?





[CLJS-145] Cannot create more than one browser evaluation environment Created: 06/Feb/12  Updated: 07/Dec/12

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

Type: Defect Priority: Major
Reporter: Stuart Sierra Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None


 Description   

When testing multi-user applications, it may be desirable to run multiple browser-connected REPLs from the same Clojure process. Currently, the socket connection for the browser-connected REPL is stored in a global atom, so it is not possible to create multiple browser-connected REPLs on different ports.






[CLJS-240] Warning under advanced compilation about incorrect protocol implementation signatures Created: 05/May/12  Updated: 05/May/12

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

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





[CLJS-246] Use protocol mask test in protocol fns Created: 09/May/12  Updated: 17/Jun/12

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

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Michał Marczyk
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-CLJS-246-have-protocol-methods-check-bitmasks-for-fa.patch    

 Description   

This is a performance win on many browsers.

http://jsperf.com/direct-vs-chain/8



 Comments   
Comment by Michał Marczyk [ 10/May/12 1:11 PM ]

See CLJS-247 for comments relevant to this patch.

Comment by David Nolen [ 10/May/12 3:30 PM ]

Not seeing much of a perf benefit from this, though Michal reports differently. More investigation is needed.

Comment by David Nolen [ 17/Jun/12 12:14 PM ]

patch no longer applies. I wonder if I see bad behavior because I was testing with node or it was prior to the fixes around avoiding deoptimization.

Comment by Michał Marczyk [ 17/Jun/12 9:28 PM ]

I'll bring it up to date with the recent changes, thanks for the prod!





[CLJS-247] possible protocol dispatch performance enhancement Created: 10/May/12  Updated: 23/May/12

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

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: Michał Marczyk
Resolution: Unresolved Votes: 0
Labels: None


 Description   

We could at the call site do the bit test and call directly? Otherwise, call the slow path? Implications for code size, but perhaps this could be a flag for people who really want the performance?



 Comments   
Comment by David Nolen [ 10/May/12 11:19 AM ]

flag might be:

:inline-protocol-fns true
Comment by Michał Marczyk [ 10/May/12 11:57 AM ]

No switch in this version – will add one if it seems it's worth it.

With this applied, core-advanced-test.js grows in size to 360301 bytes from 357528 bytes on current master.

Comment by Michał Marczyk [ 10/May/12 12:31 PM ]

This does seem to be a perf win on both :simple and :advanced, by the way.

Comment by Michał Marczyk [ 10/May/12 1:09 PM ]

Reattaching the patch to CLJS-246. Will get back to this.

Comment by David Nolen [ 17/May/12 1:33 PM ]

After some discussion with Rich this is definitely a direction we should pursue. It's very similar to what Clojure currently does.

Comment by David Nolen [ 17/May/12 9:29 PM ]

I went ahead and tried this, http://github.com/clojure/clojurescript/compare/master...cljs-247-protocol-fn-call-sites.

Code size is not very different 364k vs 373k for compiling all of the tests.

This is not going to be faster given our use of satisfies? I noticed that if we removed the satisfies? calls this is a performance win.

Problem: If a symbol passes a satisfies? it would be nice if we could tag it as satisfying the protocol and just emit the protocol dispatch directly. However this would not work for JavaScript primitives.

Comment by David Nolen [ 18/May/12 12:40 AM ]

Looks like I spoke a bit too soon There was a typo in the branch. The performance improvement between this and master is small for V8, but measurable for SpiderMonkey and JavaScriptCore.

Also, we could do the satisfies? optimization such that it works for JS natives with a simple gensymed mutable local around the callsite.

Comment by David Nolen [ 23/May/12 9:56 AM ]

K for handling natives simply tagging the symbol is not enough. We need to set a runtime gensymed flag that denotes whether it's a fast path protocol call. We can then avoid any redundants tests in the true branch of satisfies? and emit code like the following:

fast-path-flag ? foo.cljs$lang$Protocol$bar$arity0$(x) : cljs.core.Protocol.bar[goog.typeOf(x)](x);




[CLJS-299] PersistentVector push-tail, do-assoc, pop-tail should not contain recursive calls Created: 04/Jun/12  Updated: 31/Aug/12

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

Type: Enhancement Priority: Major
Reporter: David Nolen Assignee: Michał Marczyk
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-CLJS-299-eliminate-recursive-calls-in-PV-s-push-tail.patch     Text File 0001-CLJS-299-eliminate-recursive-calls-in-PV-s-push-tail.patch    

 Description   

This prevents V8 inlining. Lazlo's earlier experiments seemed to suggest ~30% gain.



 Comments   
Comment by Michał Marczyk [ 15/Aug/12 6:17 AM ]

Here's a patch which eliminates recursion in all the fns mentioned in the ticket name.

I haven't done much in the way of measuring the impact on perf; a naive benchmark of (assoc huge-vector 123 :foo) seems to indicate a modest perf gain (a few percent shaved off the runtime).

Note that whether pop-tail as implemented in this patch is an improvement over the previous version is not that clear, since it needs to precalculate the level at which the main loop should terminate. Careful measurements will be necessary. (I wouldn't be surprised if the difference turned out to be unmeasurable, in which case I guess we needn't bother with the change.)

push-tail and do-assoc have no such problems – all the work being done needs to be done (and is now done in a non-recursive fashion).

Hm... Actually that probably means this patch should be split in two (pop-tail & rest). I'll get around to that soon.

More importantly, some benchmarks for large data structures should be added (assoc / conj of 32 items (at any rate, a large enough number of items for the tail to be pushed in) / repeated pops (again, enough to pop the tail)). ("Large" here means "large enough for the shift of the vector to grow at least to 10", meaning size > 1024 + 32; shift 15 would be better, requiring size > 32768 + 32.)

Comment by David Nolen [ 17/Aug/12 12:36 AM ]

Awesome! Lets split the patch in two.

Comment by Michał Marczyk [ 17/Aug/12 4:23 AM ]

Ok. Here's a new patch which eliminates recursion in push-tail and do-assoc. I guess the large data structure benchmarks should probably get in first – see CLJS-357 (some benchmarks already attached – could use some scrutiny in case they're not exercising what they should be; initial runs indicate a very modest speedup).

I'll give pop-tail a little more thought and write a new patch for it sometime soon too. (Perhaps worth pointing out is that the zlvl precalculation in the current version of the pop-tail patch doesn't need to traverse any nodes – it's all bit twiddling – so it should be pretty cheap... I guess we'll see what the benchmarks say – I haven't actually ran them on this code yet.)

Comment by David Nolen [ 29/Aug/12 8:44 PM ]

So how did the benchmarks turn out for these?

Comment by David Nolen [ 31/Aug/12 9:04 AM ]

I applied and ran these benchmarks using the lasted V8. These don't seem to make any difference. Perhaps V8 no longer has issues with the recursive cases? I didn't test beyond running the benchmark script. Might be worth getting something up on JSPerf.





[CLJS-327] Backend agnostic repl infrastructure Created: 25/Jun/12  Updated: 26/Jun/12

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

Type: Enhancement Priority: Major
Reporter: Raphaël AMIARD Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File backend-agnostic-repl.patch    
Patch: Code

 Description   

This enhancement is about changing some names and docs in the repl infrastructure, so that it is backend agnostic.

The code is already backend agnostic, so the only changes that were needed are about references to Javascript.



 Comments   
Comment by David Nolen [ 26/Jun/12 11:34 AM ]

Thanks! Did you verify that browser REPL continues to function properly?





[CLJS-335] user defined tagged literals in CLJS Created: 06/Jul/12  Updated: 25/Dec/12

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

Type: Enhancement Priority: Major
Reporter: kovas boguta Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

I'm trying to make my own tagged literals for cljs, and its a rough scene. I've probably spend 15 hours trying to get this to work properly.

The quick hack of binding cljs-data-readers is a pretty bad solution, and doesn't work with cljsbuild.

One solution is to just copy the mechanism of data_readers.clj, instead calling it cljs_data_readers.clj. That would help.

A better solution is to just pass through all the tagged literals, and resolve them on the cljs side, eg `((cljs.core/get (cljs.core/deref cljs.reader/tag-table) ~tag) ~data))

That way the definition of the tags doesn't have to be repeated twice, as is done now (once in cljs.reader, and once in the clj-side cljs.tagged-literals) .

The problem with this is that clj itself is incapable of passing through undefined tags without exploding, which is also a near showstopper. Having something like cljs_data_readers.clj would get the job done in the meantime.

(another minor issue is that the cljs reader doesn't handle namespaced symbols, so in #a/b, b is what is used as the key into cljs-data-readers)



 Comments   
Comment by kovas boguta [ 06/Jul/12 12:52 AM ]

I've never used this before, so just assume everything in bold has earmuffs around it.

Comment by David Nolen [ 30/Aug/12 7:38 PM ]

This seems like a lot of separate issues rolled into one. Can we break this ticket apart into simpler actionable tickets?

Comment by kovas boguta [ 15/Dec/12 10:35 PM ]

Now that we have default-data-reader-fn, its possible to have a clean fix. Just set default-data-reader-fn to the function described above.

Should I generate a patch?

Comment by David Nolen [ 21/Dec/12 4:58 PM ]

What function defined above?

Comment by kovas boguta [ 25/Dec/12 1:30 PM ]

the function is
(fn [tag data] `((cljs.core/get (cljs.core/deref cljs.reader/tag-table) ~tag) ~data))

The proposal is to bind default-data-reader-fn to the above, in compiler.clj for the compile-file* function. And get rid of the binding for data-readers in that function as well.

It should be possible to get rid of the tagged_literals.clj file as well, since those definitions are no longer needed after this change.





[CLJS-344] clojure.reflect is asynchronous (should use CrossPageChannel) Created: 25/Jul/12  Updated: 08/Oct/12

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

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


 Description   

This makes printing at the REPL a bit annoying. We should be using the CrossPageChannel and not a ajax request to the built in webserver.



 Comments   
Comment by Brandon Bloom [ 03/Sep/12 3:36 PM ]

Was this ticket supposed to be filed against Clojure, not ClojureScript?

Comment by David Nolen [ 03/Sep/12 3:51 PM ]

No. This ticket refers to the HackerSchool work to provide a reflection hook for ClojureScript to make the REPL interactions more friendly. Look at clojure.reflect in the ClojureScript repo.

Comment by Frank Siebenlist [ 08/Oct/12 4:55 PM ]

As we've changed the topic of this issue a little bit..., I'd like to add the additional requirement that the reflection facility should be pluggable, meaning that if I have additional help/reflection functions that I want to make available to the cljs-repl users, then I should not have to wait for acceptance in a new clojurescript version.

Maybe some form of registration API thru which I can add new cljs-functions that communicate with their clj-counterparts thru some naming convention . Not sure about the details here...

Comment by David Nolen [ 08/Oct/12 5:06 PM ]

That's really a separate issue that probably warrants it's own discussion.

Comment by Frank Siebenlist [ 08/Oct/12 5:24 PM ]

Well... you started to add the (seemingly unrelated) CrossPageChannel requirement to the asynchronous one

But seriously, the pluggability requirement is probably important to keep in mind when any implementation for asynchronous clojure/reflect is designed and implemented - I'll open-up another issue for pluggability to keep it clean.





[CLJS-345] clojure.reflect support for Rhino REPL Created: 25/Jul/12  Updated: 25/Jul/12

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

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


 Description   

clojure.reflect should work for the Rhino REPL






[CLJS-364] compiler needs to put all args of an invocation after 20 into an array-seq Created: 29/Aug/12  Updated: 29/Aug/12

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

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


 Description   

This ticket is related to CLJS-359






[CLJS-365] apply needs to put all args after the 20th into an array seq Created: 29/Aug/12  Updated: 29/Aug/12

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

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


 Description   

This ticket is related to CLJS-359






[CLJS-374] satisfies? produces strange code when the protocol is not in the fast-path list Created: 06/Sep/12  Updated: 06/Sep/12

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

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





[CLJS-375] loop doesn't seem to preserve tag information as evidenced by extra cljs.core.truth_ calls Created: 06/Sep/12  Updated: 06/Sep/12

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

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





[CLJS-399] Lazy initialize global-hierarchy Created: 19/Oct/12  Updated: 23/Oct/12

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

Type: Enhancement Priority: Major
Reporter: Herwig Hochleitner Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-Atoms-fully-backed-by-protocols-introduces-clojure.c.patch     Text File 0002-Lazy-initialize-global-hierarchy.patch    
Patch: Code

 Description   

Depends on extend-instance http://dev.clojure.org/jira/browse/CLJS-398

First patch backs atoms by a protocol IPlace and implements reset! and swap! and compare-and-set! only with protocols

Second patch uses extend-instance to implement global-hierarchy a custom lazy atom

In effect, multimethods and hierarchies can be omitted by gclosure, taking 1K off of hello world

https://groups.google.com/d/topic/clojure/LNfJRw07u8I/discussion



 Comments   
Comment by David Nolen [ 19/Oct/12 5:18 PM ]

The protocol should probably just be called IAtom. A note, changing atoms to go through protocols has performance implications - generally protocol fns are about twice as slow as regular fns.

I'll take a closer look.





[CLJS-402] Add a facility to obtain the version information of the clojurescript build that is in use Created: 21/Oct/12  Updated: 26/Feb/13

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

Type: Enhancement Priority: Major
Reporter: Frank Siebenlist Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: enhancement

Attachments: File CLJS402-3rd-patch-file.diff    

 Description   

Currently there is no function or var defined in the clojurescript library that can be used to easily obtain the version information of the build that is in use.

Without that version information, debugging and reporting of errors is more cumbersome than needed, wastes time, causes confusion discussing issues...

A simple function and/or var like the ones used for clojure would be very helpful:

user=> (clojure-version)
"1.4.0"
user=> clojure-version
{:major 1, :minor 4, :incremental 0, :qualifier nil}



 Comments   
Comment by Frank Siebenlist [ 21/Oct/12 2:16 PM ]

Auto-generation from the build script of version_autogen.clj and version_autogen.cljs files
that both define the cljs.version-autogen/clojurescript-version
with the current version info for both the clj and cljs environments

Comment by David Nolen [ 21/Oct/12 3:43 PM ]

Why a separate namespace for this?

Comment by Frank Siebenlist [ 21/Oct/12 9:15 PM ]

Good point - probably better to add the clojurescript-version var to the cljs.core namespace.

New patch change the build script to auto-generates the clojurescript-version assignment statements in both cljs/core.clj and cljs/core.cljs to reflect the correct version info.

In that way it resembles more the clojure.core use of clojure-version.

Note that the two separate assignments for clj and cljs are needed to detect out-of-sync of repl-compiler version with the compiler used to generate the js-code that was downloaded thru the webpage.

Difficult to write a test-script, but it seems to work in my repl:


user=> (require 'cljs.core)
nil
user=> cljs.core/*clojurescript-version*
{:minor 0, :revision 1515, :major 0}
user=> (run-repl-listen)
"Type: " :cljs/quit " to quit"
ClojureScript:cljs.user> *clojurescript-version*
{:revision 1515, :major 0, :minor 0}
ClojureScript:cljs.user>

Comment by Frank Siebenlist [ 21/Oct/12 9:16 PM ]

CLJS-402: build script auto-generates the clojurescript-version assignment statements in both cljs/core.clj and cljs/core.cljs to reflect the correct version info

Comment by Frank Siebenlist [ 22/Oct/12 12:00 AM ]

When I tried to implement a "clojurescript-version" function like the "clojure-version" one, I (re)discovered that cljs/core.clj is not your average cli-file but some funky file used by the clojurescript compiler to bootstrap - in other words it's not a good file to require and run normal functions from your clj-environment.

So I moved the *clojurescript-version* var to cljs/compiler.clj as it seemed to make sense to associate the version with the compiler.

On the cljs site, I left the *clojurescript-version* in cljs/core.cljs, although I was tempted to create a cljs.compiler namespace to store that var on the cljs side to make it symmetric .

Also added a (clojurescript-version) function to both the clj and cljs sides, with an added special-fn in the cljs/repl.clj such that you can ask for the compiler version of the repl-server from the cljs-repl.

Updated 3rd patch file replaces the previous one.

Just wanted to record an example of a mismatch in compilers:

user=> (run-repl-listen)
"Type: " :cljs/quit " to quit"
ClojureScript:cljs.user> (clojurescript-version)
"0.0.1515"
ClojureScript:cljs.user> (clj-clojurescript-version)
"0.0.1516"
ClojureScript:cljs.user>

This happens when you generate the javascript from your cljs with a "lein cljsbuild once" command with compiler version "0.0.1515",
then upgrade the compiler to "0.0.1516" and then run the cljs-repl without regenerating the javascript for the webpage-download.
Very obscure things can happen after that...

Comment by Frank Siebenlist [ 22/Oct/12 12:03 AM ]

build script auto-generates the clojurescript-version assignment statements in both cljs/compiler.clj and cljs/core.cljs to reflect the correct version info
Function "clojurescript-version" is added to both compiler.clj and core.cljs to mimic equivalent "clojure-version"
Special-fn "clj-clojurescript-version was added to repl.clj to obtain the compiler's clojurescript-compiler version from the cljs-repl

Comment by David Nolen [ 22/Oct/12 7:06 AM ]

The patch uses sed, I'm not sure this is such a great idea since whatever the patch does should probably work with whatever build setup we have on Hudson.

Comment by Chouser [ 22/Oct/12 8:05 AM ]

Would it make sense to call this 'clojure-version' as well, instead of clojurescript-version? It's a map, and so various flags could be added to differentiate jvm, js, python, c, etc. runtimes. What does ClojureCLR do?

Comment by Frank Siebenlist [ 22/Oct/12 10:52 AM ]

sed was already used in the build script... a few lines down, the pom file is transformed with:

sed -e s/CLOJURESCRIPT_VERSION/0.0-$REVISION/ < "$POM_TEMPLATE" > "$POM_FILE"

Comment by Frank Siebenlist [ 22/Oct/12 11:15 AM ]

A quick scan of the src-code showed that ClojureCRL uses clojure-version and *clojure-version*.

However, there is less chance for confusion as you are supposedly running on the CLR already.

With ClojureScript you can have these three intertwined "clojure" environments that are all live at the same time: the clojure version, the repl clojurescript version, and the clojurescript version used to compile the initially loaded js. Not sure if overloading the clojure-version fn-name and relying on namespaces to differentiate will be helpful... but it's not that big of a deal and I'm easily persuaded otherwise - somebody should make the call and I'll change it.

Comment by David Nolen [ 26/Feb/13 7:51 AM ]

Sorry just now coming back to this ticket. I think it's probably preferable that the map of properties be called the same thing everywhere. I would apply the patch with this change. I note it no longer applies to master.





[CLJS-404] Automate Browser REPL testing Created: 23/Oct/12  Updated: 23/Oct/12

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

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


 Description   

It's worth investigating Selenium, PhantomJS, etc. as solutions to sanity check the Browser REPL when we run the other tests.






[CLJS-410] support ^:expose annotation Created: 28/Oct/12  Updated: 28/Oct/12

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

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


 Description   
(def ^:export m 1)
(defn foo [g]
  (g m))

Because of constant propagation GClosure may replace m in foo with 1. It may be better to for :export to implicitly :expose but we need to check the output.

http://developers.google.com/closure/compiler/docs/js-for-compiler






[CLJS-414] Implement specify, allowing instances to implement protocols Created: 30/Oct/12  Updated: 03/May/13

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

Type: Enhancement Priority: Major
Reporter: Herwig Hochleitner Assignee: Herwig Hochleitner
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001_1-CLJS-414-specify-and-specify-macros.patch     Text File 0001-CLJS-414-specify-and-specify-macros.patch     Text File 0002-CLJS-414-Implement-extend-type-in-terms-of-specify.patch     Text File 0101-CLJS-414-specify-and-specify-macros.patch     Text File 0102-CLJS-414-Implement-extend-type-in-terms-of-specify.patch     Text File 0103-CLJS-414-Test-specify-features-deprecation-nowarn-an.patch     Text File 0104-CLJS-414-Update-specify-to-allow-implementing-IFn-an.patch     Text File 0201-CLJS-414-specify-and-specify-macros.patch     Text File 0202-CLJS-414-Implement-extend-type-in-terms-of-specify.patch     Text File 0203-CLJS-414-Test-specify-features-deprecation-nowarn-an.patch     Text File 0204-CLJS-414-Update-specify-to-allow-implementing-IFn-an.patch    

 Description   

Javascript objects are fully dynamic. Currently, ClojureScript has no mechanism to exploit that for protocol implementation.

CLJS-398 was a first attempt to implement an operation to extend single instances, but it fell short because it offered no control over which closures to attach onto the object (i.e. allocates every time). Also, specify is a much better name than extend-instance.

extend-type can be implemented in terms of specify (by specifying the .prototype), but extend-type has grown from its humble beginnings
https://github.com/clojure/clojurescript/blob/b75730da8abc3abc6134d8dd9ec426ab792d3662/src/clj/cljs/core.clj#L42
to an monster of complexity
https://github.com/clojure/clojurescript/blob/72e55315c6973caa74af39b66052424f73872033/src/clj/cljs/core.clj#L438
Currently it does

  • print warnings
  • optimize IFn impls
  • special case the Object "protocol"
  • special case js builtins

and all that in a single macro body. So this is also a good opportunity to do some refactoring.

specify should have an interface similar to extend-type. Additionally a lower level operation is needed to attach existing lambdas as protocol methods. It's called specify* in my current implementation. It takes a lambda for every specified protocol-method-arity, with a syntax loosely based on clojure.core/extend.



 Comments   
Comment by Herwig Hochleitner [ 30/Oct/12 11:21 PM ]

First patch implements specify, second switches extend-type to use it.

Comment by David Nolen [ 31/Oct/12 9:30 AM ]

This is a big patch so it's going to take time to review. First question, if we're going to follow the footsteps of extend what's the purpose of changing the syntax like having to specify a map of arities?

Comment by Herwig Hochleitner [ 31/Oct/12 10:32 AM ]

The reason is that I wanted specify* to do as little as possible. It's basically just an abstraction over the name mangling for protocol methods, which was completely hidden till now. One of the purported use cases is:

(def methA-1 [this] ...)
(def methA-2 [this x] ...)
(def methB-1 [this] ...)

(defn specify-to-P [o]
  (specify* o
    P {methA {1 methA-1
              2 methA-2}
       methB {1 methB-1}}))

Here the method bodies are not allocated every time specify-to-P is called, as opposed to what the more high-level specify would do. If we didn't know which arities are to be generated, there would be simply no way to infer it:

  • there is no simple way to know at compile time which arities an fn has
  • if there was we wouldn't be able to get the fn at compile time in all cases
  • defprotocol doesn't expose it's methods or their arities

EDIT:

As for using symbols instead of keywords: I could do this, since specify* is a macro, not a function.
Making specify* a function may have its own merits, which I frankly hadn't thought about. Actually, that might be sweet, I'll look into that possibility.

Comment by Herwig Hochleitner [ 31/Oct/12 12:59 PM ]

As for specify* being a function: It uses a map in its syntax and at the same time is used to define PersistentHashMap, so that wouldn't work.
EDIT: the real reason is name mangling, see comment below

What could conceivably be done is to have a core function (specify-method [proto method arity impl]).
EDIT: can't be done without reflection, same reason

That way we could support consumers that want to determine the set of implemented protocols at runtime, similar to extend. This can be a separate ticket where we work out whether it's :method 'method or "method".

As for specify* using symbols: My gut feeling tells me that since it will always be a compiler macro (or builtin) and takes the arities, there is no merit in making it superficially more similar to extend.

OTOH, it occurs to me that given specify-method, we could leave out specify* completely. I think I'll try that when I get home from work. Thoughts on that approach?

Comment by Herwig Hochleitner [ 31/Oct/12 7:59 PM ]

Actually, I had a rationale for using symbols in specify*, which I just now rediscovered while trying to implement aforementioned specify-method.
It uses symbols to highlight the fact, that the method names are subject to the same (gclosure) minification as every other name.

This is also the real reason specify* (or specify-method) can't be a function: It would need a reflective layer to go from [proto method arity] to the gclosure minified version of $proto$method$arity$a. We don't have that in clojurescript, since it would considerably add to the output size.

Considering that all, I think specify* in the current form is appropriate after all.

Nevertheless I found an unrelated issue in the patch where 'Object would be resolved (with an unused result), triggering a warning. I added the 0001_1 patch, which supersedes 0001 and is functionally equivalent modulo the warning issue. 0002 still applies.

Comment by Herwig Hochleitner [ 01/Nov/12 12:09 AM ]

Attached patch set 01** supersedes patch set 00**

The differences are

  • Make ^:skip-protocol-flag work
  • Added tests
Comment by Herwig Hochleitner [ 03/Nov/12 12:53 AM ]

Set up a design page http://dev.clojure.org/display/design/specify+i.e.+reify+for+instances

Comment by Herwig Hochleitner [ 04/Nov/12 10:06 PM ]

Attached patch 0104, applies on top of other 01* patches.
It adds capability to specify* IFn and allows specify* to take an expression too.

Comment by Herwig Hochleitner [ 03/May/13 7:30 PM ]

rebased to current master
see also https://groups.google.com/d/topic/clojure-dev/1UegnkLSwhE/discussion





[CLJS-433] Throw error when user tries to use wrong syntax for multiple arity functions in extend-type Created: 29/Nov/12  Updated: 29/Nov/12

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

Type: Enhancement Priority: Major
Reporter: Max Penet Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Right now it allows to mix declarations, sometimes allowing an illegal syntax (-nth shouldn't be allowed in the following example)

example from jayq:

(extend-type js/jQuery

  IIndexed
  (-nth [this n] ...)
  (-nth [this n not-found] ...)

  ILookup
  (-lookup
    ([this k] ...)
    ([this k not-found] ...))

It already throws an error with some protocols such as IFn, but not for all of them.






[CLJS-436] defn missing arg vector gives error about max Created: 06/Dec/12  Updated: 08/Dec/12

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

Type: Defect Priority: Major
Reporter: David Nolen Assignee: Michał Marczyk
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-CLJS-436-validate-arguments-to-fn-forms.patch    

 Comments   
Comment by David Nolen [ 06/Dec/12 10:09 AM ]

The issue is actually a bit subtle for example:

(defn foo "name")

is valid Clojure - however this doesn't work in ClojureScript. In this case ClojureScript generates the following:

function () {
    switch (arguments.length) {
    }
    throw (new Error("Invalid arity: " + arguments.length));
}
Comment by David Nolen [ 06/Dec/12 10:19 AM ]

After talking to Rich the above really should not compile.

Comment by Michał Marczyk [ 08/Dec/12 6:09 PM ]

Here's a patch with the fn* validations I could think of. It seems to cause the compilation time to increase by a measurable amount, which I find quite surprising (even though it's to be expected that there will be quite of few fn* forms in CLJS sources). I'd love to know if it's just on my box (let's hope so). If validations really have that sort of effect, I'm thinking about refactoring the analyser so that they can be turned on (which should also be the default) and off (for particularly fast compilations).

Comment by Michał Marczyk [ 08/Dec/12 6:11 PM ]

Ah, wait, there's a minor typo in the commit message, I'll fix it in a second...

Comment by Michał Marczyk [ 08/Dec/12 6:13 PM ]

...um, no there isn't. Sorry for the confusion.





[CLJS-449] stack traces for ex-info Created: 23/Dec/12  Updated: 23/Dec/12

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

Type: Enhancement Priority: Major
Reporter: Tom Jack Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-hack-ex-info-stacktraces.patch    

 Description   

Currently, ex-info exceptions have no stack traces, which makes them.. much less useful.

Attached patch (0001-hack-ex-info-stacktraces.patch) is one hackish way of getting stack traces back when Error.captureStackTrace is available (at least in Chrome, presumably in Node as well).

But this seems unacceptable — all the stuff emitted for the deftype (making the constructor print as a type) gets overwritten.

Is there a better way?

Will this maybe be made irrelevant by source maps?



 Comments   
Comment by David Nolen [ 23/Dec/12 11:51 AM ]

Isn't the stack trace recoverable from the original exception?

Comment by Tom Jack [ 23/Dec/12 4:01 PM ]

I hadn't considered that. If a cause is provided, that seems reasonable. The only trouble is that you still have to know where the ExceptionInfo is being thrown, so that you can catch it and throw the cause. Chrome's debugger would make it easy to at least find where the ExceptionInfo is thrown, but it's still more trouble than having the appropriate stack trace directly on the ExceptionInfo.

If no cause is provided, of course that won't work. But I suppose one could write (ex-info msg data (js/Error.)) instead of (ex-info msg data)? Personally, I don't expect to pass a cause very often — I expect the binary arity to be much more common in my cljs libraries.

If we rely on the cause for the stack trace, maybe we could have the cause default to a new Error if not supplied? It seems sort of conceivable that we could also wire up the ExceptionInfo to proxy .stack to that Error so that the stacktrace will come through, without needing to override the ExceptionInfo constructor.





[CLJS-454] Instance Reader to Support Micro/Nanoseconds Created: 04/Jan/13  Updated: 21/Feb/13

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

Type: Defect Priority: Major
Reporter: Anatoly Polinsky Assignee: Unassigned
Resolution: Unresolved Votes: 3
Labels: reader, timestamp
Environment:

N/A


Attachments: Text File cljs-reader-nanosecond-workarround-corrected.patch    

 Description   

Any timestamps with a greater than millisecond precision cannot be handled by the ClouseScript reader:

> cljs.reader.read_date("2012-12-30T23:20:05.066980000-00:00")
> Error: Assert failed: timestamp millisecond field must be in range 0..999 Failed:  0<=66980000<=999 (<= low n high)

Here "2012-12-30T23:20:05.066980000-00:00" is an example of an ordinary timestamp that is returned from Postgres.

ClojureScript reader interprets the nanosecond portion "066980000" as milliseconds and the check here fails:

def parse-and-validate-timestamp
...
   (check 0 ms 999 "timestamp millisecond field must be in range 0..999")


 Comments   
Comment by David Nolen [ 04/Jan/13 4:55 PM ]

Is this behavior supported in Clojure?

Comment by Jozef Wagner [ 05/Jan/13 6:48 AM ]

It seems it is

Comment by Anatoly Polinsky [ 06/Jan/13 2:18 AM ]

@David,

Yep, it is supported. Enhancing Jozef's response:

user=> (use 'clojure.instant)
nil
user=> (read-instant-date "2012-12-30T23:20:05.066980000-00:00")
#inst "2012-12-30T23:20:05.066-00:00"

/Anatoly

Comment by David Nolen [ 09/Jan/13 10:59 PM ]

Ok, do you all have a good idea about what a patch would look like?

Comment by Thomas Heller [ 05/Feb/13 3:28 PM ]

Since JavaScript has no support for nanoseconds in Date, I'd vote for dropping the nanoseconds. Currently the reader just blows up when reading a String with java.sql.Timestamp printed in CLJ, since that is printed in nanosecond precision.

While probably not the best solution, I attached a patch for cljs.reader/parse-and-validate-timestamp fn that just drops the nanoseconds from the millisecond portion. Would be easier to just strip the ms string to 3 digits but that would cause "2012-12-30T23:20:05.066980000012312312123121-00:00" to validate.

Comment by Thomas Heller [ 05/Feb/13 3:35 PM ]

Well, Math. Just realized that this is not really correct, since 1000 is closer to 999 than it is to 100.

Comment by Thomas Heller [ 05/Feb/13 3:37 PM ]

Sorry, for that brainfart.

Comment by David Nolen [ 06/Feb/13 11:39 AM ]

Or we could return a custom ClojureScript Date type that provides the same api as js/Date but adds support for nanoseconds.

Comment by Thomas Heller [ 20/Feb/13 5:20 PM ]

One could extend the js/Date prototype with a setNanos/getNanos method and call them accordingly. I'd offer to implement that but the cljs.reader/parse-and-validate-timestamp function scares me, any objections to rewriting that?

As for the js/Date extension, thats easy enough:

(set! (.. js/Date -prototype -setNanos) (fn [ns] (this-as self (set! (.-nanos self) ns))))
(set! (.. js/Date -prototype -getNanos) (fn [] (this-as self (or (.-nanos self) 0))))

Not sure if its a good idea though, messing with otherwise native code might not be "stable".

Not convinced that keeping the nanos around is "required" since javascript cannot construct Dates with nanos, but its probably better not to lose the nanos in case of round tripping from clj -> cljs -> clj.

Comment by David Nolen [ 21/Feb/13 12:25 AM ]

We definitely don't want to mutate Date's prototype without namespacing. I'm not sure we want to mutate Date's prototype at all. That's why I suggested a ClojureScript type with the same interface as Date just as Google has done in Closure.





[CLJS-456] Function named same as ns fails Created: 13/Jan/13  Updated: 14/Jan/13

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

Type: Defect Priority: Major
Reporter: Jonas Enlund Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

In a fresh script/repljs on clojurescript master I see the following behaviour:

ClojureScript:cljs.user> (ns foo.bar)
ClojureScript:foo.bar> (defn id [x] x)
#<
  function id(x) {
      return x;
  }
  >
  ClojureScript:foo.bar> (defn foo [] (id 42))
  #<
  function foo() {
      return foo.bar.id.call(null, 42);
  }
  >
ClojureScript:foo.bar> (foo)
  "Error evaluating:" (foo) :as "foo.bar.foo.call(null)"
  org.mozilla.javascript.EcmaError: TypeError: Cannot read property "id" from undefined (<cljs repl>#4)
      at <cljs repl>:4 (foo)
      at <cljs repl>:4 (anonymous)
      at <cljs repl>:4
 
nil
ClojureScript:foo.bar>

(https://www.refheap.com/paste/8494 in case formatting fails)






[CLJS-457] Implement notion of "unbound", i.e. uninitialized variables, in ClojureScript to mimic Clojure's behaviour Created: 15/Jan/13  Updated: 15/Jan/13

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

Type: Defect Priority: Major
Reporter: Frank Siebenlist Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

clojurescript r1552



 Description   

The following REPL snippets show different behavior for "unbound" vars in cljs and clj:

--------
ClojureScript:cljs.user> (def a nil)
nil
ClojureScript:cljs.user> (def b)

ClojureScript:cljs.user> (= a b)
true
--------
user=> (def a nil)
#'user/a
user=> (def b)
#'user/b
user=> (= a b)
false
--------

As a possible solution, D. Nolen suggested that we could "simulate this by creating a Unbound type and initializing def'ed vars without init expressions to instances of it."






[CLJS-463] Google Closure Class interop form (genclass) Created: 26/Jan/13  Updated: 11/May/13

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

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


 Description   

Currently it's not really possible to use to the existing deftype/record to construct "classes" that interop well with Google Closure. It seems odd to ship Closure and then provide no tools for writing ClojureScript against it, especially the UI component parts. Several people have asked for this now so perhaps we really should offer the ClojureScript equivalent of genclass.



 Comments   
Comment by Tyler Tallman [ 11/May/13 3:06 PM ]

What do you think of this approach based on
based on http://www.50ply.com/blog/2012/07/08/extending-closure-from-clojurescript/

While it may not preserve enough of gen-class's semantics. This would be enough for us to start gradually porting our large GClosure code base to Clojurescript. The code size reduction would be enormous.

sample_use
(ns com.example
  (:require [goog.ui.tree.TreeControl :as TreeControl]))
(gen-class
  :name DemoTree
  :extends goog/ui.tree.TreeControl
  :constructor ([name config]
                 (goog/base (js* "this") name config))
  :methods [[handleKeyEvent [e]
              (goog/base (js* "this") "handleKeyEvent" e)
              ;; my special code to handle the key event
    ]])

here is a untested mock implementation modified from http://www.50ply.com/blog/2012/07/08/extending-closure-from-clojurescript/

I changed constructors to constructor because there can be only one in js

This unfortunately has different semantics from gen-class because the original did not include the definition of the methods and constructor inline. It tried to read the Clojure gen-class source,but I still do not yet understand how the :prefix grabbing of functions from the current namespace works from within a macro.

For Google Closure interop each class should have its own provide

dryrun_for_gen-class
(defmacro gen-class [{new-type :name base-type :extends ctor :constructor methods :methods}]
  `(do
     ;(goog/provide ~@(str *ns* "." new-type)) 
     (defn ~new-type ~@ctor)

     (goog/inherits ~type ~base-type)

     ~@(map
        (fn [method]
          `(set! (.. ~type -prototype ~(to-property (first method)))
                 (fn ~@(rest method))))
        methods)))




[CLJS-474] Name every fn in CLJS sources (for debugging purposes) Created: 18/Feb/13  Updated: 18/Feb/13

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

Type: Enhancement Priority: Major
Reporter: Thomas Heller Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File cljs-better-fn-names.patch    
Patch: Code

 Description   

As mentioned here: https://groups.google.com/forum/?fromgroups=#!topic/clojurescript/ZX6M4KXx8I8

Naming every fn in the compiled javascript functions makes it a little easier to find out whats going on when looking at a stacktrace. This patch names every function generated as fn_<ns>/<orig-name>_<line>. See example stacktrace in the discussion above.

The optional cljs snippet (https://gist.github.com/thheller/4972200) then also transforms this data and prints functions as

(pr-str name)
=> #<function cljs.core/name line:5876>

instead of dumping the javascript source on you.

The .patch has the drawback that the generated source size grows a bit (about 10% on my codebase), but advanced compilation takes care of that (although even that is still a bit larger, the closure compiler doesnt seem to strip unused function names). One could make this a compiler option if the size differences are too big.






[CLJS-478] ClojureScript js->clj not converting Created: 26/Feb/13  Updated: 26/Feb/13

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

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

ClojureScript 0.0-1586 build #22, Chrome, OSX



 Description   

I've updated to 0.0-1586 build #22 from a much older release: 0.0-1450

I'm now geting a problem with (js->clj token) not converting token to a map; this worked before I upgraded.

token is generated by the google OAuth 2 process: "gapi.auth.authorize"

I don't think the problem is with js->clj rather something about token so it isn't recognised as a js/Object.

(println (expose token true)) gives:

access_token = ya29.AHES6ZSgnk3Ws5bB-2aDx41Bbr335hKugjZJfcNAs83d121S306fxy64
token_type = Bearer
expires_in = 3600
client_id = 52351124085.apps.googleusercontent.com
scope = https://www.googleapis.com/auth/drive.file,https://www.googleapis.com/auth/drive.metadata.readonly,https://www.googleapis.com/auth/drive.readonly
g_user_cookie_policy = undefined
cookie_policy = undefined
issued_at = 1361807171
expires_at = 1361810771

This looks ok.

however
> token

gives:

"Error evaluating:" token :as "esef.client.evidence.token"
#<TypeError: Object [object Object] has no method 'toString'>
TypeError: Object [object Object] has no method 'toString'

> (type token)

gives a blank line. I think this is why js->clj isn't converting.

> (alength token)

gives a blank line.

(.-token_type token)

Correctly gives ya29.AHES6ZSgnk3Ws5bB-2aDx41Bbr335hKugjZJfcNAs83d121S306fxy64

I haven't managed to recreate 'token' with a minimal test case but I'm fairly new to javascript. It's impractical to to include my OAuth 2 code because its tied into all my google security.
If you can suggest anything that will provide you with more info on 'token' I'll try and help.

As a work-around I manually create the MAP by explicitly reading each property, I couldn't get a list of properties.



 Comments   
Comment by David Nolen [ 26/Feb/13 11:00 AM ]

type just returns the constructor property of an Object. For some reason this is returning undefined instead of value. It's likely that this has nothing to do with ClojureScript and more to do with Google Closure. Have you investigated whether the OAuth token constructor has changed in Closure itself?

Comment by Mike Longworth [ 26/Feb/13 11:21 AM ]

I don't think the token object or the apis have any significant relationship with closure, they are loaded dynamically from google (gapi.client.load):
https://code.google.com/p/google-api-javascript-client/wiki/ReferenceDocs#OAuth_2.0_Token_Object
https://code.google.com/p/google-api-javascript-client/wiki/GettingStarted

Comment by David Nolen [ 26/Feb/13 11:25 AM ]

Did type return something for you instead of undefined in 1450?

Comment by Mike Longworth [ 26/Feb/13 11:40 AM ]

Sorry I can't answer that; js->clj just worked so I didn't probe too deeply but looking at the code in js->clj It looks like it must have. I tried the original implementation of js->clj before the recent changes but confirmed this still suffers from the same problem (type x) js/Object):

(defn js->clj
"Recursively transforms JavaScript arrays into ClojureScript
vectors, and JavaScript objects into ClojureScript maps. With
option ':keywordize-keys true' will convert object fields from
strings to keywords."
[x & options]
(let [{:keys [keywordize-keys]} options
keyfn (if keywordize-keys keyword str)
f (fn thisfn [x]
(cond
(seq? x) (doall (map thisfn x))
(coll? x) (into (empty x) (map thisfn x))
(goog.isArray x) (vec (map thisfn x))
(identical? (type x) js/Object) (into {} (for [k (js-keys x)]
[(keyfn k)
(thisfn (aget x k))]))
:else x))]
(f x)))





[CLJS-479] load-file in REPL improperly qualifies current-namespace ::keywords Created: 28/Feb/13  Updated: 24/Apr/13

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

Type: Defect Priority: Major
Reporter: Chas Emerick Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: File CLJS-479.diff    
Patch: Code

 Description   

This can be seen by opening a REPL and:

(load-file "cljs/ns_test/foo.cljs")

The ::foo keyword in that file is resolved improperly:

ClojureScript:cljs.user> cljs.ns-test.foo/kw
:user/foo

cljs.repl/load-stream needs to force *ns* to track *cljs-ns* so that the Clojure reader will properly resolve auto-namespacing keywords. A patch is attached that does this, ensuring that any Clojure namespaces created solely for this purpose are removed.



 Comments   
Comment by Chas Emerick [ 28/Feb/13 4:53 AM ]

Note that there are two other places where the Clojure reader is used in ClojureScript — one in the analyzer, one in the compiler — where a similar fix may be required. Perhaps cljs.compiler/forms-seq should be the sole place where the Clojure reader is used with *ns* properly tracked therein...

Comment by David Nolen [ 24/Apr/13 9:49 PM ]

Is this fixed in master?





[CLJS-480] *cljs-data-readers* is bound to *data-readers* inconsistently Created: 01/Mar/13  Updated: 17/May/13

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

Type: Defect Priority: Major
Reporter: Chas Emerick Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-CLJS-480-bind-data-readers-in-parse-ns.patch     Text File 0002-Bring-back-multiple-test-compilations-and-overhaul-o.patch    

 Description   

It looks like *cljs-data-readers* is not being bound to *data-readers* where it should be.

At a minimum, cljs.repl/load-stream does not. The practical effect of this instance is that e.g. (load-file "some/cljs/file.cljs") will fail if that file or any other contains a user-defined literal tag. Similar behaviour exists elsewhere, e.g. (load-namespace 'some.cljs.ns) will not load a namespace that contains user-defined tags (I think that one is due to *cljs-data-readers* not being bound in the analyzer).

This is related to CLJS-479 insofar as it's another symptom of ClojureScript loading code in subtly different ways in multiple places.

I'm happy to do either of:

  1. submit issues+patches fixing issues as I encounter them, or
  2. attempt a more significant refactoring that sets up (hopefully) one and only one place where ClojureScript reads code (i.e. uses LispReader) so that behaviour can be consistent

I'm somewhat hesitant re: (2) insofar as the specific requirements of the compiler and analyzer and REPL may be divergent in ways that I'm not yet aware of, but it seems like it's worth a shot.



 Comments   
Comment by Herwig Hochleitner [ 17/May/13 3:10 PM ]

Attached patch 0001 binds data-readers in cljs.compiler/parse-ns.

This allows the compiler to run, even if files with reader tags are already compiled.

This in turn allows multiple test compilations to be brought back, which I'll submit as part of a patch for an additional debugging flag, if nobody beats me to it.

I think this won't fix load-file , but after the hotfix we should probably look for the proper place in the compiler to bind data-readers.

Comment by Herwig Hochleitner [ 17/May/13 5:25 PM ]

Patch 0002 is my overhaul for the test script.
Since it's a test case for patch 0001, I think it's justifiable on this ticket.

Note: On my machine, with SpiderMonkey 185, the test case (not (integer? 1e+308)) fails. It probably doesn't have to do anything with the removed -n flag (there is no js -n omm), I just wanted to mention it.





[CLJS-497] Constant literal optimization Created: 25/Apr/13  Updated: 25/Apr/13

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

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


 Description   

We should optimize constant literals, in particular keywords. This optimization means that we will have to decide whether to make identical? slower by testing for keywords (this means it's probably a bad idea to continue to inline it) or to provide a special keyword-identical? that does the right thing.






[CLJS-499] Reassess ObjectMap vs. PersistentArrayMap Created: 25/Apr/13  Updated: 07/May/13

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

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


 Description   

Here are some benchmarks after performance improvements have been applied to PersistentArrayMap in master:

For the smallest sizes PAMs are nearly identical in performance to OMs, as we start nearing the PHM threshold PAMs are nearly 2X faster on WebKit Nightly, and nearly 3X faster on the latest Chrome. Only Firefox Nightly lags behind for lookup times at larger sizes.

Again we see nearly identical (or much better) performance at small sizes and much better performance for PAMs as we approach the PHM threshold.



 Comments   
Comment by Tyler Tallman [ 07/May/13 12:11 PM ]

When I try to run the jsprefs I get "ReferenceError: cljs_perf is not defined."





[CLJS-505] reduce-kv doesn't work on this dataset Created: 12/May/13  Updated: 12/May/13

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

Type: Defect Priority: Major
Reporter: Ben Burdette Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Chromium browser on kde mint



 Description   

reduce-kv seems to fail with certain datasets in clojurescript but works in clojure. plain reduce works in both. Test dataset and functions:

(def tst '{0 (0.16245458703559382 0.16299961144753652), 1 (0.17095488518209803 0.1662484375243468), 2 (0.19709700082585824 0.1876248353737042 0.18162592547515274), 3 (0.21941419798490325 0.21807914100386067 0.21533585716040135 0.21307519864852958 0.20703453840254027 0.20459935129415552), 4 (0.2254558759699653 0.22553167887455705 0.2234426184638531), 5 (0.23427611508459756 0.2325434766605363 0.22990656317710662 0.22720478209110223), 6 (0.236386202300682 0.237142940385559 0.23819488667547528 0.23768692982616965 0.23701568705350426 0.2519226069678777), 7 (0.23496439825060444 0.2366135730772095 0.2358487071572212 0.2343505595436482 0.2339754113241729 0.23574632954272087 0.2342899279492302 0.23394402094793673 0.2253325456308313 0.23115349467838542 0.23764956541775945 0.24569178483873644 0.24935940319340053), 8 (0.20547261591662125 0.20726089154784122 0.21592818189465432 0.21750737743637422), 9 (0.18799738410585773 0.195400717149256 0.19631498833296726), 10 (0.1719302696659648 0.17805792401151166 0.18237267730425885), 11 (0.1623645568284537 0.16481390708298796 0.16716904262359314), 12 (0.16156804839942243 0.16211838120784386), 13 (0.16995648347966535 0.16559349825186068), 14 (0.19176771652550495 0.17696322624338934), 15 (0.23973485828855146 0.22420582245618542 0.2145975801770993 0.20208630026741867), 16 (0.2946896009888785 0.28676176338007714 0.28325454941805994 0.2716914099321759 0.26202250017945194 0.25452401319317824 0.2458771184353157), 17 (0.33300741045445653 0.3282046117335755 0.32330639472087175 0.3191873692036449 0.31290612056170736 0.30418343504691503 0.3004101566486822), 18 (0.341869650592079 0.34431149263906713 0.3457698150448536 0.34421452862514235 0.3429726966458358 0.3388988973880783 0.33579154357727864), 19 (0.2968748091051211 0.3023852506442652 0.3121637065261914 0.31141190562184173 0.32205821745972246 0.32898706631919056 0.33322752162957553 0.3396066565159988), 20 (0.2317683974879252 0.24538548478582375 0.2645130722935203 0.27362218406430894), 21 (0.20128274621982342 0.21819083560963268), 22 (0.1732991500114435 0.1811216605973363 0.19151484878018085), 23 (0.16575238432187128)})

; this returns nil in clojurescript, returns a sorted dataset in clojure.
(defn sortpi [pi]
(reduce-kv (fn [c k v] (assoc c k (sort v))) {} pi))

(sortpi tst)

; this version works in both clojurescript and clojure:
(defn sortpi2 [pi]
(reduce (fn [c [k v]] (assoc c k (sort v))) {} pi))

(sortpi2 tst)



 Comments   
Comment by Michał Marczyk [ 12/May/13 10:49 PM ]

Works for me on master. Which version of ClojureScript are you using?





[CLJS-506] Flag to disable minification in advanced mode Created: 19/May/13  Updated: 19/May/13

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

Type: Enhancement Priority: Major
Reporter: Herwig Hochleitner Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-CLJS-506-Add-a-debug-flag-to-the-compiler-options.patch    

 Description   

Problem:
Some code has different semantics when compiled in advanced mode.
Clojurescript tries to minimize those cases, but examples are usage of aget or forgotten externs files.
There exits closure compiler options to generate names based on original expressions, even with advanced optimizations.
However, there exists no clojurescript compiler option for that.

Proposal:
Add a :debug compiler option to clojurescript, which can be set to true to turn the following closure compiler options on:

  • generatePseudoNames true
  • anonymousFunctionNaming AnonymousFunctionNamingPolicy/UNMAPPED

Attached patch implements this, as a result the compiled test suite is indeed quite readable.



 Comments   
Comment by Herwig Hochleitner [ 19/May/13 10:11 AM ]

Patch 0001 depends on patches 0001 and 0002 from CLJS-480 because of changes to the test script.





[CLJS-5] Compiler should emit optional source maps Created: 24/Jun/20  Updated: 22/Dec/12

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

Type: Enhancement Priority: Major
Reporter: Anonymous Assignee: David Nolen
Resolution: Unresolved Votes: 4
Labels: None


 Description   

== New Notes ==

http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/

Source map support will be landing in Chrome in 6 weeks.

== Old Notes ==

Google's debugging tooling consists of at least these two big pieces:

  • The `--create_source_map` compiler flag, which generates a table mapping source JS to compiled JS
  • The [Closure Inspector](http://code.google.com/closure/compiler/docs/inspector.html), a Firefox plugin that uses the source maps to provide error messages pointing to original code instead of compiled code

Open Questions

  • What does integrating with Closure Inspector look like?
  • Can we use code from gclosure to generate our own cljs ��� compiled JS mappings?
  • Would we need to modify Closure Inspector?

Imported from github issue #31



 Comments   
Comment by David Nolen [ 06/Apr/12 3:03 PM ]

There's a patch for Clojure, here CLJ-960

Related, https://github.com/brandonbloom/clojurescript/compare/clojure:master...brandonbloom:track-pos

Comment by David Nolen [ 01/Jun/12 8:49 AM ]

wip here http://github.com/clojure/clojurescript/tree/source-map

Comment by David Nolen [ 03/Jun/12 11:03 AM ]

Related ticket (tracking line & col during emission) that was resolved - http://dev.clojure.org/jira/browse/CLJS-176

Comment by Chouser [ 24/Jun/20 12:00 AM ]

Later





[CLJS-29] Automate pre-push testing Created: 22/Jul/11  Updated: 04/Apr/12

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

Type: Task Priority: Minor
Reporter: Brenton Ashworth Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Document the steps to follow to test that nothing is broken before pushing changes.

Automate this process.



 Comments   
Comment by David Nolen [ 04/Apr/12 11:35 PM ]

Do we need something more sophisticated then this: http://github.com/clojure/clojurescript/wiki/Running-the-tests





[CLJS-37] A way to create js objects and arrays from cljs maps and vectors, without copying if possible. Created: 26/Jul/11  Updated: 18/Sep/12

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

Type: Enhancement Priority: Minor
Reporter: Chouser Assignee: Unassigned
Resolution: Unresolved Votes: 4
Labels: None

Attachments: Text File 0001-Add-as-js.-CLJS-37.patch    
Patch: Code and Test

 Description   

There's currently no convenient way to create a js object from a map. Arrays can be created using the `array` function, but this always creates a copy. In cases where you know the object or array will not be modified, it would be a shame to still pay for a copy of the object. This is especially true when the cljs map or vector is a literal such that nothing else can have a reference to it anyway.



 Comments   
Comment by Chouser [ 26/Jul/11 11:07 PM ]

My plan is a macro `as-js` that takes a single expression. If it's a literal vector or map, it will expand to a js* form that will emit the appropriate array or object literal. In the case of a map, all the keys must be constants (string, keyword, or symbol) in order to for this to work since literal object keys in javascript aren't evaluated. Keyword and symbol keys would be converted to strings.

If the argument to the `as-js` macro isn't a literal (or is a map with non-constant keys), the macro will expand to a call to an `-as-js` protocol fn. When called on a vector, the vector will return its internal array. When called on an ObjMap whose keys are all s convtrings, its internal strobj will be returned. If any of the ObjMap's keys are not strings, then no appropriate js obj exists and a new one will be created, converting keys to strings just like the macro above. HashMaps never contain an appropriate js object, so a new one would be created, again converting keys to strings.

So in the common case of maps whose keys are known at compile time, such as (as-js {:foo "bar" :baz (str "qu" "ux")}), this would at compile time become the js obj literal {"foo": "bar", "baz" cljs.core.str("qu", "ux")}. When the map or vector is not a literal, the least possible copying is done to produce the correct obj or array at runtime.

...why do I have this annoying feeling that I may have done something too compound here?

Comment by David Nolen [ 28/Oct/11 6:58 PM ]

Some work towards a solution: https://github.com/clojure/clojurescript/compare/37-support-for-js-literals

Comment by Chouser [ 28/Oct/11 8:53 PM ]

The macro-based solution I outlined above is unacceptable.

The key issue is that Rich wants the reader to actually create the target type (js array or object) at read time, so special reader syntax is required. I think the syntax was to be #js[1 2 3] for arrays and #js{k v k v} for objects. Then of course there needs to be support in the compiler to generate code that evaluates the array elements and the object values (but not their keys, since the js literal produced can't have expressions for keys).

Comment by Aaron Brooks [ 29/Oct/11 12:28 PM ]

Does a special reader syntax ask for something readable across other platforms? i.e. #native[]/#native{}

It seems that this would enhance the ability of ClojureScript libraries to be reusable across other platforms. It's easier to get around macro/function differences between platforms, however reader syntax differences would cut off the options for sharing source files between Clojure platforms.

Comment by Nicolas Buduroi [ 11/Apr/12 12:30 AM ]

Any update on this issue?

Comment by David Nolen [ 11/Apr/12 2:41 PM ]

Waiting on whether Clojure becomes a JSON superset.





[CLJS-61] All global vars (f.e. __dirname) of node.js should be in cljs.nodejs Created: 27/Aug/11  Updated: 04/Apr/12

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

Type: Defect Priority: Minor
Reporter: Javier Neira Sanchez Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

clojure 1.3.0-alpha-8
clojurescript commit 22a64ff17b343b6c61039fcb66fd9acf34d98522
windows vista
node.js version v0.4.11



 Description   

To get access of all node.js goodies without using js* it would be nice to all global variables of node.js (http://nodejs.org/docs/v0.4.11/api/globals.html#process) were part of the module cljs/nodejs
Thanks






[CLJS-81] cljsc :externs flag fails when opts map not quoted Created: 23/Sep/11  Updated: 02/Jun/12

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

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


 Description   

For example, in the samples/hello-js directory, running the following works fine:

    cljsc src '{:optimizations :advanced :output-to "hello-extern.js" :externs ["externs.js"]}'

However, the following fails:

    cljsc src {:optimizations :advanced :externs ["./externs.js"]} > hello-extern.js

With the error message "Exception in thread "main" java.lang.IllegalArgumentException: No implementation of method: :as-file of protocol: #'clojure.java.io/Coercions found for class: clojure.lang.Symbol".

Fully qualifying the path to externs.js seems to work, BUT it actually fails by placing an exception message into the hello-externs.js file.



 Comments   
Comment by Brian Taylor [ 02/Jun/12 4:48 PM ]

I think your shell (bash?) may be treating the [...] portion of that expression as a character class and substituting matches from the file system. I'm not aware of any method for avoiding this other than changing shells to one that won't try to expand the [...].

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_03.html

Perhaps we should change the documentation examples so that they always quote the opts map. Maybe that would help avoid confusion.





[CLJS-91] cljsc does not copy dojo dependencies Created: 14/Oct/11  Updated: 14/Oct/11

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

Type: Defect Priority: Minor
Reporter: Jason Thomas Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

When I run "cljsc.bat src > hello.js" on as program that uses Dojo it does not copy the Dojo dependencies to the out directory. If I manually copy the Dojo dependencies it works fine. I did create a dojo.jar file in the clojurescript/lib folder.

Here is the program and html:

(ns hello (:require [dojo :as dojo]))
(defn ^:export say-hello [] (dojo/place "<div>hello world</div>" (dojo/body)))

If this is really a bug as opposed to expected behavior, I can sign a CA and take a crack at fixing it.






[CLJS-101] Node fails with :whitespace, works with :simple Created: 17/Nov/11  Updated: 29/Sep/12

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

Type: Defect Priority: Minor
Reporter: Ulrik Sandberg Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

NodeJS 0.6.1
MacOSX Lion



 Description   

Running the example from http://mmcgrana.github.com/2011/09/clojurescript-nodejs.html. Node fails if using :whitespace optimizations, but works when using :simple. The problem seems to be missing object literals.

The source is:

$ cat src/testing-cljs-node/hello.cljs 
(ns testing-cljs-node.hello)

(defn start [& _]
  (println "Hello World!"))

(set! *main-cli-fn* start)

Here is the compilation that results in the broken code:

$ cljsc src/testing-cljs-node/hello.cljs '{:optimizations :whitespace :pretty-print true :target :nodejs}' > out/hello.js
$ node out/hello.js

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
TypeError: Cannot set property 'Unicode' of undefined
    at Object.<anonymous> (/Users/ulrik/Source/testing-cljs-node/out/hello.js:487:21)
    at Module._compile (module.js:432:26)
    at Object..js (module.js:450:10)
    at Module.load (module.js:351:31)
    at Function._load (module.js:310:12)
    at Array.0 (module.js:470:10)
    at EventEmitter._tickCallback (node.js:192:40)

When changing the optimizations to :simple, however, it works:

$ cljsc src/testing-cljs-node/hello.cljs '{:optimizations :simple :pretty-print true :target :nodejs}' > out/hello.js
$ node out/hello.js
The "sys" module is now called "util". It should have a similar interface.
Hello World!

The offending line 487 in the :whitespace code:

goog.provide("goog.string");
goog.provide("goog.string.Unicode");
goog.string.Unicode = {NBSP:"\u00a0"};  // line 487

In the working :simple code, the corresponding lines looks like this:

goog.string = {};
goog.string.Unicode = {NBSP:"\u00a0"};  // line 367

If I fix that by adding a line that creates the object, I get another error on line 901:

goog.provide("goog.userAgent.jscript");
goog.require("goog.string");
goog.userAgent.jscript.ASSUME_NO_JSCRIPT = false;  // line 901

In the working code, it looks like this:

goog.userAgent = {};
goog.userAgent.jscript = {};
goog.userAgent.jscript.ASSUME_NO_JSCRIPT = !1;  // line 683

And if I fix that, I get another error on line 975:

goog.provide("goog.debug.Error");
goog.debug.Error = function(opt_msg) {  // line 975

The working code:

goog.debug = {};
goog.debug.Error = function(a) {  // line 730

etc etc



 Comments   
Comment by David Nolen [ 19/Apr/12 11:49 PM ]

I'm not sure how to fix this since the implementation of goog.provide has no meaning in Node.js. As a compromise perhaps we should complain if you try to target node with :whitespace optimizations?

Comment by Ulrik Sandberg [ 20/Apr/12 5:50 AM ]

Sure, that would probably be sufficient to point the user to what the problem really is.

Perhaps it's obvious to everyone else that :whitespace doesn't make sense for Node, but it wasn't to me. But I can now deduce that :simple maybe resolves all provide/require into a single file, whereas :whitespace is an intermediate format that is not applicable for Node.

Comment by David Nolen [ 20/Apr/12 11:29 AM ]

I don't think it's obvious at all and many people have encountered this issue.

Comment by Tom Jack [ 16/Aug/12 2:54 AM ]

Something that seems to work is

#!/usr/bin/nodejs
var _cljsGlobal_ = {};
with (_cljsGlobal_) {
var COMPILED = false;
_cljsGlobal_.goog = {};
goog.global = _cljsGlobal_;
// ... rest of source
}

Does this cause any problems other than forcing e.g. ;module.exports = _cljsGlobal_.mori; in whitespace mode?

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

Using with is probably not an acceptable solution.

Comment by David Nolen [ 28/Sep/12 10:08 PM ]

nclosure actually sounds kind of promising! Do we need to do anything more then recommend that people install nclosure if they want to work :whitespace or :none for the optimization level? If the nclosure approach is simple enough we could perhaps duplicate the strategy?

Comment by Paul deGrandis [ 29/Sep/12 5:27 PM ]

Haha I deleted the comment after I started digging into the code. I'll try to capture my adventure here.

CLJS's node compat layer is built in the opposite direction as nclojure - that is, we provide an externs file for node, and assume interop will happen that way.
nclosure's approach is to hijack the base interactions with goog, and decide to dispatch accordingly to Node or to the Closure lib, but it expects you're writing node-based code. Everything is pushed into shared object off of the node `globals`.

My hypothesis was: I can use the nclosure stuff, but allow ALL dispatching to go to closure (since we have externs file), which very well may call node stuff in the end. The small shim would allow for skirting around the issues described here.

I hacked together the js files and copied the result in to my CLJS-compiled-JS file. All looked good except - the nclosure JS code needs to be inserted into the file before compilation happens. The nclosure stuff redefines core goog interactions, which is why it works. Technically, we could do a preamble hook when we're gathering all the the files together (much like how main-cli-fn is at the tail of all files).

That said, when inserted into the right spot, it prevents the errors.





[CLJS-147] Method to specify externs that should be used by the the compiler in jar-ed non-gclosure/foreign javascript libs Created: 09/Feb/12  Updated: 04/Apr/12

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

Type: Enhancement Priority: Minor
Reporter: Dave Sann Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Please see discussion here:

https://groups.google.com/d/topic/clojure/kqtCC_stbEU/discussion



 Comments   
Comment by David Nolen [ 04/Apr/12 5:53 PM ]

Have you looked lein cljs-build. Does the extern feature there address the issue?





[CLJS-163] Using ^:extern in repl fails Created: 15/Mar/12  Updated: 17/Jun/12

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

Type: Defect Priority: Minor
Reporter: icyrock.com Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

ClojureScript version used:

commit aa51a01141131736871e791918df63f185155421
Author: David Nolen <dnolen@Davids-MacBook-Pro.local>
Date: Wed Mar 14 20:21:07 2012 -0400



 Description   
ClojureScript:cljs.user> (defn ^:export a [])
"Error evaluating:" (defn a []) :as "cljs.user.a = (function a(){\nreturn null;\n});\ngoog.exportSymbol('cljs.user.a', cljs.user.a);\n"
org.mozilla.javascript.EvaluatorException: missing ; before statement (<cljs repl>#41)

nil
ClojureScript:cljs.user> (defn a [])
#<
function a() {
    return null;
}
>
ClojureScript:cljs.user>





[CLJS-167] Allow exiting CLJS repl with EOF/ctrl-D as well as :cljs/quit Created: 24/Mar/12  Updated: 08/Oct/12

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

Type: Enhancement Priority: Minor
Reporter: Alan Malloy Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File quit.patch    
Patch: Code

 Description   

The CLJS repl is not a perfectly well-behaved command-line tool, in that it does not respect the convention of quitting by sending an EOF character with ctrl-D. This must be causing a small amount of irritation to everyone who uses the repl and is used to the customary amenities of any command-line tool; we could ease a little bit of frustration by supporting EOF.

I've attached a patch to improve this behavior, without affecting anything else.



 Comments   
Comment by Frank Siebenlist [ 08/Oct/12 11:20 AM ]

I like the idea, but I normally start the cljs-repl from a clj-repl with

user=> (run-repl-listen 9000 ".lein-cljsbuild-repl")

and then the proposed solution seems to exit both the cljs-repl and the clj-repl as well with a single ctrl-D, which increases the irritation with a small amount...

Sorry, I'm not well versed enough in the IO intricacies to provide an alternative.





[CLJS-171] Implement Pods Created: 28/Mar/12  Updated: 17/Jun/12

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

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


 Description   

It would be interesting to implement Pods in ClojureScript so that transients can become an implementation detail.






[CLJS-186] ClojureScript wiki/The-REPL-and-Evaluation-Environments - small issues Created: 19/Apr/12  Updated: 30/May/12

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

Type: Defect Priority: Minor
Reporter: Mike Lamb Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: documentation, wiki


 Description   

I just worked through the "The REPL and Evaluation Environments" wiki page and had to make the following change to get the example to work.

— The-REPL-and-Evaluation-Environments.md.0 2012-04-19 17:40:23.000000000 -0400
+++ The-REPL-and-Evaluation-Environments.md 2012-04-19 17:40:48.000000000 -0400
@@ -57,6 +57,7 @@
<body>
<div id="content">
<script type="text/javascript" src="out/goog/base.js"></script>
+ <script type="text/javascript" src="out/goog/deps.js"></script>
<script type="text/javascript" src="foo.js"></script>
<script type="text/javascript">
goog.require('foo');

Something else I noticed was that I didn't get the "Starting server on port 9000" message.



 Comments   
Comment by Brian Taylor [ 30/May/12 4:26 PM ]

In my environment, the deps.js script tag is appended to the page automatically as a side-effect of loading base.js.

base.js (line 613 in my release)

// Allow projects to manage the deps files themselves.
  if (!goog.global.CLOSURE_NO_DEPS) {
    goog.importScript_(goog.basePath + 'deps.js');
  }




[CLJS-197] Minor additions to clojure.browser.dom Created: 23/Apr/12  Updated: 30/Sep/12

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

Type: Enhancement Priority: Minor
Reporter: Moritz Ulrich Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-add-clojure.browser.dom-remove-node.patch     Text File 0002-docstrings-for-clojure.browser.dom.patch    
Patch: Code

 Description   

These two patches add clojure.browser.dom/remove-node and some missing docstrings to clojure.browser.dom.

What else can be done in this namespace? I don't want to break things, but I think some functions (log, click) don't really belong there.



 Comments   
Comment by David Nolen [ 23/Apr/12 11:26 AM ]

It's not my impression that clojure.browser.dom is meant to be a library for general consumption (though I could be wrong). I think it's there to support browser REPL and the samples.

Comment by Moritz Ulrich [ 23/Apr/12 5:00 PM ]

You might be right. It's still a very useful piece of code and makes DOM manipulation much more "clojure-y". I think it should be kept and improved.

Comment by Edward Tsech [ 30/Sep/12 10:14 AM ]

As I can see clojure.browser.dom isn't used in clojure.browser.repl. Is it there only for samples?





[CLJS-210] Implement Var form, var-get, and var? in CLJS Created: 27/Apr/12  Updated: 28/Oct/12

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

Type: Enhancement Priority: Minor
Reporter: Brandon Bloom Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: patch,

Attachments: Text File vars1.patch    
Patch: Code and Test

 Description   

See discussion of Vars in CLJS here: http://dev.clojure.org/display/design/Dynamic+Binding
My goal is to eventually implement dynamic scope capture, via bound-fn and friends. The attached patch is a step in that direction.

This patch adds support for parsing the (var foo) form. The #' reader macro is provided by JVM Clojure.

#'foo emits code to construct a Var object. In this patch, each invocation of 'var will create a unique Var object. This means they are '= by fully qualified symbol, but not 'identical?. Simple memoization would fix that, but I'm not going to bother until I get to Dynamic Var objects.

The main advantage of this level of Var support is for the interactive development convenience of being able to defer dereferencing top-levels. For example, (def fog (comp f #'g)) will pick up redefinitions of 'g, but not of 'f.



 Comments   
Comment by Brandon Bloom [ 28/Apr/12 10:07 PM ]

I found two issues with this patch:

1) I never used the IVar that I declared :-P

2) (apply #'+ (range 100)) throws "Invalid arity: 101" – this is related to http://dev.clojure.org/jira/browse/CLJS-211

I'll look into fixing both. However, we should discuss supporting variable arity protocol methods...

Comment by David Nolen [ 17/Jun/12 12:17 PM ]

any support for reified vars is a low priority for the foreseeable future.

Comment by Brandon Bloom [ 01/Sep/12 7:46 PM ]

Reified vars (and binding frames!) are a requirement for a CPS transform to be correct with respect to dynamic bindings.

Comment by Tom Jack [ 10/Sep/12 5:11 PM ]

+1 towards bound-fn and friends. I had an explanation written here but now I see "async Javascript (ie. nearly all Javascript) makes the binding macro effectively useless without bound-fn". Indeed.

Comment by Herwig Hochleitner [ 28/Oct/12 7:34 PM ]

bound-fn could also be implemented by setting / resetting bound vars before / after the wrapped fn, similar to binding. We would just need to add tracking of the currently rebound dynamic vars.
That should also be CPS - friendly, no?

Comment by Tom Jack [ 28/Oct/12 9:03 PM ]

I've considered that and would love to see it happen.

But what about:

(def ^:dynamic *foo* 3)
(set! *foo* 4)
(def f (bound-fn [] *foo*))
(set! *foo* 5)
(f)




[CLJS-257] optimize dead code elimination Created: 16/May/12  Updated: 20/Feb/13

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

Type: Defect Priority: Minor
Reporter: David Nolen Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None


 Description   

When compiling some code I noticed that cljs.core.apply doesn't get removed, I suspect this may trigger other fns to also not get eliminated. Needs investigation.



 Comments   
Comment by David Nolen [ 16/May/12 12:45 PM ]

It looks like removing apply manually eliminates apply-to as expected. Another dead code elimination issue - the global-hierarchy atom. No need to emit this if the user never uses multimethods.

Comment by David Nolen [ 20/Feb/13 8:43 AM ]

Global hierarchy atom issue has been addressed in master.





[CLJS-270] Warn if ISeq is implemented and ISeqable and ICollection are not Created: 24/May/12  Updated: 30/May/12

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

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





[CLJS-287] Allow extending 'set-options' for Closure Compiler Created: 31/May/12  Updated: 31/May/12

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

Type: Enhancement Priority: Minor
Reporter: Sergei Lebedev Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Currently, ClojureScript only exposes a limited set of options to the API users. Would be nice to have a way of extending cljs.clojure/set-options to handle arbitrary options, like --define (which is already covered in CLJS-77).






[CLJS-295] remove the full inst literal test - adds 10 seconds to test runs when testing all the major JS engines Created: 03/Jun/12  Updated: 17/Jun/12

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

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


 Comments   
Comment by David Nolen [ 17/Jun/12 12:04 PM ]

To be honest this mostly affects people doing performance work who run the tests against all three JS engines. The tests execute fairly quickly under V8, but they take a long time under JavaScriptCore and SpiderMonkey. I understand that the full tests are desireable - would be nice if there was a way to run :all or :core benchmarks, or something like that.





[CLJS-338] Incorrect implementation of IReduce by ArrayChunk Created: 22/Jul/12  Updated: 14/Aug/12

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

Type: Defect Priority: Minor
Reporter: Anton Frolov Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bug


 Description   

(reduce + (array-chunk (array 1 2 3 4) 1 3)) => 2 (instead of 5)
(reduce + 0 (array-chunk (array 1 2 3 4) 1 3)) => 3 (instead of 5)
(reduce + (array-chunk (array 1 2 3 4) 1 1)) => 2 (instead of 0)

In src/cljs/cljs/core.cljs, line #1817:
(deftype ArrayChunk [arr off end]
;; ...
IReduce
(-reduce [coll f]
(ci-reduce coll f (aget arr off) (inc off))) ;; should be (if (< off end) (ci-reduce coll f (aget arr off) 1) 0)
(-reduce [coll f start]
(ci-reduce coll f start off))) ;; should be (ci-reduce coll f start 0)



 Comments   
Comment by David Nolen [ 14/Aug/12 6:29 AM ]

Thanks for the report. ArrayChunk is an implementation detail - do these conditions actually arise?





[CLJS-339] (inc nil) returns 1 instead of throwing an exception Created: 23/Jul/12  Updated: 23/Jul/12

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

Type: Defect Priority: Minor
Reporter: Evan Mezeske Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bug


 Description   

(inc nil) => 1 in ClojureScript
(inc nil) => raise NullPointerException in Clojure

I think that Clojure's behavior (throwing) makes more sense in this context.



 Comments   
Comment by Evan Mezeske [ 23/Jul/12 12:44 AM ]

I observe that in my JS console, "undefined + 1 => NaN" but "null + 1 => 1". I assume this has something to do with this issue.

Comment by David Nolen [ 23/Jul/12 12:30 PM ]

Do you have any suggestions on how to make this work without slowing arithmetic down? If not I'm inclined to close this as Won't Fix.

Comment by Evan Mezeske [ 23/Jul/12 12:50 PM ]

I do not. I haven't had a chance to put a lot of thought into it, though.

I consider this kind of problem to be rather insidious. Null is not a number, and treating it as zero will lead to nasty bugs creeping into people's code.

A historical anecdote: the C function "int atoi(char* s)" takes a string and returns the number it represents. However, if the string can't be converted, it returns zero (which could also be a valid result for e.g. the string "0"). Technically, it's possible to distinguish "0 meaning error" and "0 meaning 0" by taking additional steps after the function call, but in practice people forget to do this. Thus, atoi is universally a disaster. I have literally seen the lights go off in a warehouse due to atoi's poor design (I used to work in building control).

Treating null as zero will result in similar problems. Someone forgets to check the result of a computation, it's null, and the program silently continues as if nothing is wrong. Hello, data corruption.

So I seriously urge you to not close this as Won't Fix, even if a performant solution is not yet obvious. IMHO it's worth more thought.

Comment by David Nolen [ 23/Jul/12 12:56 PM ]

Closing as Won't Fix doesn't mean we don't care, but this issue is simply a symptom of something much larger - punting on numerics. A ticket is the wrong place for this discussion as it has many nuances. It should be a part of a larger design for ClojureScript numerics. Without that larger discussion this ticket is likely to get stuck in limbo.

Comment by Evan Mezeske [ 23/Jul/12 12:59 PM ]

Fair enough! I thought Won't Fix had stronger implications than that. Do you know if there's already a design doc that addresses numerics? Or should I start one?

Comment by Fogus [ 23/Jul/12 1:04 PM ]

One place that this has burned me, that may warrant a separate card is

(update-in some-map [:foo :bar] inc)
where the key at that location did not exist. I would have preferred an exception rather than an broken 1.

Comment by Evan Mezeske [ 23/Jul/12 1:09 PM ]

@Fogus: Huh, that is the exact same use-case that burned me – I was using update-in/inc on a nested map. The default value for my [:foo :bar] was, in fact, supposed to be zero, so it silently worked for me. But when I moved that code from the client in my webapp (ClojureScript) to the server (Clojure), I found out that my original implementation was wonky.

Comment by David Nolen [ 23/Jul/12 1:17 PM ]

It doesn't seem to me that you could do that safely without fnil + 0. I too hate JS's silent failures around numerics. Been hoping someone would tackle this challenge with gusto.

Comment by Evan Mezeske [ 23/Jul/12 1:21 PM ]

@David Nolen: Yeah, fnil would do the job. In my case, I was calling update-in on what I thought was an initialized map, but it was actually nil. update-in initialized each level of nesting with an empty map, and then inc was called on nil. My fix was simply to initialize the nested maps like I meant to.

Comment by Fogus [ 23/Jul/12 1:21 PM ]

David,
That was ultimately the solution, so I suppose we need to start advocating this pattern so that others might avoid the same fate.





[CLJS-349] cljs.compiler: No defmethod for emit-constant clojure.lang.LazySeq Created: 30/Jul/12  Updated: 31/Oct/12

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

Type: Defect Priority: Minor
Reporter: Julien Fantin Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-CLJS-349-Allow-ISeq-to-be-emitted-by-macros-as-a-con.patch     File fixbug349.diff    

 Description   

The cljs compiler errors when trying to emit-constant for a clojure.lang.LazySeq.

Example : https://www.refheap.com/paste/3901

Here syms is defined as a LazySeq on line 3, then on line 7 it is quoted. The error is included in the refheap.

Emitting a cljs.core.list for this type seems to solve the issue.



 Comments   
Comment by David Nolen [ 31/Aug/12 9:27 AM ]

Can you identify precisely where a LazySeq is getting emitted here? A LazySeq is not literal so this seems like a bug in the macro to me. I could be wrong. Thanks!

Comment by Herwig Hochleitner [ 28/Oct/12 9:31 PM ]

The lazy seq seems to be introduced on line 7, the '~syms form

`(let [mappings# (into {} (map-indexed #(identity [%2 %1]) '~syms))

Clojure allows lazy-seqs to be embedded: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L4538

As an aside: The relevant protocol is not literality, but the print-dup multimethod. Do / Should we have print-dup in CLJS?

Comment by Herwig Hochleitner [ 31/Oct/12 10:10 PM ]

Attached patch 0001 doesn't add a case for LazySeq, but folds two cases for PersistentList and Cons into one for ISeq.





[CLJS-353] Use different primitives for array access and property/object access Created: 09/Aug/12  Updated: 29/Aug/12

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

Type: Defect Priority: Minor
Reporter: Raphaël AMIARD Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-CLJS-353-Use-different-primitives-for-array-access-a.patch     Text File 0001-CLJS-353-Use-different-primitives-for-array-access-a.patch    

 Description   

In javascript, array access (array[index]) and property access (object["property"]) have the same syntax, hence aget/aset are used for both in the core library.

But this isn't true for every target language. For example in Lua, there are no arrays, so if you want to have an array like container, array access will need to go through a function.

This patch proposes to add new builtins : oget and oset (for obj-get obj-set) and use them where appropriate. The generated code will be the same for javascript, but will enable alternate backend implementers to treat both differently



 Comments   
Comment by Raphaël AMIARD [ 09/Aug/12 7:24 AM ]

All test pass

Comment by David Nolen [ 09/Aug/12 5:26 PM ]

Not sure I like the names oget/set. How about obj-get obj-set?

Comment by Raphaël AMIARD [ 10/Aug/12 4:08 AM ]

fine by me, added a new patch !

Comment by David Nolen [ 10/Aug/12 11:07 AM ]

The patches are identical.





[CLJS-381] Implement cljs$lang$applyTo on String.prototype instead of apply Created: 20/Sep/12  Updated: 21/Nov/12

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

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


 Comments   
Comment by Laszlo Török [ 20/Nov/12 9:42 AM ]

Why is this needed?

Comment by David Nolen [ 20/Nov/12 6:27 PM ]

It's a bit ugly, not to mention asking for clashes to implement apply instead of cljs$lang$applyTo.

Comment by Laszlo Török [ 21/Nov/12 9:48 AM ]

So the expectation here is having

(apply js/String [1])

result in "1"?

Since js/String is a built-in function object (defmethod emit :fn ...) will not produce cljs$lang$applyTo magic.

So is this sg for the compiler to do in a bootstrap step or rather a (set! String.prototype.cljs$lang$applyTo ...) hack?

Comment by David Nolen [ 21/Nov/12 10:19 AM ]

Lowering the priority on this ticket. If have we have real Keywords & Symbols we don't need to bother with this.





[CLJS-407] cljs.import-test not run in test suite / ordering problem in the compiler Created: 24/Oct/12  Updated: 21/Dec/12

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

Type: Defect Priority: Minor
Reporter: Herwig Hochleitner Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-CLJS-407-Hook-up-cljs.import-test-to-the-test-runner.patch    

 Description   

The test code from CLJS-312 is not hooked up to the test suite, which is trivially fixed.

Hooking up the test, however reveals a deeper problem (besides that it has a failing assumption):

Presumably due to the goog.provides later in the files, the compiler orders the output wrong, which results in not provided errors.
Most interestingly, this problem goes away, when compiling from a prepopulated out directory, presumably because then the closure compiler handles the ordering?



 Comments   
Comment by Herwig Hochleitner [ 24/Oct/12 3:23 AM ]

Patch hooks up the tests into the test suite.

If you want to see the provide error, delete out before compiling.

If you want to see the failing assertion from the original test, compile a second time.

Comment by David Nolen [ 24/Oct/12 11:01 AM ]

In order to better understand tickets it best not to complect different issues If there's a problem not addressed by the patch please mention that in another ticket (and feel to reference that one here).

I assume the patch fixes one thing, but reveals an unresolved issue, am I correct?

Comment by Herwig Hochleitner [ 24/Oct/12 11:26 AM ]

You're right, the ordering problem could be a different ticket. Sorry for that.

To clarify, there are three issues at play:

1) Part of the testsuite not executed (fixed by the patch)
2) The part that is now executed fails, didn't have time this morning to find out the original intention of Michał, can probably do tomorrow, if he doesn't pick it up.
3) The compilate is different depending on whether the .js file is cached in out/. This might require some deeper investigation.

The reason I decided to roll it into one ticket is that only addressing one of 2) and 3) leaves the test suite failing. I almost wanted to reopen CLJS-312, but decided against it, since it's water under the bridge.

Comment by David Nolen [ 21/Dec/12 6:07 PM ]

I fixed some dependency ordering issue in another patch, would be nice to know if the ordering issues are addressed. What part of this ticket is still relevant? This is why tickets that only address one thing at a time are nice





[CLJS-412] Undeclared warning when defining protocols Created: 29/Oct/12  Updated: 21/Dec/12

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

Type: Defect Priority: Minor
Reporter: Brandon Bloom Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Evaluate the following in a ./script/repl session

(require '[cljs.compiler :as comp])
(require '[cljs.analyzer :as ana])

;; This trickery seems to be the minimum logic to prepare a top level namespace
(def repl-env
  (binding [ana/*cljs-ns* 'cljs.user]
    (-> (ana/empty-env)
        (ana/analyze '(ns some-ns))
        :env
        (assoc :ns (ana/get-namespace ana/*cljs-ns*)))))

(defn analyze [form]
  (binding [ana/*cljs-warn-on-undeclared* true]
    (ana/analyze repl-env form)))

(-> '(defprotocol P
       (f [_ x]))
  analyze
  keys) ; keys is just so the output isn't huge

The first time you evaluate that last form, you get an error like this one:

WARNING: Use of undeclared Var some-ns/f at line 45

You'll get similar errors each time you rename f and re-evaluate the form.



 Comments   
Comment by Brandon Bloom [ 29/Oct/12 3:57 PM ]

Seems like the underlying issue is referring to a var while it is being defined. This form exhibits the same issue:

(def f [x] (aget f "prototype"))
Comment by Brandon Bloom [ 29/Oct/12 7:09 PM ]

The more I study this, the more I'm convinced that cljs-warn-on-undeclared is broken badly. Recursive functions (not using recur) generate this warning. As do certain parameters, locals, or other variable references that are actually defined. The issue seems to stem from a conflation between symbol definition and resolution. resolve-var, resolve-existing-var, and (parse 'def ...) are all tangled in a crazy mutually recursive way. A lot of that stems from a recursive analyze call to yield init-expr and ultimately fn-var? inside of the def parse code.

Comment by David Nolen [ 21/Dec/12 6:02 PM ]

Your first comment isn't valid code so I'm not sure what you mean. When I enter it correctly into the REPL I get no warnings. I also get no warnings when defining at a protocol at the REPL. Do you have a specific minimal CLJS project that exhibits the issue?





[CLJS-420] Unexpected behavior with dispatch on Keyword via protocols Created: 18/Nov/12  Updated: 18/Nov/12

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

Type: Defect Priority: Minor
Reporter: Max Penet Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bug, enhancement


 Description   

At the moment if you create a protocol and expect it to be able to dispatch on keywords you need to do it in js/String, trying to extend on cljs.core.Keyword doesn't work as keywords are just Strings.

See https://gist.github.com/4104635



 Comments   
Comment by David Nolen [ 18/Nov/12 3:14 PM ]

This is a known issue which will have to wait for if and when Keywords and Symbols become proper types in ClojureScript.

Extending js/Object is not recommended, if you actually need to add functionality to the base JS native types the convention is different from Clojure: default instead of Object, string instead of js/String. Please refer to core.cljs if you want more examples.

Comment by Max Penet [ 18/Nov/12 3:27 PM ]

Thanks for the pointer about default and string, I didn't know about that.

I reported the issue at the demand of bbloom. It does seem to be difficult to address without taking a (major) performance hit unfortunately.





[CLJS-428] Using */ inside of a docstring causes compiler to produce invalid JavaScript Created: 25/Nov/12  Updated: 22/Dec/12

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

Type: Defect Priority: Minor
Reporter: Murphy McMahon Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Linux, lein-cljsbuild



 Description   

Due to how function docstrings are output by the ClojureScript compiler, the use of

*/
within a docstring causes the compiler to produce invalid JavaScript, breaking compilation, since '*/' will close the docstring's JavaScript comment block and the remaining docstring text will be uncommented as a result.



 Comments   
Comment by Murphy McMahon [ 25/Nov/12 12:32 PM ]

I didn't realize JIRA treats asterisks as markup, so just for clarification: the characters that produce the defect are slash asterisk, ie JavaScript's block comment closing syntax.

Comment by David Nolen [ 22/Dec/12 3:30 PM ]

Do you have a suggested fix for this?





[CLJS-434] ClojureScript compiler prepends "self__" to defmulti forms when metadata in form of ^:field. Created: 01/Dec/12  Updated: 20/Jan/13

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

Type: Defect Priority: Minor
Reporter: Andrew Mcveigh Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bug
Environment:

Mac OS X (10.7), java version "1.6.0_37", leiningen 2 preview 10, cljsbuild 0.2.9.
clojure/clojurescript master 01 December 2012 - 5ac1503



 Description   

Using the def form, with the specific metadata ^:field causes the cljs compiler
to prepend "self__" to the output js form.

The browser (latest chrome/firefox) does not recognize "self__".

Test Case: Tested against master: 5ac1503
-------------

(ns test-def)

(def ^:foo e identity)
e
; test_def.e = cljs.core.identity;
; test_def.e;

(def ^:field f identity)
f
; test_def.f = cljs.core.identity;
; self__.test_def.f;
; Uncaught ReferenceError: self__ is not defined

https://gist.github.com/4185793



 Comments   
Comment by Brandon Bloom [ 01/Dec/12 5:37 PM ]

code tags

Comment by David Nolen [ 20/Jan/13 12:54 AM ]

This one is a bit annoying. We should probably use namespaced keywords internally.





[CLJS-443] protocol dispatch performance enhancement & extend-type to nil Created: 17/Dec/12  Updated: 20/Feb/13

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

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


 Description   

Currently we extend to nil to a bunch of protocols, while this was convenient for the initial implementation this has many unfortunate performance consequences. We should probably not extend nil to anything and deal with the nil value directly as is done in Clojure on the JVM. In addition we can add a special ^not-native type-hint. In critical paths this would allow us to inline calls directly to protocol implementations.

Perhaps this could also allow us to hint with ^native to inline calls to the native tables.



 Comments   
Comment by David Nolen [ 20/Feb/13 8:40 AM ]

^not-native support is already in master and does deliver performance benefits in the cases where native types need not be considered.





[CLJS-450] (ns) within (do) inconsistent with Clojure behaviour Created: 27/Dec/12  Updated: 05/Jan/13

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

Type: Defect Priority: Minor
Reporter: Stuart Campbell Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

An (ns) within a (do) doesn't quite work as expected at the REPL:

ClojureScript:cljs.user> (do (ns foo) (def x 42))   
nil
ClojureScript:foo> x
nil
ClojureScript:cljs.user> cljs.user/x
42

The Clojure equivalent:

user=> (do (ns foo) (def x 42))
#'foo/x
foo=> x
42


 Comments   
Comment by David Nolen [ 05/Jan/13 2:05 PM ]

Looks like we need to do something similar to what is done in Clojure with top level do - http://github.com/frenchy64/typed-clojure/pull/4





[CLJS-452] clojure.browser.net: enable WebSockets? Created: 31/Dec/12  Updated: 20/Jan/13

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

Type: Enhancement Priority: Minor
Reporter: Linus Ericsson Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: enhancement
Environment:

clojurescript in browsers, wrapper for Google Closures WebSocket.


Attachments: Text File 0001-enabled-websockets.patch    
Patch: Code

 Description   

In https://github.com/clojure/clojurescript/blob/master/src/cljs/clojure/browser/net.cljs there's a nicely prepared support for WebSockets with the note

;; WebSocket is not supported in the 3/23/11 release of Google
;; Closure, but will be included in the next release.

is there anything preventing us from enable the support for WebSockets with the next release of ClojureScript?

patch 0001-enable-websockets.patch do just enable the functionality. No test-cases included.



 Comments   
Comment by David Nolen [ 20/Jan/13 12:51 AM ]

Have you verified that this doesn't break browser REPL? Thanks!





[CLJS-453] ArrayVector for small vectors Created: 04/Jan/13  Updated: 04/Jan/13

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

Type: Enhancement Priority: Minor
Reporter: Jozef Wagner Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

master cljs, chrome


Attachments: Text File 0001-ArrayVector-New-vector-implementation-for-small-vect.patch    

 Description   

Just like we have an ArrayMap for small maps, I propose to have an ArrayVector for small vectors.

Use cases:

  • pair of values, e.g. coordinates, triples and other tuple values
  • returning multiple values from a function and subsequent destructuring in a caller fn

ArrayVector has 100x faster vector creation compared to PersistentVector.
With an ^ArrayVector hint, it offers more than 10x faster destructuring. Without it, it is still about 40% faster.

Example of such destructuring:

(defn foo [a b] 
  [(+ a b) (- a b) (* a b)])

(defn bar []
  (let [[plus minus times] ^ArrayVector (foo 1 2)]
    (str "bla bla" plus "blaah" minus)))

I've attached a patch with complete implementation of such vector, supporting all basic functionalities as well as transients. This patch also replaces default vector implementation with ArrayVector, falling back to PersistentVector for large vectors.

ArrayVector implementation can also be found at array-vec branch at https://github.com/wagjo/clojurescript/tree/array-vec



 Comments   
Comment by David Nolen [ 04/Jan/13 4:54 PM ]

Thanks! This interesting, it would be helpful to see a more comprehensive set of benchmarks on jsperf.com.





[CLJS-469] Bad Exception message when multimethod has no dispatch-fn Created: 12/Feb/13  Updated: 20/Feb/13

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

Type: Defect Priority: Minor
Reporter: Thomas Heller Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File cljs-multi-fn-ex-msg-inamed.patch    
Patch: Code

 Description   

When a multi-fn has no dispatch method for a given value the current exception string prints the cljs.core/name function instead of the actual name of the mf. Minor bug but makes it kinda hard to track down which multi-fn actually failed to dispatch.

The attached patch fixes that but directly accessing the name property of the multi-fn which is not very clean but better than the current error. AFAICT cljs doesnt have the clojure.lang.Named protocol, which would probably be cleaner.



 Comments   
Comment by Thomas Heller [ 12/Feb/13 6:12 AM ]

Corrected the .patch

Comment by David Nolen [ 19/Feb/13 8:54 AM ]

ClojureScript now has an INamed protocol

Comment by Thomas Heller [ 20/Feb/13 3:42 PM ]

Updated the .patch to implement INamed for cljs.core/MultiFn, turning its name into a real symbol.

Tests pass but I dont know if that part of the code is actually tested.

Comment by Thomas Heller [ 20/Feb/13 3:43 PM ]

Oh, I'm not quite sure that the way I resolved the namespace for the symbol is totally correct. It works but I had to dig a bit.





[CLJS-475] Node.js target fails with optimizations set to :none or :whitespace Created: 21/Feb/13  Updated: 01/Mar/13

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

Type: Defect Priority: Minor
Reporter: Paul Gearon Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: Compiler, bug
Environment:

Clojure 1.5.0-RC16
Clojurescript 0.0-1586
java version "1.7.0_04"
Java(TM) SE Runtime Environment (build 1.7.0_04-b21)
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)
OSX Mountain Lion 10.8.2


Attachments: GZip Archive out-none.tar.gz     GZip Archive out-whitespace.tar.gz     File pr.js-none     File pr.js-whitespace    

 Description   

Compiling a hello world program for Node.js works fine if using optimizations of :advanced or :simple, but if using :none or :whitespace then an error will be reported for either "goog undefined" or "goog.string" undefined respectively.

The program is shown here:

(ns pr.core)
(defn -main []
(println "Hello World!"))
(set! main-cli-fn -main)

This program is in src/cljs/pr/core.cljs. The repl line used to compile is:
(cljs.closure/build "src/cljs" {:output-to "src/js/pr.js" :target :nodejs :pretty-print true :optimizations :none})

When compiled with optimizations of :none, the output is:

$ node src/js/pr.js

/Users/pag/src/test/clj/pr/src/js/pr.js:1
(function (exports, require, module, __filename, __dirname) { goog.addDependen
^
ReferenceError: goog is not defined
at Object.<anonymous> (/Users/pag/src/test/clj/pr/src/js/pr.js:1:63)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:492:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)


When running with optimizations of :whitespace the output is:

$ node src/js/pr.js

/Users/pag/src/test/clj/pr/src/js/pr.js:493
goog.string.Unicode = {NBSP:"\u00a0"};
^
TypeError: Cannot set property 'Unicode' of undefined
at Object.<anonymous> (/Users/pag/src/test/clj/pr/src/js/pr.js:493:21)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:492:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)


When running with optimizations of either :simple or :advanced, the output is:

$ node src/js/pr.js
Hello World!


I have included the two javascript output files that match the above errors.



 Comments   
Comment by Paul Gearon [ 21/Feb/13 4:40 PM ]

Remaining generated files

Comment by David Nolen [ 25/Feb/13 3:46 PM ]

This is a known bug. We need goog.require/provide to actually mean something to Node.js. I'm not sure how this can be made to work. I've been hoping for a patch for this since ClojureScript was first announced, but I haven't seen anything yet.





[CLJS-476] Reading a value from a module does not work if the module is def'ed Created: 22/Feb/13  Updated: 22/Feb/13

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

Type: Defect Priority: Minor
Reporter: Paul Gearon Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: Compiler, bug, scope
Environment:

Clojure 1.5.0-RC16
Clojurescript 0.0-1586
java version "1.7.0_04"
Java(TM) SE Runtime Environment (build 1.7.0_04-b21)
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)
OSX Mountain Lion 10.8.2



 Description   

Referring to a value in a module can have a scoping issue when using the "static accessor" operator of module/VALUE_NAME. The static accessor works if the module is loaded into a local value but not if def'ed. This example uses the mmap module for Node.js, and successfully reads the PROT_READ value:

(ns stat.core)
(defn -main []
(let [m (js/require "mmap")]
(println "value: " m/PROT_READ)))
(set! main-cli-fn -main)

This correctly prints "value: 1"

However, if the value for m is def'ed instead, then the compiler assumes that the reference to m is local to the function and therefore not defined:

(ns stat.core)
(def m (js/require "mmap"))
(defn -main []
(println "value: " m/PROT_READ))
(set! main-cli-fn -main)

/Users/pag/src/test/clj/stat/target/stat.js:12836
return cljs.core.println.call(null, "value: ", m.PROT_READ)
^
ReferenceError: m is not defined
at Function.stat.core._main (/Users/pag/src/test/clj/stat/target/stat.js:12836:50)
at cljs.core.apply.b (/Users/pag/src/test/clj/stat/target/stat.js:5621:14)
at cljs.core.apply.a (/Users/pag/src/test/clj/stat/target/stat.js:5656:18)
at Object.<anonymous> (/Users/pag/src/test/clj/stat/target/stat.js:12844:17)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:492:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)

In this case, the value of m.PROT_READ should have been stat.core.m.PROT_READ.

On the other hand, using . syntax fixes the scoping issue:
(ns stat.core)
(def m (js/require "mmap"))
(defn -main []
(println "value: " (.-PROT_READ m)))
(set! main-cli-fn -main)






[CLJS-485] clojure.string/replace ignores regex flags Created: 12/Mar/13  Updated: 12/Mar/13

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

Type: Defect Priority: Minor
Reporter: Esa Virtanen Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: bug, patch, test

Attachments: Text File 0001-Take-regex-flags-m-i-into-account-in-clojure.string-.patch    
Patch: Code and Test

 Description   

The replace function in namespace clojure.string ignores regex flag provided in the match pattern. For example:

CLJS
clojure.string/replace "I am NOT matched" #"(?i)not " "")
=> "I am NOT matched"
CLJ
clojure.string/replace "I am NOT matched" #"(?i)not " "")
=> "I am matched"

The attached patch fixes this by parsing the m and i flags, if set, from the match object, instead of explicitly setting only "g".






[CLJS-487] Make cljsc copy js sources to public directory Created: 16/Mar/13  Updated: 16/Mar/13

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

Type: Enhancement Priority: Minor
Reporter: John Chijioke Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: cljs, cljsc, js
Environment:

Linux jetty web server



 Description   

I'll like cljsc to copy my js sources to the public directory as it does when compiling the cljs sources and make the correct entry in the generated deps.js so that the source can be retrievable with GET without extra configuration.






[CLJS-489] Browser-REPL automation & usability enhancements Created: 22/Mar/13  Updated: 30/Mar/13

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

Type: Enhancement Priority: Minor
Reporter: Chas Emerick Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: File CLJS-489.diff    
Patch: Code

 Description   

The current implementation of browser-REPL yields a number of usability problems:

  • only one browser-REPL can be used at a time due to globals used to track REPL state
  • Browser-REPL currently involves two web servers: the one you're serving your app from, and the one that the REPL itself uses
    • This makes setup difficult in the interactive case — especially for newcomers, the less experienced, or the tired
    • Perhaps more significantly, coordinating the two servers and their associated state is less than easy if one wants to automate the browser-REPL for testing of DOM-related cljs code

Attached is a patch that addresses these issues:

  • Multiple concurrent browser-REPLs can be safely used
  • The browser-REPL's HTTP server is now always-on
  • Replaced the custom HTTP server with com.sun.net.httpserver.* bits, which are a part of J2SE 6+, not random implementation details http://docs.oracle.com/javase/7/docs/technotes/guides/net/enhancements-6.0.html
  • Each browser-REPL session supports a new top-level "entry" URL that can be used to easily start the REPL in a browser or other JS runtime (i.e. you don't need to have a separate webapp running to initiate the browser-REPL connection)
  • The entry (and REPL) URLs are available in slots on the browser-REPL's environment, making it trivial to automate browser-REPL sessions with e.g. phantomjs or a headless chromium or etc. This pattern is implemented by a new `exec-env` function; the default is to start the REPL in phantomjs using a temporary script, but it's super-easy to use a regular browser. e.g. this will use Chrome on OS X in the background:
(cljs.repl/repl (cljs.repl.browser/exec-env
                  :exec-cmds ["open" "-ga" "/Applications/Google Chrome.app"]))

(This enhancement has been discussed previously {here|http://groups.google.com/group/clojurescript/browse_thread/thread/963d6b7334bdf61c}.)



 Comments   
Comment by Chas Emerick [ 22/Mar/13 3:24 AM ]

Aside: if this is accepted, a fair bit of documentation on the github wiki (and maybe dev.clojure.org wiki?) will need to be updated (something I'm happy to do FWIW).

Comment by Chas Emerick [ 22/Mar/13 3:54 PM ]

I just discovered that cljs.repl.reflect depends directly upon cljs.repl.server. I'll have to unroll that in order to be able to remove the latter...

Comment by Brenton Ashworth [ 29/Mar/13 5:24 PM ]

Thanks for working on this Chas. This has been in need of improvement for a long time. Can't wait to take this for a spin.

Comment by Chas Emerick [ 30/Mar/13 8:43 AM ]

I've never used cljs.repl.reflect, so I had to take a close look at what it supports, thus the delay.

First, background: cljs.repl.reflect provides backing support for two operations:

  • getting the documentation for a cljs "var" (i.e. any top-level function or other definition), and
  • obtaining the macroexpansion of a Clojure macro as provided by the ClojureScript analyzer

These operations are exposed within the ClojureScript REPL via clojure.reflect/doc and clojure.reflect/macroexpand, respectively.

I see a couple of issues here. First, aside from the problems in their current implementations (e.g. clojure.reflect/doc does not re-sugar arglists prior to printing them), both of these operations (doc and macroexpand) can simply be provided by macros, eliminating any dependence on a particular REPL environment/implementation. e.g., this does well for `doc`:

(defmacro doc
  [fq-sym]
  (let [meta (get-meta fq-sym)]
    `(do
       (println "-------------------------")
       (println ~(:name meta))
       (println ~(pr-str (map (partial mapv :name) (read-string (:method-params meta)))))
       (println " " ~(:doc meta)))))

A similar macro for macroexpand is trivial to produce.

Second, doc and macroexpand just don't belong in clojure.reflect. AFAICT, clojure.* namespaces in ClojureScript should be maximally isomorphic to their Clojure namesakes. This means that doc should be in clojure.repl; placing macroexpand is a little trickier, but perhaps a default-referred macro in cljs.core would make sense? (clojure.core/macroexpand is obviously already taken.)

So, my tl;dr plan (which I'll make concrete in a patch after circulating this comment on various mailing lists to get feedback) is:

1. reimplement doc and macroexpand as macros in more appropriate namespaces
2. rm the current cljs.repl.reflect and clojure.reflect namespaces

This should clear the way for the improved browser-REPL to land.





[CLJS-490] cljs.closure/get-upstream-deps* should use RT/baseLoader instead of the TCCL Created: 25/Mar/13  Updated: 25/Mar/13

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

Type: Defect Priority: Minor
Reporter: Toby Crawley Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None

Attachments: File 2013-02-25-closure-RT-baseloader.diff    

 Description   

get-upstream-deps* currently uses the context classloader for the current thread, which causes issues when called from within a clojure runtime that has the intended classloader bound to Compiler.LOADER. Is there a specific reason to use the TCCL directly, or would calling RT.baseLoader suffice here? I'm attaching a patch that uses baseLoader instead.



 Comments   
Comment by Toby Crawley [ 25/Mar/13 10:12 AM ]

On further examination, this change may not make sense. Clojure itself uses the TCCL directly and ignores baseLoader when locating resources.





[CLJS-494] -lookup method call inside get macro and keyword invoke Created: 10/Apr/13  Updated: 14/Apr/13

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

Type: Defect Priority: Minor
Reporter: Daniel Skarda Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Environment:

ClojureScript from githhub



 Description   

I noticed that -lookup method is called incorrectly at two places

There are two -lookup methods defined for ILookup:

cljs/cljs/core.cljs:198
(defprotocol ILookup
(-lookup [o k] [o k not-found]))

clj/cljs/core.clj:426
(defmacro get
([coll k]
`(-lookup ~coll ~k nil))
([coll k not-found]
`(-lookup ~coll ~k ~not-found)))

As you see, macro (get foo bar) never calls first method. In first case it supplies default argument (instead calling method with 2 arguments).

Same for IFn and keywords:

(deftype Keyword [k]
IFn
(invoke [_ coll]
(when-not (nil? coll)
(let [strobj (.-strobj coll)]
(if (nil? strobj)
(-lookup coll k nil)
(aget strobj k)))))



 Comments   
Comment by Jozef Wagner [ 12/Apr/13 3:37 AM ]

Note that 2 argument get guarantees to return nil if the key is not found. This differs from e.g. 2 argument nth, which should throw if key is not found (index is out of bounds). If 2 argument -lookup does not guarantee to return nil when key is not found, we should keep it as it is.

Comment by Michał Marczyk [ 12/Apr/13 5:13 AM ]

get insisting on nil is definitely by design, as explained by Jozef. So, there is no bug here.

As a matter of style it might be good to have get-the-function and get-the-macro do exactly the same thing; the question remains whether we should add an explicit nil to the -lookup call in get-the-function or remove the nil from the macro and just rely on -lookup to do the right thing. I'd probably go for the former to eliminate one unnecessary indirection (described below).

About -lookup "doing the right thing": it certainly seems to me that -lookup's contract is that of get, even if this is not explicitly documented; also, in almost all instances the binary -lookup delegates to ternary -lookup or ternary -nth (with nil supplied as the final argument), the exception being TransientHashMap's -lookup which basically has that call inlined.

Note that the binary -lookup is called is also called in some other places in core.cljs.

Comment by David Nolen [ 14/Apr/13 5:57 PM ]

Yes the main idea behind inlining get into -lookup was because they do essentially the same thing and we can remove a level of indirection. Similarly I'd prefer that we add the nil to -lookup to avoid the the indirection if not given a not-found value.





[CLJS-498] Reassess ObjectMap vs. PersistentArrayMap Created: 25/Apr/13  Updated: 25/Apr/13

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

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


 Description   

On V8, PAMs are competitive with OMs. On other browsers the performance doesn't look as good but this is probably due to the higher order code in array-map-index-of. We should remove the higher order code and more closely follow the Java PAM implementation which has different lookup loops for the different cases.






[CLJS-503] v8 penalizes coercive nil? Created: 04/May/13  Updated: 04/May/13

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

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


 Description   

We check for nil coercively with != and = because we want to handle both JavaScript null and undefined. These operations are slower than !== and ==. We would like to fix this but we can't simply make nil? not be coercive. The persistent data structures rely on this because they reach into JS Arrays that been allocated with a certain size. However in JS the empty slots are filled with undefined and null requiring the more expensive coercive nil? check.

Making nil? non-coercive seems to bring less of performance boost in WebKit/Firefox Nightlies, but v8 is still the king and everyone seems to be moving towards it performance wise.

One issue with making nil? non-coercive is that undefined will then fall through many of the core library functions. This means that users will need to be more careful in interop scenarios.






[CLJS-3] testing spike (assert, test.generative) Created: 16/Jun/20  Updated: 23/Aug/11

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

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


 Description   

Things we will need to have/work around:

  • clojure.walk
  • rethink deep-take (simple approach: omit)
    • or have a bindable var for compare-depth
  • fully qualified name hack
  • eval (macro time only?)
  • atoms
  • binding
  • development time namespace walking, or some other way to find tests
  • math fns

Imported from github issue #12



 Comments   
Comment by Chouser [ 24/Jun/20 12:00 AM ]

Comment by stuarthalloway, Thu Jun 16 00:37:49 2011:

Can I import the goog libraries when and as necessary to implement core fns? I assume I will need some math support for test.generative.

Comment by Chouser [ 24/Jun/20 12:00 AM ]

Comment by richhickey, Thu Jun 16 04:45:01 2011:

Yes, you should be able to require them, depends on #8

Comment by Chouser [ 24/Jun/20 12:00 AM ]

Later





[CLJS-13] Implement ratios Created: 12/Jul/20  Updated: 03/Sep/12

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

Type: Enhancement Priority: Minor
Reporter: Stuart Halloway Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Clojure.java contains support for Ratio types. It would be nice to have them in Clojurescript as well, but as far as I can tell this would be new development (please comment if I'm wrong). That is, there is no implementation of Ratio types in GClosure so this feature would need to be implemented from the ground up. In additional to the Ratio type, the following corresponding functions would also need implementations:

  • `ratio?`
  • `numerator`
  • `denominator`
  • `rationalize`

Plus the ratio type would need to be rolled into the existing mathematical frameworkings.

Imported from github issue #66



 Comments   
Comment by David Nolen [ 10/Oct/11 10:12 PM ]

What approach do you envision here given that we can't reliably detect integers in JavaScript?

Comment by Brandon Bloom [ 03/Sep/12 3:30 PM ]

See CLJS-370 for more reliable integer detection





[CLJS-288] Compilation of unordered collections Created: 31/May/12  Updated: 23/Sep/12

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

Type: Defect Priority: Trivial
Reporter: Brandon Bloom Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Given:

(defn f [x] (println x) x)

{(f 5) (f 10), (f :x) (f :y)}

Clojure produces:

5
10
:x
:y

{5 10, :x :y}

ClojureScript produces:

5
:x
10
:y

{5 10, :x :y}

 Comments   
Comment by Brandon Bloom [ 16/Aug/12 9:28 PM ]

See also: CLJ-1043

I realized that this problem is actually only partially solvable as is. We could assign the interleaved keys and values to locals before constructing the map. Unfortunately, that doesn't solve a bigger underlying problem: The reader returns unordered sets and maps.

Comment by David Nolen [ 31/Aug/12 9:23 AM ]

Is this actually a problem?

Comment by Brandon Bloom [ 23/Sep/12 7:40 PM ]

See discussion at http://dev.clojure.org/jira/browse/CLJ-1043?focusedCommentId=29526#comment-29526





[CLJS-297] Eliminate :meta, :vector, :set, and :map ops Created: 03/Jun/12  Updated: 31/Aug/12

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

Type: Enhancement Priority: Trivial
Reporter: Brandon Bloom Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: patch, patch,

Attachments: Text File emit-ds-via-macros.patch    
Patch: Code

 Description   

The attached patch eliminates the :meta, :set, :vector, and :map ops.

These four operations can be defined more simply in terms of
calls to with-meta, set, vector, and hash-map respectively.

The compiler was optimizing construction of vectors and maps. Now,
those optimizations are implemented as macros. Additionally, sets
are optimized in much the same way.

3 files changed, 52 insertions, 99 deletions

Also worth mentioning: as macros instead of ops & emit methods, these optimizations can apply to any backend. The macros create ClojureScript forms, rather than manually generating JavaScript.



 Comments   
Comment by Brandon Bloom [ 17/Jun/12 4:40 PM ]

I'd also like to extend this for Symbols and Keywords.

I've been experimenting with fleshed out Symbol and Keyword objects with interning. I've found that I need emitters, macros, and functions. With the approach here, I could eliminate the emitters and instead have the analyzer produce invocation forms.

Comment by Raphaël AMIARD [ 18/Jun/12 1:20 PM ]

I think this is an interesting patch. It would be worth adapting it to the decoupled emitters. It raises the question of how it would be possible to share part of the emitters between backends.

Comment by David Nolen [ 18/Jun/12 3:25 PM ]

I don't see many benefits falling out of this patch. How to best emit language primitives like literals and constants may vary from host to host - perhaps emitting bytecode directly will work best for some implementations.

Comment by Brandon Bloom [ 18/Jun/12 5:18 PM ]

Couldn't macros emit bytecode via a mechanism similar to the js* form?

My goals with this are:

1) Move some optimizations from the emit phase further down the pipeline. For example, consider choosing the best associative data structure to create. Why should {:foo "bar"} be optimized to an ObjMap or ArrayMap but (hash-map :foo "bar") not be? Why should that optimization be implemented in such a way that it can not be reused by alternative backends?

2) Operate at a higher level. Prefer working with Clojure forms over target-language code fragments (either strings or byte codes). This is where the code length savings is coming from.

If we continue with this approach, I see 4 or 5 more places where analyzer & emitter code can be replaced with shorter, simpler macros, which are more readily reused by alternate backends.

The one implication (downside?) this approach has on consumers of the analyzer or API is that they may need to do a little extra work when considering :invoke operations for static analysis and the like. However, that seems likely for most analyzers anyway, so this would be a matter of (defmethod handle-special-form :map) vs (defmethod handle-invoke :hash-map)

Comment by Michał Marczyk [ 18/Jun/12 5:53 PM ]

Re: 1, I don't think we should be "optimizing" hash-map or array-map (or similar) calls. These functions are a documented way of requesting a map of a particular type (see the docstrings) which I think should not be removed. If anything, we might want to introduce an obj-map function to create arbitrarily large ObjMaps on request (in fact I'll look into that, but that is a separate discussion).

Additionally, the fact that {} is optimized to be a ObjMap in CLJS goes to show that any map-emitting macro will need to be rewritten for each target platform (ObjMap only makes sense when targeting JS, so this optimization simply won't be applicable to other backends). If so and assuming hash-map & Co. retain the behaviour advertised in their docstrings, there's not much gain to implementing this in a macro over just writings a bunch of emitters.

As for decoupling emitters – I think it's perfectly fine for them not to be decoupled, they are the layer closest to the platform after all. Certainly if there's some code which turns out to look the same across multiple platforms it might be worth it to move it upwards in the stack (not necessarily, though – moving it sideways, to a utility namespace / library, might turn out to be more appropriate), but I have a feeling this is an issue best decided once there actually are multiple backends in place and the various costs and benefits can be judged properly.

Now, the story might well be different if we were to introduce some generic factory functions – "create a map of some type", "create a set of some type" etc. – if (and only if!) they would be meant for public consumption. Then implementing a bunch of compiler macros around those new factories and letting them handle data structure literals would save some duplicate work. I don't want to pronounce an opinion on the usefulness of such generic factory functions at this time – just pointing out the possibility.

Comment by Brandon Bloom [ 23/Jun/12 5:14 PM ]

> These functions are a documented way of requesting a map of a particular type

D'oh! You're right.

> we might want to introduce an obj-map

I see you did just that with CLJS-322 – nice.

> the story might well be different if we were to introduce some generic factory functions

There are already some generic factory functions. 'set, for example, is documented as "Returns a set of the distinct elements of coll." despite always returning a PersistentHashSet. Similar for vector and some others. It seems like map is the only core data structure that realistically has several reasonable choices for a default representation.

> implementing a bunch of compiler macros around those new factories and letting them handle data structure literals would save some duplicate work

So all this was somewhat inspired by tagged_literals.clj – You'll see that those functions are effectively macros which take a form and, generally, return an invocation form.

In my mind, I see Clojure's sugar syntax as a strict expansion transformation.

For example, ^:m {:x [@y 'z/w true]} is simply a shortcut for:

(with-meta (make-map (keyword "x") (vector (deref y) (symbol "z" "w") Boolean/TRUE)) (make-map (keyword "m") Boolean/TRUE))

This sort of thing already happens for @ derefs, # lambdas, etc.

In theory, this could be implemented at a level lower than the compiler. You could, for instance, define a reader "desugar" mode which only returns lists and primitives instead of vectors, maps, etc. This would greatly reduce the number of special forms in the compiler, since all of these boil down to invocations with macros.

Emit methods could be replaced with macros for at least these things: vars, maps, vectors, sets, nil, bools, regexes, keywords, symbols, metadata, and empty lists.

The result would be a significant reduction in the amount of code in the compiler for a proportionally smaller increase in the amount of code in per-language macros and maybe the reader.

> I have a feeling this is an issue best decided once there actually are multiple backends in place

I'll grant you that.

I've said my piece on the topic and don't feel very strongly about this particular patch. I just wanted to spark the discussion about reusing more bits of the compiler between backends. In my mind, it's almost always preferable to transform lists than it is to emit strings. I tried that, and the result was a reduction in responsibilities for the analyzer and macros that were easier to work with than emit methods.

Comment by Michał Marczyk [ 24/Jun/12 7:41 PM ]

Some further discussion here:

http://clojure-log.n01se.net/date/2012-06-24.html#20:30a

Comment by Brandon Bloom [ 16/Aug/12 9:34 PM ]

One other advantage of function application over special casing maps/sets/etc is that argument evaluation order is well defined for function application (left-to-right). The Clojure reader returns un-ordered maps & sets, so without changing the reader, we have no way of being able to know what order map key-value-pairs or set elements were originally in. I filed a bug on that. I think we need to make the reader extensible to say to create the return values from their children expressions. In the case of the ClojureScript compiler, we do care about order, so we'd want to return either a (make-map ...) form directly, or a sorted-map by read-order. Same goes for sets.

Comment by David Nolen [ 31/Aug/12 9:24 AM ]

There's not enough rationale for this one.





[CLJS-301] Inline instance? Created: 05/Jun/12  Updated: 22/Dec/12

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

Type: Enhancement Priority: Trivial
Reporter: Brandon Bloom Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: patch, patch,

Attachments: Text File CLJS-301-v002.patch     Text File inline-instanceof.patch    
Patch: Code

 Description   

See discussion on http://dev.clojure.org/jira/browse/CLJS-300

This is a low priority patch for inlining instanceof checks. I don't know if it has any significant performance improvement, but the patch was sort of a side effect of my work on CLJS-300, so I figured I'd bundle it up and share it here in case someone wants to test it's perf impact and apply if it is a win.



 Comments   
Comment by David Nolen [ 22/Dec/12 3:29 PM ]

This will probably result in a minor performance boost, but it is nice to get another jsSTAR out of core.cljs. If you update the patch to work on master, I will apply it.





[CLJS-471] Empty regexp causes Closure Compiler error Created: 13/Feb/13  Updated: 25/Apr/13

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

Type: Defect Priority: Trivial
Reporter: Bodil Stokke Assignee: Michał Marczyk
Resolution: Unresolved Votes: 0
Labels: None

Attachments: Text File 0001-CLJS-471-prevent-empty-regexps-from-causing-compiler.patch    

 Description   

An empty regexp of the form #"" compiles to //, which is not an empty regexp but a comment, causing the code following the supposed regexp on the affected line to be commented out. This tends to cause compiler errors when Closure Compiler tries to parse it.

#"" should instead produce either /(?:)/ or new RegExp("").



 Comments   
Comment by Michał Marczyk [ 06/Apr/13 6:50 PM ]

Commit message:

CLJS-471: prevent empty regexps from causing compiler errors

This patch chooses to emit

  (new RegExp(""))

rather than

  /(?:)/

so that (pr-str #"") returns

  "#\"\""

rather than

  "#\"(?:)\""

A test for the above is included.
Comment by David Nolen [ 24/Apr/13 9:52 PM ]

I tried applying this in master, the included test fails.

Comment by Michał Marczyk [ 25/Apr/13 5:57 AM ]

Thanks for letting me know. I've checked the value of new RegExp("").source in a Node.js REPL (0.10.3) and it turns out to be '(?'. So, how important is it that we return "#\"\"" rather than "#\"(?\"" anyway? I'm thinking maybe not that much, seeing how regexp support in JS is different to that on the JVM in more fundamental ways. I'll just assume this is correct and attach a new patch accepting both representations soon. Of course if there's a better way to do it, I'll be happy to implement it.





Generated at Sun May 19 10:48:38 CDT 2013 using JIRA 4.4#649-r158309.