source: trunk/src/xmlpatterns/functions/qaggregatefns.cpp@ 5

Last change on this file since 5 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 12.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
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
56QT_BEGIN_NAMESPACE
57
58using namespace QPatternist;
59
60Item CountFN::evaluateSingleton(const DynamicContext::Ptr &context) const
61{
62 return Integer::fromValue(m_operands.first()->evaluateSequence(context)->count());
63}
64
65Expression::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
76Expression::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
98Expression::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
141Item 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
172Expression::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
218SequenceType::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
234Item 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
261Expression::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
300SequenceType::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
316QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.