Skip to content

Commit c2a0e6f

Browse files
committed
Make evaluation of macro call params at the point of call instead of point of macro definition
1 parent e0a7db0 commit c2a0e6f

15 files changed

+544
-466
lines changed

src/expression_evaluator.cpp

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ BinaryExpression::BinaryExpression(BinaryExpression::Operation oper, ExpressionE
8787
{
8888
if (m_oper == In)
8989
{
90-
CallParams params;
90+
CallParamsInfo params;
9191
params.kwParams["seq"] = rightExpr;
9292
m_inTester = CreateTester("in", params);
9393
}
@@ -185,7 +185,7 @@ InternalValue DictCreator::Evaluate(RenderContext& context)
185185
return CreateMapAdapter(std::move(result));;
186186
}
187187

188-
ExpressionFilter::ExpressionFilter(const std::string& filterName, CallParams params)
188+
ExpressionFilter::ExpressionFilter(const std::string& filterName, CallParamsInfo params)
189189
{
190190
m_filter = CreateFilter(filterName, std::move(params));
191191
if (!m_filter)
@@ -200,7 +200,7 @@ InternalValue ExpressionFilter::Evaluate(const InternalValue& baseVal, RenderCon
200200
return m_filter->Filter(baseVal, context);
201201
}
202202

203-
IsExpression::IsExpression(ExpressionEvaluatorPtr<> value, const std::string& tester, CallParams params)
203+
IsExpression::IsExpression(ExpressionEvaluatorPtr<> value, const std::string& tester, CallParamsInfo params)
204204
: m_value(value)
205205
{
206206
m_tester = CreateTester(tester, std::move(params));
@@ -268,13 +268,15 @@ void CallExpression::Render(OutStream& stream, RenderContext& values)
268268
}
269269
}
270270

271+
auto callParams = helpers::EvaluateCallParams(m_params, values);
272+
271273
if (callable->GetType() == Callable::Type::Expression)
272274
{
273-
stream.WriteValue(callable->GetExpressionCallable()(m_params, values));
275+
stream.WriteValue(callable->GetExpressionCallable()(callParams, values));
274276
}
275277
else
276278
{
277-
callable->GetStatementCallable()(m_params, stream, values);
279+
callable->GetStatementCallable()(callParams, stream, values);
278280
}
279281
}
280282

@@ -294,22 +296,24 @@ InternalValue CallExpression::CallArbitraryFn(RenderContext& values)
294296
if (kind != Callable::GlobalFunc && kind != Callable::UserCallable && kind != Callable::Macro)
295297
return InternalValue();
296298

299+
auto callParams = helpers::EvaluateCallParams(m_params, values);
300+
297301
if (callable->GetType() == Callable::Type::Expression)
298302
{
299-
return callable->GetExpressionCallable()(m_params, values);
303+
return callable->GetExpressionCallable()(callParams, values);
300304
}
301305

302306
TargetString resultStr;
303307
auto stream = values.GetRendererCallback()->GetStreamOnString(resultStr);
304-
callable->GetStatementCallable()(m_params, stream, values);
308+
callable->GetStatementCallable()(callParams, stream, values);
305309
return resultStr;
306310
}
307311

308312
InternalValue CallExpression::CallGlobalRange(RenderContext& values)
309313
{
310314
bool isArgsParsed = true;
311315

312-
auto args = helpers::ParseCallParams({{"start"}, {"stop", true}, {"step"}}, m_params, isArgsParsed);
316+
auto args = helpers::ParseCallParamsInfo({ { "start" }, { "stop", true }, { "step" } }, m_params, isArgsParsed);
313317
if (!isArgsParsed)
314318
return InternalValue();
315319

@@ -385,8 +389,23 @@ enum ParamState
385389
MappedKw,
386390
};
387391

388-
template<typename T>
389-
ParsedArguments ParseCallParamsImpl(const T& args, const CallParams& params, bool& isSucceeded)
392+
template<typename Result>
393+
struct ParsedArgumentDefaultValGetter;
394+
395+
template<>
396+
struct ParsedArgumentDefaultValGetter<ParsedArguments>
397+
{
398+
static auto Get(const InternalValue& val) { return val; }
399+
};
400+
401+
template<>
402+
struct ParsedArgumentDefaultValGetter<ParsedArgumentsInfo>
403+
{
404+
static auto Get(const InternalValue& val) { return std::make_shared<ConstantExpression>(val); }
405+
};
406+
407+
template<typename Result, typename T, typename P>
408+
Result ParseCallParamsImpl(const T& args, const P& params, bool& isSucceeded)
390409
{
391410
struct ArgInfo
392411
{
@@ -401,7 +420,7 @@ ParsedArguments ParseCallParamsImpl(const T& args, const CallParams& params, boo
401420

402421
isSucceeded = true;
403422

404-
ParsedArguments result;
423+
Result result;
405424

406425
int argIdx = 0;
407426
int firstMandatoryIdx = -1;
@@ -465,6 +484,8 @@ ParsedArguments ParseCallParamsImpl(const T& args, const CallParams& params, boo
465484
;
466485

467486
isFirstTime = false;
487+
if (startPosArg == args.size())
488+
break;
468489
continue;
469490
}
470491

@@ -510,7 +531,14 @@ ParsedArguments ParseCallParamsImpl(const T& args, const CallParams& params, boo
510531
case NotFound:
511532
{
512533
if (!IsEmpty(argInfo.info->defaultVal))
513-
result.args[argInfo.info->name] = std::make_shared<ConstantExpression>(argInfo.info->defaultVal);
534+
#if __cplusplus >= 201703L
535+
if constexpr (std::is_same<Result, ParsedArgumentsInfo>::value)
536+
result.args[argInfo.info->name] = std::make_shared<ConstantExpression>(argInfo.info->defaultVal);
537+
else
538+
result.args[argInfo.info->name] = argInfo.info->defaultVal;
539+
#else
540+
result.args[argInfo.info->name] = ParsedArgumentDefaultValGetter<Result>::Get(argInfo.info->defaultVal);
541+
#endif
514542
break;
515543
}
516544
case NotFoundMandatory:
@@ -537,12 +565,35 @@ ParsedArguments ParseCallParamsImpl(const T& args, const CallParams& params, boo
537565

538566
ParsedArguments ParseCallParams(const std::initializer_list<ArgumentInfo>& args, const CallParams& params, bool& isSucceeded)
539567
{
540-
return ParseCallParamsImpl(args, params, isSucceeded);
568+
return ParseCallParamsImpl<ParsedArguments>(args, params, isSucceeded);
541569
}
542570

543571
ParsedArguments ParseCallParams(const std::vector<ArgumentInfo>& args, const CallParams& params, bool& isSucceeded)
544572
{
545-
return ParseCallParamsImpl(args, params, isSucceeded);
573+
return ParseCallParamsImpl<ParsedArguments>(args, params, isSucceeded);
574+
}
575+
576+
ParsedArgumentsInfo ParseCallParamsInfo(const std::initializer_list<ArgumentInfo>& args, const CallParamsInfo& params, bool& isSucceeded)
577+
{
578+
return ParseCallParamsImpl<ParsedArgumentsInfo>(args, params, isSucceeded);
579+
}
580+
581+
ParsedArgumentsInfo ParseCallParamsInfo(const std::vector<ArgumentInfo>& args, const CallParamsInfo& params, bool& isSucceeded)
582+
{
583+
return ParseCallParamsImpl<ParsedArgumentsInfo>(args, params, isSucceeded);
584+
}
585+
586+
CallParams EvaluateCallParams(const CallParamsInfo& info, RenderContext& context)
587+
{
588+
CallParams result;
589+
590+
for (auto& p : info.posParams)
591+
result.posParams.push_back(p->Evaluate(context));
592+
593+
for (auto& kw : info.kwParams)
594+
result.kwParams[kw.first] = kw.second->Evaluate(context);
595+
596+
return result;
546597
}
547598

548599
}

src/expression_evaluator.h

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ using ExpressionEvaluatorPtr = std::shared_ptr<T>;
3131
using Expression = ExpressionEvaluatorBase;
3232

3333
struct CallParams
34+
{
35+
std::unordered_map<std::string, InternalValue> kwParams;
36+
std::vector<InternalValue> posParams;
37+
};
38+
39+
struct CallParamsInfo
3440
{
3541
std::unordered_map<std::string, ExpressionEvaluatorPtr<>> kwParams;
3642
std::vector<ExpressionEvaluatorPtr<>> posParams;
@@ -50,7 +56,7 @@ struct ArgumentInfo
5056
}
5157
};
5258

53-
struct ParsedArguments
59+
struct ParsedArgumentsInfo
5460
{
5561
std::unordered_map<std::string, ExpressionEvaluatorPtr<>> args;
5662
std::unordered_map<std::string, ExpressionEvaluatorPtr<>> extraKwArgs;
@@ -66,6 +72,22 @@ struct ParsedArguments
6672
}
6773
};
6874

75+
struct ParsedArguments
76+
{
77+
std::unordered_map<std::string, InternalValue> args;
78+
std::unordered_map<std::string, InternalValue> extraKwArgs;
79+
std::vector<InternalValue> extraPosArgs;
80+
81+
InternalValue operator[](const std::string& name) const
82+
{
83+
auto p = args.find(name);
84+
if (p == args.end())
85+
return InternalValue();
86+
87+
return p->second;
88+
}
89+
};
90+
6991
class ExpressionFilter;
7092
class IfExpression;
7193

@@ -219,9 +241,9 @@ class IsExpression : public Expression
219241
virtual bool Test(const InternalValue& baseVal, RenderContext& context) = 0;
220242
};
221243

222-
using TesterFactoryFn = std::function<std::shared_ptr<ITester> (CallParams params)>;
244+
using TesterFactoryFn = std::function<std::shared_ptr<ITester>(CallParamsInfo params)>;
223245

224-
IsExpression(ExpressionEvaluatorPtr<> value, const std::string& tester, CallParams params);
246+
IsExpression(ExpressionEvaluatorPtr<> value, const std::string& tester, CallParamsInfo params);
225247
InternalValue Evaluate(RenderContext& context) override;
226248

227249
private:
@@ -275,7 +297,7 @@ class CallExpression : public Expression
275297
public:
276298
virtual ~CallExpression() {}
277299

278-
CallExpression(ExpressionEvaluatorPtr<> valueRef, CallParams params)
300+
CallExpression(ExpressionEvaluatorPtr<> valueRef, CallParamsInfo params)
279301
: m_valueRef(std::move(valueRef))
280302
, m_params(std::move(params))
281303
{
@@ -294,7 +316,7 @@ class CallExpression : public Expression
294316

295317
private:
296318
ExpressionEvaluatorPtr<> m_valueRef;
297-
CallParams m_params;
319+
CallParamsInfo m_params;
298320
};
299321

300322
class ExpressionFilter
@@ -308,9 +330,9 @@ class ExpressionFilter
308330
virtual InternalValue Filter(const InternalValue& baseVal, RenderContext& context) = 0;
309331
};
310332

311-
using FilterFactoryFn = std::function<std::shared_ptr<IExpressionFilter> (CallParams params)>;
333+
using FilterFactoryFn = std::function<std::shared_ptr<IExpressionFilter>(CallParamsInfo params)>;
312334

313-
ExpressionFilter(const std::string& filterName, CallParams params);
335+
ExpressionFilter(const std::string& filterName, CallParamsInfo params);
314336

315337
InternalValue Evaluate(const InternalValue& baseVal, RenderContext& context);
316338
void SetParentFilter(std::shared_ptr<ExpressionFilter> parentFilter)
@@ -351,6 +373,9 @@ namespace helpers
351373
{
352374
ParsedArguments ParseCallParams(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParams& params, bool& isSucceeded);
353375
ParsedArguments ParseCallParams(const std::vector<ArgumentInfo>& args, const CallParams& params, bool& isSucceeded);
376+
ParsedArgumentsInfo ParseCallParamsInfo(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParamsInfo& params, bool& isSucceeded);
377+
ParsedArgumentsInfo ParseCallParamsInfo(const std::vector<ArgumentInfo>& args, const CallParamsInfo& params, bool& isSucceeded);
378+
CallParams EvaluateCallParams(const CallParamsInfo& info, RenderContext& context);
354379
}
355380
} // jinja2
356381

src/expression_parser.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionPars
140140
return MakeParseError(ErrorCode::ExpectedIdentifier, nextTok);
141141

142142
std::string name = AsString(nextTok.value);
143-
ParseResult<CallParams> params;
144-
143+
ParseResult<CallParamsInfo> params;
144+
145145
if (lexer.EatIfEqual('('))
146146
params = ParseCallParams(lexer);
147147

@@ -435,7 +435,7 @@ ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionPars
435435
{
436436
ExpressionEvaluatorPtr<Expression> result;
437437

438-
ParseResult<CallParams> params = ParseCallParams(lexer);
438+
ParseResult<CallParamsInfo> params = ParseCallParams(lexer);
439439
if (!params)
440440
return params.get_unexpected();
441441

@@ -444,9 +444,9 @@ ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionPars
444444
return result;
445445
}
446446

447-
ExpressionParser::ParseResult<CallParams> ExpressionParser::ParseCallParams(LexScanner& lexer)
447+
ExpressionParser::ParseResult<CallParamsInfo> ExpressionParser::ParseCallParams(LexScanner& lexer)
448448
{
449-
CallParams result;
449+
CallParamsInfo result;
450450

451451
if (lexer.EatIfEqual(')'))
452452
return result;
@@ -534,7 +534,7 @@ ExpressionParser::ParseResult<ExpressionEvaluatorPtr<ExpressionFilter>> Expressi
534534
return MakeParseError(ErrorCode::ExpectedIdentifier, tok);
535535

536536
std::string name = AsString(tok.value);
537-
ParseResult<CallParams> params;
537+
ParseResult<CallParamsInfo> params;
538538

539539
if (lexer.NextToken() == '(')
540540
params = ParseCallParams(lexer);

src/expression_parser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ExpressionParser
2020
explicit ExpressionParser(const Settings& settings, TemplateEnv* env = nullptr);
2121
ParseResult<RendererPtr> Parse(LexScanner& lexer);
2222
ParseResult<ExpressionEvaluatorPtr<FullExpressionEvaluator>> ParseFullExpression(LexScanner& lexer, bool includeIfPart = true);
23-
ParseResult<CallParams> ParseCallParams(LexScanner& lexer);
23+
ParseResult<CallParamsInfo> ParseCallParams(LexScanner& lexer);
2424
ParseResult<ExpressionEvaluatorPtr<ExpressionFilter>> ParseFilterExpression(LexScanner& lexer);
2525
private:
2626
ParseResult<ExpressionEvaluatorPtr<Expression>> ParseLogicalNot(LexScanner& lexer);

0 commit comments

Comments
 (0)