summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/clj/clojure/core.clj140
-rw-r--r--src/clj/clojure/genclass.clj6
-rw-r--r--src/clj/clojure/gvec.clj6
-rw-r--r--src/jvm/clojure/lang/Compiler.java483
-rw-r--r--src/jvm/clojure/lang/LispReader.java2
-rw-r--r--src/jvm/clojure/lang/Numbers.java1258
-rw-r--r--src/jvm/clojure/lang/Reflector.java21
-rw-r--r--test/clojure/test_clojure/java_interop.clj2
-rw-r--r--test/clojure/test_clojure/numbers.clj57
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);
+ re