Skip to content

Commit b2b7b2d

Browse files
committed
Partially implement recursive loops
1 parent 705ab2f commit b2b7b2d

File tree

4 files changed

+87
-2
lines changed

4 files changed

+87
-2
lines changed

src/statements.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "expression_evaluator.h"
12
#include "statements.h"
23
#include "template_impl.h"
34
#include "value_visitors.h"
@@ -10,10 +11,31 @@ void ForStatement::Render(OutStream& os, RenderContext& values)
1011
{
1112
InternalValue loopVal = m_value->Evaluate(values);
1213

14+
RenderLoop(loopVal, os, values);
15+
}
16+
17+
void ForStatement::RenderLoop(const InternalValue& loopVal, OutStream& os, RenderContext& values)
18+
{
1319
auto& context = values.EnterScope();
1420

1521
InternalValueMap loopVar;
1622
context["loop"] = MapAdapter::CreateAdapter(&loopVar);
23+
if (m_isRecursive)
24+
{
25+
loopVar["operator()"] = Callable([this](const CallParams& params, OutStream& stream, RenderContext& context) {
26+
bool isSucceeded = false;
27+
auto parsedParams = helpers::ParseCallParams({{"var", true}}, params, isSucceeded);
28+
if (!isSucceeded)
29+
return;
30+
31+
auto var = parsedParams["var"];
32+
if (!var)
33+
return;
34+
35+
RenderLoop(var->Evaluate(context), stream, context);
36+
});
37+
38+
}
1739

1840
bool isConverted = false;
1941
auto loopItems = ConvertToList(loopVal, InternalValue(), isConverted);

src/statements.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ class TemplateImpl;
2222
class ForStatement : public Statement
2323
{
2424
public:
25-
ForStatement(std::vector<std::string> vars, ExpressionEvaluatorPtr<> expr, ExpressionEvaluatorPtr<> ifExpr)
25+
ForStatement(std::vector<std::string> vars, ExpressionEvaluatorPtr<> expr, ExpressionEvaluatorPtr<> ifExpr, bool isRecursive)
2626
: m_vars(std::move(vars))
2727
, m_value(expr)
2828
, m_ifExpr(ifExpr)
29+
, m_isRecursive(isRecursive)
2930
{
3031
}
3132

@@ -40,11 +41,15 @@ class ForStatement : public Statement
4041
}
4142

4243
void Render(OutStream& os, RenderContext& values) override;
44+
45+
private:
46+
void RenderLoop(const InternalValue& val, OutStream& os, RenderContext& values);
4347

4448
private:
4549
std::vector<std::string> m_vars;
4650
ExpressionEvaluatorPtr<> m_value;
4751
ExpressionEvaluatorPtr<> m_ifExpr;
52+
bool m_isRecursive;
4853
RendererPtr m_mainBody;
4954
RendererPtr m_elseBody;
5055
};

src/template_parser.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,23 @@ bool StatementsParser::ParseFor(LexScanner& lexer, StatementInfoList& statements
8585
auto valueExpr = exprPraser.ParseFullExpression(lexer, false);
8686
if (!valueExpr)
8787
return false;
88+
89+
Token flagsTok;
90+
bool isRecursive = false;
91+
if (lexer.EatIfEqual(Token::Identifier, &flagsTok))
92+
{
93+
auto flagsName = AsString(flagsTok.value);
94+
if (flagsName != "recursive")
95+
return false;
96+
97+
isRecursive = true;
98+
}
8899

89100
ExpressionEvaluatorPtr<> ifExpr;
90101
if (lexer.EatIfEqual(Token::If))
91102
ifExpr = exprPraser.ParseFullExpression(lexer, false);
92103

93-
auto renderer = std::make_shared<ForStatement>(vars, valueExpr, ifExpr);
104+
auto renderer = std::make_shared<ForStatement>(vars, valueExpr, ifExpr, isRecursive);
94105
StatementInfo statementInfo = StatementInfo::Create(StatementInfo::ForStatement, pos);
95106
statementInfo.renderer = renderer;
96107
statementsInfo.push_back(statementInfo);

test/forloop_test.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,3 +337,50 @@ b[1] = image[1];
337337
}
338338

339339

340+
TEST(ForLoopTest, DISABLED_RecursiveLoop)
341+
{
342+
std::string source = R"(
343+
{%set items=[
344+
{'name'='root1', 'children'=[
345+
{'name'='child1_1'},
346+
{'name'='child1_2'},
347+
{'name'='child1_3'}
348+
]},
349+
{'name'='root2', 'children'=[
350+
{'name'='child2_1'},
351+
{'name'='child2_2'},
352+
{'name'='child2_3'}
353+
]},
354+
{'name'='root3', 'children'=[
355+
{'name'='child3_1'},
356+
{'name'='child3_2'},
357+
{'name'='child3_3'}
358+
]}
359+
] %}
360+
{% for i in items recursive %}
361+
{{i.name}} -> {{loop(i.children)}}
362+
{% endfor %}
363+
)";
364+
365+
Template tpl;
366+
ASSERT_TRUE(tpl.Load(source));
367+
368+
ValuesMap params = {};
369+
370+
std::string result = tpl.RenderAsString(params);
371+
std::cout << "[" << result << "]" << std::endl;
372+
std::string expectedResult = R"DELIM(
373+
a[0] = image[0];
374+
b[0] = image[0];
375+
b[1] = image[1];
376+
a[1] = image[1];
377+
b[0] = image[0];
378+
b[1] = image[1];
379+
a[2] = image[2];
380+
b[0] = image[0];
381+
b[1] = image[1];
382+
)DELIM";
383+
384+
EXPECT_EQ(expectedResult, result);
385+
}
386+

0 commit comments

Comments
 (0)