2e514dae261824253efd27a185cf58b01e11e89d
[profile/ivi/qtxmlpatterns.git] / src / xmlpatterns / expr / qexpressionsequence.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qcardinalityverifier_p.h"
43 #include "qcommonsequencetypes_p.h"
44 #include "qemptysequence_p.h"
45 #include "qsequencemappingiterator_p.h"
46
47 #include "qexpressionsequence_p.h"
48
49 QT_BEGIN_NAMESPACE
50
51 using namespace QPatternist;
52
53 ExpressionSequence::ExpressionSequence(const Expression::List &ops) : UnlimitedContainer(ops)
54 {
55     Q_ASSERT_X(1 < ops.count(), Q_FUNC_INFO,
56                "It makes no sense to have an ExpressionSequence containing less than two expressions.");
57 }
58
59 Item::Iterator::Ptr ExpressionSequence::mapToSequence(const Expression::Ptr &expr,
60                                                       const DynamicContext::Ptr &context) const
61 {
62     return expr->evaluateSequence(context);
63 }
64
65 Item::Iterator::Ptr ExpressionSequence::evaluateSequence(const DynamicContext::Ptr &context) const
66 {
67     return makeSequenceMappingIterator<Item>(ConstPtr(this),
68                                              makeListIterator(m_operands),
69                                              context);
70 }
71
72 void ExpressionSequence::evaluateToSequenceReceiver(const DynamicContext::Ptr &context) const
73 {
74     Expression::List::const_iterator it(m_operands.constBegin());
75     const Expression::List::const_iterator end(m_operands.constEnd());
76     Expression::List result;
77
78     for(; it != end; ++it)
79         (*it)->evaluateToSequenceReceiver(context);
80 }
81
82 Expression::Ptr ExpressionSequence::compress(const StaticContext::Ptr &context)
83 {
84     const Expression::Ptr me(UnlimitedContainer::compress(context));
85
86     if(me != this)
87         return me;
88
89     Expression::List::const_iterator it(m_operands.constBegin());
90     const Expression::List::const_iterator end(m_operands.constEnd());
91     Expression::List result;
92
93     for(; it != end; ++it)
94     {
95         const ID Id = (*it)->id();
96
97         /* Remove empty sequences. This is rather important because we have some steps in the parser that
98          * intentionally, unconditionally and for temporary reasons create expressions like (expr, ()). Of course,
99          * empty sequences also occur as part of optimizations.
100          *
101          * User function call sites that are of type empty-sequence() must be avoided since
102          * they may contain calls to fn:error(), which we would rewrite away otherwise. */
103         if(Id != IDUserFunctionCallsite && (*it)->staticType()->cardinality().isEmpty())
104         {
105             /* Rewrite "(1, (), 2)" into "(1, 2)" by not
106              * adding (*it) to result. */
107             continue;
108         }
109         else if(Id == IDExpressionSequence)
110         {
111             /* Rewrite "(1, (2, 3), 4)" into "(1, 2, 3, 4)" */
112             Expression::List::const_iterator seqIt((*it)->operands().constBegin());
113             const Expression::List::const_iterator seqEnd((*it)->operands().constEnd());
114
115             for(; seqIt != seqEnd; ++seqIt)
116                 result.append(*seqIt);
117         }
118         else
119             result.append(*it);
120     }
121
122     if(result.isEmpty())
123         return EmptySequence::create(this, context);
124     else if(result.count() == 1)
125         return result.first();
126     else
127     {
128         m_operands = result;
129         return me;
130     }
131 }
132
133 Expression::Ptr ExpressionSequence::typeCheck(const StaticContext::Ptr &context,
134                                               const SequenceType::Ptr &reqType)
135 {
136     Q_ASSERT(reqType);
137     Expression::List::iterator it(m_operands.begin());
138     const Expression::List::iterator end(m_operands.end());
139
140     /* We treat the cardinality differently here by allowing the empty sequence
141      * for each individual Expression, since the Cardinality can be conformed to by
142      * the ExpressionSequence as a whole(which we check for at the end). */
143     const SequenceType::Ptr testOnlyIT(makeGenericSequenceType(reqType->itemType(),
144                                                                Cardinality::empty() |
145                                                                reqType->cardinality()));
146
147     for(; it != end; ++it)
148         *it = (*it)->typeCheck(context, testOnlyIT);
149
150     /* The above loop is only guaranteed to find item type errors, but the cardinality
151      * can still be wrong since the operands were treated individually. */
152     return CardinalityVerifier::verifyCardinality(Expression::Ptr(this), reqType->cardinality(), context);
153 }
154
155 Expression::Properties ExpressionSequence::properties() const
156 {
157     const Expression::List::const_iterator end(m_operands.constEnd());
158     Expression::List::const_iterator it;
159     bool allEvaled = true;
160     Expression::Properties props(DisableElimination); /* Why do we have this flag? */
161
162     for(it = m_operands.constBegin(); it != end; ++it)
163     {
164         const Expression::Properties newp((*it)->properties());
165         props |= newp;
166
167         if((newp & IsEvaluated) != IsEvaluated)
168         {
169             allEvaled = false;
170             break;
171         }
172     }
173
174     if(!allEvaled)
175         props &= ~IsEvaluated; /* Remove IsEvaluated. */
176
177     /* One of our children might need the focus, but we don't, so
178      * cut it out. */
179     return props & ~RequiresFocus;
180 }
181
182 SequenceType::Ptr ExpressionSequence::staticType() const
183 {
184     return operandsUnionType<ProductOfCardinality>();
185 }
186
187 SequenceType::List ExpressionSequence::expectedOperandTypes() const
188 {
189     SequenceType::List result;
190     /* ExpressionSequence is a bit strange type wise since it has an
191      * infinite amount of operands. */
192     result.append(CommonSequenceTypes::ZeroOrMoreItems);
193     return result;
194 }
195
196 ExpressionVisitorResult::Ptr ExpressionSequence::accept(const ExpressionVisitor::Ptr &visitor) const
197 {
198     return visitor->visit(this);
199 }
200
201 Expression::ID ExpressionSequence::id() const
202 {
203     return IDExpressionSequence;
204 }
205
206 QT_END_NAMESPACE