Update copyright year in license headers.
[profile/ivi/qtxmlpatterns.git] / src / xmlpatterns / expr / quserfunctioncallsite.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qcommonsequencetypes_p.h"
43 #include "qdynamiccontextstore_p.h"
44 #include "qevaluationcache_p.h"
45
46 #include "quserfunctioncallsite_p.h"
47
48 QT_BEGIN_NAMESPACE
49
50 using namespace QPatternist;
51
52 UserFunctionCallsite::UserFunctionCallsite(const QXmlName nameP,
53                                            const FunctionSignature::Arity ar) : CallSite(nameP)
54                                                                               , m_arity(ar)
55                                                                               , m_expressionSlotOffset(-2)
56
57 {
58 }
59
60 Item::Iterator::Ptr UserFunctionCallsite::evaluateSequence(const DynamicContext::Ptr &context) const
61 {
62     return m_body->evaluateSequence(bindVariables(context));
63 }
64
65 Item UserFunctionCallsite::evaluateSingleton(const DynamicContext::Ptr &context) const
66 {
67     return m_body->evaluateSingleton(bindVariables(context));
68 }
69
70 bool UserFunctionCallsite::evaluateEBV(const DynamicContext::Ptr &context) const
71 {
72     return m_body->evaluateEBV(bindVariables(context));
73 }
74
75 void UserFunctionCallsite::evaluateToSequenceReceiver(const DynamicContext::Ptr &context) const
76 {
77     m_body->evaluateToSequenceReceiver(bindVariables(context));
78 }
79
80 DynamicContext::Ptr UserFunctionCallsite::bindVariables(const DynamicContext::Ptr &context) const
81 {
82     const DynamicContext::Ptr stackContext(context->createStack());
83     Q_ASSERT(stackContext);
84
85     const Expression::List::const_iterator end(m_operands.constEnd());
86     Expression::List::const_iterator it(m_operands.constBegin());
87
88     VariableSlotID slot = m_expressionSlotOffset;
89
90     for(; it != end; ++it)
91     {
92         stackContext->setExpressionVariable(slot,
93                                             Expression::Ptr(new DynamicContextStore(*it, context)));
94         ++slot;
95     }
96
97     return stackContext;
98 }
99
100 SequenceType::List UserFunctionCallsite::expectedOperandTypes() const
101 {
102     SequenceType::List result;
103
104     if(m_functionDeclaration)
105     {
106         const FunctionArgument::List args(m_functionDeclaration->signature()->arguments());
107         const FunctionArgument::List::const_iterator end(args.constEnd());
108         FunctionArgument::List::const_iterator it(args.constBegin());
109
110         for(; it != end; ++it)
111             result.append((*it)->type());
112     }
113     else
114         result.append(CommonSequenceTypes::ZeroOrMoreItems);
115
116     return result;
117 }
118
119 Expression::Ptr UserFunctionCallsite::typeCheck(const StaticContext::Ptr &context,
120                                                 const SequenceType::Ptr &reqType)
121 {
122     /* The parser calls TypeChecker::applyFunctionConversion() on user function
123      * bodies, possibly indirectly, before all function call sites have been
124      * resolved. Hence it's possible that we're called before before the usual
125      * typeCheck() pass, and hence before we have been resolved/checked and
126      * subsequently m_functionDeclaration set. Therefore, encounter for that below.
127      *
128      * UnresolvedVariableReference::typeCheck() has the same dilemma.
129      */
130
131     /* Ensure that the return value of the function is properly
132      * converted/does match from where it is called(which is here). */
133     if(isRecursive() || !m_functionDeclaration)
134         return CallSite::typeCheck(context, reqType);
135     else
136     {
137         /* Update, such that we use a recent version of the body that has typeCheck()
138          * and compress() rewrites included. */
139         m_body = m_functionDeclaration->body();
140
141         /* Note, we can't assign to m_functionDeclaration->body() because UserFunction can apply
142          * to several different callsites. Hence we need our own version. */
143         m_body = m_body->typeCheck(context, reqType);
144
145         /* We just act as a pipe for m_body, so we don't have to typecheck ourselves. However,
146          * the arguments must match the function declaration. */
147         typeCheckOperands(context);
148         return Expression::Ptr(this);
149     }
150 }
151
152 Expression::Ptr UserFunctionCallsite::compress(const StaticContext::Ptr &context)
153 {
154     if(!isRecursive())
155         rewrite(m_body, m_body->compress(context), context);
156
157     return CallSite::compress(context);
158 }
159
160 Expression::Properties UserFunctionCallsite::properties() const
161 {
162     return DisableElimination;
163 }
164
165 SequenceType::Ptr UserFunctionCallsite::staticType() const
166 {
167     /* Our return type, is the static type of the function body. We could have also used
168      * m_functionDeclaration->signature()->returnType(), but it doesn't get updated
169      * when function conversion is applied.
170      * We can't use m_body's type if we're recursive, because m_body computes its type
171      * from its children, and we're at least one of the children. Hence, we would
172      * recurse infinitely if we did.
173      *
174      * m_body can be null here if we're called before setSource().
175      */
176     if(isRecursive() || !m_body)
177         return CommonSequenceTypes::ZeroOrMoreItems; // TODO use the declaration, it can have a type explicitly.
178     else
179         return m_body->staticType();
180 }
181
182 ExpressionVisitorResult::Ptr UserFunctionCallsite::accept(const ExpressionVisitor::Ptr &visitor) const
183 {
184     return visitor->visit(this);
185 }
186
187 Expression::ID UserFunctionCallsite::id() const
188 {
189     return IDUserFunctionCallsite;
190 }
191
192 bool UserFunctionCallsite::isSignatureValid(const FunctionSignature::Ptr &sign) const
193 {
194     Q_ASSERT(sign);
195
196     return sign->name() == name()
197            &&
198            sign->isArityValid(m_arity);
199 }
200
201 bool UserFunctionCallsite::configureRecursion(const CallTargetDescription::Ptr &sign)
202 {
203     Q_ASSERT(sign);
204
205     setIsRecursive(isSignatureValid(sign));
206     return isRecursive();
207 }
208
209 void UserFunctionCallsite::setSource(const UserFunction::Ptr &userFunction,
210                                      const VariableSlotID cacheSlotOffset)
211 {
212     m_functionDeclaration = userFunction;
213     m_body = userFunction->body();
214     m_expressionSlotOffset = userFunction->expressionSlotOffset();
215
216     const int len = m_operands.size();
217
218     const VariableDeclaration::List varDecls(userFunction->argumentDeclarations());
219
220     for(int i = 0; i < len; ++i)
221     {
222         /* We don't want evaluation caches for range variables, it's not necessary since
223          * the item is already cached in DynamicContext::rangeVariable(). */
224         if(m_operands.at(i)->is(IDRangeVariableReference))
225             continue;
226
227         /* Note that we pass in cacheSlotOffset + i here instead of varDecls.at(i)->slot since
228          * we want independent caches for each callsite. */
229         m_operands[i] = Expression::Ptr(new EvaluationCache<false>(m_operands.at(i),
230                                                                    varDecls.at(i),
231                                                                    cacheSlotOffset + i));
232     }
233 }
234
235 FunctionSignature::Arity UserFunctionCallsite::arity() const
236 {
237     return m_arity;
238 }
239
240 CallTargetDescription::Ptr UserFunctionCallsite::callTargetDescription() const
241 {
242     return m_functionDeclaration->signature();
243 }
244
245 QT_END_NAMESPACE