001: package net.sf.saxon.instruct;
002:
003: import net.sf.saxon.Controller;
004: import net.sf.saxon.expr.*;
005: import net.sf.saxon.om.Item;
006: import net.sf.saxon.om.NamePool;
007: import net.sf.saxon.om.SequenceIterator;
008: import net.sf.saxon.trace.TraceListener;
009: import net.sf.saxon.trans.XPathException;
010: import net.sf.saxon.type.ItemType;
011: import net.sf.saxon.type.TypeHierarchy;
012:
013: import java.io.PrintStream;
014: import java.util.Iterator;
015:
016: /**
017: * This class is a tracing wrapper around any expression: it delivers the same result as the
018: * wrapped expression, but traces its evaluation to a TraceListener
019: */
020:
021: public class TraceWrapper extends Instruction {
022: Expression child; // the instruction or other expression to be traced
023:
024: /**
025: * Simplify an expression. This performs any static optimization (by rewriting the expression
026: * as a different expression). The default implementation does nothing.
027: *
028: * @exception net.sf.saxon.trans.XPathException if an error is discovered during expression
029: * rewriting
030: * @return the simplified expression
031: */
032:
033: public Expression simplify(StaticContext env) throws XPathException {
034: child = child.simplify(env);
035: return this ;
036: }
037:
038: public Expression typeCheck(StaticContext env,
039: ItemType contextItemType) throws XPathException {
040: child = child.typeCheck(env, contextItemType);
041: adoptChildExpression(child);
042: return this ;
043: }
044:
045: public Expression optimize(Optimizer opt, StaticContext env,
046: ItemType contextItemType) throws XPathException {
047: child = child.optimize(opt, env, contextItemType);
048: adoptChildExpression(child);
049: return this ;
050: }
051:
052: /**
053: * Offer promotion for this subexpression. The offer will be accepted if the subexpression
054: * is not dependent on the factors (e.g. the context item) identified in the PromotionOffer.
055: * This method is always called at compile time.
056: *
057: * @param offer details of the offer, for example the offer to move
058: * expressions that don't depend on the context to an outer level in
059: * the containing expression
060: * @return if the offer is not accepted, return this expression unchanged.
061: * Otherwise return the result of rewriting the expression to promote
062: * this subexpression
063: * @throws net.sf.saxon.trans.XPathException
064: * if any error is detected
065: */
066:
067: public Expression promote(PromotionOffer offer)
068: throws XPathException {
069: // Many rewrites are not attempted if tracing is activated. But those that are, for example
070: // rewriting of calls to current(), must be carried out.
071: Expression newChild = child.promote(offer);
072: if (newChild != child) {
073: child = newChild;
074: adoptChildExpression(child);
075: return this ;
076: }
077: return this ;
078: }
079:
080: /**
081: * Execute this instruction, with the possibility of returning tail calls if there are any.
082: * This outputs the trace information via the registered TraceListener,
083: * and invokes the instruction being traced.
084: * @param context the dynamic execution context
085: * @return either null, or a tail call that the caller must invoke on return
086: * @throws net.sf.saxon.trans.XPathException
087: */
088: public TailCall processLeavingTail(XPathContext context)
089: throws XPathException {
090: Controller controller = context.getController();
091: TraceListener listener = controller.getTraceListener();
092: if (controller.isTracing()) {
093: listener.enter(getInstructionInfo(), context);
094: }
095: // Don't attempt tail call optimization when tracing, the results are too confusing
096: child.process(context);
097: if (controller.isTracing()) {
098: listener.leave(getInstructionInfo());
099: }
100: return null;
101: }
102:
103: /**
104: * Get the item type of the items returned by evaluating this instruction
105: * @return the static item type of the instruction
106: * @param th
107: */
108:
109: public ItemType getItemType(TypeHierarchy th) {
110: return child.getItemType(th);
111: }
112:
113: /**
114: * Determine the static cardinality of the expression. This establishes how many items
115: * there will be in the result of the expression, at compile time (i.e., without
116: * actually evaluating the result.
117: *
118: * @return one of the values Cardinality.ONE_OR_MORE,
119: * Cardinality.ZERO_OR_MORE, Cardinality.EXACTLY_ONE,
120: * Cardinality.ZERO_OR_ONE, Cardinality.EMPTY. This default
121: * implementation returns ZERO_OR_MORE (which effectively gives no
122: * information).
123: */
124:
125: public int getCardinality() {
126: return child.getCardinality();
127: }
128:
129: /**
130: * Determine which aspects of the context the expression depends on. The result is
131: * a bitwise-or'ed value composed from constants such as {@link net.sf.saxon.expr.StaticProperty#DEPENDS_ON_CONTEXT_ITEM} and
132: * {@link net.sf.saxon.expr.StaticProperty#DEPENDS_ON_CURRENT_ITEM}. The default implementation combines the intrinsic
133: * dependencies of this expression with the dependencies of the subexpressions,
134: * computed recursively. This is overridden for expressions such as FilterExpression
135: * where a subexpression's dependencies are not necessarily inherited by the parent
136: * expression.
137: *
138: * @return a set of bit-significant flags identifying the dependencies of
139: * the expression
140: */
141:
142: public int getDependencies() {
143: return child.getDependencies();
144: }
145:
146: /**
147: * Determine whether this instruction creates new nodes.
148: *
149: *
150: */
151:
152: public final boolean createsNewNodes() {
153: return (child.getSpecialProperties() & StaticProperty.NON_CREATIVE) == 0;
154: }
155:
156: /**
157: * Get the static properties of this expression (other than its type). The result is
158: * bit-signficant. These properties are used for optimizations. In general, if
159: * property bit is set, it is true, but if it is unset, the value is unknown.
160: *
161: * @return a set of flags indicating static properties of this expression
162: */
163:
164: public int computeDependencies() {
165: if (child instanceof ComputedExpression) {
166: return ((ComputedExpression) child).computeDependencies();
167: } else {
168: return 0;
169: }
170: }
171:
172: /**
173: * Evaluate an expression as a single item. This always returns either a single Item or
174: * null (denoting the empty sequence). No conversion is done. This method should not be
175: * used unless the static type of the expression is a subtype of "item" or "item?": that is,
176: * it should not be called if the expression may return a sequence. There is no guarantee that
177: * this condition will be detected.
178: *
179: * @param context The context in which the expression is to be evaluated
180: * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the
181: * expression
182: * @return the node or atomic value that results from evaluating the
183: * expression; or null to indicate that the result is an empty
184: * sequence
185: */
186:
187: public Item evaluateItem(XPathContext context)
188: throws XPathException {
189: Controller controller = context.getController();
190: if (controller.isTracing()) {
191: controller.getTraceListener().enter(getInstructionInfo(),
192: context);
193: }
194: Item result = child.evaluateItem(context);
195: if (controller.isTracing()) {
196: controller.getTraceListener().leave(getInstructionInfo());
197: }
198: return result;
199: }
200:
201: /**
202: * Return an Iterator to iterate over the values of a sequence. The value of every
203: * expression can be regarded as a sequence, so this method is supported for all
204: * expressions. This default implementation handles iteration for expressions that
205: * return singleton values: for non-singleton expressions, the subclass must
206: * provide its own implementation.
207: *
208: * @exception net.sf.saxon.trans.XPathException if any dynamic error occurs evaluating the
209: * expression
210: * @param context supplies the context for evaluation
211: * @return a SequenceIterator that can be used to iterate over the result
212: * of the expression
213: */
214:
215: public SequenceIterator iterate(XPathContext context)
216: throws XPathException {
217: Controller controller = context.getController();
218: if (controller.isTracing()) {
219: controller.getTraceListener().enter(getInstructionInfo(),
220: context);
221: }
222: SequenceIterator result = child.iterate(context);
223: if (controller.isTracing()) {
224: controller.getTraceListener().leave(getInstructionInfo());
225: }
226: return result;
227: }
228:
229: public Iterator iterateSubExpressions() {
230: return new MonoIterator(child);
231: }
232:
233: public int getInstructionNameCode() {
234: if (child instanceof Instruction) {
235: return ((Instruction) child).getInstructionNameCode();
236: } else {
237: return -1;
238: }
239: }
240:
241: /**
242: * Diagnostic print of expression structure. The expression is written to the System.err
243: * output stream
244: *
245: * @param level indentation level for this expression
246: * @param out
247: */
248:
249: public void display(int level, NamePool pool, PrintStream out) {
250: child.display(level, pool, out);
251: }
252: }
|