📄 invoke.java
字号:
package gnu.kawa.reflect;import gnu.mapping.*;import gnu.expr.*;import gnu.bytecode.*;import gnu.lists.FString;import java.lang.reflect.Array;import gnu.kawa.lispexpr.ClassNamespace; // FIXMEpublic class Invoke extends ProcedureN implements CanInline{ /** The kind on invoke operation. * 'N' - make (new). * 'S' - invoke-static (static or non-static): * The first operand is a Class or Type, the second is the name, * and if the is non-static the 3rd is the receiver. * 's' - Like 'S' but only allow static methods. [not used] * 'V' - non-static invoke, only allow non-static methods. [not used] * '*' - non-static invoke, can match static methods also. * This is Java's 'Primary.MethodName(args)' - if the selected method * is static, we only use Primary's type for method select, * but ignore its value. */ char kind; Language language; public static final Invoke invoke = new Invoke("invoke", '*'); public static final Invoke invokeStatic = new Invoke("invoke-static", 'S'); public static final Invoke invokeSpecial = new Invoke("invoke-special", 'P'); public static final Invoke make = new Invoke("make", 'N'); public Invoke(String name, char kind) { super(name); this.kind = kind; this.language = Language.getDefaultLanguage(); } public Invoke(String name, char kind, Language language) { super(name); this.kind = kind; this.language = language; } public static Object invoke$V(Object[] args) throws Throwable { return invoke.applyN(args); } public static Object invokeStatic$V(Object[] args) throws Throwable { return invokeStatic.applyN(args); } public static Object make$V(Object[] args) throws Throwable { return make.applyN(args); } private static ObjectType typeFrom (Object arg, Invoke thisProc) { if (arg instanceof Class) arg = Type.make((Class) arg); if (arg instanceof ObjectType) return (ObjectType) arg; if (arg instanceof String || arg instanceof FString) return ClassType.make(arg.toString()); if (arg instanceof Symbol) return ClassType.make(((Symbol) arg).getName()); if (arg instanceof ClassNamespace) return ((ClassNamespace) arg).getClassType(); throw new WrongType(thisProc, 0, arg, "class-specifier"); } public void apply (CallContext ctx) throws Throwable { Object[] args = ctx.getArgs(); if (kind=='S' || kind=='V' || kind=='s' || kind=='*') { // The following is an optimization, so that output from the // method is sent directly to ctx.consumer, rather than reified. int nargs = args.length; Procedure.checkArgCount(this, nargs); Object arg0 = args[0]; ObjectType dtype = (ObjectType) ((kind == 'S' || kind == 's') ? typeFrom(arg0, this) : Type.make(arg0.getClass())); Procedure proc = lookupMethods(dtype, args[1]); Object[] margs = new Object[nargs-(kind == 'S' ? 2 : 1)]; int i = 0; if (kind == 'V' || kind == '*') margs[i++] = args[0]; System.arraycopy(args, 2, margs, i, nargs - 2); proc.checkN(margs, ctx); } else ctx.writeValue(this.applyN(args)); } public Object applyN (Object[] args) throws Throwable { if (kind == 'P') throw new RuntimeException(getName() + ": invoke-special not allowed at run time"); int nargs = args.length; Procedure.checkArgCount(this, nargs); Object arg0 = args[0]; ObjectType dtype = (kind != 'V' && kind != '*' ? typeFrom(arg0, this) : (ObjectType) Type.make(arg0.getClass())); Object mname; if (kind == 'N') { mname = null; if (dtype instanceof TypeValue) { Procedure constructor = ((TypeValue) dtype).getConstructor(); if (constructor != null) { nargs--; Object[] xargs = new Object[nargs]; System.arraycopy(args, 1, xargs, 0, nargs); return constructor.applyN(xargs); } } if (dtype instanceof PairClassType) { PairClassType ptype = (PairClassType) dtype; dtype = ptype.instanceType; } if (dtype instanceof ArrayType) { Type elementType = ((ArrayType) dtype).getComponentType(); int len; len = args.length-1; String name; int length; int i; boolean lengthSpecified; if (len >= 2 && args[1] instanceof Keyword && ("length".equals(name = ((Keyword) args[1]).getName()) || "size".equals(name))) { length = ((Number) args[2]).intValue(); i = 3; lengthSpecified = true; } else { length = len; i = 1; lengthSpecified = false; } Object arr = Array.newInstance(elementType.getReflectClass(), length); int index = 0; for (; i <= len; i++) { Object arg = args[i]; if (lengthSpecified && arg instanceof Keyword && i < len) { String kname = ((Keyword) arg).getName(); try { index = Integer.parseInt(kname); } catch (Throwable ex) { throw new RuntimeException("non-integer keyword '"+kname+"' in array constructor"); } arg = args[++i]; } Array.set(arr, index, elementType.coerceFromObject(arg)); index++; } return arr; } } else { mname = args[1]; } MethodProc proc = lookupMethods((ObjectType) dtype, mname); if (kind != 'N') { Object[] margs = new Object[nargs-(kind == 'S' || kind == 's' ? 2 : 1)]; int i = 0; if (kind == 'V' || kind == '*') margs[i++] = args[0]; System.arraycopy(args, 2, margs, i, nargs - 2); return proc.applyN(margs); } else { CallContext vars = CallContext.getInstance(); int err = proc.matchN(args, vars); if (err == 0) return vars.runUntilValue(); if ((nargs & 1) == 1) { // Check if args is a set of (keyword,value)-pairs. for (int i = 1; ; i += 2) { if (i == nargs) { Object result; result = proc.apply1(args[0]); for (i = 1; i < nargs; i += 2) { Keyword key = (Keyword) args[i]; Object arg = args[i+1]; SlotSet.apply(false, result, key.getName(), arg); } return result; } if (! (args[i] instanceof Keyword)) break; } } MethodProc vproc = ClassMethods.apply((ClassType) dtype, "valueOf", '\0', language); if (vproc != null) { Object[] margs = new Object[nargs-1]; System.arraycopy(args, 1, margs, 0, nargs-1); err = vproc.matchN(margs, vars); if (err == 0) return vars.runUntilValue(); } throw MethodProc.matchFailAsException(err, proc, args); } } public int numArgs() { return (-1 << 12) | (kind == 'N' ? 1 : 2); } protected MethodProc lookupMethods(ObjectType dtype, Object name) { String mname; if (kind == 'N') mname = "<init>"; else { if (name instanceof String || name instanceof FString) mname = name.toString(); else if (name instanceof Symbol) mname = ((Symbol) name).getName(); else throw new WrongType(this, 1, null); mname = Compilation.mangleName(mname); } MethodProc proc = ClassMethods.apply(dtype, mname, kind == 'P' ? 'P' : kind == '*' || kind == 'V' ? 'V' : '\0', language); if (proc == null) throw new RuntimeException(getName() + ": no method named `" + mname + "' in class " + dtype.getName()); return proc; } protected PrimProcedure[] getMethods(ObjectType ctype, String mname, ClassType caller) { return ClassMethods.getMethods(ctype, mname, kind == 'P' ? 'P' : kind == '*' || kind == 'V' ? 'V' : '\0', caller, language); } private static long selectApplicable(PrimProcedure[] methods, ObjectType ctype, Expression[] args, int margsLength, int argsStartIndex, int objIndex) { Type[] atypes = new Type[margsLength]; int dst = 0; if (objIndex >= 0) atypes[dst++] = ctype; for (int src = argsStartIndex; src < args.length && dst < atypes.length; src++, dst++) atypes[dst] = args[src].getType(); return ClassMethods.selectApplicable(methods, atypes); } /** Return an array if args (starting with start) is a set of * (keyword, value)-value pairs. */ static Object[] checkKeywords(Type type, Expression[] args, int start, ClassType caller) { int len = args.length; if (((len - start) & 1) != 0) return null; Object[] fields = new Object[(len-start) >> 1]; for (int i = fields.length; -- i>= 0; ) { Expression arg = args[start + 2 * i]; if (! (arg instanceof QuoteExp)) return null; Object value = ((QuoteExp) arg).getValue(); if (! (value instanceof Keyword)) return null; String name = ((Keyword) value).getName(); Member slot = SlotSet.lookupMember((ClassType) type, name, caller); fields[i] = slot != null ? (Object) slot : (Object) name; } return fields; } /** Check if class exists. * @return 1 if class actually exists; * -1 is class should exist, but doesn't; * and 0 otherwise. */ public static int checkKnownClass (Type type, Compilation comp) { if (type instanceof ClassType && ((ClassType) type).isExisting()) { try { type.getReflectClass(); return 1; } catch (Exception ex) { comp.error('e', "unknown class: " + type.getName()); return -1; } } return 0; } /** Resolve class specifier to ClassType at inline time. * This is an optimization to avoid having a module-level binding * created for the class name. */ public static ApplyExp inlineClassName (ApplyExp exp, int carg, InlineCalls walker) { Compilation comp = walker.getCompilation();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -