Qt 4.8
qarithmeticexpression.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 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.
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 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.
24 **
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.
28 **
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.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qboolean_p.h"
43 #include "qbuiltintypes_p.h"
44 #include "qcommonsequencetypes_p.h"
45 #include "qemptysequence_p.h"
46 #include "qgenericsequencetype_p.h"
47 #include "qliteral_p.h"
48 #include "qpatternistlocale_p.h"
49 #include "qschemanumeric_p.h"
51 
53 
55 
56 using namespace QPatternist;
57 
60  const Expression::Ptr &op2) : PairContainer(op1, op2)
61  , m_op(op)
62  , m_isCompat(false)
63 {
64 }
65 
67 {
68  const Item op1(m_operand1->evaluateSingleton(context));
69  if(!op1)
70  return Item();
71 
72  const Item op2(m_operand2->evaluateSingleton(context));
73  if(!op2)
74  return Item();
75 
76  return flexiblyCalculate(op1, m_op, op2, m_mather, context, this,
78 }
79 
95 {
96 public:
98  const SourceLocationReflection *const reflection) : Literal(item)
99  , m_reflection(reflection)
100  {
101  }
102 
104  {
105  return m_reflection;
106  }
107 
108 private:
110 };
111 
114  const Item &op2,
115  const AtomicMathematician::Ptr &mather,
116  const DynamicContext::Ptr &context,
117  const SourceLocationReflection *const reflection,
118  const ReportContext::ErrorCode code,
119  const bool isCompat)
120 {
121  if(mather)
122  return mather->calculate(op1, op, op2, context);
123 
124  /* This is a very heavy code path. */
125  Expression::Ptr a1(new DelegatingReflectionExpression(op1, reflection));
126  Expression::Ptr a2(new DelegatingReflectionExpression(op2, reflection));
127 
128  const AtomicMathematician::Ptr ingela(fetchMathematician(a1, a2, op, true, context, reflection, code, isCompat));
129 
130  return ingela->calculate(a1->evaluateSingleton(context),
131  op,
132  a2->evaluateSingleton(context),
133  context);
134 }
135 
137  const SequenceType::Ptr &reqType)
138 {
139  m_isCompat = context->compatModeEnabled();
140 
141  const Expression::Ptr me(PairContainer::typeCheck(context, reqType));
144 
145  if(*CommonSequenceTypes::Empty == *t1 ||
147  {
148  return EmptySequence::create(this, context);
149  }
150 
151  if(*BuiltinTypes::xsAnyAtomicType == *t1 ||
153  *BuiltinTypes::numeric == *t1 ||
154  *BuiltinTypes::numeric == *t2)
155  {
156  /* The static type of (at least) one of the operands could not
157  * be narrowed further than xs:anyAtomicType, so we do the operator
158  * lookup at runtime. */
159  return me;
160  }
161 
162  m_mather = fetchMathematician(m_operand1, m_operand2, m_op, true, context, this,
164 
165  return me;
166 }
167 
170  Expression::Ptr &op2,
172  const bool issueError,
173  const ReportContext::Ptr &context,
174  const SourceLocationReflection *const reflection,
175  const ReportContext::ErrorCode code,
176  const bool isCompat)
177 {
178  ItemType::Ptr t1(op1->staticType()->itemType());
179  ItemType::Ptr t2(op2->staticType()->itemType());
180 
181  if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1)
182  || (isCompat && (BuiltinTypes::xsString->xdtTypeMatches(t1)
183  || BuiltinTypes::xsDecimal->xdtTypeMatches(t1))))
184  {
186  /* The types might have changed, reload. */
187  t1 = op1->staticType()->itemType();
188  }
189 
190  if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t2)
191  || (isCompat && (BuiltinTypes::xsString->xdtTypeMatches(t1)
192  || BuiltinTypes::xsDecimal->xdtTypeMatches(t1))))
193  {
195  /* The types might have changed, reload. */
196  t2 = op2->staticType()->itemType();
197  }
198 
199  const AtomicMathematicianLocator::Ptr locator
200  (static_cast<const AtomicType *>(t1.data())->mathematicianLocator());
201 
202  if(!locator)
203  {
204  if(!issueError)
205  return AtomicMathematician::Ptr();
206 
207  context->error(QtXmlPatterns::tr(
208  "Operator %1 cannot be used on type %2.")
210  .arg(formatType(context->namePool(), t1)),
211  code, reflection);
212  return AtomicMathematician::Ptr();
213  }
214 
215  const AtomicMathematician::Ptr comp
216  (static_cast<const AtomicType *>(t2.data())->accept(locator, op, reflection));
217 
218  if(comp)
219  return comp;
220 
221  if(!issueError)
222  return AtomicMathematician::Ptr();
223 
224  context->error(QtXmlPatterns::tr("Operator %1 cannot be used on "
225  "atomic values of type %2 and %3.")
227  .arg(formatType(context->namePool(), t1))
228  .arg(formatType(context->namePool(), t2)),
229  code, reflection);
230  return AtomicMathematician::Ptr();
231 }
232 
234 {
235  Cardinality card;
236 
237  /* These variables are important because they ensure staticType() only
238  * gets called once from this function. Before, this lead to strange
239  * semi-infinite recursion involving many arithmetic expressions. */
242 
243  if(st1->cardinality().allowsEmpty() ||
244  st2->cardinality().allowsEmpty())
245  {
246  card = Cardinality::zeroOrOne();
247  }
248  else
249  card = Cardinality::exactlyOne();
250 
252  return makeGenericSequenceType(BuiltinTypes::xsInteger, card);
253 
254  const ItemType::Ptr t1(st1->itemType());
255  const ItemType::Ptr t2(st2->itemType());
256  ItemType::Ptr returnType;
257 
258  /* Please, make this beautiful? */
259  if(BuiltinTypes::xsTime->xdtTypeMatches(t1) ||
260  BuiltinTypes::xsDate->xdtTypeMatches(t1) ||
261  BuiltinTypes::xsDateTime->xdtTypeMatches(t1))
262  {
263  if(BuiltinTypes::xsDuration->xdtTypeMatches(t2))
264  returnType = t1;
265  else
266  returnType = BuiltinTypes::xsDayTimeDuration;
267  }
268  else if(BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t1))
269  {
271  BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t2))
272  {
273  returnType = BuiltinTypes::xsDecimal;
274  }
275  else if(BuiltinTypes::numeric->xdtTypeMatches(t2))
277  else
278  returnType = t2;
279  }
280  else if(BuiltinTypes::xsYearMonthDuration->xdtTypeMatches(t2))
281  {
283  }
284  else if(BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t1))
285  {
287  BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t2))
288  {
289  returnType = BuiltinTypes::xsDecimal;
290  }
291  else if(BuiltinTypes::numeric->xdtTypeMatches(t2))
292  returnType = BuiltinTypes::xsDayTimeDuration;
293  else
294  returnType = t2;
295  }
296  else if(BuiltinTypes::xsDayTimeDuration->xdtTypeMatches(t2))
297  {
298  returnType = BuiltinTypes::xsDayTimeDuration;
299  }
300  else if(BuiltinTypes::xsDouble->xdtTypeMatches(t1) ||
301  BuiltinTypes::xsDouble->xdtTypeMatches(t2))
302  {
303  returnType = BuiltinTypes::xsDouble;
304  }
305  else if(BuiltinTypes::xsFloat->xdtTypeMatches(t1) ||
306  BuiltinTypes::xsFloat->xdtTypeMatches(t2))
307  {
308  if(m_isCompat)
309  returnType = BuiltinTypes::xsFloat;
310  else
311  returnType = BuiltinTypes::xsDouble;
312  }
313  else if(BuiltinTypes::xsInteger->xdtTypeMatches(t1) &&
314  BuiltinTypes::xsInteger->xdtTypeMatches(t2))
315  {
316  if(m_isCompat)
317  returnType = BuiltinTypes::xsDouble;
318  else
319  {
320  /* "A div B numeric numeric op:numeric-divide(A, B)
321  * numeric; but xs:decimal if both operands are xs:integer" */
323  returnType = BuiltinTypes::xsDecimal;
324  else
325  returnType = BuiltinTypes::xsInteger;
326  }
327  }
328  else if(m_isCompat && (BuiltinTypes::xsInteger->xdtTypeMatches(t1) &&
329  BuiltinTypes::xsInteger->xdtTypeMatches(t2)))
330  {
331  returnType = BuiltinTypes::xsDouble;
332  }
333  else
334  {
335  /* If typeCheck() has been called, our operands conform to expectedOperandTypes(), and
336  * the types are hence either xs:decimals, or xs:anyAtomicType(meaning the static type could
337  * not be inferred), or empty-sequence(). So we use the union of the two types. The combinations
338  * could also be wrong.*/
339  returnType = t1 | t2;
340 
341  /* However, if we're called before typeCheck(), we could potentially have nodes, so we need to make
342  * sure that the type is at least atomic. */
343  if(!BuiltinTypes::xsAnyAtomicType->xdtTypeMatches(returnType))
344  returnType = BuiltinTypes::xsAnyAtomicType;
345  }
346 
347  return makeGenericSequenceType(returnType, card);
348 }
349 
351 {
352  SequenceType::List result;
355  return result;
356 }
357 
359 {
360  return visitor->visit(this);
361 }
362 
virtual bool compatModeEnabled() const =0
static const AtomicType::Ptr xsDayTimeDuration
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QString formatKeyword(const QString &keyword)
static const AtomicType::Ptr xsDuration
const SourceLocationReflection *const m_reflection
QString formatType(const NamePool::Ptr &np, const T &type)
Formats ItemType and SequenceType.
virtual Expression::Ptr typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType)
Definition: qexpression.cpp:70
static Expression::Ptr create(const Expression *const replacementFor, const StaticContext::Ptr &context)
Creates an EmptySequence that is a replacement for replacementFor.
static const AtomicType::Ptr xsYearMonthDuration
static const AtomicType::Ptr xsString
virtual const SourceLocationReflection * actualReflection() const
Returns this.
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static const AtomicType::Ptr xsDateTime
static QString displayName(const AtomicMathematician::Operator op)
The namespace for the internal API of QtXmlPatterns.
static const AtomicType::Ptr xsDouble
QExplicitlySharedDataPointer< AtomicMathematician > Ptr
ArithmeticExpression(const Expression::Ptr &operand1, const AtomicMathematician::Operator op, const Expression::Ptr &operand2)
virtual SequenceType::List expectedOperandTypes() const
static const AtomicType::Ptr xsUntypedAtomic
Houses an AtomicValue, making it available as an Expression.
Definition: qliteral_p.h:74
QExplicitlySharedDataPointer< Expression > Ptr
A smart pointer wrapping mutable Expression instances.
static AtomicMathematician::Ptr fetchMathematician(Expression::Ptr &t1, Expression::Ptr &t2, const AtomicMathematician::Operator op, const bool issueError, const ReportContext::Ptr &context, const SourceLocationReflection *const reflection, const ReportContext::ErrorCode code=ReportContext::XPTY0004, const bool isCompat=false)
virtual SequenceType::Ptr staticType() const =0
static const EmptySequenceType::Ptr Empty
static Cardinality zeroOrOne()
DelegatingReflectionExpression(const Item &item, const SourceLocationReflection *const reflection)
Contains functions used for formatting arguments, such as keywords and paths, in translated strings...
Represents an item in the XPath 2.0 Data Model.
Definition: qitem_p.h:182
static const AtomicType::Ptr xsFloat
Contains class Numeric. This file was originally called qnumeric_p.h, but various build systems canno...
virtual Item evaluateSingleton(const DynamicContext::Ptr &context) const
static const AtomicType::Ptr numeric
static const AtomicType::Ptr xsInteger
static Cardinality exactlyOne()
Casts every item in a sequence obtained from evaluating an Expression, to a requested atomic type...
static const AtomicType::Ptr xsTime
virtual SequenceType::Ptr staticType() const
static const AtomicType::Ptr xsDecimal
static const AtomicType::Ptr xsAnyAtomicType
Represents a cardinality, a possible , often represented by occurrence indicators.
virtual ItemType::Ptr itemType() const =0
static const AtomicType::Ptr xsDate
virtual ExpressionVisitorResult::Ptr accept(const ExpressionVisitor::Ptr &visitor) const
static const SequenceType::Ptr ZeroOrOneAtomicType
virtual Expression::Ptr typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType)
static Item flexiblyCalculate(const Item &op1, const AtomicMathematician::Operator op, const Item &op2, const AtomicMathematician::Ptr &mather, const DynamicContext::Ptr &context, const SourceLocationReflection *const reflection, const ReportContext::ErrorCode code=ReportContext::XPTY0004, const bool isCompat=false)
virtual Item calculate(const Item &operand1, const Operator op, const Item &operand2, const QExplicitlySharedDataPointer< DynamicContext > &context) const =0
virtual Item evaluateSingleton(const DynamicContext::Ptr &context) const
const AtomicMathematician::Operator m_op
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
Base class for all instances that represents something at a certain location.
Base class for expressions that has exactly two operands.