/**************************************************************************** ** ** 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