37 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
38 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
39 import com.sun.org.apache.bcel.internal.generic.InstructionConstants;
40 import com.sun.org.apache.bcel.internal.generic.InstructionList;
41 import com.sun.org.apache.bcel.internal.generic.InvokeInstruction;
42 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
43 import com.sun.org.apache.bcel.internal.generic.NEW;
44 import com.sun.org.apache.bcel.internal.generic.PUSH;
45 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
46 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
47 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
48 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
49 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
50 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
51 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MultiHashtable;
52 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ObjectType;
53 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
54 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
55 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
56 import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
57
58 /**
59 * @author Jacek Ambroziak
60 * @author Santiago Pericas-Geertsen
61 * @author Morten Jorgensen
62 * @author Erwin Bolwidt <ejb@klomp.org>
63 * @author Todd Miller
64 */
65 class FunctionCall extends Expression {
66
67 // Name of this function call
68 private QName _fname;
69 // Arguments to this function call (might not be any)
70 private final Vector _arguments;
71 // Empty argument list, used for certain functions
72 private final static Vector EMPTY_ARG_LIST = new Vector(0);
73
74 // Valid namespaces for Java function-call extension
75 protected final static String EXT_XSLTC =
76 TRANSLET_URI;
139 private static final Hashtable _java2Internal = new Hashtable();
140
141 // The mappings between EXSLT extension namespaces and implementation classes
142 private static final Hashtable _extensionNamespaceTable = new Hashtable();
143
144 // Extension functions that are implemented in BasisLibrary
145 private static final Hashtable _extensionFunctionTable = new Hashtable();
146 /**
147 * inner class to used in internal2Java mappings, contains
148 * the Java type and the distance between the internal type and
149 * the Java type.
150 */
151 static class JavaType {
152 public Class type;
153 public int distance;
154
155 public JavaType(Class type, int distance){
156 this.type = type;
157 this.distance = distance;
158 }
159 public boolean equals(Object query){
160 return query.equals(type);
161 }
162 }
163
164 /**
165 * Defines 2 conversion tables:
166 * 1. From internal types to Java types and
167 * 2. From Java types to internal types.
168 * These two tables are used when calling external (Java) functions.
169 */
170 static {
171 try {
172 final Class nodeClass = Class.forName("org.w3c.dom.Node");
173 final Class nodeListClass = Class.forName("org.w3c.dom.NodeList");
174
175 // -- Internal to Java --------------------------------------------
176
177 // Type.Boolean -> { boolean(0), Boolean(1), Object(2) }
178 _internal2Java.put(Type.Boolean, new JavaType(Boolean.TYPE, 0));
179 _internal2Java.put(Type.Boolean, new JavaType(Boolean.class, 1));
180 _internal2Java.put(Type.Boolean, new JavaType(Object.class, 2));
260 }
261 catch (ClassNotFoundException e) {
262 System.err.println(e);
263 }
264 }
265
266 public FunctionCall(QName fname, Vector arguments) {
267 _fname = fname;
268 _arguments = arguments;
269 _type = null;
270 }
271
272 public FunctionCall(QName fname) {
273 this(fname, EMPTY_ARG_LIST);
274 }
275
276 public String getName() {
277 return(_fname.toString());
278 }
279
280 public void setParser(Parser parser) {
281 super.setParser(parser);
282 if (_arguments != null) {
283 final int n = _arguments.size();
284 for (int i = 0; i < n; i++) {
285 final Expression exp = (Expression)_arguments.elementAt(i);
286 exp.setParser(parser);
287 exp.setParent(this);
288 }
289 }
290 }
291
292 public String getClassNameFromUri(String uri)
293 {
294 String className = (String)_extensionNamespaceTable.get(uri);
295
296 if (className != null)
297 return className;
298 else {
299 if (uri.startsWith(JAVA_EXT_XSLTC)) {
302 }
303 else if (uri.startsWith(JAVA_EXT_XALAN)) {
304 int length = JAVA_EXT_XALAN.length() + 1;
305 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
306 }
307 else if (uri.startsWith(JAVA_EXT_XALAN_OLD)) {
308 int length = JAVA_EXT_XALAN_OLD.length() + 1;
309 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
310 }
311 else {
312 int index = uri.lastIndexOf('/');
313 return (index > 0) ? uri.substring(index+1) : uri;
314 }
315 }
316 }
317
318 /**
319 * Type check a function call. Since different type conversions apply,
320 * type checking is different for standard and external (Java) functions.
321 */
322 public Type typeCheck(SymbolTable stable)
323 throws TypeCheckError
324 {
325 if (_type != null) return _type;
326
327 final String namespace = _fname.getNamespace();
328 String local = _fname.getLocalPart();
329
330 if (isExtension()) {
331 _fname = new QName(null, null, local);
332 return typeCheckStandard(stable);
333 }
334 else if (isStandard()) {
335 return typeCheckStandard(stable);
336 }
337 // Handle extension functions (they all have a namespace)
338 else {
339 try {
340 _className = getClassNameFromUri(namespace);
341
663 protected final Expression argument(int i) {
664 return (Expression)_arguments.elementAt(i);
665 }
666
667 protected final Expression argument() {
668 return argument(0);
669 }
670
671 protected final int argumentCount() {
672 return _arguments.size();
673 }
674
675 protected final void setArgument(int i, Expression exp) {
676 _arguments.setElementAt(exp, i);
677 }
678
679 /**
680 * Compile the function call and treat as an expression
681 * Update true/false-lists.
682 */
683 public void translateDesynthesized(ClassGenerator classGen,
684 MethodGenerator methodGen)
685 {
686 Type type = Type.Boolean;
687 if (_chosenMethodType != null)
688 type = _chosenMethodType.resultType();
689
690 final InstructionList il = methodGen.getInstructionList();
691 translate(classGen, methodGen);
692
693 if ((type instanceof BooleanType) || (type instanceof IntType)) {
694 _falseList.add(il.append(new IFEQ(null)));
695 }
696 }
697
698
699 /**
700 * Translate a function call. The compiled code will leave the function's
701 * return value on the JVM's stack.
702 */
703 public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
704 final int n = argumentCount();
705 final ConstantPoolGen cpg = classGen.getConstantPool();
706 final InstructionList il = methodGen.getInstructionList();
707 final boolean isSecureProcessing = classGen.getParser().getXSLTC().isSecureProcessing();
708 int index;
709
710 // Translate calls to methods in the BasisLibrary
711 if (isStandard() || isExtension()) {
712 for (int i = 0; i < n; i++) {
713 final Expression exp = argument(i);
714 exp.translate(classGen, methodGen);
715 exp.startIterator(classGen, methodGen);
716 }
717
718 // append "F" to the function's name
719 final String name = _fname.toString().replace('-', '_') + "F";
720 String args = Constants.EMPTYSTRING;
721
722 // Special precautions for some method calls
840 if (_thisArgument != null && _clazz.isInterface()) {
841 index = cpg.addInterfaceMethodref(clazz,
842 _fname.getLocalPart(),
843 buffer.toString());
844 il.append(new INVOKEINTERFACE(index, n+1));
845 }
846 else {
847 index = cpg.addMethodref(clazz,
848 _fname.getLocalPart(),
849 buffer.toString());
850 il.append(_thisArgument != null ? (InvokeInstruction) new INVOKEVIRTUAL(index) :
851 (InvokeInstruction) new INVOKESTATIC(index));
852 }
853
854 // Convert the return type back to our internal type
855 _type.translateFrom(classGen, methodGen,
856 _chosenMethod.getReturnType());
857 }
858 }
859
860 public String toString() {
861 return "funcall(" + _fname + ", " + _arguments + ')';
862 }
863
864 public boolean isStandard() {
865 final String namespace = _fname.getNamespace();
866 return (namespace == null) || (namespace.equals(Constants.EMPTYSTRING));
867 }
868
869 public boolean isExtension() {
870 final String namespace = _fname.getNamespace();
871 return (namespace != null) && (namespace.equals(EXT_XSLTC));
872 }
873
874 /**
875 * Returns a vector with all methods named <code>_fname</code>
876 * after stripping its namespace or <code>null</code>
877 * if no such methods exist.
878 */
879 private Vector findMethods() {
1052
1053 int nArgs = argsType.size();
1054 for (int i = 0; i < nArgs; i++) {
1055 final Type intType = (Type)argsType.elementAt(i);
1056 buf.append(intType.toString());
1057 if (i < nArgs - 1) buf.append(", ");
1058 }
1059
1060 buf.append(')');
1061 return buf.toString();
1062 }
1063
1064 /**
1065 * To support EXSLT extensions, convert names with dash to allowable Java names:
1066 * e.g., convert abc-xyz to abcXyz.
1067 * Note: dashes only appear in middle of an EXSLT function or element name.
1068 */
1069 protected static String replaceDash(String name)
1070 {
1071 char dash = '-';
1072 StringBuffer buff = new StringBuffer("");
1073 for (int i = 0; i < name.length(); i++) {
1074 if (i > 0 && name.charAt(i-1) == dash)
1075 buff.append(Character.toUpperCase(name.charAt(i)));
1076 else if (name.charAt(i) != dash)
1077 buff.append(name.charAt(i));
1078 }
1079 return buff.toString();
1080 }
1081
1082 /**
1083 * Translate code to call the BasisLibrary.unallowed_extensionF(String)
1084 * method.
1085 */
1086 private void translateUnallowedExtension(ConstantPoolGen cpg,
1087 InstructionList il) {
1088 int index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
1089 "unallowed_extension_functionF",
1090 "(Ljava/lang/String;)V");
1091 il.append(new PUSH(cpg, _fname.toString()));
1092 il.append(new INVOKESTATIC(index));
|
37 import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
38 import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
39 import com.sun.org.apache.bcel.internal.generic.InstructionConstants;
40 import com.sun.org.apache.bcel.internal.generic.InstructionList;
41 import com.sun.org.apache.bcel.internal.generic.InvokeInstruction;
42 import com.sun.org.apache.bcel.internal.generic.LocalVariableGen;
43 import com.sun.org.apache.bcel.internal.generic.NEW;
44 import com.sun.org.apache.bcel.internal.generic.PUSH;
45 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.BooleanType;
46 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
47 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
48 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.IntType;
49 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
50 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodType;
51 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MultiHashtable;
52 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ObjectType;
53 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ReferenceType;
54 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type;
55 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.TypeCheckError;
56 import com.sun.org.apache.xalan.internal.utils.ObjectFactory;
57 import java.util.Objects;
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 _arguments;
72 // Empty argument list, used for certain functions
73 private final static Vector EMPTY_ARG_LIST = new Vector(0);
74
75 // Valid namespaces for Java function-call extension
76 protected final static String EXT_XSLTC =
77 TRANSLET_URI;
140 private static final Hashtable _java2Internal = new Hashtable();
141
142 // The mappings between EXSLT extension namespaces and implementation classes
143 private static final Hashtable _extensionNamespaceTable = new Hashtable();
144
145 // Extension functions that are implemented in BasisLibrary
146 private static final Hashtable _extensionFunctionTable = new Hashtable();
147 /**
148 * inner class to used in internal2Java mappings, contains
149 * the Java type and the distance between the internal type and
150 * the Java type.
151 */
152 static class JavaType {
153 public Class type;
154 public int distance;
155
156 public JavaType(Class type, int distance){
157 this.type = type;
158 this.distance = distance;
159 }
160
161 @Override
162 public int hashCode() {
163 return Objects.hashCode(this.type);
164 }
165
166 @Override
167 public boolean equals(Object query){
168 return query != null && query.equals(type);
169 }
170 }
171
172 /**
173 * Defines 2 conversion tables:
174 * 1. From internal types to Java types and
175 * 2. From Java types to internal types.
176 * These two tables are used when calling external (Java) functions.
177 */
178 static {
179 try {
180 final Class nodeClass = Class.forName("org.w3c.dom.Node");
181 final Class nodeListClass = Class.forName("org.w3c.dom.NodeList");
182
183 // -- Internal to Java --------------------------------------------
184
185 // Type.Boolean -> { boolean(0), Boolean(1), Object(2) }
186 _internal2Java.put(Type.Boolean, new JavaType(Boolean.TYPE, 0));
187 _internal2Java.put(Type.Boolean, new JavaType(Boolean.class, 1));
188 _internal2Java.put(Type.Boolean, new JavaType(Object.class, 2));
268 }
269 catch (ClassNotFoundException e) {
270 System.err.println(e);
271 }
272 }
273
274 public FunctionCall(QName fname, Vector arguments) {
275 _fname = fname;
276 _arguments = arguments;
277 _type = null;
278 }
279
280 public FunctionCall(QName fname) {
281 this(fname, EMPTY_ARG_LIST);
282 }
283
284 public String getName() {
285 return(_fname.toString());
286 }
287
288 @Override
289 public void setParser(Parser parser) {
290 super.setParser(parser);
291 if (_arguments != null) {
292 final int n = _arguments.size();
293 for (int i = 0; i < n; i++) {
294 final Expression exp = (Expression)_arguments.elementAt(i);
295 exp.setParser(parser);
296 exp.setParent(this);
297 }
298 }
299 }
300
301 public String getClassNameFromUri(String uri)
302 {
303 String className = (String)_extensionNamespaceTable.get(uri);
304
305 if (className != null)
306 return className;
307 else {
308 if (uri.startsWith(JAVA_EXT_XSLTC)) {
311 }
312 else if (uri.startsWith(JAVA_EXT_XALAN)) {
313 int length = JAVA_EXT_XALAN.length() + 1;
314 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
315 }
316 else if (uri.startsWith(JAVA_EXT_XALAN_OLD)) {
317 int length = JAVA_EXT_XALAN_OLD.length() + 1;
318 return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING;
319 }
320 else {
321 int index = uri.lastIndexOf('/');
322 return (index > 0) ? uri.substring(index+1) : uri;
323 }
324 }
325 }
326
327 /**
328 * Type check a function call. Since different type conversions apply,
329 * type checking is different for standard and external (Java) functions.
330 */
331 @Override
332 public Type typeCheck(SymbolTable stable)
333 throws TypeCheckError
334 {
335 if (_type != null) return _type;
336
337 final String namespace = _fname.getNamespace();
338 String local = _fname.getLocalPart();
339
340 if (isExtension()) {
341 _fname = new QName(null, null, local);
342 return typeCheckStandard(stable);
343 }
344 else if (isStandard()) {
345 return typeCheckStandard(stable);
346 }
347 // Handle extension functions (they all have a namespace)
348 else {
349 try {
350 _className = getClassNameFromUri(namespace);
351
673 protected final Expression argument(int i) {
674 return (Expression)_arguments.elementAt(i);
675 }
676
677 protected final Expression argument() {
678 return argument(0);
679 }
680
681 protected final int argumentCount() {
682 return _arguments.size();
683 }
684
685 protected final void setArgument(int i, Expression exp) {
686 _arguments.setElementAt(exp, i);
687 }
688
689 /**
690 * Compile the function call and treat as an expression
691 * Update true/false-lists.
692 */
693 @Override
694 public void translateDesynthesized(ClassGenerator classGen,
695 MethodGenerator methodGen)
696 {
697 Type type = Type.Boolean;
698 if (_chosenMethodType != null)
699 type = _chosenMethodType.resultType();
700
701 final InstructionList il = methodGen.getInstructionList();
702 translate(classGen, methodGen);
703
704 if ((type instanceof BooleanType) || (type instanceof IntType)) {
705 _falseList.add(il.append(new IFEQ(null)));
706 }
707 }
708
709
710 /**
711 * Translate a function call. The compiled code will leave the function's
712 * return value on the JVM's stack.
713 */
714 @Override
715 public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
716 final int n = argumentCount();
717 final ConstantPoolGen cpg = classGen.getConstantPool();
718 final InstructionList il = methodGen.getInstructionList();
719 final boolean isSecureProcessing = classGen.getParser().getXSLTC().isSecureProcessing();
720 int index;
721
722 // Translate calls to methods in the BasisLibrary
723 if (isStandard() || isExtension()) {
724 for (int i = 0; i < n; i++) {
725 final Expression exp = argument(i);
726 exp.translate(classGen, methodGen);
727 exp.startIterator(classGen, methodGen);
728 }
729
730 // append "F" to the function's name
731 final String name = _fname.toString().replace('-', '_') + "F";
732 String args = Constants.EMPTYSTRING;
733
734 // Special precautions for some method calls
852 if (_thisArgument != null && _clazz.isInterface()) {
853 index = cpg.addInterfaceMethodref(clazz,
854 _fname.getLocalPart(),
855 buffer.toString());
856 il.append(new INVOKEINTERFACE(index, n+1));
857 }
858 else {
859 index = cpg.addMethodref(clazz,
860 _fname.getLocalPart(),
861 buffer.toString());
862 il.append(_thisArgument != null ? (InvokeInstruction) new INVOKEVIRTUAL(index) :
863 (InvokeInstruction) new INVOKESTATIC(index));
864 }
865
866 // Convert the return type back to our internal type
867 _type.translateFrom(classGen, methodGen,
868 _chosenMethod.getReturnType());
869 }
870 }
871
872 @Override
873 public String toString() {
874 return "funcall(" + _fname + ", " + _arguments + ')';
875 }
876
877 public boolean isStandard() {
878 final String namespace = _fname.getNamespace();
879 return (namespace == null) || (namespace.equals(Constants.EMPTYSTRING));
880 }
881
882 public boolean isExtension() {
883 final String namespace = _fname.getNamespace();
884 return (namespace != null) && (namespace.equals(EXT_XSLTC));
885 }
886
887 /**
888 * Returns a vector with all methods named <code>_fname</code>
889 * after stripping its namespace or <code>null</code>
890 * if no such methods exist.
891 */
892 private Vector findMethods() {
1065
1066 int nArgs = argsType.size();
1067 for (int i = 0; i < nArgs; i++) {
1068 final Type intType = (Type)argsType.elementAt(i);
1069 buf.append(intType.toString());
1070 if (i < nArgs - 1) buf.append(", ");
1071 }
1072
1073 buf.append(')');
1074 return buf.toString();
1075 }
1076
1077 /**
1078 * To support EXSLT extensions, convert names with dash to allowable Java names:
1079 * e.g., convert abc-xyz to abcXyz.
1080 * Note: dashes only appear in middle of an EXSLT function or element name.
1081 */
1082 protected static String replaceDash(String name)
1083 {
1084 char dash = '-';
1085 final StringBuilder buff = new StringBuilder("");
1086 for (int i = 0; i < name.length(); i++) {
1087 if (i > 0 && name.charAt(i-1) == dash)
1088 buff.append(Character.toUpperCase(name.charAt(i)));
1089 else if (name.charAt(i) != dash)
1090 buff.append(name.charAt(i));
1091 }
1092 return buff.toString();
1093 }
1094
1095 /**
1096 * Translate code to call the BasisLibrary.unallowed_extensionF(String)
1097 * method.
1098 */
1099 private void translateUnallowedExtension(ConstantPoolGen cpg,
1100 InstructionList il) {
1101 int index = cpg.addMethodref(BASIS_LIBRARY_CLASS,
1102 "unallowed_extension_functionF",
1103 "(Ljava/lang/String;)V");
1104 il.append(new PUSH(cpg, _fname.toString()));
1105 il.append(new INVOKESTATIC(index));
|