KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > expr > Assignation


1 package net.sf.saxon.expr;
2 import net.sf.saxon.om.NamePool;
3 import net.sf.saxon.om.ValueRepresentation;
4 import net.sf.saxon.trans.XPathException;
5 import net.sf.saxon.value.EmptySequence;
6
7 import java.util.ArrayList JavaDoc;
8 import java.util.Iterator JavaDoc;
9 import java.util.List JavaDoc;
10
11 /**
12 * Assignation is an abstract superclass for the kinds of expression
13 * that declare range variables: for, some, and every.
14 */

15
16 public abstract class Assignation extends ComputedExpression implements Binding {
17
18     protected int slotNumber = -999; // slot number for range variable
19
// (initialized to ensure a crash if no real slot is allocated)
20
protected Expression sequence; // the expression over which the variable ranges
21
protected Expression action; // the action performed for each value of the variable
22
protected String JavaDoc variableName;
23     protected int nameCode;
24
25     protected transient RangeVariableDeclaration declaration;
26
27     /**
28      * Set the reference to the variable declaration
29      */

30
31     public void setVariableDeclaration (RangeVariableDeclaration decl) {
32         declaration = decl;
33         nameCode = decl.getNameCode();
34         variableName = decl.getVariableName();
35     }
36
37     /**
38      * Get the variable declaration
39      */

40
41     public RangeVariableDeclaration getVariableDeclaration() {
42         return declaration;
43     }
44
45     /**
46      * Add the "return" or "satisfies" expression, and fix up all references to the
47      * range variable that occur within that expression
48      * @param action the expression that occurs after the "return" keyword of a "for"
49      * expression, the "satisfies" keyword of "some/every", or the ":=" operator of
50      * a "let" expression.
51      *
52      * <p>This method must be called <b>after</b> calling setVariableDeclaration()</p>
53      */

54
55     public void setAction(Expression action) {
56         this.action = action;
57         if (declaration != null) {
58             declaration.fixupReferences(this);
59         }
60         adoptChildExpression(action);
61     }
62
63     /**
64      * Indicate whether the binding is local or global. A global binding is one that has a fixed
65      * value for the life of a query or transformation; any other binding is local.
66      */

67
68     public final boolean isGlobal() {
69         return false;
70     }
71
72     /**
73     * Test whether it is permitted to assign to the variable using the saxon:assign
74     * extension element. This will only be for an XSLT global variable where the extra
75     * attribute saxon:assignable="yes" is present.
76     */

77
78     public final boolean isAssignable() {
79         return false;
80     }
81
82     /**
83      * If this is a local variable held on the local stack frame, return the corresponding slot number.
84      * In other cases, return -1.
85      */

86
87     public int getLocalSlotNumber() {
88         return slotNumber;
89     }
90
91     /**
92      * Get the action expression
93      */

94
95     public Expression getAction() {
96         return action;
97     }
98
99     /**
100      * Set the "sequence" expression - the one to which the variable is bound
101      */

102
103     public void setSequence(Expression sequence) {
104         this.sequence = sequence;
105         adoptChildExpression(sequence);
106     }
107
108     /**
109     * Set the slot number for the range variable
110     */

111
112     public void setSlotNumber(int nr) {
113         slotNumber = nr;
114     }
115
116     /**
117      * Get the number of slots required. Normally 1, except for a FOR expression with an AT clause, where it is 2.
118      */

119
120     public int getRequiredSlots() {
121         return 1;
122     }
123
124     /**
125     * Simplify the expression
126     */

127
128      public Expression simplify(StaticContext env) throws XPathException {
129         sequence = sequence.simplify(env);
130         action = action.simplify(env);
131         return this;
132     }
133
134
135     /**
136     * Promote this expression if possible
137     */

138
139     public Expression promote(PromotionOffer offer) throws XPathException {
140         Expression exp = offer.accept(this);
141         if (exp != null) {
142             return exp;
143         } else {
144             sequence = doPromotion(sequence, offer);
145             if (offer.action == PromotionOffer.INLINE_VARIABLE_REFERENCES ||
146                     offer.action == PromotionOffer.UNORDERED ||
147                     offer.action == PromotionOffer.REPLACE_CURRENT) {
148                 action = doPromotion(action, offer);
149             } else if (offer.action == PromotionOffer.RANGE_INDEPENDENT) {
150                 // Pass the offer to the action expression only if the action isn't dependent on the
151
// variable bound by this assignation
152
Binding[] savedBindingList = offer.bindingList;
153                 Binding[] newBindingList = extendBindingList(offer.bindingList);
154                 offer.bindingList = newBindingList;
155                 action = doPromotion(action, offer);
156                 offer.bindingList = savedBindingList;
157             }
158             return this;
159         }
160     }
161
162     /**
163      * Extend an array of variable bindings to include the binding(s) defined in this expression
164      */

165
166     protected Binding[] extendBindingList(Binding[] in) {
167         Binding[] newBindingList = new Binding[in.length+1];
168         System.arraycopy(in, 0, newBindingList, 0, in.length);
169         newBindingList[in.length] = this;
170         return newBindingList;
171     }
172
173     /**
174      * Promote a WHERE clause whose condition doesn't depend on the variable being bound.
175      * This rewrites an expression of the form
176      *
177      * <p>let $i := SEQ return if (C) then R else ()</p>
178      *
179      * <p>to the form:</p>
180      *
181      * <p>if (C) then (let $i := SEQ return R) else ()
182      */

183
184     protected Expression promoteWhereClause(Binding positionBinding) {
185         if (action instanceof IfExpression) {
186             Container container = getParentExpression();
187             IfExpression ifex = (IfExpression)action;
188             Expression condition = ifex.getCondition();
189             Expression elseex = ifex.getElseExpression();
190             if (elseex instanceof EmptySequence) {
191                 Binding[] bindingList;
192                 if (positionBinding == null) {
193                     Binding[] bl = {this};
194                     bindingList = bl;
195                 } else {
196                     Binding[] bl = {this, positionBinding};
197                     bindingList = bl;
198                 }
199                 List JavaDoc list = new ArrayList JavaDoc(5);
200                 Expression promotedCondition = null;
201                 BooleanExpression.listAndComponents(condition, list);
202                 for (int i=list.size()-1; i>=0; i--) {
203                     Expression term = (Expression)list.get(i);
204                     if (!ExpressionTool.dependsOnVariable(term, bindingList)) {
205                         if (promotedCondition == null) {
206                             promotedCondition = term;
207                         } else {
208                             promotedCondition = new BooleanExpression(term, Token.AND, promotedCondition);
209                         }
210                         list.remove(i);
211                     }
212                 }
213                 if (promotedCondition != null) {
214                     if (list.size() == 0) {
215                         // the whole if() condition has been promoted
216
Expression oldThen = ifex.getThenExpression();
217                         setAction(oldThen);
218                         ifex.setParentExpression(container);
219                         ifex.setThenExpression(this);
220                         return ifex;
221                     } else {
222                         // one or more terms of the if() condition have been promoted
223
Expression retainedCondition = (Expression)list.get(0);
224                         for (int i=1; i<list.size(); i++) {
225                             retainedCondition = new BooleanExpression(
226                                     retainedCondition, Token.AND, (Expression)list.get(i));
227                         }
228                         ifex.setCondition(retainedCondition);
229                         IfExpression newIf = new IfExpression(
230                                 promotedCondition, this, EmptySequence.getInstance());
231                         newIf.setParentExpression(container);
232                         return newIf;
233                     }
234                 }
235
236             }
237         }
238         return null;
239     }
240
241     /**
242     * Get the immediate subexpressions of this expression
243     */

244
245     public Iterator JavaDoc iterateSubExpressions() {
246         return new PairIterator(sequence, action);
247     }
248
249     // Following methods implement the VariableDeclaration interface, in relation to the range
250
// variable
251

252     public int getVariableNameCode() {
253         return nameCode;
254     }
255
256     public int getVariableFingerprint() {
257         return nameCode & 0xfffff;
258     }
259
260     /**
261     * Get the display name of the range variable, for diagnostics only
262     */

263
264     public String JavaDoc getVariableName(NamePool pool) {
265         if (variableName == null) {
266             return "zz:var" + hashCode();
267         } else {
268             return variableName;
269         }
270     }
271
272     /**
273     * Get the value of the range variable
274     */

275
276     public ValueRepresentation evaluateVariable(XPathContext context) throws XPathException {
277         return context.evaluateLocalVariable(slotNumber);
278     }
279
280 }
281
282
283
284 //
285
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
286
// you may not use this file except in compliance with the License. You may obtain a copy of the
287
// License at http://www.mozilla.org/MPL/
288
//
289
// Software distributed under the License is distributed on an "AS IS" basis,
290
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
291
// See the License for the specific language governing rights and limitations under the License.
292
//
293
// The Original Code is: all this file.
294
//
295
// The Initial Developer of the Original Code is Michael H. Kay
296
//
297
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
298
//
299
// Contributor(s): none.
300
//
301
Popular Tags