KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > expr > PrimProcedure


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

4 package gnu.expr;
5 import gnu.bytecode.*;
6 import gnu.mapping.*;
7
8 /** A primitive Procedure implemented by a plain Java method. */
9
10 public class PrimProcedure extends MethodProc implements gnu.expr.Inlineable
11 {
12   Type retType;
13   /** The types of the method parameters.
14    * If known, the types have been coerced to Language-specific parameters.
15    * Does not include the implicit static link argument of some constructors.
16    */

17   Type[] argTypes;
18   Method method;
19   int op_code;
20   /** 'P' means use invokespecial;
21    * 'V' means expect a target (this) argument, even if method is static;
22    * '\0' means don't expect a target. */

23   char mode;
24
25   /** If non-null, the LambdaExp that this PrimProcedure implements. */
26   LambdaExp source;
27
28   java.lang.reflect.Member JavaDoc member;
29
30   public final int opcode() { return op_code; }
31
32   public Type getReturnType () { return retType; }
33   public void setReturnType (Type retType) { this.retType = retType; }
34
35   public boolean isSpecial() { return mode == 'P'; }
36
37   public Type getReturnType (Expression[] args) { return retType; }
38
39   /** Return true iff the last parameter is a "rest" argument. */
40   public boolean takesVarArgs()
41   {
42     if (method != null)
43       {
44     String JavaDoc name = method.getName();
45     return name.endsWith("$V") || name.endsWith("$V$X");
46       }
47     return false;
48   }
49
50   public boolean takesContext()
51   {
52     return method != null && takesContext(method);
53   }
54
55   public static boolean takesContext(Method method)
56   {
57     return method.getName().endsWith("$X");
58   }
59
60   public final boolean isConstructor()
61   {
62     // invokespecial == primitive-constructor
63
return opcode() == 183 && mode != 'P';
64   }
65
66   /** Whether we are passed an argument for the 'target' / 'receiver' / 'this'.
67    * Normally this is false for static methods and true for non-static
68    * methods. However, we may need to be able to call a static method using
69    * {@code object.name(args...)} (Java syntax) or
70    * {@code (invoke object 'name args...)} (Scheme syntax).
71    * This includes when the {@code object} is implied.
72    * In this case we need to ignore the first argument's value.
73    */

74   public boolean takesTarget ()
75   {
76     return mode != '\0';
77   }
78
79   /** The (minimum, number) of arguments.
80    * Doesn't not count implicit CallContext argument.
81    * Does count 'this' argument for non-static methods.
82    * Does count an implicit staticLink argument for constructor.
83    */

84   public int numArgs()
85   {
86     int num = argTypes.length;
87     if (takesTarget())
88       num++;
89     if (takesContext())
90       num--;
91     return takesVarArgs() ? (num - 1) + (-1 << 12) : num + (num << 12);
92   }
93
94   public int match0 (CallContext ctx)
95   {
96     return matchN(ProcedureN.noArgs, ctx);
97   }
98
99   public int match1 (Object JavaDoc arg1, CallContext ctx)
100   {
101     Object JavaDoc[] args = { arg1 };
102     return matchN(args, ctx);
103   }
104
105   public int match2 (Object JavaDoc arg1, Object JavaDoc arg2, CallContext ctx)
106   {
107     Object JavaDoc[] args = { arg1, arg2 };
108     return matchN(args, ctx);
109   }
110
111   public int match3 (Object JavaDoc arg1, Object JavaDoc arg2, Object JavaDoc arg3, CallContext ctx)
112   {
113     Object JavaDoc[] args = { arg1, arg2, arg3 };
114     return matchN(args, ctx);
115   }
116
117   public int match4 (Object JavaDoc arg1, Object JavaDoc arg2, Object JavaDoc arg3, Object JavaDoc arg4,
118              CallContext ctx)
119   {
120     Object JavaDoc[] args = { arg1, arg2, arg3, arg4 };
121     return matchN(args, ctx);
122   }
123
124   public int matchN (Object JavaDoc[] args, CallContext ctx)
125   {
126     int nargs = args.length;
127     boolean takesVarArgs = takesVarArgs();
128     int fixArgs = minArgs();
129     if (nargs < fixArgs)
130       return NO_MATCH_TOO_FEW_ARGS|fixArgs;
131     if (! takesVarArgs && nargs > fixArgs)
132       return NO_MATCH_TOO_MANY_ARGS|fixArgs;
133     int paramCount = argTypes.length;
134     Type elementType = null;
135     Object JavaDoc[] restArray = null;
136     int extraCount = (takesTarget() || isConstructor()) ? 1 : 0;
137     boolean takesContext = takesContext();
138     Object JavaDoc[] rargs = new Object JavaDoc[paramCount];
139     if (takesContext)
140       rargs[--paramCount] = ctx;
141     Object JavaDoc extraArg;
142     if (takesVarArgs)
143       {
144     Type restType = argTypes[paramCount-1];
145     if (restType == Compilation.scmListType)
146       { // FIXME
147
rargs[paramCount-1] = gnu.lists.LList.makeList(args, fixArgs);
148         nargs = fixArgs;
149             elementType = Type.pointer_type;
150       }
151     else
152       {
153         ArrayType restArrayType = (ArrayType) restType;
154         elementType = restArrayType.getComponentType();
155         Class JavaDoc elementClass = elementType.getReflectClass();
156         restArray = (Object JavaDoc[])
157           java.lang.reflect.Array.newInstance(elementClass, nargs-fixArgs);
158         rargs[paramCount-1] = restArray;
159       }
160       }
161     if (isConstructor())
162       extraArg = args[0];
163     else if (extraCount != 0)
164       {
165     try
166       {
167             extraArg = method.getDeclaringClass().coerceFromObject(args[0]);
168       }
169     catch (ClassCastException JavaDoc ex)
170           {
171             return NO_MATCH_BAD_TYPE|1;
172           }
173       }
174     else
175       extraArg = null;
176     for (int i = extraCount; i < args.length; i++)
177       {
178         Object JavaDoc arg = args[i];
179         Type type = i < fixArgs ? argTypes[i-extraCount] : elementType;
180         if (type != Type.pointer_type)
181           {
182             try
183               {
184                 arg = type.coerceFromObject(arg);
185               }
186             catch (ClassCastException JavaDoc ex)
187               {
188                 return NO_MATCH_BAD_TYPE|(i+1);
189               }
190           }
191         if (i < fixArgs)
192           rargs[i-extraCount] = arg;
193         else if (restArray != null) // I.e. using array rather than LList.
194
restArray[i - fixArgs] = arg;
195       }
196     ctx.value1 = extraArg;
197     ctx.values = rargs;
198     ctx.proc = this;
199     return 0;
200   }
201
202   public void apply (CallContext ctx) throws Throwable JavaDoc
203   {
204     int arg_count = argTypes.length;
205     boolean is_constructor = isConstructor();
206     boolean slink = is_constructor && method.getDeclaringClass().hasOuterLink();
207
208     try
209       {
210     if (member == null)
211       {
212         Class JavaDoc clas = method.getDeclaringClass().getReflectClass();
213         Class JavaDoc[] paramTypes = new Class JavaDoc[arg_count+(slink?1:0)];
214         for (int i = arg_count; --i >= 0; )
215           paramTypes[i+(slink?1:0)] = argTypes[i].getReflectClass();
216             if (slink)
217               paramTypes[0] = method.getDeclaringClass().getOuterLinkType().getReflectClass();
218         if (is_constructor)
219           member = clas.getConstructor(paramTypes);
220         else
221           member = clas.getMethod(method.getName(), paramTypes);
222       }
223     Object JavaDoc result;
224     if (is_constructor)
225           {
226             Object JavaDoc[] args = ctx.values;
227             if (slink)
228               {
229                 int nargs = args.length + 1;
230                 Object JavaDoc[] xargs = new Object JavaDoc[nargs];
231                 System.arraycopy(args, 0, xargs, 1, nargs-1);
232                 xargs[0] = ((PairClassType) ctx.value1).staticLink;
233                 args = xargs;
234               }
235
236             result = (((java.lang.reflect.Constructor JavaDoc) member)
237                       .newInstance(args));
238           }
239     else
240       result = retType.coerceToObject(((java.lang.reflect.Method JavaDoc) member)
241                       .invoke(ctx.value1, ctx.values));
242         if (! takesContext())
243           ctx.consumer.writeObject(result);
244       }
245     catch (java.lang.reflect.InvocationTargetException JavaDoc ex)
246       {
247     throw ex.getTargetException();
248       }
249   }
250
251   public PrimProcedure (String JavaDoc className, String JavaDoc methodName, int numArgs)
252   {
253     this(ClassType.make(className).getDeclaredMethod(methodName, numArgs));
254   }
255
256   public PrimProcedure(java.lang.reflect.Method JavaDoc method, Language language)
257   {
258     this(((ClassType) language.getTypeFor(method.getDeclaringClass()))
259          .getMethod(method), language);
260   }
261
262   public PrimProcedure(Method method)
263   {
264     init(method);
265     this.retType = method.getName().endsWith("$X") ? Type.pointer_type
266       : method.getReturnType();
267   }
268
269   public PrimProcedure(Method method, Language language)
270   {
271     this(method, '\0', language);
272   }
273
274   public PrimProcedure(Method method, char mode, Language language)
275   {
276     this.mode = mode;
277
278     init(method);
279
280     // This stuff deals with that a language may have its own mapping
281
// from Java types to language types, for coercions and other reasons.
282
Type[] pTypes = this.argTypes;
283     int nTypes = pTypes.length;
284     argTypes = null;
285     for (int i = nTypes; --i >= 0; )
286       {
287     Type javaType = pTypes[i];
288         if (javaType instanceof ClassType
289             && ! ((ClassType) javaType).isExisting())
290           continue;
291     Type langType = language.getLangTypeFor(javaType);
292     if (javaType != langType)
293       {
294         if (argTypes == null)
295           {
296         argTypes = new Type[nTypes];
297         System.arraycopy(pTypes, 0, argTypes, 0, nTypes);
298           }
299         argTypes[i] = langType;
300       }
301       }
302     if (argTypes == null)
303       argTypes = pTypes;
304     if (isConstructor())
305       retType = method.getDeclaringClass();
306     else if (method.getName().endsWith("$X"))
307       retType = Type.pointer_type;
308     else
309       {
310         retType = language.getLangTypeFor(method.getReturnType());
311
312         // Kludge - tostring_type doesn't have methods.
313
// It shouldn't be used as the "type" of anything -
314
// it's just a type with a coercion. FIXME.
315
if (retType == Type.tostring_type)
316           retType = Type.string_type;
317       }
318   }
319   
320   private void init(Method method)
321   {
322     this.method = method;
323     int flags = method.getModifiers();
324     if ((flags & Access.STATIC) != 0)
325       this.op_code = 184; // invokestatic
326
else
327       {
328     ClassType mclass = method.getDeclaringClass();
329     if (mode == 'P')
330       this.op_code = 183; // invokespecial
331
else
332           {
333             mode = 'V';
334             if ("<init>".equals(method.getName()))
335               this.op_code = 183; // invokespecial
336
else if ((mclass.getModifiers() & Access.INTERFACE) != 0)
337               this.op_code = 185; // invokeinterface
338
else
339               this.op_code = 182; // invokevirtual
340
}
341       }
342     Type[] mtypes = method.getParameterTypes();
343     if (isConstructor() && method.getDeclaringClass().hasOuterLink())
344       {
345         int len = mtypes.length-1;
346         Type[] types = new Type[len];
347         System.arraycopy(mtypes, 1, types, 0, len);
348         mtypes = types;
349       }
350     this.argTypes = mtypes;
351   }
352
353   public PrimProcedure(Method method, LambdaExp source)
354   {
355     this(method);
356     this.retType = source.getReturnType();
357     this.source = source;
358   }
359
360   public PrimProcedure(int opcode, Type retType, Type[] argTypes)
361   {
362     this.op_code = opcode;
363     this.retType = retType;
364     this.argTypes= argTypes;
365   }
366
367   public static PrimProcedure makeBuiltinUnary(int opcode, Type type)
368   {
369     // FIXME - should cache!
370
Type[] args = new Type[1];
371     args[0] = type;
372     return new PrimProcedure(opcode, type, args);
373   }
374
375   public static PrimProcedure makeBuiltinBinary(int opcode, Type type)
376   {
377     // FIXME - should cache!
378
Type[] args = new Type[2];
379     args[0] = type;
380     args[1] = type;
381     return new PrimProcedure(opcode, type, args);
382   }
383
384   public PrimProcedure(int op_code, ClassType classtype, String JavaDoc name,
385                Type retType, Type[] argTypes)
386   {
387     this.op_code = op_code;
388     method = classtype.addMethod (name, op_code == 184 ? Access.STATIC : 0,
389                   argTypes, retType);
390     this.retType = retType;
391     this.argTypes= argTypes;
392     mode = op_code == 184 ? '\0' : 'V';
393   }
394
395   /** True if there is no 'this' parameter. */
396   public final boolean getStaticFlag()
397   {
398     return method == null
399       || method.getStaticFlag()
400       || isConstructor();
401   }
402
403   public final Type[] getParameterTypes() { return argTypes; }
404
405   /** Compile arguments and push unto stack.
406    * @param args arguments to evaluate and push.
407    * @param thisType If we are calling a non-static function,
408    * then args[0] is the receiver and thisType is its expected class.
409    * If thisType==Type.void_type, ignore argTypes[0]. (It is used to to
410    * pass a link to a closure environment, which was pushed by our caller.)
411    * If thisType==null, no special handling of args[0] or argTypes[0].
412    */

413   private void compileArgs(Expression[] args, int startArg, Type thisType, Compilation comp)
414  {
415     boolean variable = takesVarArgs();
416     String JavaDoc name = getName();
417     Type arg_type = null;
418     gnu.bytecode.CodeAttr code = comp.getCode();
419     int skipArg = thisType == Type.void_type ? 1 : 0;
420     int arg_count = argTypes.length - skipArg;
421     if (takesContext())
422       arg_count--;
423     boolean is_static = thisType == null || skipArg != 0;
424     int fix_arg_count = variable ? arg_count - 1 : args.length - startArg;
425     Declaration argDecl = source == null ? null : source.firstDecl();
426     if (argDecl != null && argDecl.isThisParameter())
427       argDecl = argDecl.nextDecl();
428     for (int i = 0; ; ++i)
429       {
430         if (variable && i == fix_arg_count)
431           {
432             arg_type = argTypes[arg_count-1+skipArg];
433         if (arg_type == Compilation.scmListType)
434           {
435         gnu.kawa.functions.MakeList.compile(args, startArg+i, comp);
436         break;
437           }
438             code.emitPushInt(args.length - startArg - fix_arg_count);
439             arg_type = ((ArrayType) arg_type).getComponentType();
440             code.emitNewArray(arg_type);
441           }
442         if (i + startArg >= args.length)
443           break;
444         if (i >= fix_arg_count)
445           {
446             code.emitDup(1); // dup array.
447
code.emitPushInt(i - fix_arg_count);
448           }
449         else
450           arg_type = argDecl != null && (is_static || i > 0) ? argDecl.getType()
451         : is_static ? argTypes[i + skipArg]
452             : i==0 ? thisType
453             : argTypes[i-1];
454     comp.usedClass(arg_type);
455     Target target =
456       source == null ? CheckedTarget.getInstance(arg_type, name, i+1)
457       : CheckedTarget.getInstance(arg_type, source, i);
458     args[startArg+i].compileNotePosition(comp, target, args[startArg+i]);
459         if (i >= fix_arg_count)
460           code.emitArrayStore(arg_type);
461     if (argDecl != null && (is_static || i > 0))
462       argDecl = argDecl.nextDecl();
463       }
464   }
465
466   public void compile (ApplyExp exp, Compilation comp, Target target)
467   {
468     gnu.bytecode.CodeAttr code = comp.getCode();
469     ClassType mclass = method == null ? null : method.getDeclaringClass();
470     Expression[] args = exp.getArgs();
471     if (isConstructor())
472       {
473         code.emitNew(mclass);
474         code.emitDup(mclass);
475       }
476     String JavaDoc arg_error = WrongArguments.checkArgCount(this, args.length);
477     if (arg_error != null)
478       comp.error('e', arg_error);
479
480     compile(getStaticFlag() ? null : mclass, exp, comp, target);
481   }
482
483   void compile (Type thisType, ApplyExp exp, Compilation comp, Target target)
484   {
485     Expression[] args = exp.getArgs();
486     gnu.bytecode.CodeAttr code = comp.getCode();
487     Type stackType = retType;
488     int startArg = 0;
489     if (isConstructor())
490       {
491         ClassType mclass = method == null ? null : method.getDeclaringClass();
492         if (mclass.hasOuterLink())
493           {
494             // This can be optimized in most cases. FIXME.
495
args[0].compile(comp, Target.pushValue(Compilation.typeClassType));
496             code.emitInvokeStatic(ClassType.make("gnu.expr.PairClassType").getDeclaredMethod("extractStaticLink", 1));
497             code.emitCheckcast(mclass.getOuterLinkType());
498             thisType = Type.void_type;
499           }
500         else
501           thisType = null;
502         startArg = 1;
503       }
504     else if (takesTarget() && method.getStaticFlag())
505       startArg = 1;
506
507     compileArgs(args, startArg, thisType, comp);
508
509     if (method == null)
510       {
511         code.emitPrimop (opcode(), args.length, retType);
512         target.compileFromStack(comp, stackType);
513       }
514     else
515       {
516         compileInvoke(comp, method, target,
517                       exp.isTailCall(), op_code, stackType);
518       }
519   }
520
521   /** Emit the actual invoke operation, after arguments have been pushed.
522    * Does whatever magic is needed to pass the result to target,
523    * including passing CallContext or special handling of ConsumerTarget.
524    */

525   public static void
526   compileInvoke (Compilation comp, Method method, Target target,
527                  boolean isTailCall, int op_code, Type stackType)
528   {
529     CodeAttr code = comp.getCode();
530     comp.usedClass(method.getDeclaringClass());
531     comp.usedClass(method.getReturnType());
532     if (! takesContext(method))
533       {
534         code.emitInvokeMethod(method, op_code);
535       }
536     else if (target instanceof IgnoreTarget
537                || (target instanceof ConsumerTarget
538                  && ((ConsumerTarget) target).isContextTarget()))
539       {
540         Field consumerFld = null;
541         Variable saveCallContext = null;
542         comp.loadCallContext();
543         if (target instanceof IgnoreTarget)
544           {
545             ClassType typeCallContext = Compilation.typeCallContext;
546             consumerFld = typeCallContext.getDeclaredField("consumer");
547             
548             // Consumer saveConsumer = ctx.consumer;
549
// ctx.consumer = VoidConsumer.instance:
550
code.pushScope();
551             saveCallContext = code.addLocal(typeCallContext);
552             code.emitDup();
553             code.emitGetField(consumerFld);
554             code.emitStore(saveCallContext);
555             code.emitDup();
556             code.emitGetStatic(ClassType.make("gnu.lists.VoidConsumer")
557                                .getDeclaredField("instance"));
558             code.emitPutField(consumerFld);
559           }
560         code.emitInvokeMethod(method, op_code);
561         if (isTailCall)
562           {
563             comp.loadCallContext();
564             code.emitInvoke(Compilation.typeCallContext
565                             .getDeclaredMethod("runUntilDone", 0));
566           }
567         if (target instanceof IgnoreTarget)
568           {
569             // ctx.consumer = saveConsumer
570
comp.loadCallContext();
571             code.emitLoad(saveCallContext);
572             code.emitPutField(consumerFld);
573             code.popScope();
574          }
575         return;
576       }
577     else
578       {
579         comp.loadCallContext();
580         stackType = Type.pointer_type;
581         code.pushScope();
582         Variable saveIndex = code.addLocal(Type.int_type);
583         comp.loadCallContext();
584         code.emitInvokeVirtual(Compilation.typeCallContext.
585                                getDeclaredMethod("startFromContext", 0));
586         code.emitStore(saveIndex);
587         code.emitWithCleanupStart();
588         code.emitInvokeMethod(method, op_code);
589         code.emitWithCleanupCatch(null);
590         comp.loadCallContext();
591         code.emitLoad(saveIndex);
592         code.emitInvokeVirtual(Compilation.typeCallContext.
593                                getDeclaredMethod("cleanupFromContext", 1));
594         code.emitWithCleanupDone();
595         comp.loadCallContext();
596         code.emitLoad(saveIndex);
597         code.emitInvokeVirtual(Compilation.typeCallContext.
598                                getDeclaredMethod("getFromContext", 1));
599         code.popScope();
600       }
601     target.compileFromStack(comp, stackType);
602   }
603
604   public Type getParameterType(int index)
605   {
606     if (takesTarget())
607       {
608         if (index == 0)
609           return isConstructor() ? Type.pointer_type
610             : method.getDeclaringClass();
611         index--;
612       }
613     int lenTypes = argTypes.length;
614     if (index < lenTypes - 1)
615       return argTypes[index];
616     boolean varArgs = takesVarArgs();
617     if (index < lenTypes && ! varArgs)
618       return argTypes[index];
619     // if (! varArgs) ERROR;
620
Type restType = argTypes[lenTypes - 1];
621     if (restType instanceof ArrayType)
622       return ((ArrayType) restType).getComponentType();
623     else // Should be LList or some other Sequence class.
624
return Type.pointer_type;
625   }
626
627   // This is null in JDK 1.1 and something else in JDK 1.2.
628
private static ClassLoader JavaDoc systemClassLoader
629   = PrimProcedure.class.getClassLoader();
630
631   public static PrimProcedure getMethodFor (Procedure pproc, Expression[] args)
632   {
633     return getMethodFor(pproc, null, args, Language.getDefaultLanguage());
634   }
635
636   /** Search for a matching static method in a procedure's class.
637    * @return a PrimProcedure that is suitable, or null. */

638   public static PrimProcedure getMethodFor (Procedure pproc, Declaration decl,
639                         Expression[] args,
640                         Language language)
641   {
642     int nargs = args.length;
643     Type[] atypes = new Type[nargs];
644     for (int i = nargs; --i >= 0;) atypes[i] = args[i].getType();
645     return getMethodFor(pproc, decl, atypes, language);
646   }
647
648   public static PrimProcedure getMethodFor (Procedure pproc, Declaration decl,
649                         Type[] atypes, Language language)
650   {
651     if (pproc instanceof GenericProc)
652       {
653     GenericProc gproc = (GenericProc) pproc;
654     MethodProc[] methods = gproc.methods;
655     pproc = null;
656     for (int i = gproc.count; --i >= 0; )
657       {
658         int applic = methods[i].isApplicable(atypes);
659         if (applic < 0)
660           continue;
661         if (pproc != null)
662           return null; // Ambiguous.
663
pproc = methods[i];
664       }
665     if (pproc == null)
666       return null;
667       }
668     if (pproc instanceof PrimProcedure)
669       {
670     PrimProcedure prproc = (PrimProcedure) pproc;
671     if (prproc.isApplicable(atypes) >= 0)
672       return prproc;
673       }
674     Class JavaDoc pclass = getProcedureClass(pproc);
675     if (pclass == null)
676       return null;
677     return getMethodFor((ClassType) Type.make(pclass), pproc.getName(),
678             decl, atypes, language);
679   }
680
681   public static Class JavaDoc getProcedureClass (Object JavaDoc pproc)
682   {
683     Class JavaDoc procClass;
684     if (pproc instanceof ModuleMethod)
685       procClass = ((ModuleMethod) pproc).module.getClass();
686     else
687       procClass = pproc.getClass();
688     try
689       {
690     if (procClass.getClassLoader() == systemClassLoader)
691       return procClass;
692       }
693     catch (SecurityException JavaDoc ex)
694       {
695       }
696     return null;
697   }
698
699   /** Get PrimProcedure for matching method in given class. */
700   public static PrimProcedure
701   getMethodFor (Class JavaDoc procClass, String JavaDoc name, Declaration decl,
702                 Expression[] args, Language language)
703   {
704     return getMethodFor((ClassType) Type.make(procClass),
705             name, decl, args, language);
706   }
707
708   public static PrimProcedure
709   getMethodFor (ClassType procClass, String JavaDoc name, Declaration decl,
710                 Expression[] args, Language language)
711   {
712     int nargs = args.length;
713     Type[] atypes = new Type[nargs];
714     for (int i = nargs; --i >= 0;) atypes[i] = args[i].getType();
715     return getMethodFor(procClass, name, decl, atypes, language);
716   }
717
718   public static PrimProcedure
719   getMethodFor (ClassType procClass, String JavaDoc name, Declaration decl,
720         Type[] atypes, Language language)
721   {
722     PrimProcedure best = null;
723     int bestCode = -1;
724     boolean bestIsApply = false;
725     try
726       {
727         if (name == null)
728           return null;
729         String JavaDoc mangledName = Compilation.mangleName(name);
730         String JavaDoc mangledNameV = mangledName + "$V";
731         String JavaDoc mangledNameVX = mangledName + "$V$X";
732         String JavaDoc mangledNameX = mangledName + "$X";
733     boolean applyOk = true; // Also look for "apply" and "apply$V".
734
for (Method meth = procClass.getDeclaredMethods();
735        meth != null; meth = meth.getNext())
736           {
737             int mods = meth.getModifiers();
738             if ((mods & (Access.STATIC|Access.PUBLIC))
739                 != (Access.STATIC|Access.PUBLIC))
740           {
741         if (decl == null || decl.base == null)
742           continue;
743           }
744             String JavaDoc mname = meth.getName();
745         boolean isApply;
746         if (mname.equals(mangledName)
747         || mname.equals(mangledNameV)
748         || mname.equals(mangledNameX)
749         || mname.equals(mangledNameVX))
750           {
751         isApply = false;
752           }
753         else if (applyOk
754              && (mname.equals("apply") || mname.equals("apply$V")))
755           {
756         isApply = true;
757           }
758             else
759               continue;
760         if (! isApply)
761           {
762         // If we saw a real match, ignore "apply".
763
applyOk = false;
764         if (bestIsApply)
765           {
766             best = null;
767             bestCode = -1;
768             bestIsApply = false;
769           }
770           }
771         PrimProcedure prproc = new PrimProcedure(meth, language);
772         prproc.setName(name);
773         int code = prproc.isApplicable(atypes);
774         if (code < 0 || code < bestCode)
775           continue;
776         if (code > bestCode)
777           {
778         best = prproc;
779           }
780         else if (best != null)
781           {
782         best = (PrimProcedure) MethodProc.mostSpecific(best, prproc);
783         if (best == null)
784           { // Ambiguous.
785
if (bestCode > 0)
786               return null;
787           }
788           }
789         bestCode = code;
790         bestIsApply = isApply;
791           }
792       }
793     catch (SecurityException JavaDoc ex)
794       {
795       }
796     return best;
797   }
798
799   public String JavaDoc getName()
800   {
801     String JavaDoc name = super.getName();
802     if (name != null)
803       return name;
804     name = getVerboseName();
805     setName(name);
806     return name;
807   }
808
809   public String JavaDoc getVerboseName()
810   {
811     StringBuffer JavaDoc buf = new StringBuffer JavaDoc(100);
812     if (method == null)
813       {
814     buf.append("<op ");
815     buf.append(op_code);
816     buf.append('>');
817       }
818     else
819       {
820     buf.append(method.getDeclaringClass().getName());
821     buf.append('.');
822     buf.append(method.getName());
823       }
824     buf.append('(');
825     for (int i = 0; i < argTypes.length; i++)
826       {
827     if (i > 0)
828       buf.append(',');
829     buf.append(argTypes[i].getName());
830       }
831     buf.append(')');
832     return buf.toString();
833   }
834
835
836   public String JavaDoc toString()
837   {
838     StringBuffer JavaDoc buf = new StringBuffer JavaDoc(100);
839     buf.append(retType.getName());
840     buf.append(' ');
841     buf.append(getVerboseName());
842     return buf.toString();
843   }
844
845   public void print(java.io.PrintWriter JavaDoc ps)
846   {
847     ps.print("#<primitive procedure ");
848     ps.print(toString());
849     ps.print ('>');
850   }
851 }
852
Popular Tags