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