001: package net.sf.saxon.pattern;
002:
003: import net.sf.saxon.expr.*;
004: import net.sf.saxon.om.*;
005: import net.sf.saxon.trans.XPathException;
006: import net.sf.saxon.type.ItemType;
007: import net.sf.saxon.type.SchemaType;
008: import net.sf.saxon.type.Type;
009: import net.sf.saxon.type.TypeHierarchy;
010: import net.sf.saxon.value.BooleanValue;
011:
012: import java.io.PrintStream;
013: import java.util.Iterator;
014:
015: /**
016: * The PatternSponsor class allows a Pattern to be treated like an expression. Although
017: * patterns are not evaluated at run-time in the same way as expressions, they need to
018: * be manipulated in much the same way as expressions at compile time: for example variables
019: * need to be bound, dependencies need to be analyzed, and so on. This is especially true
020: * of patterns appearing in the xsl:number and xsl:for-each-group instructions (less so for
021: * the more common match patterns in xsl:template).
022: *
023: * <p>This class implements the Expression interface, so that an Expression can have a
024: * PatternSponsor as a subexpression; it wraps a Pattern.</p>
025: *
026: * <p>A Pattern is treated as a boolean expression that returns true if the pattern matches
027: * the context node. However, it is not currently evaluated in that way.</p>
028: */
029:
030: public class PatternSponsor implements Expression {
031:
032: private Pattern pattern;
033:
034: public PatternSponsor(Pattern pattern) {
035: this .pattern = pattern;
036: }
037:
038: /**
039: * Get the wrapped pattern
040: */
041:
042: public Pattern getPattern() {
043: return pattern;
044: }
045:
046: /**
047: * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
048: * This method indicates which of these methods is provided directly. The other methods will always be available
049: * indirectly, using an implementation that relies on one of the other methods.
050: */
051:
052: public int getImplementationMethod() {
053: return EVALUATE_METHOD;
054: }
055:
056: /**
057: * Simplify an expression. This performs any static optimization (by rewriting the expression
058: * as a different expression). The default implementation does nothing.
059: *
060: * @return the simplified expression
061: * @throws net.sf.saxon.trans.StaticError if an error is discovered during expression
062: * rewriting
063: */
064:
065: public Expression simplify(StaticContext env) throws XPathException {
066: pattern = pattern.simplify(env);
067: return this ;
068: }
069:
070: /**
071: * Perform optimisation of an expression and its subexpressions.
072: * <p/>
073: * <p>This method is called after all references to functions and variables have been resolved
074: * to the declaration of the function or variable, and after all type checking has been done.</p>
075: *
076: * @param opt the optimizer in use. This provides access to supporting functions; it also allows
077: * different optimization strategies to be used in different circumstances.
078: * @param env the static context of the expression
079: * @param contextItemType the static type of "." at the point where this expression is invoked.
080: * The parameter is set to null if it is known statically that the context item will be undefined.
081: * If the type of the context item is not known statically, the argument is set to
082: * {@link net.sf.saxon.type.Type#ITEM_TYPE}
083: * @return the original expression, rewritten if appropriate to optimize execution
084: * @throws net.sf.saxon.trans.StaticError if an error is discovered during this phase
085: * (typically a type error)
086: */
087:
088: public Expression optimize(Optimizer opt, StaticContext env,
089: ItemType contextItemType) throws XPathException {
090: return this ;
091: }
092:
093: /**
094: * Perform type checking of an expression and its subexpressions.
095: * <p/>
096: * <p>This checks statically that the operands of the expression have
097: * the correct type; if necessary it generates code to do run-time type checking or type
098: * conversion. A static type error is reported only if execution cannot possibly succeed, that
099: * is, if a run-time type error is inevitable. The call may return a modified form of the expression.</p>
100: * <p/>
101: * <p>This method is called after all references to functions and variables have been resolved
102: * to the declaration of the function or variable. However, the types of such functions and
103: * variables may not be accurately known if they have not been explicitly declared.</p>
104: *
105: * @param env the static context of the expression
106: * @param contextItemType the static type of "." at the point where this expression is invoked.
107: * The parameter is set to null if it is known statically that the context item will be undefined.
108: * If the type of the context item is not known statically, the argument is set to
109: * {@link net.sf.saxon.type.Type#ITEM_TYPE}
110: * @return the original expression, rewritten to perform necessary
111: * run-time type checks, and to perform other type-related
112: * optimizations
113: * @throws net.sf.saxon.trans.StaticError if an error is discovered during this phase
114: * (typically a type error)
115: */
116:
117: public Expression typeCheck(StaticContext env,
118: ItemType contextItemType) throws XPathException {
119: pattern = pattern.analyze(env, contextItemType);
120: return this ;
121: }
122:
123: /**
124: * Offer promotion for this subexpression. The offer will be accepted if the subexpression
125: * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer.
126: * By default the offer is not accepted - this is appropriate in the case of simple expressions
127: * such as constant values and variable references where promotion would give no performance
128: * advantage. This method is always called at compile time.
129: *
130: * @param offer details of the offer, for example the offer to move
131: * expressions that don't depend on the context to an outer level in
132: * the containing expression
133: * @return if the offer is not accepted, return this expression unchanged.
134: * Otherwise return the result of rewriting the expression to promote
135: * this subexpression
136: * @throws net.sf.saxon.trans.XPathException
137: * if any error is detected
138: */
139:
140: public Expression promote(PromotionOffer offer)
141: throws XPathException {
142: pattern.promote(offer);
143: return this ;
144: }
145:
146: /**
147: * Get the static properties of this expression (other than its type). The result is
148: * bit-signficant. These properties are used for optimizations. In general, if
149: * property bit is set, it is true, but if it is unset, the value is unknown.
150: *
151: * @return a set of flags indicating static properties of this expression
152: */
153:
154: public int getSpecialProperties() {
155: return 0;
156: }
157:
158: /**
159: * <p>Determine the static cardinality of the expression. This establishes how many items
160: * there will be in the result of the expression, at compile time (i.e., without
161: * actually evaluating the result.</p>
162: * <p/>
163: * <p>This method should always return a result, though it may be the best approximation
164: * that is available at the time.</p>
165: *
166: * @return one of the values {@link StaticProperty#ALLOWS_ONE},
167: * {@link StaticProperty#ALLOWS_ZERO_OR_MORE}, {@link StaticProperty#ALLOWS_ZERO_OR_ONE},
168: * {@link StaticProperty#ALLOWS_ONE_OR_MORE}, {@link StaticProperty#EMPTY}.
169: */
170:
171: public int getCardinality() {
172: return StaticProperty.EXACTLY_ONE;
173: }
174:
175: /**
176: * Determine the data type of the expression, if possible. All expression return
177: * sequences, in general; this method determines the type of the items within the
178: * sequence, assuming that (a) this is known in advance, and (b) it is the same for
179: * all items in the sequence.
180: * <p/>
181: * <p>This method should always return a result, though it may be the best approximation
182: * that is available at the time.</p>
183: *
184: * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER,
185: * Type.NODE, or Type.ITEM (meaning not known at compile time)
186: * @param th
187: */
188:
189: public ItemType getItemType(TypeHierarchy th) {
190: return Type.BOOLEAN_TYPE;
191: }
192:
193: /**
194: * Determine which aspects of the context the expression depends on. The result is
195: * a bitwise-or'ed value composed from constants such as {@link net.sf.saxon.expr.StaticProperty#DEPENDS_ON_CONTEXT_ITEM} and
196: * {@link net.sf.saxon.expr.StaticProperty#DEPENDS_ON_CURRENT_ITEM}. The default implementation combines the intrinsic
197: * dependencies of this expression with the dependencies of the subexpressions,
198: * computed recursively. This is overridden for expressions such as FilterExpression
199: * where a subexpression's dependencies are not necessarily inherited by the parent
200: * expression.
201: *
202: * @return a set of bit-significant flags identifying the dependencies of
203: * the expression
204: */
205:
206: public int getDependencies() {
207: return pattern.getDependencies();
208: }
209:
210: /**
211: * Get the immediate sub-expressions of this expression. Default implementation
212: * returns a zero-length array, appropriate for an expression that has no
213: * sub-expressions.
214: *
215: * @return an iterator containing the sub-expressions of this expression
216: */
217:
218: public Iterator iterateSubExpressions() {
219: return pattern.iterateSubExpressions();
220: }
221:
222: /**
223: * Get the container that immediately contains this expression. This method
224: * returns null for an outermost expression; it also return null in the case
225: * of literal values. For an XPath expression occurring within an XSLT stylesheet,
226: * this method returns the XSLT instruction containing the XPath expression.
227: *
228: * @return the expression that contains this expression, if known; return null
229: * if there is no containing expression or if the containing expression is unknown.
230: */
231:
232: public Container getParentExpression() {
233: return pattern;
234: }
235:
236: /**
237: * Evaluate an expression as a single item. This always returns either a single Item or
238: * null (denoting the empty sequence). No conversion is done. This method should not be
239: * used unless the static type of the expression is a subtype of "item" or "item?": that is,
240: * it should not be called if the expression may return a sequence. There is no guarantee that
241: * this condition will be detected.
242: *
243: * @param context The context in which the expression is to be evaluated
244: * @return the node or atomic value that results from evaluating the
245: * expression; or null to indicate that the result is an empty
246: * sequence
247: * @throws net.sf.saxon.trans.XPathException
248: * if any dynamic error occurs evaluating the
249: * expression
250: */
251:
252: public Item evaluateItem(XPathContext context)
253: throws XPathException {
254: return BooleanValue.get(effectiveBooleanValue(context));
255: }
256:
257: /**
258: * Return an Iterator to iterate over the values of a sequence. The value of every
259: * expression can be regarded as a sequence, so this method is supported for all
260: * expressions. This default implementation handles iteration for expressions that
261: * return singleton values: for non-singleton expressions, the subclass must
262: * provide its own implementation.
263: *
264: * @param context supplies the context for evaluation
265: * @return a SequenceIterator that can be used to iterate over the result
266: * of the expression
267: * @throws net.sf.saxon.trans.XPathException
268: * if any dynamic error occurs evaluating the
269: * expression
270: */
271:
272: public SequenceIterator iterate(XPathContext context)
273: throws XPathException {
274: return SingletonIterator.makeIterator(evaluateItem(context));
275: }
276:
277: /**
278: * Get the effective boolean value of the expression. This returns false if the value
279: * is the empty sequence, a zero-length string, a number equal to zero, or the boolean
280: * false. Otherwise it returns true.
281: *
282: * @param context The context in which the expression is to be evaluated
283: * @return the effective boolean value
284: * @throws net.sf.saxon.trans.XPathException
285: * if any dynamic error occurs evaluating the
286: * expression
287: */
288:
289: public boolean effectiveBooleanValue(XPathContext context)
290: throws XPathException {
291: Item contextItem = context.getContextItem();
292: if (contextItem instanceof NodeInfo) {
293: return pattern.matches((NodeInfo) contextItem, context);
294: }
295: return false;
296: }
297:
298: /**
299: * Evaluate an expression as a String. This function must only be called in contexts
300: * where it is known that the expression will return a single string (or where an empty sequence
301: * is to be treated as a zero-length string). Implementations should not attempt to convert
302: * the result to a string, other than converting () to "". This method is used mainly to
303: * evaluate expressions produced by compiling an attribute value template.
304: *
305: * @param context The context in which the expression is to be evaluated
306: * @return the value of the expression, evaluated in the current context.
307: * The expression must return a string or (); if the value of the
308: * expression is (), this method returns "".
309: * @throws net.sf.saxon.trans.XPathException
310: * if any dynamic error occurs evaluating the
311: * expression
312: * @throws ClassCastException if the result type of the
313: * expression is not xs:string?
314: */
315:
316: public String evaluateAsString(XPathContext context)
317: throws XPathException {
318: return evaluateItem(context).getStringValue();
319: }
320:
321: /**
322: * Process the instruction, without returning any tail calls
323: *
324: * @param context The dynamic context, giving access to the current node,
325: * the current variables, etc.
326: */
327:
328: public void process(XPathContext context) throws XPathException {
329: throw new UnsupportedOperationException(
330: "Patterns cannot be evaluated in push mode");
331: }
332:
333: /**
334: * Diagnostic print of expression structure. The expression is written to the System.err
335: * output stream
336: *
337: * @param level indentation level for this expression
338: * @param pool NamePool used to expand any names appearing in the expression
339: * @param out Output destination
340: */
341:
342: public void display(int level, NamePool pool, PrintStream out) {
343: out.println(ExpressionTool.indent(level) + "pattern "
344: + pattern.toString());
345: }
346:
347: /**
348: * Check statically that the results of the expression are capable of constructing the content
349: * of a given schema type.
350: *
351: * @param parentType The schema type
352: * @param env the static context
353: * @param whole true if this expression is expected to make the whole content of the type, false
354: * if it is expected to make up only a part
355: * @throws net.sf.saxon.trans.XPathException
356: * if the expression doesn't match the required content type
357: */
358:
359: public void checkPermittedContents(SchemaType parentType,
360: StaticContext env, boolean whole) throws XPathException {
361: throw new UnsupportedOperationException(
362: "checkPermittedContents() is not applicable to a pattern");
363: }
364: }
365:
366: //
367: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
368: // you may not use this file except in compliance with the License. You may obtain a copy of the
369: // License at http://www.mozilla.org/MPL/
370: //
371: // Software distributed under the License is distributed on an "AS IS" basis,
372: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
373: // See the License for the specific language governing rights and limitations under the License.
374: //
375: // The Original Code is: all this file.
376: //
377: // The Initial Developer of the Original Code is Michael H. Kay.
378: //
379: // Contributor(s): Michael Kay
380: //
|