operand0 = TypeChecker.staticTypeCheck(operand0, atomicType, false, role0, visitor);
final ItemType itemType0 = operand0.getItemType(th);
if (itemType0 instanceof EmptySequenceTest) {
return new Literal(EmptySequence.getInstance());
}
AtomicType type0 = (AtomicType) itemType0.getPrimitiveItemType();
if (type0.getFingerprint() == StandardNames.XS_UNTYPED_ATOMIC) {
operand0 = new UntypedAtomicConverter(operand0, BuiltInAtomicType.DOUBLE, true, role0);
type0 = BuiltInAtomicType.DOUBLE;
} else if (/*!(operand0 instanceof UntypedAtomicConverter)*/
(operand0.getSpecialProperties()&StaticProperty.NOT_UNTYPED) == 0 &&
th.relationship(type0, BuiltInAtomicType.UNTYPED_ATOMIC) != TypeHierarchy.DISJOINT) {
operand0 = new UntypedAtomicConverter(operand0, BuiltInAtomicType.DOUBLE, false, role0);
type0 = (AtomicType)operand0.getItemType(th);
}
// System.err.println("First operand"); operand0.display(10);
RoleLocator role1 = new RoleLocator(RoleLocator.BINARY_EXPR, Token.tokens[operator], 1);
//role1.setSourceLocator(this);
operand1 = TypeChecker.staticTypeCheck(operand1, atomicType, false, role1, visitor);
final ItemType itemType1 = operand1.getItemType(th);
if (itemType1 instanceof EmptySequenceTest) {
return new Literal(EmptySequence.getInstance());
}
AtomicType type1 = (AtomicType)itemType1.getPrimitiveItemType();
if (type1.getFingerprint() == StandardNames.XS_UNTYPED_ATOMIC) {
operand1 = new UntypedAtomicConverter(operand1, BuiltInAtomicType.DOUBLE, true, role1);
type1 = BuiltInAtomicType.DOUBLE;
} else if (/*!(operand1 instanceof UntypedAtomicConverter) &&*/
(operand1.getSpecialProperties()&StaticProperty.NOT_UNTYPED) == 0 &&
th.relationship(type1, BuiltInAtomicType.UNTYPED_ATOMIC) != TypeHierarchy.DISJOINT) {
operand1 = new UntypedAtomicConverter(operand1, BuiltInAtomicType.DOUBLE, false, role1);
type1 = (AtomicType)operand1.getItemType(th);
}
if (operand0 != oldOp0) {
adoptChildExpression(operand0);
}
if (operand1 != oldOp1) {
adoptChildExpression(operand1);
}
if (Literal.isEmptySequence(operand0) ||
Literal.isEmptySequence(operand1)) {
return new Literal(EmptySequence.getInstance());
}
if (type0.isExternalType() || type1.isExternalType()) {
XPathException de = new XPathException("Arithmetic operators are not defined for external objects");
de.setLocator(this);
de.setErrorCode("XPTY0004");
throw de;
}
if (operator == Token.NEGATE) {
if (operand1 instanceof Literal && ((Literal)operand1).getValue() instanceof NumericValue) {
NumericValue nv = (NumericValue)((Literal)operand1).getValue();
return new Literal(nv.negate());
} else {
NegateExpression ne = new NegateExpression(operand1);
ne.setBackwardsCompatible(false);
return visitor.typeCheck(ne, contextItemType);
}
}
// Get a calculator to implement the arithmetic operation. If the types are not yet specifically known,
// we allow this to return an "ANY" calculator which defers the decision. However, we only allow this if
// at least one of the operand types is AnyAtomicType or (otherwise unspecified) numeric.
boolean mustResolve = !(type0.equals(BuiltInAtomicType.ANY_ATOMIC) || type1.equals(BuiltInAtomicType.ANY_ATOMIC)
|| type0.equals(BuiltInAtomicType.NUMERIC) || type1.equals(BuiltInAtomicType.NUMERIC));
calculator = Calculator.getCalculator(
type0.getFingerprint(), type1.getFingerprint(), mapOpCode(operator), mustResolve);
if (calculator == null) {
XPathException de = new XPathException("Arithmetic operator is not defined for arguments of types (" +
type0.getDescription() + ", " + type1.getDescription() + ")");
de.setLocator(this);
de.setErrorCode("XPTY0004");
throw de;
}