use of org.exist.xquery.value.ComputableValue in project exist by eXist-db.
the class OpNumeric method eval.
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
final Sequence lseq = Atomize.atomize(getLeft().eval(contextSequence, contextItem));
final Sequence rseq = Atomize.atomize(getRight().eval(contextSequence, contextItem));
if (lseq.hasMany()) {
throw new XPathException(this, ErrorCodes.XPTY0004, "Too many operands at the left of " + operator.symbol);
}
if (rseq.hasMany()) {
throw new XPathException(this, ErrorCodes.XPTY0004, "Too many operands at the right of " + operator.symbol);
}
Sequence result;
if (rseq.isEmpty()) {
result = Sequence.EMPTY_SEQUENCE;
} else if (lseq.isEmpty()) {
result = Sequence.EMPTY_SEQUENCE;
} else {
Item lvalue = lseq.itemAt(0);
Item rvalue = rseq.itemAt(0);
try {
if (lvalue.getType() == Type.UNTYPED_ATOMIC || lvalue.getType() == Type.ATOMIC) {
lvalue = lvalue.convertTo(Type.NUMBER);
}
if (rvalue.getType() == Type.UNTYPED_ATOMIC || rvalue.getType() == Type.ATOMIC) {
rvalue = rvalue.convertTo(Type.NUMBER);
}
if (!(lvalue instanceof ComputableValue)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")' can not be an operand for " + operator.symbol);
}
if (!(rvalue instanceof ComputableValue)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(rvalue.getType()) + "(" + rvalue + ")' can not be an operand for " + operator.symbol);
}
// TODO : move to implementations
if (operator == ArithmeticOperator.DIVISION_INTEGER) {
if (!Type.subTypeOfUnion(lvalue.getType(), Type.NUMBER)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")' can not be an operand for " + operator.symbol);
}
if (!Type.subTypeOfUnion(rvalue.getType(), Type.NUMBER)) {
throw new XPathException(this, ErrorCodes.XPTY0004, "'" + Type.getTypeName(rvalue.getType()) + "(" + rvalue + ")' can not be an operand for " + operator.symbol);
}
// If the divisor is (positive or negative) zero, then an error is raised [err:FOAR0001]
if (((NumericValue) rvalue).isZero()) {
throw new XPathException(this, ErrorCodes.FOAR0001, "Division by zero");
}
// If either operand is NaN then an error is raised [err:FOAR0002].
if (((NumericValue) lvalue).isNaN()) {
throw new XPathException(this, ErrorCodes.FOAR0002, "Division of " + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")'");
}
// If either operand is NaN then an error is raised [err:FOAR0002].
if (((NumericValue) rvalue).isNaN()) {
throw new XPathException(this, ErrorCodes.FOAR0002, "Division of " + Type.getTypeName(rvalue.getType()) + "(" + rvalue + ")'");
}
// If $arg1 is INF or -INF then an error is raised [err:FOAR0002].
if (((NumericValue) lvalue).isInfinite()) {
throw new XPathException(this, ErrorCodes.FOAR0002, "Division of " + Type.getTypeName(lvalue.getType()) + "(" + lvalue + ")'");
}
result = ((NumericValue) lvalue).idiv((NumericValue) rvalue);
} else {
result = applyOperator((ComputableValue) lvalue, (ComputableValue) rvalue);
}
// TODO : type-checks on MOD operator : maybe the same ones than above -pb
} catch (final XPathException e) {
e.setLocation(line, column);
throw e;
}
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
// Sets the return type if not already set
if (returnType == Type.ATOMIC) // TODO : refine previously set type ? -pb
{
returnType = result.getItemType();
}
return result;
}
use of org.exist.xquery.value.ComputableValue in project exist by eXist-db.
the class FunMin method eval.
/* (non-Javadoc)
* @see org.exist.xquery.Expression#eval(org.exist.dom.persistent.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
*/
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
boolean computableProcessing = false;
Sequence result;
final Sequence arg = getArgument(0).eval(contextSequence, contextItem);
if (arg.isEmpty()) {
result = Sequence.EMPTY_SEQUENCE;
} else {
// TODO : test if a range index is defined *iff* it is compatible with the collator
final Collator collator = getCollator(contextSequence, contextItem, 2);
final SequenceIterator iter = arg.unorderedIterator();
AtomicValue min = null;
while (iter.hasNext()) {
final Item item = iter.nextItem();
if (item instanceof QNameValue) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(item.getType()), arg);
}
AtomicValue value = item.atomize();
// Duration values must either all be xs:yearMonthDuration values or must all be xs:dayTimeDuration values.
if (Type.subTypeOf(value.getType(), Type.DURATION)) {
value = ((DurationValue) value).wrap();
if (value.getType() == Type.YEAR_MONTH_DURATION) {
if (min != null && min.getType() != Type.YEAR_MONTH_DURATION) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
}
} else if (value.getType() == Type.DAY_TIME_DURATION) {
if (min != null && min.getType() != Type.DAY_TIME_DURATION) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
}
} else {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(value.getType()), value);
}
// Any value of type xdt:untypedAtomic is cast to xs:double
} else if (value.getType() == Type.UNTYPED_ATOMIC) {
value = value.convertTo(Type.DOUBLE);
}
if (min == null) {
min = value;
} else {
if (Type.getCommonSuperType(min.getType(), value.getType()) == Type.ATOMIC) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
}
// Any value of type xdt:untypedAtomic is cast to xs:double
if (value.getType() == Type.ATOMIC) {
value = value.convertTo(Type.DOUBLE);
}
// Numeric tests
if (Type.subTypeOfUnion(value.getType(), Type.NUMBER)) {
// Don't mix comparisons
if (!Type.subTypeOfUnion(min.getType(), Type.NUMBER)) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), min);
}
if (((NumericValue) value).isNaN()) {
// Type NaN correctly
value = value.promote(min);
if (value.getType() == Type.FLOAT) {
min = FloatValue.NaN;
} else {
min = DoubleValue.NaN;
}
// although result will be NaN, we need to continue on order to type correctly
continue;
}
min = min.promote(value);
}
// Ugly test
if (value instanceof ComputableValue) {
if (!(min instanceof ComputableValue)) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), min);
}
// Type value correctly
value = value.promote(min);
min = min.min(collator, value);
computableProcessing = true;
} else {
if (computableProcessing) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(min.getType()) + " and " + Type.getTypeName(value.getType()), value);
}
if (Collations.compare(collator, value.getStringValue(), min.getStringValue()) < 0) {
min = value;
}
}
}
}
result = min;
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
return result;
}
use of org.exist.xquery.value.ComputableValue in project exist by eXist-db.
the class FunAvg method eval.
/* (non-Javadoc)
* @see org.exist.xquery.Expression#eval(org.exist.dom.persistent.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
*/
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
Sequence result;
final Sequence inner = getArgument(0).eval(contextSequence, contextItem);
if (inner.isEmpty()) {
result = Sequence.EMPTY_SEQUENCE;
} else {
final SequenceIterator iter = inner.iterate();
Item item = iter.nextItem();
AtomicValue value = item.atomize();
// Any values of type xdt:untypedAtomic are cast to xs:double
if (value.getType() == Type.UNTYPED_ATOMIC) {
value = value.convertTo(Type.DOUBLE);
}
if (!(value instanceof ComputableValue)) {
throw new XPathException(this, ErrorCodes.FORG0006, Type.getTypeName(value.getType()) + "(" + value + ") " + "can not be an operand in a sum", value);
}
// Set the first value
ComputableValue sum = (ComputableValue) value;
while (iter.hasNext()) {
item = iter.nextItem();
value = item.atomize();
// Any value of type xdt:untypedAtomic are cast to xs:double
if (value.getType() == Type.UNTYPED_ATOMIC) {
value = value.convertTo(Type.DOUBLE);
}
if (!(value instanceof ComputableValue)) {
throw new XPathException(this, ErrorCodes.FORG0006, "" + Type.getTypeName(value.getType()) + "(" + value + ") can not be an operand in a sum", value);
}
if (Type.subTypeOfUnion(value.getType(), Type.NUMBER)) {
if (((NumericValue) value).isInfinite()) {
gotInfinity = true;
}
if (((NumericValue) value).isNaN()) {
sum = DoubleValue.NaN;
break;
}
}
try {
sum = (ComputableValue) sum.promote(value);
// Aggregate next values
sum = sum.plus((ComputableValue) value);
} catch (final XPathException e) {
throw new XPathException(this, ErrorCodes.FORG0006, e.getMessage());
}
}
result = sum.div(new IntegerValue(inner.getItemCount()));
}
if (!gotInfinity) {
if (Type.subTypeOfUnion(result.getItemType(), Type.NUMBER) && ((NumericValue) result).isInfinite()) {
// Throw an overflow exception here since we get an infinity
// whereas is hasn't been provided by the sequence
// TODO ? -pb
}
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
return result;
}
use of org.exist.xquery.value.ComputableValue in project exist by eXist-db.
the class FunSum method eval.
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
Sequence result;
final Sequence inner = getArgument(0).eval(contextSequence, contextItem);
if (inner.isEmpty()) {
// If $zero is not specified, then the value returned for an empty sequence is the xs:integer value 0
Sequence zero = IntegerValue.ZERO;
if (getSignature().getArgumentCount() == 2) {
zero = getArgument(1).eval(contextSequence, contextItem);
}
result = zero;
} else {
final SequenceIterator iter = inner.iterate();
Item item = iter.nextItem();
AtomicValue value = item.atomize();
value = check(value, null);
// Set the first value
ComputableValue sum = (ComputableValue) value;
while (iter.hasNext()) {
item = iter.nextItem();
value = item.atomize();
value = check(value, sum);
if (Type.subTypeOfUnion(value.getType(), Type.NUMBER)) {
if (((NumericValue) value).isInfinite()) {
gotInfinity = true;
}
if (((NumericValue) value).isNaN()) {
sum = DoubleValue.NaN;
break;
}
}
sum = (ComputableValue) sum.promote(value);
// Aggregate next values
sum = sum.plus((ComputableValue) value);
}
result = sum;
}
if (!gotInfinity) {
if (Type.subTypeOfUnion(result.getItemType(), Type.NUMBER) && ((NumericValue) result).isInfinite()) {
// Throw an overflow eception here since we get an infinity
// whereas is hasn't been provided by the sequence
}
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
return result;
}
use of org.exist.xquery.value.ComputableValue in project exist by eXist-db.
the class FunMax method eval.
/* (non-Javadoc)
* @see org.exist.xquery.Expression#eval(org.exist.dom.persistent.DocumentSet, org.exist.xquery.value.Sequence, org.exist.xquery.value.Item)
*/
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
context.getProfiler().message(this, Profiler.DEPENDENCIES, "DEPENDENCIES", Dependency.getDependenciesName(this.getDependencies()));
if (contextSequence != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT SEQUENCE", contextSequence);
}
if (contextItem != null) {
context.getProfiler().message(this, Profiler.START_SEQUENCES, "CONTEXT ITEM", contextItem.toSequence());
}
}
Sequence result;
final Sequence arg = getArgument(0).eval(contextSequence, contextItem);
if (arg.isEmpty()) {
result = Sequence.EMPTY_SEQUENCE;
} else {
boolean computableProcessing = false;
// TODO : test if a range index is defined *iff* it is compatible with the collator
final Collator collator = getCollator(contextSequence, contextItem, 2);
final SequenceIterator iter = arg.unorderedIterator();
AtomicValue max = null;
while (iter.hasNext()) {
final Item item = iter.nextItem();
if (item instanceof QNameValue) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(item.getType()), arg);
}
AtomicValue value = item.atomize();
// Duration values must either all be xs:yearMonthDuration values or must all be xs:dayTimeDuration values.
if (Type.subTypeOf(value.getType(), Type.DURATION)) {
value = ((DurationValue) value).wrap();
if (value.getType() == Type.YEAR_MONTH_DURATION) {
if (max != null && max.getType() != Type.YEAR_MONTH_DURATION) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(max.getType()) + " and " + Type.getTypeName(value.getType()), value);
}
} else if (value.getType() == Type.DAY_TIME_DURATION) {
if (max != null && max.getType() != Type.DAY_TIME_DURATION) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(max.getType()) + " and " + Type.getTypeName(value.getType()), value);
}
} else {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(value.getType()), value);
}
// Any value of type xdt:untypedAtomic is cast to xs:double
} else if (value.getType() == Type.UNTYPED_ATOMIC) {
value = value.convertTo(Type.DOUBLE);
}
if (max == null) {
max = value;
} else {
if (Type.getCommonSuperType(max.getType(), value.getType()) == Type.ATOMIC) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(max.getType()) + " and " + Type.getTypeName(value.getType()), max);
}
// Any value of type xdt:untypedAtomic is cast to xs:double
if (value.getType() == Type.UNTYPED_ATOMIC) {
value = value.convertTo(Type.DOUBLE);
}
// Numeric tests
if (Type.subTypeOfUnion(value.getType(), Type.NUMBER)) {
// Don't mix comparisons
if (!Type.subTypeOfUnion(max.getType(), Type.NUMBER)) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(max.getType()) + " and " + Type.getTypeName(value.getType()), max);
}
if (((NumericValue) value).isNaN()) {
// Type NaN correctly
value = value.promote(max);
if (value.getType() == Type.FLOAT) {
max = FloatValue.NaN;
} else {
max = DoubleValue.NaN;
}
// although result will be NaN, we need to continue on order to type correctly
continue;
} else {
max = max.promote(value);
}
}
// Ugly test
if (max instanceof ComputableValue && value instanceof ComputableValue) {
// Type value correctly
value = value.promote(max);
max = (ComputableValue) max.max(collator, value);
computableProcessing = true;
} else {
if (computableProcessing) {
throw new XPathException(this, ErrorCodes.FORG0006, "Cannot compare " + Type.getTypeName(max.getType()) + " and " + Type.getTypeName(value.getType()), max);
}
if (Collations.compare(collator, value.getStringValue(), max.getStringValue()) > 0) {
max = value;
}
}
}
}
result = max;
}
if (context.getProfiler().isEnabled()) {
context.getProfiler().end(this, "", result);
}
return result;
}
Aggregations