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.style.StandardNames;
007: import net.sf.saxon.trans.DynamicError;
008: import net.sf.saxon.trans.XPathException;
009: import net.sf.saxon.type.ItemType;
010: import net.sf.saxon.type.Type;
011: import net.sf.saxon.type.TypeHierarchy;
012: import net.sf.saxon.value.*;
013:
014: /**
015: * A NumericPromoter performs numeric promotion on each item in a supplied sequence
016: */
017:
018: public final class NumericPromoter extends UnaryExpression implements
019: MappingFunction {
020:
021: private int requiredType; // always xs:float or xs:double
022:
023: /**
024: * Constructor
025: * @param sequence this must be a sequence of atomic values. This is not checked; a ClassCastException
026: * will occur if the precondition is not satisfied.
027: * @param requiredType the item type to which all items in the sequence should be converted,
028: * using the rules for "cast as".
029: */
030:
031: public NumericPromoter(Expression sequence, int requiredType) {
032: super (sequence);
033: this .requiredType = requiredType;
034: ExpressionTool.copyLocationInfo(sequence, this );
035: }
036:
037: /**
038: * Simplify an expression
039: */
040:
041: public Expression simplify(StaticContext env) throws XPathException {
042: operand = operand.simplify(env);
043: if (operand instanceof AtomicValue) {
044: return promote(((AtomicValue) operand), null);
045: } else if (operand instanceof Value) {
046: return SequenceExtent.makeSequenceExtent(
047: iterate(env.makeEarlyEvaluationContext())).reduce();
048: }
049: return this ;
050: }
051:
052: /**
053: * Type-check the expression
054: */
055:
056: public Expression typeCheck(StaticContext env,
057: ItemType contextItemType) throws XPathException {
058: operand = operand.typeCheck(env, contextItemType);
059: return this ;
060: }
061:
062: /**
063: * Optimize the expression
064: */
065:
066: public Expression optimize(Optimizer opt, StaticContext env,
067: ItemType contextItemType) throws XPathException {
068: operand = operand.optimize(opt, env, contextItemType);
069: return this ;
070: }
071:
072: /**
073: * Iterate over the sequence of values
074: */
075:
076: public SequenceIterator iterate(XPathContext context)
077: throws XPathException {
078: SequenceIterator base = operand.iterate(context);
079: return new MappingIterator(base, this , null);
080: }
081:
082: /**
083: * Evaluate as an Item. This should only be called if the expression has cardinality zero-or-one
084: */
085:
086: public Item evaluateItem(XPathContext context)
087: throws XPathException {
088: Item item = operand.evaluateItem(context);
089: if (item == null)
090: return null;
091: return promote(((AtomicValue) item), context);
092: }
093:
094: /**
095: * Implement the mapping function
096: */
097:
098: public Object map(Item item, XPathContext context)
099: throws XPathException {
100: return promote(((AtomicValue) item), context);
101: }
102:
103: /**
104: * Perform the promotion
105: */
106:
107: private AtomicValue promote(AtomicValue value, XPathContext context)
108: throws XPathException {
109: AtomicValue v = value.getPrimitiveValue();
110: if (!(v instanceof NumericValue || v instanceof UntypedAtomicValue)) {
111: final TypeHierarchy th = context.getNamePool()
112: .getTypeHierarchy();
113: DynamicError err = new DynamicError(
114: "Cannot promote non-numeric value to "
115: + getItemType(th).toString());
116: err.setLocator(this );
117: err.setXPathContext(context);
118: throw err;
119: }
120: return v.convert(requiredType, context);
121: }
122:
123: /**
124: * Determine the data type of the items returned by the expression, if possible
125: * @return a value such as Type.STRING, Type.BOOLEAN, Type.NUMBER, Type.NODE,
126: * or Type.ITEM (meaning not known in advance)
127: * @param th
128: */
129:
130: public ItemType getItemType(TypeHierarchy th) {
131: if (requiredType == StandardNames.XS_DOUBLE) {
132: return Type.DOUBLE_TYPE;
133: } else {
134: return Type.FLOAT_TYPE;
135: }
136: }
137:
138: /**
139: * Is this expression the same as another expression?
140: */
141:
142: public boolean equals(Object other) {
143: return super .equals(other)
144: && requiredType == ((NumericPromoter) other).requiredType;
145: }
146:
147: /**
148: * Give a string representation of the operator for use in diagnostics
149: * @return the operator, as a string
150: */
151:
152: protected String displayOperator(NamePool pool) {
153: final TypeHierarchy th = pool.getTypeHierarchy();
154: return "promote items to " + getItemType(th).toString(pool);
155: }
156:
157: }
158:
159: //
160: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
161: // you may not use this file except in compliance with the License. You may obtain a copy of the
162: // License at http://www.mozilla.org/MPL/
163: //
164: // Software distributed under the License is distributed on an "AS IS" basis,
165: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
166: // See the License for the specific language governing rights and limitations under the License.
167: //
168: // The Original Code is: all this file.
169: //
170: // The Initial Developer of the Original Code is Michael H. Kay
171: //
172: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
173: //
174: // Contributor(s): none.
175: //
|