2
This file is part of the Grantlee template system.
4
Copyright (c) 2009,2010 Stephen Kelly <steveire@gmail.com>
6
This library is free software; you can redistribute it and/or
7
modify it under the terms of the GNU Lesser General Public
8
License as published by the Free Software Foundation; either version
9
2 of the Licence, or (at your option) any later version.
11
This library is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
Library General Public License for more details.
16
You should have received a copy of the GNU Lesser General Public
17
License along with this library. If not, see <http://www.gnu.org/licenses/>.
23
#include <QtCore/QFile>
25
#include "nodebuiltins_p.h"
26
#include "taglibraryinterface.h"
28
#include "template_p.h"
31
#include "exception.h"
33
#include "grantlee_version.h"
35
using namespace Grantlee;
43
ParserPrivate( Parser *parser, const QList<Token> &tokenList )
45
m_tokenList( tokenList ) {
49
NodeList extendNodeList( NodeList list, Node *node );
52
Parses the template to create a Nodelist.
53
The given @p parent is the parent of each node in the returned list.
55
NodeList parse( QObject *parent, const QStringList &stopAt = QStringList() );
57
void openLibrary( TagLibraryInterface * library );
58
Q_DECLARE_PUBLIC( Parser )
61
QList<Token> m_tokenList;
63
QHash<QString, AbstractNodeFactory*> m_nodeFactories;
64
QHash<QString, Filter::Ptr> m_filters;
71
void ParserPrivate::openLibrary( TagLibraryInterface *library )
74
QHashIterator<QString, AbstractNodeFactory*> nodeIt( library->nodeFactories() );
76
TemplateImpl *ti = qobject_cast<TemplateImpl *>( q->parent() );
78
Engine const *cengine = ti->engine();
81
Engine *engine = const_cast<Engine *>( cengine );
83
while ( nodeIt.hasNext() ) {
85
nodeIt.value()->setEngine( engine );
86
m_nodeFactories.insert( nodeIt.key(), nodeIt.value() );
88
QHashIterator<QString, Filter*> filterIt( library->filters() );
89
while ( filterIt.hasNext() ) {
91
Filter::Ptr f = Filter::Ptr( filterIt.value() );
92
m_filters.insert( filterIt.key(), f );
96
Parser::Parser( const QList<Token> &tokenList, QObject *parent )
97
: QObject( parent ), d_ptr( new ParserPrivate( this, tokenList ) )
101
TemplateImpl *ti = qobject_cast<TemplateImpl *>( parent );
103
Engine const *cengine = ti->engine();
106
Engine *engine = const_cast<Engine *>( cengine );
107
engine->loadDefaultLibraries();
108
Q_FOREACH( const QString &libraryName, engine->defaultLibraries() ) {
109
TagLibraryInterface *library = engine->loadLibrary( libraryName );
112
d->openLibrary( library );
118
// Don't delete filters here because filters must out-live the parser in the
119
// filter expressions.
120
qDeleteAll( d_ptr->m_nodeFactories );
125
void Parser::setTokens( const QList< Token >& tokenList )
128
d->m_tokenList = tokenList;
132
void Parser::loadLib( const QString &name )
135
TemplateImpl *ti = qobject_cast<TemplateImpl *>( parent() );
136
Engine const *cengine = ti->engine();
139
Engine *engine = const_cast<Engine *>( cengine );
140
TagLibraryInterface *library = engine->loadLibrary( name );
143
d->openLibrary( library );
146
NodeList ParserPrivate::extendNodeList( NodeList list, Node *node )
148
if ( node->mustBeFirst() && list.containsNonText() ) {
149
throw Grantlee::Exception( TagSyntaxError, QString(
150
"Node appeared twice in template: %1" ).arg( node->metaObject()->className() ) );
157
void Parser::skipPast( const QString &tag )
159
while ( hasNextToken() ) {
160
Token token = takeNextToken();
161
if ( token.tokenType == BlockToken && token.content.trimmed() == tag )
164
throw Grantlee::Exception( UnclosedBlockTagError, QString( "No closing tag found for %1" ).arg( tag ) );
167
Filter::Ptr Parser::getFilter( const QString &name ) const
170
if ( !d->m_filters.contains( name ) )
171
throw Grantlee::Exception( UnknownFilterError, QString( "Unknown filter: %1" ).arg( name ) );
172
return d->m_filters.value( name );
175
NodeList Parser::parse( Node *parent, const QString &stopAt )
178
return d->parse( parent, QStringList() << stopAt );
181
NodeList Parser::parse( TemplateImpl *parent, const QStringList &stopAt )
184
return d->parse( parent, stopAt );
187
NodeList Parser::parse( Node *parent, const QStringList &stopAt )
190
return d->parse( parent, stopAt );
193
NodeList ParserPrivate::parse( QObject *parent, const QStringList &stopAt )
198
while ( q->hasNextToken() ) {
199
Token token = q->takeNextToken();
200
if ( token.tokenType == TextToken ) {
201
nodeList = extendNodeList( nodeList, new TextNode( token.content, parent ) );
202
} else if ( token.tokenType == VariableToken ) {
203
if ( token.content.isEmpty() ) {
204
// Error. Empty variable
206
if ( q->hasNextToken() )
207
message = QString( "Empty variable before \"%1\", line %2, %3" ).arg( q->takeNextToken().content.left( 20 ) ).arg( token.linenumber ).arg( q->parent()->objectName() );
209
message = QString( "Empty variable at end of input." );
211
throw Grantlee::Exception( EmptyVariableError, message );
214
FilterExpression filterExpression;
216
filterExpression = FilterExpression( token.content, q );
217
} catch ( Grantlee::Exception e )
219
throw Grantlee::Exception( e.errorCode(), QString( "%1, line %2, %3" ).arg( e.what() )
220
.arg( token.linenumber )
221
.arg( q->parent()->objectName() ) );
224
nodeList = extendNodeList( nodeList, new VariableNode( filterExpression, parent ) );
225
} else if ( token.tokenType == BlockToken ) {
226
if ( stopAt.contains( token.content ) ) {
227
// put the token back.
228
q->prependToken( token );
232
QStringList tagContents = token.content.split( ' ' );
233
if ( tagContents.size() == 0 ) {
235
if ( q->hasNextToken() )
236
message = QString( "Empty block tag before \"%1\", line %2, %3" ).arg( token.content.left( 20 ) ).arg( token.linenumber ).arg( q->parent()->objectName() );
238
message = QString( "Empty block tag at end of input." );
240
throw Grantlee::Exception( EmptyBlockTagError, message );
242
QString command = tagContents.at( 0 );
243
AbstractNodeFactory *nodeFactory = m_nodeFactories[command];
246
if ( !nodeFactory ) {
247
throw Grantlee::Exception( InvalidBlockTagError, QString( "Unknown tag: \"%1\", line %2, %3" ).arg( command ).arg( token.linenumber ).arg( q->parent()->objectName() ) );
250
// TODO: Make getNode take a Token instead?
253
n = nodeFactory->getNode( token.content, q );
254
} catch ( Grantlee::Exception e ){
255
throw Grantlee::Exception( e.errorCode(), QString( "%1, line %2, %3" ).arg( e.what() )
256
.arg( token.linenumber )
257
.arg( q->parent()->objectName() ) );
260
throw Grantlee::Exception( EmptyBlockTagError, QString( "Failed to get node from %1, line %2, %3" ).arg( command ).arg( token.linenumber ).arg( q->parent()->objectName() ) );
263
n->setParent( parent );
265
nodeList = extendNodeList( nodeList, n );
269
if ( !stopAt.isEmpty() ) {
270
QString message = QString( "Unclosed tag in template %1. Expected one of: (%2)" ).arg( q->parent()->objectName() ).arg( stopAt.join( " " ) );
271
throw Grantlee::Exception( UnclosedBlockTagError, message );
278
bool Parser::hasNextToken() const
281
return d->m_tokenList.size() > 0;
284
Token Parser::takeNextToken()
287
return d->m_tokenList.takeAt( 0 );
290
void Parser::removeNextToken()
293
if ( !d->m_tokenList.isEmpty() )
294
d->m_tokenList.removeAt( 0 );
297
void Parser::prependToken( const Token &token )
300
d->m_tokenList.prepend( token );
303
#include "parser.moc"