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 int bestConstrDistance = Integer.MAX_VALUE; _type = null; // reset 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; int currConstrDistance = 0; 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); Object match = _internal2Java.maps(intType, extType); if (match != null) { currConstrDistance += ((JavaType) match).distance; } else if (intType instanceof ObjectType) { ObjectType objectType = (ObjectType) intType; if (objectType.getJavaClass() == extType) continue; else if (extType.isAssignableFrom(objectType.getJavaClass())) currConstrDistance += 1; else { currConstrDistance = Integer.MAX_VALUE; break; } } else { // no mapping available currConstrDistance = Integer.MAX_VALUE; break; } } if (j == nArgs && currConstrDistance < bestConstrDistance) { _chosenConstructor = constructor; _isExtConstructor = true; bestConstrDistance = currConstrDistance; _type = (_clazz != null) ? Type.newObjectType(_clazz) : Type.newObjectType(_className); } } if (_type != null) { return _type; } throw new TypeCheckError(ErrorMsg.ARGUMENT_CONVERSION_ERR, getMethodSignature(argsType)); }
/** * Type check a call to an external (Java) method. The method must be static an public, and a * legal type conversion must exist for all its arguments and its return type. Every method of * name <code>_fname</code> is inspected as a possible candidate. */ public Type typeCheckExternal(SymbolTable stable) throws TypeCheckError { int nArgs = _arguments.size(); final String name = _fname.getLocalPart(); // check if function is a contructor 'new' if (_fname.getLocalPart().equals("new")) { return typeCheckConstructor(stable); } // check if we are calling an instance method else { boolean hasThisArgument = false; if (nArgs == 0) _isStatic = true; if (!_isStatic) { if (_namespace_format == NAMESPACE_FORMAT_JAVA || _namespace_format == NAMESPACE_FORMAT_PACKAGE) hasThisArgument = true; Expression firstArg = (Expression) _arguments.elementAt(0); Type firstArgType = (Type) firstArg.typeCheck(stable); if (_namespace_format == NAMESPACE_FORMAT_CLASS && firstArgType instanceof ObjectType && _clazz != null && _clazz.isAssignableFrom(((ObjectType) firstArgType).getJavaClass())) hasThisArgument = true; if (hasThisArgument) { _thisArgument = (Expression) _arguments.elementAt(0); _arguments.remove(0); nArgs--; if (firstArgType instanceof ObjectType) { _className = ((ObjectType) firstArgType).getJavaClassName(); } else throw new TypeCheckError(ErrorMsg.NO_JAVA_FUNCT_THIS_REF, name); } } else if (_className.length() == 0) { /* * 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" } } final Vector methods = findMethods(); if (methods == null) { // Method not found in this class throw new TypeCheckError(ErrorMsg.METHOD_NOT_FOUND_ERR, _className + "." + name); } Class extType = null; final int nMethods = methods.size(); final Vector argsType = typeCheckArgs(stable); // Try all methods to identify the best fit int bestMethodDistance = Integer.MAX_VALUE; _type = null; // reset internal type for (int j, i = 0; i < nMethods; i++) { // Check if all paramteters to this method can be converted final Method method = (Method) methods.elementAt(i); final Class[] paramTypes = method.getParameterTypes(); int currMethodDistance = 0; 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); Object match = _internal2Java.maps(intType, extType); if (match != null) { currMethodDistance += ((JavaType) match).distance; } else { // no mapping available // // Allow a Reference type to match any external (Java) type at // the moment. The real type checking is performed at runtime. if (intType instanceof ReferenceType) { currMethodDistance += 1; } else if (intType instanceof ObjectType) { ObjectType object = (ObjectType) intType; if (extType.getName().equals(object.getJavaClassName())) currMethodDistance += 0; else if (extType.isAssignableFrom(object.getJavaClass())) currMethodDistance += 1; else { currMethodDistance = Integer.MAX_VALUE; break; } } else { currMethodDistance = Integer.MAX_VALUE; break; } } } if (j == nArgs) { // Check if the return type can be converted extType = method.getReturnType(); _type = (Type) _java2Internal.get(extType); if (_type == null) { _type = Type.newObjectType(extType); } // Use this method if all parameters & return type match if (_type != null && currMethodDistance < bestMethodDistance) { _chosenMethod = method; bestMethodDistance = currMethodDistance; } } } // It is an error if the chosen method is an instance menthod but we don't // have a this argument. if (_chosenMethod != null && _thisArgument == null && !Modifier.isStatic(_chosenMethod.getModifiers())) { throw new TypeCheckError(ErrorMsg.NO_JAVA_FUNCT_THIS_REF, getMethodSignature(argsType)); } if (_type != null) { if (_type == Type.NodeSet) { getXSLTC().setMultiDocument(true); } return _type; } throw new TypeCheckError(ErrorMsg.ARGUMENT_CONVERSION_ERR, getMethodSignature(argsType)); }
/** * Defines 2 conversion tables: 1. From internal types to Java types and 2. From Java types to * internal types. These two tables are used when calling external (Java) functions. */ static { try { final Class nodeClass = Class.forName("org.w3c.dom.Node"); final Class nodeListClass = Class.forName("org.w3c.dom.NodeList"); // -- Internal to Java -------------------------------------------- // Type.Boolean -> { boolean(0), Boolean(1), Object(2) } _internal2Java.put(Type.Boolean, new JavaType(Boolean.TYPE, 0)); _internal2Java.put(Type.Boolean, new JavaType(Boolean.class, 1)); _internal2Java.put(Type.Boolean, new JavaType(Object.class, 2)); // Type.Real -> { double(0), Double(1), float(2), long(3), int(4), // short(5), byte(6), char(7), Object(8) } _internal2Java.put(Type.Real, new JavaType(Double.TYPE, 0)); _internal2Java.put(Type.Real, new JavaType(Double.class, 1)); _internal2Java.put(Type.Real, new JavaType(Float.TYPE, 2)); _internal2Java.put(Type.Real, new JavaType(Long.TYPE, 3)); _internal2Java.put(Type.Real, new JavaType(Integer.TYPE, 4)); _internal2Java.put(Type.Real, new JavaType(Short.TYPE, 5)); _internal2Java.put(Type.Real, new JavaType(Byte.TYPE, 6)); _internal2Java.put(Type.Real, new JavaType(Character.TYPE, 7)); _internal2Java.put(Type.Real, new JavaType(Object.class, 8)); // Type.Int must be the same as Type.Real _internal2Java.put(Type.Int, new JavaType(Double.TYPE, 0)); _internal2Java.put(Type.Int, new JavaType(Double.class, 1)); _internal2Java.put(Type.Int, new JavaType(Float.TYPE, 2)); _internal2Java.put(Type.Int, new JavaType(Long.TYPE, 3)); _internal2Java.put(Type.Int, new JavaType(Integer.TYPE, 4)); _internal2Java.put(Type.Int, new JavaType(Short.TYPE, 5)); _internal2Java.put(Type.Int, new JavaType(Byte.TYPE, 6)); _internal2Java.put(Type.Int, new JavaType(Character.TYPE, 7)); _internal2Java.put(Type.Int, new JavaType(Object.class, 8)); // Type.String -> { String(0), Object(1) } _internal2Java.put(Type.String, new JavaType(String.class, 0)); _internal2Java.put(Type.String, new JavaType(Object.class, 1)); // Type.NodeSet -> { NodeList(0), Node(1), Object(2), String(3) } _internal2Java.put(Type.NodeSet, new JavaType(nodeListClass, 0)); _internal2Java.put(Type.NodeSet, new JavaType(nodeClass, 1)); _internal2Java.put(Type.NodeSet, new JavaType(Object.class, 2)); _internal2Java.put(Type.NodeSet, new JavaType(String.class, 3)); // Type.Node -> { Node(0), NodeList(1), Object(2), String(3) } _internal2Java.put(Type.Node, new JavaType(nodeListClass, 0)); _internal2Java.put(Type.Node, new JavaType(nodeClass, 1)); _internal2Java.put(Type.Node, new JavaType(Object.class, 2)); _internal2Java.put(Type.Node, new JavaType(String.class, 3)); // Type.ResultTree -> { NodeList(0), Node(1), Object(2), String(3) } _internal2Java.put(Type.ResultTree, new JavaType(nodeListClass, 0)); _internal2Java.put(Type.ResultTree, new JavaType(nodeClass, 1)); _internal2Java.put(Type.ResultTree, new JavaType(Object.class, 2)); _internal2Java.put(Type.ResultTree, new JavaType(String.class, 3)); _internal2Java.put(Type.Reference, new JavaType(Object.class, 0)); // Possible conversions between Java and internal types _java2Internal.put(Boolean.TYPE, Type.Boolean); _java2Internal.put(Void.TYPE, Type.Void); _java2Internal.put(Character.TYPE, Type.Real); _java2Internal.put(Byte.TYPE, Type.Real); _java2Internal.put(Short.TYPE, Type.Real); _java2Internal.put(Integer.TYPE, Type.Real); _java2Internal.put(Long.TYPE, Type.Real); _java2Internal.put(Float.TYPE, Type.Real); _java2Internal.put(Double.TYPE, Type.Real); _java2Internal.put(String.class, Type.String); _java2Internal.put(Object.class, Type.Reference); // Conversions from org.w3c.dom.Node/NodeList to internal NodeSet _java2Internal.put(nodeListClass, Type.NodeSet); _java2Internal.put(nodeClass, Type.NodeSet); // Initialize the extension namespace table _extensionNamespaceTable.put(EXT_XALAN, "org.apache.xalan.lib.Extensions"); _extensionNamespaceTable.put(EXSLT_COMMON, "org.apache.xalan.lib.ExsltCommon"); _extensionNamespaceTable.put(EXSLT_MATH, "org.apache.xalan.lib.ExsltMath"); _extensionNamespaceTable.put(EXSLT_SETS, "org.apache.xalan.lib.ExsltSets"); _extensionNamespaceTable.put(EXSLT_DATETIME, "org.apache.xalan.lib.ExsltDatetime"); _extensionNamespaceTable.put(EXSLT_STRINGS, "org.apache.xalan.lib.ExsltStrings"); // Initialize the extension function table _extensionFunctionTable.put(EXSLT_COMMON + ":nodeSet", "nodeset"); _extensionFunctionTable.put(EXSLT_COMMON + ":objectType", "objectType"); _extensionFunctionTable.put(EXT_XALAN + ":nodeset", "nodeset"); } catch (ClassNotFoundException e) { System.err.println(e); } }