Initial import from the monolithic Qt.
[profile/ivi/qtxmlpatterns.git] / src / xmlpatterns / janitors / qcardinalityverifier.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8 **
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
14 ** this package.
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 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qcommonsequencetypes_p.h"
43 #include "qcommonvalues_p.h"
44 #include "qgenericpredicate_p.h"
45 #include "qgenericsequencetype_p.h"
46 #include "qinsertioniterator_p.h"
47 #include "qpatternistlocale_p.h"
48
49 #include "qcardinalityverifier_p.h"
50
51 QT_BEGIN_NAMESPACE
52
53 using namespace QPatternist;
54
55 QString CardinalityVerifier::wrongCardinality(const Cardinality &req,
56                                               const Cardinality &got)
57 {
58     return QtXmlPatterns::tr("Required cardinality is %1; got cardinality %2.")
59                 .arg(formatType(req), formatType(got));
60 }
61
62 Expression::Ptr CardinalityVerifier::verifyCardinality(const Expression::Ptr &operand,
63                                                        const Cardinality &requiredCard,
64                                                        const StaticContext::Ptr &context,
65                                                        const ReportContext::ErrorCode code)
66 {
67     const Cardinality opCard(operand->staticType()->cardinality());
68
69     if(requiredCard.isMatch(opCard))
70         return operand;
71     else if(requiredCard.canMatch(opCard))
72         return Expression::Ptr(new CardinalityVerifier(operand, requiredCard, code));
73     else if(context->compatModeEnabled() &&
74             !opCard.isEmpty())
75     {
76         return GenericPredicate::createFirstItem(operand);
77     }
78     else
79     {
80         /* Sequences within this cardinality can never match. */
81         context->error(wrongCardinality(requiredCard, opCard), code, operand.data());
82         return operand;
83     }
84 }
85
86 CardinalityVerifier::CardinalityVerifier(const Expression::Ptr &operand,
87                                          const Cardinality &card,
88                                          const ReportContext::ErrorCode code)
89                                          : SingleContainer(operand),
90                                            m_reqCard(card),
91                                            m_allowsMany(operand->staticType()->cardinality().allowsMany()),
92                                            m_errorCode(code)
93 {
94     Q_ASSERT_X(m_reqCard != Cardinality::zeroOrMore(), Q_FUNC_INFO,
95                "It makes no sense to use CardinalityVerifier for cardinality zero-or-more.");
96 }
97
98 Item::Iterator::Ptr CardinalityVerifier::evaluateSequence(const DynamicContext::Ptr &context) const
99 {
100     const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));
101     const Item next(it->next());
102
103     if(next)
104     {
105         const Item next2(it->next());
106
107         if(next2)
108         {
109             if(m_reqCard.allowsMany())
110             {
111                 Item::List start;
112                 start.append(next);
113                 start.append(next2);
114
115                 return Item::Iterator::Ptr(new InsertionIterator(it, 1, makeListIterator(start)));
116             }
117             else
118             {
119                 context->error(wrongCardinality(m_reqCard, Cardinality::twoOrMore()), m_errorCode, this);
120                 return CommonValues::emptyIterator;
121             }
122         }
123         else
124         {
125             /* We might be instantiated for the empty sequence. */
126             if(m_reqCard.isEmpty())
127             {
128                 context->error(wrongCardinality(m_reqCard, Cardinality::twoOrMore()), m_errorCode, this);
129                 return CommonValues::emptyIterator;
130             }
131             else
132                 return makeSingletonIterator(next);
133         }
134     }
135     else
136     {
137         if(m_reqCard.allowsEmpty())
138             return CommonValues::emptyIterator;
139         else
140         {
141             context->error(wrongCardinality(m_reqCard, Cardinality::twoOrMore()), m_errorCode, this);
142             return CommonValues::emptyIterator;
143         }
144     }
145 }
146
147 Item CardinalityVerifier::evaluateSingleton(const DynamicContext::Ptr &context) const
148 {
149     if(m_allowsMany)
150     {
151         const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));
152         const Item item(it->next());
153
154         if(item)
155         {
156             if(it->next())
157             {
158                 context->error(wrongCardinality(m_reqCard, Cardinality::twoOrMore()),
159                                m_errorCode, this);
160                 return Item();
161             }
162             else
163                 return item;
164         }
165         else if(m_reqCard.allowsEmpty())
166             return Item();
167         else
168         {
169             context->error(wrongCardinality(m_reqCard), m_errorCode, this);
170             return Item();
171         }
172     }
173     else
174     {
175         const Item item(m_operand->evaluateSingleton(context));
176
177         if(item)
178             return item;
179         else if(m_reqCard.allowsEmpty())
180             return Item();
181         else
182         {
183             context->error(wrongCardinality(m_reqCard), m_errorCode, this);
184             return Item();
185         }
186     }
187 }
188
189 const SourceLocationReflection *CardinalityVerifier::actualReflection() const
190 {
191     return m_operand->actualReflection();
192 }
193
194 Expression::Ptr CardinalityVerifier::compress(const StaticContext::Ptr &context)
195 {
196     if(m_reqCard.isMatch(m_operand->staticType()->cardinality()))
197         return m_operand->compress(context);
198     else
199         return SingleContainer::compress(context);
200 }
201
202 SequenceType::List CardinalityVerifier::expectedOperandTypes() const
203 {
204     SequenceType::List result;
205     result.append(CommonSequenceTypes::ZeroOrMoreItems);
206     return result;
207 }
208
209 SequenceType::Ptr CardinalityVerifier::staticType() const
210 {
211     return makeGenericSequenceType(m_operand->staticType()->itemType(), m_reqCard);
212 }
213
214 ExpressionVisitorResult::Ptr CardinalityVerifier::accept(const ExpressionVisitor::Ptr &visitor) const
215 {
216     return visitor->visit(this);
217 }
218
219 Expression::ID CardinalityVerifier::id() const
220 {
221     return IDCardinalityVerifier;
222 }
223
224 QT_END_NAMESPACE