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);
    }
  }