KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xalan > internal > 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.1.2.1 2006/09/19 01:06:17 jeffsuttor Exp $
18  */

19
20 package com.sun.org.apache.xalan.internal.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 com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
30 import com.sun.org.apache.bcel.internal.generic.IFEQ;
31 import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE;
32 import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL;
33 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
34 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
35 import com.sun.org.apache.bcel.internal.generic.InstructionConstants;
36 import com.sun.org.apache.bcel.internal.generic.InstructionList;
37 import com.sun.org.apache.bcel.internal.generic.InvokeInstruction;
38 import com.sun.org.apache.bcel.internal.generic.NEW;
39 import com.sun.org.apache.bcel.internal.generic.PUSH;
40 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
41 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
42 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
43 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
44 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
45 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
46 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MultiHashtable;
47 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ObjectType;
48 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
49 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
50 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
51
52 /**
53  * @author Jacek Ambroziak
54  * @author Santiago Pericas-Geertsen
55  * @author Morten Jorgensen
56  * @author Erwin Bolwidt <ejb@klomp.org>
57  * @author Todd Miller
58  */

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

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

145     static class JavaType {
146     public Class JavaDoc type;
147     public int distance;
148     
149     public JavaType(Class JavaDoc type, int distance){
150         this.type = type;
151         this.distance = distance;
152     }
153     public boolean equals(Object JavaDoc query){
154         return query.equals(type);
155     }
156     }
157
158     /**
159      * Defines 2 conversion tables:
160      * 1. From internal types to Java types and
161      * 2. From Java types to internal types.
162      * These two tables are used when calling external (Java) functions.
163      */

164     static {
165     try {
166         final Class JavaDoc nodeClass = Class.forName("org.w3c.dom.Node");
167         final Class JavaDoc nodeListClass = Class.forName("org.w3c.dom.NodeList");
168
169         // -- Internal to Java --------------------------------------------
170

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

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

396     public Type typeCheckStandard(SymbolTable stable) throws TypeCheckError {
397     _fname.clearNamespace(); // HACK!!!
398

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

501     public Type typeCheckExternal(SymbolTable stable) throws TypeCheckError {
502     int nArgs = _arguments.size();
503     final String JavaDoc name = _fname.getLocalPart();
504     
505     // check if function is a contructor 'new'
506
if (_fname.getLocalPart().equals("new")) {
507         return typeCheckConstructor(stable);
508     }
509     // check if we are calling an instance method
510
else {
511         boolean hasThisArgument = false;
512       
513         if (nArgs == 0)
514             _isStatic = true;
515       
516         if (!_isStatic) {
517             if (_namespace_format == NAMESPACE_FORMAT_JAVA
518             || _namespace_format == NAMESPACE_FORMAT_PACKAGE)
519             hasThisArgument = true;
520           
521         Expression firstArg = (Expression)_arguments.elementAt(0);
522         Type firstArgType = (Type)firstArg.typeCheck(stable);
523         
524         if (_namespace_format == NAMESPACE_FORMAT_CLASS
525             && firstArgType instanceof ObjectType
526             && _clazz != null
527             && _clazz.isAssignableFrom(((ObjectType)firstArgType).getJavaClass()))
528             hasThisArgument = true;
529         
530         if (hasThisArgument) {
531             _thisArgument = (Expression) _arguments.elementAt(0);
532             _arguments.remove(0); nArgs--;
533             if (firstArgType instanceof ObjectType) {
534                 _className = ((ObjectType) firstArgType).getJavaClassName();
535             }
536             else
537                 throw new TypeCheckError(ErrorMsg.NO_JAVA_FUNCT_THIS_REF, name);
538         }
539         }
540         else if (_className.length() == 0) {
541         /*
542          * Warn user if external function could not be resolved.
543          * Warning will _NOT_ be issued is the call is properly
544          * wrapped in an <xsl:if> or <xsl:when> element. For details
545          * see If.parserContents() and When.parserContents()
546          */

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

648     public Vector JavaDoc typeCheckArgs(SymbolTable stable) throws TypeCheckError {
649     final Vector JavaDoc result = new Vector JavaDoc();
650     final Enumeration JavaDoc e = _arguments.elements();
651     while (e.hasMoreElements()) {
652         final Expression exp = (Expression)e.nextElement();
653         result.addElement(exp.typeCheck(stable));
654     }
655     return result;
656     }
657
658     protected final Expression argument(int i) {
659     return (Expression)_arguments.elementAt(i);
660     }
661
662     protected final Expression argument() {
663     return argument(0);
664     }
665     
666     protected final int argumentCount() {
667     return _arguments.size();
668     }
669
670     protected final void setArgument(int i, Expression exp) {
671     _arguments.setElementAt(exp, i);
672     }
673
674     /**
675      * Compile the function call and treat as an expression
676      * Update true/false-lists.
677      */

678     public void translateDesynthesized(ClassGenerator classGen,
679                        MethodGenerator methodGen)
680     {
681     Type type = Type.Boolean;
682     if (_chosenMethodType != null)
683         type = _chosenMethodType.resultType();
684
685     final InstructionList il = methodGen.getInstructionList();
686     translate(classGen, methodGen);
687
688     if ((type instanceof BooleanType) || (type instanceof IntType)) {
689         _falseList.add(il.append(new IFEQ(null)));
690     }
691     }
692
693
694     /**
695      * Translate a function call. The compiled code will leave the function's
696      * return value on the JVM's stack.
697      */

698     public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
699     final int n = argumentCount();
700     final ConstantPoolGen cpg = classGen.getConstantPool();
701     final InstructionList il = methodGen.getInstructionList();
702     final boolean isSecureProcessing = classGen.getParser().getXSLTC().isSecureProcessing();
703     int index;
704
705     // Translate calls to methods in the BasisLibrary
706
if (isStandard() || isExtension()) {
707         for (int i = 0; i < n; i++) {
708         final Expression exp = argument(i);
709         exp.translate(classGen, methodGen);
710         exp.startIterator(classGen, methodGen);
711         }
712
713         // append "F" to the function's name
714
final String JavaDoc name = _fname.toString().replace('-', '_') + "F";
715         String JavaDoc args = Constants.EMPTYSTRING;
716
717         // Special precautions for some method calls
718
if (name.equals("sumF")) {
719         args = DOM_INTF_SIG;
720         il.append(methodGen.loadDOM());
721         }
722         else if (name.equals("normalize_spaceF")) {
723         if (_chosenMethodType.toSignature(args).
724             equals("()Ljava/lang/String;")) {
725             args = "I"+DOM_INTF_SIG;
726             il.append(methodGen.loadContextNode());
727             il.append(methodGen.loadDOM());
728         }
729         }
730
731         // Invoke the method in the basis library
732
index = cpg.addMethodref(BASIS_LIBRARY_CLASS, name,
733                      _chosenMethodType.toSignature(args));
734         il.append(new INVOKESTATIC(index));
735     }
736     // Add call to BasisLibrary.unresolved_externalF() to generate
737
// run-time error message for unsupported external functions
738
else if (unresolvedExternal) {
739         index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
740                      "unresolved_externalF",
741                      "(Ljava/lang/String;)V");
742         il.append(new PUSH(cpg, _fname.toString()));
743         il.append(new INVOKESTATIC(index));
744     }
745     else if (_isExtConstructor) {
746             if (isSecureProcessing)
747             translateUnallowedExtension(cpg, il);
748                 
749         final String JavaDoc clazz =
750         _chosenConstructor.getDeclaringClass().getName();
751         Class JavaDoc[] paramTypes = _chosenConstructor.getParameterTypes();
752         
753         il.append(new NEW(cpg.addClass(_className)));
754         il.append(InstructionConstants.DUP);
755
756         for (int i = 0; i < n; i++) {
757         final Expression exp = argument(i);
758         exp.translate(classGen, methodGen);
759         // Convert the argument to its Java type
760
exp.startIterator(classGen, methodGen);
761         exp.getType().translateTo(classGen, methodGen, paramTypes[i]);
762         }
763
764         final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
765         buffer.append('(');
766         for (int i = 0; i < paramTypes.length; i++) {
767         buffer.append(getSignature(paramTypes[i]));
768         }
769         buffer.append(')');
770         buffer.append("V");
771
772         index = cpg.addMethodref(clazz,
773                      "<init>",
774                      buffer.toString());
775         il.append(new INVOKESPECIAL(index));
776
777         // Convert the return type back to our internal type
778
(Type.Object).translateFrom(classGen, methodGen,
779                 _chosenConstructor.getDeclaringClass());
780         
781     }
782     // Invoke function calls that are handled in separate classes
783
else {
784             if (isSecureProcessing)
785             translateUnallowedExtension(cpg, il);
786
787         final String JavaDoc clazz = _chosenMethod.getDeclaringClass().getName();
788         Class JavaDoc[] paramTypes = _chosenMethod.getParameterTypes();
789
790         // Push "this" if it is an instance method
791
if (_thisArgument != null) {
792         _thisArgument.translate(classGen, methodGen);
793         }
794
795         for (int i = 0; i < n; i++) {
796         final Expression exp = argument(i);
797         exp.translate(classGen, methodGen);
798         // Convert the argument to its Java type
799
exp.startIterator(classGen, methodGen);
800         exp.getType().translateTo(classGen, methodGen, paramTypes[i]);
801         }
802
803         final StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
804         buffer.append('(');
805         for (int i = 0; i < paramTypes.length; i++) {
806         buffer.append(getSignature(paramTypes[i]));
807         }
808         buffer.append(')');
809         buffer.append(getSignature(_chosenMethod.getReturnType()));
810
811         if (_thisArgument != null && _clazz.isInterface()) {
812             index = cpg.addInterfaceMethodref(clazz,
813                      _fname.getLocalPart(),
814                      buffer.toString());
815         il.append(new INVOKEINTERFACE(index, n+1));
816             }
817             else {
818             index = cpg.addMethodref(clazz,
819                      _fname.getLocalPart(),
820                      buffer.toString());
821             il.append(_thisArgument != null ? (InvokeInstruction) new INVOKEVIRTUAL(index) :
822                   (InvokeInstruction) new INVOKESTATIC(index));
823             }
824  
825         // Convert the return type back to our internal type
826
_type.translateFrom(classGen, methodGen,
827                 _chosenMethod.getReturnType());
828     }
829     }
830
831     public String JavaDoc toString() {
832     return "funcall(" + _fname + ", " + _arguments + ')';
833     }
834
835     public boolean isStandard() {
836     final String JavaDoc namespace = _fname.getNamespace();
837     return (namespace == null) || (namespace.equals(Constants.EMPTYSTRING));
838     }
839
840     public boolean isExtension() {
841     final String JavaDoc namespace = _fname.getNamespace();
842     return (namespace != null) && (namespace.equals(EXT_XSLTC));
843     }
844
845     /**
846      * Returns a vector with all methods named <code>_fname</code>
847      * after stripping its namespace or <code>null</code>
848      * if no such methods exist.
849      */

850     private Vector JavaDoc findMethods() {
851       
852       Vector JavaDoc result = null;
853       final String JavaDoc namespace = _fname.getNamespace();
854
855       if (_className != null && _className.length() > 0) {
856         final int nArgs = _arguments.size();
857         try {
858           if (_clazz == null) {
859                 _clazz = ObjectFactory.findProviderClass(
860                   _className, ObjectFactory.findClassLoader(), true);
861
862         if (_clazz == null) {
863           final ErrorMsg msg =
864                 new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
865           getParser().reportError(Constants.ERROR, msg);
866         }
867           }
868
869           final String JavaDoc methodName = _fname.getLocalPart();
870           final Method JavaDoc[] methods = _clazz.getMethods();
871
872           for (int i = 0; i < methods.length; i++) {
873         final int mods = methods[i].getModifiers();
874         // Is it public and same number of args ?
875
if (Modifier.isPublic(mods)
876             && methods[i].getName().equals(methodName)
877             && methods[i].getParameterTypes().length == nArgs)
878         {
879           if (result == null) {
880             result = new Vector JavaDoc();
881               }
882           result.addElement(methods[i]);
883         }
884           }
885         }
886         catch (ClassNotFoundException JavaDoc e) {
887           final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
888           getParser().reportError(Constants.ERROR, msg);
889         }
890       }
891       return result;
892     }
893
894     /**
895      * Returns a vector with all constructors named <code>_fname</code>
896      * after stripping its namespace or <code>null</code>
897      * if no such methods exist.
898      */

899     private Vector JavaDoc findConstructors() {
900         Vector JavaDoc result = null;
901         final String JavaDoc namespace = _fname.getNamespace();
902
903         final int nArgs = _arguments.size();
904         try {
905           if (_clazz == null) {
906             _clazz = ObjectFactory.findProviderClass(
907               _className, ObjectFactory.findClassLoader(), true);
908
909             if (_clazz == null) {
910               final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
911               getParser().reportError(Constants.ERROR, msg);
912             }
913           }
914
915           final Constructor JavaDoc[] constructors = _clazz.getConstructors();
916
917           for (int i = 0; i < constructors.length; i++) {
918               final int mods = constructors[i].getModifiers();
919               // Is it public, static and same number of args ?
920
if (Modifier.isPublic(mods) &&
921                   constructors[i].getParameterTypes().length == nArgs)
922               {
923                 if (result == null) {
924                   result = new Vector JavaDoc();
925                 }
926                 result.addElement(constructors[i]);
927               }
928           }
929         }
930         catch (ClassNotFoundException JavaDoc e) {
931           final ErrorMsg msg = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
932           getParser().reportError(Constants.ERROR, msg);
933         }
934             
935         return result;
936     }
937
938
939     /**
940      * Compute the JVM signature for the class.
941      */

942     static final String JavaDoc getSignature(Class JavaDoc clazz) {
943     if (clazz.isArray()) {
944         final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
945         Class JavaDoc cl = clazz;
946         while (cl.isArray()) {
947         sb.append("[");
948         cl = cl.getComponentType();
949         }
950         sb.append(getSignature(cl));
951         return sb.toString();
952     }
953     else if (clazz.isPrimitive()) {
954         if (clazz == Integer.TYPE) {
955         return "I";
956         }
957         else if (clazz == Byte.TYPE) {
958         return "B";
959         }
960         else if (clazz == Long.TYPE) {
961         return "J";
962         }
963         else if (clazz == Float.TYPE) {
964         return "F";
965         }
966         else if (clazz == Double.TYPE) {
967         return "D";
968         }
969         else if (clazz == Short.TYPE) {
970         return "S";
971         }
972         else if (clazz == Character.TYPE) {
973         return "C";
974         }
975         else if (clazz == Boolean.TYPE) {
976         return "Z";
977         }
978         else if (clazz == Void.TYPE) {
979         return "V";
980         }
981         else {
982         final String JavaDoc name = clazz.toString();
983         ErrorMsg err = new ErrorMsg(ErrorMsg.UNKNOWN_SIG_TYPE_ERR,name);
984         throw new Error JavaDoc(err.toString());
985         }
986     }
987     else {
988         return "L" + clazz.getName().replace('.', '/') + ';';
989     }
990     }
991
992     /**
993      * Compute the JVM method descriptor for the method.
994      */

995     static final String JavaDoc getSignature(Method JavaDoc meth) {
996     final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
997     sb.append('(');
998     final Class JavaDoc[] params = meth.getParameterTypes(); // avoid clone
999
for (int j = 0; j < params.length; j++) {
1000        sb.append(getSignature(params[j]));
1001    }
1002    return sb.append(')').append(getSignature(meth.getReturnType()))
1003        .toString();
1004    }
1005
1006    /**
1007     * Compute the JVM constructor descriptor for the constructor.
1008     */

1009    static final String JavaDoc getSignature(Constructor JavaDoc cons) {
1010    final StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1011    sb.append('(');
1012    final Class JavaDoc[] params = cons.getParameterTypes(); // avoid clone
1013
for (int j = 0; j < params.length; j++) {
1014        sb.append(getSignature(params[j]));
1015    }
1016    return sb.append(")V").toString();
1017    }
1018    
1019    /**
1020     * Return the signature of the current method
1021     */

1022    private String JavaDoc getMethodSignature(Vector JavaDoc argsType) {
1023    final StringBuffer JavaDoc buf = new StringBuffer JavaDoc(_className);
1024        buf.append('.').append(_fname.getLocalPart()).append('(');
1025      
1026    int nArgs = argsType.size();
1027    for (int i = 0; i < nArgs; i++) {
1028        final Type intType = (Type)argsType.elementAt(i);
1029        buf.append(intType.toString());
1030        if (i < nArgs - 1) buf.append(", ");
1031    }
1032      
1033    buf.append(')');
1034    return buf.toString();
1035    }
1036
1037    /**
1038     * To support EXSLT extensions, convert names with dash to allowable Java names:
1039     * e.g., convert abc-xyz to abcXyz.
1040     * Note: dashes only appear in middle of an EXSLT function or element name.
1041     */

1042    protected static String JavaDoc replaceDash(String JavaDoc name)
1043    {
1044        char dash = '-';
1045        StringBuffer JavaDoc buff = new StringBuffer JavaDoc("");
1046        for (int i = 0; i < name.length(); i++) {
1047        if (i > 0 && name.charAt(i-1) == dash)
1048            buff.append(Character.toUpperCase(name.charAt(i)));
1049        else if (name.charAt(i) != dash)
1050            buff.append(name.charAt(i));
1051        }
1052        return buff.toString();
1053    }
1054     
1055    /**
1056     * Translate code to call the BasisLibrary.unallowed_extensionF(String)
1057     * method.
1058     */

1059    private void translateUnallowedExtension(ConstantPoolGen cpg,
1060                                             InstructionList il) {
1061    int index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
1062                     "unallowed_extension_functionF",
1063                     "(Ljava/lang/String;)V");
1064    il.append(new PUSH(cpg, _fname.toString()));
1065    il.append(new INVOKESTATIC(index));
1066    }
1067}
1068
Popular Tags