1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qcommonsequencetypes_p.h"
41#include "qcommonvalues_p.h"
42#include "qgenericpredicate_p.h"
43#include "qgenericsequencetype_p.h"
44#include "qinsertioniterator_p.h"
45#include "qpatternistlocale_p.h"
46
47#include "qcardinalityverifier_p.h"
48
49QT_BEGIN_NAMESPACE
50
51using namespace QPatternist;
52
53QString CardinalityVerifier::wrongCardinality(const Cardinality &req,
54 const Cardinality &got)
55{
56 return QtXmlPatterns::tr(sourceText: "Required cardinality is %1; got cardinality %2.")
57 .arg(args: formatType(type: req), args: formatType(type: got));
58}
59
60Expression::Ptr CardinalityVerifier::verifyCardinality(const Expression::Ptr &operand,
61 const Cardinality &requiredCard,
62 const StaticContext::Ptr &context,
63 const ReportContext::ErrorCode code)
64{
65 const Cardinality opCard(operand->staticType()->cardinality());
66
67 if(requiredCard.isMatch(other: opCard))
68 return operand;
69 else if(requiredCard.canMatch(other: opCard))
70 return Expression::Ptr(new CardinalityVerifier(operand, requiredCard, code));
71 else if(context->compatModeEnabled() &&
72 !opCard.isEmpty())
73 {
74 return GenericPredicate::createFirstItem(sourceExpression: operand);
75 }
76 else
77 {
78 /* Sequences within this cardinality can never match. */
79 context->error(message: wrongCardinality(req: requiredCard, got: opCard), errorCode: code, reflection: operand.data());
80 return operand;
81 }
82}
83
84CardinalityVerifier::CardinalityVerifier(const Expression::Ptr &operand,
85 const Cardinality &card,
86 const ReportContext::ErrorCode code)
87 : SingleContainer(operand),
88 m_reqCard(card),
89 m_allowsMany(operand->staticType()->cardinality().allowsMany()),
90 m_errorCode(code)
91{
92 Q_ASSERT_X(m_reqCard != Cardinality::zeroOrMore(), Q_FUNC_INFO,
93 "It makes no sense to use CardinalityVerifier for cardinality zero-or-more.");
94}
95
96Item::Iterator::Ptr CardinalityVerifier::evaluateSequence(const DynamicContext::Ptr &context) const
97{
98 const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));
99 const Item next(it->next());
100
101 if(next)
102 {
103 const Item next2(it->next());
104
105 if(next2)
106 {
107 if(m_reqCard.allowsMany())
108 {
109 Item::List start;
110 start.append(t: next);
111 start.append(t: next2);
112
113 return Item::Iterator::Ptr(new InsertionIterator(it, 1, makeListIterator(list: start)));
114 }
115 else
116 {
117 context->error(message: wrongCardinality(req: m_reqCard, got: Cardinality::twoOrMore()), errorCode: m_errorCode, reflection: this);
118 return CommonValues::emptyIterator;
119 }
120 }
121 else
122 {
123 /* We might be instantiated for the empty sequence. */
124 if(m_reqCard.isEmpty())
125 {
126 context->error(message: wrongCardinality(req: m_reqCard, got: Cardinality::twoOrMore()), errorCode: m_errorCode, reflection: this);
127 return CommonValues::emptyIterator;
128 }
129 else
130 return makeSingletonIterator(item: next);
131 }
132 }
133 else
134 {
135 if(m_reqCard.allowsEmpty())
136 return CommonValues::emptyIterator;
137 else
138 {
139 context->error(message: wrongCardinality(req: m_reqCard, got: Cardinality::twoOrMore()), errorCode: m_errorCode, reflection: this);
140 return CommonValues::emptyIterator;
141 }
142 }
143}
144
145Item CardinalityVerifier::evaluateSingleton(const DynamicContext::Ptr &context) const
146{
147 if(m_allowsMany)
148 {
149 const Item::Iterator::Ptr it(m_operand->evaluateSequence(context));
150 const Item item(it->next());
151
152 if(item)
153 {
154 if(it->next())
155 {
156 context->error(message: wrongCardinality(req: m_reqCard, got: Cardinality::twoOrMore()),
157 errorCode: m_errorCode, reflection: this);
158 return Item();
159 }
160 else
161 return item;
162 }
163 else if(m_reqCard.allowsEmpty())
164 return Item();
165 else
166 {
167 context->error(message: wrongCardinality(req: m_reqCard), errorCode: m_errorCode, reflection: this);
168 return Item();
169 }
170 }
171 else
172 {
173 const Item item(m_operand->evaluateSingleton(context));
174
175 if(item)
176 return item;
177 else if(m_reqCard.allowsEmpty())
178 return Item();
179 else
180 {
181 context->error(message: wrongCardinality(req: m_reqCard), errorCode: m_errorCode, reflection: this);
182 return Item();
183 }
184 }
185}
186
187const SourceLocationReflection *CardinalityVerifier::actualReflection() const
188{
189 return m_operand->actualReflection();
190}
191
192Expression::Ptr CardinalityVerifier::compress(const StaticContext::Ptr &context)
193{
194 if(m_reqCard.isMatch(other: m_operand->staticType()->cardinality()))
195 return m_operand->compress(context);
196 else
197 return SingleContainer::compress(context);
198}
199
200SequenceType::List CardinalityVerifier::expectedOperandTypes() const
201{
202 SequenceType::List result;
203 result.append(t: CommonSequenceTypes::ZeroOrMoreItems);
204 return result;
205}
206
207SequenceType::Ptr CardinalityVerifier::staticType() const
208{
209 return makeGenericSequenceType(itemType: m_operand->staticType()->itemType(), cardinality: m_reqCard);
210}
211
212ExpressionVisitorResult::Ptr CardinalityVerifier::accept(const ExpressionVisitor::Ptr &visitor) const
213{
214 return visitor->visit(this);
215}
216
217Expression::ID CardinalityVerifier::id() const
218{
219 return IDCardinalityVerifier;
220}
221
222QT_END_NAMESPACE
223

source code of qtxmlpatterns/src/xmlpatterns/janitors/qcardinalityverifier.cpp