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.*;
011:
012: import java.io.PrintStream;
013:
014: /**
015: * InstanceOf Expression: implements "Expr instance of data-type"
016: */
017:
018: public final class InstanceOfExpression extends UnaryExpression {
019:
020: ItemType targetType;
021: int targetCardinality;
022:
023: public InstanceOfExpression(Expression source, SequenceType target) {
024: super (source);
025: targetType = target.getPrimaryType();
026: if (targetType == null) {
027: throw new IllegalArgumentException(
028: "Primary item type must not be null");
029: }
030: targetCardinality = target.getCardinality();
031: }
032:
033: /**
034: * Type-check the expression
035: * @return the checked expression
036: */
037:
038: public Expression typeCheck(StaticContext env,
039: ItemType contextItemType) throws XPathException {
040: operand = operand.typeCheck(env, contextItemType);
041: if (operand instanceof Value) {
042: return (AtomicValue) evaluateItem(env
043: .makeEarlyEvaluationContext());
044: }
045:
046: // See if we can get the answer by static analysis.
047:
048: if (Cardinality.subsumes(targetCardinality, operand
049: .getCardinality())) {
050: final TypeHierarchy th = env.getNamePool()
051: .getTypeHierarchy();
052: int relation = th.relationship(operand.getItemType(th),
053: targetType);
054: if (relation == TypeHierarchy.SAME_TYPE
055: || relation == TypeHierarchy.SUBSUMED_BY) {
056: return BooleanValue.TRUE;
057: } else if (relation == TypeHierarchy.DISJOINT) {
058: // if the item types are disjoint, the result might still be true if both sequences are empty
059: if (!Cardinality.allowsZero(targetCardinality)
060: || !Cardinality.allowsZero(operand
061: .getCardinality())) {
062: return BooleanValue.FALSE;
063: }
064: }
065: }
066: return this ;
067: }
068:
069: /**
070: * Perform optimisation of an expression and its subexpressions.
071: * <p/>
072: * <p>This method is called after all references to functions and variables have been resolved
073: * to the declaration of the function or variable, and after all type checking has been done.</p>
074: *
075: * @param opt the optimizer in use. This provides access to supporting functions; it also allows
076: * different optimization strategies to be used in different circumstances.
077: * @param env the static context of the expression
078: * @param contextItemType the static type of "." at the point where this expression is invoked.
079: * The parameter is set to null if it is known statically that the context item will be undefined.
080: * If the type of the context item is not known statically, the argument is set to
081: * {@link net.sf.saxon.type.Type#ITEM_TYPE}
082: * @return the original expression, rewritten if appropriate to optimize execution
083: * @throws net.sf.saxon.trans.StaticError if an error is discovered during this phase
084: * (typically a type error)
085: */
086:
087: public Expression optimize(Optimizer opt, StaticContext env,
088: ItemType contextItemType) throws XPathException {
089: Expression e = super .optimize(opt, env, contextItemType);
090: if (e != this ) {
091: return e;
092: }
093: if (Cardinality.subsumes(targetCardinality, operand
094: .getCardinality())) {
095: final TypeHierarchy th = env.getNamePool()
096: .getTypeHierarchy();
097: int relation = th.relationship(operand.getItemType(th),
098: targetType);
099: if (relation == TypeHierarchy.SAME_TYPE
100: || relation == TypeHierarchy.SUBSUMED_BY) {
101: return BooleanValue.TRUE;
102: } else if (relation == TypeHierarchy.DISJOINT) {
103: // if the item types are disjoint, the result might still be true if both sequences are empty
104: if (!Cardinality.allowsZero(targetCardinality)
105: || !Cardinality.allowsZero(operand
106: .getCardinality())) {
107: return BooleanValue.FALSE;
108: }
109: }
110: }
111: return this ;
112: }
113:
114: /**
115: * Is this expression the same as another expression?
116: */
117:
118: public boolean equals(Object other) {
119: return super .equals(other)
120: && targetType == ((InstanceOfExpression) other).targetType
121: && targetCardinality == ((InstanceOfExpression) other).targetCardinality;
122: }
123:
124: /**
125: * Determine the cardinality
126: */
127:
128: public int computeCardinality() {
129: return StaticProperty.EXACTLY_ONE;
130: }
131:
132: /**
133: * Determine the data type of the result of the InstanceOf expression
134: * @param th
135: */
136:
137: public ItemType getItemType(TypeHierarchy th) {
138: return Type.BOOLEAN_TYPE;
139: }
140:
141: /**
142: * Evaluate the expression
143: */
144:
145: public Item evaluateItem(XPathContext context)
146: throws XPathException {
147: return BooleanValue.get(effectiveBooleanValue(context));
148: }
149:
150: /**
151: * Evaluate the expression as a boolean
152: */
153:
154: public boolean effectiveBooleanValue(XPathContext context)
155: throws XPathException {
156: SequenceIterator iter = operand.iterate(context);
157: int count = 0;
158: while (true) {
159: Item item = iter.next();
160: if (item == null)
161: break;
162: count++;
163: if (!targetType.matchesItem(item, context)) {
164: return false;
165: }
166: if (count == 2
167: && !Cardinality.allowsMany(targetCardinality)) {
168: return false;
169: }
170: }
171: if (count == 0
172: && ((targetCardinality & StaticProperty.ALLOWS_ZERO) == 0)) {
173: return false;
174: }
175: return true;
176: }
177:
178: /**
179: * Give a string representation of the operator for use in diagnostics
180: * @return the operator, as a string
181: */
182:
183: protected String displayOperator(NamePool pool) {
184: return "instance of " + targetType.toString(pool)
185: + Cardinality.getOccurrenceIndicator(targetCardinality);
186: }
187:
188: /**
189: * Diagnostic print of expression structure
190: */
191:
192: public void display(int level, NamePool pool, PrintStream out) {
193: out.println(ExpressionTool.indent(level) + "instance of");
194: operand.display(level + 1, pool, out);
195: out
196: .println(ExpressionTool.indent(level + 1)
197: + targetType.toString(pool)
198: + Cardinality
199: .getOccurrenceIndicator(targetCardinality));
200: }
201:
202: }
203:
204: //
205: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
206: // you may not use this file except in compliance with the License. You may obtain a copy of the
207: // License at http://www.mozilla.org/MPL/
208: //
209: // Software distributed under the License is distributed on an "AS IS" basis,
210: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
211: // See the License for the specific language governing rights and limitations under the License.
212: //
213: // The Original Code is: all this file.
214: //
215: // The Initial Developer of the Original Code is Michael H. Kay
216: //
217: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
218: //
219: // Contributor(s): none.
220: //
|