|  | /**************************************************************************** | 
|  | ** | 
|  | ** Copyright (C) 2016 The Qt Company Ltd. | 
|  | ** Contact: https://www.qt.io/licensing/ | 
|  | ** | 
|  | ** This file is part of the QtXmlPatterns module of the Qt Toolkit. | 
|  | ** | 
|  | ** $QT_BEGIN_LICENSE:LGPL$ | 
|  | ** Commercial License Usage | 
|  | ** Licensees holding valid commercial Qt licenses may use this file in | 
|  | ** accordance with the commercial license agreement provided with the | 
|  | ** Software or, alternatively, in accordance with the terms contained in | 
|  | ** a written agreement between you and The Qt Company. For licensing terms | 
|  | ** and conditions see https://www.qt.io/terms-conditions. For further | 
|  | ** information use the contact form at https://www.qt.io/contact-us. | 
|  | ** | 
|  | ** GNU Lesser General Public License Usage | 
|  | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
|  | ** General Public License version 3 as published by the Free Software | 
|  | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | 
|  | ** packaging of this file. Please review the following information to | 
|  | ** ensure the GNU Lesser General Public License version 3 requirements | 
|  | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | 
|  | ** | 
|  | ** GNU General Public License Usage | 
|  | ** Alternatively, this file may be used under the terms of the GNU | 
|  | ** General Public License version 2.0 or (at your option) the GNU General | 
|  | ** Public license version 3 or any later version approved by the KDE Free | 
|  | ** Qt Foundation. The licenses are as published by the Free Software | 
|  | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
|  | ** included in the packaging of this file. Please review the following | 
|  | ** information to ensure the GNU General Public License requirements will | 
|  | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
|  | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
|  | ** | 
|  | ** $QT_END_LICENSE$ | 
|  | ** | 
|  | ****************************************************************************/ | 
|  |  | 
|  | #include "qabstractfloat_p.h" | 
|  | #include "qarithmeticexpression_p.h" | 
|  | #include "qbuiltintypes_p.h" | 
|  | #include "qcommonsequencetypes_p.h" | 
|  | #include "qcommonvalues_p.h" | 
|  | #include "qdecimal_p.h" | 
|  | #include "qgenericsequencetype_p.h" | 
|  | #include "qinteger_p.h" | 
|  | #include "qoptimizerblocks_p.h" | 
|  | #include "qsequencefns_p.h" | 
|  | #include "quntypedatomicconverter_p.h" | 
|  |  | 
|  | #include "qaggregatefns_p.h" | 
|  |  | 
|  | QT_BEGIN_NAMESPACE | 
|  |  | 
|  | using namespace QPatternist; | 
|  |  | 
|  | Item CountFN::evaluateSingleton(const DynamicContext::Ptr &context) const | 
|  | { | 
|  | return Integer::fromValue(m_operands.first()->evaluateSequence(context)->count()); | 
|  | } | 
|  |  | 
|  | Expression::Ptr CountFN::typeCheck(const StaticContext::Ptr &context, | 
|  | const SequenceType::Ptr &reqType) | 
|  | { | 
|  | if(*CommonSequenceTypes::EBV->itemType() == *reqType->itemType()) | 
|  | { | 
|  | return ByIDCreator::create(IDExistsFN, operands(), context, this)->typeCheck(context, reqType); | 
|  | } | 
|  | else | 
|  | return FunctionCall::typeCheck(context, reqType); | 
|  | } | 
|  |  | 
|  | Expression::Ptr CountFN::compress(const StaticContext::Ptr &context) | 
|  | { | 
|  | const Expression::Ptr me(FunctionCall::compress(context)); | 
|  | if(me != this) | 
|  | return me; | 
|  |  | 
|  | const Cardinality card(m_operands.first()->staticType()->cardinality()); | 
|  | if(card.isExactlyOne()) | 
|  | return wrapLiteral(CommonValues::IntegerOne, context, this); | 
|  | else if(card.isEmpty()) | 
|  | { | 
|  | /* One might think that if the operand is (), that compress() would have | 
|  | * evaluated us and therefore this line never be reached, but "()" can | 
|  | * be combined with the DisableElimination flag. */ | 
|  | return wrapLiteral(CommonValues::IntegerZero, context, this); | 
|  | } | 
|  | else if(card.isExact()) | 
|  | return wrapLiteral(Integer::fromValue(card.minimum()), context, this); | 
|  | else | 
|  | return me; | 
|  | } | 
|  |  | 
|  | Expression::Ptr AddingAggregate::typeCheck(const StaticContext::Ptr &context, | 
|  | const SequenceType::Ptr &reqType) | 
|  | { | 
|  | const Expression::Ptr me(FunctionCall::typeCheck(context, reqType)); | 
|  | ItemType::Ptr t1(m_operands.first()->staticType()->itemType()); | 
|  |  | 
|  | if(*CommonSequenceTypes::Empty == *t1) | 
|  | return me; | 
|  | else if(*BuiltinTypes::xsAnyAtomicType == *t1 || | 
|  | *BuiltinTypes::numeric == *t1) | 
|  | return me; | 
|  | else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1)) | 
|  | { | 
|  | m_operands.replace(0, Expression::Ptr(new UntypedAtomicConverter(m_operands.first(), | 
|  | BuiltinTypes::xsDouble))); | 
|  | t1 = m_operands.first()->staticType()->itemType(); | 
|  | } | 
|  | else if(!BuiltinTypes::numeric->xdtTypeMatches(t1) && | 
|  | !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t1) && | 
|  | !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1)) | 
|  | { | 
|  | /* Translator, don't translate the type names. */ | 
|  | context->error(QtXmlPatterns::tr("The first argument to %1 cannot be " | 
|  | "of type %2. It must be a numeric " | 
|  | "type, xs:yearMonthDuration or " | 
|  | "xs:dayTimeDuration.") | 
|  | .arg(formatFunction(context->namePool(), signature())) | 
|  | .arg(formatType(context->namePool(), | 
|  | m_operands.first()->staticType())), | 
|  | ReportContext::FORG0006, this); | 
|  | } | 
|  |  | 
|  | if(!m_operands.first()->staticType()->cardinality().allowsMany()) | 
|  | return m_operands.first(); | 
|  |  | 
|  | /* We know fetchMathematician won't attempt a rewrite of the operand, so this is safe. */ | 
|  | m_mather = ArithmeticExpression::fetchMathematician(m_operands.first(), m_operands.first(), | 
|  | AtomicMathematician::Add, true, context, | 
|  | this, | 
|  | ReportContext::FORG0006); | 
|  | return me; | 
|  | } | 
|  |  | 
|  | Item AvgFN::evaluateSingleton(const DynamicContext::Ptr &context) const | 
|  | { | 
|  | const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context)); | 
|  | Item sum(it->next()); | 
|  |  | 
|  | xsInteger count = 0; | 
|  | while(sum) | 
|  | { | 
|  | ++count; | 
|  | const Item next(it->next()); | 
|  | if(!next) | 
|  | break; | 
|  |  | 
|  | sum = ArithmeticExpression::flexiblyCalculate(sum, AtomicMathematician::Add, | 
|  | next, m_adder, context, | 
|  | this, | 
|  | ReportContext::FORG0006); | 
|  | }; | 
|  |  | 
|  | if(!sum) | 
|  | return Item(); | 
|  |  | 
|  | /* Note that we use the same m_mather which was used for adding, | 
|  | * can be worth to think about. */ | 
|  | return ArithmeticExpression::flexiblyCalculate(sum, AtomicMathematician::Div, | 
|  | Integer::fromValue(count), | 
|  | m_divider, context, | 
|  | this, | 
|  | ReportContext::FORG0006); | 
|  | } | 
|  |  | 
|  | Expression::Ptr AvgFN::typeCheck(const StaticContext::Ptr &context, | 
|  | const SequenceType::Ptr &reqType) | 
|  | { | 
|  | const Expression::Ptr me(FunctionCall::typeCheck(context, reqType)); | 
|  | ItemType::Ptr t1(m_operands.first()->staticType()->itemType()); | 
|  |  | 
|  | if(*CommonSequenceTypes::Empty == *t1) | 
|  | return me; | 
|  | else if(*BuiltinTypes::xsAnyAtomicType == *t1 || | 
|  | *BuiltinTypes::numeric == *t1) | 
|  | return me; | 
|  | else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1)) | 
|  | { | 
|  | m_operands.replace(0, Expression::Ptr(new UntypedAtomicConverter(m_operands.first(), | 
|  | BuiltinTypes::xsDouble))); | 
|  | t1 = m_operands.first()->staticType()->itemType(); | 
|  | } | 
|  | else if(!BuiltinTypes::numeric->xdtTypeMatches(t1) && | 
|  | !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t1) && | 
|  | !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1)) | 
|  | { | 
|  | /* Translator, don't translate the type names. */ | 
|  | context->error(QtXmlPatterns::tr("The first argument to %1 cannot be " | 
|  | "of type %2. It must be of type %3, " | 
|  | "%4, or %5.") | 
|  | .arg(signature()) | 
|  | .arg(formatType(context->namePool(), m_operands.first()->staticType())) | 
|  | .arg(formatType(context->namePool(), BuiltinTypes::numeric)) | 
|  | .arg(formatType(context->namePool(), BuiltinTypes::xsYearMonthDuration)) | 
|  | .arg(formatType(context->namePool(), BuiltinTypes::xsDayTimeDuration)), | 
|  | ReportContext::FORG0006, this); | 
|  | } | 
|  |  | 
|  | if(!m_operands.first()->staticType()->cardinality().allowsMany()) | 
|  | return m_operands.first(); | 
|  |  | 
|  | /* We use CommonValues::IntegerOne here because it is an arbitrary Expression | 
|  | * of type xs:integer */ | 
|  | Expression::Ptr op2(wrapLiteral(CommonValues::IntegerOne, context, this)); | 
|  | m_adder = ArithmeticExpression::fetchMathematician(m_operands.first(), m_operands.first(), | 
|  | AtomicMathematician::Add, true, context, this); | 
|  | m_divider = ArithmeticExpression::fetchMathematician(m_operands.first(), op2, | 
|  | AtomicMathematician::Div, true, context, this); | 
|  | return me; | 
|  | } | 
|  |  | 
|  | SequenceType::Ptr AvgFN::staticType() const | 
|  | { | 
|  | const SequenceType::Ptr opt(m_operands.first()->staticType()); | 
|  | ItemType::Ptr t(opt->itemType()); | 
|  |  | 
|  | if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t)) | 
|  | t = BuiltinTypes::xsDouble; /* xsUntypedAtomics are converted to xsDouble. */ | 
|  | else if(BuiltinTypes::xsInteger->xdtTypeMatches(t)) | 
|  | t = BuiltinTypes::xsDecimal; | 
|  |  | 
|  | /* else, it means the type is xsDayTimeDuration, xsYearMonthDuration, | 
|  | * xsDouble, xsFloat or xsAnyAtomicType, which we use as is. */ | 
|  | return makeGenericSequenceType(BuiltinTypes::xsAnyAtomicType->xdtTypeMatches(t) ? t : ItemType::Ptr(BuiltinTypes::xsAnyAtomicType), | 
|  | opt->cardinality().toWithoutMany()); | 
|  | } | 
|  |  | 
|  | Item SumFN::evaluateSingleton(const DynamicContext::Ptr &context) const | 
|  | { | 
|  | const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context)); | 
|  | Item sum(it->next()); | 
|  |  | 
|  | while(sum) | 
|  | { | 
|  | const Item next(it->next()); | 
|  | if(!next) | 
|  | break; | 
|  |  | 
|  | sum = ArithmeticExpression::flexiblyCalculate(sum, AtomicMathematician::Add, | 
|  | next, m_mather, context, this, | 
|  | ReportContext::FORG0006); | 
|  | }; | 
|  |  | 
|  | if(!sum) | 
|  | { | 
|  | if(m_operands.count() == 1) | 
|  | return CommonValues::IntegerZero; | 
|  | else | 
|  | return m_operands.last()->evaluateSingleton(context); | 
|  | } | 
|  |  | 
|  | return sum; | 
|  | } | 
|  |  | 
|  | Expression::Ptr SumFN::typeCheck(const StaticContext::Ptr &context, | 
|  | const SequenceType::Ptr &reqType) | 
|  | { | 
|  | const Expression::Ptr me(AddingAggregate::typeCheck(context, reqType)); | 
|  |  | 
|  | if(*CommonSequenceTypes::Empty == *m_operands.first()->staticType()->itemType()) | 
|  | { | 
|  | if(m_operands.count() == 1) | 
|  | return wrapLiteral(CommonValues::IntegerZero, context, this); | 
|  | else | 
|  | return m_operands.at(1); | 
|  | } | 
|  |  | 
|  | if(m_operands.count() == 1) | 
|  | return me; | 
|  |  | 
|  | const ItemType::Ptr t(m_operands.at(1)->staticType()->itemType()); | 
|  |  | 
|  | if(!BuiltinTypes::numeric->xdtTypeMatches(t) && | 
|  | !BuiltinTypes::xsAnyAtomicType->xdtTypeMatches(t) && | 
|  | *CommonSequenceTypes::Empty != *t && | 
|  | !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t) && | 
|  | !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t)) | 
|  | { | 
|  | context->error(QtXmlPatterns::tr("The second argument to %1 cannot be " | 
|  | "of type %2. It must be of type %3, " | 
|  | "%4, or %5.") | 
|  | .arg(formatFunction(context->namePool(), signature())) | 
|  | .arg(formatType(context->namePool(), m_operands.at(1)->staticType())) | 
|  | .arg(formatType(context->namePool(), BuiltinTypes::numeric)) | 
|  | .arg(formatType(context->namePool(), BuiltinTypes::xsYearMonthDuration)) | 
|  | .arg(formatType(context->namePool(), BuiltinTypes::xsDayTimeDuration)), | 
|  | ReportContext::FORG0006, this); | 
|  | return me; | 
|  | } | 
|  |  | 
|  | return me; | 
|  | } | 
|  |  | 
|  | SequenceType::Ptr SumFN::staticType() const | 
|  | { | 
|  | const SequenceType::Ptr t(m_operands.first()->staticType()); | 
|  |  | 
|  | if(m_operands.count() == 1) | 
|  | { | 
|  | return makeGenericSequenceType(t->itemType() | BuiltinTypes::xsInteger, | 
|  | Cardinality::exactlyOne()); | 
|  | } | 
|  | else | 
|  | { | 
|  | return makeGenericSequenceType(t->itemType() | m_operands.at(1)->staticType()->itemType(), | 
|  | t->cardinality().toWithoutMany()); | 
|  | } | 
|  | } | 
|  |  | 
|  | QT_END_NAMESPACE |