001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.om.Item;
004: import net.sf.saxon.om.NamePool;
005: import net.sf.saxon.om.SequenceIterator;
006: import net.sf.saxon.trans.XPathException;
007: import net.sf.saxon.type.ItemType;
008: import net.sf.saxon.type.Type;
009: import net.sf.saxon.type.TypeHierarchy;
010: import net.sf.saxon.value.BooleanValue;
011: import net.sf.saxon.value.EmptySequence;
012: import net.sf.saxon.value.SequenceType;
013:
014: import java.io.PrintStream;
015:
016: /**
017: * A QuantifiedExpression tests whether some/all items in a sequence satisfy
018: * some condition.
019: */
020:
021: class QuantifiedExpression extends Assignation {
022:
023: private int operator; // Token.SOME or Token.EVERY
024:
025: public void setOperator(int operator) {
026: this .operator = operator;
027: }
028:
029: /**
030: * Determine the static cardinality
031: */
032:
033: public int computeCardinality() {
034: return StaticProperty.EXACTLY_ONE;
035: }
036:
037: /**
038: * Type-check the expression
039: */
040:
041: public Expression typeCheck(StaticContext env,
042: ItemType contextItemType) throws XPathException {
043:
044: final TypeHierarchy th = env.getNamePool().getTypeHierarchy();
045: if (declaration == null) {
046: // we've already done the type checking, no need to do it again
047: return this ;
048: }
049:
050: // The order of events is critical here. First we ensure that the type of the
051: // sequence expression is established. This is used to establish the type of the variable,
052: // which in turn is required when type-checking the action part.
053:
054: sequence = sequence.typeCheck(env, contextItemType);
055: if (sequence instanceof EmptySequence) {
056: return BooleanValue.get(operator != Token.SOME);
057: }
058:
059: // "some" and "every" have no ordering constraints
060:
061: Optimizer opt = env.getConfiguration().getOptimizer();
062: sequence = ExpressionTool.unsorted(opt, sequence, false);
063:
064: SequenceType decl = declaration.getRequiredType();
065: SequenceType sequenceType = SequenceType.makeSequenceType(decl
066: .getPrimaryType(), StaticProperty.ALLOWS_ZERO_OR_MORE);
067: RoleLocator role = new RoleLocator(RoleLocator.VARIABLE,
068: new Integer(nameCode), 0, env.getNamePool());
069: role.setSourceLocator(this );
070: sequence = TypeChecker.strictTypeCheck(sequence, sequenceType,
071: role, env);
072: ItemType actualItemType = sequence.getItemType(th);
073: declaration.refineTypeInformation(actualItemType,
074: StaticProperty.EXACTLY_ONE, null, sequence
075: .getSpecialProperties(), env);
076:
077: declaration = null; // let the garbage collector take it
078:
079: action = action.typeCheck(env, contextItemType);
080: return this ;
081: }
082:
083: /**
084: * Perform optimisation of an expression and its subexpressions.
085: * <p/>
086: * <p>This method is called after all references to functions and variables have been resolved
087: * to the declaration of the function or variable, and after all type checking has been done.</p>
088: *
089: * @param opt the optimizer in use. This provides access to supporting functions; it also allows
090: * different optimization strategies to be used in different circumstances.
091: * @param env the static context of the expression
092: * @param contextItemType the static type of "." at the point where this expression is invoked.
093: * The parameter is set to null if it is known statically that the context item will be undefined.
094: * If the type of the context item is not known statically, the argument is set to
095: * {@link net.sf.saxon.type.Type#ITEM_TYPE}
096: * @return the original expression, rewritten if appropriate to optimize execution
097: * @throws net.sf.saxon.trans.StaticError if an error is discovered during this phase
098: * (typically a type error)
099: */
100:
101: public Expression optimize(Optimizer opt, StaticContext env,
102: ItemType contextItemType) throws XPathException {
103: sequence = sequence.optimize(opt, env, contextItemType);
104: action = action.optimize(opt, env, contextItemType);
105: PromotionOffer offer = new PromotionOffer(opt);
106: offer.containingExpression = this ;
107: offer.action = PromotionOffer.RANGE_INDEPENDENT;
108: Binding[] bindingList = { this };
109: offer.bindingList = bindingList;
110: action = doPromotion(action, offer);
111: if (offer.containingExpression instanceof LetExpression) {
112: offer.containingExpression = offer.containingExpression
113: .typeCheck(env, contextItemType).optimize(opt, env,
114: contextItemType);
115: }
116: return offer.containingExpression;
117:
118: }
119:
120: /**
121: * Determine the special properties of this expression
122: * @return {@link StaticProperty#NON_CREATIVE}.
123: */
124:
125: public int computeSpecialProperties() {
126: int p = super .computeSpecialProperties();
127: return p | StaticProperty.NON_CREATIVE;
128: }
129:
130: /**
131: * Evaluate the expression to return a singleton value
132: */
133:
134: public Item evaluateItem(XPathContext context)
135: throws XPathException {
136: return BooleanValue.get(effectiveBooleanValue(context));
137: }
138:
139: /**
140: * Get the result as a boolean
141: */
142:
143: public boolean effectiveBooleanValue(XPathContext context)
144: throws XPathException {
145:
146: // First create an iteration of the base sequence.
147:
148: SequenceIterator base = sequence.iterate(context);
149:
150: // Now test to see if some or all of the tests are true. The same
151: // logic is used for the SOME and EVERY operators
152:
153: final boolean some = (operator == Token.SOME);
154: while (true) {
155: final Item it = base.next();
156: if (it == null) {
157: break;
158: }
159: context.setLocalVariable(slotNumber, it);
160: if (some == action.effectiveBooleanValue(context)) {
161: return some;
162: }
163: }
164: return !some;
165: }
166:
167: /**
168: * Determine the data type of the items returned by the expression
169: * @return Type.BOOLEAN
170: * @param th
171: */
172:
173: public ItemType getItemType(TypeHierarchy th) {
174: return Type.BOOLEAN_TYPE;
175: }
176:
177: /**
178: * Diagnostic print of expression structure
179: */
180:
181: public void display(int level, NamePool pool, PrintStream out) {
182: out.println(ExpressionTool.indent(level)
183: + Token.tokens[operator] + " $" + getVariableName(pool)
184: + " in");
185: sequence.display(level + 1, pool, out);
186: out.println(ExpressionTool.indent(level) + "satisfies");
187: action.display(level + 1, pool, out);
188: }
189:
190: }
191:
192: //
193: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
194: // you may not use this file except in compliance with the License. You may obtain a copy of the
195: // License at http://www.mozilla.org/MPL/
196: //
197: // Software distributed under the License is distributed on an "AS IS" basis,
198: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
199: // See the License for the specific language governing rights and limitations under the License.
200: //
201: // The Original Code is: all this file.
202: //
203: // The Initial Developer of the Original Code is Michael H. Kay
204: //
205: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
206: //
207: // Contributor(s): none.
208: //
|