1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
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"
53
54 #include "qaggregatefns_p.h"
55
56 QT_BEGIN_NAMESPACE
57
58 using namespace QPatternist;
59
evaluateSingleton(const DynamicContext::Ptr & context) const60 Item CountFN::evaluateSingleton(const DynamicContext::Ptr &context) const
61 {
62 return Integer::fromValue(m_operands.first()->evaluateSequence(context)->count());
63 }
64
typeCheck(const StaticContext::Ptr & context,const SequenceType::Ptr & reqType)65 Expression::Ptr CountFN::typeCheck(const StaticContext::Ptr &context,
66 const SequenceType::Ptr &reqType)
67 {
68 if(*CommonSequenceTypes::EBV->itemType() == *reqType->itemType())
69 {
70 return ByIDCreator::create(IDExistsFN, operands(), context, this)->typeCheck(context, reqType);
71 }
72 else
73 return FunctionCall::typeCheck(context, reqType);
74 }
75
compress(const StaticContext::Ptr & context)76 Expression::Ptr CountFN::compress(const StaticContext::Ptr &context)
77 {
78 const Expression::Ptr me(FunctionCall::compress(context));
79 if(me != this)
80 return me;
81
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())
86 {
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);
91 }
92 else if(card.isExact())
93 return wrapLiteral(Integer::fromValue(card.minimum()), context, this);
94 else
95 return me;
96 }
97
typeCheck(const StaticContext::Ptr & context,const SequenceType::Ptr & reqType)98 Expression::Ptr AddingAggregate::typeCheck(const StaticContext::Ptr &context,
99 const SequenceType::Ptr &reqType)
100 {
101 const Expression::Ptr me(FunctionCall::typeCheck(context, reqType));
102 ItemType::Ptr t1(m_operands.first()->staticType()->itemType());
103
104 if(*CommonSequenceTypes::Empty == *t1)
105 return me;
106 else if(*BuiltinTypes::xsAnyAtomicType == *t1 ||
107 *BuiltinTypes::numeric == *t1)
108 return me;
109 else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1))
110 {
111 m_operands.replace(0, Expression::Ptr(new UntypedAtomicConverter(m_operands.first(),
112 BuiltinTypes::xsDouble)));
113 t1 = m_operands.first()->staticType()->itemType();
114 }
115 else if(!BuiltinTypes::numeric->xdtTypeMatches(t1) &&
116 !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t1) &&
117 !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1))
118 {
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);
128 }
129
130 if(!m_operands.first()->staticType()->cardinality().allowsMany())
131 return m_operands.first();
132
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,
136 this,
137 ReportContext::FORG0006);
138 return me;
139 }
140
evaluateSingleton(const DynamicContext::Ptr & context) const141 Item AvgFN::evaluateSingleton(const DynamicContext::Ptr &context) const
142 {
143 const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));
144 Item sum(it->next());
145
146 xsInteger count = 0;
147 while(sum)
148 {
149 ++count;
150 const Item next(it->next());
151 if(!next)
152 break;
153
154 sum = ArithmeticExpression::flexiblyCalculate(sum, AtomicMathematician::Add,
155 next, m_adder, context,
156 this,
157 ReportContext::FORG0006);
158 };
159
160 if(!sum)
161 return Item();
162
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),
167 m_divider, context,
168 this,
169 ReportContext::FORG0006);
170 }
171
typeCheck(const StaticContext::Ptr & context,const SequenceType::Ptr & reqType)172 Expression::Ptr AvgFN::typeCheck(const StaticContext::Ptr &context,
173 const SequenceType::Ptr &reqType)
174 {
175 const Expression::Ptr me(FunctionCall::typeCheck(context, reqType));
176 ItemType::Ptr t1(m_operands.first()->staticType()->itemType());
177
178 if(*CommonSequenceTypes::Empty == *t1)
179 return me;
180 else if(*BuiltinTypes::xsAnyAtomicType == *t1 ||
181 *BuiltinTypes::numeric == *t1)
182 return me;
183 else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1))
184 {
185 m_operands.replace(0, Expression::Ptr(new UntypedAtomicConverter(m_operands.first(),
186 BuiltinTypes::xsDouble)));
187 t1 = m_operands.first()->staticType()->itemType();
188 }
189 else if(!BuiltinTypes::numeric->xdtTypeMatches(t1) &&
190 !BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t1) &&
191 !BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1))
192 {
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, "
196 "%4, or %5.")
197 .arg(signature())
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);
203 }
204
205 if(!m_operands.first()->staticType()->cardinality().allowsMany())
206 return m_operands.first();
207
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);
215 return me;
216 }
217
staticType() const218 SequenceType::Ptr AvgFN::staticType() const
219 {
220 const SequenceType::Ptr opt(m_operands.first()->staticType());
221 ItemType::Ptr t(opt->itemType());
222
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;
227
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());
232 }
233
evaluateSingleton(const DynamicContext::Ptr & context) const234 Item SumFN::evaluateSingleton(const DynamicContext::Ptr &context) const
235 {
236 const Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context));
237 Item sum(it->next());
238
239 while(sum)
240 {
241 const Item next(it->next());
242 if(!next)
243 break;
244
245 sum = ArithmeticExpression::flexiblyCalculate(sum, AtomicMathematician::Add,
246 next, m_mather, context, this,
247 ReportContext::FORG0006);
248 };
249
250 if(!sum)
251 {
252 if(m_operands.count() == 1)
253 return CommonValues::IntegerZero;
254 else
255 return m_operands.last()->evaluateSingleton(context);
256 }
257
258 return sum;
259 }
260
typeCheck(const StaticContext::Ptr & context,const SequenceType::Ptr & reqType)261 Expression::Ptr SumFN::typeCheck(const StaticContext::Ptr &context,
262 const SequenceType::Ptr &reqType)
263 {
264 const Expression::Ptr me(AddingAggregate::typeCheck(context, reqType));
265
266 if(*CommonSequenceTypes::Empty == *m_operands.first()->staticType()->itemType())
267 {
268 if(m_operands.count() == 1)
269 return wrapLiteral(CommonValues::IntegerZero, context, this);
270 else
271 return m_operands.at(1);
272 }
273
274 if(m_operands.count() == 1)
275 return me;
276
277 const ItemType::Ptr t(m_operands.at(1)->staticType()->itemType());
278
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))
284 {
285 context->error(QtXmlPatterns::tr("The second argument to %1 cannot be "
286 "of type %2. It must be of type %3, "
287 "%4, or %5.")
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);
294 return me;
295 }
296
297 return me;
298 }
299
staticType() const300 SequenceType::Ptr SumFN::staticType() const
301 {
302 const SequenceType::Ptr t(m_operands.first()->staticType());
303
304 if(m_operands.count() == 1)
305 {
306 return makeGenericSequenceType(t->itemType() | BuiltinTypes::xsInteger,
307 Cardinality::exactlyOne());
308 }
309 else
310 {
311 return makeGenericSequenceType(t->itemType() | m_operands.at(1)->staticType()->itemType(),
312 t->cardinality().toWithoutMany());
313 }
314 }
315
316 QT_END_NAMESPACE
317