KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > xsltc > compiler > FunctionCall


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: FunctionCall.java,v 1.38 2004/02/23 17:29:35 aruny Exp $
18  */

19
20 package org.apache.xalan.xsltc.compiler;
21
22 import java.lang.reflect.Constructor JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24 import java.lang.reflect.Modifier JavaDoc;
25 import java.util.Enumeration JavaDoc;
26 import java.util.Hashtable JavaDoc;
27 import java.util.Vector JavaDoc;
28
29 import org.apache.bcel.generic.ConstantPoolGen;
30 import org.apache.bcel.generic.IFEQ;
31 import org.apache.bcel.generic.INVOKEINTERFACE;
32 import org.apache.bcel.generic.INVOKESPECIAL;
33 import org.apache.bcel.generic.INVOKESTATIC;
34 import org.apache.bcel.generic.INVOKEVIRTUAL;
35 import org.apache.bcel.generic.InstructionConstants;
36 import org.apache.bcel.generic.InstructionList;
37 import org.apache.bcel.generic.InvokeInstruction;
38 import org.apache.bcel.generic.NEW;
39 import org.apache.bcel.generic.PUSH;
40 import org.apache.bcel.generic.LocalVariableGen;
41 import org.apache.bcel.generic.ASTORE;
42 import org.apache.bcel.generic.ANEWARRAY;
43 import org.apache.bcel.generic.ALOAD;
44 import org.apache.bcel.generic.ACONST_NULL;
45
46
47 import org.apache.xalan.xsltc.compiler.util.BooleanType;
48 import org.apache.xalan.xsltc.compiler.util.ClassGenerator;
49 import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
50 import org.apache.xalan.xsltc.compiler.util.IntType;
51 import org.apache.xalan.xsltc.compiler.util.MethodGenerator;
52 import org.apache.xalan.xsltc.compiler.util.MethodType;
53 import org.apache.xalan.xsltc.compiler.util.MultiHashtable;
54 import org.apache.xalan.xsltc.compiler.util.ObjectType;
55 import org.apache.xalan.xsltc.compiler.util.ReferenceType;
56 import org.apache.xalan.xsltc.compiler.util.Type;
57 import org.apache.xalan.xsltc.compiler.util.TypeCheckError;
58
59 /**
60  * @author Jacek Ambroziak
61  * @author Santiago Pericas-Geertsen
62  * @author Morten Jorgensen
63  * @author Erwin Bolwidt <ejb@klomp.org>
64  * @author Todd Miller
65  */

66 class FunctionCall extends Expression {
67
68     // Name of this function call
69
private QName _fname;
70     // Arguments to this function call (might not be any)
71
private final Vector JavaDoc _arguments;
72     // Empty argument list, used for certain functions
73
private final static Vector JavaDoc EMPTY_ARG_LIST = new Vector JavaDoc(0);
74
75     // Valid namespaces for Java function-call extension
76
protected final static String JavaDoc EXT_XSLTC =
77     TRANSLET_URI;
78
79     protected final static String JavaDoc JAVA_EXT_XSLTC =
80     EXT_XSLTC + "/java";
81
82     protected final static String JavaDoc EXT_XALAN =
83     "http://xml.apache.org/xalan";
84
85     protected final static String JavaDoc JAVA_EXT_XALAN =
86     "http://xml.apache.org/xalan/java";
87
88     protected final static String JavaDoc JAVA_EXT_XALAN_OLD =
89     "http://xml.apache.org/xslt/java";
90     
91     protected final static String JavaDoc EXSLT_COMMON =
92     "http://exslt.org/common";
93
94     protected final static String JavaDoc EXSLT_MATH =
95     "http://exslt.org/math";
96     
97     protected final static String JavaDoc EXSLT_SETS =
98     "http://exslt.org/sets";
99
100     protected final static String JavaDoc EXSLT_DATETIME =
101     "http://exslt.org/dates-and-times";
102
103     protected final static String JavaDoc EXSLT_STRINGS =
104     "http://exslt.org/strings";
105     
106     // Namespace format constants
107
protected final static int NAMESPACE_FORMAT_JAVA = 0;
108     protected final static int NAMESPACE_FORMAT_CLASS = 1;
109     protected final static int NAMESPACE_FORMAT_PACKAGE = 2;
110     protected final static int NAMESPACE_FORMAT_CLASS_OR_PACKAGE = 3;
111     
112     // Namespace format
113
private int _namespace_format = NAMESPACE_FORMAT_JAVA;
114         
115     /**
116      * Stores reference to object for non-static Java calls
117      */

118     Expression _thisArgument = null;
119
120     // External Java function's class/method/signature
121
private String JavaDoc _className;
122     private Class JavaDoc _clazz;
123     private Method JavaDoc _chosenMethod;
124     private Constructor JavaDoc _chosenConstructor;
125     private MethodType _chosenMethodType;
126
127     // Encapsulates all unsupported external function calls
128
private boolean unresolvedExternal;
129
130     // If FunctionCall is a external java constructor
131
private boolean _isExtConstructor = false;
132
133     // If the java method is static
134
private boolean _isStatic = false;
135
136     // If unable to resolve statically then resolve dynamically
137
private boolean resolveDynamic = false;
138     
139     // Legal conversions between internal and Java types.
140
private static final MultiHashtable _internal2Java = new MultiHashtable();
141
142     // Legal conversions between Java and internal types.
143
private static final Hashtable JavaDoc _java2Internal = new Hashtable JavaDoc();
144     
145     // The mappings between EXSLT extension namespaces and implementation classes
146
private static final Hashtable JavaDoc _extensionNamespaceTable = new Hashtable JavaDoc();
147
148     // Extension functions that are implemented in BasisLibrary
149
private static final Hashtable JavaDoc _extensionFunctionTable = new Hashtable JavaDoc();
150     /**
151      * inner class to used in internal2Java mappings, contains
152      * the Java type and the distance between the internal type and
153      * the Java type.
154      */

155     static class JavaType {
156     public Class JavaDoc type;
157     public int distance;
158     
159     public JavaType(Class JavaDoc type, int distance){
160         this.type = type;
161         this.distance = distance;
162     }
163     public boolean equals(Object JavaDoc query){
164         return query.equals(type);
165     }
166     }
167
168     /**
169      * Defines 2 conversion tables:
170      * 1. From internal types to Java types and
171      * 2. From Java types to internal types.
172      * These two tables are used when calling external (Java) functions.
173      */

174     static {
175     try {
176         final Class JavaDoc nodeClass = Class.forName("org.w3c.dom.Node");
177         final Class JavaDoc nodeListClass = Class.forName("org.w3c.dom.NodeList");
178
179         // -- Internal to Java --------------------------------------------
180

181             // Type.Boolean -> { boolean(0), Boolean(1), Object(2) }
182
_internal2Java.put(Type.Boolean, new JavaType(Boolean.TYPE, 0));
183         _internal2Java.put(Type.Boolean, new JavaType(Boolean JavaDoc.class, 1));
184         _internal2Java.put(Type.Boolean, new JavaType(Object JavaDoc.class, 2));
185
186             // Type.Real -> { double(0), Double(1), float(2), long(3), int(4),
187
// short(5), byte(6), char(7), Object(8) }
188
_internal2Java.put(Type.Real, new JavaType(Double.TYPE, 0));
189         _internal2Java.put(Type.Real, new JavaType(Double JavaDoc.class, 1));
190         _internal2Java.put(Type.Real, new JavaType(Float.TYPE, 2));
191         _internal2Java.put(Type.Real, new JavaType(Long.TYPE, 3));
192         _internal2Java.put(Type.Real, new JavaType(Integer.TYPE, 4));
193         _internal2Java.put(Type.Real, new JavaType(Short.TYPE, 5));
194         _internal2Java.put(Type.Real, new JavaType(Byte.TYPE, 6));
195         _internal2Java.put(Type.Real, new JavaType(Character.TYPE, 7));
196         _internal2Java.put(Type.Real, new JavaType(Object JavaDoc.class, 8));
197             
198             // Type.Int must be the same as Type.Real
199
_internal2Java.put(Type.Int, new JavaType(Double.TYPE, 0));
200         _internal2Java.put(Type.Int, new JavaType(Double JavaDoc.class, 1));
201         _internal2Java.put(Type.Int, new JavaType(Float.TYPE, 2));
202         _internal2Java.put(Type.Int, new JavaType(Long.TYPE, 3));
203         _internal2Java.put(Type.Int, new JavaType(Integer.TYPE, 4));
204         _internal2Java.put(Type.Int, new JavaType(Short.TYPE, 5));
205         _internal2Java.put(Type.Int, new JavaType(Byte.TYPE, 6));
206         _internal2Java.put(Type.Int, new JavaType(Character.TYPE, 7));
207         _internal2Java.put(Type.Int, new JavaType(Object JavaDoc.class, 8));
208             
209             // Type.String -> { String(0), Object(1) }
210
_internal2Java.put(Type.String, new JavaType(String JavaDoc.class, 0));
211         _internal2Java.put(Type.String, new JavaType(Object JavaDoc.class, 1));
212
213             // Type.NodeSet -> { NodeList(0), Node(1), Object(2), String(3) }
214
_internal2Java.put(Type.NodeSet, new JavaType(nodeListClass, 0));
215         _internal2Java.put(Type.NodeSet, new JavaType(nodeClass, 1));
216         _internal2Java.put(Type.NodeSet, new JavaType(Object JavaDoc.class, 2));
217         _internal2Java.put(Type.NodeSet, new JavaType(String JavaDoc.class, 3));
218
219             // Type.Node -> { Node(0), NodeList(1), Object(2), String(3) }
220
_internal2Java.put(Type.Node, new JavaType(nodeListClass, 0));
221         _internal2Java.put(Type.Node, new JavaType(nodeClass, 1));
222         _internal2Java.put(Type.Node, new JavaType(Object JavaDoc.class, 2));
223         _internal2Java.put(Type.Node, new JavaType(String JavaDoc.class, 3));
224
225             // Type.ResultTree -> { NodeList(0), Node(1), Object(2), String(3) }
226
_internal2Java.put(Type.ResultTree, new JavaType(nodeListClass, 0));
227         _internal2Java.put(Type.ResultTree, new JavaType(nodeClass, 1));
228         _internal2Java.put(Type.ResultTree, new JavaType(Object JavaDoc.class, 2));
229         _internal2Java.put(Type.ResultTree, new JavaType(String JavaDoc.class, 3));
230
231         _internal2Java.put(Type.Reference, new JavaType(Object JavaDoc.class, 0));
232
233         // Possible conversions between Java and internal types
234
_java2Internal.put(Boolean.TYPE, Type.Boolean);
235         _java2Internal.put(Void.TYPE, Type.Void);
236         _java2Internal.put(Character.TYPE, Type.Real);
237         _java2Internal.put(Byte.TYPE, Type.Real);
238         _java2Internal.put(Short.TYPE, Type.Real);
239         _java2Internal.put(Integer.TYPE, Type.Real);
240         _java2Internal.put(Long.TYPE, Type.Real);
241         _java2Internal.put(Float.TYPE, Type.Real);
242         _java2Internal.put(Double.TYPE, Type.Real);
243
244         _java2Internal.put(String JavaDoc.class, Type.String);
245
246         _java2Internal.put(Object JavaDoc.class, Type.Reference);
247
248         // Conversions from org.w3c.dom.Node/NodeList to internal NodeSet
249
_java2Internal.put(nodeListClass, Type.NodeSet);
250         _java2Internal.put(nodeClass, Type.NodeSet);
251         
252         // Initialize the extension namespace table
253
_extensionNamespaceTable.put(EXT_XALAN, "org.apache.xalan.lib.Extensions");
254         _extensionNamespaceTable.put(EXSLT_COMMON, "org.apache.xalan.lib.ExsltCommon");
255         _extensionNamespaceTable.put(EXSLT_MATH, "org.apache.xalan.lib.ExsltMath");
256         _extensionNamespaceTable.put(EXSLT_SETS, "org.apache.xalan.lib.ExsltSets");
257         _extensionNamespaceTable.put(EXSLT_DATETIME, "org.apache.xalan.lib.ExsltDatetime");
258         _extensionNamespaceTable.put(EXSLT_STRINGS, "org.apache.xalan.lib.ExsltStrings");
259         
260         // Initialize the extension function table
261
_extensionFunctionTable.put(EXSLT_COMMON + ":nodeSet", "nodeset");
262         _extensionFunctionTable.put(EXSLT_COMMON + ":objectType", "objectType");
263         _extensionFunctionTable.put(EXT_XALAN + ":nodeset", "nodeset");
264     }
265     catch (ClassNotFoundException JavaDoc e) {
266         System.err.println(e);
267     }
268     }
269         
270     public FunctionCall(QName fname, Vector JavaDoc arguments) {
271     _fname = fname;
272     _arguments = arguments;
273     _type = null;
274     }
275
276     public FunctionCall(QName fname) {
277     this(fname, EMPTY_ARG_LIST);
278     }
279
280     public String JavaDoc getName() {
281     return(_fname.toString());
282     }
283
284     public void setParser(Parser parser) {
285     super.setParser(parser);
286     if (_arguments != null) {
287         final int n = _arguments.size();
288         for (int i = 0; i < n; i++) {
289         final Expression exp = (Expression)_arguments.elementAt(i);
290         exp.setParser(parser);
291         exp.setParent(this);
292         }
293     }
294     }
295
296     public String JavaDoc getClassNameFromUri(String JavaDoc uri)
297     {
298         String JavaDoc className = (String JavaDoc)_extensionNamespaceTable.get(uri);
299     
300         if (className != null)
301             return className;
302         else {
303             if (uri.startsWith(JAVA_EXT_XSLTC)) {
304                 int length = JAVA_EXT_XSLTC.length() + 1;
305                 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
306             }
307             else if (uri.startsWith(JAVA_EXT_XALAN)) {
308                 int length = JAVA_EXT_XALAN.length() + 1;
309                 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
310             }
311             else if (uri.startsWith(JAVA_EXT_XALAN_OLD)) {
312                 int length = JAVA_EXT_XALAN_OLD.length() + 1;
313                 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
314             }
315             else {
316                 int index = uri.lastIndexOf('/');
317                 return (index > 0) ? uri.substring(index+1) : uri;
318             }
319         }
320     }
321
322     /**
323      * Type check a function call. Since different type conversions apply,
324      * type checking is different for standard and external (Java) functions.
325      */

326     public Type typeCheck(SymbolTable stable)
327     throws TypeCheckError
328     {
329         if (_type != null) return _type;
330
331     final String JavaDoc namespace = _fname.getNamespace();
332     String JavaDoc local = _fname.getLocalPart();
333
334     if (isExtension()) {
335         _fname = new QName(null, null, local);
336         return typeCheckStandard(stable);
337     }
338     else if (isStandard()) {
339         return typeCheckStandard(stable);
340     }
341     // Handle extension functions (they all have a namespace)
342
else {
343         try {
344             _className = getClassNameFromUri(namespace);
345           
346                 final int pos = local.lastIndexOf('.');
347         if (pos > 0) {
348             _isStatic = true;
349             if (_className != null && _className.length() > 0) {
350                 _namespace_format = NAMESPACE_FORMAT_PACKAGE;
351                 _className = _className + "." + local.substring(0, pos);
352             }
353             else {
354                 _namespace_format = NAMESPACE_FORMAT_JAVA;
355                 _className = local.substring(0, pos);
356             }
357               
358             _fname = new QName(namespace, null, local.substring(pos + 1));
359         }
360         else {
361             if (_className != null && _className.length() > 0) {
362                 try {
363                             _clazz = ObjectFactory.findProviderClass(
364                                 _className, ObjectFactory.findClassLoader(), true);
365                     _namespace_format = NAMESPACE_FORMAT_CLASS;
366                 }
367                 catch (ClassNotFoundException JavaDoc e) {
368                     _namespace_format = NAMESPACE_FORMAT_PACKAGE;
369                 }
370             }
371             else
372                     _namespace_format = NAMESPACE_FORMAT_JAVA;
373             
374             if (local.indexOf('-') > 0) {
375                 local = replaceDash(local);
376             }
377             
378             String JavaDoc extFunction = (String JavaDoc)_extensionFunctionTable.get(namespace + ":" + local);
379             if (extFunction != null) {
380                 _fname = new QName(null, null, extFunction);
381                 return typeCheckStandard(stable);
382             }
383             else
384                 _fname = new QName(namespace, null, local);
385         }
386           
387         return typeCheckExternal(stable);
388         }
389         catch (TypeCheckError e) {
390         ErrorMsg errorMsg = e.getErrorMsg();
391         if (errorMsg == null) {
392             final String JavaDoc name = _fname.getLocalPart();
393             errorMsg = new ErrorMsg(ErrorMsg.METHOD_NOT_FOUND_ERR, name);
394         }
395         getParser().reportError(ERROR, errorMsg);
396         return _type = Type.Void;
397         }
398       }
399     }
400
401     /**
402      * Type check a call to a standard function. Insert CastExprs when needed.
403      * If as a result of the insertion of a CastExpr a type check error is
404      * thrown, then catch it and re-throw it with a new "this".
405      */

406     public Type typeCheckStandard(SymbolTable stable) throws TypeCheckError {
407     _fname.clearNamespace(); // HACK!!!
408

409     final int n = _arguments.size();
410     final Vector JavaDoc argsType = typeCheckArgs(stable);
411     final MethodType args = new MethodType(Type.Void, argsType);
412     final MethodType ptype =
413         lookupPrimop(stable, _fname.getLocalPart(), args);
414
415     if (ptype != null) {
416         for (int i = 0; i < n; i++) {
417         final Type argType = (Type) ptype.argsType().elementAt(i);
418         final Expression exp = (Expression)_arguments.elementAt(i);
419         if (!argType.identicalTo(exp.getType())) {
420             try {
421             _arguments.setElementAt(new CastExpr(exp, argType), i);
422             }
423             catch (TypeCheckError e) {
424             throw new TypeCheckError(this); // invalid conversion
425
}
426         }
427         }
428         _chosenMethodType = ptype;
429         return _type = ptype.resultType();
430     }
431     throw new TypeCheckError(this);
432     }
433
434    
435
436     public Type typeCheckConstructor(SymbolTable stable) throws TypeCheckError{
437         final Vector JavaDoc constructors = findConstructors();
438     if (constructors == null) {
439             // Constructor not found in this class
440
throw new TypeCheckError(ErrorMsg.CONSTRUCTOR_NOT_FOUND,
441         _className);
442         
443     }
444
445     final int nConstructors = constructors.size();
446     final int nArgs = _arguments.size();
447     final Vector JavaDoc argsType = typeCheckArgs(stable);
448
449     // Try all constructors
450
int bestConstrDistance = Integer.MAX_VALUE;
451     _type = null; // reset
452
for (int j, i = 0; i < nConstructors; i++) {
453         // Check if all parameters to this constructor can be converted
454
final Constructor JavaDoc constructor =
455         (Constructor JavaDoc)constructors.elementAt(i);
456         final Class JavaDoc[] paramTypes = constructor.getParameterTypes();
457
458         Class JavaDoc extType = null;
459         int currConstrDistance = 0;
460         for (j = 0; j < nArgs; j++) {
461         // Convert from internal (translet) type to external (Java) type
462
extType = paramTypes[j];
463         final Type intType = (Type)argsType.elementAt(j);
464         Object JavaDoc match = _internal2Java.maps(intType, extType);
465         if (match != null) {
466             currConstrDistance += ((JavaType)match).distance;
467         }
468         else if (intType instanceof ObjectType) {
469             ObjectType objectType = (ObjectType)intType;
470             if (objectType.getJavaClass() == extType)
471                 continue;
472             else if (extType.isAssignableFrom(objectType.getJavaClass()))
473                 currConstrDistance += 1;
474             else {
475             currConstrDistance = Integer.MAX_VALUE;
476             break;
477             }
478         }
479         else {
480             // no mapping available
481
currConstrDistance = Integer.MAX_VALUE;
482             break;
483         }
484         }
485
486         if (j == nArgs && currConstrDistance < bestConstrDistance ) {
487             _chosenConstructor = constructor;
488             _isExtConstructor = true;
489         bestConstrDistance = currConstrDistance;
490         
491                 _type = (_clazz != null) ? Type.newObjectType(_clazz)
492                     : Type.newObjectType(_className);
493         }
494     }
495
496     if (_type != null) {
497            return _type;
498     }
499         else{
500           resolveDynamic = true;
501         }
502
503         return _type = (_clazz != null) ? Type.newObjectType(_clazz)
504                     : Type.newObjectType(_className);
505     }
506
507
508     /**
509      * Type check a call to an external (Java) method.
510      * The method must be static an public, and a legal type conversion
511      * must exist for all its arguments and its return type.
512      * Every method of name <code>_fname</code> is inspected
513      * as a possible candidate.
514      */

515     public Type typeCheckExternal(SymbolTable stable) throws TypeCheckError {
516     int nArgs = _arguments.size();
517     final String JavaDoc name = _fname.getLocalPart();
518     
519     // check if function is a contructor 'new'
520
if (_fname.getLocalPart().equals("new")) {
521         return typeCheckConstructor(stable);
522     }
523     // check if we are calling an instance method
524
else {
525         boolean hasThisArgument = false;
526       
527         if (nArgs == 0)
528             _isStatic = true;
529       
530         if (!_isStatic) {
531             if (_namespace_format == NAMESPACE_FORMAT_JAVA
532             || _namespace_format == NAMESPACE_FORMAT_PACKAGE)
533             hasThisArgument = true;
534           
535         Expression firstArg = (Expression)_arguments.elementAt(0);
536         Type firstArgType = (Type)firstArg.typeCheck(stable);
537         
538         if (_namespace_format == NAMESPACE_FORMAT_CLASS
539             && firstArgType instanceof ObjectType
540             && _clazz != null
541             && _clazz.isAssignableFrom(((ObjectType)firstArgType).getJavaClass()))
542             hasThisArgument = true;
543                 else if(firstArgType instanceof ReferenceType){
544                     resolveDynamic = true;
545                     typeCheckArgs(stable);
546                     return Type.String;
547                 }
548         
549         if (hasThisArgument) {
550             _thisArgument = (Expression) _arguments.elementAt(0);
551             _arguments.remove(0); nArgs--;
552             if (firstArgType instanceof ObjectType) {
553                 _className = ((ObjectType) firstArgType).getJavaClassName();
554             }
555             else
556                 throw new TypeCheckError(ErrorMsg.NO_JAVA_FUNCT_THIS_REF, name);
557         }
558         }
559         else if (_className.length() == 0) {
560         /*
561          * Warn user if external function could not be resolved.
562          * Warning will _NOT_ be issued is the call is properly
563          * wrapped in an <xsl:if> or <xsl:when> element. For details
564          * see If.parserContents() and When.parserContents()
565          */

566         final Parser parser = getParser();
567         if (parser != null) {
568             reportWarning(this, parser, ErrorMsg.FUNCTION_RESOLVE_ERR,
569                   _fname.toString());
570         }
571         unresolvedExternal = true;
572         return _type = Type.Int; // use "Int" as "unknown"
573
}
574     }
575     
576     final Vector JavaDoc methods = findMethods();
577     
578     if (methods == null) {
579         // Method not found in this class
580
throw new TypeCheckError(ErrorMsg.METHOD_NOT_FOUND_ERR, _className + "." + name);
581     }
582
583     Class JavaDoc extType = null;
584     final int nMethods = methods.size();
585     final Vector JavaDoc argsType = typeCheckArgs(stable);
586
587     // Try all methods to identify the best fit
588
int bestMethodDistance = Integer.MAX_VALUE;
589     _type = null; // reset internal type
590
for (int j, i = 0; i < nMethods; i++) {
591         // Check if all paramteters to this method can be converted
592
final Method JavaDoc method = (Method JavaDoc)methods.elementAt(i);
593         final Class JavaDoc[] paramTypes = method.getParameterTypes();
594         
595         int currMethodDistance = 0;
596         for (j = 0; j < nArgs; j++) {
597         // Convert from internal (translet) type to external (Java) type
598
extType = paramTypes[j];
599         final Type intType = (Type)argsType.elementAt(j);
600         Object JavaDoc match = _internal2Java.maps(intType, extType);
601         if (match != null) {
602             currMethodDistance += ((JavaType)match).distance;
603         }
604         else {
605             // no mapping available
606
//
607
// Allow a Reference type to match any external (Java) type at
608
// the moment. The real type checking is performed at runtime.
609
if (intType instanceof ReferenceType) {
610                currMethodDistance += 1;
611             }
612             else if (intType instanceof ObjectType) {
613                 ObjectType object = (ObjectType)intType;
614                 if (extType.getName().equals(object.getJavaClassName()))
615                     currMethodDistance += 0;
616                 else if (extType.isAssignableFrom(object.getJavaClass()))
617                     currMethodDistance += 1;
618                 else {
619                     currMethodDistance = Integer.MAX_VALUE;
620                     break;
621                 }
622             }
623             else {
624                 currMethodDistance = Integer.MAX_VALUE;
625                 break;
626             }
627         }
628         }
629
630         if (j == nArgs) {
631           // Check if the return type can be converted
632
extType = method.getReturnType();
633         
634           _type = (Type) _java2Internal.get(extType);
635           if (_type == null) {
636               _type = Type.newObjectType(extType);
637           }
638
639           // Use this method if all parameters & return type match
640
if (_type != null && currMethodDistance < bestMethodDistance) {
641               _chosenMethod = method;
642               bestMethodDistance = currMethodDistance;
643           }
644         }
645     }
646     
647     // It is an error if the chosen method is an instance menthod but we don't
648
// have a this argument.
649
if (_chosenMethod != null && _thisArgument == null &&
650         !Modifier.isStatic(_chosenMethod.getModifiers())) {
651         throw new TypeCheckError(ErrorMsg.NO_JAVA_FUNCT_THIS_REF, getMethodSignature(argsType));
652     }
653
654     if (_type != null) {
655         if (_type == Type.NodeSet) {
656                 getXSLTC().setMultiDocument(true);
657             }
658         return _type;
659     }
660
661     throw new TypeCheckError(ErrorMsg.ARGUMENT_CONVERSION_ERR, getMethodSignature(argsType));
662     }
663
664     /**
665      * Type check the actual arguments of this function call.
666      */

667     public Vector JavaDoc typeCheckArgs(SymbolTable stable) throws TypeCheckError {
668     final Vector JavaDoc result = new Vector JavaDoc();
669     final Enumeration JavaDoc e = _arguments.elements();
670     while (e.hasMoreElements()) {
671         final Expression exp = (Expression)e.nextElement();
672         result.addElement(exp.typeCheck(stable));
673     }
674     return result;
675     }
676
677     protected final Expression argument(int i) {
678     return (Expression)_arguments.elementAt(i);
679     }
680
681     protected final Expression argument() {
682     return argument(0);
683     }
684     
685     protected final int argumentCount() {
686     return _arguments.size();
687     }
688
689     protected final void setArgument(int i, Expression exp) {
690     _arguments.setElementAt(exp, i);
691     }
692
693     /**
694      * Compile the function call and treat as an expression
695      * Update true/false-lists.
696      */

697     public void translateDesynthesized(ClassGenerator classGen,
698                        MethodGenerator methodGen)
699     {
700     Type type = Type.Boolean;
701     if (_chosenMethodType != null)
702         type = _chosenMethodType.resultType();
703
704     final InstructionList il = methodGen.getInstructionList();
705     translate(classGen, methodGen);
706
707     if ((type instanceof BooleanType) || (type instanceof IntType)) {
708         _falseList.add(il.append(new IFEQ(null)));
709     }
710     }
711
712
713     /**
714      * Translate a function call. The compiled code will leave the function's
715      * return value on the JVM's stack.
716      */

717     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
718     final int n = argumentCount();
719     final ConstantPoolGen cpg = classGen.getConstantPool();
720     final InstructionList il = methodGen.getInstructionList();
721     int index;
722
723     // Translate calls to methods in the BasisLibrary
724
if (isStandard() || isExtension()) {
725         for (int i = 0; i < n; i++) {
726         final Expression exp = argument(i);
727         exp.translate(classGen, methodGen);
728         exp.startIterator(classGen, methodGen);
729         }
730
731         // append "F" to the function's name
732
final String JavaDoc name = _fname.toString().replace('-', '_') + "F";
733         String JavaDoc args = Constants.EMPTYSTRING;
734
735         // Special precautions for some method calls
736
if (name.equals("sumF")) {
737         args = DOM_INTF_SIG;
738         il.append(methodGen.loadDOM());
739         }
740         else if (name.equals("normalize_spaceF")) {
741         if (_chosenMethodType.toSignature(args).
742             equals("()Ljava/lang/String;")) {
743             args = "I"+DOM_INTF_SIG;
744             il.append(methodGen.loadContextNode());
745             il.append(methodGen.loadDOM());
746         }
747         }
748
749         // Invoke the method in the basis library
750
index = cpg.addMethodref(BASIS_LIBRARY_CLASS, name,
751                      _chosenMethodType.toSignature(args));
752         il.append(new INVOKESTATIC(index));
753     }
754     // Add call to BasisLibrary.unresolved_externalF() to generate
755
// run-time error message for unsupported external functions
756
else if (unresolvedExternal) {
757         index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
758                      "unresolved_externalF",
759                      "(Ljava/lang/String;)V");
760         il.append(new PUSH(cpg, _fname.toString()));
761         il.append(new INVOKESTATIC(index));
762     }
763     else if (_isExtConstructor) {
764         final String JavaDoc clazz =
765         _chosenConstructor.getDeclaringClass().getName();
766         Class JavaDoc[] paramTypes = _chosenConstructor.getParameterTypes();
767         
768         il.append(new NEW(cpg.addClass(_className)));
769         il.append(InstructionConstants.DUP);
770
771         for (int i = 0; i < n; i++) {
772         final Expression exp = argument(i);
773         exp.translate(classGen, methodGen);
774         // Convert the argument to its Java type
775
exp.startIterator(classGen, methodGen);
776         exp.getType().translateTo(classGen, methodGen, paramTypes[i]);
777         }
778
779         final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
780         buffer.append('(');
781         for (int i = 0; i < paramTypes.length; i++) {
782         buffer.append(getSignature(paramTypes[i]));
783         }
784         buffer.append(')');
785         buffer.append("V");
786
787         index = cpg.addMethodref(clazz,
788                      "<init>",
789                      buffer.toString());
790         il.append(new INVOKESPECIAL(index));
791
792         // Convert the return type back to our internal type
793
(Type.Object).translateFrom(classGen, methodGen,
794                 _chosenConstructor.getDeclaringClass());
795         
796     }
797     else if(resolveDynamic) {
798
799           final LocalVariableGen _local = methodGen.addLocalVariable2("objects",
800               org.apache.bcel.generic.Type.OBJECT, il.getEnd());
801
802           //Create the Object[].
803
il.append(new PUSH(cpg, n + 1));
804           il.append(new ANEWARRAY(cpg.addClass(OBJECT_CLASS)));
805
806           // Push "this" if it is an instance method
807
il.append(DUP);
808           if (_thisArgument != null) {
809             il.append(new PUSH(cpg, 0));
810             _thisArgument.translate(classGen, methodGen);
811           }
812           //else add null to the Object array
813
else {
814             il.append(new PUSH(cpg, 0));
815             il.append(ACONST_NULL);
816           }
817           il.append(AASTORE);
818
819           //Add the parameters to Object[]
820
for (int i = 0; i < n; i++) {
821             il.append(DUP);
822             il.append(new PUSH(cpg, i + 1));
823             Expression exp = argument(i);
824             exp.translate(classGen, methodGen);
825             exp.startIterator(classGen, methodGen);
826             exp.getType().translateTo(classGen, methodGen, Type.Reference);
827             il.append(AASTORE);
828           }
829           il.append(new ASTORE(_local.getIndex()));
830
831           //call invoke parameter
832
String JavaDoc methodName = null;
833           if (_chosenMethod != null)
834             methodName = _chosenMethod.getName();
835           else
836             methodName = _fname.getLocalPart();
837
838           il.append(new PUSH(cpg, _className));
839           il.append(new PUSH(cpg, methodName));
840           il.append(new ALOAD(_local.getIndex()));
841
842           index = cpg.addMethodref(CALL_FUNCTION_CLASS, INVOKE_METHOD,
843               "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;");
844           il.append(new INVOKESTATIC(index));
845
846         }
847     // Invoke function calls that are handled in separate classes
848
else {
849         final String JavaDoc clazz = _chosenMethod.getDeclaringClass().getName();
850         Class JavaDoc[] paramTypes = _chosenMethod.getParameterTypes();
851
852         // Push "this" if it is an instance method
853
if (_thisArgument != null) {
854         _thisArgument.translate(classGen, methodGen);
855         }
856
857         for (int i = 0; i < n; i++) {
858         final Expression exp = argument(i);
859         exp.translate(classGen, methodGen);
860         // Convert the argument to its Java type
861
exp.startIterator(classGen, methodGen);
862         exp.getType().translateTo(classGen, methodGen, paramTypes[i]);
863         }
864
865         final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
866         buffer.append('(');
867         for (int i = 0; i < paramTypes.length; i++) {
868         buffer.append(getSignature(paramTypes[i]));
869         }
870         buffer.append(')');
871         buffer.append(getSignature(_chosenMethod.getReturnType()));
872
873         if (_thisArgument != null && _clazz.isInterface()) {
874             index = cpg.addInterfaceMethodref(clazz,
875                      _fname.getLocalPart(),
876                      buffer.toString());
877         il.append(new INVOKEINTERFACE(index, n+1));
878             }
879             else {
880             index = cpg.addMethodref(clazz,
881                      _fname.getLocalPart(),
882                      buffer.toString());
883             il.append(_thisArgument != null ? (InvokeInstruction) new INVOKEVIRTUAL(index) :
884                   (InvokeInstruction) new INVOKESTATIC(index));
885             }
886  
887         // Convert the return type back to our internal type
888
_type.translateFrom(classGen, methodGen,
889                 _chosenMethod.getReturnType());
890     }
891     }
892
893     public String JavaDoc toString() {
894     return "funcall(" + _fname + ", " + _arguments + ')';
895     }
896
897     public boolean isStandard() {
898     final String JavaDoc namespace = _fname.getNamespace();
899     return (namespace == null) || (namespace.equals(Constants.EMPTYSTRING));
900     }
901
902     public boolean isExtension() {
903     final String JavaDoc namespace = _fname.getNamespace();
904     return (namespace != null) && (namespace.equals(EXT_XSLTC));
905     }
906
907     /**
908      * Returns a vector with all methods named <code>_fname</code>
909      * after stripping its namespace or <code>null</code>
910      * if no such methods exist.
911      */

912     private Vector JavaDoc findMethods() {
913       
914       Vector JavaDoc result = null;
915       final String JavaDoc namespace = _fname.getNamespace();
916
917       if (_className != null && _className.length() > 0) {
918         final int nArgs = _arguments.size();
919         try {
920           if (_clazz == null) {
921                 _clazz = ObjectFactory.findProviderClass(
922                   _className, ObjectFactory.findClassLoader(), true);
923
924         if (_clazz == null) {
925           final ErrorMsg msg =
926                 new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
927           getParser().reportError(Constants.ERROR, msg);
928         }
929           }
930
931           final String JavaDoc methodName = _fname.getLocalPart();
932           final Method JavaDoc[] methods = _clazz.getMethods();
933
934           for (int i = 0; i < methods.length; i++) {
935         final int mods = methods[i].getModifiers();
936         // Is it public and same number of args ?
937
if (Modifier.isPublic(mods)
938             && methods[i].getName().equals(methodName)
939             && methods[i].getParameterTypes().length == nArgs)
940         {
941           if (result == null) {
942             result = new Vector JavaDoc();
943               }
944           result.addElement(methods[i]);
945         }
946           }
947         }
948         catch (ClassNotFoundException JavaDoc e) {
949           final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
950           getParser().reportError(Constants.ERROR, msg);
951         }
952       }
953       return result;
954     }
955
956     /**
957      * Returns a vector with all constructors named <code>_fname</code>
958      * after stripping its namespace or <code>null</code>
959      * if no such methods exist.
960      */

961     private Vector JavaDoc findConstructors() {
962         Vector JavaDoc result = null;
963         final String JavaDoc namespace = _fname.getNamespace();
964
965         final int nArgs = _arguments.size();
966         try {
967           if (_clazz == null) {
968             _clazz = ObjectFactory.findProviderClass(
969               _className, ObjectFactory.findClassLoader(), true);
970
971             if (_clazz == null) {
972               final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
973               getParser().reportError(Constants.ERROR, msg);
974             }
975           }
976
977           final Constructor JavaDoc[] constructors = _clazz.getConstructors();
978
979           for (int i = 0; i < constructors.length; i++) {
980               final int mods = constructors[i].getModifiers();
981               // Is it public, static and same number of args ?
982
if (Modifier.isPublic(mods) &&
983                   constructors[i].getParameterTypes().length == nArgs)
984               {
985                 if (result == null) {
986                   result = new Vector JavaDoc();
987                 }
988                 result.addElement(constructors[i]);
989               }
990           }
991         }
992         catch (ClassNotFoundException JavaDoc e) {
993           final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
994           getParser().reportError(Constants.ERROR, msg);
995         }
996             
997         return result;
998     }
999
1000
1001    /**
1002     * Compute the JVM signature for the class.
1003     */

1004    static final String JavaDoc getSignature(Class JavaDoc clazz) {
1005    if (clazz.isArray()) {
1006        final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1007        Class JavaDoc cl = clazz;
1008        while (cl.isArray()) {
1009        sb.append("[");
1010        cl = cl.getComponentType();
1011        }
1012        sb.append(getSignature(cl));
1013        return sb.toString();
1014    }
1015    else if (clazz.isPrimitive()) {
1016        if (clazz == Integer.TYPE) {
1017        return "I";
1018        }
1019        else if (clazz == Byte.TYPE) {
1020        return "B";
1021        }
1022        else if (clazz == Long.TYPE) {
1023        return "J";
1024        }
1025        else if (clazz == Float.TYPE) {
1026        return "F";
1027        }
1028        else if (clazz == Double.TYPE) {
1029        return "D";
1030        }
1031        else if (clazz == Short.TYPE) {
1032        return "S";
1033        }
1034        else if (clazz == Character.TYPE) {
1035        return "C";
1036        }
1037        else if (clazz == Boolean.TYPE) {
1038        return "Z";
1039        }
1040        else if (clazz == Void.TYPE) {
1041        return "V";
1042        }
1043        else {
1044        final String JavaDoc name = clazz.toString();
1045        ErrorMsg err = new ErrorMsg(ErrorMsg.UNKNOWN_SIG_TYPE_ERR,name);
1046        throw new Error JavaDoc(err.toString());
1047        }
1048    }
1049    else {
1050        return "L" + clazz.getName().replace('.', '/') + ';';
1051    }
1052    }
1053
1054    /**
1055     * Compute the JVM method descriptor for the method.
1056     */

1057    static final String JavaDoc getSignature(Method JavaDoc meth) {
1058    final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1059    sb.append('(');
1060    final Class JavaDoc[] params = meth.getParameterTypes(); // avoid clone
1061
for (int j = 0; j < params.length; j++) {
1062        sb.append(getSignature(params[j]));
1063    }
1064    return sb.append(')').append(getSignature(meth.getReturnType()))
1065        .toString();
1066    }
1067
1068    /**
1069     * Compute the JVM constructor descriptor for the constructor.
1070     */

1071    static final String JavaDoc getSignature(Constructor JavaDoc cons) {
1072    final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1073    sb.append('(');
1074    final Class JavaDoc[] params = cons.getParameterTypes(); // avoid clone
1075
for (int j = 0; j < params.length; j++) {
1076        sb.append(getSignature(params[j]));
1077    }
1078    return sb.append(")V").toString();
1079    }
1080    
1081    /**
1082     * Return the signature of the current method
1083     */

1084    private String JavaDoc getMethodSignature(Vector JavaDoc argsType) {
1085    final StringBuffer JavaDoc buf = new StringBuffer JavaDoc(_className);
1086        buf.append('.').append(_fname.getLocalPart()).append('(');
1087      
1088    int nArgs = argsType.size();
1089    for (int i = 0; i < nArgs; i++) {
1090        final Type intType = (Type)argsType.elementAt(i);
1091        buf.append(intType.toString());
1092        if (i < nArgs - 1) buf.append(", ");
1093    }
1094      
1095    buf.append(')');
1096    return buf.toString();
1097    }
1098
1099    /**
1100     * To support EXSLT extensions, convert names with dash to allowable Java names:
1101     * e.g., convert abc-xyz to abcXyz.
1102     * Note: dashes only appear in middle of an EXSLT function or element name.
1103     */

1104    protected static String JavaDoc replaceDash(String JavaDoc name)
1105    {
1106        char dash = '-';
1107        StringBuffer JavaDoc buff = new StringBuffer JavaDoc("");
1108        for (int i = 0; i < name.length(); i++) {
1109        if (i > 0 && name.charAt(i-1) == dash)
1110            buff.append(Character.toUpperCase(name.charAt(i)));
1111        else if (name.charAt(i) != dash)
1112            buff.append(name.charAt(i));
1113        }
1114        return buff.toString();
1115    }
1116     
1117}
1118
Popular Tags