Skip to content

Commit a2d6177

Browse files
committed
Refine 'CallParams' struct and implement parser for '[]' tuples and
dictionaries
1 parent 3e6bea2 commit a2d6177

File tree

9 files changed

+183
-30
lines changed

9 files changed

+183
-30
lines changed

src/expression_evaluator.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ Value DictCreator::Evaluate(RenderContext& context)
109109
return Value(result);
110110
}
111111

112-
ExpressionFilter::ExpressionFilter(std::string filterName, std::unordered_map<std::string, ExpressionEvaluatorPtr<> > params)
112+
ExpressionFilter::ExpressionFilter(std::string filterName, CallParams params)
113113
{
114114
auto p = s_filters.find(filterName);
115115
if (p == s_filters.end())
@@ -126,7 +126,7 @@ Value ExpressionFilter::Evaluate(const Value& baseVal, RenderContext& context)
126126
return m_filter->Filter(baseVal, context);
127127
}
128128

129-
IsExpression::IsExpression(ExpressionEvaluatorPtr<> value, std::string tester, CallParamsList params)
129+
IsExpression::IsExpression(ExpressionEvaluatorPtr<> value, std::string tester, CallParams params)
130130
: m_value(value)
131131
{
132132
auto p = s_testers.find(tester);
@@ -151,4 +151,15 @@ Value IfExpression::EvaluateAltValue(RenderContext& context)
151151
return m_altValue ? m_altValue->Evaluate(context) : Value();
152152
}
153153

154+
Value DictionaryCreator::Evaluate(RenderContext& context)
155+
{
156+
ValuesMap result;
157+
for (auto& i : m_items)
158+
{
159+
result[i.first] = i.second->Evaluate(context);
160+
}
161+
162+
return result;
163+
}
164+
154165
}

src/expression_evaluator.h

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ template<typename T = ExpressionEvaluatorBase>
2121
using ExpressionEvaluatorPtr = std::shared_ptr<T>;
2222
using Expression = ExpressionEvaluatorBase;
2323

24-
using CallParamsList = std::unordered_map<std::string, ExpressionEvaluatorPtr<>>;
24+
struct CallParams
25+
{
26+
std::unordered_map<std::string, ExpressionEvaluatorPtr<>> kwParams;
27+
std::vector<ExpressionEvaluatorPtr<>> posParams;
28+
};
2529

2630
class ExpressionFilter;
2731
class IfExpression;
@@ -102,6 +106,20 @@ class TupleCreator : public Expression
102106
std::vector<ExpressionEvaluatorPtr<>> m_exprs;
103107
};
104108

109+
class DictionaryCreator : public Expression
110+
{
111+
public:
112+
DictionaryCreator(std::unordered_map<std::string, ExpressionEvaluatorPtr<>> items)
113+
: m_items(std::move(items))
114+
{
115+
}
116+
117+
Value Evaluate(RenderContext&) override;
118+
119+
private:
120+
std::unordered_map<std::string, ExpressionEvaluatorPtr<>> m_items;
121+
};
122+
105123
class DictCreator : public Expression
106124
{
107125
public:
@@ -183,9 +201,9 @@ class IsExpression : public Expression
183201
virtual bool Test(const Value& baseVal, RenderContext& context) = 0;
184202
};
185203

186-
using TesterFactoryFn = std::function<std::shared_ptr<ITester> (CallParamsList params)>;
204+
using TesterFactoryFn = std::function<std::shared_ptr<ITester> (CallParams params)>;
187205

188-
IsExpression(ExpressionEvaluatorPtr<> value, std::string tester, CallParamsList params);
206+
IsExpression(ExpressionEvaluatorPtr<> value, std::string tester, CallParams params);
189207
Value Evaluate(RenderContext& context) override;
190208

191209
private:
@@ -205,9 +223,9 @@ class ExpressionFilter
205223
virtual Value Filter(const Value& baseVal, RenderContext& context) = 0;
206224
};
207225

208-
using FilterFactoryFn = std::function<std::shared_ptr<IExpressionFilter> (CallParamsList params)>;
226+
using FilterFactoryFn = std::function<std::shared_ptr<IExpressionFilter> (CallParams params)>;
209227

210-
ExpressionFilter(std::string filterName, CallParamsList params);
228+
ExpressionFilter(std::string filterName, CallParams params);
211229

212230
Value Evaluate(const Value& baseVal, RenderContext& context);
213231
void SetParentFilter(std::shared_ptr<ExpressionFilter> parentFilter)
@@ -247,18 +265,23 @@ class IfExpression
247265

248266
namespace helpers
249267
{
250-
inline bool FindParam(const CallParamsList& params, std::string posName, std::string paramName, ExpressionEvaluatorPtr<>& value)
251-
{
252-
auto p = params.find(paramName);
253-
if (p == params.end())
254-
p = params.find(posName);
268+
constexpr size_t NoPosParam = std::numeric_limits<size_t>::max();
255269

256-
if (p != params.end())
270+
inline bool FindParam(const CallParams& params, size_t pos, std::string paramName, ExpressionEvaluatorPtr<>& value)
271+
{
272+
auto p = params.kwParams.find(paramName);
273+
if (p != params.kwParams.end())
257274
{
258275
value = p->second;
259276
return true;
260277
}
261278

279+
if (pos < params.posParams.size())
280+
{
281+
value = params.posParams[pos];
282+
return true;
283+
}
284+
262285
return false;
263286
}
264287
}

src/expression_parser.cpp

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ ExpressionEvaluatorPtr<Expression> ExpressionParser::ParseLogicalCompare(LexScan
132132

133133
std::string name = tok.value.asString();
134134
bool valid = true;
135-
CallParamsList params;
135+
CallParams params;
136136

137137
if (lexer.NextToken() == '(')
138138
params = ParseCallParams(lexer, valid);
@@ -314,6 +314,8 @@ ExpressionEvaluatorPtr<Expression> ExpressionParser::ParseValueExpression(LexSca
314314
return std::make_shared<ConstantExpression>(Value(false));
315315
case '(':
316316
return ParseBracedExpressionOrTuple(lexer);
317+
case '[':
318+
return ParseTuple(lexer);
317319
case '{':
318320
return ParseDictionary(lexer);
319321
}
@@ -355,6 +357,51 @@ ExpressionEvaluatorPtr<Expression> ExpressionParser::ParseDictionary(LexScanner&
355357
{
356358
ExpressionEvaluatorPtr<Expression> result;
357359

360+
std::unordered_map<std::string, ExpressionEvaluatorPtr<Expression>> items;
361+
while (lexer.NextToken() != '}')
362+
{
363+
lexer.ReturnToken();;
364+
Token key = lexer.NextToken();
365+
if (key != Token::String)
366+
return result;
367+
368+
if (lexer.NextToken() != '=')
369+
return result;
370+
371+
auto expr = ParseFullExpression(lexer);
372+
if (!expr)
373+
return result;
374+
375+
items[key.value.asString()] = expr;
376+
377+
if (lexer.PeekNextToken() == ',')
378+
lexer.EatToken();
379+
}
380+
381+
result = std::make_shared<DictionaryCreator>(std::move(items));
382+
383+
return result;
384+
}
385+
386+
ExpressionEvaluatorPtr<Expression> ExpressionParser::ParseTuple(LexScanner& lexer)
387+
{
388+
ExpressionEvaluatorPtr<Expression> result;
389+
390+
std::vector<ExpressionEvaluatorPtr<Expression>> exprs;
391+
while (lexer.NextToken() != ']')
392+
{
393+
lexer.ReturnToken();
394+
auto expr = ParseFullExpression(lexer);
395+
if (!expr)
396+
return result;
397+
398+
exprs.push_back(expr);
399+
if (lexer.PeekNextToken() == ',')
400+
lexer.EatToken();
401+
}
402+
403+
result = std::make_shared<TupleCreator>(std::move(exprs));
404+
358405
return result;
359406
}
360407

@@ -390,11 +437,11 @@ ExpressionEvaluatorPtr<Expression> ExpressionParser::ParseCall(LexScanner& lexer
390437
return result;
391438
}
392439

393-
std::unordered_map<std::string, ExpressionEvaluatorPtr<> > ExpressionParser::ParseCallParams(LexScanner& lexer, bool& isValid)
440+
CallParams ExpressionParser::ParseCallParams(LexScanner& lexer, bool& isValid)
394441
{
395-
std::unordered_map<std::string, ExpressionEvaluatorPtr<> > result;
442+
CallParams result;
396443

397-
int posParamId = 0;
444+
isValid = true;
398445
while (lexer.NextToken() != ')')
399446
{
400447
lexer.ReturnToken();
@@ -408,9 +455,6 @@ std::unordered_map<std::string, ExpressionEvaluatorPtr<> > ExpressionParser::Par
408455
else
409456
{
410457
lexer.ReturnToken();
411-
std::ostringstream str;
412-
str << "param" << posParamId ++;
413-
paramName = str.str();
414458
}
415459

416460
auto valueExpr = ParseFullExpression(lexer);
@@ -419,7 +463,11 @@ std::unordered_map<std::string, ExpressionEvaluatorPtr<> > ExpressionParser::Par
419463
isValid = false;
420464
return result;
421465
}
422-
result[paramName] = valueExpr;
466+
if (paramName.empty())
467+
result.posParams.push_back(valueExpr);
468+
else
469+
result.kwParams[paramName] = valueExpr;
470+
423471
if (lexer.PeekNextToken() == ',')
424472
lexer.EatToken();
425473
}
@@ -463,7 +511,7 @@ ExpressionEvaluatorPtr<ExpressionFilter> ExpressionParser::ParseFilterExpression
463511

464512
std::string name = tok.value.asString();
465513
bool valid = true;
466-
std::unordered_map<std::string, ExpressionEvaluatorPtr<>> params;
514+
CallParams params;
467515

468516
if (lexer.NextToken() == '(')
469517
params = ParseCallParams(lexer, valid);

src/expression_parser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ class ExpressionParser
2626
ExpressionEvaluatorPtr<Expression> ParseValueExpression(LexScanner& lexer);
2727
ExpressionEvaluatorPtr<Expression> ParseBracedExpressionOrTuple(LexScanner& lexer);
2828
ExpressionEvaluatorPtr<Expression> ParseDictionary(LexScanner& lexer);
29+
ExpressionEvaluatorPtr<Expression> ParseTuple(LexScanner& lexer);
2930
ExpressionEvaluatorPtr<SubscriptExpression> ParseSubsicpt(LexScanner& lexer, const std::vector<std::string>& valueRef);
3031
ExpressionEvaluatorPtr<Expression> ParseCall(LexScanner& lexer, const std::vector<std::string>& valueRef);
31-
std::unordered_map<std::string, ExpressionEvaluatorPtr<>> ParseCallParams(LexScanner& lexer, bool& isValid);
32+
CallParams ParseCallParams(LexScanner& lexer, bool& isValid);
3233
std::vector<std::string> ParseValueRef(LexScanner& lexer);
3334
ExpressionEvaluatorPtr<ExpressionFilter> ParseFilterExpression(LexScanner& lexer);
3435
ExpressionEvaluatorPtr<IfExpression> ParseIfExpression(LexScanner& lexer);

src/filters.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ namespace filters
1010

1111
Join::Join(FilterParams params)
1212
{
13-
if (!helpers::FindParam(params, "param0", "d", m_delimiterEval))
13+
if (!helpers::FindParam(params, 0, "d", m_delimiterEval))
1414
m_delimiterEval = std::make_shared<ConstantExpression>("");
1515

16-
helpers::FindParam(params, "param1", "attribute", m_attribute);
16+
helpers::FindParam(params, 1, "attribute", m_attribute);
1717
}
1818

1919
Value Join::Filter(const Value& baseVal, RenderContext& context)
@@ -40,7 +40,7 @@ Value Join::Filter(const Value& baseVal, RenderContext& context)
4040

4141
Sort::Sort(FilterParams params)
4242
{
43-
helpers::FindParam(params, "", "attribute", m_attrNameEvaluator);
43+
helpers::FindParam(params, 0, "attribute", m_attrNameEvaluator);
4444
}
4545

4646
struct GetAsValuesListVisitor : boost::static_visitor<ValuesList>

src/filters.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
namespace jinja2
1212
{
1313
using FilterPtr = std::shared_ptr<ExpressionFilter::IExpressionFilter>;
14-
using FilterParams = std::unordered_map<std::string, ExpressionEvaluatorPtr<>>;
14+
using FilterParams = CallParams;
1515

1616
template<typename F>
1717
struct FilterFactory

src/testers.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ bool Defined::Test(const Value& baseVal, RenderContext& context)
1313

1414
StartsWith::StartsWith(TesterParams params)
1515
{
16-
helpers::FindParam(params, "param0", "param0", m_stringEval);
16+
helpers::FindParam(params, 0, "", m_stringEval);
1717
}
1818

1919
bool StartsWith::Test(const Value& baseVal, RenderContext& context)

src/testers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
namespace jinja2
1212
{
1313
using TesterPtr = std::shared_ptr<IsExpression::ITester>;
14-
using TesterParams = CallParamsList;
14+
using TesterParams = CallParams;
1515

1616
template<typename F>
1717
struct TesterFactory

test/set_test.cpp

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ paramsVal: 3
3535
EXPECT_EQ(expectedResult, result);
3636
}
3737

38-
TEST(SetTest, TupleAssignmentTest)
38+
TEST(SetTest, Tuple1AssignmentTest)
3939
{
4040
std::string source = R"(
4141
{% set firstName, lastName = emploee %}
@@ -61,3 +61,73 @@ lastName: Dow
6161
)";
6262
EXPECT_EQ(expectedResult, result);
6363
}
64+
65+
TEST(SetTest, Tuple2AssignmentTest)
66+
{
67+
std::string source = R"(
68+
{% set tuple = ("Hello", "World") %}
69+
hello: {{tuple[0]}}
70+
world: {{tuple[1]}}
71+
)";
72+
73+
Template tpl;
74+
ASSERT_TRUE(tpl.Load(source));
75+
76+
ValuesMap params = {
77+
};
78+
79+
std::string result = tpl.RenderAsString(params);
80+
std::cout << result << std::endl;
81+
std::string expectedResult = R"(
82+
hello: Hello
83+
world: World
84+
)";
85+
EXPECT_EQ(expectedResult, result);
86+
}
87+
88+
TEST(SetTest, Tuple3AssignmentTest)
89+
{
90+
std::string source = R"(
91+
{% set tuple = ["Hello", "World"] %}
92+
hello: {{tuple[0]}}
93+
world: {{tuple[1]}}
94+
)";
95+
96+
Template tpl;
97+
ASSERT_TRUE(tpl.Load(source));
98+
99+
ValuesMap params = {
100+
};
101+
102+
std::string result = tpl.RenderAsString(params);
103+
std::cout << result << std::endl;
104+
std::string expectedResult = R"(
105+
hello: Hello
106+
world: World
107+
)";
108+
EXPECT_EQ(expectedResult, result);
109+
}
110+
111+
112+
TEST(SetTest, Tuple4AssignmentTest)
113+
{
114+
std::string source = R"(
115+
{% set dict = {'hello' = "Hello", 'world' = "World"} %}
116+
hello: {{dict.hello}}
117+
world: {{dict.world}}
118+
)";
119+
120+
Template tpl;
121+
ASSERT_TRUE(tpl.Load(source));
122+
123+
ValuesMap params = {
124+
};
125+
126+
std::string result = tpl.RenderAsString(params);
127+
std::cout << result << std::endl;
128+
std::string expectedResult = R"(
129+
hello: Hello
130+
world: World
131+
)";
132+
EXPECT_EQ(expectedResult, result);
133+
}

0 commit comments

Comments
 (0)