summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/org/clojure/runtime/RT.java1
-rw-r--r--src/org/clojure/runtime/Reflector.java217
2 files changed, 203 insertions, 15 deletions
diff --git a/src/org/clojure/runtime/RT.java b/src/org/clojure/runtime/RT.java
index 619d7586..ef55bb00 100644
--- a/src/org/clojure/runtime/RT.java
+++ b/src/org/clojure/runtime/RT.java
@@ -17,6 +17,7 @@ import java.util.Iterator;
public class RT{
static public Symbol T = Symbol.intern("t");
+ static public final Object[] EMPTY_ARRAY = new Object[]{};
static public Object eq(Object arg1, Object arg2) {
return (arg1 == arg2)?Boolean.TRUE:null;
diff --git a/src/org/clojure/runtime/Reflector.java b/src/org/clojure/runtime/Reflector.java
index 1c9cb90f..06098c10 100644
--- a/src/org/clojure/runtime/Reflector.java
+++ b/src/org/clojure/runtime/Reflector.java
@@ -12,44 +12,231 @@
package org.clojure.runtime;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
public class Reflector{
-public static Object invokeInstanceMember(String name, Object arg1) throws Exception
+public static Object invokeInstanceMethod(String name, Object target, Object[] args) throws Exception
+ {
+ Class c = target.getClass();
+ List methods = getMethods(c, args.length, name);
+ if(methods.isEmpty())
+ {
+ throw new IllegalArgumentException("No matching field or method found");
+ }
+ else if(methods.size() == 1)
+ {
+ Method m = (Method) methods.get(0);
+ return m.invoke(target, boxArgs(m.getParameterTypes(), args));
+ }
+ else //overloaded w/same arity
+ {
+ for(Iterator i = methods.iterator(); i.hasNext();)
+ {
+ Method m = (Method) i.next();
+
+ Class[] params = m.getParameterTypes();
+ if(isCongruent(params, args))
+ {
+ Object[] boxedArgs = boxArgs(params, args);
+ return m.invoke(target, boxedArgs);
+ }
+ }
+ throw new IllegalArgumentException("No matching field or method found");
+
+ }
+ }
+
+public static Object invokeInstanceMember(String name, Object target) throws Exception
{
- return throwNotImplemented();
+ //check for field first
+ Class c = target.getClass();
+ Field f = getField(c, name);
+ if(f != null) //field get
+ {
+ return f.get(target);
+ }
+ return invokeInstanceMethod(name, target, RT.EMPTY_ARRAY);
}
-public static Object invokeInstanceMember(String name, Object arg1, Object arg2) throws Exception
+public static Object invokeInstanceMember(String name, Object target, Object arg1) throws Exception
{
- return throwNotImplemented();
+ //check for field first
+ Class c = target.getClass();
+ Field f = getField(c, name);
+ if(f != null) //field set
+ {
+ f.set(target, boxArg(f.getType(), arg1));
+ return arg1;
+ }
+ return invokeInstanceMethod(name, target, new Object[]{arg1});
}
-public static Object invokeInstanceMember(String name, Object arg1, Object arg2, Object arg3) throws Exception
+public static Object invokeInstanceMember(String name, Object target, Object arg1, Object arg2) throws Exception
{
- return throwNotImplemented();
+ return invokeInstanceMethod(name, target, new Object[]{arg1, arg2});
}
-public static Object invokeInstanceMember(String name, Object arg1, Object arg2, Object arg3, Object arg4)
+public static Object invokeInstanceMember(String name, Object target, Object arg1, Object arg2, Object arg3)
throws Exception
{
- return throwNotImplemented();
+ return invokeInstanceMethod(name, target, new Object[]{arg1, arg2, arg3});
}
-public static Object invokeInstanceMember(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5)
+public static Object invokeInstanceMember(String name, Object target, Object arg1, Object arg2, Object arg3,
+ Object arg4)
throws Exception
{
- return throwNotImplemented();
+ return invokeInstanceMethod(name, target, new Object[]{arg1, arg2, arg3, arg4});
}
-public static Object invokeInstanceMember(String name, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5,
- Cons args)
+public static Object invokeInstanceMember(String name, Object target, Object arg1, Object arg2, Object arg3,
+ Object arg4,
+ Cons arglist)
throws Exception
{
- return throwNotImplemented();
+ Object[] args = new Object[4 + RT.length(arglist)];
+ args[0] = arg1;
+ args[1] = arg2;
+ args[2] = arg3;
+ args[3] = arg4;
+ for(int i = 4; arglist != null; i++, arglist = arglist.rest)
+ args[i] = arglist.first;
+ return invokeInstanceMethod(name, target, args);
+ }
+
+
+static public Field getField(Class c, String name)
+ {
+ Field[] allfields = c.getFields();
+ for(int i = 0; i < allfields.length; i++)
+ {
+ if(name.equals(allfields[i].getName()))
+ return allfields[i];
+ }
+ return null;
+ }
+
+static public List getMethods(Class c, int arity, String name)
+ {
+ Method[] allmethods = c.getMethods();
+ ArrayList methods = new ArrayList();
+ for(int i = 0; i < allmethods.length; i++)
+ {
+ if(name.equals(allmethods[i].getName())
+ && !Modifier.isStatic(allmethods[i].getModifiers())
+ && allmethods[i].getParameterTypes().length == arity)
+ {
+ methods.add(allmethods[i]);
+ }
+ }
+ return methods;
+ }
+
+
+static Object boxArg(Class paramType, Object arg)
+ {
+ Class argType = arg.getClass();
+ if(primBoxTypeMatch(paramType, argType))
+ return arg;
+ if(paramType == boolean.class)
+ {
+ if(arg == null)
+ return Boolean.FALSE;
+ return Boolean.TRUE;
+ }
+ else if(paramType.isPrimitive() && arg instanceof Num)
+ {
+ Num n = (Num) arg;
+ if(paramType == int.class)
+ return RT.box(n.intValue());
+ else if(paramType == float.class)
+ return RT.box(n.floatValue());
+ else if(paramType == double.class)
+ return RT.box(n.doubleValue());
+ else if(paramType == long.class)
+ return RT.box(n.longValue());
+ else if(paramType == char.class)
+ return RT.box((char) n.intValue());
+ else if(paramType == short.class)
+ return RT.box(n.shortValue());
+ else
+ return RT.box(n.byteValue());
+ }
+ else
+ return arg;
+ }
+
+static Object[] boxArgs(Class[] params, Object[] args)
+ {
+ if(params.length == 0)
+ return null;
+ Object[] ret = new Object[params.length];
+ for(int i = 0; i < params.length; i++)
+ {
+ Object arg = args[i];
+ Class paramType = params[i];
+ ret[i] = boxArg(paramType, arg);
+ }
+ return ret;
+ }
+
+static public boolean primBoxTypeMatch(Class primType, Class boxType)
+ {
+ if(primType == int.class)
+ return boxType == Integer.class;
+ else if(primType == float.class)
+ return boxType == Float.class;
+ else if(primType == double.class)
+ return boxType == Double.class;
+ else if(primType == long.class)
+ return boxType == Long.class;
+ else if(primType == char.class)
+ return boxType == Character.class;
+ else if(primType == short.class)
+ return boxType == Short.class;
+ else if(primType == byte.class)
+ return boxType == Byte.class;
+ return false;
}
-static protected Object throwNotImplemented()
+static boolean isCongruent(Class[] params, Object[] args)
{
- throw new IllegalAccessError("Sorry, not implemented");
+ boolean ret = false;
+ if(args == null)
+ return params.length == 0;
+ if(params.length == args.length)
+ {
+ ret = true;
+ for(int i = 0; ret && i < params.length; i++)
+ {
+ Object arg = args[i];
+ Class argType = (arg == null) ? null : arg.getClass();
+ Class paramType = params[i];
+ if(paramType == boolean.class)
+ {
+ ret = arg == null || argType == Boolean.class;
+ }
+ else if(paramType.isPrimitive())
+ {
+ if(arg == null)
+ ret = false;
+ else
+ ret = primBoxTypeMatch(paramType, argType);
+ }
+ else
+ {
+ ret = arg == null
+ || argType == paramType
+ || paramType.isAssignableFrom(argType);
+ }
+ }
+ }
+ return ret;
}
}