Skip to content

Commit 3a593f5

Browse files
committed
Implement 'for' loops with 'if' condition
1 parent 3f4c4b6 commit 3a593f5

File tree

7 files changed

+97
-10
lines changed

7 files changed

+97
-10
lines changed

src/expression_parser.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ RendererPtr ExpressionParser::Parse(LexScanner& lexer)
2121
return result;
2222
}
2323

24-
ExpressionEvaluatorPtr<FullExpressionEvaluator> ExpressionParser::ParseFullExpression(LexScanner &lexer)
24+
ExpressionEvaluatorPtr<FullExpressionEvaluator> ExpressionParser::ParseFullExpression(LexScanner &lexer, bool includeIfPart)
2525
{
2626
ExpressionEvaluatorPtr<FullExpressionEvaluator> result;
2727
LexScanner::StateSaver saver(lexer);
@@ -45,11 +45,14 @@ ExpressionEvaluatorPtr<FullExpressionEvaluator> ExpressionParser::ParseFullExpre
4545
ExpressionEvaluatorPtr<IfExpression> ifExpr;
4646
if (lexer.PeekNextToken() == Token::If)
4747
{
48-
lexer.EatToken();
49-
ifExpr = ParseIfExpression(lexer);
50-
if (!ifExpr)
51-
return result;
52-
evaluator->SetTester(ifExpr);
48+
if (includeIfPart)
49+
{
50+
lexer.EatToken();
51+
ifExpr = ParseIfExpression(lexer);
52+
if (!ifExpr)
53+
return result;
54+
evaluator->SetTester(ifExpr);
55+
}
5356
}
5457

5558
saver.Commit();

src/expression_parser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class ExpressionParser
1212
public:
1313
ExpressionParser();
1414
RendererPtr Parse(LexScanner& lexer);
15-
ExpressionEvaluatorPtr<FullExpressionEvaluator> ParseFullExpression(LexScanner& lexer);
15+
ExpressionEvaluatorPtr<FullExpressionEvaluator> ParseFullExpression(LexScanner& lexer, bool includeIfPart = true);
1616
private:
1717
ExpressionEvaluatorPtr<Expression> ParseLogicalNot(LexScanner& lexer);
1818
ExpressionEvaluatorPtr<Expression> ParseLogicalOr(LexScanner& lexer);

src/internal_value.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,18 @@ class ListAdapter
7171
public:
7272
ListAdapter() {}
7373
explicit ListAdapter(ListAccessorProvider prov) : m_accessorProvider(std::move(prov)) {}
74+
ListAdapter(const ListAdapter&) = default;
75+
ListAdapter(ListAdapter&&) = default;
7476

7577
static ListAdapter CreateAdapter(InternalValueList&& values);
7678
static ListAdapter CreateAdapter(const GenericList& values);
7779
static ListAdapter CreateAdapter(const ValuesList& values);
7880
static ListAdapter CreateAdapter(GenericList&& values);
7981
static ListAdapter CreateAdapter(ValuesList&& values);
8082

83+
ListAdapter& operator = (const ListAdapter&) = default;
84+
ListAdapter& operator = (ListAdapter&&) = default;
85+
8186
size_t GetSize() const
8287
{
8388
if (m_accessorProvider && m_accessorProvider())

src/statements.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,28 @@ void ForStatement::Render(OutStream& os, RenderContext& values)
1818
if (!isConverted)
1919
return;
2020

21+
if (m_ifExpr)
22+
{
23+
auto& tempContext = values.EnterScope();
24+
InternalValueList newLoopItems;
25+
for (auto& curValue : loopItems)
26+
{
27+
if (m_vars.size() > 1)
28+
{
29+
for (auto& varName : m_vars)
30+
tempContext[varName] = Subscript(curValue, varName);
31+
}
32+
else
33+
tempContext[m_vars[0]] = curValue;
34+
35+
if (ConvertToBool(m_ifExpr->Evaluate(values)))
36+
newLoopItems.push_back(curValue);
37+
}
38+
values.ExitScope();
39+
40+
loopItems = ListAdapter::CreateAdapter(std::move(newLoopItems));
41+
}
42+
2143
int64_t itemsNum = static_cast<int64_t>(loopItems.GetSize());
2244
loopVar["length"] = InternalValue(itemsNum);
2345
bool loopRendered = false;

src/statements.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ using StatementPtr = std::shared_ptr<T>;
1919
class ForStatement : public Statement
2020
{
2121
public:
22-
ForStatement(std::vector<std::string> vars, ExpressionEvaluatorPtr<> expr)
22+
ForStatement(std::vector<std::string> vars, ExpressionEvaluatorPtr<> expr, ExpressionEvaluatorPtr<> ifExpr)
2323
: m_vars(std::move(vars))
2424
, m_value(expr)
25+
, m_ifExpr(ifExpr)
2526
{
2627
}
2728

@@ -40,6 +41,7 @@ class ForStatement : public Statement
4041
private:
4142
std::vector<std::string> m_vars;
4243
ExpressionEvaluatorPtr<> m_value;
44+
ExpressionEvaluatorPtr<> m_ifExpr;
4345
RendererPtr m_mainBody;
4446
RendererPtr m_elseBody;
4547
};

src/template_parser.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,15 @@ bool StatementsParser::ParseFor(LexScanner& lexer, StatementInfoList& statements
7676
return false;
7777

7878
ExpressionParser exprPraser;
79-
auto valueExpr = exprPraser.ParseFullExpression(lexer);
79+
auto valueExpr = exprPraser.ParseFullExpression(lexer, false);
8080
if (!valueExpr)
8181
return false;
8282

83-
auto renderer = std::make_shared<ForStatement>(vars, valueExpr);
83+
ExpressionEvaluatorPtr<> ifExpr;
84+
if (lexer.EatIfEqual(Token::If))
85+
ifExpr = exprPraser.ParseFullExpression(lexer, false);
86+
87+
auto renderer = std::make_shared<ForStatement>(vars, valueExpr, ifExpr);
8488
StatementInfo statementInfo = StatementInfo::Create(StatementInfo::ForStatement, pos);
8589
statementInfo.renderer = renderer;
8690
statementsInfo.push_back(statementInfo);

test/forloop_test.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,57 @@ a[4] = image[b];
194194
EXPECT_EQ(expectedResult, result);
195195
}
196196

197+
TEST(ForLoopTest, LoopWithIf)
198+
{
199+
std::string source = R"(
200+
{% for i in range(10) if i is even %}
201+
a[{{i}}] = image[{{i}}];
202+
{% endfor %}
203+
)";
204+
205+
Template tpl;
206+
ASSERT_TRUE(tpl.Load(source));
207+
208+
ValuesMap params = {
209+
};
210+
211+
std::string result = tpl.RenderAsString(params);
212+
std::cout << result << std::endl;
213+
std::string expectedResult = R"(
214+
a[0] = image[0];
215+
a[2] = image[2];
216+
a[4] = image[4];
217+
a[6] = image[6];
218+
a[8] = image[8];
219+
)";
220+
EXPECT_EQ(expectedResult, result);
221+
}
222+
223+
TEST(ForLoopTest, LoopVariableWithIf)
224+
{
225+
std::string source = R"(
226+
{% for i in its if i is even%}
227+
{{i}} length={{loop.length}}, index={{loop.index}}, index0={{loop.index0}}, first={{loop.first}}, last={{loop.last}}, previtem={{loop.previtem}}, nextitem={{loop.nextitem}};
228+
{% endfor %}
229+
)";
230+
231+
Template mytemplate;
232+
ASSERT_TRUE(mytemplate.Load(source));
233+
234+
ValuesMap params = {
235+
{"its", ValuesList{0, 1, 2, 3, 4} }
236+
};
237+
238+
std::string result = mytemplate.RenderAsString(params);
239+
std::cout << result << std::endl;
240+
std::string expectedResult = R"(
241+
0 length=3, index=1, index0=0, first=true, last=false, previtem=, nextitem=2;
242+
2 length=3, index=2, index0=1, first=false, last=false, previtem=0, nextitem=4;
243+
4 length=3, index=3, index0=2, first=false, last=true, previtem=2, nextitem=;
244+
)";
245+
EXPECT_EQ(expectedResult, result);
246+
}
247+
197248
TEST(ForLoopTest, LoopVariable)
198249
{
199250
std::string source = R"(

0 commit comments

Comments
 (0)