source: trunk/src/xmlpatterns/expr/qgeneralcomparison.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 10.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
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.
23**
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.
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 have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qbuiltintypes_p.h"
43#include "qcommonsequencetypes_p.h"
44#include "qcommonvalues_p.h"
45#include "qebvextractor_p.h"
46#include "qitem_p.h"
47#include "qliteral_p.h"
48#include "qoptimizationpasses_p.h"
49#include "quntypedatomicconverter_p.h"
50#include "qvaluecomparison_p.h"
51
52#include "qgeneralcomparison_p.h"
53
54QT_BEGIN_NAMESPACE
55
56using namespace QPatternist;
57
58GeneralComparison::GeneralComparison(const Expression::Ptr &op1,
59 const AtomicComparator::Operator op,
60 const Expression::Ptr &op2,
61 const bool isBackwardsCompat) : PairContainer(op1, op2)
62 , m_operator(op)
63 , m_isBackwardsCompat(isBackwardsCompat)
64{
65}
66
67bool GeneralComparison::generalCompare(const Item &op1,
68 const Item &op2,
69 const DynamicContext::Ptr &context) const
70{
71 Q_ASSERT(op1);
72 Q_ASSERT(op2);
73
74 if(comparator())
75 return compare(op1, op2, comparator(), m_operator);
76
77 Expression::Ptr a1(new Literal(op1));
78 Expression::Ptr a2(new Literal(op2));
79
80 const AtomicComparator::Ptr comp(fetchGeneralComparator(a1, a2, context));
81 /* The fetchGeneralComparator call may rewrite a1 and/or a2. */
82 Q_ASSERT(a1);
83 Q_ASSERT(a2);
84 Q_ASSERT(comp);
85
86 return compare(a1->evaluateSingleton(context),
87 a2->evaluateSingleton(context),
88 comp,
89 m_operator);
90}
91
92bool GeneralComparison::evaluateEBV(const DynamicContext::Ptr &context) const
93{
94 const Item::Iterator::Ptr it1(m_operand1->evaluateSequence(context));
95 Item item1(it1->next());
96
97 if(!item1)
98 return false;
99
100 const Item::Iterator::Ptr it2(m_operand2->evaluateSequence(context));
101 Item::List cache;
102 Item item2;
103
104 while(true)
105 {
106 item2 = it2->next();
107 if(!item2)
108 break;
109
110 if(generalCompare(item1, item2, context))
111 return true;
112
113 cache.append(item2);
114 }
115
116 while(true)
117 {
118 item1 = it1->next();
119
120 if(!item1)
121 return false;
122
123 const Item::List::const_iterator end(cache.constEnd());
124 Item::List::const_iterator it(cache.constBegin());
125
126 for(; it != end; ++it)
127 if(generalCompare(item1, *it, context))
128 return true;
129 }
130
131 Q_ASSERT(false);
132 return false;
133}
134
135Expression::Ptr GeneralComparison::compress(const StaticContext::Ptr &context)
136{
137 const Expression::Ptr me(PairContainer::compress(context));
138
139 if(me != this)
140 return me;
141
142 if(ValueComparison::isCaseInsensitiveCompare(m_operand1, m_operand2))
143 useCaseInsensitiveComparator();
144
145 return me;
146}
147
148Expression::Ptr GeneralComparison::typeCheck(const StaticContext::Ptr &context,
149 const SequenceType::Ptr &reqType)
150{
151
152 const Expression::Ptr me(PairContainer::typeCheck(context, reqType));
153
154 const ItemType::Ptr t1(m_operand1->staticType()->itemType());
155 const ItemType::Ptr t2(m_operand2->staticType()->itemType());
156
157 if(*CommonSequenceTypes::Empty == *t1 ||
158 *CommonSequenceTypes::Empty == *t2)
159 {
160 return wrapLiteral(CommonValues::BooleanFalse, context, this);
161 }
162
163 if(*BuiltinTypes::xsAnyAtomicType == *t1 ||
164 *BuiltinTypes::xsAnyAtomicType == *t2)
165 return me;
166
167 prepareComparison(fetchGeneralComparator(m_operand1, m_operand2, context));
168
169 if(!m_operand1->staticType()->cardinality().allowsMany() &&
170 !m_operand2->staticType()->cardinality().allowsMany())
171 {
172 /* Rewrite to a ValueComparison whose operands uses typing rules
173 * as for an general comparison(that's what's done above). */
174 return rewrite(Expression::Ptr(new ValueComparison(m_operand1,
175 m_operator,
176 m_operand2))->typeCheck(context, reqType),
177 context);
178 }
179 else
180 return me;
181}
182
183void GeneralComparison::updateType(ItemType::Ptr &type,
184 const Expression::Ptr &source)
185{
186 type = source->staticType()->itemType();
187}
188
189AtomicComparator::Ptr GeneralComparison::fetchGeneralComparator(Expression::Ptr &op1,
190 Expression::Ptr &op2,
191 const ReportContext::Ptr &context) const
192{
193 ItemType::Ptr t1(op1->staticType()->itemType());
194 ItemType::Ptr t2(op2->staticType()->itemType());
195
196 /* a. "If one of the atomic values is an instance of xs:untypedAtomic and
197 * the other is an instance of a numeric type, then the xs:untypedAtomic
198 * value is cast to the type xs:double." */
199 if(BuiltinTypes::numeric->xdtTypeMatches(t1) &&
200 BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t2))
201 {
202 op2 = Expression::Ptr(new UntypedAtomicConverter(op2, BuiltinTypes::xsDouble));
203
204 /* The types might have changed, reload. */
205 updateType(t2, op2);
206 }
207 else if(BuiltinTypes::numeric->xdtTypeMatches(t2) &&
208 BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1))
209 {
210 op1 = Expression::Ptr(new UntypedAtomicConverter(op1, BuiltinTypes::xsDouble));
211
212 /* The types might have changed, reload. */
213 updateType(t1, op1);
214 }
215 /* "If XPath 1.0 compatibility mode is true, a general comparison is
216 * evaluated by applying the following rules, in order:
217 * 1. If either operand is a single atomic value that is an instance of
218 * xs:boolean, then the other operand is converted to xs:boolean by taking
219 * its effective boolean value."
220 *
221 * Notably, it's not conversion to boolean, it is EBV extraction.
222 */
223 else if(m_isBackwardsCompat && BuiltinTypes::xsBoolean->xdtTypeMatches(t1))
224 {
225 op2 = Expression::Ptr(new EBVExtractor(op2));
226 updateType(t2, op2);
227 }
228 else if(m_isBackwardsCompat && BuiltinTypes::xsBoolean->xdtTypeMatches(t2))
229 {
230 op1 = Expression::Ptr(new EBVExtractor(op1));
231 updateType(t1, op1);
232 }
233 /* b. "If one of the atomic values is an instance of xs:untypedAtomic and
234 * the other is an instance of xs:untypedAtomic or xs:string, then the
235 * xs:untypedAtomic value (or values) is (are) cast to the type xs:string."
236 *
237 * c. "If one of the atomic values is an instance of xs:untypedAtomic and the
238 * other is not an instance of xs:string, xs:untypedAtomic, or any numeric
239 * type, then the xs:untypedAtomic value is cast to the dynamic type of the
240 * other value." */
241 else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1) &&
242 !BuiltinTypes::xsString->xdtTypeMatches(t2) &&
243 !BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t2) &&
244 !BuiltinTypes::xsAnyURI->xdtTypeMatches(t2))
245 {
246 op1 = Expression::Ptr(new UntypedAtomicConverter(op1, t2));
247 updateType(t1, op1);
248 }
249 else if(BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t2) &&
250 !BuiltinTypes::xsString->xdtTypeMatches(t1) &&
251 !BuiltinTypes::xsUntypedAtomic->xdtTypeMatches(t1) &&
252 !BuiltinTypes::xsAnyURI->xdtTypeMatches(t1))
253 {
254 op2 = Expression::Ptr(new UntypedAtomicConverter(op2, t1));
255 updateType(t2, op2);
256 }
257
258 /* d. "After performing the conversions described above, the atomic
259 * values are compared using one of the value comparison operators
260 * eq, ne, lt, le, gt, or ge, depending on whether the general comparison
261 * operator was =, !=, <, <=, >, or >=. The values have the required
262 * magnitude relationship if and only if the result of this value comparison
263 * is true." */
264
265 return fetchComparator(t1, t2, context);
266}
267
268OptimizationPass::List GeneralComparison::optimizationPasses() const
269{
270 Q_ASSERT(!OptimizationPasses::comparisonPasses.isEmpty());
271 return OptimizationPasses::comparisonPasses;
272}
273
274SequenceType::List GeneralComparison::expectedOperandTypes() const
275{
276 SequenceType::List result;
277 result.append(CommonSequenceTypes::ZeroOrMoreAtomicTypes);
278 result.append(CommonSequenceTypes::ZeroOrMoreAtomicTypes);
279 return result;
280}
281
282SequenceType::Ptr GeneralComparison::staticType() const
283{
284 return CommonSequenceTypes::ExactlyOneBoolean;
285}
286
287ExpressionVisitorResult::Ptr GeneralComparison::accept(const ExpressionVisitor::Ptr &visitor) const
288{
289 return visitor->visit(this);
290}
291
292Expression::ID GeneralComparison::id() const
293{
294 return IDGeneralComparison;
295}
296
297QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.