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.trans.XPathException;
006: import net.sf.saxon.type.*;
007: import net.sf.saxon.value.AtomicValue;
008: import net.sf.saxon.value.BooleanValue;
009: import net.sf.saxon.value.SequenceType;
010: import net.sf.saxon.value.ValidationErrorValue;
011:
012: /**
013: * Castable Expression: implements "Expr castable as atomic-type?".
014: * The implementation simply wraps a cast expression with a try/catch.
015: */
016:
017: public final class CastableExpression extends UnaryExpression {
018:
019: AtomicType targetType;
020: boolean allowEmpty;
021:
022: public CastableExpression(Expression source, AtomicType target,
023: boolean allowEmpty) {
024: super (source);
025: this .targetType = target;
026: this .allowEmpty = allowEmpty;
027: }
028:
029: /**
030: * Simplify the expression
031: * @return the simplified expression
032: */
033:
034: public Expression simplify(StaticContext env) throws XPathException {
035: operand = operand.simplify(env);
036: if (operand instanceof AtomicValue) {
037: return BooleanValue.get(effectiveBooleanValue(env
038: .makeEarlyEvaluationContext()));
039: }
040: return this ;
041: }
042:
043: /**
044: * Type-check the expression
045: */
046:
047: public Expression typeCheck(StaticContext env,
048: ItemType contextItemType) throws XPathException {
049: operand = operand.typeCheck(env, contextItemType);
050: SequenceType atomicType = SequenceType.makeSequenceType(
051: Type.ANY_ATOMIC_TYPE,
052: (allowEmpty ? StaticProperty.ALLOWS_ZERO_OR_ONE
053: : StaticProperty.EXACTLY_ONE));
054:
055: RoleLocator role = new RoleLocator(RoleLocator.TYPE_OP,
056: "castable as", 0, null);
057: role.setSourceLocator(this );
058: try {
059: operand = TypeChecker.staticTypeCheck(operand, atomicType,
060: false, role, env);
061: } catch (XPathException err) {
062: return BooleanValue.FALSE;
063: }
064:
065: final TypeHierarchy th = env.getNamePool().getTypeHierarchy();
066: if (!CastExpression.isPossibleCast(operand.getItemType(th)
067: .getPrimitiveType(), targetType.getPrimitiveType())) {
068: return BooleanValue.FALSE;
069: }
070:
071: if (operand instanceof AtomicValue) {
072: return BooleanValue.get(effectiveBooleanValue(env
073: .makeEarlyEvaluationContext()));
074: }
075: return this ;
076: }
077:
078: /**
079: * Type-check the expression
080: */
081:
082: public Expression optimize(Optimizer opt, StaticContext env,
083: ItemType contextItemType) throws XPathException {
084: operand = operand.optimize(opt, env, contextItemType);
085: if (operand instanceof AtomicValue) {
086: return BooleanValue.get(effectiveBooleanValue(env
087: .makeEarlyEvaluationContext()));
088: }
089: return this ;
090: }
091:
092: /**
093: * Is this expression the same as another expression?
094: */
095:
096: public boolean equals(Object other) {
097: return super .equals(other)
098: && targetType == ((CastableExpression) other).targetType
099: && allowEmpty == ((CastableExpression) other).allowEmpty;
100: }
101:
102: /**
103: * Determine the data type of the result of the Castable expression
104: * @param th
105: */
106:
107: public ItemType getItemType(TypeHierarchy th) {
108: return Type.BOOLEAN_TYPE;
109: }
110:
111: public int computeCardinality() {
112: return StaticProperty.EXACTLY_ONE;
113: }
114:
115: /**
116: * Determine the special properties of this expression
117: * @return {@link StaticProperty#NON_CREATIVE}.
118: */
119:
120: public int computeSpecialProperties() {
121: int p = super .computeSpecialProperties();
122: return p | StaticProperty.NON_CREATIVE;
123: }
124:
125: /**
126: * Evaluate the expression
127: */
128:
129: public Item evaluateItem(XPathContext context) {
130: return BooleanValue.get(effectiveBooleanValue(context));
131: }
132:
133: public boolean effectiveBooleanValue(XPathContext context) {
134: try {
135: AtomicValue value = (AtomicValue) operand
136: .evaluateItem(context);
137: if (value == null) {
138: return allowEmpty;
139: }
140: if (targetType instanceof BuiltInAtomicType) {
141: return !(value.convert(targetType, context, true) instanceof ValidationErrorValue);
142: } else {
143: AtomicValue prim = value.convert(
144: (AtomicType) targetType.getBuiltInBaseType(),
145: context, true);
146: if (prim instanceof ValidationErrorValue) {
147: return false;
148: }
149: AtomicValue val = targetType.makeDerivedValue(prim,
150: prim.getStringValueCS(), true);
151: return !(val instanceof ValidationErrorValue);
152: }
153: } catch (XPathException err) {
154: return false;
155: }
156: }
157:
158: /**
159: * Give a string representation of the operator for use in diagnostics
160: * @return the operator, as a string
161: */
162:
163: protected String displayOperator(NamePool pool) {
164: return "castable as " + targetType.toString(pool);
165: }
166:
167: }
168:
169: //
170: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
171: // you may not use this file except in compliance with the License. You may obtain a copy of the
172: // License at http://www.mozilla.org/MPL/
173: //
174: // Software distributed under the License is distributed on an "AS IS" basis,
175: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
176: // See the License for the specific language governing rights and limitations under the License.
177: //
178: // The Original Code is: all this file.
179: //
180: // The Initial Developer of the Original Code is Michael H. Kay
181: //
182: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
183: //
184: // Contributor(s): none.
185: //
|