001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.Controller;
004: import net.sf.saxon.value.Value;
005: import net.sf.saxon.event.SequenceOutputter;
006: import net.sf.saxon.om.*;
007: import net.sf.saxon.trans.XPathException;
008: import net.sf.saxon.type.ItemType;
009: import net.sf.saxon.type.Type;
010: import net.sf.saxon.type.TypeHierarchy;
011:
012: import java.io.PrintStream;
013: import java.util.Arrays;
014: import java.util.Iterator;
015:
016: /**
017: * An abstract implementation of Expression designed to make it easy to implement new expressions,
018: * in particular, expressions to support extension instructions.
019: */
020:
021: public abstract class SimpleExpression extends ComputedExpression {
022:
023: public static final Expression[] NO_ARGUMENTS = new Expression[0];
024:
025: protected Expression[] arguments = NO_ARGUMENTS;
026:
027: /**
028: * Constructor
029: */
030:
031: public SimpleExpression() {
032: }
033:
034: /**
035: * Set the immediate sub-expressions of this expression.
036: * @param sub an array containing the sub-expressions of this expression
037: */
038:
039: public void setArguments(Expression[] sub) {
040: arguments = sub;
041: for (int i = 0; i < sub.length; i++) {
042: adoptChildExpression(sub[i]);
043: }
044: }
045:
046: /**
047: * Get the immediate sub-expressions of this expression.
048: * @return an array containing the sub-expressions of this expression
049: */
050:
051: public Iterator iterateSubExpressions() {
052: return Arrays.asList(arguments).iterator();
053: }
054:
055: /**
056: * Simplify the expression
057: * @return the simplified expression
058: */
059:
060: public Expression simplify(StaticContext env) throws XPathException {
061: for (int i = 0; i < arguments.length; i++) {
062: if (arguments[i] != null) {
063: arguments[i] = arguments[i].simplify(env);
064: }
065: }
066: return this ;
067: }
068:
069: public Expression typeCheck(StaticContext env,
070: ItemType contextItemType) throws XPathException {
071: for (int i = 0; i < arguments.length; i++) {
072: if (arguments[i] != null) {
073: arguments[i] = arguments[i].typeCheck(env,
074: contextItemType);
075: }
076: }
077: return this ;
078: }
079:
080: public Expression optimize(Optimizer opt, StaticContext env,
081: ItemType contextItemType) throws XPathException {
082: for (int i = 0; i < arguments.length; i++) {
083: if (arguments[i] != null) {
084: arguments[i] = arguments[i].optimize(opt, env,
085: contextItemType);
086: }
087: }
088: return this ;
089: }
090:
091: /**
092: * Offer promotion for this subexpression. The offer will be accepted if the subexpression
093: * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer.
094: * By default the offer is not accepted - this is appropriate in the case of simple expressions
095: * such as constant values and variable references where promotion would give no performance
096: * advantage. This method is always called at compile time.
097: *
098: * @param offer details of the offer, for example the offer to move
099: * expressions that don't depend on the context to an outer level in
100: * the containing expression
101: * @exception XPathException if any error is detected
102: * @return if the offer is not accepted, return this expression unchanged.
103: * Otherwise return the result of rewriting the expression to promote
104: * this subexpression
105: */
106:
107: public Expression promote(PromotionOffer offer)
108: throws XPathException {
109: for (int i = 0; i < arguments.length; i++) {
110: if (arguments[i] != null) {
111: arguments[i] = doPromotion(arguments[i], offer);
112: }
113: }
114: return this ;
115: }
116:
117: /**
118: * Determine the data type of the items returned by this expression. This implementation
119: * returns "item()", which can be overridden in a subclass.
120: * @return the data type
121: * @param th
122: */
123:
124: public ItemType getItemType(TypeHierarchy th) {
125: return Type.ITEM_TYPE;
126: }
127:
128: /**
129: * Determine the static cardinality of the expression. This implementation
130: * returns "zero or more", which can be overridden in a subclass.
131: */
132:
133: public int computeCardinality() {
134: if ((getImplementationMethod() & Expression.EVALUATE_METHOD) == 0) {
135: return StaticProperty.ALLOWS_ONE_OR_MORE;
136: } else {
137: return StaticProperty.ALLOWS_ZERO_OR_ONE;
138: }
139: }
140:
141: /**
142: * Compute the dependencies of an expression, as the union of the
143: * dependencies of its subexpressions. (This is overridden for path expressions
144: * and filter expressions, where the dependencies of a subexpression are not all
145: * propogated). This method should be called only once, to compute the dependencies;
146: * after that, getDependencies should be used.
147: * @return the depencies, as a bit-mask
148: */
149:
150: public int computeDependencies() {
151: return super .computeDependencies();
152: }
153:
154: /**
155: * Evaluate an expression as a single item. This always returns either a single Item or
156: * null (denoting the empty sequence). No conversion is done. This method should not be
157: * used unless the static type of the expression is a subtype of "item" or "item?": that is,
158: * it should not be called if the expression may return a sequence. There is no guarantee that
159: * this condition will be detected.
160: *
161: * @param context The context in which the expression is to be evaluated
162: * @exception XPathException if any dynamic error occurs evaluating the
163: * expression
164: * @return the node or atomic value that results from evaluating the
165: * expression; or null to indicate that the result is an empty
166: * sequence
167: */
168:
169: public Item evaluateItem(XPathContext context)
170: throws XPathException {
171: int m = getImplementationMethod();
172: if ((m & Expression.EVALUATE_METHOD) != 0) {
173: dynamicError(
174: "evaluateItem() is not implemented in the subclass "
175: + this .getClass(), context);
176: } else if ((m & Expression.ITERATE_METHOD) != 0) {
177: return iterate(context).next();
178: } else {
179: Controller controller = context.getController();
180: XPathContext c2 = context.newMinorContext();
181: c2.setOrigin(this );
182: SequenceOutputter seq = new SequenceOutputter(1);
183: seq.setPipelineConfiguration(controller
184: .makePipelineConfiguration());
185: c2.setTemporaryReceiver(seq);
186: process(c2);
187: return seq.getFirstItem();
188: }
189: return null;
190: }
191:
192: /**
193: * Return an Iterator to iterate over the values of a sequence. The value of every
194: * expression can be regarded as a sequence, so this method is supported for all
195: * expressions. This default implementation handles iteration for expressions that
196: * return singleton values: for non-singleton expressions, the subclass must
197: * provide its own implementation.
198: *
199: * @exception XPathException if any dynamic error occurs evaluating the
200: * expression
201: * @param context supplies the context for evaluation
202: * @return a SequenceIterator that can be used to iterate over the result
203: * of the expression
204: */
205:
206: public SequenceIterator iterate(XPathContext context)
207: throws XPathException {
208: int m = getImplementationMethod();
209: if ((m & Expression.EVALUATE_METHOD) != 0) {
210: Item item = evaluateItem(context);
211: if (item == null) {
212: return EmptyIterator.getInstance();
213: } else {
214: return SingletonIterator.makeIterator(item);
215: }
216: } else if ((m & Expression.ITERATE_METHOD) != 0) {
217: dynamicError(
218: "iterate() is not implemented in the subclass "
219: + this .getClass(), context);
220:
221: } else {
222: Controller controller = context.getController();
223: XPathContext c2 = context.newMinorContext();
224: c2.setOrigin(this );
225: SequenceOutputter seq = new SequenceOutputter();
226: seq.setPipelineConfiguration(controller
227: .makePipelineConfiguration());
228: c2.setTemporaryReceiver(seq);
229:
230: process(c2);
231:
232: return Value.getIterator(seq.getSequence());
233: }
234: return null;
235: }
236:
237: /**
238: * Process the instruction, without returning any tail calls
239: * @param context The dynamic context, giving access to the current node,
240: * the current variables, etc.
241: */
242:
243: public void process(XPathContext context) throws XPathException {
244: int m = getImplementationMethod();
245: if ((m & Expression.EVALUATE_METHOD) == 0) {
246: SequenceIterator iter = iterate(context);
247: while (true) {
248: Item it = iter.next();
249: if (it == null)
250: break;
251: context.getReceiver().append(it, locationId,
252: NodeInfo.ALL_NAMESPACES);
253: }
254: } else {
255: Item item = evaluateItem(context);
256: context.getReceiver().append(item, locationId,
257: NodeInfo.ALL_NAMESPACES);
258: }
259: }
260:
261: /**
262: * Diagnostic print of expression structure. The expression is written to the System.err
263: * output stream
264: *
265: * @param level indentation level for this expression
266: * @param out
267: */
268:
269: public void display(int level, NamePool pool, PrintStream out) {
270: out.println(ExpressionTool.indent(level) + getExpressionType());
271: for (int i = 0; i < arguments.length; i++) {
272: arguments[i].display(level + 1, pool, out);
273: }
274: }
275:
276: /**
277: * Return a distinguishing name for the expression, for use in diagnostics.
278: * By default the class name is used.
279: */
280:
281: public String getExpressionType() {
282: return getClass().getName();
283: }
284:
285: }
286:
287: //
288: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
289: // you may not use this file except in compliance with the License. You may obtain a copy of the
290: // License at http://www.mozilla.org/MPL/
291: //
292: // Software distributed under the License is distributed on an "AS IS" basis,
293: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
294: // See the License for the specific language governing rights and limitations under the License.
295: //
296: // The Original Code is: all this file.
297: //
298: // The Initial Developer of the Original Code is Michael H. Kay.
299: //
300: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
301: //
302: // Contributor(s): none.
303: //
|