summaryrefslogtreecommitdiffstats
path: root/desktop-widgets/templatelayout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'desktop-widgets/templatelayout.cpp')
-rw-r--r--desktop-widgets/templatelayout.cpp72
1 files changed, 48 insertions, 24 deletions
diff --git a/desktop-widgets/templatelayout.cpp b/desktop-widgets/templatelayout.cpp
index 89222b8a8..c69d24b29 100644
--- a/desktop-widgets/templatelayout.cpp
+++ b/desktop-widgets/templatelayout.cpp
@@ -129,8 +129,7 @@ QString TemplateLayout::generate()
QList<token> tokens = lexer(templateContents);
QString buffer;
QTextStream out(&buffer);
- int pos = 0;
- parser(tokens, pos, out, state);
+ parser(tokens, 0, tokens.size(), out, state);
htmlContent = out.readAll();
return htmlContent;
}
@@ -156,8 +155,7 @@ QString TemplateLayout::generateStatistics()
QList<token> tokens = lexer(templateContents);
QString buffer;
QTextStream out(&buffer);
- int pos = 0;
- parser(tokens, pos, out, state);
+ parser(tokens, 0, tokens.size(), out, state);
htmlContent = out.readAll();
return htmlContent;
}
@@ -286,35 +284,47 @@ static QRegularExpression forloop(R"(\s*(\w+)\s+in\s+(\w+))"); // Look for "VAR
static QRegularExpression ifstatement(R"(forloop\.counter\|\s*divisibleby\:\s*(\d+))"); // Look for forloop.counter|divisibleby: NUMBER
template<typename V, typename T>
-void TemplateLayout::parser_for(QList<token> tokenList, int &pos, QTextStream &out, State &state,
+void TemplateLayout::parser_for(QList<token> tokenList, int from, int to, QTextStream &out, State &state,
const V &data, const T *&act)
{
const T *old = act;
int i = 1; // Loop iterators start at one
int olditerator = state.forloopiterator;
- int savepos = pos;
for (const T &item: data) {
act = &item;
- state.forloopiterator = i;
- pos = savepos;
- ++i;
- parser(tokenList, pos, out, state);
+ state.forloopiterator = i++;
+ parser(tokenList, from, to, out, state);
}
act = old;
state.forloopiterator = olditerator;
}
-void TemplateLayout::parser(QList<token> tokenList, int &pos, QTextStream &out, State &state)
+// Find end of for or if block. Keeps track of nested blocks.
+// Pos should point one past the starting tag.
+// Returns -1 if no matching end tag found.
+static int findEnd(const QList<token> &tokenList, int from, int to, token_t start, token_t end)
{
- while (pos < tokenList.length()) {
+ int depth = 1;
+ for (int pos = from; pos < to; ++pos) {
+ if (tokenList[pos].type == start) {
+ ++depth;
+ } else if (tokenList[pos].type == end) {
+ if (--depth <= 0)
+ return pos;
+ }
+ }
+ return -1;
+}
+
+void TemplateLayout::parser(QList<token> tokenList, int from, int to, QTextStream &out, State &state)
+{
+ for (int pos = from; pos < to; ++pos) {
switch (tokenList[pos].type) {
case LITERAL:
out << translate(tokenList[pos].contents, state);
- ++pos;
break;
case BLOCKSTART:
case BLOCKSTOP:
- ++pos;
break;
case FORSTART:
{
@@ -327,23 +337,31 @@ void TemplateLayout::parser(QList<token> tokenList, int &pos, QTextStream &out,
state.types[itemname] = listname;
QString buffer;
QTextStream capture(&buffer);
+ int loop_end = findEnd(tokenList, pos, to, FORSTART, FORSTOP);
+ if (loop_end < 0) {
+ out << "UNMATCHED FOR: '" << argument << "'";
+ break;
+ }
if (listname == "years") {
- parser_for(tokenList, pos, capture, state, state.years, state.currentYear);
+ parser_for(tokenList, pos, loop_end, capture, state, state.years, state.currentYear);
} else if (listname == "dives") {
- parser_for(tokenList, pos, capture, state, state.dives, state.currentDive);
+ parser_for(tokenList, pos, loop_end, capture, state, state.dives, state.currentDive);
} else if (listname == "cylinders") {
if (state.currentDive)
- parser_for(tokenList, pos, capture, state, state.currentDive->cylinders, state.currentCylinder);
+ parser_for(tokenList, pos, loop_end, capture, state, state.currentDive->cylinders, state.currentCylinder);
else
qWarning("cylinders loop outside of dive");
} else if (listname == "cylinderObjects") {
if (state.currentDive)
- parser_for(tokenList, pos, capture, state, state.currentDive->cylinderObjects, state.currentCylinderObject);
+ parser_for(tokenList, pos, loop_end, capture, state, state.currentDive->cylinderObjects, state.currentCylinderObject);
else
qWarning("cylinderObjects loop outside of dive");
+ } else {
+ qWarning("unknown loop: %s", qPrintable(listname));
}
state.types.remove(itemname);
out << capture.readAll();
+ pos = loop_end;
} else {
out << "PARSING ERROR: '" << argument << "'";
}
@@ -355,13 +373,20 @@ void TemplateLayout::parser(QList<token> tokenList, int &pos, QTextStream &out,
++pos;
QRegularExpressionMatch match = ifstatement.match(argument);
if (match.hasMatch()) {
+ int if_end = findEnd(tokenList, pos, to, IFSTART, IFSTOP);
+ if (if_end < 0) {
+ out << "UNMATCHED IF: '" << argument << "'";
+ break;
+ }
int divisor = match.captured(1).toInt();
- QString buffer;
- QTextStream capture(&buffer);
int counter = std::max(0, state.forloopiterator);
- parser(tokenList, pos, capture, state);
- if (!(counter % divisor))
+ if (!(counter % divisor)) {
+ QString buffer;
+ QTextStream capture(&buffer);
+ parser(tokenList, pos, if_end, capture, state);
out << capture.readAll();
+ }
+ pos = if_end;
} else {
out << "PARSING ERROR: '" << argument << "'";
}
@@ -369,11 +394,10 @@ void TemplateLayout::parser(QList<token> tokenList, int &pos, QTextStream &out,
break;
case FORSTOP:
case IFSTOP:
- ++pos;
+ out << "UNEXPECTED END: " << tokenList[pos].contents;
return;
case PARSERERROR:
out << "PARSING ERROR";
- ++pos;
}
}
}