diff options
author | Rich Hickey <richhickey@gmail.com> | 2006-10-15 15:56:08 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2006-10-15 15:56:08 +0000 |
commit | 348f4fa02df4c2b111be5cc7afd48123fd40d195 (patch) | |
tree | 5ec845ba0f9108172e9dfabbf127011f0f9d051a /src | |
parent | b8e4aa5295ac361ebc01c40274b336b875e93489 (diff) |
interim checkin
Diffstat (limited to 'src')
-rw-r--r-- | src/cli/runtime/RT.cs | 6 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 168 | ||||
-rw-r--r-- | src/jvm/clojure/lang/RT.java | 4 |
3 files changed, 159 insertions, 19 deletions
diff --git a/src/cli/runtime/RT.cs b/src/cli/runtime/RT.cs index 40626d62..75659413 100644 --- a/src/cli/runtime/RT.cs +++ b/src/cli/runtime/RT.cs @@ -170,7 +170,11 @@ static public ISeq rest(Object x) return null;
return seq(x).rest();
}
-
+
+static public ISeq rrest(Object x) {
+ return rest(rest(x));
+}
+
static public Object peek(Object x)
{
if (x == null)
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 759b8730..1a3faa01 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -18,7 +18,7 @@ import java.io.FileInputStream; import java.lang.reflect.Field; import java.lang.reflect.Constructor; import java.lang.reflect.Method; -import java.util.Iterator; +import java.lang.reflect.Modifier; public class Compiler { ///* @@ -390,13 +390,19 @@ private static Expr analyzeSeq(C context, ISeq form) throws Exception { else { PersistentArrayList args = new PersistentArrayList(4); - for (ISeq s = RT.rest(form); s != null; s = s.rest()) + for (ISeq s = op instanceof InstanceMemberSymbol ? RT.rrest(form) : RT.rest(form); s != null; s = s.rest()) args = args.cons(analyze(C.EXPRESSION, macroexpand(s.first()))); if (op instanceof ClassSymbol) return new InvokeConstructorExpr((ClassSymbol) op, args); else if (op instanceof StaticMemberSymbol) return new InvokeStaticMethodExpr((StaticMemberSymbol) op, args); + else if (op instanceof InstanceMemberSymbol) + return analyzeInstanceInvoke((InstanceMemberSymbol) op, + analyze(C.EXPRESSION, macroexpand(RT.second(form))), + args); + + Expr fexpr = (op instanceof Symbol) ? analyzeSymbol((Symbol) op, true) : analyze(C.EXPRESSION, op); if (fexpr instanceof FnExpr) ((FnExpr) fexpr).isCalledDirectly = true; @@ -404,6 +410,18 @@ private static Expr analyzeSeq(C context, ISeq form) throws Exception { } } +private static Expr analyzeInstanceInvoke(InstanceMemberSymbol sym, Expr target, PersistentArrayList args) + throws Exception { + Class targetClass = null; + if (sym.className != null) + targetClass = getTypeNamed(resolveHostClassname(sym.className)); + else if (target.getHostType() != null) + targetClass = target.getHostType(); + else //must make reflection-based call + return new InvokeUntypedInstanceMemberExpr(sym.memberName, target, args); + return new InvokeInstanceMemberExpr(targetClass, sym.memberName, target, args); +} + static class InvokeExpr extends AnExpr { Expr fexpr; PersistentArrayList args; @@ -465,20 +483,34 @@ static class InvokeStaticMethodExpr extends AHostExpr { final String resolvedClassName; final Class type; PersistentArrayList args; - Method method; + final Method method; + final Class returnType; public InvokeStaticMethodExpr(StaticMemberSymbol sym, PersistentArrayList args) throws Exception { this.sym = sym; this.args = args; this.resolvedClassName = resolveHostClassname(sym.className); this.type = getTypeNamed(resolvedClassName); - this.method = findSingleStaticMethod(type, sym.memberName, args); + Object sm = findSingleMethod(type, sym.memberName, args, true); + if(sm instanceof Method) + { + method = (Method) sm; + returnType = method.getReturnType(); + } + else if(sm instanceof Class) + { + method = null; + returnType = (Class) sm; + } + else + { + method = null; + returnType = null; + } } public Class getHostType() throws Exception { - if (method != null) - return method.getReturnType(); - return null; + return returnType; } public void emitHostExpr() throws Exception { @@ -491,6 +523,91 @@ static class InvokeStaticMethodExpr extends AHostExpr { } } +static class InvokeUntypedInstanceMemberExpr extends AnExpr { + final String name; + final Expr target; + PersistentArrayList args; + + public InvokeUntypedInstanceMemberExpr(String name, Expr target, PersistentArrayList args) throws Exception { + this.name = name; + this.args = args; + this.target = target; + } + + public void emitExpression() throws Exception { + format("Reflector.invokeInstanceMember(~S,~A~{,~A~})", name, target, RT.seq(args)); + } + +} + +static class InvokeInstanceMemberExpr extends AHostExpr { + final String name; + final Expr target; + PersistentArrayList args; + final Class targetType; + final Field field; + final Method method; + final Class returnType; + + public InvokeInstanceMemberExpr(Class targetClass, String name, Expr target, PersistentArrayList args) + throws Exception { + this.name = name; + this.args = args; + this.target = target; + this.targetType = targetClass; + field = Reflector.getField(targetClass, name, false); + if (field != null) + { + method = null; + returnType = field.getType(); + } + else + { + Object sm = findSingleMethod(targetClass, name, args, false); + if(sm instanceof Method) + { + method = (Method) sm; + returnType = method.getReturnType(); + } + else if(sm instanceof Class) + { + method = null; + returnType = (Class) sm; + } + else + { + method = null; + returnType = null; + } + } + } + + public Class getHostType() throws Exception { + return returnType; + } + + public void emitHostExpr() throws Exception { + if(target.canEmitHostExpr()) + target.emitHostExpr(); + else + emitConvert(targetType, target); + if(field != null) + { + format(".~A", name); + } + else + { + format(".~A(", name); + if (method != null) + emitTypedArgs(method.getParameterTypes(), args, method.isVarArgs()); + else + emitHostArgs(args); + format(")"); + } + } + +} + static void emitHostArgs(PersistentArrayList args) throws Exception { for (int i = 0; i < args.count(); i++) { @@ -512,7 +629,6 @@ static void emitTypedArgs(Class[] parameterTypes, PersistentArrayList args, bool { Expr arg = (Expr) args.nth(i); if (arg.canEmitHostExpr()) - //emitCast(parameterTypes[i], arg); arg.emitHostExpr(); else emitConvert(parameterTypes[i], arg); @@ -528,7 +644,6 @@ static void emitTypedArgs(Class[] parameterTypes, PersistentArrayList args, bool Expr arg = (Expr) args.nth(i); if (arg.canEmitHostExpr()) arg.emitHostExpr(); - // emitCast(vtype, arg); else emitConvert(vtype, arg); if (i < args.count() - 1) @@ -594,28 +709,45 @@ public static Constructor findSingleConstructor(Class c, PersistentArrayList arg return found; } -/*returns null unless single method with matching arity, throws if no method can handle arity*/ +/*returns Method if single method with matching arity, + returns Class of return type if all methods with same arity have same return type + else returns null + throws if no method can handle arity*/ -public static Method findSingleStaticMethod(Class c, String methodName, PersistentArrayList args) throws Exception { +public static Object findSingleMethod(Class c, String methodName, PersistentArrayList args, boolean isStatic) throws Exception { Method[] allmethods = c.getMethods(); Method found = null; + int foundCount = 0; + boolean returnsMatch = true; for (int i = 0; i < allmethods.length; i++) { Method method = allmethods[i]; - if (method.getName().equals(methodName) && - (method.getParameterTypes().length == args.count() - || (method.isVarArgs() && method.getParameterTypes().length <= args.count()))) + if (Modifier.isStatic(method.getModifiers()) == isStatic + && method.getName().equals(methodName) + && (method.getParameterTypes().length == args.count() + || (method.isVarArgs() && method.getParameterTypes().length <= args.count()))) { if (found == null) + { found = method; + foundCount = 1; + } else - return null; //more than one matching + { + ++foundCount; + if (method.getReturnType() != found.getReturnType()) + returnsMatch = false; + } } } - //verify that at least one ctor can handle arity (requires variadic detection) - if (found == null) + //verify that at least one method can handle arity (requires variadic detection) + if (foundCount == 0) throw new Exception("No method that can handle arity"); - return found; + else if(foundCount == 1) + return found; + else if(returnsMatch) + return found.getReturnType(); + return null; } private static Expr analyzeLet(C context, ISeq form) throws Exception { diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index ae9f3e4a..a4ce4795 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -160,6 +160,10 @@ static public ISeq rest(Object x) { return seq(x).rest(); } +static public ISeq rrest(Object x) { + return rest(rest(x)); +} + static public Object peek(Object x) { if(x == null) return null; |