src/xmlpatterns/expr/quserfunctioncallsite.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 "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