001: package net.sf.saxon.query;
002:
003: import net.sf.saxon.expr.Expression;
004: import net.sf.saxon.expr.ExpressionTool;
005: import net.sf.saxon.expr.UserFunctionCall;
006: import net.sf.saxon.functions.FunctionLibrary;
007: import net.sf.saxon.om.NamePool;
008: import net.sf.saxon.trans.StaticError;
009: import net.sf.saxon.trans.XPathException;
010: import net.sf.saxon.Configuration;
011:
012: import java.util.ArrayList;
013: import java.util.Iterator;
014: import java.util.List;
015:
016: /**
017: * An UnboundFunctionLibrary is not a real function library; rather, it is used to keep track of function calls
018: * that cannot yet be bound to a known declared function, but will have to be bound when all user-declared functions
019: * are available.
020: */
021:
022: public class UnboundFunctionLibrary implements FunctionLibrary {
023:
024: private List unboundFunctionCalls = new ArrayList(20);
025: private boolean resolving = false;
026:
027: /**
028: * Create an XQueryFunctionLibrary
029: */
030:
031: public UnboundFunctionLibrary() {
032: }
033:
034: /**
035: * Test whether a function with a given name and arity is available. This supports
036: * the function-available() function in XSLT. Since this library is used only in XQuery,
037: * and contains no real functions, we always return false
038: * @param uri The URI of the function name
039: * @param local The local part of the function name
040: * @param arity The number of arguments. This is set to -1 in the case of the single-argument
041: * function-available() function; in this case the method should return true if there is some
042: * matching extension function, regardless of its arity.
043: */
044:
045: public boolean isAvailable(int fingerprint, String uri,
046: String local, int arity) {
047: return false;
048: }
049:
050: /**
051: * Identify a (namespace-prefixed) function appearing in the expression. This
052: * method is called by the XQuery parser to resolve function calls found within
053: * the query.
054: * <p>Note that a function call may appear earlier in the query than the definition
055: * of the function to which it is bound. Unlike XSLT, we cannot search forwards to
056: * find the function definition. Binding of function calls is therefore a two-stage
057: * process; at the time the function call is parsed, we simply register it as
058: * pending; subsequently at the end of query parsing all the pending function
059: * calls are resolved. Another consequence of this is that we cannot tell at the time
060: * a function call is parsed whether it is a call to an internal (XSLT or XQuery)
061: * function or to an extension function written in Java.
062: * @return an Expression representing the function call. This will normally be
063: * a FunctionCall, but it may be rewritten as some other expression.
064: * @throws net.sf.saxon.trans.XPathException if the function call is invalid, either because it is
065: * an unprefixed call to a non-system function, or because it is calling a system
066: * function that is available in XSLT only. A prefixed function call that cannot
067: * be recognized at this stage is assumed to be a forwards reference, and is bound
068: * later when bindUnboundFunctionCalls() is called.
069: */
070:
071: public Expression bind(int nameCode, String uri, String local,
072: Expression[] arguments) throws XPathException {
073: if (resolving) {
074: return null;
075: }
076: UserFunctionCall ufc = new UserFunctionCall();
077: ufc.setFunctionNameCode(nameCode);
078: ufc.setArguments(arguments);
079: unboundFunctionCalls.add(ufc);
080: return ufc;
081: }
082:
083: /**
084: * Bind function calls that could not be bound when first encountered. These
085: * will either be forwards references to functions declared later in the query,
086: * or errors. This method is for internal use.
087: * @throws net.sf.saxon.trans.StaticError if a function call refers to a function that has
088: * not been declared
089: */
090:
091: public void bindUnboundFunctionCalls(XQueryFunctionBinder lib,
092: Configuration config) throws XPathException {
093: resolving = true;
094: final NamePool pool = config.getNamePool();
095: Iterator iter = unboundFunctionCalls.iterator();
096: while (iter.hasNext()) {
097: UserFunctionCall ufc = (UserFunctionCall) iter.next();
098:
099: // The original UserFunctionCall is effectively a dummy: we weren't able to find a function
100: // definition at the time. So we try again.
101: final int nc = ufc.getFunctionNameCode();
102: final int arity = ufc.getNumberOfArguments();
103: final String uri = pool.getURI(nc);
104: final String local = pool.getLocalName(nc);
105:
106: XQueryFunction fd = lib.getDeclaration(nc, uri, local, ufc
107: .getArguments());
108: if (fd != null) {
109: fd.registerReference(ufc);
110: ufc.setStaticType(fd.getResultType());
111: ufc.setConfirmed(true);
112: } else {
113: String msg = "Cannot find a matching " + arity
114: + "-argument function named "
115: + pool.getClarkName(nc) + "()";
116: if (!config.isAllowExternalFunctions()) {
117: msg += ". Note: external function calls have been disabled";
118: }
119: StaticError err = new StaticError(msg, ExpressionTool
120: .getLocator(ufc));
121: err.setErrorCode("XPST0017");
122: throw err;
123: }
124: }
125: }
126:
127: /**
128: * This method creates a copy of a FunctionLibrary: if the original FunctionLibrary allows
129: * new functions to be added, then additions to this copy will not affect the original, or
130: * vice versa.
131: *
132: * @return a copy of this function library. This must be an instance of the original class.
133: */
134:
135: public FunctionLibrary copy() {
136: UnboundFunctionLibrary qfl = new UnboundFunctionLibrary();
137: qfl.unboundFunctionCalls = new ArrayList(unboundFunctionCalls);
138: return qfl;
139: }
140:
141: }
142:
143: //
144: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
145: // you may not use this file except in compliance with the License. You may obtain a copy of the
146: // License at http://www.mozilla.org/MPL/
147: //
148: // Software distributed under the License is distributed on an "AS IS" basis,
149: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
150: // See the License for the specific language governing rights and limitations under the License.
151: //
152: // The Original Code is: all this file.
153: //
154: // The Initial Developer of the Original Code is Michael H. Kay.
155: //
156: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
157: //
158: // Contributor(s): none.
159: //
|