001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.instruct.UserFunction;
004: import net.sf.saxon.instruct.UserFunctionParameter;
005: import net.sf.saxon.type.ItemType;
006: import net.sf.saxon.type.TypeHierarchy;
007: import net.sf.saxon.value.SequenceType;
008: import net.sf.saxon.value.Value;
009:
010: import java.util.ArrayList;
011: import java.util.Iterator;
012: import java.util.List;
013:
014: /**
015: * Represents the defining occurrence of a variable declared for local use
016: * within an expression, for example the $x in "for $x in ...". This object is used
017: * only at compile-time. In XQuery (but not in XSLT) this class is also used to represent
018: * the formal arguments of a function.
019: */
020:
021: public class RangeVariableDeclaration implements VariableDeclaration {
022:
023: private int nameCode;
024: private SequenceType requiredType;
025: private String variableName;
026: private List references = new ArrayList(5);
027:
028: /**
029: * Set the name of the variable, as a namepool name code
030: * @param nameCode
031: */
032:
033: public void setNameCode(int nameCode) {
034: this .nameCode = nameCode;
035: }
036:
037: /**
038: * Get the name of the variable, as a namepool name code
039: * @return the nameCode
040: */
041:
042: public int getNameCode() {
043: return nameCode;
044: }
045:
046: /**
047: * Get the required type (declared type) of the variable
048: * @return the required type
049: */
050:
051: public SequenceType getRequiredType() {
052: return requiredType;
053: }
054:
055: /**
056: * Set the required type (declared type) of the variable
057: * @param requiredType the required type
058: */
059: public void setRequiredType(SequenceType requiredType) {
060: this .requiredType = requiredType;
061: }
062:
063: public void setVariableName(String variableName) {
064: this .variableName = variableName;
065: }
066:
067: public String getVariableName() {
068: return variableName;
069: }
070:
071: public void registerReference(BindingReference ref) {
072: references.add(ref);
073: }
074:
075: public void setReferenceList(List references) {
076: this .references = references;
077: }
078:
079: public List getReferenceList() {
080: return references;
081: }
082:
083: /**
084: * Determine how often the range variable is referenced. This is the number of times
085: * it is referenced at run-time: so a reference in a loop counts as "many".
086: * @param binding the variable binding
087: * @param env
088: * @return the number of references. The only interesting values are 0, 1, and "many" (represented
089: * by any value >1).
090: */
091: public int getReferenceCount(Binding binding, StaticContext env) {
092: return getReferenceCount(references, binding, env, true);
093: }
094:
095: /**
096: * Determine how often a variable is referenced. This is the number of times
097: * it is referenced at run-time: so a reference in a loop counts as "many". This code
098: * currently handles local variables (Let expressions) and function parameters. It is
099: * not currently used for XSLT template parameters. It's not the end of the world if
100: * the answer is wrong (unless it's wrongly given as zero), but if wrongly returned as
101: * 1 then the variable will be repeatedly evaluated.
102: * @param references a list of references to a variable binding: each item in this list
103: * must be a VariableReference object
104: * @param binding the variable binding
105: * @param removeUnbound
106: * @return the number of references. The interesting values are 0, 1, "many" (represented
107: * by any value >1), and the special value FILTERED, which indicates that there are
108: * multiple references and one or more of them is of the form $x[....] indicating that an
109: * index might be useful.
110: */
111:
112: public static int getReferenceCount(List references,
113: Binding binding, StaticContext env, boolean removeUnbound) {
114: if (removeUnbound) {
115: // remove any references to the variable that have been inlined
116: for (int i = references.size() - 1; i >= 0; i--) {
117: if (((VariableReference) references.get(i))
118: .getBinding() == null) {
119: references.remove(i);
120: }
121: }
122: }
123: int rcount = 0;
124: for (int i = references.size() - 1; i >= 0; i--) {
125: BindingReference bref = (BindingReference) references
126: .get(i);
127: if (bref instanceof VariableReference) {
128: VariableReference ref = (VariableReference) bref;
129: Expression child = ref;
130: Container parent = ref.getParentExpression();
131: boolean filtered = (parent instanceof FilterExpression && child == ((FilterExpression) parent)
132: .getBaseExpression());
133: int count = 0;
134: while (parent != null) {
135:
136: if (parent instanceof ComputedExpression) {
137: // If the variable reference occurs in a subexpression that is evaluated repeatedly, for example
138: // in the predicate of a filter expression, then return 10, meaning "multiple references".
139: if (parent == binding) {
140: rcount += 1;
141: break;
142: } else if (filtered
143: && parent instanceof FilterExpression
144: && child == ((FilterExpression) parent)
145: .getBaseExpression()) {
146: return FILTERED; // no need to look any further
147: } else if (ExpressionTool
148: .isRepeatedSubexpression(
149: (ComputedExpression) parent,
150: child, env)) {
151: rcount += 10;
152: break;
153: } else {
154: child = (ComputedExpression) parent;
155: parent = child.getParentExpression();
156: if (count++ > 10000) {
157: throw new IllegalStateException(
158: "The expression tree appears to contain a cycle");
159: }
160: }
161: } else if (parent instanceof UserFunction) {
162: UserFunctionParameter[] params = ((UserFunction) parent)
163: .getParameterDefinitions();
164: for (int p = 0; p < params.length; p++) {
165: if (params[p] == binding) {
166: int refs = params[p]
167: .getReferenceCount();
168: rcount += refs;
169: }
170: }
171: rcount += 10;
172: break;
173: } else {
174: // we should have found the binding by now, but we haven't - so just skip the optimization
175: rcount += 10;
176: break;
177: }
178: }
179: rcount += 10;
180: } else {
181: // it must be a saxon:assign
182: rcount++;
183: }
184: }
185: return rcount;
186: }
187:
188: public static final int FILTERED = 10000;
189:
190: public void fixupReferences(Binding binding) {
191: for (Iterator iter = references.iterator(); iter.hasNext();) {
192: BindingReference ref = (BindingReference) iter.next();
193: ref.setStaticType(requiredType, null, 0);
194: // we supply the properties of the expression (3rd argument) later
195: // in the call of refineTypeInformation
196: ref.fixup(binding);
197: }
198: }
199:
200: public void refineTypeInformation(ItemType type, int cardinality,
201: Value constantValue, int properties, StaticContext env) {
202: for (Iterator iter = references.iterator(); iter.hasNext();) {
203: BindingReference ref = (BindingReference) iter.next();
204: if (ref instanceof VariableReference) {
205: final TypeHierarchy th = env.getNamePool()
206: .getTypeHierarchy();
207: ItemType oldItemType = ((VariableReference) ref)
208: .getItemType(th);
209: ItemType newItemType = oldItemType;
210: if (env.getNamePool().getTypeHierarchy().isSubType(
211: type, oldItemType)) {
212: newItemType = type;
213: }
214: int newcard = cardinality
215: & ((VariableReference) ref).getCardinality();
216: if (newcard == 0) {
217: // this will probably lead to a type error later
218: newcard = ((VariableReference) ref)
219: .getCardinality();
220: }
221: SequenceType seqType = SequenceType.makeSequenceType(
222: newItemType, newcard);
223:
224: ref.setStaticType(seqType, constantValue, properties);
225: }
226: }
227: }
228: }
229:
230: //
231: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
232: // you may not use this file except in compliance with the License. You may obtain a copy of the
233: // License at http://www.mozilla.org/MPL/
234: //
235: // Software distributed under the License is distributed on an "AS IS" basis,
236: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
237: // See the License for the specific language governing rights and limitations under the License.
238: //
239: // The Original Code is: all this file.
240: //
241: // The Initial Developer of the Original Code is Michael H. Kay.
242: //
243: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
244: //
245: // Contributor(s): none.
246: //
|