KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.expr;
2
3 import net.sf.saxon.instruct.UserFunction;
4 import net.sf.saxon.instruct.UserFunctionParameter;
5 import net.sf.saxon.type.ItemType;
6 import net.sf.saxon.type.Type;
7 import net.sf.saxon.value.SequenceType;
8 import net.sf.saxon.value.Value;
9
10 import java.util.ArrayList JavaDoc;
11 import java.util.Iterator JavaDoc;
12 import java.util.List JavaDoc;
13
14 /**
15  * Represents the defining occurrence of a variable declared for local use
16  * within an expression, for example the $x in "for $x in ...". This object is used
17  * only at compile-time. In XQuery (but not in XSLT) this class is also used to represent
18  * the formal arguments of a function.
19  */

20
21 public class RangeVariableDeclaration implements VariableDeclaration {
22
23     private int nameCode;
24     private SequenceType requiredType;
25     private String JavaDoc variableName;
26     private List JavaDoc references = new ArrayList JavaDoc(5);
27
28     /**
29      * Set the name of the variable, as a namepool name code
30      * @param nameCode
31      */

32
33     public void setNameCode(int nameCode) {
34         this.nameCode = nameCode;
35     }
36
37     /**
38      * Get the name of the variable, as a namepool name code
39      * @return the nameCode
40      */

41
42     public int getNameCode() {
43         return nameCode;
44     }
45
46     /**
47      * Get the required type (declared type) of the variable
48      * @return the required type
49      */

50
51     public SequenceType getRequiredType() {
52         return requiredType;
53     }
54
55     /**
56      * Set the required type (declared type) of the variable
57      * @param requiredType the required type
58      */

59     public void setRequiredType(SequenceType requiredType) {
60         this.requiredType = requiredType;
61     }
62
63     public void setVariableName(String JavaDoc variableName) {
64         this.variableName = variableName;
65     }
66
67     public String JavaDoc getVariableName() {
68         return variableName;
69     }
70
71     public void registerReference(BindingReference ref) {
72         references.add(ref);
73     }
74
75     public void setReferenceList(List JavaDoc references) {
76         this.references = references;
77     }
78
79     public List JavaDoc getReferenceList() {
80         return references;
81     }
82
83     /**
84      * Determine how often the range variable is referenced. This is the number of times
85      * it is referenced at run-time: so a reference in a loop counts as "many".
86      * @param binding the variable binding
87      * @return the number of references. The only interesting values are 0, 1, and "many" (represented
88      * by any value >1).
89      */

90     public int getReferenceCount(Binding binding) {
91         return getReferenceCount(references, binding);
92     }
93
94     /**
95      * Determine how often a variable is referenced. This is the number of times
96      * it is referenced at run-time: so a reference in a loop counts as "many". This code
97      * currently handles local variables (Let expressions) and function parameters. It is
98      * not currently used for XSLT template parameters. It's not the end of the world if
99      * the answer is wrong (unless it's wrongly given as zero), but if wrongly returned as
100      * 1 then the variable will be repeatedly evaluated.
101      * @param references a list of references to a variable binding: each item in this list
102      * must be a VariableReference object
103      * @param binding the variable binding
104      * @return the number of references. The interesting values are 0, 1, "many" (represented
105      * by any value >1), and the special value FILTERED, which indicates that there are
106      * multiple references and one or more of them is of the form $x[....] indicating that an
107      * index might be useful.
108      */

109
110     public static int getReferenceCount(List JavaDoc references, Binding binding) {
111         // remove any references to the variable that have been inlined
112
for (int i=references.size()-1; i>=0; i--) {
113             if (((VariableReference)references.get(i)).getBinding() == null) {
114                 references.remove(i);
115             }
116         }
117         if (references.size() != 1) {
118             // TODO: we're not returning FILTERED if there's only one reference
119
return references.size();
120         }
121         VariableReference ref = (VariableReference)references.get(0);
122         Expression child = ref;
123         Container parent = ref.getParentExpression();
124         boolean filtered = (parent instanceof FilterExpression && child == ((FilterExpression)parent).getBaseExpression());
125         int count = 0;
126         while (parent != null) {
127
128             if (parent instanceof ComputedExpression) {
129                 // If the variable reference occurs in a subexpression that is evaluated repeatedly, for example
130
// in the predicate of a filter expression, then return 10, meaning "multiple references".
131
if (parent == binding) {
132                     return 1;
133                 } else if (filtered && parent instanceof FilterExpression && child == ((FilterExpression)parent).getBaseExpression()) {
134                     return FILTERED;
135                 } else if (ExpressionTool.isRepeatedSubexpression((ComputedExpression)parent, child)) {
136                     return 10;
137                 } else {
138                     child = (ComputedExpression)parent;
139                     parent = child.getParentExpression();
140                     if (count++ > 10000) {
141                         throw new IllegalStateException JavaDoc("The expression tree appears to contain a cycle");
142                     }
143                 }
144             } else if (parent instanceof UserFunction) {
145                 UserFunctionParameter[] params = ((UserFunction)parent).getParameterDefinitions();
146                 for (int p=0; p<params.length; p++) {
147                     if (params[p] == binding) {
148                         int refs = params[p].getReferenceCount();
149                         return refs;
150                     }
151                 }
152                 return 10;
153             } else {
154                 // we should have found the binding by now, but we haven't - so just skip the optimization
155
return 10;
156             }
157         }
158         return 10;
159     }
160
161     public static final int FILTERED = 10000;
162
163     public void fixupReferences(Binding binding) {
164         for (Iterator JavaDoc iter=references.iterator(); iter.hasNext();) {
165             BindingReference ref = (BindingReference)iter.next();
166             ref.setStaticType(requiredType, null, 0);
167                    // we supply the properties of the expression (3rd argument) later
168
// in the call of refineTypeInformation
169
ref.fixup(binding);
170         }
171     }
172
173     public void refineTypeInformation(ItemType type, int cardinality,
174                                       Value constantValue, int properties) {
175         for (Iterator JavaDoc iter=references.iterator(); iter.hasNext();) {
176             BindingReference ref = (BindingReference)iter.next();
177             if (ref instanceof VariableReference) {
178                 ItemType oldItemType = ((VariableReference)ref).getItemType();
179                 ItemType newItemType = oldItemType;
180                 if (Type.isSubType(type, oldItemType)) {
181                     newItemType = type;
182                 }
183                 int newcard = cardinality & ((VariableReference)ref).getCardinality();
184                 if (newcard==0) {
185                     // this will probably lead to a type error later
186
newcard = ((VariableReference)ref).getCardinality();
187                 }
188                 SequenceType seqType = SequenceType.makeSequenceType(newItemType, newcard);
189
190                 ref.setStaticType(seqType, constantValue, properties);
191             }
192         }
193     }
194 }
195
196 //
197
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
198
// you may not use this file except in compliance with the License. You may obtain a copy of the
199
// License at http://www.mozilla.org/MPL/
200
//
201
// Software distributed under the License is distributed on an "AS IS" basis,
202
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
203
// See the License for the specific language governing rights and limitations under the License.
204
//
205
// The Original Code is: all this file.
206
//
207
// The Initial Developer of the Original Code is Michael H. Kay.
208
//
209
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
210
//
211
// Contributor(s): none.
212
//
Popular Tags