diff options
-rw-r--r-- | src/clj/clojure/core.clj | 140 | ||||
-rw-r--r-- | src/clj/clojure/genclass.clj | 6 | ||||
-rw-r--r-- | src/clj/clojure/gvec.clj | 6 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 483 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LispReader.java | 2 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Numbers.java | 1258 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Reflector.java | 21 | ||||
-rw-r--r-- | test/clojure/test_clojure/java_interop.clj | 2 | ||||
-rw-r--r-- | test/clojure/test_clojure/numbers.clj | 57 |
9 files changed, 1075 insertions, 900 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 3ec651f0..157b25d7 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -970,61 +970,117 @@ :added "1.0"} [x] (. clojure.lang.Numbers (dec x))) -(defn unchecked-inc - "Returns a number one greater than x, an int or long. +(defn unchecked-inc-int + "Returns a number one greater than x, an int. Note - uses a primitive operator subject to overflow." - {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_inc ~x))) + {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_int_inc ~x))) :added "1.0"} - [x] (. clojure.lang.Numbers (unchecked_inc x))) + [x] (. clojure.lang.Numbers (unchecked_int_inc x))) -(defn unchecked-dec - "Returns a number one less than x, an int or long. +(defn unchecked-inc-long + "Returns a number one greater than x, a long. Note - uses a primitive operator subject to overflow." - {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_dec ~x))) + {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_long_inc ~x))) :added "1.0"} - [x] (. clojure.lang.Numbers (unchecked_dec x))) + [x] (. clojure.lang.Numbers (unchecked_long_inc x))) -(defn unchecked-negate - "Returns the negation of x, an int or long. +(defn unchecked-dec-int + "Returns a number one less than x, an int. Note - uses a primitive operator subject to overflow." - {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_negate ~x))) + {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_int_dec ~x))) :added "1.0"} - [x] (. clojure.lang.Numbers (unchecked_negate x))) + [x] (. clojure.lang.Numbers (unchecked_int_dec x))) -(defn unchecked-add - "Returns the sum of x and y, both int or long. +(defn unchecked-dec-long + "Returns a number one less than x, a long. Note - uses a primitive operator subject to overflow." - {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_add ~x ~y))) + {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_long_dec ~x))) :added "1.0"} - [x y] (. clojure.lang.Numbers (unchecked_add x y))) + [x] (. clojure.lang.Numbers (unchecked_long_dec x))) -(defn unchecked-subtract - "Returns the difference of x and y, both int or long. +(defn unchecked-negate-int + "Returns the negation of x, an int. Note - uses a primitive operator subject to overflow." - {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_subtract ~x ~y))) + {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_int_negate ~x))) :added "1.0"} - [x y] (. clojure.lang.Numbers (unchecked_subtract x y))) + [x] (. clojure.lang.Numbers (unchecked_int_negate x))) -(defn unchecked-multiply - "Returns the product of x and y, both int or long. +(defn unchecked-negate-long + "Returns the negation of x, a long. Note - uses a primitive operator subject to overflow." - {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_multiply ~x ~y))) + {:inline (fn [x] `(. clojure.lang.Numbers (unchecked_long_negate ~x))) :added "1.0"} - [x y] (. clojure.lang.Numbers (unchecked_multiply x y))) + [x] (. clojure.lang.Numbers (unchecked_long_negate x))) -(defn unchecked-divide - "Returns the division of x by y, both int or long. +(defn unchecked-add-int + "Returns the sum of x and y, both int. + Note - uses a primitive operator subject to overflow." + {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_add ~x ~y))) + :added "1.0"} + [x y] (. clojure.lang.Numbers (unchecked_int_add x y))) + +(defn unchecked-add-long + "Returns the sum of x and y, both long. + Note - uses a primitive operator subject to overflow." + {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_long_add ~x ~y))) + :added "1.0"} + [x y] (. clojure.lang.Numbers (unchecked_long_add x y))) + +(defn unchecked-subtract-int + "Returns the difference of x and y, both int. + Note - uses a primitive operator subject to overflow." + {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_subtract ~x ~y))) + :added "1.0"} + [x y] (. clojure.lang.Numbers (unchecked_int_subtract x y))) + +(defn unchecked-subtract-long + "Returns the difference of x and y, both long. + Note - uses a primitive operator subject to overflow." + {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_long_subtract ~x ~y))) + :added "1.0"} + [x y] (. clojure.lang.Numbers (unchecked_long_subtract x y))) + +(defn unchecked-multiply-int + "Returns the product of x and y, both int. + Note - uses a primitive operator subject to overflow." + {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_multiply ~x ~y))) + :added "1.0"} + [x y] (. clojure.lang.Numbers (unchecked_int_multiply x y))) + +(defn unchecked-multiply-long + "Returns the product of x and y, both long. + Note - uses a primitive operator subject to overflow." + {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_long_multiply ~x ~y))) + :added "1.0"} + [x y] (. clojure.lang.Numbers (unchecked_long_multiply x y))) + +(defn unchecked-divide-int + "Returns the division of x by y, both int. + Note - uses a primitive operator subject to truncation." + {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_divide ~x ~y))) + :added "1.0"} + [x y] (. clojure.lang.Numbers (unchecked_int_divide x y))) + +(defn unchecked-divide-long + "Returns the division of x by y, both long. + Note - uses a primitive operator subject to truncation." + {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_long_divide ~x ~y))) + :added "1.0"} + [x y] (. clojure.lang.Numbers (unchecked_long_divide x y))) + +(defn unchecked-remainder-int + "Returns the remainder of division of x by y, both int. Note - uses a primitive operator subject to truncation." - {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_divide ~x ~y))) + {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_int_remainder ~x ~y))) :added "1.0"} - [x y] (. clojure.lang.Numbers (unchecked_divide x y))) + [x y] (. clojure.lang.Numbers (unchecked_int_remainder x y))) -(defn unchecked-remainder - "Returns the remainder of division of x by y, both int or long. +(defn unchecked-remainder-long + "Returns the remainder of division of x by y, both long. Note - uses a primitive operator subject to truncation." - {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_remainder ~x ~y))) + {:inline (fn [x y] `(. clojure.lang.Numbers (unchecked_long_remainder ~x ~y))) :added "1.0"} - [x y] (. clojure.lang.Numbers (unchecked_remainder x y))) + [x y] (. clojure.lang.Numbers (unchecked_long_remainder x y))) (defn pos? "Returns true if num is greater than zero, else false" @@ -2183,11 +2239,11 @@ [bindings & body] (let [i (first bindings) n (second bindings)] - `(let [n# (int ~n)] + `(let [n# ~n] (loop [~i (int 0)] (when (< ~i n#) ~@body - (recur (inc ~i))))))) + (recur (unchecked-inc-long ~i))))))) (defn map "Returns a lazy sequence consisting of the result of applying f to the @@ -2553,17 +2609,17 @@ {:tag 'clojure.lang.IChunk}) count- (gensym "count_") i- (gensym "i_") - recform `(recur (next ~seq-) nil (int 0) (int 0)) + recform `(recur (next ~seq-) nil 0 0) steppair (step recform (nnext exprs)) needrec (steppair 0) subform (steppair 1) recform-chunk - `(recur ~seq- ~chunk- ~count- (unchecked-inc ~i-)) + `(recur ~seq- ~chunk- ~count- (unchecked-inc-long ~i-)) steppair-chunk (step recform-chunk (nnext exprs)) subform-chunk (steppair-chunk 1)] [true `(loop [~seq- (seq ~v), ~chunk- nil, - ~count- (int 0), ~i- (int 0)] + ~count- 0, ~i- 0] (if (< ~i- ~count-) (let [~k (.nth ~chunk- ~i-)] ~subform-chunk @@ -2660,11 +2716,11 @@ (= 2 (count bindings)) "exactly 2 forms in binding vector") (let [i (first bindings) n (second bindings)] - `(let [n# (int ~n)] - (loop [~i (int 0)] + `(let [n# ~n] + (loop [~i 0] (when (< ~i n#) ~@body - (recur (unchecked-inc ~i))))))) + (recur (unchecked-inc-long ~i))))))) #_(defn into "Returns a new coll consisting of to-coll with all of the items of @@ -3849,12 +3905,12 @@ (= k :when) `(if ~v ~(do-cmod etc) (recur - (unchecked-inc ~gi))) + (unchecked-inc-long ~gi))) (keyword? k) (err "Invalid 'for' keyword " k) :else `(do (chunk-append ~gb ~body-expr) - (recur (unchecked-inc ~gi)))))] + (recur (unchecked-inc-long ~gi)))))] `(fn ~giter [~gxs] (lazy-seq (loop [~gxs ~gxs] diff --git a/src/clj/clojure/genclass.clj b/src/clj/clojure/genclass.clj index bacc9277..a1e0fcdb 100644 --- a/src/clj/clojure/genclass.clj +++ b/src/clj/clojure/genclass.clj @@ -299,7 +299,7 @@ (arg-types (count ptypes))))) ;expecting [[super-ctor-args] state] returned (. gen dup) - (. gen push 0) + (. gen push (int 0)) (. gen (invokeStatic rt-type nth-method)) (. gen storeLocal local) @@ -307,14 +307,14 @@ (. gen dupX1) (dotimes [i (count super-pclasses)] (. gen loadLocal local) - (. gen push i) + (. gen push (int i)) (. gen (invokeStatic rt-type nth-method)) (. clojure.lang.Compiler$HostExpr (emitUnboxArg nil gen (nth super-pclasses i)))) (. gen (invokeConstructor super-type super-m)) (if state (do - (. gen push 1) + (. gen push (int 1)) (. gen (invokeStatic rt-type nth-method)) (. gen (putField ctype state-name obj-type))) (. gen pop)) diff --git a/src/clj/clojure/gvec.clj b/src/clj/clojure/gvec.clj index feff544a..bfebb2ea 100644 --- a/src/clj/clojure/gvec.clj +++ b/src/clj/clojure/gvec.clj @@ -62,11 +62,11 @@ (if (< aidx (count vec)) (let [node (.arrayFor vec aidx) result (loop [result result - node-idx (bit-and (int 0x1f) aidx)] + node-idx (bit-and 0x1f aidx)] (if (< node-idx (.alength am node)) (recur (f result (.aget am node node-idx)) (inc node-idx)) result))] - (recur result (bit-and (int 0xffe0) (+ aidx (int 32))))) + (recur result (bit-and 0xffe0 (+ aidx 32)))) result))) clojure.lang.ISeq @@ -141,7 +141,7 @@ (if (= i cnt) hash (let [val (.nth this i)] - (recur (unchecked-add (unchecked-multiply (int 31) hash) + (recur (unchecked-add-int (unchecked-multiply-int 31 hash) (clojure.lang.Util/hash val)) (inc i)))))) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 29e8fbbd..9f8c7b5f 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -139,6 +139,7 @@ private static final Type SYMBOL_TYPE = Type.getType(Symbol.class); private static final Type IFN_TYPE = Type.getType(IFn.class); private static final Type AFUNCTION_TYPE = Type.getType(AFunction.class); private static final Type RT_TYPE = Type.getType(RT.class); +private static final Type NUMBERS_TYPE = Type.getType(Numbers.class); final static Type CLASS_TYPE = Type.getType(Class.class); final static Type NS_TYPE = Type.getType(Namespace.class); final static Type UTIL_TYPE = Type.getType(Util.class); @@ -726,22 +727,20 @@ static public abstract class HostExpr implements Expr, MaybePrimitiveExpr{ else { if(returnType == int.class) - //gen.invokeStatic(NUM_TYPE, fromIntMethod); gen.invokeStatic(INTEGER_TYPE, intValueOfMethod); else if(returnType == float.class) { - //gen.visitInsn(F2D); - gen.invokeStatic(FLOAT_TYPE, floatValueOfMethod); - //m = floatValueOfMethod; + gen.visitInsn(F2D); + gen.invokeStatic(DOUBLE_TYPE, doubleValueOfMethod); } else if(returnType == double.class) gen.invokeStatic(DOUBLE_TYPE, doubleValueOfMethod); - else if(returnType == long.class) - gen.invokeStatic(LONG_TYPE, longValueOfMethod); - else if(returnType == byte.class) - gen.invokeStatic(BYTE_TYPE, byteValueOfMethod); - else if(returnType == short.class) - gen.invokeStatic(SHORT_TYPE, shortValueOfMethod); + else if(returnType == long.class) + gen.invokeStatic(NUMBERS_TYPE, Method.getMethod("Number num(long)")); + else if(returnType == byte.class) + gen.invokeStatic(BYTE_TYPE, byteValueOfMethod); + else if(returnType == short.class) + gen.invokeStatic(SHORT_TYPE, shortValueOfMethod); } } } @@ -1163,9 +1162,35 @@ static abstract class MethodExpr extends HostExpr{ Expr e = (Expr) args.nth(i); try { - if(maybePrimitiveType(e) == parameterTypes[i]) + final Class primc = maybePrimitiveType(e); + if(primc == parameterTypes[i]) { - ((MaybePrimitiveExpr) e).emitUnboxed(C.EXPRESSION, objx, gen); + final MaybePrimitiveExpr pe = (MaybePrimitiveExpr) e; + pe.emitUnboxed(C.EXPRESSION, objx, gen); + } + else if(primc == int.class && parameterTypes[i] == long.class) + { + final MaybePrimitiveExpr pe = (MaybePrimitiveExpr) e; + pe.emitUnboxed(C.EXPRESSION, objx, gen); + gen.visitInsn(I2L); + } + else if(primc == long.class && parameterTypes[i] == int.class) + { + final MaybePrimitiveExpr pe = (MaybePrimitiveExpr) e; + pe.emitUnboxed(C.EXPRESSION, objx, gen); + gen.invokeStatic(RT_TYPE, Method.getMethod("int intCast(long)")); + } + else if(primc == float.class && parameterTypes[i] == double.class) + { + final MaybePrimitiveExpr pe = (MaybePrimitiveExpr) e; + pe.emitUnboxed(C.EXPRESSION, objx, gen); + gen.visitInsn(F2D); + } + else if(primc == double.class && parameterTypes[i] == float.class) + { + final MaybePrimitiveExpr pe = (MaybePrimitiveExpr) e; + pe.emitUnboxed(C.EXPRESSION, objx, gen); + gen.visitInsn(D2F); } else { @@ -1508,6 +1533,66 @@ static class UnresolvedVarExpr implements Expr{ } } +static class NumberExpr extends LiteralExpr implements MaybePrimitiveExpr{ + final Number n; + public final int id; + + public NumberExpr(Number n){ + this.n = n; + this.id = registerConstant(n); + } + + Object val(){ + return n; + } + + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ + if(context != C.STATEMENT) + { + objx.emitConstant(gen, id); +// emitUnboxed(context,objx,gen); +// HostExpr.emitBoxReturn(objx,gen,getJavaClass()); + } + } + + public boolean hasJavaClass() throws Exception{ + return true; + } + + public Class getJavaClass(){ + if(n instanceof Integer) + return long.class; + else if(n instanceof Double) + return double.class; + else if(n instanceof Long) + return long.class; + else + throw new IllegalStateException("Unsupported Number type: " + n.getClass().getName()); + } + + public boolean canEmitPrimitive(){ + return true; + } + + public void emitUnboxed(C context, ObjExpr objx, GeneratorAdapter gen){ + if(n instanceof Integer) + gen.push(n.longValue()); + else if(n instanceof Double) + gen.push(n.doubleValue()); + else if(n instanceof Long) + gen.push(n.longValue()); + } + + static public Expr parse(Number form){ + if(form instanceof Integer + || form instanceof Double + || form instanceof Long) + return new NumberExpr(form); + else + return new ConstantExpr(form); + } +} + static class ConstantExpr extends LiteralExpr{ //stuff quoted vals in classloader at compile time, pull out at runtime //this won't work for static compilation... @@ -3938,119 +4023,124 @@ static public class ObjExpr implements Expr{ gen.push(((Integer) value).intValue()); gen.invokeStatic(Type.getType(Integer.class), Method.getMethod("Integer valueOf(int)")); } + else if(value instanceof Long) + { + gen.push(((Long) value).longValue()); + gen.invokeStatic(Type.getType(Long.class), Method.getMethod("Long valueOf(long)")); + } else if(value instanceof Double) { gen.push(((Double) value).doubleValue()); gen.invokeStatic(Type.getType(Double.class), Method.getMethod("Double valueOf(double)")); } - else if(value instanceof Character) - { - gen.push(((Character) value).charValue()); - gen.invokeStatic(Type.getType(Character.class), Method.getMethod("Character valueOf(char)")); - } - else if(value instanceof Class) - { - Class cc = (Class)value; - if(cc.isPrimitive()) - { - Type bt; - if ( cc == boolean.class ) bt = Type.getType(Boolean.class); - else if ( cc == byte.class ) bt = Type.getType(Byte.class); - else if ( cc == char.class ) bt = Type.getType(Character.class); - else if ( cc == double.class ) bt = Type.getType(Double.class); - else if ( cc == float.class ) bt = Type.getType(Float.class); - else if ( cc == int.class ) bt = Type.getType(Integer.class); - else if ( cc == long.class ) bt = Type.getType(Long.class); - else if ( cc == short.class ) bt = Type.getType(Short.class); - else throw new RuntimeException( - "Can't embed unknown primitive in code: " + value); - gen.getStatic( bt, "TYPE", Type.getType(Class.class) ); - } - else - { - gen.push(destubClassName(cc.getName())); - gen.invokeStatic(Type.getType(Class.class), Method.getMethod("Class forName(String)")); - } - } - else if(value instanceof Symbol) - { - gen.push(((Symbol) value).ns); - gen.push(((Symbol) value).name); - gen.invokeStatic(Type.getType(Symbol.class), - Method.getMethod("clojure.lang.Symbol create(String,String)")); - } - else if(value instanceof Keyword) - { - emitValue(((Keyword) value).sym, gen); - gen.invokeStatic(Type.getType(Keyword.class), - Method.getMethod("clojure.lang.Keyword intern(clojure.lang.Symbol)")); - } + else if(value instanceof Character) + { + gen.push(((Character) value).charValue()); + gen.invokeStatic(Type.getType(Character.class), Method.getMethod("Character valueOf(char)")); + } + else if(value instanceof Class) + { + Class cc = (Class)value; + if(cc.isPrimitive()) + { + Type bt; + if ( cc == boolean.class ) bt = Type.getType(Boolean.class); + else if ( cc == byte.class ) bt = Type.getType(Byte.class); + else if ( cc == char.class ) bt = Type.getType(Character.class); + else if ( cc == double.class ) bt = Type.getType(Double.class); + else if ( cc == float.class ) bt = Type.getType(Float.class); + else if ( cc == int.class ) bt = Type.getType(Integer.class); + else if ( cc == long.class ) bt = Type.getType(Long.class); + else if ( cc == short.class ) bt = Type.getType(Short.class); + else throw new RuntimeException( + "Can't embed unknown primitive in code: " + value); + gen.getStatic( bt, "TYPE", Type.getType(Class.class) ); + } + else + { + gen.push(destubClassName(cc.getName())); + gen.invokeStatic(Type.getType(Class.class), Method.getMethod("Class forName(String)")); + } + } + else if(value instanceof Symbol) + { + gen.push(((Symbol) value).ns); + gen.push(((Symbol) value).name); + gen.invokeStatic(Type.getType(Symbol.class), + Method.getMethod("clojure.lang.Symbol create(String,String)")); + } + else if(value instanceof Keyword) + { + emitValue(((Keyword) value).sym, gen); + gen.invokeStatic(Type.getType(Keyword.class), + Method.getMethod("clojure.lang.Keyword intern(clojure.lang.Symbol)")); + } // else if(value instanceof KeywordCallSite) // { // emitValue(((KeywordCallSite) value).k.sym, gen); // gen.invokeStatic(Type.getType(KeywordCallSite.class), // Method.getMethod("clojure.lang.KeywordCallSite create(clojure.lang.Symbol)")); // } - else if(value instanceof Var) - { - Var var = (Var) value; - gen.push(var.ns.name.toString()); - gen.push(var.sym.toString()); - gen.invokeStatic(RT_TYPE, Method.getMethod("clojure.lang.Var var(String,String)")); - } - else if(value instanceof IPersistentMap) - { - List entries = new ArrayList(); - for(Map.Entry entry : (Set<Map.Entry>) ((Map) value).entrySet()) - { - entries.add(entry.getKey()); - entries.add(entry.getValue()); - } - emitListAsObjectArray(entries, gen); - gen.invokeStatic(RT_TYPE, - Method.getMethod("clojure.lang.IPersistentMap map(Object[])")); - } - else if(value instanceof IPersistentVector) - { - emitListAsObjectArray(value, gen); - gen.invokeStatic(RT_TYPE, Method.getMethod( - "clojure.lang.IPersistentVector vector(Object[])")); - } - else if(value instanceof ISeq || value instanceof IPersistentList) - { - emitListAsObjectArray(value, gen); - gen.invokeStatic(Type.getType(java.util.Arrays.class), - Method.getMethod("java.util.List asList(Object[])")); - gen.invokeStatic(Type.getType(PersistentList.class), - Method.getMethod( - "clojure.lang.IPersistentList create(java.util.List)")); - } - else - { - String cs = null; - try - { - cs = RT.printString(value); - //System.out.println("WARNING SLOW CODE: " + value.getClass() + " -> " + cs); - } - catch(Exception e) - { - throw new RuntimeException( - "Can't embed object in code, maybe print-dup not defined: " + - value); - } - if(cs.length() == 0) - throw new RuntimeException( - "Can't embed unreadable object in code: " + value); - - if(cs.startsWith("#<")) - throw new RuntimeException( - "Can't embed unreadable object in code: " + cs); - - gen.push(cs); - gen.invokeStatic(RT_TYPE, readStringMethod); - partial = false; - } + else if(value instanceof Var) + { + Var var = (Var) value; + gen.push(var.ns.name.toString()); + gen.push(var.sym.toString()); + gen.invokeStatic(RT_TYPE, Method.getMethod("clojure.lang.Var var(String,String)")); + } + else if(value instanceof IPersistentMap) + { + List entries = new ArrayList(); + for(Map.Entry entry : (Set<Map.Entry>) ((Map) value).entrySet()) + { + entries.add(entry.getKey()); + entries.add(entry.getValue()); + } + emitListAsObjectArray(entries, gen); + gen.invokeStatic(RT_TYPE, + Method.getMethod("clojure.lang.IPersistentMap map(Object[])")); + } + else if(value instanceof IPersistentVector) + { + emitListAsObjectArray(value, gen); + gen.invokeStatic(RT_TYPE, Method.getMethod( + "clojure.lang.IPersistentVector vector(Object[])")); + } + else if(value instanceof ISeq || value instanceof IPersistentList) + { + emitListAsObjectArray(value, gen); + gen.invokeStatic(Type.getType(java.util.Arrays.class), + Method.getMethod("java.util.List asList(Object[])")); + gen.invokeStatic(Type.getType(PersistentList.class), + Method.getMethod( + "clojure.lang.IPersistentList create(java.util.List)")); + } + else + { + String cs = null; + try + { + cs = RT.printString(value); + //System.out.println("WARNING SLOW CODE: " + value.getClass() + " -> " + cs); + } + catch(Exception e) + { + throw new RuntimeException( + "Can't embed object in code, maybe print-dup not defined: " + + value); + } + if(cs.length() == 0) + throw new RuntimeException( + "Can't embed unreadable object in code: " + value); + + if(cs.startsWith("#<")) + throw new RuntimeException( + "Can't embed unreadable object in code: " + cs); + + gen.push(cs); + gen.invokeStatic(RT_TYPE, readStringMethod); + partial = false; + } if(partial) { @@ -4558,26 +4648,8 @@ public static class FnMethod extends ObjMethod{ try { Var.pushThreadBindings(RT.map(LOOP_LABEL, loopLabel, METHOD, this)); - MaybePrimitiveExpr be = (MaybePrimitiveExpr) body; - if(Util.isPrimitive(retClass) && be.canEmitPrimitive()) - { - if(be.getJavaClass() == retClass) - be.emitUnboxed(C.RETURN,fn,gen); - //todo - support the standard widening conversions - else - throw new IllegalArgumentException("Mismatched primitive return, expected: " - + retClass + ", had: " + be.getJavaClass()); - } - else - { - body.emit(C.RETURN, fn, gen); - if(retClass == void.class) - { - gen.pop(); - } - else - gen.unbox(getReturnType()); - } + emitBody(objx, gen, retClass, body); + Label end = gen.mark(); for(ISeq lbs = argLocals.seq(); lbs != null; lbs = lbs.next()) { @@ -4739,6 +4811,7 @@ abstract public static class ObjMethod{ PersistentHashSet localsUsedInCatchFinally = PersistentHashSet.EMPTY; protected IPersistentMap methodMeta; + public final IPersistentMap locals(){ return locals; } @@ -4768,6 +4841,48 @@ abstract public static class ObjMethod{ this.objx = objx; } + static void emitBody(ObjExpr objx, GeneratorAdapter gen, Class retClass, Expr body) throws Exception{ + MaybePrimitiveExpr be = (MaybePrimitiveExpr) body; + if(Util.isPrimitive(retClass) && be.canEmitPrimitive()) + { + Class bc = maybePrimitiveType(be); + if(bc == retClass) + be.emitUnboxed(C.RETURN, objx, gen); + else if(retClass == long.class && bc == int.class) + { + be.emitUnboxed(C.RETURN, objx, gen); + gen.visitInsn(I2L); + } + else if(retClass == double.class && bc == float.class) + { + be.emitUnboxed(C.RETURN, objx, gen); + gen.visitInsn(F2D); + } + else if(retClass == int.class && bc == long.class) + { + be.emitUnboxed(C.RETURN, objx, gen); + gen.invokeStatic(RT_TYPE, Method.getMethod("int intCast(long)")); + } + else if(retClass == float.class && bc == double.class) + { + be.emitUnboxed(C.RETURN, objx, gen); + gen.visitInsn(D2F); + } + else + throw new IllegalArgumentException("Mismatched primitive return, expected: " + + retClass + ", had: " + be.getJavaClass()); + } + else + { + body.emit(C.RETURN, objx, gen); + if(retClass == void.class) + { + gen.pop(); + } + else + gen.unbox(Type.getType(retClass)); + } + } abstract int numParams(); abstract String getMethodName(); abstract Type getReturnType(); @@ -5245,6 +5360,13 @@ public static class LetExpr implements Expr, MaybePrimitiveExpr{ if(sym.getNamespace() != null) throw new Exception("Can't let qualified name: " + sym); Expr init = analyze(C.EXPRESSION, bindings.nth(i + 1), sym.name); + if(isLoop) + { + if(maybePrimitiveType(init) == int.class) + init = new StaticMethodExpr("", 0, null, RT.class, "longCast", RT.vector(init)); + else if(maybePrimitiveType(init) == float.class) + init = new StaticMethodExpr("", 0, null, RT.class, "doubleCast", RT.vector(init)); + } //sequential enhancement of env (like Lisp let*) LocalBinding lb = registerLocal(sym, tagOf(sym), init,false); BindingInit bi = new BindingInit(lb, init); @@ -5389,18 +5511,47 @@ public static class RecurExpr implements Expr{ Class primc = lb.getPrimitiveType(); try { - if(!(arg instanceof MaybePrimitiveExpr && arg.hasJavaClass() && arg.getJavaClass() == primc)) - throw new IllegalArgumentException("recur arg for primitive local: " + + final Class pc = maybePrimitiveType(arg); + if(pc == primc) + ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen); + else if(primc == long.class && pc == int.class) + { + ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen); + gen.visitInsn(I2L); + } + else if(primc == double.class && pc == float.class) + { + ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen); + gen.visitInsn(F2D); + } + else if(primc == int.class && pc == long.class) + { + ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen); + gen.invokeStatic(RT_TYPE, Method.getMethod("int intCast(long)")); + } + else if(primc == float.class && pc == double.class) + { + ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen); + gen.visitInsn(D2F); + } + else + { + if(RT.booleanCast(RT.WARN_ON_REFLECTION.deref())) + //throw new IllegalArgumentException + RT.errPrintWriter().println + ("recur arg for primitive local: " + lb.name + " must be matching primitive, had: " + (arg.hasJavaClass() ? arg.getJavaClass().getName():"Object") + ", needed: " + primc.getName()); + arg.emit(C.EXPRESSION, objx, gen); + HostExpr.emitUnboxArg(objx,gen,primc); + } } catch(Exception e) { throw new RuntimeException(e); } - ((MaybePrimitiveExpr) arg).emitUnboxed(C.EXPRESSION, objx, gen); } else { @@ -5501,28 +5652,28 @@ private static Expr analyze(C context, Object form, String name) throws Exceptio return analyzeSymbol((Symbol) form); else if(fclass == Keyword.class) return registerKeyword((Keyword) form); -// else if(form instanceof Num) -// return new NumExpr((Num) form); + else if(form instanceof Number) + return NumberExpr.parse((Number) form); else if(fclass == String.class) return new StringExpr(((String) form).intern()); // else if(fclass == Character.class) // return new CharExpr((Character) form); - else if(form instanceof IPersistentCollection && ((IPersistentCollection) form).count() == 0) - { - Expr ret = new EmptyExpr(form); - if(RT.meta(form) != null) - ret = new MetaExpr(ret, MapExpr - .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta())); - return ret; - } - else if(form instanceof ISeq) - return analyzeSeq(context, (ISeq) form, name); - else if(form instanceof IPersistentVector) - return VectorExpr.parse(context, (IPersistentVector) form); - else if(form instanceof IPersistentMap) - return MapExpr.parse(context, (IPersistentMap) form); - else if(form instanceof IPersistentSet) - return SetExpr.parse(context, (IPersistentSet) form); + else if(form instanceof IPersistentCollection && ((IPersistentCollection) form).count() == 0) + { + Expr ret = new EmptyExpr(form); + if(RT.meta(form) != null) + ret = new MetaExpr(ret, MapExpr + .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta())); + return ret; + } + else if(form instanceof ISeq) + return analyzeSeq(context, (ISeq) form, name); + else if(form instanceof IPersistentVector) + return VectorExpr.parse(context, (IPersistentVector) form); + else if(form instanceof IPersistentMap) + return MapExpr.parse(context, (IPersistentMap) form); + else if(form instanceof IPersistentSet) + return SetExpr.parse(context, (IPersistentSet) form); // else //throw new UnsupportedOperationException(); @@ -7004,27 +7155,7 @@ public static class NewInstanceMethod extends ObjMethod{ try { Var.pushThreadBindings(RT.map(LOOP_LABEL, loopLabel, METHOD, this)); - MaybePrimitiveExpr be = (MaybePrimitiveExpr) body; - if(Util.isPrimitive(retClass) && be.canEmitPrimitive()) - { - if(be.getJavaClass() == retClass) - be.emitUnboxed(C.RETURN,obj,gen); - //todo - support the standard widening conversions - else - throw new IllegalArgumentException("Mismatched primitive return, expected: " - + retClass + ", had: " + be.getJavaClass()); - } - else - { - body.emit(C.RETURN, obj, gen); - if(retClass == void.class) - { - gen.pop(); - } - else - gen.unbox(retType); - } - + emitBody(objx, gen, retClass, body); Label end = gen.mark(); gen.visitLocalVariable("this", obj.objtype.getDescriptor(), null, loopLabel, end, 0); for(ISeq lbs = argLocals.seq(); lbs != null; lbs = lbs.next()) diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java index 409ec858..1d95c741 100644 --- a/src/jvm/clojure/lang/LispReader.java +++ b/src/jvm/clojure/lang/LispReader.java @@ -330,7 +330,7 @@ private static Object matchNumber(String s){ { if(m.group(8) != null) return BigInteger.ZERO; - return new Long(0); + return Numbers.num(0); } boolean negate = (m.group(1).equals("-")); String n; |