1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
46 #include "qabstractdatetime_p.h"
47 #include "qabstractduration_p.h"
48 #include "qabstractfloat_p.h"
49 #include "qdaytimeduration_p.h"
50 #include "qdecimal_p.h"
51 #include "qinteger_p.h"
52 #include "qpatternistlocale_p.h"
54 #include "qatomicmathematicians_p.h"
58 using namespace QPatternist
;
60 /* The translation strings is place here once, in order to reduce work for translators,
61 * and provide consistency. */
63 static inline QString
idivZeroInvalid()
65 return QtXmlPatterns::tr("Integer division (%1) by zero (%2) is undefined.")
66 .arg(formatKeyword("idiv"))
67 .arg(formatData("0"));
70 static inline QString
divZeroInvalid()
72 return QtXmlPatterns::tr("Division (%1) by zero (%2) is undefined.")
73 .arg(formatKeyword("div"))
74 .arg(formatData("0"));
77 static inline QString
modZeroInvalid()
79 return QtXmlPatterns::tr("Modulus division (%1) by zero (%2) is undefined.")
80 .arg(formatKeyword("mod"))
81 .arg(formatData("0"));
84 Item
DecimalMathematician::calculate(const Item
&o1
,
87 const QExplicitlySharedDataPointer
<DynamicContext
> &context
) const
93 if(o2
.as
<Numeric
>()->toInteger() == 0)
95 context
->error(divZeroInvalid(), ReportContext::FOAR0001
, this);
96 return Item(); /* Silences source code analyzer warning. */
99 return toItem(Decimal::fromValue(o1
.as
<Numeric
>()->toDecimal() / o2
.as
<Numeric
>()->toDecimal()));
103 if(o2
.as
<Numeric
>()->toInteger() == 0)
105 context
->error(idivZeroInvalid(), ReportContext::FOAR0001
, this);
106 return Item(); /* Silences source code analyzer warning. */
109 return Integer::fromValue(static_cast<xsInteger
>(o1
.as
<Numeric
>()->toDecimal() /
110 o2
.as
<Numeric
>()->toDecimal()));
113 return toItem(Decimal::fromValue(o1
.as
<Numeric
>()->toDecimal() - o2
.as
<Numeric
>()->toDecimal()));
116 if(o2
.as
<Numeric
>()->toInteger() == 0)
118 context
->error(modZeroInvalid(), ReportContext::FOAR0001
, this);
119 return Item(); /* Silences source code analyzer warning. */
122 return toItem(Decimal::fromValue(::fmod(o1
.as
<Numeric
>()->toDecimal(), o2
.as
<Numeric
>()->toDecimal())));
125 return toItem(Decimal::fromValue(o1
.as
<Numeric
>()->toDecimal() * o2
.as
<Numeric
>()->toDecimal()));
127 return toItem(Decimal::fromValue(o1
.as
<Numeric
>()->toDecimal() + o2
.as
<Numeric
>()->toDecimal()));
131 return Item(); /* GCC unbarfer. */
134 Item
IntegerMathematician::calculate(const Item
&o1
,
137 const QExplicitlySharedDataPointer
<DynamicContext
> &context
) const
142 if(o2
.as
<Numeric
>()->toInteger() == 0)
144 context
->error(divZeroInvalid(), ReportContext::FOAR0001
, this);
145 return Item(); /* Silences source code analyzer warning. */
147 else /* C++ automatically performs truncation of long integer(xsInteger). */
148 return toItem(Decimal::fromValue(o1
.as
<Numeric
>()->toDecimal() / o2
.as
<Numeric
>()->toDecimal()));
151 if(o2
.as
<Numeric
>()->toInteger() == 0)
153 context
->error(idivZeroInvalid(), ReportContext::FOAR0001
, this);
154 return Item(); /* Silences source code analyzer warning. */
156 else /* C++ automatically performs truncation of long integer(xsInteger). */
157 return Integer::fromValue(o1
.as
<Numeric
>()->toInteger() / o2
.as
<Numeric
>()->toInteger());
160 return Integer::fromValue(o1
.as
<Numeric
>()->toInteger() - o2
.as
<Numeric
>()->toInteger());
163 const xsInteger divisor
= o2
.as
<Numeric
>()->toInteger();
167 context
->error(modZeroInvalid(), ReportContext::FOAR0001
, this);
168 return Item(); /* Silences source code analyzer warning. */
171 return Integer::fromValue(o1
.as
<Numeric
>()->toInteger() % divisor
);
174 return Integer::fromValue(o1
.as
<Numeric
>()->toInteger() * o2
.as
<Numeric
>()->toInteger());
176 return Integer::fromValue(o1
.as
<Numeric
>()->toInteger() + o2
.as
<Numeric
>()->toInteger());
180 return Item(); /* GCC unbarfer. */
183 Item
DurationNumericMathematician::calculate(const Item
&o1
,
186 const QExplicitlySharedDataPointer
<DynamicContext
> &context
) const
188 Q_ASSERT(op
== Div
|| op
== Multiply
);
190 const AbstractDuration::Ptr
duration(o1
.as
<AbstractDuration
>());
191 const xsDouble dbl
= o2
.as
<Numeric
>()->toDouble();
198 return duration
->fromValue(0);
201 context
->error(QtXmlPatterns::tr(
202 "Dividing a value of type %1 by %2 (not-a-number) "
204 .arg(formatType(context
->namePool(),
206 .arg(formatData("NaN")),
207 ReportContext::FOCA0005
,
211 else if(Double::isEqual(dbl
, 0))
213 context
->error(QtXmlPatterns::tr(
214 "Dividing a value of type %1 by %2 or %3 (plus or "
215 "minus zero) is not allowed.")
216 .arg(formatType(context
->namePool(),
218 .arg(formatData("-0"))
219 .arg(formatData("0")),
220 ReportContext::FODT0002
,
225 return duration
->fromValue(static_cast<AbstractDuration::Value
>(duration
->value() / dbl
));
229 if(Double::isEqual(dbl
, 0))
230 return duration
->fromValue(0);
233 context
->error(QtXmlPatterns::tr(
234 "Dividing a value of type %1 by %2 (not-a-number) "
236 .arg(formatType(context
->namePool(),
238 .arg(formatData("NaN")),
239 ReportContext::FOCA0005
,
245 context
->error(QtXmlPatterns::tr(
246 "Multiplication of a value of type %1 by %2 or %3 "
247 "(plus or minus infinity) is not allowed.")
248 .arg(formatType(context
->namePool(),
250 .arg(formatData("-INF"))
251 .arg(formatData("INF")),
252 ReportContext::FODT0002
,
257 return duration
->fromValue(static_cast<AbstractDuration::Value
>(duration
->value() * dbl
));
262 return Item(); /* Silence warning. */
267 Item
DurationDurationMathematician::calculate(const Item
&o1
,
270 const QExplicitlySharedDataPointer
<DynamicContext
> &) const
272 const AbstractDuration::Ptr
duration(o1
.as
<AbstractDuration
>());
273 const AbstractDuration::Value op2
= o2
.as
<AbstractDuration
>()->value();
278 return toItem(Decimal::fromValue(static_cast<xsDecimal
>(duration
->value()) / op2
));
280 return duration
->fromValue(duration
->value() - op2
);
282 return duration
->fromValue(duration
->value() + op2
);
286 return Item(); /* Silence warning. */
291 OperandSwitcherMathematician::
292 OperandSwitcherMathematician(const AtomicMathematician::Ptr
&mathematician
) : m_mather(mathematician
)
294 Q_ASSERT(mathematician
);
297 Item
OperandSwitcherMathematician::calculate(const Item
&o1
,
300 const QExplicitlySharedDataPointer
<DynamicContext
> &context
) const
302 return m_mather
->calculate(o2
, op
, o1
, context
);
306 Item
DateTimeDurationMathematician::calculate(const Item
&o1
,
309 const QExplicitlySharedDataPointer
<DynamicContext
> &context
) const
311 Q_ASSERT(op
== Substract
|| op
== Add
);
313 const AbstractDateTime::Ptr
adt(o1
.as
<AbstractDateTime
>());
314 const AbstractDuration::Ptr
dur(o2
.as
<AbstractDuration
>());
315 QDateTime
dt(adt
->toDateTime());
316 //pDebug() << "DateTimeDurationMathematician::calculate():" << dt.toString();
317 //dt.setDateOnly(false);
318 const qint8 sign
= (op
== Add
? 1 : -1) * (dur
->isPositive() ? 1 : -1);
320 // TODO milli seconds
321 dt
= dt
.addSecs(sign
* (dur
->seconds() + dur
->minutes() * 60 + dur
->hours() * 60 * 60));
322 dt
= dt
.addDays(sign
* dur
->days());
323 dt
= dt
.addMonths(sign
* dur
->months());
324 dt
= dt
.addYears(sign
* dur
->years());
328 if(AbstractDateTime::isRangeValid(dt
.date(), msg
))
329 return adt
->fromValue(dt
);
332 context
->error(msg
, ReportContext::FODT0001
,
338 Item
AbstractDateTimeMathematician::calculate(const Item
&o1
,
341 const QExplicitlySharedDataPointer
<DynamicContext
> &) const
343 Q_ASSERT(op
== Substract
|| op
== Add
);
344 QDateTime
dt1(o1
.as
<AbstractDateTime
>()->toDateTime());
345 QDateTime
dt2(o2
.as
<AbstractDateTime
>()->toDateTime());
347 const int diff
= op
== Add
? dt1
.secsTo(dt2
) : dt2
.secsTo(dt1
);
349 return toItem(DayTimeDuration::fromSeconds(diff
));