24 #include "exception.h"
26 #include "cutelee_version.h"
27 #include "nodebuiltins_p.h"
28 #include "taglibraryinterface.h"
30 #include "template_p.h"
41 : q_ptr(parser), m_tokenList(tokenList)
57 QList<Token> m_tokenList;
59 QHash<QString, AbstractNodeFactory *> m_nodeFactories;
60 QHash<QString, std::shared_ptr<Filter>> m_filters;
70 auto ti = qobject_cast<TemplateImpl *>(q->parent());
72 auto cengine = ti->engine();
74 auto engine =
const_cast<Engine *
>(cengine);
77 for (
auto nodeIt = factories.begin(), nodeEnd = factories.end();
78 nodeIt != nodeEnd; ++nodeIt) {
79 nodeIt.value()->setEngine(engine);
80 m_nodeFactories.insert(nodeIt.key(), nodeIt.value());
82 auto filters = library->
filters();
83 for (
auto filterIt = filters.begin(), filterEnd = filters.end();
84 filterIt != filterEnd; ++filterIt) {
85 auto f = std::shared_ptr<Filter>(filterIt.value());
86 m_filters.insert(filterIt.key(), f);
95 auto ti = qobject_cast<TemplateImpl *>(parent);
97 auto cengine = ti->engine();
100 auto engine =
const_cast<Engine *
>(cengine);
101 engine->loadDefaultLibraries();
103 for (
const QString &libraryName : libs) {
104 auto library = engine->loadLibrary(libraryName);
107 d->openLibrary(library);
115 qDeleteAll(d_ptr->m_nodeFactories);
119 void Parser::loadLib(
const QString &name)
122 auto ti = qobject_cast<TemplateImpl *>(parent());
123 auto cengine = ti->engine();
125 auto engine =
const_cast<Engine *
>(cengine);
126 auto library = engine->loadLibrary(name);
129 d->openLibrary(library);
137 QStringLiteral(
"Node appeared twice in template: %1")
138 .arg(QLatin1String(node->metaObject()->className())));
149 if (token.tokenType ==
BlockToken && token.content == tag)
153 UnclosedBlockTagError,
154 QStringLiteral(
"No closing tag found for %1").arg(tag));
160 const auto it = d->m_filters.constFind(name);
161 if (Q_LIKELY(it != d->m_filters.constEnd())) {
165 QStringLiteral(
"Unknown filter: %1").arg(name));
171 return d->parse(parent, {stopAt});
177 return d->parse(parent, stopAt);
183 return d->parse(parent, stopAt);
191 while (q->hasNextToken()) {
192 const auto token = q->takeNextToken();
194 nodeList = extendNodeList(nodeList,
new TextNode(token.content, parent));
196 if (token.content.isEmpty()) {
199 Q_ASSERT(q->hasNextToken());
200 message = QStringLiteral(
"Empty variable before \"%1\", line %2, %3")
201 .arg(q->takeNextToken().content.left(20))
202 .arg(token.linenumber)
203 .arg(q->parent()->objectName());
212 QStringLiteral(
"%1, line %2, %3")
214 .arg(token.linenumber)
215 .arg(q->parent()->objectName()));
218 nodeList = extendNodeList(nodeList,
219 new VariableNode(filterExpression, parent));
222 const auto command = token.content.section(QLatin1Char(
' '), 0, 0);
223 if (stopAt.contains(command)) {
227 q->prependToken(token);
231 if (command.isEmpty()) {
233 Q_ASSERT(q->hasNextToken());
234 message = QStringLiteral(
"Empty block tag before \"%1\", line %2, %3")
235 .arg(token.content.left(20))
236 .arg(token.linenumber)
237 .arg(q->parent()->objectName());
241 auto nodeFactory = m_nodeFactories[command];
245 q->invalidBlockTag(token, command, stopAt);
251 n = nodeFactory->getNode(token.content, q);
254 QStringLiteral(
"%1, line %2, %3")
256 .arg(token.linenumber)
257 .arg(q->parent()->objectName()));
262 QStringLiteral(
"Failed to get node from %1, line %2, %3")
264 .arg(token.linenumber)
265 .arg(q->parent()->objectName()));
268 n->setParent(parent);
270 nodeList = extendNodeList(nodeList, n);
274 if (!stopAt.isEmpty()) {
276 = QStringLiteral(
"Unclosed tag in template %1. Expected one of: (%2)")
277 .arg(q->parent()->objectName(),
278 stopAt.join(QChar::fromLatin1(
' ')));
288 return !d->m_tokenList.isEmpty();
294 return d->m_tokenList.takeFirst();
300 d->m_tokenList.removeFirst();
303 void Parser::invalidBlockTag(
const Token &token,
const QString &command,
304 const QStringList &stopAt)
306 if (!stopAt.empty()) {
308 InvalidBlockTagError,
309 QStringLiteral(
"Invalid block tag on line %1: '%2', expected '%3'")
311 .arg(command, stopAt.join(QStringLiteral(
"', '"))));
314 InvalidBlockTagError,
315 QStringLiteral(
"Invalid block tag on line %1: '%2\''. Did you forget "
316 "to register or load this tag?")
325 d->m_tokenList.prepend(token);
Cutelee::Engine is the main entry point for creating Cutelee Templates.
QStringList defaultLibraries() const
An exception for use when implementing template tags.
A FilterExpression object represents a filter expression in a template.
A list of Nodes with some convenience API for rendering them.
bool containsNonText() const
void append(Cutelee::Node *node)
Base class for all nodes.
NodeList parse(QObject *parent, const QStringList &stopAt)
The Parser class processes a string template into a tree of nodes.
bool hasNextToken() const
void skipPast(const QString &tag)
void prependToken(const Token &token)
NodeList parse(Node *parent, const QStringList &stopAt={})
std::shared_ptr< Filter > getFilter(const QString &name) const
Parser(const QList< Token > &tokenList, QObject *parent)
The TagLibraryInterface returns available tags and filters from libraries.
virtual QHash< QString, Filter * > filters(const QString &name={})
virtual QHash< QString, AbstractNodeFactory * > nodeFactories(const QString &name={})
The Cutelee namespace holds all public Cutelee API.
@ BlockToken
The Token is a block, ie, part of a tag.
@ TextToken
The Token is a text fragment.
@ VariableToken
The Token is a variable node.
int linenumber
The line number this Token starts at.