001: package net.sf.saxon.instruct;
002:
003: import net.sf.saxon.expr.*;
004: import net.sf.saxon.om.*;
005: import net.sf.saxon.pattern.NoNodeTest;
006: import net.sf.saxon.style.StandardNames;
007: import net.sf.saxon.trans.XPathException;
008: import net.sf.saxon.type.ItemType;
009: import net.sf.saxon.type.TypeHierarchy;
010: import net.sf.saxon.value.SequenceType;
011:
012: import java.io.PrintStream;
013: import java.util.Collections;
014: import java.util.Iterator;
015:
016: /**
017: * This class defines common behaviour across xsl:variable, xsl:param, and xsl:with-param;
018: * also saxon:assign
019: */
020:
021: public abstract class GeneralVariable extends Instruction implements
022: Binding {
023:
024: private static final int ASSIGNABLE = 1;
025: private static final int REQUIRED = 4;
026: private static final int TUNNEL = 8;
027:
028: private byte properties = 0;
029: Expression select = null;
030: protected int nameCode = -1;
031: SequenceType requiredType;
032: private int slotNumber;
033: private String variableName;
034: protected int referenceCount = 10;
035:
036: public GeneralVariable() {
037: };
038:
039: public void init(Expression select, int nameCode) {
040: this .select = select;
041: this .nameCode = nameCode;
042: adoptChildExpression(select);
043: }
044:
045: public void setSelectExpression(Expression select) {
046: this .select = select;
047: adoptChildExpression(select);
048: }
049:
050: public Expression getSelectExpression() {
051: return select;
052: }
053:
054: public void setRequiredType(SequenceType required) {
055: requiredType = required;
056: }
057:
058: public SequenceType getRequiredType() {
059: return requiredType;
060: }
061:
062: public void setNameCode(int nameCode) {
063: this .nameCode = nameCode;
064: }
065:
066: public int getNameCode() {
067: return nameCode;
068: }
069:
070: public void setAssignable(boolean assignable) {
071: if (assignable) {
072: properties |= ASSIGNABLE;
073: } else {
074: properties &= ~ASSIGNABLE;
075: }
076: }
077:
078: public void setRequiredParam(boolean requiredParam) {
079: if (requiredParam) {
080: properties |= REQUIRED;
081: } else {
082: properties &= ~REQUIRED;
083: }
084: }
085:
086: public void setTunnel(boolean tunnel) {
087: if (tunnel) {
088: properties |= TUNNEL;
089: } else {
090: properties &= ~TUNNEL;
091: }
092: }
093:
094: public void setReferenceCount(int refCount) {
095: referenceCount = refCount;
096: }
097:
098: /**
099: * Test whether it is permitted to assign to the variable using the saxon:assign
100: * extension element. This will only be true if the extra attribute saxon:assignable="yes"
101: * is present.
102: */
103:
104: public final boolean isAssignable() {
105: return (properties & ASSIGNABLE) != 0;
106: }
107:
108: /**
109: * Get the name of the variable (as a NamePool fingerprint)
110: * @return the NamePool fingerprint of the variable's expanded name.
111: */
112:
113: public int getVariableFingerprint() {
114: return nameCode & 0xfffff;
115: }
116:
117: /**
118: * Get the type of the result of this instruction. An xsl:variable instruction returns nothing, so the
119: * type is empty.
120: * @return the empty type.
121: * @param th
122: */
123:
124: public ItemType getItemType(TypeHierarchy th) {
125: return NoNodeTest.getInstance();
126: }
127:
128: /**
129: * Get the cardinality of the result of this instruction. An xsl:variable instruction returns nothing, so the
130: * type is empty.
131: * @return the empty cardinality.
132: */
133:
134: public int getCardinality() {
135: return StaticProperty.EMPTY;
136: }
137:
138: public boolean isGlobal() {
139: return false;
140: }
141:
142: /**
143: * If this is a local variable held on the local stack frame, return the corresponding slot number.
144: * In other cases, return -1.
145: */
146:
147: public int getLocalSlotNumber() {
148: return slotNumber;
149: }
150:
151: public final boolean isRequiredParam() {
152: return (properties & REQUIRED) != 0;
153: }
154:
155: public final boolean isTunnelParam() {
156: return (properties & TUNNEL) != 0;
157: }
158:
159: public int getInstructionNameCode() {
160: return StandardNames.XSL_VARIABLE;
161: }
162:
163: public Expression simplify(StaticContext env) throws XPathException {
164: if (select != null) {
165: select = select.simplify(env);
166: }
167: return this ;
168: }
169:
170: public Expression typeCheck(StaticContext env,
171: ItemType contextItemType) throws XPathException {
172: if (select != null) {
173: select = select.typeCheck(env, contextItemType);
174: adoptChildExpression(select);
175: }
176: checkAgainstRequiredType(env);
177: return this ;
178: }
179:
180: public Expression optimize(Optimizer opt, StaticContext env,
181: ItemType contextItemType) throws XPathException {
182: if (select != null) {
183: select = select.optimize(opt, env, contextItemType);
184: adoptChildExpression(select);
185: }
186: return this ;
187: }
188:
189: /**
190: * Check the select expression against the required type.
191: * @param env
192: * @throws XPathException
193: */
194:
195: private void checkAgainstRequiredType(StaticContext env)
196: throws XPathException {
197: // Note, in some cases we are doing this twice.
198: RoleLocator role = new RoleLocator(RoleLocator.VARIABLE,
199: variableName, 0, null);
200: role.setSourceLocator(this );
201: SequenceType r = requiredType;
202: if (r != null && select != null) {
203: // check that the expression is consistent with the required type
204: select = TypeChecker.staticTypeCheck(select, requiredType,
205: false, role, env);
206: }
207: }
208:
209: /**
210: * Evaluate an expression as a single item. This always returns either a single Item or
211: * null (denoting the empty sequence). No conversion is done. This method should not be
212: * used unless the static type of the expression is a subtype of "item" or "item?": that is,
213: * it should not be called if the expression may return a sequence. There is no guarantee that
214: * this condition will be detected.
215: *
216: * @param context The context in which the expression is to be evaluated
217: * @exception XPathException if any dynamic error occurs evaluating the
218: * expression
219: * @return the node or atomic value that results from evaluating the
220: * expression; or null to indicate that the result is an empty
221: * sequence
222: */
223:
224: public Item evaluateItem(XPathContext context)
225: throws XPathException {
226: process(context);
227: return null;
228: }
229:
230: /**
231: * Return an Iterator to iterate over the values of a sequence. The value of every
232: * expression can be regarded as a sequence, so this method is supported for all
233: * expressions. This default implementation relies on the process() method: it
234: * "pushes" the results of the instruction to a sequence in memory, and then
235: * iterates over this in-memory sequence.
236: *
237: * In principle instructions should implement a pipelined iterate() method that
238: * avoids the overhead of intermediate storage.
239: *
240: * @exception XPathException if any dynamic error occurs evaluating the
241: * expression
242: * @param context supplies the context for evaluation
243: * @return a SequenceIterator that can be used to iterate over the result
244: * of the expression
245: */
246:
247: public SequenceIterator iterate(XPathContext context)
248: throws XPathException {
249: evaluateItem(context);
250: return EmptyIterator.getInstance();
251: }
252:
253: /**
254: * Evaluate the variable. That is,
255: * get the value of the select expression if present or the content
256: * of the element otherwise, either as a tree or as a sequence
257: */
258:
259: public ValueRepresentation getSelectValue(XPathContext context)
260: throws XPathException {
261: if (select == null) {
262: throw new AssertionError("*** No select expression!!");
263: // The value of the variable is a sequence of nodes and/or atomic values
264:
265: } else {
266: // There is a select attribute: do a lazy evaluation of the expression,
267: // which will already contain any code to force conversion to the required type.
268:
269: if (isAssignable()) {
270: return ExpressionTool.eagerEvaluate(select, context);
271: } else {
272: return ExpressionTool.lazyEvaluate(select, context,
273: referenceCount);
274: }
275:
276: }
277: }
278:
279: /**
280: * Handle promotion offers, that is, non-local tree rewrites.
281: * @param offer The type of rewrite being offered
282: * @throws XPathException
283: */
284:
285: protected void promoteInst(PromotionOffer offer)
286: throws XPathException {
287: if (select != null) {
288: select = doPromotion(select, offer);
289: }
290: }
291:
292: /**
293: * Get all the XPath expressions associated with this instruction
294: * (in XSLT terms, the expression present on attributes of the instruction,
295: * as distinct from the child instructions in a sequence construction)
296: */
297:
298: public Iterator iterateSubExpressions() {
299: if (select != null) {
300: return new MonoIterator(select);
301: } else {
302: return Collections.EMPTY_LIST.iterator();
303: }
304: }
305:
306: /**
307: * Diagnostic print of expression structure. The expression is written to the System.err
308: * output stream
309: *
310: * @param level indentation level for this expression
311: * @param out
312: */
313:
314: public void display(int level, NamePool pool, PrintStream out) {
315: out.println(ExpressionTool.indent(level) + "variable "
316: + pool.getDisplayName(nameCode));
317: if (select != null) {
318: select.display(level + 1, pool, out);
319: }
320: }
321:
322: public int getSlotNumber() {
323: return slotNumber;
324: }
325:
326: public void setSlotNumber(int s) {
327: slotNumber = s;
328: }
329:
330: public void setVariableName(String s) {
331: variableName = s;
332: }
333:
334: public String getVariableName() {
335: return variableName;
336: }
337: }
338:
339: //
340: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
341: // you may not use this file except in compliance with the License. You may obtain a copy of the
342: // License at http://www.mozilla.org/MPL/
343: //
344: // Software distributed under the License is distributed on an "AS IS" basis,
345: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
346: // See the License for the specific language governing rights and limitations under the License.
347: //
348: // The Original Code is: all this file.
349: //
350: // The Initial Developer of the Original Code is Michael H. Kay.
351: //
352: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
353: //
354: // Contributor(s): none.
355: //
|