#include "internal_value.h" #include "expression_evaluator.h" #include "generic_adapters.h" #include "helpers.h" #include "value_visitors.h" namespace jinja2 { void InternalValue::SetParentData(const InternalValue& val) { m_parentData = val.GetData(); } void InternalValue::SetParentData(InternalValue&& val) { m_parentData = std::move(val.GetData()); } void ListAdapter::Iterator::increment() { m_isFinished = !m_iterator->MoveNext(); ++ m_currentIndex; m_currentVal = m_isFinished ? InternalValue() : m_iterator->GetCurrent(); } std::atomic_uint64_t UserCallable::m_gen{}; bool Value::IsEqual(const Value& rhs) const { return this->m_data == rhs.m_data; } bool operator==(const Value& lhs, const Value& rhs) { return lhs.IsEqual(rhs); } bool operator!=(const Value& lhs, const Value& rhs) { return !(lhs == rhs); } bool operator==(const GenericMap& lhs, const GenericMap& rhs) { auto* lhsAccessor = lhs.GetAccessor(); auto* rhsAccessor = rhs.GetAccessor(); return lhsAccessor && rhsAccessor && lhsAccessor->IsEqual(*rhsAccessor); } bool operator!=(const GenericMap& lhs, const GenericMap& rhs) { return !(lhs == rhs); } bool operator==(const UserCallable& lhs, const UserCallable& rhs) { // TODO: rework return lhs.IsEqual(rhs); } bool operator!=(const UserCallable& lhs, const UserCallable& rhs) { return !(lhs == rhs); } bool operator==(const types::ValuePtr<UserCallable>& lhs, const types::ValuePtr<UserCallable>& rhs) { if (lhs && rhs) return *lhs == *rhs; if ((lhs && !rhs) || (!lhs && rhs)) return false; return true; } bool operator!=(const types::ValuePtr<UserCallable>& lhs, const types::ValuePtr<UserCallable>& rhs) { return !(lhs == rhs); } bool operator==(const types::ValuePtr<ValuesMap>& lhs, const types::ValuePtr<ValuesMap>& rhs) { if (lhs && rhs) return *lhs == *rhs; if ((lhs && !rhs) || (!lhs && rhs)) return false; return true; } bool operator!=(const types::ValuePtr<ValuesMap>& lhs, const types::ValuePtr<ValuesMap>& rhs) { return !(lhs == rhs); } bool operator==(const types::ValuePtr<Value>& lhs, const types::ValuePtr<Value>& rhs) { if (lhs && rhs) return *lhs == *rhs; if ((lhs && !rhs) || (!lhs && rhs)) return false; return true; } bool operator!=(const types::ValuePtr<Value>& lhs, const types::ValuePtr<Value>& rhs) { return !(lhs == rhs); } bool operator==(const types::ValuePtr<std::vector<Value>>& lhs, const types::ValuePtr<std::vector<Value>>& rhs) { if (lhs && rhs) return *lhs == *rhs; if ((lhs && !rhs) || (!lhs && rhs)) return false; return true; } bool operator!=(const types::ValuePtr<std::vector<Value>>& lhs, const types::ValuePtr<std::vector<Value>>& rhs) { return !(lhs == rhs); } bool InternalValue::IsEqual(const InternalValue &other) const { if (m_data != other.m_data) return false; return m_parentData == other.m_parentData; } InternalValue Value2IntValue(const Value& val); InternalValue Value2IntValue(Value&& val); struct SubscriptionVisitor : public visitors::BaseVisitor<> { using BaseVisitor<>::operator(); template<typename CharT> InternalValue operator()(const MapAdapter& values, const std::basic_string<CharT>& fieldName) const { auto field = ConvertString<std::string>(fieldName); if (!values.HasValue(field)) return InternalValue(); return values.GetValueByName(field); } template<typename CharT> InternalValue operator()(const MapAdapter& values, const std::basic_string_view<CharT>& fieldName) const { auto field = ConvertString<std::string>(fieldName); if (!values.HasValue(field)) return InternalValue(); return values.GetValueByName(field); } template<typename CharT> InternalValue operator()(std::basic_string<CharT> value, const std::basic_string<CharT>& /*fieldName*/) const { return TargetString(std::move(value)); } InternalValue operator()(const ListAdapter& values, int64_t index) const { if (index < 0 || static_cast<size_t>(index) >= values.GetSize()) return InternalValue(); return values.GetValueByIndex(index); } InternalValue operator()(const MapAdapter& /*values*/, int64_t /*index*/) const { return InternalValue(); } template<typename CharT> InternalValue operator()(const std::basic_string<CharT>& str, int64_t index) const { if (index < 0 || static_cast<size_t>(index) >= str.size()) return InternalValue(); std::basic_string<CharT> resultStr(1, str[static_cast<size_t>(index)]); return TargetString(std::move(resultStr)); } template<typename CharT> InternalValue operator()(const std::basic_string_view<CharT>& str, int64_t index) const { // std::cout << "operator() (const std::basic_string<CharT>& str, int64_t index)" << ": index = " << index << std::endl; if (index < 0 || static_cast<size_t>(index) >= str.size()) return InternalValue(); std::basic_string<CharT> result(1, str[static_cast<size_t>(index)]); return TargetString(std::move(result)); } template<typename CharT> InternalValue operator()(const KeyValuePair& values, const std::basic_string<CharT>& fieldName) const { return SubscriptKvPair(values, ConvertString<std::string>(fieldName)); } template<typename CharT> InternalValue operator()(const KeyValuePair& values, const std::basic_string_view<CharT>& fieldName) const { return SubscriptKvPair(values, ConvertString<std::string>(fieldName)); } InternalValue SubscriptKvPair(const KeyValuePair& values, const std::string& field) const { // std::cout << "operator() (const KeyValuePair& values, const std::string& field)" << ": field = " << field << std::endl; if (field == "key") return InternalValue(values.key); else if (field == "value") return values.value; return InternalValue(); } }; InternalValue Subscript(const InternalValue& val, const InternalValue& subscript, RenderContext* values) { static const std::string callOperName = "value()"; auto result = Apply2<SubscriptionVisitor>(val, subscript); if (!values) return result; auto map = GetIf<MapAdapter>(&result); if (!map || !map->HasValue(callOperName)) return result; auto callableVal = map->GetValueByName(callOperName); auto callable = GetIf<Callable>(&callableVal); if (!callable || callable->GetKind() == Callable::Macro || callable->GetType() == Callable::Type::Statement) return result; CallParams callParams; return callable->GetExpressionCallable()(callParams, *values); } InternalValue Subscript(const InternalValue& val, const std::string& subscript, RenderContext* values) { return Subscript(val, InternalValue(subscript), values); } struct StringGetter : public visitors::BaseVisitor<std::string> { using BaseVisitor::operator(); std::string operator()(const std::string& str) const { return str; } std::string operator()(const std::string_view& str) const { return std::string(str.begin(), str.end()); } std::string operator()(const std::wstring& str) const { return ConvertString<std::string>(str); } std::string operator()(const std::wstring_view& str) const { return ConvertString<std::string>(str); } }; std::string AsString(const InternalValue& val) { return Apply<StringGetter>(val); } struct ListConverter : public visitors::BaseVisitor<boost::optional<ListAdapter>> { using BaseVisitor::operator(); using result_t = boost::optional<ListAdapter>; bool strictConvertion; ListConverter(bool strict) : strictConvertion(strict) { } result_t operator()(const ListAdapter& list) const { return list; } result_t operator()(const MapAdapter& map) const { if (strictConvertion) return result_t(); InternalValueList list; for (auto& k : map.GetKeys()) list.push_back(TargetString(k)); return ListAdapter::CreateAdapter(std::move(list)); } template<typename CharT> result_t operator() (const std::basic_string<CharT>& str) const { return strictConvertion ? result_t() : result_t(ListAdapter::CreateAdapter(str.size(), [str](size_t idx) { return TargetString(str.substr(idx, 1));})); } template<typename CharT> result_t operator()(const std::basic_string_view<CharT>& str) const { return strictConvertion ? result_t() : result_t(ListAdapter::CreateAdapter(str.size(), [str](size_t idx) { return TargetString(std::basic_string<CharT>(str[idx], 1)); })); } }; ListAdapter ConvertToList(const InternalValue& val, bool& isConverted, bool strictConversion) { auto result = Apply<ListConverter>(val, strictConversion); if (!result) { isConverted = false; return ListAdapter(); } isConverted = true; return result.get(); } ListAdapter ConvertToList(const InternalValue& val, InternalValue subscipt, bool& isConverted, bool strictConversion) { auto result = Apply<ListConverter>(val, strictConversion); if (!result) { isConverted = false; return ListAdapter(); } isConverted = true; if (IsEmpty(subscipt)) return std::move(result.get()); return result.get().ToSubscriptedList(subscipt, false); } template<typename T> class ByRef { public: explicit ByRef(const T& val) : m_val(&val) { } const T& Get() const { return *m_val; } T& Get() { return *const_cast<T*>(m_val); } bool ShouldExtendLifetime() const { return false; } bool operator==(const ByRef<T>& other) const { if (m_val && other.m_val && m_val != other.m_val) return false; if ((m_val && !other.m_val) || (!m_val && other.m_val)) return false; return true; } bool operator!=(const ByRef<T>& other) const { return !(*this == other); } private: const T* m_val{}; }; template<typename T> class ByVal { public: explicit ByVal(T&& val) : m_val(std::move(val)) { } ~ByVal() = default; const T& Get() const { return m_val; } T& Get() { return m_val; } bool ShouldExtendLifetime() const { return false; } bool operator==(const ByVal<T>& other) const { return m_val == other.m_val; } bool operator!=(const ByVal<T>& other) const { return !(*this == other); } private: T m_val; }; template<typename T> class BySharedVal { public: explicit BySharedVal(T&& val) : m_val(std::make_shared<T>(std::move(val))) { } ~BySharedVal() = default; const T& Get() const { return *m_val; } T& Get() { return *m_val; } bool ShouldExtendLifetime() const { return true; } bool operator==(const BySharedVal<T>& other) const { return m_val == other.m_val; } bool operator!=(const BySharedVal<T>& other) const { return !(*this == other); } private: std::shared_ptr<T> m_val; }; template<template<typename> class Holder> class GenericListAdapter : public IListAccessor { public: struct Enumerator : public IListAccessorEnumerator { ListEnumeratorPtr m_enum; explicit Enumerator(ListEnumeratorPtr e) : m_enum(std::move(e)) { } // Inherited via IListAccessorEnumerator void Reset() override { if (m_enum) m_enum->Reset(); } bool MoveNext() override { return !m_enum ? false : m_enum->MoveNext(); } InternalValue GetCurrent() const override { return !m_enum ? InternalValue() : Value2IntValue(m_enum->GetCurrent()); } IListAccessorEnumerator* Clone() const override { return !m_enum ? new Enumerator(MakeEmptyListEnumeratorPtr()) : new Enumerator(m_enum->Clone()); } IListAccessorEnumerator* Transfer() override { return new Enumerator(std::move(m_enum)); } bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const Enumerator*>(&other); if (!val) return false; if (m_enum && val->m_enum && !m_enum->IsEqual(*val->m_enum)) return false; if ((m_enum && !val->m_enum) || (!m_enum && val->m_enum)) return false; return true; } }; template<typename U> GenericListAdapter(U&& values) : m_values(std::forward<U>(values)) { } std::optional<size_t> GetSize() const override { return m_values.Get().GetSize(); } std::optional<InternalValue> GetItem(int64_t idx) const override { const IListItemAccessor* accessor = m_values.Get().GetAccessor(); auto indexer = accessor->GetIndexer(); if (!indexer) return std::optional<InternalValue>(); auto val = indexer->GetItemByIndex(idx); return visit(visitors::InputValueConvertor(true, false), std::move(val.data())).get(); } bool ShouldExtendLifetime() const override { return m_values.ShouldExtendLifetime(); } ListAccessorEnumeratorPtr CreateListAccessorEnumerator() const override { const IListItemAccessor* accessor = m_values.Get().GetAccessor(); if (!accessor) return ListAccessorEnumeratorPtr(new Enumerator(MakeEmptyListEnumeratorPtr())); return ListAccessorEnumeratorPtr(new Enumerator(m_values.Get().GetAccessor()->CreateEnumerator())); } GenericList CreateGenericList() const override { // return m_values.Get(); return GenericList([list = m_values]() -> const IListItemAccessor* { return list.Get().GetAccessor(); }); } private: Holder<GenericList> m_values; }; template<template<typename> class Holder> class ValuesListAdapter : public IndexedListAccessorImpl<ValuesListAdapter<Holder>> { public: template<typename U> ValuesListAdapter(U&& values) : m_values(std::forward<U>(values)) { } size_t GetItemsCountImpl() const { return m_values.Get().size(); } std::optional<InternalValue> GetItem(int64_t idx) const override { const auto& val = m_values.Get()[static_cast<size_t>(idx)]; return visit(visitors::InputValueConvertor(false, true), val.data()).get(); } bool ShouldExtendLifetime() const override { return m_values.ShouldExtendLifetime(); } GenericList CreateGenericList() const override { // return m_values.Get(); return GenericList([list = *this]() -> const IListItemAccessor* { return &list; }); } private: Holder<ValuesList> m_values; }; ListAdapter ListAdapter::CreateAdapter(InternalValueList&& values) { class Adapter : public IndexedListAccessorImpl<Adapter> { public: explicit Adapter(InternalValueList&& values) : m_values(std::move(values)) { } size_t GetItemsCountImpl() const { return m_values.size(); } std::optional<InternalValue> GetItem(int64_t idx) const override { return m_values[static_cast<size_t>(idx)]; } bool ShouldExtendLifetime() const override { return false; } GenericList CreateGenericList() const override { return GenericList([adapter = *this]() -> const IListItemAccessor* { return &adapter; }); } private: InternalValueList m_values; }; return ListAdapter([accessor = Adapter(std::move(values))]() { return &accessor; }); } ListAdapter ListAdapter::CreateAdapter(const GenericList& values) { return ListAdapter([accessor = GenericListAdapter<ByRef>(values)]() { return &accessor; }); } ListAdapter ListAdapter::CreateAdapter(const ValuesList& values) { return ListAdapter([accessor = ValuesListAdapter<ByRef>(values)]() { return &accessor; }); } ListAdapter ListAdapter::CreateAdapter(GenericList&& values) { return ListAdapter([accessor = GenericListAdapter<BySharedVal>(std::move(values))]() { return &accessor; }); } ListAdapter ListAdapter::CreateAdapter(ValuesList&& values) { return ListAdapter([accessor = ValuesListAdapter<BySharedVal>(std::move(values))]() { return &accessor; }); } ListAdapter ListAdapter::CreateAdapter(std::function<std::optional<InternalValue>()> fn) { using GenFn = std::function<std::optional<InternalValue>()>; class Adapter : public IListAccessor { public: class Enumerator : public IListAccessorEnumerator { public: explicit Enumerator(const GenFn* fn) : m_fn(fn) { if (!fn) throw std::runtime_error("List enumerator couldn't be created without element accessor function!"); } void Reset() override {} bool MoveNext() override { if (m_isFinished) return false; auto res = (*m_fn)(); if (!res) return false; m_current = *res; return true; } InternalValue GetCurrent() const override { return m_current; } IListAccessorEnumerator* Clone() const override { auto result = new Enumerator(*this); return result; } IListAccessorEnumerator* Transfer() override { auto result = new Enumerator(std::move(*this)); return result; } bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const Enumerator*>(&other); if (!val) return false; if (m_isFinished != val->m_isFinished) return false; if (m_current != val->m_current) return false; // TODO: compare fn? if (m_fn != val->m_fn) return false; return true; } protected: const GenFn* m_fn{}; InternalValue m_current; bool m_isFinished = false; }; explicit Adapter(std::function<std::optional<InternalValue>()>&& fn) : m_fn(std::move(fn)) { } std::optional<size_t> GetSize() const override { return std::optional<size_t>(); } std::optional<InternalValue> GetItem(int64_t /*idx*/) const override { return std::optional<InternalValue>(); } bool ShouldExtendLifetime() const override { return false; } ListAccessorEnumeratorPtr CreateListAccessorEnumerator() const override { return ListAccessorEnumeratorPtr(new Enumerator(&m_fn)); } GenericList CreateGenericList() const override { return GenericList(); // return GenericList([adapter = *this]() -> const ListItemAccessor* {return &adapter; }); } private: std::function<std::optional<InternalValue>()> m_fn; }; return ListAdapter([accessor = Adapter(std::move(fn))]() { return &accessor; }); } ListAdapter ListAdapter::CreateAdapter(size_t listSize, std::function<InternalValue(size_t idx)> fn) { using GenFn = std::function<InternalValue(size_t idx)>; class Adapter : public IndexedListAccessorImpl<Adapter> { public: explicit Adapter(size_t listSize, GenFn&& fn) : m_listSize(listSize) , m_fn(std::move(fn)) { } size_t GetItemsCountImpl() const { return m_listSize; } std::optional<InternalValue> GetItem(int64_t idx) const override { return m_fn(static_cast<size_t>(idx)); } bool ShouldExtendLifetime() const override { return false; } GenericList CreateGenericList() const override { return GenericList([adapter = *this]() -> const IListItemAccessor* { return &adapter; }); } private: size_t m_listSize; GenFn m_fn; }; return ListAdapter([accessor = Adapter(listSize, std::move(fn))]() { return &accessor; }); } template<typename Holder> auto CreateIndexedSubscribedList(Holder&& holder, const InternalValue& subscript, size_t size) { return ListAdapter::CreateAdapter( size, [h = std::forward<Holder>(holder), subscript](size_t idx) -> InternalValue { return Subscript(h.Get().GetValueByIndex(idx), subscript, nullptr); }); } template<typename Holder> auto CreateGenericSubscribedList(Holder&& holder, const InternalValue& subscript) { return ListAdapter::CreateAdapter([h = std::forward<Holder>(holder), e = ListAccessorEnumeratorPtr(), isFirst = true, isLast = false, subscript]() mutable { using ResultType = std::optional<InternalValue>; if (isFirst) { e = h.Get().GetEnumerator(); isLast = !e->MoveNext(); isFirst = false; } if (isLast) return ResultType(); return ResultType(Subscript(e->GetCurrent(), subscript, nullptr)); }); } ListAdapter ListAdapter::ToSubscriptedList(const InternalValue& subscript, bool asRef) const { auto listSize = GetSize(); if (asRef) { ByRef<ListAdapter> holder(*this); return listSize ? CreateIndexedSubscribedList(holder, subscript, *listSize) : CreateGenericSubscribedList(holder, subscript); } else { ListAdapter tmp(*this); BySharedVal<ListAdapter> holder(std::move(tmp)); return listSize ? CreateIndexedSubscribedList(std::move(holder), subscript, *listSize) : CreateGenericSubscribedList(std::move(holder), subscript); } } InternalValueList ListAdapter::ToValueList() const { InternalValueList result; std::copy(begin(), end(), std::back_inserter(result)); return result; } template<template<typename> class Holder, bool CanModify> class InternalValueMapAdapter : public MapAccessorImpl<InternalValueMapAdapter<Holder, CanModify>> { public: template<typename U> InternalValueMapAdapter(U&& values) : m_values(std::forward<U>(values)) { } size_t GetSize() const override { return m_values.Get().size(); } bool HasValue(const std::string& name) const override { return m_values.Get().count(name) != 0; } InternalValue GetItem(const std::string& name) const override { auto& vals = m_values.Get(); auto p = vals.find(name); if (p == vals.end()) return InternalValue(); return p->second; } std::vector<std::string> GetKeys() const override { std::vector<std::string> result; for (auto& i : m_values.Get()) result.push_back(i.first); return result; } bool SetValue(std::string name, const InternalValue& val) override { if (CanModify) { m_values.Get()[name] = val; return true; } return false; } bool ShouldExtendLifetime() const override { return m_values.ShouldExtendLifetime(); } GenericMap CreateGenericMap() const override { return GenericMap([accessor = *this]() -> const IMapItemAccessor* { return &accessor; }); } bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const InternalValueMapAdapter*>(&other); if (!val) return false; return m_values == val->m_values; } private: Holder<InternalValueMap> m_values; }; InternalValue Value2IntValue(const Value& val) { auto result = std::visit(visitors::InputValueConvertor(false, true), val.data()); if (result) return result.get(); return InternalValue(ValueRef(val)); } InternalValue Value2IntValue(Value&& val) { auto result = std::visit(visitors::InputValueConvertor(true, false), val.data()); if (result) return result.get(); return InternalValue(ValueRef(val)); } template<template<typename> class Holder> class GenericMapAdapter : public MapAccessorImpl<GenericMapAdapter<Holder>> { public: template<typename U> GenericMapAdapter(U&& values) : m_values(std::forward<U>(values)) { } size_t GetSize() const override { return m_values.Get().GetSize(); } bool HasValue(const std::string& name) const override { return m_values.Get().HasValue(name); } InternalValue GetItem(const std::string& name) const override { auto val = m_values.Get().GetValueByName(name); if (val.isEmpty()) return InternalValue(); return Value2IntValue(std::move(val)); } std::vector<std::string> GetKeys() const override { return m_values.Get().GetKeys(); } bool ShouldExtendLifetime() const override { return m_values.ShouldExtendLifetime(); } GenericMap CreateGenericMap() const override { return GenericMap([accessor = *this]() -> const IMapItemAccessor* { return accessor.m_values.Get().GetAccessor(); }); } bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const GenericMapAdapter*>(&other); if (!val) return false; return m_values == val->m_values; } private: Holder<GenericMap> m_values; }; template<template<typename> class Holder> class ValuesMapAdapter : public MapAccessorImpl<ValuesMapAdapter<Holder>> { public: template<typename U> ValuesMapAdapter(U&& values) : m_values(std::forward<U>(values)) { } size_t GetSize() const override { return m_values.Get().size(); } bool HasValue(const std::string& name) const override { return m_values.Get().count(name) != 0; } InternalValue GetItem(const std::string& name) const override { auto& vals = m_values.Get(); auto p = vals.find(name); if (p == vals.end()) return InternalValue(); return Value2IntValue(p->second); } std::vector<std::string> GetKeys() const override { std::vector<std::string> result; for (auto& i : m_values.Get()) result.push_back(i.first); return result; } bool ShouldExtendLifetime() const override { return m_values.ShouldExtendLifetime(); } GenericMap CreateGenericMap() const override { return GenericMap([accessor = *this]() -> const IMapItemAccessor* { return &accessor; }); } bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const ValuesMapAdapter*>(&other); if (!val) return false; return m_values == val->m_values; } private: Holder<ValuesMap> m_values; }; MapAdapter CreateMapAdapter(InternalValueMap&& values) { return MapAdapter([accessor = InternalValueMapAdapter<ByVal, true>(std::move(values))]() mutable { return &accessor; }); } MapAdapter CreateMapAdapter(const InternalValueMap* values) { return MapAdapter([accessor = InternalValueMapAdapter<ByRef, false>(*values)]() mutable { return &accessor; }); } MapAdapter CreateMapAdapter(const GenericMap& values) { return MapAdapter([accessor = GenericMapAdapter<ByRef>(values)]() mutable { return &accessor; }); } MapAdapter CreateMapAdapter(GenericMap&& values) { return MapAdapter([accessor = GenericMapAdapter<BySharedVal>(std::move(values))]() mutable { return &accessor; }); } MapAdapter CreateMapAdapter(const ValuesMap& values) { return MapAdapter([accessor = ValuesMapAdapter<ByRef>(values)]() mutable { return &accessor; }); } MapAdapter CreateMapAdapter(ValuesMap&& values) { return MapAdapter([accessor = ValuesMapAdapter<BySharedVal>(std::move(values))]() mutable { return &accessor; }); } struct OutputValueConvertor { using result_t = Value; result_t operator()(const EmptyValue&) const { return result_t(); } result_t operator()(const MapAdapter& adapter) const { return result_t(adapter.CreateGenericMap()); } result_t operator()(const ListAdapter& adapter) const { return result_t(adapter.CreateGenericList()); } result_t operator()(const ValueRef& ref) const { return ref.get(); } result_t operator()(const TargetString& str) const { switch (str.index()) { case 0: return std::get<std::string>(str); default: return std::get<std::wstring>(str); } } result_t operator()(const TargetStringView& str) const { switch (str.index()) { case 0: return std::get<std::string_view>(str); default: return std::get<std::wstring_view>(str); } } result_t operator()(const KeyValuePair& pair) const { return ValuesMap{ { "key", Value(pair.key) }, { "value", IntValue2Value(pair.value) } }; } result_t operator()(const Callable&) const { return result_t(); } result_t operator()(const UserCallable&) const { return result_t(); } result_t operator()(const std::shared_ptr<IRendererBase>&) const { return result_t(); } template<typename T> result_t operator()(const RecWrapper<T>& val) const { return this->operator()(const_cast<const T&>(*val)); } template<typename T> result_t operator()(RecWrapper<T>& val) const { return this->operator()(*val); } template<typename T> result_t operator()(T&& val) const { return result_t(std::forward<T>(val)); } bool m_byValue; }; Value OptIntValue2Value(std::optional<InternalValue> val) { if (val) return Apply<OutputValueConvertor>(val.value()); return Value(); } Value IntValue2Value(const InternalValue& val) { return Apply<OutputValueConvertor>(val); } class ContextMapper : public IMapItemAccessor { public: explicit ContextMapper(RenderContext* context) : m_context(context) { } size_t GetSize() const override { return std::numeric_limits<size_t>::max(); } bool HasValue(const std::string& name) const override { bool found = false; m_context->FindValue(name, found); return found; } Value GetValueByName(const std::string& name) const override { bool found = false; auto p = m_context->FindValue(name, found); return found ? IntValue2Value(p->second) : Value(); } std::vector<std::string> GetKeys() const override { return std::vector<std::string>(); } bool IsEqual(const IComparable& other) const override { auto* val = dynamic_cast<const ContextMapper*>(&other); if (!val) return false; if (m_context && val->m_context && !m_context->IsEqual(*val->m_context)) { return false; } if ((m_context && !val->m_context) || (!m_context && val->m_context)) return false; return true; } private: RenderContext* m_context; }; UserCallableParams PrepareUserCallableParams(const CallParams& params, RenderContext& context, const std::vector<ArgumentInfo>& argsInfo) { UserCallableParams result; ParsedArguments args = helpers::ParseCallParams(argsInfo, params, result.paramsParsed); if (!result.paramsParsed) return result; for (auto& argInfo : argsInfo) { if (argInfo.name.size() > 1 && argInfo.name[0] == '*') continue; auto p = args.args.find(argInfo.name); if (p == args.args.end()) { result.args[argInfo.name] = IntValue2Value(argInfo.defaultVal); continue; } const auto& v = p->second; result.args[argInfo.name] = IntValue2Value(v); } ValuesMap extraKwArgs; for (auto& p : args.extraKwArgs) extraKwArgs[p.first] = IntValue2Value(p.second); result.extraKwArgs = Value(std::move(extraKwArgs)); ValuesList extraPosArgs; for (auto& p : args.extraPosArgs) extraPosArgs.push_back(IntValue2Value(p)); result.extraPosArgs = Value(std::move(extraPosArgs)); result.context = GenericMap([accessor = ContextMapper(&context)]() -> const IMapItemAccessor* { return &accessor; }); return result; } namespace visitors { InputValueConvertor::result_t InputValueConvertor::ConvertUserCallable(const UserCallable& val) { std::vector<ArgumentInfo> args; for (auto& pi : val.argsInfo) { args.emplace_back(pi.paramName, pi.isMandatory, Value2IntValue(pi.defValue)); } return InternalValue(Callable(Callable::UserCallable, [val, argsInfo = std::move(args)](const CallParams& params, RenderContext& context) -> InternalValue { auto ucParams = PrepareUserCallableParams(params, context, argsInfo); return Value2IntValue(val.callable(ucParams)); })); } } // namespace visitors } // namespace jinja2