tmiller 2002/07/25 04:44:19
Modified: java/src/org/apache/xalan/xsltc Translet.java
java/src/org/apache/xalan/xsltc/compiler CastExpr.java
FunctionCall.java Parser.java
java/src/org/apache/xalan/xsltc/compiler/util
ErrorMessages.java ErrorMsg.java NodeSetType.java
Log:
bug fix 10837, support of ext java functions
Revision Changes Path
1.4 +3 -1 xml-xalan/java/src/org/apache/xalan/xsltc/Translet.java
Index: Translet.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/Translet.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- Translet.java 28 Sep 2001 14:39:14 -0000 1.3
+++ Translet.java 25 Jul 2002 11:44:19 -0000 1.4
@@ -80,4 +80,6 @@
throws TransletException;
public void addAuxiliaryClass(Class auxClass);
public Class getAuxiliaryClass(String className);
+ public String[] getNamesArray();
+ public String[] getNamespaceArray();
}
1.13 +7 -1 xml-xalan/java/src/org/apache/xalan/xsltc/compiler/CastExpr.java
Index: CastExpr.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/CastExpr.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- CastExpr.java 28 Jun 2002 15:09:16 -0000 1.12
+++ CastExpr.java 25 Jul 2002 11:44:19 -0000 1.13
@@ -109,6 +109,7 @@
InternalTypeMap.put(Type.NodeSet, Type.String);
InternalTypeMap.put(Type.NodeSet, Type.Node);
InternalTypeMap.put(Type.NodeSet, Type.Reference);
+ InternalTypeMap.put(Type.NodeSet, Type.Object);
InternalTypeMap.put(Type.Node, Type.Node);
InternalTypeMap.put(Type.Node, Type.Boolean);
@@ -116,6 +117,7 @@
InternalTypeMap.put(Type.Node, Type.String);
InternalTypeMap.put(Type.Node, Type.NodeSet);
InternalTypeMap.put(Type.Node, Type.Reference);
+ InternalTypeMap.put(Type.Node, Type.Object);
InternalTypeMap.put(Type.ResultTree, Type.ResultTree);
InternalTypeMap.put(Type.ResultTree, Type.Boolean);
@@ -123,6 +125,7 @@
InternalTypeMap.put(Type.ResultTree, Type.String);
InternalTypeMap.put(Type.ResultTree, Type.NodeSet);
InternalTypeMap.put(Type.ResultTree, Type.Reference);
+ InternalTypeMap.put(Type.ResultTree, Type.Object);
InternalTypeMap.put(Type.Reference, Type.Reference);
InternalTypeMap.put(Type.Reference, Type.Boolean);
@@ -132,6 +135,9 @@
InternalTypeMap.put(Type.Reference, Type.Node);
InternalTypeMap.put(Type.Reference, Type.NodeSet);
InternalTypeMap.put(Type.Reference, Type.ResultTree);
+ InternalTypeMap.put(Type.Reference, Type.Object);
+
+ InternalTypeMap.put(Type.Object, Type.String);
InternalTypeMap.put(Type.Void, Type.String);
}
1.20 +213 -29
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/FunctionCall.java
Index: FunctionCall.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/FunctionCall.java,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -r1.19 -r1.20
--- FunctionCall.java 18 Jul 2002 17:24:43 -0000 1.19
+++ FunctionCall.java 25 Jul 2002 11:44:19 -0000 1.20
@@ -60,6 +60,7 @@
* @author Santiago Pericas-Geertsen
* @author Morten Jorgensen
* @author Erwin Bolwidt <[EMAIL PROTECTED]>
+ * @author Todd Miller
*
*/
@@ -71,8 +72,18 @@
import java.lang.reflect.*;
+import org.apache.bcel.generic.NEW;
+import org.apache.bcel.generic.IFEQ;
+import org.apache.bcel.generic.PUSH;
+import org.apache.bcel.generic.INVOKESTATIC;
+import org.apache.bcel.generic.INVOKEVIRTUAL;
+import org.apache.bcel.generic.INVOKESPECIAL;
+import org.apache.bcel.generic.ConstantPoolGen;
+import org.apache.bcel.generic.InstructionList;
+import org.apache.bcel.generic.InstructionConstants;
+import org.apache.bcel.generic.InvokeInstruction;
+
import org.apache.xalan.xsltc.compiler.util.Type;
-import org.apache.bcel.generic.*;
import org.apache.xalan.xsltc.compiler.util.*;
import org.apache.xalan.xsltc.runtime.TransletLoader;
@@ -98,15 +109,23 @@
protected final static String JAVA_EXT_XALAN =
"http://xml.apache.org/xslt/java";
+ /**
+ * Stores reference to object for non-static Java calls
+ */
+ Expression _thisArgument = null;
// External Java function's class/method/signature
- private String _className;
- private Method _chosenMethod;
- private MethodType _chosenMethodType;
+ private String _className;
+ private Method _chosenMethod;
+ private Constructor _chosenConstructor;
+ private MethodType _chosenMethodType;
// Encapsulates all unsupported external function calls
private boolean unresolvedExternal;
+ // If FunctionCall is a external java constructor
+ private boolean _isExtConstructor = false;
+
// Legal conversions between internal and Java types.
private static final MultiHashtable _internal2Java = new MultiHashtable();
@@ -175,6 +194,8 @@
_java2Internal.put(objectClass, Type.Reference);
// Conversions from org.w3c.dom.Node/NodeList are not supported
+ // GTM
+ _java2Internal.put(nodeListClass, Type.NodeSet);
}
catch (ClassNotFoundException e) {
System.err.println(e);
@@ -242,19 +263,19 @@
// Handle extension functions (they all have a namespace)
else {
try {
+ // GTM: namespace = http://xml.apache.org/xslt/java
_className = getClassNameFromUri(namespace);
final int pos = local.lastIndexOf('.');
if (pos > 0) {
_className = _className + local.substring(0, pos);
- _fname = new QName(namespace, null, local.substring(pos + 1));
+ _fname = new QName(namespace, null,
+ local.substring(pos + 1));
}
else {
_fname = new QName(namespace, null, local);
}
- if (_className.length() > 0) {
- return typeCheckExternal(stable);
- }
+ return typeCheckExternal(stable);
}
catch (TypeCheckError e) {
ErrorMsg errorMsg = e.getErrorMsg();
@@ -265,20 +286,6 @@
getParser().reportError(ERROR, errorMsg);
return _type = Type.Void;
}
-
- /*
- * Warn user if external function could not be resolved.
- * Warning will _NOT_ be issued is the call is properly
- * wrapped in an <xsl:if> or <xsl:when> element. For details
- * see If.parserContents() and When.parserContents()
- */
- final Parser parser = getParser();
- if (parser != null) {
- reportWarning(this, parser, ErrorMsg.FUNCTION_RESOLVE_ERR,
- _fname.toString());
- }
- unresolvedExternal = true;
- return _type = Type.Int; // use "Int" as "unknown"
}
}
@@ -315,6 +322,56 @@
throw new TypeCheckError(this);
}
+
+
+ public Type typeCheckConstructor(SymbolTable stable) throws TypeCheckError{
+ final Vector constructors = findConstructors();
+ if (constructors == null) {
+ // Constructor not found in this class
+ throw new TypeCheckError(ErrorMsg.CONSTRUCTOR_NOT_FOUND,
+ _className);
+
+ }
+
+ final int nConstructors = constructors.size();
+ final int nArgs = _arguments.size();
+ final Vector argsType = typeCheckArgs(stable);
+
+ // Try all constructors
+ for (int j, i = 0; i < nConstructors; i++) {
+ // Check if all parameters to this constructor can be converted
+ final Constructor constructor =
+ (Constructor)constructors.elementAt(i);
+ final Class[] paramTypes = constructor.getParameterTypes();
+
+ Class extType = null;
+ for (j = 0; j < nArgs; j++) {
+ // Convert from internal (translet) type to external (Java) type
+ extType = paramTypes[j];
+ final Type intType = (Type)argsType.elementAt(j);
+ if (!_internal2Java.maps(intType, extType)) break;
+ }
+
+ if (j == nArgs) {
+ _chosenConstructor = constructor;
+ _isExtConstructor = true;
+ return _type = new ObjectType(_className);
+ }
+ }
+
+ final StringBuffer buf = new StringBuffer(_className);
+ buf.append('.').append(_fname.getLocalPart()).append('(');
+ for (int i = 0; i < nArgs; i++) {
+ final Type intType = (Type)argsType.elementAt(i);
+ buf.append(intType.toString());
+ if (i < nArgs - 1) buf.append(", ");
+ }
+ buf.append(')');
+ throw new TypeCheckError(ErrorMsg.ARGUMENT_CONVERSION_ERR,
+ buf.toString());
+ }
+
+
/**
* Type check a call to an external (Java) method.
* The method must be static an public, and a legal type conversion
@@ -323,17 +380,54 @@
* as a possible candidate.
*/
public Type typeCheckExternal(SymbolTable stable) throws TypeCheckError {
+ int nArgs = _arguments.size();
+ final String name = _fname.getLocalPart();
+
+ // check if we are calling an instance method
+ if (_className.length() == 0) {
+ if (nArgs > 0) {
+ _thisArgument = (Expression) _arguments.elementAt(0);
+ _arguments.remove(0); nArgs--;
+ Type type = _thisArgument.typeCheck(stable);
+ if (type instanceof ObjectType) {
+ _className = ((ObjectType) type).getJavaClassName();
+ }
+ else {
+ // TODO: define a new error message
+ throw new TypeCheckError(ErrorMsg.NO_JAVA_FUNCT_THIS_REF,
+ name);
+ }
+ }
+ else {
+ /*
+ * Warn user if external function could not be resolved.
+ * Warning will _NOT_ be issued is the call is properly
+ * wrapped in an <xsl:if> or <xsl:when> element. For details
+ * see If.parserContents() and When.parserContents()
+ */
+ final Parser parser = getParser();
+ if (parser != null) {
+ reportWarning(this, parser, ErrorMsg.FUNCTION_RESOLVE_ERR,
+ _fname.toString());
+ }
+ unresolvedExternal = true;
+ return _type = Type.Int; // use "Int" as "unknown"
+ }
+ }
+ // check if function is a contructor 'new'
+ else if (_fname.getLocalPart().equals("new")) {
+ return typeCheckConstructor(stable);
+ }
+
final Vector methods = findMethods();
if (methods == null) {
// Method not found in this class
- final String name = _fname.getLocalPart();
throw new TypeCheckError(ErrorMsg.METHOD_NOT_FOUND_ERR, name);
}
Class extType = null;
final int nMethods = methods.size();
- final int nArgs = _arguments.size();
final Vector argsType = typeCheckArgs(stable);
// Try all methods with the same name as this function
@@ -359,6 +453,9 @@
// Use this method if all parameters & return type match
if (_type != null) {
_chosenMethod = method;
+ if (_type == Type.NodeSet){
+ getXSLTC().setMultiDocument(true);
+ }
return _type;
}
}
@@ -475,11 +572,50 @@
il.append(new PUSH(cpg, _fname.toString()));
il.append(new INVOKESTATIC(index));
}
+ else if (_isExtConstructor) {
+ final String clazz =
+ _chosenConstructor.getDeclaringClass().getName();
+ Class[] paramTypes = _chosenConstructor.getParameterTypes();
+
+ il.append(new NEW(cpg.addClass(_className)));
+ il.append(InstructionConstants.DUP);
+
+ for (int i = 0; i < n; i++) {
+ final Expression exp = argument(i);
+ exp.translate(classGen, methodGen);
+ // Convert the argument to its Java type
+ exp.startResetIterator(classGen, methodGen);
+ exp.getType().translateTo(classGen, methodGen, paramTypes[i]);
+ }
+
+ final StringBuffer buffer = new StringBuffer();
+ buffer.append('(');
+ for (int i = 0; i < paramTypes.length; i++) {
+ buffer.append(getSignature(paramTypes[i]));
+ }
+ buffer.append(')');
+ buffer.append("V");
+
+ index = cpg.addMethodref(clazz,
+ "<init>",
+ buffer.toString());
+ il.append(new INVOKESPECIAL(index));
+
+ // Convert the return type back to our internal type
+ (Type.Object).translateFrom(classGen, methodGen,
+ _chosenConstructor.getDeclaringClass());
+
+ }
// Invoke function calls that are handled in separate classes
else {
final String clazz = _chosenMethod.getDeclaringClass().getName();
Class[] paramTypes = _chosenMethod.getParameterTypes();
+ // Push "this" if it is an instance method
+ if (_thisArgument != null) {
+ _thisArgument.translate(classGen, methodGen);
+ }
+
for (int i = 0; i < n; i++) {
final Expression exp = argument(i);
exp.translate(classGen, methodGen);
@@ -499,7 +635,9 @@
index = cpg.addMethodref(clazz,
_fname.getLocalPart(),
buffer.toString());
- il.append(new INVOKESTATIC(index));
+ il.append(_thisArgument != null ?
+ (InvokeInstruction) new INVOKEVIRTUAL(index) :
+ (InvokeInstruction) new INVOKESTATIC(index));
// Convert the return type back to our internal type
_type.translateFrom(classGen, methodGen,
@@ -549,10 +687,8 @@
for (int i = 0; i < methods.length; i++) {
final int mods = methods[i].getModifiers();
-
- // Is it public, static and same number of args ?
+ // Is it public and same number of args ?
if (Modifier.isPublic(mods)
- && Modifier.isStatic(mods)
&& methods[i].getName().equals(methodName)
&& methods[i].getParameterTypes().length == nArgs)
{
@@ -572,6 +708,54 @@
}
return result;
}
+
+ /**
+ * Returns a vector with all constructors named <code>_fname</code>
+ * after stripping its namespace or <code>null</code>
+ * if no such methods exist.
+ */
+ private Vector findConstructors() {
+ Vector result = null;
+ final String namespace = _fname.getNamespace();
+
+ if (namespace.startsWith(JAVA_EXT_XSLTC) ||
+ namespace.startsWith(JAVA_EXT_XALAN)) {
+ final int nArgs = _arguments.size();
+ try {
+ TransletLoader loader = new TransletLoader();
+ final Class clazz = loader.loadClass(_className);
+
+ if (clazz == null) {
+ final ErrorMsg msg =
+ new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
+ getParser().reportError(Constants.ERROR, msg);
+ }
+ else {
+ final Constructor[] constructors = clazz.getConstructors();
+
+ for (int i = 0; i < constructors.length; i++) {
+ final int mods = constructors[i].getModifiers();
+ // Is it public, static and same number of args ?
+ if (Modifier.isPublic(mods) &&
+ constructors[i].getParameterTypes().length == nArgs)
+ {
+ if (result == null) {
+ result = new Vector();
+ }
+ result.addElement(constructors[i]);
+ }
+ }
+ }
+ }
+ catch (ClassNotFoundException e) {
+ final ErrorMsg msg =
+ new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, _className);
+ getParser().reportError(Constants.ERROR, msg);
+ }
+ }
+ return result;
+ }
+
/**
* Compute the JVM signature for the class.
1.51 +3 -3 xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Parser.java
Index: Parser.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/Parser.java,v
retrieving revision 1.50
retrieving revision 1.51
diff -u -r1.50 -r1.51
--- Parser.java 9 Jul 2002 15:37:23 -0000 1.50
+++ Parser.java 25 Jul 2002 11:44:19 -0000 1.51
@@ -754,7 +754,7 @@
MethodType B_V = new MethodType(Type.Boolean, Type.Void);
MethodType B_B = new MethodType(Type.Boolean, Type.Boolean);
MethodType B_S = new MethodType(Type.Boolean, Type.String);
- MethodType D_T = new MethodType(Type.NodeSet, Type.ResultTree);
+ MethodType D_X = new MethodType(Type.NodeSet, Type.Object);
MethodType R_RR = new MethodType(Type.Real, Type.Real, Type.Real);
MethodType I_II = new MethodType(Type.Int, Type.Int, Type.Int);
MethodType B_RR = new MethodType(Type.Boolean, Type.Real, Type.Real);
@@ -840,7 +840,7 @@
_symbolTable.addPrimop("system-property", S_S);
// Extensions
- _symbolTable.addPrimop("nodeset", D_T);
+ _symbolTable.addPrimop("nodeset", D_X);
// Operators +, -, *, /, % defined on real types.
_symbolTable.addPrimop("+", R_RR);
1.12 +7 -3
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages.java
Index: ErrorMessages.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages.java,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- ErrorMessages.java 23 May 2002 14:52:09 -0000 1.11
+++ ErrorMessages.java 25 Jul 2002 11:44:19 -0000 1.12
@@ -83,7 +83,7 @@
// CLASS_NOT_FOUND_ERR
"Cannot find class ''{0}''.",
// METHOD_NOT_FOUND_ERR
- "Cannot find external method ''{0}'' (must be static and public).",
+ "Cannot find external method ''{0}'' (must be public).",
// ARGUMENT_CONVERSION_ERR
"Cannot convert argument/return type in call to method ''{0}''",
// FILE_NOT_FOUND_ERR
@@ -265,7 +265,11 @@
// UNSUPPORTED_ENCODING
"Output encoding ''{0}'' is not supported on this JVM.",
// SYNTAX_ERR
- "Syntax error in ''{0}''."
+ "Syntax error in ''{0}''.",
+ // CONSTRUCTOR_NOT_FOUND
+ "Cannot find external constructor ''{0}''.",
+ // NO_JAVA_FUNCT_THIS_REF
+ "First argument to non-static Java function ''{0}'' is not valid object ref."
};
private static Vector _keys;
1.14 +3 -1
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/util/ErrorMsg.java
Index: ErrorMsg.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/util/ErrorMsg.java,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- ErrorMsg.java 6 May 2002 17:52:55 -0000 1.13
+++ ErrorMsg.java 25 Jul 2002 11:44:19 -0000 1.14
@@ -166,6 +166,8 @@
public static final int STRAY_SORT_ERR = 74;
public static final int UNSUPPORTED_ENCODING = 75;
public static final int SYNTAX_ERR = 76;
+ public static final int CONSTRUCTOR_NOT_FOUND = 77;
+ public static final int NO_JAVA_FUNCT_THIS_REF = 78;
// All error messages are localized and are stored in resource bundles.
// This array and the following 4 strings are read from that bundle.
1.10 +47 -1
xml-xalan/java/src/org/apache/xalan/xsltc/compiler/util/NodeSetType.java
Index: NodeSetType.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/compiler/util/NodeSetType.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- NodeSetType.java 1 Feb 2002 20:08:11 -0000 1.9
+++ NodeSetType.java 25 Jul 2002 11:44:19 -0000 1.10
@@ -113,6 +113,9 @@
else if (type == Type.Reference) {
translateTo(classGen, methodGen, (ReferenceType) type);
}
+ else if (type == Type.Object) {
+ translateTo(classGen, methodGen, (ObjectType) type);
+ }
else {
ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
toString(), type.toString());
@@ -121,6 +124,39 @@
}
/**
+ * Translates an external Java Class into an internal type.
+ * Expects the Java object on the stack, pushes the internal type
+ */
+ public void translateFrom(ClassGenerator classGen,
+ MethodGenerator methodGen, Class clazz)
+ {
+
+ InstructionList il = methodGen.getInstructionList();
+ ConstantPoolGen cpg = classGen.getConstantPool();
+ if (clazz.getName().equals("org.w3c.dom.NodeList")) {
+ // w3c NodeList is on the stack from the external Java function call.
+ // call BasisFunction to consume NodeList and leave Iterator on
+ // the stack.
+ il.append(classGen.loadTranslet()); // push translet onto stack
+ il.append(methodGen.loadDOM()); // push DOM onto stack
+ final int convert = cpg.addMethodref(BASIS_LIBRARY_CLASS,
+ "nodeList2Iterator",
+ "("
+ + "Lorg/w3c/dom/NodeList;"
+ + TRANSLET_INTF_SIG
+ + DOM_INTF_SIG
+ + ")" + NODE_ITERATOR_SIG );
+ il.append(new INVOKESTATIC(convert));
+ }
+ else {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
+ toString(), clazz.getName());
+ classGen.getParser().reportError(Constants.FATAL, err);
+ }
+ }
+
+
+ /**
* Translates a node-set into a synthesized boolean.
* The boolean value of a node-set is "true" if non-empty
* and "false" otherwise. Notice that the
@@ -177,6 +213,16 @@
public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
NodeType type) {
getFirstNode(classGen, methodGen);
+ }
+
+ /**
+ * Subsume node-set into ObjectType.
+ *
+ * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
+ */
+ public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
+ ObjectType type) {
+ methodGen.getInstructionList().append(NOP);
}
/**
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]