001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.om.NamePool;
004: import net.sf.saxon.trans.StaticError;
005: import net.sf.saxon.trans.XPathException;
006: import net.sf.saxon.type.ItemType;
007: import net.sf.saxon.value.Value;
008:
009: import java.io.PrintStream;
010: import java.util.Arrays;
011: import java.util.Iterator;
012:
013: /**
014: * Abstract superclass for calls to system-defined and user-defined functions
015: */
016:
017: public abstract class FunctionCall extends ComputedExpression {
018:
019: /**
020: * The name of the function
021: */
022:
023: private int nameCode;
024:
025: /**
026: * The array of expressions representing the actual parameters
027: * to the function call
028: */
029:
030: protected Expression[] argument;
031:
032: /**
033: * Set the name code of the function being called
034: */
035:
036: public final void setFunctionNameCode(int nc) {
037: nameCode = nc;
038: }
039:
040: /**
041: * Get the name code of the function being called
042: * @return the name code as recorded in the name pool
043: */
044:
045: public final int getFunctionNameCode() {
046: return nameCode;
047: }
048:
049: /**
050: * Determine the number of actual arguments supplied in the function call
051: */
052:
053: public final int getNumberOfArguments() {
054: return argument.length;
055: }
056:
057: /**
058: * Method called by the expression parser when all arguments have been supplied
059: */
060:
061: public void setArguments(Expression[] args) {
062: argument = args;
063: for (int a = 0; a < args.length; a++) {
064: adoptChildExpression(args[a]);
065: }
066: }
067:
068: /**
069: * Simplify the function call. Default method is to simplify each of the supplied arguments and
070: * evaluate the function if all are now known.
071: */
072:
073: public Expression simplify(StaticContext env) throws XPathException {
074: return simplifyArguments(env);
075: }
076:
077: /**
078: * Simplify the arguments of the function.
079: * Called from the simplify() method of each function.
080: * @return the result of simplifying the arguments of the expression
081: */
082:
083: protected final Expression simplifyArguments(StaticContext env)
084: throws XPathException {
085: for (int i = 0; i < argument.length; i++) {
086: Expression exp = argument[i].simplify(env);
087: if (exp != argument[i]) {
088: adoptChildExpression(exp);
089: argument[i] = exp;
090: }
091: }
092: return this ;
093: }
094:
095: /**
096: * Type-check the expression. This also calls preEvaluate() to evaluate the function
097: * if all the arguments are constant; functions that do not require this behavior
098: * can override the preEvaluate method.
099: */
100:
101: public Expression typeCheck(StaticContext env,
102: ItemType contextItemType) throws XPathException {
103: boolean fixed = true;
104: for (int i = 0; i < argument.length; i++) {
105: Expression exp = argument[i]
106: .typeCheck(env, contextItemType);
107: if (exp != argument[i]) {
108: adoptChildExpression(exp);
109: argument[i] = exp;
110: }
111: if (!(argument[i] instanceof Value)) {
112: fixed = false;
113: }
114: }
115: checkArguments(env);
116: if (fixed) {
117: return preEvaluate(env);
118: } else {
119: return this ;
120: }
121: }
122:
123: /**
124: * Perform optimisation of an expression and its subexpressions.
125: * <p/>
126: * <p>This method is called after all references to functions and variables have been resolved
127: * to the declaration of the function or variable, and after all type checking has been done.</p>
128: *
129: * @param opt the optimizer in use. This provides access to supporting functions; it also allows
130: * different optimization strategies to be used in different circumstances.
131: * @param env the static context of the expression
132: * @param contextItemType the static type of "." at the point where this expression is invoked.
133: * The parameter is set to null if it is known statically that the context item will be undefined.
134: * If the type of the context item is not known statically, the argument is set to
135: * {@link net.sf.saxon.type.Type#ITEM_TYPE}
136: * @return the original expression, rewritten if appropriate to optimize execution
137: * @throws net.sf.saxon.trans.StaticError if an error is discovered during this phase
138: * (typically a type error)
139: */
140:
141: public Expression optimize(Optimizer opt, StaticContext env,
142: ItemType contextItemType) throws XPathException {
143: boolean fixed = true;
144: for (int i = 0; i < argument.length; i++) {
145: Expression exp = argument[i].optimize(opt, env,
146: contextItemType);
147: if (exp != argument[i]) {
148: adoptChildExpression(exp);
149: argument[i] = exp;
150: }
151: if (!(argument[i] instanceof Value)) {
152: fixed = false;
153: }
154: }
155: checkArguments(env);
156: if (fixed) {
157: return preEvaluate(env);
158: } else {
159: return this ;
160: }
161: }
162:
163: /**
164: * Pre-evaluate a function at compile time. Functions that do not allow
165: * pre-evaluation, or that need access to context information, can override this method.
166: */
167:
168: public Expression preEvaluate(StaticContext env)
169: throws XPathException {
170: return ExpressionTool.eagerEvaluate(this , env
171: .makeEarlyEvaluationContext());
172: }
173:
174: /**
175: * Promote this expression if possible
176: */
177:
178: public Expression promote(PromotionOffer offer)
179: throws XPathException {
180: Expression exp = offer.accept(this );
181: if (exp != null) {
182: return exp;
183: } else {
184: if (offer.action != PromotionOffer.UNORDERED) {
185: for (int i = 0; i < argument.length; i++) {
186: argument[i] = doPromotion(argument[i], offer);
187: }
188: }
189: return this ;
190: }
191: }
192:
193: /**
194: * Method supplied by each class of function to check arguments during parsing, when all
195: * the argument expressions have been read
196: */
197:
198: protected abstract void checkArguments(StaticContext env)
199: throws XPathException;
200:
201: /**
202: * Check number of arguments. <BR>
203: * A convenience routine for use in subclasses.
204: * @param min the minimum number of arguments allowed
205: * @param max the maximum number of arguments allowed
206: * @return the actual number of arguments
207: * @throws net.sf.saxon.trans.XPathException if the number of arguments is out of range
208: */
209:
210: protected int checkArgumentCount(int min, int max, StaticContext env)
211: throws XPathException {
212: int numArgs = argument.length;
213: if (min == max && numArgs != min) {
214: throw new StaticError("Function "
215: + getDisplayName(env.getNamePool()) + " must have "
216: + min + pluralArguments(min), ExpressionTool
217: .getLocator(this ));
218: }
219: if (numArgs < min) {
220: throw new StaticError("Function "
221: + getDisplayName(env.getNamePool())
222: + " must have at least " + min
223: + pluralArguments(min), ExpressionTool
224: .getLocator(this ));
225: }
226: if (numArgs > max) {
227: throw new StaticError("Function "
228: + getDisplayName(env.getNamePool())
229: + " must have no more than " + max
230: + pluralArguments(max), ExpressionTool
231: .getLocator(this ));
232: }
233: return numArgs;
234: }
235:
236: /**
237: * Utility routine used in constructing error messages
238: */
239:
240: private static String pluralArguments(int num) {
241: if (num == 1)
242: return " argument";
243: return " arguments";
244: }
245:
246: /**
247: * Get the immediate subexpressions of this expression
248: */
249:
250: public Iterator iterateSubExpressions() {
251: return Arrays.asList(argument).iterator();
252: }
253:
254: /**
255: * Diagnostic print of expression structure
256: */
257:
258: public final String getDisplayName(NamePool pool) {
259: return pool.getDisplayName(getFunctionNameCode());
260: }
261:
262: public void display(int level, NamePool pool, PrintStream out) {
263: out.println(ExpressionTool.indent(level) + "function "
264: + getDisplayName(pool));
265: for (int a = 0; a < argument.length; a++) {
266: argument[a].display(level + 1, pool, out);
267: }
268: }
269:
270: }
271:
272: //
273: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
274: // you may not use this file except in compliance with the License. You may obtain a copy of the
275: // License at http://www.mozilla.org/MPL/
276: //
277: // Software distributed under the License is distributed on an "AS IS" basis,
278: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
279: // See the License for the specific language governing rights and limitations under the License.
280: //
281: // The Original Code is: all this file.
282: //
283: // The Initial Developer of the Original Code is Michael H. Kay.
284: //
285: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
286: //
287: // Contributor(s): none.
288: //
|