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 "qemptysequence_p.h"
42#include "qgenericsequencetype_p.h"
43#include "qitemmappingiterator_p.h"
44#include "qoptimizationpasses_p.h"
45#include "qsequencemappingiterator_p.h"
46
47#include "qforclause_p.h"
48
49QT_BEGIN_NAMESPACE
50
51using namespace QPatternist;
52
53ForClause::ForClause(const VariableSlotID varSlot,
54 const Expression::Ptr &bindingSequence,
55 const Expression::Ptr &returnExpression,
56 const VariableSlotID positionSlot) : PairContainer(bindingSequence, returnExpression),
57 m_varSlot(varSlot),
58 m_positionSlot(positionSlot),
59 m_allowsMany(true)
60{
61 Q_ASSERT(m_positionSlot > -2);
62}
63
64Item ForClause::mapToItem(const Item &item,
65 const DynamicContext::Ptr &context) const
66{
67 context->setRangeVariable(slot: m_varSlot, newValue: item);
68 return m_operand2->evaluateSingleton(context);
69}
70
71Item::Iterator::Ptr ForClause::mapToSequence(const Item &item,
72 const DynamicContext::Ptr &context) const
73{
74 context->setRangeVariable(slot: m_varSlot, newValue: item);
75 return m_operand2->evaluateSequence(context);
76}
77
78void ForClause::riggPositionalVariable(const DynamicContext::Ptr &context,
79 const Item::Iterator::Ptr &source) const
80{
81 if(m_positionSlot > -1)
82 context->setPositionIterator(slot: m_positionSlot, newValue: source);
83}
84
85Item::Iterator::Ptr ForClause::evaluateSequence(const DynamicContext::Ptr &context) const
86{
87 const Item::Iterator::Ptr source(m_operand1->evaluateSequence(context));
88
89 riggPositionalVariable(context, source);
90
91 if(m_allowsMany)
92 {
93 return makeSequenceMappingIterator<Item>(mapper: ConstPtr(this),
94 source,
95 context);
96 }
97 else
98 {
99 return makeItemMappingIterator<Item>(mapper: ConstPtr(this),
100 source,
101 context);
102 }
103}
104
105Item ForClause::evaluateSingleton(const DynamicContext::Ptr &context) const
106{
107 return evaluateSequence(context)->next();
108}
109
110void ForClause::evaluateToSequenceReceiver(const DynamicContext::Ptr &context) const
111{
112 Item::Iterator::Ptr it;
113 const Item::Iterator::Ptr source(m_operand1->evaluateSequence(context));
114
115 riggPositionalVariable(context, source);
116
117 Item next(source->next());
118
119 while(next)
120 {
121 context->setRangeVariable(slot: m_varSlot, newValue: next);
122 m_operand2->evaluateToSequenceReceiver(context);
123 next = source->next();
124 }
125}
126
127Expression::Ptr ForClause::typeCheck(const StaticContext::Ptr &context,
128 const SequenceType::Ptr &reqType)
129{
130 const Expression::Ptr me(PairContainer::typeCheck(context, reqType));
131 const Cardinality card(m_operand1->staticType()->cardinality());
132
133 /* If our source is empty we will always evaluate to the empty sequence, so rewrite. */
134 if(card.isEmpty())
135 return EmptySequence::create(replacementFor: this, context);
136 else
137 return me;
138
139 /* This breaks because the variable references haven't rewritten themselves, so
140 * they dangle. When this is fixed, evaluateSingleton can be removed. */
141 /*
142 else if(card->allowsMany())
143 return me;
144 else
145 return m_operand2;
146 */
147}
148
149Expression::Ptr ForClause::compress(const StaticContext::Ptr &context)
150{
151 const Expression::Ptr me(PairContainer::compress(context));
152 if(me != this)
153 return me;
154
155 /* This is done after calling PairContainer::typeCheck(). The advantage of this is that
156 * m_allowsMany is updated according to what the operand says after it has compressed. However,
157 * if it was initialized to false(as it once was..), ForClause::evaluateSequence()
158 * would potentially have been called by PairContainer::compress(), and it would have
159 * used an unsafe branch. */
160 m_allowsMany = m_operand2->staticType()->cardinality().allowsMany();
161
162 return me;
163}
164
165SequenceType::Ptr ForClause::staticType() const
166{
167 const SequenceType::Ptr returnType(m_operand2->staticType());
168
169 return makeGenericSequenceType(itemType: returnType->itemType(),
170 cardinality: m_operand1->staticType()->cardinality()
171 * /* multiply operator */
172 returnType->cardinality());
173}
174
175SequenceType::List ForClause::expectedOperandTypes() const
176{
177 SequenceType::List result;
178 result.append(t: CommonSequenceTypes::ZeroOrMoreItems);
179 result.append(t: CommonSequenceTypes::ZeroOrMoreItems);
180 return result;
181}
182
183ExpressionVisitorResult::Ptr ForClause::accept(const ExpressionVisitor::Ptr &visitor) const
184{
185 return visitor->visit(this);
186}
187
188OptimizationPass::List ForClause::optimizationPasses() const
189{
190 return OptimizationPasses::forPasses;
191}
192
193Expression::ID ForClause::id() const
194{
195 return IDForClause;
196}
197
198QT_END_NAMESPACE
199

source code of qtxmlpatterns/src/xmlpatterns/expr/qforclause.cpp