1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qabstractfloat_p.h"
43 #include "qarithmeticexpression_p.h"
44 #include "qbuiltintypes_p.h"
45 #include "qcommonsequencetypes_p.h"
46 #include "qcommonvalues_p.h"
47 #include "qdecimal_p.h"
48 #include "qgenericsequencetype_p.h"
49 #include "qinteger_p.h"
50 #include "qoptimizerblocks_p.h"
51 #include "qsequencefns_p.h"
52 #include "quntypedatomicconverter_p.h"
54 #include "qaggregatefns_p.h"
58 using namespace QPatternist;
60 Item CountFN::evaluateSingleton(const DynamicContext::Ptr &context) const
62 return Integer::fromValue(m_operands.first()->evaluateSequence(context)->count());
65 Expression::Ptr CountFN::typeCheck(const StaticContext::Ptr &context,
66 const SequenceType::Ptr &reqType)
68 if(*CommonSequenceTypes::EBV->itemType() == *reqType->itemType())
70 return ByIDCreator::create(IDExistsFN, operands(), context, this)->typeCheck(context, reqType);
73 return FunctionCall::typeCheck(context, reqType);
76 Expression::Ptr CountFN::compress(const StaticContext::Ptr &context)
78 const Expression::Ptr me(FunctionCall::compress(context));
82 const Cardinality card(m_operands.first()->staticType()->cardinality());
83 if(card.isExactlyOne())
84 return wrapLiteral(CommonValues::IntegerOne, context, this);
85 else if(card.isEmpty())
87 /* One might think that if the operand is (), that compress() would have
88 * evaluated us and therefore this line never be reached, but "()" can
89 * be combined with the DisableElimination flag. */
90 return wrapLiteral(CommonValues::IntegerZero, context, this);
92 else if(card.isExact())
93 return wrapLiteral(Integer::fromValue(card.minimum()), context, this);
98 Expression::Ptr AddingAggregate::typeCheck(const StaticContext::Ptr &context,
99 const SequenceType::Ptr &reqType)
101 const Expression::Ptr me(FunctionCall::typeCheck(context, reqType));
102 ItemType::Ptr t1(m_operands.first()->staticType()->itemType());
104 if(*CommonSequenceTypes::Empty == *t1)
106 else if(*BuiltinTypes::xsAnyAtomicType == *t1 ||
107 *BuiltinTypes::numeric == *t1)
109 else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1))
111 m_operands.replace(0, Expression::Ptr(new UntypedAtomicConverter(m_operands.first(),
112 BuiltinTypes::xsDouble)));
113 t1 = m_operands.first()->staticType()->itemType();
115 else if(!BuiltinTypes::numeric->xdtTypeMatches(t1) &&
116 !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t1) &&
117 !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1))
119 /* Translator, don't translate the type names. */
120 context->error(QtXmlPatterns::tr("The first argument to %1 cannot be "
121 "of type %2. It must be a numeric "
122 "type, xs:yearMonthDuration or "
123 "xs:dayTimeDuration.")
124 .arg(formatFunction(context->namePool(), signature()))
125 .arg(formatType(context->namePool(),
126 m_operands.first()->staticType())),
127 ReportContext::FORG0006, this);
130 if(!m_operands.first()->staticType()->cardinality().allowsMany())
131 return m_operands.first();
133 /* We know fetchMathematician won't attempt a rewrite of the operand, so this is safe. */
134 m_mather = ArithmeticExpression::fetchMathematician(m_operands.first(), m_operands.first(),
135 AtomicMathematician::Add, true, context,
137 ReportContext::FORG0006);
141 Item AvgFN::evaluateSingleton(const DynamicContext::Ptr &context) const
143 const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));
144 Item sum(it->next());
150 const Item next(it->next());
154 sum = ArithmeticExpression::flexiblyCalculate(sum, AtomicMathematician::Add,
155 next, m_adder, context,
157 ReportContext::FORG0006);
163 /* Note that we use the same m_mather which was used for adding,
164 * can be worth to think about. */
165 return ArithmeticExpression::flexiblyCalculate(sum, AtomicMathematician::Div,
166 Integer::fromValue(count),
169 ReportContext::FORG0006);
172 Expression::Ptr AvgFN::typeCheck(const StaticContext::Ptr &context,
173 const SequenceType::Ptr &reqType)
175 const Expression::Ptr me(FunctionCall::typeCheck(context, reqType));
176 ItemType::Ptr t1(m_operands.first()->staticType()->itemType());
178 if(*CommonSequenceTypes::Empty == *t1)
180 else if(*BuiltinTypes::xsAnyAtomicType == *t1 ||
181 *BuiltinTypes::numeric == *t1)
183 else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1))
185 m_operands.replace(0, Expression::Ptr(new UntypedAtomicConverter(m_operands.first(),
186 BuiltinTypes::xsDouble)));
187 t1 = m_operands.first()->staticType()->itemType();
189 else if(!BuiltinTypes::numeric->xdtTypeMatches(t1) &&
190 !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t1) &&
191 !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1))
193 /* Translator, don't translate the type names. */
194 context->error(QtXmlPatterns::tr("The first argument to %1 cannot be "
195 "of type %2. It must be of type %3, "
198 .arg(formatType(context->namePool(), m_operands.first()->staticType()))
199 .arg(formatType(context->namePool(), BuiltinTypes::numeric))
200 .arg(formatType(context->namePool(), BuiltinTypes::xsYearMonthDuration))
201 .arg(formatType(context->namePool(), BuiltinTypes::xsDayTimeDuration)),
202 ReportContext::FORG0006, this);
205 if(!m_operands.first()->staticType()->cardinality().allowsMany())
206 return m_operands.first();
208 /* We use CommonValues::IntegerOne here because it is an arbitrary Expression
209 * of type xs:integer */
210 Expression::Ptr op2(wrapLiteral(CommonValues::IntegerOne, context, this));
211 m_adder = ArithmeticExpression::fetchMathematician(m_operands.first(), m_operands.first(),
212 AtomicMathematician::Add, true, context, this);
213 m_divider = ArithmeticExpression::fetchMathematician(m_operands.first(), op2,
214 AtomicMathematician::Div, true, context, this);
218 SequenceType::Ptr AvgFN::staticType() const
220 const SequenceType::Ptr opt(m_operands.first()->staticType());
221 ItemType::Ptr t(opt->itemType());
223 if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t))
224 t = BuiltinTypes::xsDouble; /* xsUntypedAtomics are converted to xsDouble. */
225 else if(BuiltinTypes::xsInteger->xdtTypeMatches(t))
226 t = BuiltinTypes::xsDecimal;
228 /* else, it means the type is xsDayTimeDuration, xsYearMonthDuration,
229 * xsDouble, xsFloat or xsAnyAtomicType, which we use as is. */
230 return makeGenericSequenceType(BuiltinTypes::xsAnyAtomicType->xdtTypeMatches(t) ? t : ItemType::Ptr(BuiltinTypes::xsAnyAtomicType),
231 opt->cardinality().toWithoutMany());
234 Item SumFN::evaluateSingleton(const DynamicContext::Ptr &context) const
236 const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));
237 Item sum(it->next());
241 const Item next(it->next());
245 sum = ArithmeticExpression::flexiblyCalculate(sum, AtomicMathematician::Add,
246 next, m_mather, context, this,
247 ReportContext::FORG0006);
252 if(m_operands.count() == 1)
253 return CommonValues::IntegerZero;
255 return m_operands.last()->evaluateSingleton(context);
261 Expression::Ptr SumFN::typeCheck(const StaticContext::Ptr &context,
262 const SequenceType::Ptr &reqType)
264 const Expression::Ptr me(AddingAggregate::typeCheck(context, reqType));
266 if(*CommonSequenceTypes::Empty == *m_operands.first()->staticType()->itemType())
268 if(m_operands.count() == 1)
269 return wrapLiteral(CommonValues::IntegerZero, context, this);
271 return m_operands.at(1);
274 if(m_operands.count() == 1)
277 const ItemType::Ptr t(m_operands.at(1)->staticType()->itemType());
279 if(!BuiltinTypes::numeric->xdtTypeMatches(t) &&
280 !BuiltinTypes::xsAnyAtomicType->xdtTypeMatches(t) &&
281 *CommonSequenceTypes::Empty != *t &&
282 !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t) &&
283 !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t))
285 context->error(QtXmlPatterns::tr("The second argument to %1 cannot be "
286 "of type %2. It must be of type %3, "
288 .arg(formatFunction(context->namePool(), signature()))
289 .arg(formatType(context->namePool(), m_operands.at(1)->staticType()))
290 .arg(formatType(context->namePool(), BuiltinTypes::numeric))
291 .arg(formatType(context->namePool(), BuiltinTypes::xsYearMonthDuration))
292 .arg(formatType(context->namePool(), BuiltinTypes::xsDayTimeDuration)),
293 ReportContext::FORG0006, this);
300 SequenceType::Ptr SumFN::staticType() const
302 const SequenceType::Ptr t(m_operands.first()->staticType());
304 if(m_operands.count() == 1)
306 return makeGenericSequenceType(t->itemType() | BuiltinTypes::xsInteger,
307 Cardinality::exactlyOne());
311 return makeGenericSequenceType(t->itemType() | m_operands.at(1)->staticType()->itemType(),
312 t->cardinality().toWithoutMany());