1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
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 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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));