#ifndef JINJA2CPP_SRC_EXPRESSION_EVALUATOR_H #define JINJA2CPP_SRC_EXPRESSION_EVALUATOR_H #include "internal_value.h" #include "render_context.h" #include <jinja2cpp/utils/i_comparable.h> #include <memory> #include <limits> namespace jinja2 { enum { InvalidFn = -1, RangeFn = 1, LoopCycleFn = 2 }; class ExpressionEvaluatorBase : public IComparable { public: virtual ~ExpressionEvaluatorBase() {} virtual InternalValue Evaluate(RenderContext& values) = 0; virtual void Render(OutStream& stream, RenderContext& values); }; template<typename T = ExpressionEvaluatorBase> using ExpressionEvaluatorPtr = std::shared_ptr<T>; using Expression = ExpressionEvaluatorBase; inline bool operator==(const ExpressionEvaluatorPtr<>& lhs, const ExpressionEvaluatorPtr<>& rhs) { if (lhs && rhs && !lhs->IsEqual(*rhs)) return false; if ((lhs && !rhs) || (!lhs && rhs)) return false; return true; } inline bool operator!=(const ExpressionEvaluatorPtr<>& lhs, const ExpressionEvaluatorPtr<>& rhs) { return !(lhs == rhs); } struct CallParams { std::unordered_map<std::string, InternalValue> kwParams; std::vector<InternalValue> posParams; }; inline bool operator==(const CallParams& lhs, const CallParams& rhs) { if (lhs.kwParams != rhs.kwParams) return false; if (lhs.posParams != rhs.posParams) return false; return true; } inline bool operator!=(const CallParams& lhs, const CallParams& rhs) { return !(lhs == rhs); } struct CallParamsInfo { std::unordered_map<std::string, ExpressionEvaluatorPtr<>> kwParams; std::vector<ExpressionEvaluatorPtr<>> posParams; }; inline bool operator==(const CallParamsInfo& lhs, const CallParamsInfo& rhs) { if (lhs.kwParams != rhs.kwParams) return false; if (lhs.posParams != rhs.posParams) return false; return true; } inline bool operator!=(const CallParamsInfo& lhs, const CallParamsInfo& rhs) { return !(lhs == rhs); } struct ArgumentInfo { std::string name; bool mandatory = false; InternalValue defaultVal; ArgumentInfo(std::string argName, bool isMandatory = false, InternalValue def = InternalValue()) : name(std::move(argName)) , mandatory(isMandatory) , defaultVal(std::move(def)) { } }; inline bool operator==(const ArgumentInfo& lhs, const ArgumentInfo& rhs) { if (lhs.name != rhs.name) return false; if (lhs.mandatory != rhs.mandatory) return false; if (!(lhs.defaultVal == rhs.defaultVal)) return false; return true; } inline bool operator!=(const ArgumentInfo& lhs, const ArgumentInfo& rhs) { return !(lhs == rhs); } struct ParsedArgumentsInfo { std::unordered_map<std::string, ExpressionEvaluatorPtr<>> args; std::unordered_map<std::string, ExpressionEvaluatorPtr<>> extraKwArgs; std::vector<ExpressionEvaluatorPtr<>> extraPosArgs; ExpressionEvaluatorPtr<> operator[](const std::string& name) const { auto p = args.find(name); if (p == args.end()) return ExpressionEvaluatorPtr<>(); return p->second; } }; inline bool operator==(const ParsedArgumentsInfo& lhs, const ParsedArgumentsInfo& rhs) { if (lhs.args != rhs.args) return false; if (lhs.extraKwArgs != rhs.extraKwArgs) return false; if (lhs.extraPosArgs != rhs.extraPosArgs) return false; return true; } inline bool operator!=(const ParsedArgumentsInfo& lhs, const ParsedArgumentsInfo& rhs) { return !(lhs == rhs); } struct ParsedArguments { std::unordered_map<std::string, InternalValue> args; std::unordered_map<std::string, InternalValue> extraKwArgs; std::vector<InternalValue> extraPosArgs; InternalValue operator[](const std::string& name) const { auto p = args.find(name); if (p == args.end()) return InternalValue(); return p->second; } }; inline bool operator==(const ParsedArguments& lhs, const ParsedArguments& rhs) { if (lhs.args != rhs.args) return false; if (lhs.extraKwArgs != rhs.extraKwArgs) return false; if (lhs.extraPosArgs != rhs.extraPosArgs) return false; return true; } inline bool operator!=(const ParsedArguments& lhs, const ParsedArguments& rhs) { return !(lhs == rhs); } class ExpressionFilter; class IfExpression; class FullExpressionEvaluator : public ExpressionEvaluatorBase { public: void SetExpression(ExpressionEvaluatorPtr<Expression> expr) { m_expression = std::move(expr); } void SetTester(ExpressionEvaluatorPtr<IfExpression> expr) { m_tester = std::move(expr); } InternalValue Evaluate(RenderContext& values) override; void Render(OutStream &stream, RenderContext &values) override; bool IsEqual(const IComparable& other) const override { const auto* eval = dynamic_cast<const FullExpressionEvaluator*>(&other); if (!eval) return false; if (m_expression != eval->m_expression) return false; if (m_tester != eval->m_tester) return false; return true; } private: ExpressionEvaluatorPtr<Expression> m_expression; ExpressionEvaluatorPtr<IfExpression> m_tester; }; class ValueRefExpression : public Expression { public: ValueRefExpression(std::string valueName) : m_valueName(std::move(valueName)) { } InternalValue Evaluate(RenderContext& values) override; bool IsEqual(const IComparable& other) const override { auto* value = dynamic_cast<const ValueRefExpression*>(&other); if (!value) return false; return m_valueName != value->m_valueName; } private: std::string m_valueName; }; class SubscriptExpression : public Expression { public: SubscriptExpression(ExpressionEvaluatorPtr<Expression> value) : m_value(value) { } InternalValue Evaluate(RenderContext& values) override; void AddIndex(ExpressionEvaluatorPtr<Expression> value) { m_subscriptExprs.push_back(value); } bool IsEqual(const IComparable& other) const override { auto* otherPtr = dynamic_cast<const SubscriptExpression*>(&other); if (!otherPtr) return false; if (m_value != otherPtr->m_value) return false; if (m_subscriptExprs != otherPtr->m_subscriptExprs) return false; return true; } private: ExpressionEvaluatorPtr<Expression> m_value; std::vector<ExpressionEvaluatorPtr<Expression>> m_subscriptExprs; }; class FilteredExpression : public Expression { public: explicit FilteredExpression(ExpressionEvaluatorPtr<Expression> expression, ExpressionEvaluatorPtr<ExpressionFilter> filter) : m_expression(std::move(expression)) , m_filter(std::move(filter)) { } InternalValue Evaluate(RenderContext&) override; bool IsEqual(const IComparable& other) const override { auto* otherPtr = dynamic_cast<const FilteredExpression*>(&other); if (!otherPtr) return false; if (m_expression != otherPtr->m_expression) return false; if (m_filter != otherPtr->m_filter) return false; return true; } private: ExpressionEvaluatorPtr<Expression> m_expression; ExpressionEvaluatorPtr<ExpressionFilter> m_filter; }; class ConstantExpression : public Expression { public: ConstantExpression(InternalValue constant) : m_constant(constant) {} InternalValue Evaluate(RenderContext&) override { return m_constant; } bool IsEqual(const IComparable& other) const override { auto* otherVal = dynamic_cast<const ConstantExpression*>(&other); if (!otherVal) return false; return m_constant == otherVal->m_constant; } private: InternalValue m_constant; }; class TupleCreator : public Expression { public: TupleCreator(std::vector<ExpressionEvaluatorPtr<>> exprs) : m_exprs(std::move(exprs)) { } InternalValue Evaluate(RenderContext&) override; bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const TupleCreator*>(&other); if (!val) return false; return m_exprs == val->m_exprs; } private: std::vector<ExpressionEvaluatorPtr<>> m_exprs; }; /* class DictionaryCreator : public Expression { public: DictionaryCreator(std::unordered_map<std::string, ExpressionEvaluatorPtr<>> items) : m_items(std::move(items)) { } InternalValue Evaluate(RenderContext&) override; private: std::unordered_map<std::string, ExpressionEvaluatorPtr<>> m_items; };*/ class DictCreator : public Expression { public: DictCreator(std::unordered_map<std::string, ExpressionEvaluatorPtr<>> exprs) : m_exprs(std::move(exprs)) { } InternalValue Evaluate(RenderContext&) override; bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const DictCreator*>(&other); if (!val) return false; return m_exprs == val->m_exprs; } private: std::unordered_map<std::string, ExpressionEvaluatorPtr<>> m_exprs; }; class UnaryExpression : public Expression { public: enum Operation { LogicalNot, UnaryPlus, UnaryMinus }; UnaryExpression(Operation oper, ExpressionEvaluatorPtr<> expr) : m_oper(oper) , m_expr(expr) {} InternalValue Evaluate(RenderContext&) override; bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const UnaryExpression*>(&other); if (!val) return false; if (m_oper != val->m_oper) return false; if (m_expr != val->m_expr) return false; return true; } private: Operation m_oper; ExpressionEvaluatorPtr<> m_expr; }; class IsExpression : public Expression { public: virtual ~IsExpression() {} struct ITester : IComparable { virtual ~ITester() {} virtual bool Test(const InternalValue& baseVal, RenderContext& context) = 0; }; using TesterPtr = std::shared_ptr<ITester>; using TesterFactoryFn = std::function<TesterPtr(CallParamsInfo params)>; IsExpression(ExpressionEvaluatorPtr<> value, const std::string& tester, CallParamsInfo params); InternalValue Evaluate(RenderContext& context) override; bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const IsExpression*>(&other); if (!val) return false; if (m_value != val->m_value) return false; if (m_tester != val->m_tester) return false; if (m_tester && val->m_tester && !m_tester->IsEqual(*val->m_tester)) return false; return true; } private: ExpressionEvaluatorPtr<> m_value; TesterPtr m_tester; }; class BinaryExpression : public Expression { public: enum Operation { LogicalAnd, LogicalOr, LogicalEq, LogicalNe, LogicalGt, LogicalLt, LogicalGe, LogicalLe, In, Plus, Minus, Mul, Div, DivReminder, DivInteger, Pow, StringConcat }; enum CompareType { Undefined = 0, CaseSensitive = 0, CaseInsensitive = 1 }; BinaryExpression(Operation oper, ExpressionEvaluatorPtr<> leftExpr, ExpressionEvaluatorPtr<> rightExpr); InternalValue Evaluate(RenderContext&) override; bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const BinaryExpression*>(&other); if (!val) return false; if (m_oper != val->m_oper) return false; if (m_leftExpr != val->m_leftExpr) return false; if (m_rightExpr != val->m_rightExpr) return false; if (m_inTester && val->m_inTester && !m_inTester->IsEqual(*val->m_inTester)) return false; if ((!m_inTester && val->m_inTester) || (m_inTester && !val->m_inTester)) return false; return true; } private: Operation m_oper; ExpressionEvaluatorPtr<> m_leftExpr; ExpressionEvaluatorPtr<> m_rightExpr; IsExpression::TesterPtr m_inTester; }; class CallExpression : public Expression { public: virtual ~CallExpression() {} CallExpression(ExpressionEvaluatorPtr<> valueRef, CallParamsInfo params) : m_valueRef(std::move(valueRef)) , m_params(std::move(params)) { } InternalValue Evaluate(RenderContext &values) override; void Render(OutStream &stream, RenderContext &values) override; auto& GetValueRef() const {return m_valueRef;} auto& GetParams() const {return m_params;} bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const CallExpression*>(&other); if (!val) return false; if (m_valueRef != val->m_valueRef) return false; return m_params == val->m_params; } private: InternalValue CallArbitraryFn(RenderContext &values); InternalValue CallGlobalRange(RenderContext &values); InternalValue CallLoopCycle(RenderContext &values); private: ExpressionEvaluatorPtr<> m_valueRef; CallParamsInfo m_params; }; class ExpressionFilter : public IComparable { public: virtual ~ExpressionFilter() {} struct IExpressionFilter : IComparable { virtual ~IExpressionFilter() {} virtual InternalValue Filter(const InternalValue& baseVal, RenderContext& context) = 0; }; using ExpressionFilterPtr = std::shared_ptr<IExpressionFilter>; using FilterFactoryFn = std::function<ExpressionFilterPtr(CallParamsInfo params)>; ExpressionFilter(const std::string& filterName, CallParamsInfo params); InternalValue Evaluate(const InternalValue& baseVal, RenderContext& context); void SetParentFilter(std::shared_ptr<ExpressionFilter> parentFilter) { m_parentFilter = std::move(parentFilter); } bool IsEqual(const IComparable& other) const override { auto* valuePtr = dynamic_cast<const ExpressionFilter*>(&other); if (!valuePtr) return false; if (m_filter && valuePtr->m_filter && !m_filter->IsEqual(*valuePtr->m_filter)) return false; if ((m_filter && !valuePtr->m_filter) || (!m_filter && !valuePtr->m_filter)) return false; if (m_parentFilter != valuePtr->m_parentFilter) return false; return true; } private: ExpressionFilterPtr m_filter; std::shared_ptr<ExpressionFilter> m_parentFilter; }; class IfExpression : public IComparable { public: virtual ~IfExpression() {} IfExpression(ExpressionEvaluatorPtr<> testExpr, ExpressionEvaluatorPtr<> altValue) : m_testExpr(testExpr) , m_altValue(altValue) { } bool Evaluate(RenderContext& context); InternalValue EvaluateAltValue(RenderContext& context); void SetAltValue(ExpressionEvaluatorPtr<> altValue) { m_altValue = std::move(altValue); } bool IsEqual(const IComparable& other) const override { auto* valPtr = dynamic_cast<const IfExpression*>(&other); if (!valPtr) return false; if (m_testExpr != valPtr->m_testExpr) return false; if (m_altValue != valPtr->m_altValue) return false; return true; } private: ExpressionEvaluatorPtr<> m_testExpr; ExpressionEvaluatorPtr<> m_altValue; }; namespace helpers { ParsedArguments ParseCallParams(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParams& params, bool& isSucceeded); ParsedArguments ParseCallParams(const std::vector<ArgumentInfo>& args, const CallParams& params, bool& isSucceeded); ParsedArgumentsInfo ParseCallParamsInfo(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParamsInfo& params, bool& isSucceeded); ParsedArgumentsInfo ParseCallParamsInfo(const std::vector<ArgumentInfo>& args, const CallParamsInfo& params, bool& isSucceeded); CallParams EvaluateCallParams(const CallParamsInfo& info, RenderContext& context); } // namespace helpers } // namespace jinja2 #endif // JINJA2CPP_SRC_EXPRESSION_EVALUATOR_H