diff options
author | Qt by Nokia <qt-info@nokia.com> | 2011-04-27 12:05:43 +0200 |
---|---|---|
committer | axis <qt-info@nokia.com> | 2011-04-27 12:05:43 +0200 |
commit | e1b2c9deb5943faae2b29be6a5c006f75bb73f06 (patch) | |
tree | fc79e45367c0a8fc71185e9afc33f7503a58653c /src/xmlpatterns/expr/quserfunctioncallsite.cpp | |
download | qtxmlpatterns-e1b2c9deb5943faae2b29be6a5c006f75bb73f06.tar.gz |
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you
want to look at revision history older than this, please refer to the
Qt Git wiki for how to use Git history grafting. At the time of
writing, this wiki is located here:
http://qt.gitorious.org/qt/pages/GitIntroductionWithQt
If you have already performed the grafting and you don't see any
history beyond this commit, try running "git log" with the "--follow"
argument.
Branched from the monolithic repo, Qt master branch, at commit
896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/xmlpatterns/expr/quserfunctioncallsite.cpp')
-rw-r--r-- | src/xmlpatterns/expr/quserfunctioncallsite.cpp | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/src/xmlpatterns/expr/quserfunctioncallsite.cpp b/src/xmlpatterns/expr/quserfunctioncallsite.cpp new file mode 100644 index 0000000..4e81484 --- /dev/null +++ b/src/xmlpatterns/expr/quserfunctioncallsite.cpp @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcommonsequencetypes_p.h" +#include "qdynamiccontextstore_p.h" +#include "qevaluationcache_p.h" + +#include "quserfunctioncallsite_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +UserFunctionCallsite::UserFunctionCallsite(const QXmlName nameP, + const FunctionSignature::Arity ar) : CallSite(nameP) + , m_arity(ar) + , m_expressionSlotOffset(-2) + +{ +} + +Item::Iterator::Ptr UserFunctionCallsite::evaluateSequence(const DynamicContext::Ptr &context) const +{ + return m_body->evaluateSequence(bindVariables(context)); +} + +Item UserFunctionCallsite::evaluateSingleton(const DynamicContext::Ptr &context) const +{ + return m_body->evaluateSingleton(bindVariables(context)); +} + +bool UserFunctionCallsite::evaluateEBV(const DynamicContext::Ptr &context) const +{ + return m_body->evaluateEBV(bindVariables(context)); +} + +void UserFunctionCallsite::evaluateToSequenceReceiver(const DynamicContext::Ptr &context) const +{ + m_body->evaluateToSequenceReceiver(bindVariables(context)); +} + +DynamicContext::Ptr UserFunctionCallsite::bindVariables(const DynamicContext::Ptr &context) const +{ + const DynamicContext::Ptr stackContext(context->createStack()); + Q_ASSERT(stackContext); + + const Expression::List::const_iterator end(m_operands.constEnd()); + Expression::List::const_iterator it(m_operands.constBegin()); + + VariableSlotID slot = m_expressionSlotOffset; + + for(; it != end; ++it) + { + stackContext->setExpressionVariable(slot, + Expression::Ptr(new DynamicContextStore(*it, context))); + ++slot; + } + + return stackContext; +} + +SequenceType::List UserFunctionCallsite::expectedOperandTypes() const +{ + SequenceType::List result; + + if(m_functionDeclaration) + { + const FunctionArgument::List args(m_functionDeclaration->signature()->arguments()); + const FunctionArgument::List::const_iterator end(args.constEnd()); + FunctionArgument::List::const_iterator it(args.constBegin()); + + for(; it != end; ++it) + result.append((*it)->type()); + } + else + result.append(CommonSequenceTypes::ZeroOrMoreItems); + + return result; +} + +Expression::Ptr UserFunctionCallsite::typeCheck(const StaticContext::Ptr &context, + const SequenceType::Ptr &reqType) +{ + /* The parser calls TypeChecker::applyFunctionConversion() on user function + * bodies, possibly indirectly, before all function call sites have been + * resolved. Hence it's possible that we're called before before the usual + * typeCheck() pass, and hence before we have been resolved/checked and + * subsequently m_functionDeclaration set. Therefore, encounter for that below. + * + * UnresolvedVariableReference::typeCheck() has the same dilemma. + */ + + /* Ensure that the return value of the function is properly + * converted/does match from where it is called(which is here). */ + if(isRecursive() || !m_functionDeclaration) + return CallSite::typeCheck(context, reqType); + else + { + /* Update, such that we use a recent version of the body that has typeCheck() + * and compress() rewrites included. */ + m_body = m_functionDeclaration->body(); + + /* Note, we can't assign to m_functionDeclaration->body() because UserFunction can apply + * to several different callsites. Hence we need our own version. */ + m_body = m_body->typeCheck(context, reqType); + + /* We just act as a pipe for m_body, so we don't have to typecheck ourselves. However, + * the arguments must match the function declaration. */ + typeCheckOperands(context); + return Expression::Ptr(this); + } +} + +Expression::Ptr UserFunctionCallsite::compress(const StaticContext::Ptr &context) +{ + if(!isRecursive()) + rewrite(m_body, m_body->compress(context), context); + + return CallSite::compress(context); +} + +Expression::Properties UserFunctionCallsite::properties() const +{ + return DisableElimination; +} + +SequenceType::Ptr UserFunctionCallsite::staticType() const +{ + /* Our return type, is the static type of the function body. We could have also used + * m_functionDeclaration->signature()->returnType(), but it doesn't get updated + * when function conversion is applied. + * We can't use m_body's type if we're recursive, because m_body computes its type + * from its children, and we're at least one of the children. Hence, we would + * recurse infinitely if we did. + * + * m_body can be null here if we're called before setSource(). + */ + if(isRecursive() || !m_body) + return CommonSequenceTypes::ZeroOrMoreItems; // TODO use the declaration, it can have a type explicitly. + else + return m_body->staticType(); +} + +ExpressionVisitorResult::Ptr UserFunctionCallsite::accept(const ExpressionVisitor::Ptr &visitor) const +{ + return visitor->visit(this); +} + +Expression::ID UserFunctionCallsite::id() const +{ + return IDUserFunctionCallsite; +} + +bool UserFunctionCallsite::isSignatureValid(const FunctionSignature::Ptr &sign) const +{ + Q_ASSERT(sign); + + return sign->name() == name() + && + sign->isArityValid(m_arity); +} + +bool UserFunctionCallsite::configureRecursion(const CallTargetDescription::Ptr &sign) +{ + Q_ASSERT(sign); + + setIsRecursive(isSignatureValid(sign)); + return isRecursive(); +} + +void UserFunctionCallsite::setSource(const UserFunction::Ptr &userFunction, + const VariableSlotID cacheSlotOffset) +{ + m_functionDeclaration = userFunction; + m_body = userFunction->body(); + m_expressionSlotOffset = userFunction->expressionSlotOffset(); + + const int len = m_operands.size(); + + const VariableDeclaration::List varDecls(userFunction->argumentDeclarations()); + + for(int i = 0; i < len; ++i) + { + /* We don't want evaluation caches for range variables, it's not necessary since + * the item is already cached in DynamicContext::rangeVariable(). */ + if(m_operands.at(i)->is(IDRangeVariableReference)) + continue; + + /* Note that we pass in cacheSlotOffset + i here instead of varDecls.at(i)->slot since + * we want independent caches for each callsite. */ + m_operands[i] = Expression::Ptr(new EvaluationCache<false>(m_operands.at(i), + varDecls.at(i), + cacheSlotOffset + i)); + } +} + +FunctionSignature::Arity UserFunctionCallsite::arity() const +{ + return m_arity; +} + +CallTargetDescription::Ptr UserFunctionCallsite::callTargetDescription() const +{ + return m_functionDeclaration->signature(); +} + +QT_END_NAMESPACE |