KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > mapping > MethodProc


1 // Copyright (c) 1999, 2004 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.mapping;
5 import gnu.bytecode.Type;
6
7 /** Similar to a CLOS method.
8  * Can check if arguments "match" before committing to calling method. */

9
10 public abstract class MethodProc extends ProcedureN
11 {
12   /** The parameter types.
13    * Usually either an Type[] or a String encoding. */

14   protected Object JavaDoc argTypes;
15
16   /** Test if method is applicable to an invocation with given arguments.
17    * Returns -1 if no; 1 if yes; 0 if need to check at run-time. */

18   public int isApplicable(Type[] argTypes)
19   {
20     int argCount = argTypes.length;
21     int num = numArgs();
22     if (argCount < (num & 0xFFF)
23     || (num >= 0 && argCount > (num >> 12)))
24       return -1;
25     int result = 1;
26     for (int i = argCount; --i >= 0; )
27       {
28         Type ptype = getParameterType(i);
29         int code = ptype.compare(argTypes[i]);
30         if (code == -3)
31           return -1;
32         if (code < 0)
33           result = 0;
34       }
35     return result;
36   }
37
38   /** Return number of parameters, including optional and rest arguments. */
39   public int numParameters()
40   {
41     int num = numArgs();
42     int max = num >> 12;
43     if (max >= 0)
44       return max;
45     // This isn't really right, but it works for PrimProcedure. FIXME.
46
int min = num & 0xFFF;
47     return min + 1;
48   }
49
50   static final Type[] unknownArgTypes = { Type.pointer_type };
51
52   /** Figure out or decode the parameter types, setting argTypes. */
53   protected void resolveParameterTypes()
54   {
55     argTypes = unknownArgTypes;
56   }
57
58   public Type getParameterType(int index)
59   {
60     if (! (argTypes instanceof Type[]))
61       resolveParameterTypes();
62
63     Type[] atypes = (Type[]) argTypes;
64     if (index >= atypes.length)
65       index = atypes.length - 1;
66     return atypes[index];
67   }
68
69   /** Return code from match: Unspecified failure. */
70   public static final int NO_MATCH = -1;
71
72   /** Return code from match: Too few actual arguments.
73    * The lower half is the minimum number of arguments (if not 0xffff). */

74   public static final int NO_MATCH_TOO_FEW_ARGS = 0xfff10000;
75
76   /** Return code from match: Too many actual arguments.
77    * The lower half is the maximum number of arguments (if not 0xffff). */

78   public static final int NO_MATCH_TOO_MANY_ARGS = 0xfff20000;
79
80   /** Return code from match: Ambigious which method to select. */
81   public static final int NO_MATCH_AMBIGUOUS = 0xfff30000;
82
83   /** Return code from match: Invalid argument type.
84    * In that case the lower half is the 1-origin index of the first
85    * argument that does not match. */

86   public static final int NO_MATCH_BAD_TYPE = 0xfff40000;
87
88   /** Helper method to throw an exception if a <code>matchX</code>
89    * method fails. */

90   public static RuntimeException JavaDoc
91   matchFailAsException(int code, Procedure proc, Object JavaDoc[] args)
92   {
93     int arg = (short) code;
94     code &= 0xffff0000;
95     if (code != NO_MATCH_BAD_TYPE)
96       return new WrongArguments(proc, args.length);
97     return new WrongType(proc, arg, arg > 0 ? args[arg-1] : null);
98   }
99
100   public Object JavaDoc applyN(Object JavaDoc[] args) throws Throwable JavaDoc
101   {
102     checkArgCount(this, args.length);
103     CallContext ctx = CallContext.getInstance();
104     checkN(args, ctx);
105     return ctx.runUntilValue();
106   }
107
108   /** Return the more specific of the arguments.
109    * @return null if neither is more specific. */

110   public static MethodProc mostSpecific(MethodProc proc1, MethodProc proc2)
111   {
112     // True if we've determined proc1 cannot be the more specific.
113
boolean not1 = false;
114     // True if we've determined proc2 cannot be the more specific.
115
boolean not2 = false;
116     int min1 = proc1.minArgs();
117     int min2 = proc2.minArgs();
118     int max1 = proc1.maxArgs();
119     int max2 = proc2.maxArgs();
120     if ((max1 >= 0 && max1 < min2)
121     || (max2 >= 0 && max2 < min1))
122       return null;
123     int num1 = proc1.numParameters();
124     int num2 = proc2.numParameters();
125     int limit = num1 > num2 ? num1 : num2;
126     if (max1 != max2)
127       {
128         if (max1 < 0)
129           not2 = true;
130         if (max2 < 0)
131           not1 = true;
132       }
133     if (min1 < min2)
134       not2 = true;
135     else if (min1 > min2)
136       not1 = true;
137     for (int i = 0; i < limit; i++)
138       {
139         Type t1 = proc1.getParameterType(i);
140         Type t2 = proc2.getParameterType(i);
141     int comp = t1.compare(t2);
142         if (comp == -1)
143           {
144             not2 = true;
145             if (not1)
146               return null;
147           }
148         if (comp == 1)
149           {
150             not1 = true;
151             if (not2)
152               return null;
153           }
154       }
155     return not2 ? proc1 : not1 ? proc2 : null;
156   }
157
158   /** Return the index of the most specific method. */
159   public static int mostSpecific(MethodProc[] procs, int length)
160   {
161     if (length <= 1) // Handles length==0 and length==1.
162
return length - 1;
163     // best is non-null if there is a single most specific method.
164
MethodProc best = procs[0];
165     // This array (which is allocated lazily) is used if there is is a set
166
// of bestn methods none of which are more specific than the others.
167
MethodProc[] bests = null;
168     // If best==null, then the index of the most specific method;
169
// otherwise the active length of the bests array.
170
int bestn = 0;
171   outer:
172     for (int i = 1; i < length; i++)
173       {
174         MethodProc method = procs[i];
175     if (best != null)
176       {
177         MethodProc winner = mostSpecific(best, method);
178         if (winner == null)
179           {
180         if (bests == null)
181           bests = new MethodProc[length];
182         bests[0] = best;
183         bests[1] = method;
184         bestn = 2;
185         best = null;
186           }
187         else if (winner == method)
188           {
189         best = method;
190         bestn = i;
191           }
192       }
193     else
194       {
195         for (int j = 0; j < bestn; j++)
196           {
197         MethodProc old = bests[j];
198         MethodProc winner = mostSpecific(old, method);
199         if (winner == old)
200           continue outer;
201         if (winner == null)
202           {
203             bests[bestn++] = method;
204             continue outer;
205           }
206           }
207         // At this point method is more specific than bests[0..bestn-1].
208
best = method;
209         bestn = i;
210       }
211       }
212     return best == null ? -1 : bestn;
213   }
214 }
215
Popular Tags