The bug is not in `case` but is a result of calling `with-symbol-macros` on it.
Normally `case` expands to use a `sorted-map` for the lookup of case values
when you have a compact set of test values (as opposed to a sparse set). You
can see that here:
user=> (macroexpand '(case \a (\0 \1 \2 \3 \4 \5 \6 \7 \8) true false))
(let* [G__873 \a] (case* G__873 0 0 false {48 [\0 true], 49 [\1 true], 50 [\2
true], 51 [\3 true], 52 [\4 true], 53 [\5 true], 54 [\6 true], 55 [\7 true], 56
[\8 true]} :compact :hash-equiv nil))
Here, the keys are in order and so the compiler can create an array to hold the
values based on (56-48)+1 as the length.
Based on my reading of the clojure.tools.macro source, `with-symbol-macros`
forces the expansion and recursively goes into the map and reconstructs it as a
regular (unsorted) map as can be seen here:
user=> (macroexpand '(clojure.tools.macro/with-symbol-macros (case \a (\0 \1 \2
\3 \4 \5 \6 \7 \8) true false)))
(do (let* [G__865 \a] (case* G__865 0 0 false {55 [\7 true], 54 [\6 true], 48
[\0 true], 50 [\2 true], 56 [\8 true], 51 [\3 true], 53 [\5 true], 52 [\4
true], 49 [\1 true]} :compact :hash-equiv nil)))
When confronted with this, the compiler attempts to calculate (49-55)+1 and
gets the exception you saw.
I believe that the fix - to clojure.tools.macro - would be to add special
treatment for the `case*` form:
https://github.com/clojure/tools.macro/blob/master/src/main/clojure/clojure/tools/macro.clj#L167-179
If you want to report that as a bug: http://dev.clojure.org/jira/browse/TMACRO
Although it sounds like you have a reasonable workaround?
Sean
On Jul 4, 2014, at 1:38 PM, François-René Rideau <[email protected]> wrote:
> Using clojure 1.6.0 and clojure.algo.monads, I got a compiler error that I
> could reduce to this case:
>
> (fn [c] (domonad sequence-m [_ (case c (\0 \1 \2 \3 \4 \5 \6 \7 \8) c)] c))
>
> CompilerException java.lang.NegativeArraySizeException,
> compiling:(/tmp/form-init1574284988203454652.clj:1:1)
>
> Macro-expanding it, I could further reduce it to:
>
> (fn [c] (clojure.tools.macro/with-symbol-macros (case c (\0 \1 \2 \3 \4 \5 \6
> \7 \8) c) c))
>
> Note that if I remove one case, the error disappears; 9 cases seems to be the
> magic number. Also, I don't know what clojure.tools.macro/with-symbol-macros
> does, but without it the code compiles fine.
>
> Even if I remove this particular bit from the case statement in my parser and
> replace it by a last-case test, the code compiles but my larger case fails,
> in a way that condp = doesn't.
>
> Can anyone fix the case macro?
signature.asc
Description: Message signed with OpenPGP using GPGMail
