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