/****************************************************************************
**
** Copyright (C) 2010 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$
**
****************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
#ifndef Patternist_ParserContext_H
#define Patternist_ParserContext_H
#include <QFlags>
#include <QSharedData>
#include <QStack>
#include <QStringList>
#include <QtGlobal>
#include <QXmlQuery>
#include "qbuiltintypes_p.h"
#include "qfunctionsignature_p.h"
#include "qorderby_p.h"
#include "qtemplatemode_p.h"
#include "quserfunctioncallsite_p.h"
#include "quserfunction_p.h"
#include "qvariabledeclaration_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
namespace QPatternist
{
class Tokenizer;
/**
* @short Contains data used when parsing and tokenizing.
*
* When ExpressionFactory::create() is called, an instance of this class
* is passed to the scanner and parser. It holds all information that is
* needed to create the expression.
*
* @author Frans Englich <frans.englich@nokia.com>
*/
class ParserContext : public QSharedData
{
public:
typedef QExplicitlySharedDataPointer<ParserContext> Ptr;
enum PrologDeclaration
{
BoundarySpaceDecl = 1,
DefaultCollationDecl = 2,
BaseURIDecl = 4,
ConstructionDecl = 8,
OrderingModeDecl = 16,
EmptyOrderDecl = 32,
CopyNamespacesDecl = 64,
DeclareDefaultElementNamespace = 128,
DeclareDefaultFunctionNamespace = 256
};
typedef QFlags<PrologDeclaration> PrologDeclarations;
/**
* Constructs a ParserContext instance.
*
* @param context the static context as defined in XPath. This contain
* namespace bindings, error handler, and other information necessary
* for creating an XPath expression.
* @param lang the particular XPath language sub-set that should be parsed
* @param tokenizer the Tokenizer to use.
* @see ExpressionFactory::LanguageAccent
*/
ParserContext(const StaticContext::Ptr &context,
const QXmlQuery::QueryLanguage lang,
Tokenizer *const tokenizer);
/**
* @short Removes the recently pushed variables from
* scope. The amount of removed variables is @p amount.
*
* finalizePushedVariable() can be seen as popping the variable.
*
*/
void finalizePushedVariable(const int amount = 1,
const bool shouldPop = true);
inline VariableSlotID allocatePositionalSlot()
{
++m_positionSlot;
return m_positionSlot;
}
inline VariableSlotID allocateExpressionSlot()
{
const VariableSlotID retval = m_expressionSlot;
++m_expressionSlot;
return retval;
}
inline VariableSlotID allocateGlobalVariableSlot()
{
++m_globalVariableSlot;
return m_globalVariableSlot;
}
inline bool hasDeclaration(const PrologDeclaration decl) const
{
return m_prologDeclarations.testFlag(decl);
}
inline void registerDeclaration(const PrologDeclaration decl)
{
m_prologDeclarations |= decl;
}
/**
* The namespaces declared with <tt>declare namespace</tt>.
*/
QStringList declaredPrefixes;
/**
* This is a temporary stack, used for keeping variables in scope,
* such as for function arguments & let clauses.
*/
VariableDeclaration::Stack variables;
inline bool isXSLT() const
{
return languageAccent == QXmlQuery::XSLT20;
}
const StaticContext::Ptr staticContext;
/**
* We don't store a Tokenizer::Ptr here, because then we would get a
* circular referencing between ParserContext and XSLTTokenizer, and
* hence they would never destruct.
*/
Tokenizer *const tokenizer;
const QXmlQuery::QueryLanguage languageAccent;
/**
* Only used in the case of XSL-T. Is the name of the initial template
* to call. If null, no name was provided, and regular template
* matching should be done.
*/
QXmlName initialTemplateName;
/**
* Used when parsing direct element constructors. It is used
* for ensuring tags are well-balanced.
*/
QStack<QXmlName> tagStack;
/**
* The actual expression, the Query. This member may be @c null,
* such as in the case of an XQuery library module.
*/
Expression::Ptr queryBody;
/**
* The user functions declared in the prolog.
*/
UserFunction::List userFunctions;
/**
* Contains all calls to user defined functions.
*/
UserFunctionCallsite::List userFunctionCallsites;
/**
* All variables declared with <tt>declare variable</tt>.
*/
VariableDeclaration::List declaredVariables;
inline VariableSlotID currentPositionSlot() const
{
return m_positionSlot;
}
inline VariableSlotID currentExpressionSlot() const
{
return m_expressionSlot;
}
inline void restoreNodeTestSource()
{
nodeTestSource = BuiltinTypes::element;
}
inline VariableSlotID allocateCacheSlot()
{
return ++m_evaluationCacheSlot;
}
inline VariableSlotID allocateCacheSlots(const int count)
{
const VariableSlotID retval = m_evaluationCacheSlot + 1;
m_evaluationCacheSlot += count + 1;
return retval;
}
ItemType::Ptr nodeTestSource;
QStack<Expression::Ptr> typeswitchSource;
/**
* The library module namespace set with <tt>declare module</tt>.
*/
QXmlName::NamespaceCode moduleNamespace;
/**
* When a direct element constructor is processed, resolvers are
* created in order to carry the namespace declarations. In such case,
* the old resolver is pushed here.
*/
QStack<NamespaceResolver::Ptr> resolvers;
/**
* This is used for handling the following obscene case:
*
* - <tt>\<e\>{1}{1}\<\/e\></tt> produce <tt>\<e\>11\</e\></tt>
* - <tt>\<e\>{1, 1}\<\/e\></tt> produce <tt>\<e\>1 1\</e\></tt>
*
* This boolean tracks whether the previous reduction inside element
* content was done with an enclosed expression.
*/
bool isPreviousEnclosedExpr;
int elementConstructorDepth;
QStack<bool> scanOnlyStack;
QStack<OrderBy::Stability> orderStability;
/**
* Whether any prolog declaration that must occur after the first
* group has been encountered.
*/
bool hasSecondPrologPart;
bool preserveNamespacesMode;
bool inheritNamespacesMode;
/**
* Contains all named templates. Since named templates
* can also have rules, each body may also be in templateRules.
*/
QHash<QXmlName, Template::Ptr> namedTemplates;
/**
* All the @c xsl:call-template instructions that we have encountered.
*/
QVector<Expression::Ptr> templateCalls;
/**
* If we're in XSL-T, and a variable reference is encountered
* which isn't in-scope, it's added to this hash since a global
* variable declaration may appear later on.
*
* We use a multi hash, since we can encounter several references to
* the same variable before it's declared.
*/
QMultiHash<QXmlName, Expression::Ptr> unresolvedVariableReferences;
/**
*
* Contains the encountered template rules, as opposed
* to named templates.
*
* The key is the name of the template mode. If it's a default
* constructed value, it's the default mode.
*
* Since templates rules may also be named, each body may also be in
* namedTemplates.
*
* To be specific, the values are not the templates, the values are
* modes, and the TemplateMode contains the patterns and bodies.
*/
QHash<QXmlName, TemplateMode::Ptr> templateRules;
/**
* @short Returns the TemplateMode for @p modeName or @c null if the
* mode being asked for is @c #current.
*/
TemplateMode::Ptr modeFor(const QXmlName &modeName)
{
/* #current is not a mode, so it cannot contain templates. #current
* specifies how to look up templates wrt. mode. This check helps
* code that calls us, asking for the mode it needs to lookup in.
*/
if(modeName == QXmlName(StandardNamespaces::InternalXSLT, StandardLocalNames::current))
return TemplateMode::Ptr();
TemplateMode::Ptr &mode = templateRules[modeName];
if(!mode)
mode = TemplateMode::Ptr(new TemplateMode(modeName));
Q_ASSERT(templateRules[modeName]);
return mode;
}
inline TemplatePattern::ID allocateTemplateID()
{
++m_currentTemplateID;
return m_currentTemplateID;
}
/**
* The @c xsl:param appearing inside template.
*/
VariableDeclaration::List templateParameters;
/**
* The @c xsl:with-param appearing in template calling instruction.
*/
WithParam::Hash templateWithParams;
inline void templateParametersHandled()
{
finalizePushedVariable(templateParameters.count());
templateParameters.clear();
}
inline void templateWithParametersHandled()
{
templateWithParams.clear();
}
inline bool isParsingWithParam() const
{
return m_isParsingWithParam.top();
}
void startParsingWithParam()
{
m_isParsingWithParam.push(true);
}
void endParsingWithParam()
{
m_isParsingWithParam.pop();
}
/**
* This is used to deal with XSL-T's exception to the @c node() type,
* which doesn't match document nodes.
*/
bool isParsingPattern;
ImportPrecedence currentImportPrecedence;
bool isFirstTemplate() const
{
return m_currentTemplateID == InitialTemplateID;
}
/**
* Whether we're processing XSL-T 1.0 code.
*/
QStack<bool> isBackwardsCompat;
private:
enum
{
InitialTemplateID = -1
};
VariableSlotID m_evaluationCacheSlot;
VariableSlotID m_expressionSlot;
VariableSlotID m_positionSlot;
PrologDeclarations m_prologDeclarations;
VariableSlotID m_globalVariableSlot;
TemplatePattern::ID m_currentTemplateID;
/**
* The default is @c false. If we're not parsing @c xsl:with-param,
* hence parsing @c xsl:param, the value has changed.
*/
QStack<bool> m_isParsingWithParam;
Q_DISABLE_COPY(ParserContext)
};
}
QT_END_NAMESPACE
QT_END_HEADER
#endif