1 // Copyright (c) 2015 Per M.A. Bothner. 2 // This is free software; for terms and warranty disclaimer see ./COPYING. 3 4 package gnu.expr; 5 import gnu.mapping.*; 6 import java.lang.reflect.*; 7 /* #ifdef use:java.lang.invoke */ 8 import java.lang.invoke.MethodHandle; 9 /* #else */ 10 // import gnu.mapping.CallContext.MethodHandle; 11 /* #endif */ 12 import kawa.SourceMethodType; 13 14 public class CompiledProc extends MethodProc { 15 protected int numArgs; 16 private Object module; // rename to frame? or context? 17 getModule()18 public Object getModule() { return module; } 19 getModuleClass()20 public Class getModuleClass() { 21 /* #ifdef JAVA8 */ 22 try { 23 return java.lang.invoke.MethodHandles.lookup() 24 .revealDirect(getApplyMethod()) 25 .getDeclaringClass(); 26 } catch (Exception ex) { 27 } 28 /* #endif */ 29 if (module == null || module instanceof Class) 30 return (Class) module; 31 else 32 return module.getClass(); 33 } 34 CompiledProc(Object module, boolean resultGoesToConsumer, MethodHandle applyMethod, Object name, int numArgs)35 public CompiledProc(Object module, boolean resultGoesToConsumer, MethodHandle applyMethod, Object name, int numArgs) { 36 init(resultGoesToConsumer, applyMethod, name, numArgs); 37 this.module = module; 38 } 39 CompiledProc(boolean resultGoesToConsumer, MethodHandle applyMethod, Object name, int numArgs, Object argTypes)40 public CompiledProc(boolean resultGoesToConsumer, MethodHandle applyMethod, Object name, 41 int numArgs, Object argTypes) { 42 init(resultGoesToConsumer, applyMethod, name, numArgs); 43 this.argTypes = argTypes; 44 } 45 makeResultToObject(Object module, MethodHandle applyMethod, Object name, int numArgs)46 public static CompiledProc makeResultToObject(Object module, MethodHandle applyMethod, Object name, int numArgs) { 47 return new CompiledProc(module, false, applyMethod, name, numArgs); 48 } 49 makeResultToConsumer(Object module, MethodHandle applyMethod, Object name, int numArgs)50 public static CompiledProc makeResultToConsumer(Object module, MethodHandle applyMethod, Object name, int numArgs) { 51 return new CompiledProc(module, true, applyMethod, name, numArgs); 52 } 53 initResultToObject(Object module, MethodHandle applyMethod, Object name, int numArgs)54 public void initResultToObject(Object module, MethodHandle applyMethod, Object name, int numArgs) { 55 init(false, applyMethod, name, numArgs); 56 this.module = module; 57 } 58 initResultToConsumer(Object module, MethodHandle applyMethod, Object name, int numArgs)59 public void initResultToConsumer(Object module, MethodHandle applyMethod, Object name, int numArgs) { 60 init(true, applyMethod, name, numArgs); 61 this.module = module; 62 } 63 init(boolean resultGoesToConsumer, MethodHandle applyMethod, Object name, int numArgs)64 public CompiledProc init(boolean resultGoesToConsumer, 65 MethodHandle applyMethod, 66 Object name, int numArgs) { 67 if (resultGoesToConsumer) { 68 applyToConsumerMethod = applyMethod; 69 applyToObjectMethod = applyToObjectDefault; 70 } else { 71 applyToObjectMethod = applyMethod; 72 applyToConsumerMethod = applyToConsumerDefault; 73 } 74 this.numArgs = numArgs; 75 if (name != null) 76 setSymbol(name); 77 return this; 78 } 79 80 /** Figure out parameter types. 81 * Uses reflection to get method parameter types. 82 * INCOMPLETE - does not handle procedures with optional or rest args, 83 or with patterns. */ resolveParameterTypes()84 protected void resolveParameterTypes() { 85 Method method = null; 86 String name = getName(); 87 if (name != null) { 88 try { 89 Class moduleClass = getModuleClass(); 90 Method[] methods = moduleClass.getDeclaredMethods(); 91 String mangledName = Mangling.mangleMethod(name); 92 for (int i = methods.length; --i >= 0; ) { 93 if (methods[i].getName().equals(mangledName)) { 94 if (method != null) { 95 method = null; 96 break; 97 } 98 method = methods[i]; 99 } 100 } 101 if (method != null) { 102 Language lang = Language.getDefaultLanguage(); 103 if (lang != null) { 104 Class[] parameterClasses = method.getParameterTypes(); 105 int numParamTypes = parameterClasses.length; 106 gnu.bytecode.Type[] atypes = new gnu.bytecode.Type[numParamTypes]; 107 String[] annotTypes; 108 try { 109 SourceMethodType sourceType = method.getAnnotation(SourceMethodType.class); 110 annotTypes = sourceType == null ? null : sourceType.value(); 111 } catch (Throwable ex) { 112 annotTypes = null; 113 } 114 for (int i = numParamTypes; --i >= 0; ) { 115 atypes[i] = lang.getTypeFor(parameterClasses[i]); 116 if (annotTypes != null) 117 atypes[i] = 118 PrimProcedure.decodeType(atypes[i], 119 annotTypes, i+1, 120 null, lang); 121 } 122 this.argTypes = atypes; 123 } 124 } 125 } catch (Exception ex) { 126 } 127 } 128 if (argTypes == null) 129 super.resolveParameterTypes(); 130 } 131 numArgs()132 public int numArgs() { return numArgs; } 133 } 134