diff --git a/include/jinja2cpp/value.h b/include/jinja2cpp/value.h index 19fed209..431bc736 100644 --- a/include/jinja2cpp/value.h +++ b/include/jinja2cpp/value.h @@ -50,6 +50,10 @@ class GenericMap return m_accessor()->GetSize(); } Value GetValueByIndex(int64_t index) const; + auto GetKeys() const + { + return m_accessor()->GetKeys(); + } std::function m_accessor; }; @@ -69,12 +73,17 @@ class GenericList } Value GetValueByIndex(int64_t idx) const; - + auto GetAccessor() const { return m_accessor(); } + bool IsValid() const + { + return !(!m_accessor); + } + std::function m_accessor; }; @@ -106,6 +115,8 @@ class Value { const ValueData& data() const {return m_data;} + ValueData& data() {return m_data;} + bool isString() const { return boost::get(&m_data) != nullptr; diff --git a/src/expression_evaluator.cpp b/src/expression_evaluator.cpp index 1711dbe0..661a81c4 100644 --- a/src/expression_evaluator.cpp +++ b/src/expression_evaluator.cpp @@ -1,5 +1,6 @@ #include "expression_evaluator.h" #include "filters.h" +#include "internal_value.h" #include "testers.h" #include "value_visitors.h" @@ -17,6 +18,7 @@ std::unordered_map ExpressionFil {"camelize", FilterFactory::MakeCreator(filters::StringConverter::CamelMode)}, {"capitalize", FilterFactory::MakeCreator(filters::StringConverter::CapitalMode)}, {"default", &FilterFactory::Create}, + {"d", &FilterFactory::Create}, {"dictsort", &FilterFactory::Create}, {"escape", FilterFactory::MakeCreator(filters::StringConverter::EscapeHtmlMode)}, {"escapecpp", FilterFactory::MakeCreator(filters::StringConverter::EscapeCppMode)}, @@ -61,12 +63,12 @@ std::unordered_map IsExpression::s_t {"startsWith", &TesterFactory::Create}, }; -Value FullExpressionEvaluator::Evaluate(RenderContext& values) +InternalValue FullExpressionEvaluator::Evaluate(RenderContext& values) { if (!m_expression) - return Value(); + return InternalValue(); - Value origVal = m_expression->Evaluate(values); + InternalValue origVal = m_expression->Evaluate(values); if (m_filter) origVal = m_filter->Evaluate(origVal, values); @@ -76,31 +78,31 @@ Value FullExpressionEvaluator::Evaluate(RenderContext& values) return origVal; } -Value ValueRefExpression::Evaluate(RenderContext& values) +InternalValue ValueRefExpression::Evaluate(RenderContext& values) { bool found = false; auto p = values.FindValue(m_valueName, found); if (found) return p->second; - return Value(); + return InternalValue(); } -Value SubscriptExpression::Evaluate(RenderContext& values) +InternalValue SubscriptExpression::Evaluate(RenderContext& values) { - return m_value->Evaluate(values).subscript(m_subscriptExpr->Evaluate(values)); + return Subscript(m_value->Evaluate(values), m_subscriptExpr->Evaluate(values)); } -Value UnaryExpression::Evaluate(RenderContext& values) +InternalValue UnaryExpression::Evaluate(RenderContext& values) { - return boost::apply_visitor(visitors::UnaryOperation(m_oper), m_expr->Evaluate(values).data()); + return Apply(m_expr->Evaluate(values), m_oper); } -Value BinaryExpression::Evaluate(RenderContext& context) +InternalValue BinaryExpression::Evaluate(RenderContext& context) { - Value leftVal = m_leftExpr->Evaluate(context); - Value rightVal = m_rightExpr->Evaluate(context); - Value result; + InternalValue leftVal = m_leftExpr->Evaluate(context); + InternalValue rightVal = m_rightExpr->Evaluate(context); + InternalValue result; switch (m_oper) { @@ -121,7 +123,7 @@ Value BinaryExpression::Evaluate(RenderContext& context) case jinja2::BinaryExpression::DivReminder: case jinja2::BinaryExpression::DivInteger: case jinja2::BinaryExpression::Pow: - result = boost::apply_visitor(visitors::BinaryMathOperation(m_oper), leftVal.data(), rightVal.data()); + result = Apply2(leftVal, rightVal, m_oper); break; case jinja2::BinaryExpression::StringConcat: default: @@ -130,26 +132,26 @@ Value BinaryExpression::Evaluate(RenderContext& context) return result; } -Value TupleCreator::Evaluate(RenderContext& context) +InternalValue TupleCreator::Evaluate(RenderContext& context) { - ValuesList result; + InternalValueList result; for (auto& e : m_exprs) { result.push_back(e->Evaluate(context)); } - return Value(result); + return ListAdapter::CreateAdapter(std::move(result)); } -Value DictCreator::Evaluate(RenderContext& context) +InternalValue DictCreator::Evaluate(RenderContext& context) { - ValuesMap result; + InternalValueMap result; for (auto& e : m_exprs) { result[e.first] = e.second->Evaluate(context); } - return Value(result); + return MapAdapter::CreateAdapter(std::move(result));; } ExpressionFilter::ExpressionFilter(std::string filterName, CallParams params) @@ -161,7 +163,7 @@ ExpressionFilter::ExpressionFilter(std::string filterName, CallParams params) m_filter = p->second(std::move(params)); } -Value ExpressionFilter::Evaluate(const Value& baseVal, RenderContext& context) +InternalValue ExpressionFilter::Evaluate(const InternalValue& baseVal, RenderContext& context) { if (m_parentFilter) return m_filter->Filter(m_parentFilter->Evaluate(baseVal, context), context); @@ -179,22 +181,23 @@ IsExpression::IsExpression(ExpressionEvaluatorPtr<> value, std::string tester, C m_tester = p->second(std::move(params)); } -Value IsExpression::Evaluate(RenderContext& context) +InternalValue IsExpression::Evaluate(RenderContext& context) { return m_tester->Test(m_value->Evaluate(context), context); } bool IfExpression::Evaluate(RenderContext& context) { - return boost::apply_visitor(visitors::BooleanEvaluator(), m_testExpr->Evaluate(context).data()); + return ConvertToBool(m_testExpr->Evaluate(context)); } -Value IfExpression::EvaluateAltValue(RenderContext& context) +InternalValue IfExpression::EvaluateAltValue(RenderContext& context) { - return m_altValue ? m_altValue->Evaluate(context) : Value(); + return m_altValue ? m_altValue->Evaluate(context) : InternalValue(); } -Value DictionaryCreator::Evaluate(RenderContext& context) +/* +InternalValue DictionaryCreator::Evaluate(RenderContext& context) { ValuesMap result; for (auto& i : m_items) @@ -203,9 +206,9 @@ Value DictionaryCreator::Evaluate(RenderContext& context) } return result; -} +}*/ -Value CallExpression::Evaluate(RenderContext& values) +InternalValue CallExpression::Evaluate(RenderContext& values) { std::string valueRef = boost::algorithm::join(m_valueRef, "."); @@ -214,29 +217,29 @@ Value CallExpression::Evaluate(RenderContext& values) else if (valueRef == "loop.cycle") return CallLoopCycle(values); - return Value(); + return InternalValue(); } -Value CallExpression::CallGlobalRange(RenderContext& values) +InternalValue CallExpression::CallGlobalRange(RenderContext& values) { bool isArgsParsed = true; auto args = helpers::ParseCallParams({{"start"}, {"stop", true}, {"step"}}, m_params, isArgsParsed); if (!isArgsParsed) - return Value(); + return InternalValue(); auto startExpr = args["start"]; auto stopExpr = args["stop"]; auto stepExpr = args["step"]; - Value startVal = startExpr ? startExpr->Evaluate(values) : Value(); - Value stopVal = stopExpr ? stopExpr->Evaluate(values) : Value(); - Value stepVal = stepExpr ? stepExpr->Evaluate(values) : Value(); + InternalValue startVal = startExpr ? startExpr->Evaluate(values) : InternalValue(); + InternalValue stopVal = stopExpr ? stopExpr->Evaluate(values) : InternalValue(); + InternalValue stepVal = stepExpr ? stepExpr->Evaluate(values) : InternalValue(); - int64_t start = boost::apply_visitor(visitors::IntegerEvaluator(), startVal.data()); - int64_t stop = boost::apply_visitor(visitors::IntegerEvaluator(), stopVal.data()); - int64_t step = boost::apply_visitor(visitors::IntegerEvaluator(), stepVal.data()); + int64_t start = Apply(startVal); + int64_t stop = Apply(stopVal); + int64_t step = Apply(stepVal); if (!stepExpr) { @@ -245,10 +248,10 @@ Value CallExpression::CallGlobalRange(RenderContext& values) else { if (step == 0) - return Value(); + return InternalValue(); } - class RangeGenerator : public ListItemAccessor + class RangeGenerator : public IListAccessor { public: RangeGenerator(int64_t start, int64_t stop, int64_t step) @@ -264,7 +267,7 @@ Value CallExpression::CallGlobalRange(RenderContext& values) auto count = distance / m_step; return count < 0 ? 0 : static_cast(count); } - Value GetValueByIndex(int64_t idx) const override + InternalValue GetValueByIndex(int64_t idx) const override { return m_start + m_step * idx; } @@ -275,18 +278,18 @@ Value CallExpression::CallGlobalRange(RenderContext& values) int64_t m_step; }; - return GenericList([accessor = RangeGenerator(start, stop, step)]() -> const ListItemAccessor* {return &accessor;}); + return ListAdapter([accessor = RangeGenerator(start, stop, step)]() -> const IListAccessor* {return &accessor;}); } -Value CallExpression::CallLoopCycle(RenderContext& values) +InternalValue CallExpression::CallLoopCycle(RenderContext& values) { bool loopFound = false; auto loopValP = values.FindValue("loop", loopFound); if (!loopFound) - return Value(); + return InternalValue(); - const ValuesMap* loop = boost::get(&loopValP->second.data()); - int64_t baseIdx = boost::apply_visitor(visitors::IntegerEvaluator(), (*loop).at("index0").data()); + auto loop = boost::get(&loopValP->second); + int64_t baseIdx = Apply(loop->GetValueByName("index0")); auto idx = static_cast(baseIdx % m_params.posParams.size()); return m_params.posParams[idx]->Evaluate(values); } @@ -421,7 +424,7 @@ ParsedArguments ParseCallParams(const std::initializer_list& args, continue; case NotFound: { - if (!argInfo.info->defaultVal.isEmpty()) + if (!IsEmpty(argInfo.info->defaultVal)) result.args[argInfo.info->name] = std::make_shared(argInfo.info->defaultVal); break; } diff --git a/src/expression_evaluator.h b/src/expression_evaluator.h index bf44ea7d..bf018d85 100644 --- a/src/expression_evaluator.h +++ b/src/expression_evaluator.h @@ -1,7 +1,7 @@ #ifndef EXPRESSION_EVALUATOR_H #define EXPRESSION_EVALUATOR_H -#include "jinja2cpp/value.h" +#include "internal_value.h" #include "render_context.h" #include @@ -15,7 +15,7 @@ class ExpressionEvaluatorBase public: virtual ~ExpressionEvaluatorBase() {} - virtual Value Evaluate(RenderContext& values) = 0; + virtual InternalValue Evaluate(RenderContext& values) = 0; }; template @@ -32,9 +32,9 @@ struct ArgumentInfo { std::string name; bool mandatory; - Value defaultVal; + InternalValue defaultVal; - ArgumentInfo(std::string argName, bool isMandatory = false, Value def = Value()) + ArgumentInfo(std::string argName, bool isMandatory = false, InternalValue def = InternalValue()) : name(std::move(argName)) , mandatory(isMandatory) , defaultVal(std::move(def)) @@ -76,7 +76,7 @@ class FullExpressionEvaluator : public ExpressionEvaluatorBase { m_tester = expr; } - Value Evaluate(RenderContext& values) override; + InternalValue Evaluate(RenderContext& values) override; private: ExpressionEvaluatorPtr m_expression; ExpressionEvaluatorPtr m_filter; @@ -90,7 +90,7 @@ class ValueRefExpression : public Expression : m_valueName(valueName) { } - Value Evaluate(RenderContext& values) override; + InternalValue Evaluate(RenderContext& values) override; private: std::string m_valueName; }; @@ -103,7 +103,7 @@ class SubscriptExpression : public Expression , m_subscriptExpr(subscriptExpr) { } - Value Evaluate(RenderContext& values) override; + InternalValue Evaluate(RenderContext& values) override; private: ExpressionEvaluatorPtr m_value; ExpressionEvaluatorPtr m_subscriptExpr; @@ -112,15 +112,15 @@ class SubscriptExpression : public Expression class ConstantExpression : public Expression { public: - ConstantExpression(Value constant) + ConstantExpression(InternalValue constant) : m_constant(constant) {} - Value Evaluate(RenderContext&) override + InternalValue Evaluate(RenderContext&) override { return m_constant; } private: - Value m_constant; + InternalValue m_constant; }; class TupleCreator : public Expression @@ -131,12 +131,12 @@ class TupleCreator : public Expression { } - Value Evaluate(RenderContext&) override; + InternalValue Evaluate(RenderContext&) override; private: std::vector> m_exprs; }; - +/* class DictionaryCreator : public Expression { public: @@ -145,11 +145,11 @@ class DictionaryCreator : public Expression { } - Value Evaluate(RenderContext&) override; + InternalValue Evaluate(RenderContext&) override; private: std::unordered_map> m_items; -}; +};*/ class DictCreator : public Expression { @@ -159,7 +159,7 @@ class DictCreator : public Expression { } - Value Evaluate(RenderContext&) override; + InternalValue Evaluate(RenderContext&) override; private: std::unordered_map> m_exprs; @@ -179,7 +179,7 @@ class UnaryExpression : public Expression : m_oper(oper) , m_expr(expr) {} - Value Evaluate(RenderContext&) override; + InternalValue Evaluate(RenderContext&) override; private: Operation m_oper; ExpressionEvaluatorPtr<> m_expr; @@ -221,7 +221,7 @@ class BinaryExpression : public Expression , m_leftExpr(leftExpr) , m_rightExpr(rightExpr) {} - Value Evaluate(RenderContext&) override; + InternalValue Evaluate(RenderContext&) override; private: Operation m_oper; ExpressionEvaluatorPtr<> m_leftExpr; @@ -236,13 +236,13 @@ class IsExpression : public Expression struct ITester { virtual ~ITester() {} - virtual bool Test(const Value& baseVal, RenderContext& context) = 0; + virtual bool Test(const InternalValue& baseVal, RenderContext& context) = 0; }; using TesterFactoryFn = std::function (CallParams params)>; IsExpression(ExpressionEvaluatorPtr<> value, std::string tester, CallParams params); - Value Evaluate(RenderContext& context) override; + InternalValue Evaluate(RenderContext& context) override; private: ExpressionEvaluatorPtr<> m_value; @@ -261,14 +261,14 @@ class CallExpression : public Expression { } - Value Evaluate(RenderContext &values); + InternalValue Evaluate(RenderContext &values); auto& GetValueRef() const {return m_valueRef;} auto& GetParams() const {return m_params;} private: - Value CallGlobalRange(RenderContext &values); - Value CallLoopCycle(RenderContext &values); + InternalValue CallGlobalRange(RenderContext &values); + InternalValue CallLoopCycle(RenderContext &values); private: std::vector m_valueRef; @@ -283,14 +283,14 @@ class ExpressionFilter struct IExpressionFilter { virtual ~IExpressionFilter() {} - virtual Value Filter(const Value& baseVal, RenderContext& context) = 0; + virtual InternalValue Filter(const InternalValue& baseVal, RenderContext& context) = 0; }; using FilterFactoryFn = std::function (CallParams params)>; ExpressionFilter(std::string filterName, CallParams params); - Value Evaluate(const Value& baseVal, RenderContext& context); + InternalValue Evaluate(const InternalValue& baseVal, RenderContext& context); void SetParentFilter(std::shared_ptr parentFilter) { m_parentFilter = parentFilter; @@ -315,7 +315,7 @@ class IfExpression } bool Evaluate(RenderContext& context); - Value EvaluateAltValue(RenderContext& context); + InternalValue EvaluateAltValue(RenderContext& context); void SetAltValue(ExpressionEvaluatorPtr<> altValue) { diff --git a/src/expression_parser.cpp b/src/expression_parser.cpp index 6da9e3b3..2a3e85bb 100644 --- a/src/expression_parser.cpp +++ b/src/expression_parser.cpp @@ -130,7 +130,7 @@ ExpressionEvaluatorPtr ExpressionParser::ParseLogicalCompare(LexScan if (nextTok != Token::Identifier) return ExpressionEvaluatorPtr(); - std::string name = nextTok.value.asString(); + std::string name = AsString(nextTok.value); bool valid = true; CallParams params; @@ -298,7 +298,7 @@ ExpressionEvaluatorPtr ExpressionParser::ParseValueExpression(LexSca { for (size_t i = 1; i < valueRef.size(); ++ i) { - auto indexExpr = std::make_shared(Value(valueRef[i])); + auto indexExpr = std::make_shared(InternalValue(valueRef[i])); baseValueRef = std::make_shared(baseValueRef, indexExpr); } } @@ -309,9 +309,9 @@ ExpressionEvaluatorPtr ExpressionParser::ParseValueExpression(LexSca case Token::String: return std::make_shared(tok.value); case Token::True: - return std::make_shared(Value(true)); + return std::make_shared(InternalValue(true)); case Token::False: - return std::make_shared(Value(false)); + return std::make_shared(InternalValue(false)); case '(': return ParseBracedExpressionOrTuple(lexer); case '[': @@ -372,13 +372,13 @@ ExpressionEvaluatorPtr ExpressionParser::ParseDictionary(LexScanner& if (!expr) return result; - items[key.value.asString()] = expr; + items[AsString(key.value)] = expr; if (lexer.PeekNextToken() == ',') lexer.EatToken(); } - result = std::make_shared(std::move(items)); + result = std::make_shared(std::move(items)); return result; } @@ -420,7 +420,7 @@ ExpressionEvaluatorPtr ExpressionParser::ParseSubsicpt(LexS { for (size_t i = 1; i < valueRef.size(); ++ i) { - auto indexExpr = std::make_shared(Value(valueRef[i])); + auto indexExpr = std::make_shared(InternalValue(valueRef[i])); baseValueRef = std::make_shared(baseValueRef, indexExpr); } } @@ -456,7 +456,7 @@ CallParams ExpressionParser::ParseCallParams(LexScanner& lexer, bool& isValid) std::string paramName; if (tok == Token::Identifier && lexer.PeekNextToken() == '=') { - paramName = tok.value.asString(); + paramName = AsString(tok.value); lexer.EatToken(); } else @@ -485,7 +485,7 @@ CallParams ExpressionParser::ParseCallParams(LexScanner& lexer, bool& isValid) std::vector ExpressionParser::ParseValueRef(LexScanner& lexer) { Token tok = lexer.NextToken(); - auto valueName = tok.value.asString(); + auto valueName = AsString(tok.value); std::vector result; result.push_back(valueName); @@ -496,7 +496,7 @@ std::vector ExpressionParser::ParseValueRef(LexScanner& lexer) if (tok != Token::Identifier) return std::vector(); - result.push_back(tok.value.asString()); + result.push_back(AsString(tok.value)); } lexer.ReturnToken(); @@ -516,7 +516,7 @@ ExpressionEvaluatorPtr ExpressionParser::ParseFilterExpression if (tok != Token::Identifier) return empty; - std::string name = tok.value.asString(); + std::string name = AsString(tok.value); bool valid = true; CallParams params; diff --git a/src/filters.cpp b/src/filters.cpp index a6494f6d..d1524c5e 100644 --- a/src/filters.cpp +++ b/src/filters.cpp @@ -1,7 +1,9 @@ #include "filters.h" #include "value_visitors.h" +#include "value_helpers.h" #include +#include namespace jinja2 { @@ -16,32 +18,38 @@ bool FilterBase::ParseParams(const std::initializer_list& argsInfo return result; } +InternalValue FilterBase::GetArgumentValue(std::string argName, RenderContext& context, InternalValue defVal) +{ + auto argExpr = m_args[argName]; + return argExpr ? argExpr->Evaluate(context) : std::move(defVal); +} + Join::Join(FilterParams params) { ParseParams({{"d", false, std::string()}, {"attribute"}}, params); } -Value Join::Filter(const Value& baseVal, RenderContext& context) +InternalValue Join::Filter(const InternalValue& baseVal, RenderContext& context) { - if (!baseVal.isList()) - return Value(); + InternalValue attrName = GetArgumentValue("attribute", context); - auto attrExpr = m_args["attribute"]; - Value attrName = attrExpr ? attrExpr->Evaluate(context) : Value(); + bool isConverted = false; + ListAdapter values = ConvertToList(baseVal, attrName, isConverted); - ValuesList values = boost::apply_visitor(visitors::ListEvaluator(attrName), baseVal.data()); + if (!isConverted) + return InternalValue(); bool isFirst = true; - Value result; - Value delimiter = m_args["d"]->Evaluate(context); - for (const Value& val : values) + InternalValue result; + InternalValue delimiter = m_args["d"]->Evaluate(context); + for (const InternalValue& val : values) { if (isFirst) isFirst = false; else - result = boost::apply_visitor(visitors::StringJoiner(), result.data(), delimiter.data()); + result = Apply2(result, delimiter); - result = boost::apply_visitor(visitors::StringJoiner(), result.data(), val.data()); + result = Apply2(result, val); } return result; @@ -49,35 +57,37 @@ Value Join::Filter(const Value& baseVal, RenderContext& context) Sort::Sort(FilterParams params) { - ParseParams({{"reverse", false, Value(false)}, {"case_sensitive", false, Value(false)}, {"attribute", false}}, params); + ParseParams({{"reverse", false, InternalValue(false)}, {"case_sensitive", false, InternalValue(false)}, {"attribute", false}}, params); } -Value Sort::Filter(const Value& baseVal, RenderContext& context) +InternalValue Sort::Filter(const InternalValue& baseVal, RenderContext& context) { - auto attrExpr = m_args["attribute"]; - auto isReverseExpr = m_args["reverse"]; - auto isCsExpr = m_args["case_sensitive"]; - Value attrName = attrExpr ? attrExpr->Evaluate(context) : Value(); - Value isReverseVal = isReverseExpr ? isReverseExpr->Evaluate(context) : Value(false); - Value isCsVal = isCsExpr ? isCsExpr->Evaluate(context) : Value(false); + InternalValue attrName = GetArgumentValue("attribute", context); + InternalValue isReverseVal = GetArgumentValue("reverse", context, InternalValue(false)); + InternalValue isCsVal = GetArgumentValue("case_sensitive", context, InternalValue(false)); + + bool isConverted = false; + ListAdapter origValues = ConvertToList(baseVal, isConverted); + if (!isConverted) + return InternalValue(); + InternalValueList values = origValues.ToValueList(); - ValuesList values = Apply(baseVal); BinaryExpression::Operation oper = - Apply(isReverseVal) ? BinaryExpression::LogicalGt : BinaryExpression::LogicalLt; + ConvertToBool(isReverseVal) ? BinaryExpression::LogicalGt : BinaryExpression::LogicalLt; BinaryExpression::CompareType compType = - Apply(isCsVal) ? BinaryExpression::CaseSensitive : BinaryExpression::CaseInsensitive; + ConvertToBool(isCsVal) ? BinaryExpression::CaseSensitive : BinaryExpression::CaseInsensitive; std::sort(values.begin(), values.end(), [&attrName, oper, compType](auto& val1, auto& val2) { - Value cmpRes; - if (attrName.isEmpty()) - cmpRes = boost::apply_visitor(visitors::BinaryMathOperation(oper, compType), val1.data(), val2.data()); + InternalValue cmpRes; + if (IsEmpty(attrName)) + cmpRes = Apply2(val1, val2, oper, compType); else - cmpRes = boost::apply_visitor(visitors::BinaryMathOperation(oper, compType), val1.subscript(attrName).data(), val2.subscript(attrName).data()); + cmpRes = Apply2(Subscript(val1, attrName), Subscript(val2, attrName), oper, compType); - return Apply(cmpRes); + return ConvertToBool(cmpRes); }); - return values; + return ListAdapter::CreateAdapter(std::move(values)); } Attribute::Attribute(FilterParams params) @@ -85,19 +95,28 @@ Attribute::Attribute(FilterParams params) } -Value Attribute::Filter(const Value& baseVal, RenderContext& context) +InternalValue Attribute::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } Default::Default(FilterParams params) { - + ParseParams({{"default_value", false, InternalValue(std::string(""))}, {"boolean", false, InternalValue(false)}}, params); } -Value Default::Filter(const Value& baseVal, RenderContext& context) +InternalValue Default::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + InternalValue defaultVal = GetArgumentValue("default_value", context); + InternalValue conditionResult = GetArgumentValue("boolean", context); + + if (IsEmpty(baseVal)) + return defaultVal; + + if (ConvertToBool(conditionResult) && !ConvertToBool(baseVal)) + return defaultVal; + + return baseVal; } DictSort::DictSort(FilterParams params) @@ -105,9 +124,9 @@ DictSort::DictSort(FilterParams params) } -Value DictSort::Filter(const Value& baseVal, RenderContext& context) +InternalValue DictSort::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } GroupBy::GroupBy(FilterParams params) @@ -115,9 +134,9 @@ GroupBy::GroupBy(FilterParams params) } -Value GroupBy::Filter(const Value& baseVal, RenderContext& context) +InternalValue GroupBy::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } Map::Map(FilterParams params) @@ -125,9 +144,9 @@ Map::Map(FilterParams params) } -Value Map::Filter(const Value& baseVal, RenderContext& context) +InternalValue Map::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } PrettyPrint::PrettyPrint(FilterParams params) @@ -135,9 +154,9 @@ PrettyPrint::PrettyPrint(FilterParams params) } -Value PrettyPrint::Filter(const Value& baseVal, RenderContext& context) +InternalValue PrettyPrint::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } Random::Random(FilterParams params) @@ -145,19 +164,146 @@ Random::Random(FilterParams params) } -Value Random::Filter(const Value& baseVal, RenderContext& context) +InternalValue Random::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } SequenceAccessor::SequenceAccessor(FilterParams params, SequenceAccessor::Mode mode) + : m_mode(mode) { - + switch (mode) + { + case FirstItemMode: + break; + case LastItemMode: + break; + case LengthMode: + break; + case MaxItemMode: + ParseParams({{"case_sensitive", false, InternalValue(false)}, {"attribute", false}}, params); + break; + case MinItemMode: + ParseParams({{"case_sensitive", false, InternalValue(false)}, {"attribute", false}}, params); + break; + case ReverseMode: + break; + case SumItemsMode: + ParseParams({{"attribute", false}, {"start", false}}, params); + break; + case UniqueItemsMode: + break; + } } -Value SequenceAccessor::Filter(const Value& baseVal, RenderContext& context) +InternalValue SequenceAccessor::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + InternalValue result; + + bool isConverted = false; + ListAdapter list = ConvertToList(baseVal, isConverted); + + if (!isConverted) + return result; + + InternalValue attrName = GetArgumentValue("attribute", context); + InternalValue isCsVal = GetArgumentValue("case_sensitive", context, InternalValue(false)); + + BinaryExpression::CompareType compType = + ConvertToBool(isCsVal) ? BinaryExpression::CaseSensitive : BinaryExpression::CaseInsensitive; + + auto lessComparator = [&attrName, &compType](auto& val1, auto& val2) { + InternalValue cmpRes; + + if (IsEmpty(attrName)) + cmpRes = Apply2(val1, val2, BinaryExpression::LogicalLt, compType); + else + cmpRes = Apply2(Subscript(val1, attrName), Subscript(val2, attrName), BinaryExpression::LogicalLt, compType); + + return ConvertToBool(cmpRes); + }; + + auto equalComparator = [&attrName, &compType](auto& val1, auto& val2) { + InternalValue cmpRes; + + if (IsEmpty(attrName)) + cmpRes = Apply2(val1, val2, BinaryExpression::LogicalEq, compType); + else + cmpRes = Apply2(Subscript(val1, attrName), Subscript(val2, attrName), BinaryExpression::LogicalEq, compType); + + return ConvertToBool(cmpRes); + }; + + switch (m_mode) + { + case FirstItemMode: + result = list.GetSize() == 0 ? InternalValue() : list.GetValueByIndex(0); + break; + case LastItemMode: + result = list.GetSize() == 0 ? InternalValue() : list.GetValueByIndex(list.GetSize() - 1); + break; + case LengthMode: + result = static_cast(list.GetSize()); + break; + case MaxItemMode: + { + auto b = list.begin(); + auto e = list.end(); + auto p = std::max_element(b, e, lessComparator); + result = p != e ? *p : InternalValue(); + break; + } + case MinItemMode: + { + auto b = list.begin(); + auto e = list.end(); + auto p = std::min_element(b, e, lessComparator); + result = p != e ? *p : InternalValue(); + break; + } + case ReverseMode: + { + InternalValueList resultList(list.GetSize()); + for (int n = 0; n < list.GetSize(); ++ n) + resultList[list.GetSize() - n - 1] = list.GetValueByIndex(n); + + result = ListAdapter::CreateAdapter(std::move(resultList)); + break; + } + case SumItemsMode: + { + ListAdapter l1; + ListAdapter* actualList; + if (IsEmpty(attrName)) + { + actualList = &list; + } + else + { + l1 = list.ToSubscriptedList(attrName, true); + actualList = &l1; + } + InternalValue start = GetArgumentValue("start", context); + InternalValue resultVal = std::accumulate(actualList->begin(), actualList->end(), start, [](const InternalValue& cur, const InternalValue& val) { + if (IsEmpty(cur)) + return val; + + return Apply2(cur, val, BinaryExpression::Plus); + }); + + result = std::move(resultVal); + break; + } + case UniqueItemsMode: + { + InternalValueList resultList; + std::unique_copy(list.begin(), list.end(), std::back_inserter(resultList), equalComparator); + result = ListAdapter::CreateAdapter(std::move(resultList)); + break; + } + } + + return result; } Serialize::Serialize(FilterParams params, Serialize::Mode mode) @@ -165,9 +311,9 @@ Serialize::Serialize(FilterParams params, Serialize::Mode mode) } -Value Serialize::Filter(const Value& baseVal, RenderContext& context) +InternalValue Serialize::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } Slice::Slice(FilterParams params, Slice::Mode mode) @@ -175,9 +321,9 @@ Slice::Slice(FilterParams params, Slice::Mode mode) } -Value Slice::Filter(const Value& baseVal, RenderContext& context) +InternalValue Slice::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } StringConverter::StringConverter(FilterParams params, StringConverter::Mode mode) @@ -185,9 +331,9 @@ StringConverter::StringConverter(FilterParams params, StringConverter::Mode mode } -Value StringConverter::Filter(const Value& baseVal, RenderContext& context) +InternalValue StringConverter::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } StringFormat::StringFormat(FilterParams params, StringFormat::Mode mode) @@ -195,9 +341,9 @@ StringFormat::StringFormat(FilterParams params, StringFormat::Mode mode) } -Value StringFormat::Filter(const Value& baseVal, RenderContext& context) +InternalValue StringFormat::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } Tester::Tester(FilterParams params, Tester::Mode mode) @@ -205,9 +351,9 @@ Tester::Tester(FilterParams params, Tester::Mode mode) } -Value Tester::Filter(const Value& baseVal, RenderContext& context) +InternalValue Tester::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } ValueConverter::ValueConverter(FilterParams params, ValueConverter::Mode mode) @@ -215,9 +361,9 @@ ValueConverter::ValueConverter(FilterParams params, ValueConverter::Mode mode) } -Value ValueConverter::Filter(const Value& baseVal, RenderContext& context) +InternalValue ValueConverter::Filter(const InternalValue& baseVal, RenderContext& context) { - return Value(); + return InternalValue(); } diff --git a/src/filters.h b/src/filters.h index 1be7016b..f11ab6ae 100644 --- a/src/filters.h +++ b/src/filters.h @@ -35,6 +35,7 @@ class FilterBase : public ExpressionFilter::IExpressionFilter public: protected: bool ParseParams(const std::initializer_list& argsInfo, const CallParams& params); + InternalValue GetArgumentValue(std::string argName, RenderContext& context, InternalValue defVal = InternalValue()); protected: ParsedArguments m_args; @@ -45,7 +46,7 @@ class Attribute : public FilterBase public: Attribute(FilterParams params); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class Default : public FilterBase @@ -53,7 +54,7 @@ class Default : public FilterBase public: Default(FilterParams params); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class DictSort : public FilterBase @@ -61,7 +62,7 @@ class DictSort : public FilterBase public: DictSort(FilterParams params); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class GroupBy : public FilterBase @@ -69,7 +70,7 @@ class GroupBy : public FilterBase public: GroupBy(FilterParams params); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class Join : public FilterBase @@ -77,7 +78,7 @@ class Join : public FilterBase public: Join(FilterParams params); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class Map : public FilterBase @@ -85,7 +86,7 @@ class Map : public FilterBase public: Map(FilterParams params); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class PrettyPrint : public FilterBase @@ -93,7 +94,7 @@ class PrettyPrint : public FilterBase public: PrettyPrint(FilterParams params); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class Random : public FilterBase @@ -101,7 +102,7 @@ class Random : public FilterBase public: Random(FilterParams params); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class SequenceAccessor : public FilterBase @@ -122,7 +123,10 @@ class SequenceAccessor : public FilterBase SequenceAccessor(FilterParams params, Mode mode); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); + +private: + Mode m_mode; }; class Serialize : public FilterBase @@ -137,7 +141,7 @@ class Serialize : public FilterBase Serialize(FilterParams params, Mode mode); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class Slice : public FilterBase @@ -151,7 +155,7 @@ class Slice : public FilterBase Slice(FilterParams params, Mode mode); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class Sort : public FilterBase @@ -159,7 +163,7 @@ class Sort : public FilterBase public: Sort(FilterParams params); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class StringConverter : public FilterBase @@ -183,7 +187,7 @@ class StringConverter : public FilterBase StringConverter(FilterParams params, Mode mode); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class StringFormat : public FilterBase @@ -196,7 +200,7 @@ class StringFormat : public FilterBase StringFormat(FilterParams params, Mode mode); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class Tester : public FilterBase @@ -212,7 +216,7 @@ class Tester : public FilterBase Tester(FilterParams params, Mode mode); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; class ValueConverter : public FilterBase @@ -229,7 +233,7 @@ class ValueConverter : public FilterBase ValueConverter(FilterParams params, Mode mode); - Value Filter(const Value& baseVal, RenderContext& context); + InternalValue Filter(const InternalValue& baseVal, RenderContext& context); }; } // filters } // jinja2 diff --git a/src/internal_value.cpp b/src/internal_value.cpp new file mode 100644 index 00000000..b6db0eeb --- /dev/null +++ b/src/internal_value.cpp @@ -0,0 +1,441 @@ +#include "internal_value.h" +#include "value_visitors.h" + +namespace jinja2 +{ + +struct SubscriptionVisitor : public visitors::BaseVisitor<> +{ + using BaseVisitor::operator (); + + InternalValue operator() (const MapAdapter& values, const std::string& field) const + { + if (!values.HasValue(field)) + return InternalValue(); + + return values.GetValueByName(field); + } + + InternalValue operator() (const ListAdapter& values, int64_t index) const + { + if (index < 0 || static_cast(index) >= values.GetSize()) + return InternalValue(); + + return values.GetValueByIndex(index); + } + + InternalValue operator() (const MapAdapter& values, int64_t index) const + { + if (index < 0 || static_cast(index) >= values.GetSize()) + return InternalValue(); + + return values.GetValueByIndex(index); + } + + template + InternalValue operator() (const std::basic_string& str, int64_t index) const + { + if (index < 0 || static_cast(index) >= str.size()) + return InternalValue(); + + std::basic_string result(1, str[static_cast(index)]); + return TargetString(std::move(result)); + } +}; + + +InternalValue Subscript(const InternalValue& val, const InternalValue& subscript) +{ + return Apply2(val, subscript); +} + +InternalValue Subscript(const InternalValue& val, const std::string& subscript) +{ + return Apply2(val, InternalValue(subscript)); +} + +std::string AsString(const InternalValue& val) +{ + auto* str = boost::get(&val); + auto* tstr = boost::get(&val); + if (str != nullptr) + return *str; + else + { + str = boost::get(tstr); + if (str != nullptr) + return *str; + } + + return std::string(); +} + +struct ListConverter : public visitors::BaseVisitor> +{ + using BaseVisitor::operator (); + + using result_t = boost::optional; + + + template + struct StringAdapter : public IListAccessor + { + using string = std::basic_string; + StringAdapter(const string* str) + : m_str(str) + { + } + + size_t GetSize() const override {return m_str->size();} + InternalValue GetValueByIndex(int64_t idx) const override {return m_str->substr(static_cast(idx), 1);} + + const string* m_str; + }; + + + result_t operator() (const ListAdapter& list) const + { + return list; + } + + template + result_t operator() (const std::basic_string& str) const + { + return result_t(ListAdapter([adaptor = StringAdapter(&str)]() {return &adaptor;})); + } + +}; + +ListAdapter ConvertToList(const InternalValue& val, bool& isConverted) +{ + auto result = Apply(val); + if (!result) + { + isConverted = false; + return ListAdapter(); + } + isConverted = true; + return result.get(); +} + +ListAdapter ConvertToList(const InternalValue& val, InternalValue subscipt, bool& isConverted) +{ + auto result = Apply(val); + if (!result) + { + isConverted = false; + return ListAdapter(); + } + isConverted = true; + + if (IsEmpty(subscipt)) + return result.get(); + + return result.get().ToSubscriptedList(subscipt, false); +} + +template +class ByRef +{ +public: + ByRef(const T& val) + : m_val(&val) + {} + + const T& Get() const {return *m_val;} +private: + const T* m_val; +}; + +template +class ByVal +{ +public: + ByVal(T&& val) + : m_val(std::move(val)) + {} + + const T& Get() const {return m_val;} +private: + T m_val; +}; + +template class Holder> +class GenericListAdapter : public IListAccessor +{ +public: + template + GenericListAdapter(U&& values) : m_values(std::forward(values)) {} + + size_t GetSize() const override {return m_values.Get().GetSize();} + InternalValue GetValueByIndex(int64_t idx) const override + { + auto val = m_values.Get().GetValueByIndex(idx); + return boost::apply_visitor(visitors::InputValueConvertor(true), val.data()).get(); + } +private: + Holder m_values; +}; + +template class Holder> +class ValuesListAdapter : public IListAccessor +{ +public: + template + ValuesListAdapter(U&& values) : m_values(std::forward(values)) {} + + size_t GetSize() const override {return m_values.Get().size();} + InternalValue GetValueByIndex(int64_t idx) const override + { + auto val = m_values.Get()[idx]; + return boost::apply_visitor(visitors::InputValueConvertor(false), val.data()).get(); + } +private: + Holder m_values; +}; + + +ListAdapter ListAdapter::CreateAdapter(InternalValueList&& values) +{ + class Adapter : public IListAccessor + { + public: + explicit Adapter(InternalValueList&& values) : m_values(std::move(values)) {} + + size_t GetSize() const override {return m_values.size();} + InternalValue GetValueByIndex(int64_t idx) const override {return m_values[static_cast(idx)];} + private: + InternalValueList m_values; + }; + + return ListAdapter([accessor = Adapter(std::move(values))]() {return &accessor;}); +} + +ListAdapter ListAdapter::CreateAdapter(const GenericList& values) +{ + return ListAdapter([accessor = GenericListAdapter(values)]() {return &accessor;}); +} + +ListAdapter ListAdapter::CreateAdapter(const ValuesList& values) +{ + return ListAdapter([accessor = ValuesListAdapter(values)]() {return &accessor;}); +} + +ListAdapter ListAdapter::CreateAdapter(GenericList&& values) +{ + return ListAdapter([accessor = GenericListAdapter(std::move(values))]() {return &accessor;}); +} + +ListAdapter ListAdapter::CreateAdapter(ValuesList&& values) +{ + return ListAdapter([accessor = ValuesListAdapter(std::move(values))]() {return &accessor;}); +} + +template class Holder> +class SubscriptedListAdapter : public IListAccessor +{ +public: + template + SubscriptedListAdapter(U&& values, const InternalValue& subscript) : m_values(std::forward(values)), m_subscript(subscript) {} + + size_t GetSize() const override {return m_values.Get().GetSize();} + InternalValue GetValueByIndex(int64_t idx) const override + { + return Subscript(m_values.Get().GetValueByIndex(idx), m_subscript); + } +private: + Holder m_values; + InternalValue m_subscript; +}; + +ListAdapter ListAdapter::ToSubscriptedList(const InternalValue& subscript, bool asRef) const +{ + if (asRef) + return ListAdapter([accessor = SubscriptedListAdapter(*this, subscript)]() {return &accessor;}); + + ListAdapter tmp(*this); + return ListAdapter([accessor = SubscriptedListAdapter(std::move(tmp), subscript)]() {return &accessor;}); +} + +InternalValueList ListAdapter::ToValueList() const +{ + InternalValueList result; + std::copy(begin(), end(), std::back_inserter(result)); + return result; +} + +template class Holder> +class InternalValueMapAdapter : public IMapAccessor +{ +public: + template + InternalValueMapAdapter(U&& values) : m_values(std::forward(values)) {} + + size_t GetSize() const override {return m_values.Get().size();} + InternalValue GetValueByIndex(int64_t idx) const override + { + InternalValueMap result; + auto p = m_values.Get().begin(); + std::advance(p, idx); + + result["key"] = InternalValue(p->first); + result["value"] = p->second; + + return MapAdapter::CreateAdapter(std::move(result)); + } + bool HasValue(const std::string& name) const override + { + return m_values.Get().count(name) != 0; + } + InternalValue GetValueByName(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 GetKeys() const override + { + std::vector result; + + for (auto& i : m_values.Get()) + result.push_back(i.first); + + return result; + } +private: + Holder m_values; +}; + +InternalValue Value2IntValue(const Value& val) +{ + auto result = boost::apply_visitor(visitors::InputValueConvertor(false), val.data()); + if (result) + return result.get(); + + return InternalValue(ValueRef(val)); +} + +InternalValue Value2IntValue(Value&& val) +{ + auto result = boost::apply_visitor(visitors::InputValueConvertor(true), val.data()); + if (result) + return result.get(); + + return InternalValue(ValueRef(val)); +} + +template class Holder> +class GenericMapAdapter : public IMapAccessor +{ +public: + template + GenericMapAdapter(U&& values) : m_values(std::forward(values)) {} + + size_t GetSize() const override {return m_values.Get().GetSize();} + InternalValue GetValueByIndex(int64_t idx) const override + { + auto val = m_values.Get().GetValueByIndex(idx); + return Value2IntValue(std::move(val)); + } + bool HasValue(const std::string& name) const override + { + return m_values.Get().HasValue(name); + } + InternalValue GetValueByName(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 GetKeys() const override + { + return m_values.Get().GetKeys(); + } + +private: + Holder m_values; +}; + + +template class Holder> +class ValuesMapAdapter : public IMapAccessor +{ +public: + template + ValuesMapAdapter(U&& values) : m_values(std::forward(values)) {} + + size_t GetSize() const override {return m_values.Get().size();} + InternalValue GetValueByIndex(int64_t idx) const override + { + InternalValueMap result; + auto p = m_values.Get().begin(); + std::advance(p, idx); + + result["key"] = InternalValue(p->first); + result["value"] = Value2IntValue(p->second); + + return MapAdapter::CreateAdapter(std::move(result)); + } + bool HasValue(const std::string& name) const override + { + return m_values.Get().count(name) != 0; + } + InternalValue GetValueByName(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 GetKeys() const override + { + std::vector result; + + for (auto& i : m_values.Get()) + result.push_back(i.first); + + return result; + } +private: + Holder m_values; +}; + + +MapAdapter MapAdapter::CreateAdapter(InternalValueMap&& values) +{ + return MapAdapter([accessor = InternalValueMapAdapter(std::move(values))]() {return &accessor;}); +} + +MapAdapter MapAdapter::CreateAdapter(const InternalValueMap* values) +{ + return MapAdapter([accessor = InternalValueMapAdapter(*values)]() {return &accessor;}); +} + +MapAdapter MapAdapter::CreateAdapter(const GenericMap& values) +{ + return MapAdapter([accessor = GenericMapAdapter(values)]() {return &accessor;}); +} + +MapAdapter MapAdapter::CreateAdapter(GenericMap&& values) +{ + return MapAdapter([accessor = GenericMapAdapter(std::move(values))]() {return &accessor;}); +} + +MapAdapter MapAdapter::CreateAdapter(const ValuesMap& values) +{ + return MapAdapter([accessor = ValuesMapAdapter(values)]() {return &accessor;}); +} + +MapAdapter MapAdapter::CreateAdapter(ValuesMap&& values) +{ + return MapAdapter([accessor = ValuesMapAdapter(std::move(values))]() {return &accessor;}); +} + +} // jinja2 diff --git a/src/internal_value.h b/src/internal_value.h new file mode 100644 index 00000000..c78ab080 --- /dev/null +++ b/src/internal_value.h @@ -0,0 +1,245 @@ +#ifndef INTERNAL_VALUE_H +#define INTERNAL_VALUE_H + +#include +#include +#include + +namespace jinja2 +{ + +template +class ReferenceWrapper +{ +public: + using type = T; + + ReferenceWrapper(T& ref) noexcept + : m_ptr(std::addressof(ref)) + { + } + + ReferenceWrapper(T&&) = delete; + ReferenceWrapper(const ReferenceWrapper&) noexcept = default; + + // assignment + ReferenceWrapper& operator=(const ReferenceWrapper& x) noexcept = default; + + // access + T& get() const noexcept + { + return *m_ptr; + } + +private: + T* m_ptr; +}; + +using ValueRef = ReferenceWrapper; +using TargetString = boost::variant; + +class ListAdapter; +class MapAdapter; + +using InternalValue = boost::variant; +using InternalValueRef = ReferenceWrapper; +using InternalValueMap = std::unordered_map; +using InternalValueList = std::vector; + +struct IListAccessor +{ + virtual ~IListAccessor() {} + + virtual size_t GetSize() const = 0; + virtual InternalValue GetValueByIndex(int64_t idx) const = 0; +}; + +using ListAccessorProvider = std::function; + +struct IMapAccessor : public IListAccessor +{ + virtual bool HasValue(const std::string& name) const = 0; + virtual InternalValue GetValueByName(const std::string& name) const = 0; + virtual std::vector GetKeys() const = 0; +}; + +using MapAccessorProvider = std::function; + +class ListAdapter +{ +public: + ListAdapter() {} + explicit ListAdapter(ListAccessorProvider prov) : m_accessorProvider(std::move(prov)) {} + + static ListAdapter CreateAdapter(InternalValueList&& values); + static ListAdapter CreateAdapter(const GenericList& values); + static ListAdapter CreateAdapter(const ValuesList& values); + static ListAdapter CreateAdapter(GenericList&& values); + static ListAdapter CreateAdapter(ValuesList&& values); + + size_t GetSize() const + { + if (m_accessorProvider && m_accessorProvider()) + { + return m_accessorProvider()->GetSize(); + } + + return 0; + } + InternalValue GetValueByIndex(int64_t idx) const; + + ListAdapter ToSubscriptedList(const InternalValue& subscript, bool asRef = false) const; + InternalValueList ToValueList() const; + + class Iterator; + + Iterator begin() const; + Iterator end() const; + +private: + ListAccessorProvider m_accessorProvider; +}; + +class MapAdapter +{ +public: + MapAdapter() {} + explicit MapAdapter(MapAccessorProvider prov) : m_accessorProvider(std::move(prov)) {} + + static MapAdapter CreateAdapter(InternalValueMap&& values); + static MapAdapter CreateAdapter(const InternalValueMap* values); + static MapAdapter CreateAdapter(const GenericMap& values); + static MapAdapter CreateAdapter(GenericMap&& values); + static MapAdapter CreateAdapter(const ValuesMap& values); + static MapAdapter CreateAdapter(ValuesMap&& values); + + size_t GetSize() const + { + if (m_accessorProvider && m_accessorProvider()) + { + return m_accessorProvider()->GetSize(); + } + + return 0; + } + InternalValue GetValueByIndex(int64_t idx) const; + bool HasValue(const std::string& name) const + { + if (m_accessorProvider && m_accessorProvider()) + { + return m_accessorProvider()->HasValue(name); + } + + return false; + } + InternalValue GetValueByName(const std::string& name) const; + std::vector GetKeys() const + { + if (m_accessorProvider && m_accessorProvider()) + { + return m_accessorProvider()->GetKeys(); + } + + return std::vector(); + } + +private: + MapAccessorProvider m_accessorProvider; +}; + +class ListAdapter::Iterator + : public boost::iterator_facade< + Iterator, + const InternalValue, + boost::single_pass_traversal_tag> +{ +public: + Iterator() + : m_current(0) + , m_list(nullptr) + {} + + explicit Iterator(const ListAdapter& list) + : m_current(0) + , m_list(&list) + , m_currentVal(list.GetSize() == 0 ? InternalValue() : list.GetValueByIndex(0)) + {} + +private: + friend class boost::iterator_core_access; + + void increment() + { + ++ m_current; + m_currentVal = m_current == m_list->GetSize() ? InternalValue() : m_list->GetValueByIndex(m_current); + } + + bool equal(const Iterator& other) const + { + if (m_list == nullptr) + return other.m_list == nullptr ? true : other.equal(*this); + + if (other.m_list == nullptr) + return m_current == m_list->GetSize(); + + return this->m_list == other.m_list && this->m_current == other.m_current; + } + + const InternalValue& dereference() const + { + return m_currentVal; + } + + int64_t m_current = 0; + const ListAdapter* m_list; + mutable InternalValue m_currentVal; +}; + +inline InternalValue ListAdapter::GetValueByIndex(int64_t idx) const +{ + if (m_accessorProvider && m_accessorProvider()) + { + return m_accessorProvider()->GetValueByIndex(idx); + } + + return InternalValue(); +} + +inline InternalValue MapAdapter::GetValueByIndex(int64_t idx) const +{ + if (m_accessorProvider && m_accessorProvider()) + { + return m_accessorProvider()->GetValueByIndex(idx); + } + + return InternalValue(); +} + +inline InternalValue MapAdapter::GetValueByName(const std::string& name) const +{ + if (m_accessorProvider && m_accessorProvider()) + { + return m_accessorProvider()->GetValueByName(name); + } + + return InternalValue(); +} + +inline ListAdapter::Iterator ListAdapter::begin() const {return Iterator(*this);} +inline ListAdapter::Iterator ListAdapter::end() const {return Iterator();} + + +inline bool IsEmpty(const InternalValue& val) +{ + return boost::get(&val) != nullptr; +} + +InternalValue Subscript(const InternalValue& val, const InternalValue& subscript); +InternalValue Subscript(const InternalValue& val, const std::string& subscript); +std::string AsString(const InternalValue& val); +ListAdapter ConvertToList(const InternalValue& val, bool& isConverted); +ListAdapter ConvertToList(const InternalValue& val, InternalValue subscipt, bool& isConverted); + +} // jinja2 + +#endif // INTERNAL_VALUE_H diff --git a/src/lexer.h b/src/lexer.h index 635d8ac9..ba1ea9d4 100644 --- a/src/lexer.h +++ b/src/lexer.h @@ -2,7 +2,7 @@ #define LEXER_H #include "lexertk.h" -#include "jinja2cpp/value.h" +#include "internal_value.h" #include @@ -85,7 +85,7 @@ struct Token Type type; CharRange range; - Value value; + InternalValue value; bool IsEof() const { @@ -112,7 +112,7 @@ struct Token struct LexerHelper { virtual std::string GetAsString(const CharRange& range) = 0; - virtual Value GetAsValue(const CharRange& range, Token::Type type) = 0; + virtual InternalValue GetAsValue(const CharRange& range, Token::Type type) = 0; virtual Token::Type GetKeyword(const CharRange& range) = 0; virtual char GetCharAt(size_t pos) = 0; }; diff --git a/src/out_stream.h b/src/out_stream.h index 6f2ebac9..33dd6e02 100644 --- a/src/out_stream.h +++ b/src/out_stream.h @@ -1,7 +1,7 @@ #ifndef OUT_STREAM_H #define OUT_STREAM_H -#include "jinja2cpp/value.h" +#include "internal_value.h" #include namespace jinja2 @@ -9,7 +9,7 @@ namespace jinja2 class OutStream { public: - OutStream(std::function chunkWriter, std::function valueWriter) + OutStream(std::function chunkWriter, std::function valueWriter) : m_chunkWriter(std::move(chunkWriter)) , m_valueWriter(valueWriter) { @@ -20,14 +20,14 @@ class OutStream m_chunkWriter(from, length); } - void WriteValue(const Value& val) + void WriteValue(const InternalValue& val) { m_valueWriter(val); } private: std::function m_chunkWriter; - std::function m_valueWriter; + std::function m_valueWriter; }; } // jinja2 diff --git a/src/render_context.h b/src/render_context.h index b0ad3acd..73540c13 100644 --- a/src/render_context.h +++ b/src/render_context.h @@ -1,7 +1,7 @@ #ifndef RENDER_CONTEXT_H #define RENDER_CONTEXT_H -#include "jinja2cpp/value.h" +#include "internal_value.h" #include @@ -10,15 +10,15 @@ namespace jinja2 class RenderContext { public: - RenderContext(const ValuesMap& extValues) + RenderContext(const InternalValueMap& extValues) { m_externalScope = &extValues; EnterScope(); } - ValuesMap& EnterScope() + InternalValueMap& EnterScope() { - m_scopes.push_back(ValuesMap()); + m_scopes.push_back(InternalValueMap()); m_currentScope = &m_scopes.back(); return *m_currentScope; } @@ -64,9 +64,9 @@ class RenderContext return *m_currentScope; } private: - ValuesMap* m_currentScope; - const ValuesMap* m_externalScope; - std::list m_scopes; + InternalValueMap* m_currentScope; + const InternalValueMap* m_externalScope; + std::list m_scopes; }; } // jinja2 diff --git a/src/statements.cpp b/src/statements.cpp index acd613ef..b8bf68d0 100644 --- a/src/statements.cpp +++ b/src/statements.cpp @@ -4,75 +4,42 @@ namespace jinja2 { -struct ValuesListAdaptorCreator : public boost::static_visitor> -{ - struct Adaptor : public ListItemAccessor - { - Adaptor(const ValuesList* list) - : m_list(list) - { - } - - size_t GetSize() const override {return m_list->size();} - Value GetValueByIndex(int64_t idx) const override {return (*m_list)[static_cast(idx)];}; - - const ValuesList* m_list; - }; - - - std::function operator() (const ValuesList& values) const - { - return [adaptor = Adaptor(&values)]() {return &adaptor;}; - } - - std::function operator() (const GenericList& values) const - { - return [&values]() {return values.GetAccessor();}; - } - - template - std::function operator() (U&&) const - { - return []() {return nullptr;}; - } - -}; - void ForStatement::Render(OutStream& os, RenderContext& values) { - Value loopVal = m_value->Evaluate(values); + InternalValue loopVal = m_value->Evaluate(values); auto& context = values.EnterScope(); - context["loop"] = ValuesMap(); - auto& loopVar = context["loop"].asMap(); + InternalValueMap loopVar; + context["loop"] = MapAdapter::CreateAdapter(&loopVar); - auto loopItems = boost::apply_visitor(ValuesListAdaptorCreator(), loopVal.data()); - if (!loopItems()) + bool isConverted = false; + auto loopItems = ConvertToList(loopVal, InternalValue(), isConverted); + if (!isConverted) return; - int64_t itemsNum = static_cast(loopItems()->GetSize()); - loopVar["length"] = Value(itemsNum); + int64_t itemsNum = static_cast(loopItems.GetSize()); + loopVar["length"] = InternalValue(itemsNum); bool loopRendered = false; for (int64_t itemIdx = 0; itemIdx != itemsNum; ++ itemIdx) { loopRendered = true; - loopVar["index"] = Value(itemIdx + 1); - loopVar["index0"] = Value(itemIdx); - loopVar["first"] = Value(itemIdx == 0); - loopVar["last"] = Value(itemIdx == itemsNum - 1); + loopVar["index"] = InternalValue(itemIdx + 1); + loopVar["index0"] = InternalValue(itemIdx); + loopVar["first"] = InternalValue(itemIdx == 0); + loopVar["last"] = InternalValue(itemIdx == itemsNum - 1); if (itemIdx != 0) - loopVar["previtem"] = loopItems()->GetValueByIndex(static_cast(itemIdx - 1)); + loopVar["previtem"] = loopItems.GetValueByIndex(static_cast(itemIdx - 1)); if (itemIdx != itemsNum - 1) - loopVar["nextitem"] = loopItems()->GetValueByIndex(static_cast(itemIdx + 1)); + loopVar["nextitem"] = loopItems.GetValueByIndex(static_cast(itemIdx + 1)); else loopVar.erase("nextitem"); - const auto& curValue = loopItems()->GetValueByIndex(static_cast(itemIdx)); - if (m_vars.size() > 1 && curValue.isMap()) + const auto& curValue = loopItems.GetValueByIndex(static_cast(itemIdx)); + if (m_vars.size() > 1) { for (auto& varName : m_vars) - context[varName] = curValue.subscript(varName); + context[varName] = Subscript(curValue, varName); } else context[m_vars[0]] = curValue; @@ -88,8 +55,8 @@ void ForStatement::Render(OutStream& os, RenderContext& values) void IfStatement::Render(OutStream& os, RenderContext& values) { - Value val = m_expr->Evaluate(values); - bool isTrue = boost::apply_visitor(visitors::BooleanEvaluator(), val.data()); + InternalValue val = m_expr->Evaluate(values); + bool isTrue = Apply(val); if (isTrue) { @@ -112,7 +79,7 @@ bool ElseBranchStatement::ShouldRender(RenderContext& values) const if (!m_expr) return true; - return boost::apply_visitor(visitors::BooleanEvaluator(), m_expr->Evaluate(values).data()); + return Apply(m_expr->Evaluate(values)); } void ElseBranchStatement::Render(OutStream& os, RenderContext& values) @@ -124,13 +91,13 @@ void SetStatement::Render(OutStream&, RenderContext& values) { if (m_expr) { - Value val = m_expr->Evaluate(values); + InternalValue val = m_expr->Evaluate(values); if (m_fields.size() == 1) values.GetCurrentScope()[m_fields[0]] = val; else { for (auto& name : m_fields) - values.GetCurrentScope()[name] = val.subscript(name); + values.GetCurrentScope()[name] = Subscript(val, name); } } } diff --git a/src/template.cpp b/src/template.cpp index df58fedc..c6bae05c 100644 --- a/src/template.cpp +++ b/src/template.cpp @@ -69,7 +69,7 @@ void Template::Render(std::ostream& os, const jinja2::ValuesMap& params) std::string Template::RenderAsString(const jinja2::ValuesMap& params) { std::ostringstream os; - GetImpl(m_impl)->Render(os, params); + Render(os, params); return os.str(); } diff --git a/src/template_impl.h b/src/template_impl.h index 75987fd3..59c0843e 100644 --- a/src/template_impl.h +++ b/src/template_impl.h @@ -1,12 +1,16 @@ #ifndef TEMPLATE_IMPL_H #define TEMPLATE_IMPL_H -#include #include "jinja2cpp/value.h" +#include "internal_value.h" #include "renderer.h" #include "template_parser.h" #include "value_visitors.h" +#include +#include + + namespace jinja2 { @@ -41,13 +45,23 @@ class TemplateImpl : public ITemplateImpl { if (m_renderer) { - RenderContext context(params); + InternalValueMap intParams; + for (auto& ip : params) + { + auto valRef = &ip.second.data(); + auto newParam = boost::apply_visitor(visitors::InputValueConvertor(), *valRef); + if (!newParam) + intParams[ip.first] = std::move(ValueRef(static_cast(*valRef))); + else + intParams[ip.first] = newParam.get(); + } + RenderContext context(intParams); OutStream outStream( [this, &os](size_t offset, size_t length) { os.write(m_template.data() + offset, length); }, - [this, &os](const Value& val) { - boost::apply_visitor(visitors::ValueRenderer(os), val.data()); + [this, &os](const InternalValue& val) { + Apply>(val, os); } ); m_renderer->Render(outStream, context); @@ -55,6 +69,7 @@ class TemplateImpl : public ITemplateImpl } private: + std::basic_string m_template; RendererPtr m_renderer; }; diff --git a/src/template_parser.cpp b/src/template_parser.cpp index 6d53527e..ab84d71b 100644 --- a/src/template_parser.cpp +++ b/src/template_parser.cpp @@ -61,7 +61,7 @@ bool StatementsParser::ParseFor(LexScanner& lexer, StatementInfoList& statements while (lexer.PeekNextToken() == Token::Identifier) { auto tok = lexer.NextToken(); - vars.push_back(tok.value.asString()); + vars.push_back(AsString(tok.value)); if (lexer.NextToken() != ',') { lexer.ReturnToken(); @@ -185,7 +185,7 @@ bool StatementsParser::ParseSet(LexScanner& lexer, StatementInfoList& statements while (lexer.PeekNextToken() == Token::Identifier) { auto tok = lexer.NextToken(); - vars.push_back(tok.value.asString()); + vars.push_back(AsString(tok.value)); if (lexer.NextToken() != ',') { lexer.ReturnToken(); diff --git a/src/template_parser.h b/src/template_parser.h index 516ceb1e..a477a075 100644 --- a/src/template_parser.h +++ b/src/template_parser.h @@ -57,15 +57,15 @@ struct ParserTraits { return str.substr(range.startOffset, range.size()); } - static Value RangeToNum(const std::string& str, CharRange range, Token::Type hint) + static InternalValue RangeToNum(const std::string& str, CharRange range, Token::Type hint) { char buff[std::max(std::numeric_limits::max_digits10, std::numeric_limits::max_digits10) * 2 + 1]; std::copy(str.data() + range.startOffset, str.data() + range.endOffset, buff); buff[range.size()] = 0; - Value result; + InternalValue result; if (hint == Token::IntegerNum) { - result = Value(static_cast(strtoll(buff, nullptr, 0))); + result = InternalValue(static_cast(strtoll(buff, nullptr, 0))); } else { @@ -124,9 +124,9 @@ struct ParserTraits #endif return result; } - static Value RangeToNum(const std::wstring& /*str*/, CharRange /*range*/, Token::Type /*hint*/) + static InternalValue RangeToNum(const std::wstring& /*str*/, CharRange /*range*/, Token::Type /*hint*/) { - return Value(); + return InternalValue(); } static Token::Type s_keywords[]; }; @@ -473,13 +473,13 @@ class TemplateParser : public LexerHelper { return traits_t::GetAsString(*m_template, range); } - Value GetAsValue(const CharRange& range, Token::Type type) override + InternalValue GetAsValue(const CharRange& range, Token::Type type) override { if (type == Token::String) - return Value(m_template->substr(range.startOffset, range.size())); + return InternalValue(m_template->substr(range.startOffset, range.size())); else if (type == Token::IntegerNum || type == Token::FloatNum) return traits_t::RangeToNum(*m_template, range, type); - return Value(); + return InternalValue(); } Token::Type GetKeyword(const CharRange& range) override { diff --git a/src/testers.cpp b/src/testers.cpp index d118fa28..88fedae0 100644 --- a/src/testers.cpp +++ b/src/testers.cpp @@ -6,9 +6,9 @@ namespace jinja2 namespace testers { -bool Defined::Test(const Value& baseVal, RenderContext& /*context*/) +bool Defined::Test(const InternalValue& baseVal, RenderContext& /*context*/) { - return boost::get(&baseVal.data()) == nullptr; + return boost::get(&baseVal) == nullptr; } StartsWith::StartsWith(TesterParams params) @@ -18,11 +18,11 @@ StartsWith::StartsWith(TesterParams params) m_stringEval = args["str"]; } -bool StartsWith::Test(const Value& baseVal, RenderContext& context) +bool StartsWith::Test(const InternalValue& baseVal, RenderContext& context) { - Value val = m_stringEval->Evaluate(context); - std::string baseStr = baseVal.asString(); - std::string str = val.asString(); + InternalValue val = m_stringEval->Evaluate(context); + std::string baseStr = AsString(baseVal); + std::string str = AsString(val); return baseStr.find(str) == 0; } diff --git a/src/testers.h b/src/testers.h index 8121691d..7ffc569b 100644 --- a/src/testers.h +++ b/src/testers.h @@ -29,7 +29,7 @@ class Defined : public IsExpression::ITester public: Defined(TesterParams) {} - bool Test(const Value& baseVal, RenderContext& context) override; + bool Test(const InternalValue& baseVal, RenderContext& context) override; }; class StartsWith : public IsExpression::ITester @@ -37,7 +37,7 @@ class StartsWith : public IsExpression::ITester public: StartsWith(TesterParams); - bool Test(const Value& baseVal, RenderContext& context) override; + bool Test(const InternalValue& baseVal, RenderContext& context) override; private: ExpressionEvaluatorPtr<> m_stringEval; diff --git a/src/value.cpp b/src/value.cpp index df14918b..3139b29a 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -1,3 +1,4 @@ +#if 0 #include "jinja2cpp/value.h" #include @@ -81,61 +82,62 @@ struct ValueRenderer : boost::static_visitor } }; -struct SubscriptionVisitor : public boost::static_visitor +struct SubscriptionVisitor : public boost::static_visitor { - Value operator() (const ValuesMap& values, const std::string& field) const + InternalValue operator() (const ValuesMap& values, const std::string& field) const { auto p = values.find(field); if (p == values.end()) - return Value(); + return InternalValue(); return p->second; } - Value operator() (const GenericMap& values, const std::string& field) const + InternalValue operator() (const GenericMap& values, const std::string& field) const { if (!values.HasValue(field)) - return Value(); + return InternalValue(); return values.GetValueByName(field); } - Value operator() (const GenericMap& values, const int64_t index) const + InternalValue operator() (const GenericMap& values, const int64_t index) const { if (index < 0 || static_cast(index) >= values.GetSize()) - return Value(); + return InternalValue(); return values.GetValueByIndex(index); } - Value operator() (const ValuesList& values, int64_t index) const + InternalValue operator() (const ValuesList& values, int64_t index) const { if (index < 0 || static_cast(index) >= values.size()) - return Value(); + return InternalValue(); return values[static_cast(index)]; } - Value operator() (const GenericList& values, const int64_t index) const + InternalValue operator() (const GenericList& values, const int64_t index) const { if (index < 0 || static_cast(index) >= values.GetSize()) - return Value(); + return InternalValue(); return values.GetValueByIndex(index); } template - Value operator() (T&& /*first*/, U&& /*second*/) const + InternalValue operator() (T&& /*first*/, U&& /*second*/) const { - return Value(); + return InternalValue(); } }; } // -Value Value::subscript(const Value& index) const +InternalValue InternalValue::subscript(const InternalValue& index) const { return boost::apply_visitor(SubscriptionVisitor(), m_data, index.m_data); } } // jinja2 +#endif diff --git a/src/value_helpers.h b/src/value_helpers.h new file mode 100644 index 00000000..0b50216b --- /dev/null +++ b/src/value_helpers.h @@ -0,0 +1,167 @@ +#ifndef VALUE_HELPERS_H +#define VALUE_HELPERS_H + +#include + +#include + +namespace jinja2 +{ +#if 0 +class GenericListIterator + : public boost::iterator_facade< + GenericListIterator, + const InternalValue, + boost::random_access_traversal_tag> +{ +public: + GenericListIterator() + : m_current(0) + , m_list(nullptr) + {} + + explicit GenericListIterator(GenericList& list) + : m_current(0) + , m_list(&list) + {} + +private: + friend class boost::iterator_core_access; + + void increment() + { + ++ m_current; + m_valueIdx = m_current; + m_currentVal = m_current == m_list->GetSize() ? InternalValue() : m_list->GetValueByIndex(static_cast(m_current)); + } + + int distance_to(const GenericListIterator& other) const + { + if (m_list == nullptr) + return other.m_list == nullptr ? 0 : -other.distance_to(*this); + + if (other.m_list == nullptr) + return m_list->GetSize() - m_current; + + return other.m_current - m_current; + } + + void advance(int distance) + { + m_current += distance; + if (distance != 0) + { + m_valueIdx = m_current; + m_currentVal = m_current == m_list->GetSize() ? InternalValue() : m_list->GetValueByIndex(static_cast(m_current)); + + } + } + + bool equal(const GenericListIterator& other) const + { + if (m_list == nullptr) + return other.m_list == nullptr ? true : other.equal(*this); + + if (other.m_list == nullptr) + return m_current == m_list->GetSize(); + + return this->m_list == other.m_list && this->m_current == other.m_current; + } + + const InternalValue& dereference() const + { + if (m_current != m_valueIdx) + m_currentVal = m_current == m_list->GetSize() ? InternalValue() : m_list->GetValueByIndex(static_cast(m_current)); + return m_currentVal; + } + + int64_t m_current = 0; + mutable int64_t m_valueIdx = -1; + mutable InternalValue m_currentVal; + GenericList* m_list; +}; + +class ConstGenericListIterator + : public boost::iterator_facade< + GenericListIterator, + const InternalValue, + boost::random_access_traversal_tag> +{ +public: + ConstGenericListIterator() + : m_current(0) + , m_list(nullptr) + {} + + explicit ConstGenericListIterator(const GenericList& list) + : m_current(0) + , m_list(&list) + {} + +private: + friend class boost::iterator_core_access; + + void increment() + { + ++ m_current; + } + + int distance_to(const ConstGenericListIterator& other) const + { + if (m_list == nullptr) + return other.m_list == nullptr ? 0 : -other.distance_to(*this); + + if (other.m_list == nullptr) + return m_list->GetSize() - m_current; + + return other.m_current - m_current; + } + + void advance(int distance) + { + m_current += distance; + } + + bool equal(const ConstGenericListIterator& other) const + { + if (m_list == nullptr) + return other.m_list == nullptr ? true : other.equal(*this); + + if (other.m_list == nullptr) + return m_current == m_list->GetSize(); + + return this->m_list == other.m_list && this->m_current == other.m_current; + } + + const InternalValue& dereference() const + { + return m_list->GetValueByIndex(static_cast(m_current)); + } + + size_t m_current; + const GenericList* m_list; +}; + +inline auto begin(GenericList& list) +{ + return GenericListIterator(list); +} + +inline auto end(GenericList& list) +{ + return GenericListIterator(); +} + +inline auto begin(const GenericList& list) +{ + return ConstGenericListIterator(list); +} + +inline auto end(const GenericList& list) +{ + return ConstGenericListIterator(); +} +#endif +} // jinja2 + +#endif // VALUE_HELPERS_H diff --git a/src/value_visitors.h b/src/value_visitors.h index 9b523171..a6f9426e 100644 --- a/src/value_visitors.h +++ b/src/value_visitors.h @@ -5,6 +5,7 @@ #include "jinja2cpp/value.h" #include +#include #include #include @@ -14,14 +15,102 @@ namespace jinja2 { namespace visitors { -template +template struct BaseVisitor : public boost::static_visitor { + R operator() (const GenericMap&) const + { + assert(false); + return R(); + } + + R operator() (const GenericList&) const + { + assert(false); + return R(); + } + + R operator() (const ValueRef&) const + { + assert(false); + return R(); + } + + R operator() (const TargetString&) const + { + assert(false); + return R(); + } + + template + R operator() (T&&) const + { + return R(); + } + template - Value operator() (T&&, U&&) const + R operator() (T&&, U&&) const + { + return R(); + } +#if 0 + template + R operator() (const GenericMap&, U&&) const + { + assert(false); + return R(); + } + + template + R operator() (const GenericList&, U&&) const + { + assert(false); + return R(); + } + + template + R operator() (const ValueRef&, U&&) const { - return Value(); + assert(false); + return R(); } + + template + R operator() (const TargetString&, U&&) const + { + assert(false); + return R(); + } + + template + R operator() (T&&, const GenericMap&) const + { + assert(false); + return R(); + } + + template + R operator() (T&&, const GenericList&) const + { + assert(false); + return R(); + } + + template + R operator() (T&&, const ValueRef&) const + { + assert(false); + return R(); + } + + template + R operator() (T&&, const TargetString&) const + { + assert(false); + return R(); + } +#endif + }; @@ -44,10 +133,105 @@ struct ValueRendererBase : public boost::static_visitor<> void operator()(const ValuesMap&) const {} void operator()(const GenericMap&) const {} void operator()(const GenericList&) const {} + void operator()(const MapAdapter&) const {} + void operator()(const ListAdapter&) const {} + void operator()(const ValueRef&) const {} + void operator()(const TargetString&) const {} std::basic_ostream* m_os; }; +struct InputValueConvertor : public boost::static_visitor> +{ + using result_t = boost::optional; + + InputValueConvertor(bool byValue = false) + : m_byValue(byValue) + { + } + + template + result_t operator() (const std::basic_string& val) const + { + // if (m_byValue) + return result_t(InternalValue(TargetString(val))); + + // return result_t(); + } + + result_t operator() (const ValuesList& vals) const + { + if (m_byValue) + { + ValuesList newVals(vals); + return result_t(InternalValue(ListAdapter::CreateAdapter(std::move(newVals)))); + } + + return result_t(InternalValue(ListAdapter::CreateAdapter(vals))); + } + + result_t operator() (ValuesList& vals) const + { + return result_t(InternalValue(ListAdapter::CreateAdapter(std::move(vals)))); + } + + result_t operator() (const GenericList& vals) const + { + if (m_byValue) + { + GenericList newVals(vals); + return result_t(InternalValue(ListAdapter::CreateAdapter(std::move(newVals)))); + } + + return result_t(InternalValue(ListAdapter::CreateAdapter(vals))); + } + + result_t operator() (GenericList& vals) const + { + return result_t(InternalValue(ListAdapter::CreateAdapter(std::move(vals)))); + } + + result_t operator() (const ValuesMap& vals) const + { + if (m_byValue) + { + ValuesMap newVals(vals); + return result_t(InternalValue(MapAdapter::CreateAdapter(std::move(newVals)))); + } + + return result_t(InternalValue(MapAdapter::CreateAdapter(vals))); + } + + result_t operator() (ValuesMap& vals) const + { + return result_t(InternalValue(MapAdapter::CreateAdapter(std::move(vals)))); + } + + result_t operator() (const GenericMap& vals) const + { + if (m_byValue) + { + GenericMap newVals(vals); + return result_t(InternalValue(MapAdapter::CreateAdapter(std::move(newVals)))); + } + + return result_t(InternalValue(MapAdapter::CreateAdapter(vals))); + } + + result_t operator() (GenericMap& vals) const + { + return result_t(InternalValue(MapAdapter::CreateAdapter(std::move(vals)))); + } + + template + result_t operator() (T&& val) const + { + return result_t(InternalValue(std::forward(val))); + } + + bool m_byValue; +}; + template struct ValueRenderer; @@ -85,16 +269,18 @@ struct ValueRenderer : ValueRendererBase } }; -struct UnaryOperation : boost::static_visitor +struct UnaryOperation : BaseVisitor { + using BaseVisitor::operator (); + UnaryOperation(UnaryExpression::Operation oper) : m_oper(oper) { } - Value operator() (int64_t val) const + InternalValue operator() (int64_t val) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::UnaryExpression::LogicalNot: @@ -111,9 +297,9 @@ struct UnaryOperation : boost::static_visitor return result; } - Value operator() (double val) const + InternalValue operator() (double val) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::UnaryExpression::LogicalNot: @@ -130,9 +316,9 @@ struct UnaryOperation : boost::static_visitor return result; } - Value operator() (bool val) const + InternalValue operator() (bool val) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::UnaryExpression::LogicalNot: @@ -145,9 +331,9 @@ struct UnaryOperation : boost::static_visitor return result; } - Value operator() (const GenericMap&) const + InternalValue operator() (const MapAdapter&) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::UnaryExpression::LogicalNot: @@ -160,9 +346,9 @@ struct UnaryOperation : boost::static_visitor return result; } - Value operator() (const GenericList&) const + InternalValue operator() (const ListAdapter&) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::UnaryExpression::LogicalNot: @@ -175,13 +361,14 @@ struct UnaryOperation : boost::static_visitor return result; } - Value operator() (const EmptyValue&) const + template + InternalValue operator() (const std::basic_string& val) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::UnaryExpression::LogicalNot: - result = true; + result = val.empty(); break; default: break; @@ -190,14 +377,13 @@ struct UnaryOperation : boost::static_visitor return result; } - template - Value operator() (const T& val) const + InternalValue operator() (const EmptyValue&) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::UnaryExpression::LogicalNot: - result = val.empty(); + result = true; break; default: break; @@ -212,6 +398,7 @@ struct UnaryOperation : boost::static_visitor struct BinaryMathOperation : BaseVisitor<> { using BaseVisitor::operator (); + // InternalValue operator() (int, int) const {return InternalValue();} bool AlmostEqual(double x, double y) const { @@ -225,9 +412,9 @@ struct BinaryMathOperation : BaseVisitor<> { } - Value operator() (double left, double right) const + InternalValue operator() (double left, double right) const { - Value result = 0; + InternalValue result = 0.0; switch (m_oper) { case jinja2::BinaryExpression::Plus: @@ -279,9 +466,9 @@ struct BinaryMathOperation : BaseVisitor<> return result; } - Value operator() (int64_t left, int64_t right) const + InternalValue operator() (int64_t left, int64_t right) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::BinaryExpression::Plus: @@ -326,20 +513,20 @@ struct BinaryMathOperation : BaseVisitor<> return result; } - Value operator() (double left, int64_t right) const + InternalValue operator() (double left, int64_t right) const { return this->operator ()(static_cast(left), static_cast(right)); } - Value operator() (int64_t left, double right) const + InternalValue operator() (int64_t left, double right) const { return this->operator ()(static_cast(left), static_cast(right)); } template - Value operator() (const std::basic_string& left, const std::basic_string& right) const + InternalValue operator() (const std::basic_string& left, const std::basic_string& right) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::BinaryExpression::Plus: @@ -384,9 +571,9 @@ struct BinaryMathOperation : BaseVisitor<> return result; } - Value operator() (bool left, bool right) + InternalValue operator() (bool left, bool right) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::BinaryExpression::LogicalEq: @@ -402,9 +589,9 @@ struct BinaryMathOperation : BaseVisitor<> return result; } - Value operator() (EmptyValue, EmptyValue) const + InternalValue operator() (EmptyValue, EmptyValue) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::BinaryExpression::LogicalEq: @@ -421,9 +608,9 @@ struct BinaryMathOperation : BaseVisitor<> } template - Value operator() (EmptyValue, T&&) const + InternalValue operator() (EmptyValue, T&&) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::BinaryExpression::LogicalEq: @@ -440,9 +627,9 @@ struct BinaryMathOperation : BaseVisitor<> } template - Value operator() (T&&, EmptyValue) const + InternalValue operator() (T&&, EmptyValue) const { - Value result; + InternalValue result; switch (m_oper) { case jinja2::BinaryExpression::LogicalEq: @@ -462,8 +649,10 @@ struct BinaryMathOperation : BaseVisitor<> BinaryExpression::CompareType m_compType; }; -struct BooleanEvaluator : boost::static_visitor +struct BooleanEvaluator : BaseVisitor { + using BaseVisitor::operator (); + bool operator() (int64_t val) const { return val != 0; @@ -479,25 +668,25 @@ struct BooleanEvaluator : boost::static_visitor return val; } - bool operator() (const GenericMap&) const + template + bool operator()(const std::basic_string& str) const { - return true; + return !str.empty(); } - bool operator() (const GenericList&) const + bool operator() (const MapAdapter& val) const { - return true; + return val.GetSize() != 0; } - bool operator() (const EmptyValue&) const + bool operator() (const ListAdapter& val) const { - return false; + return val.GetSize() != 0; } - template - bool operator() (const T& val) const + bool operator() (const EmptyValue&) const { - return !val.empty(); + return false; } }; @@ -522,20 +711,20 @@ struct IntegerEvaluator : public boost::static_visitor } }; - -struct ListEvaluator : boost::static_visitor +#if 0 +struct ValueListEvaluator : boost::static_visitor { - ListEvaluator(Value attr = Value()) + ValueListEvaluator(InternalValue attr = InternalValue()) : m_attr(std::move(attr)) {} ValuesList operator() (const ValuesList& values) const { - if (m_attr.isEmpty()) + if (IsEmpty(m_attr)) return values; ValuesList result; - std::transform(values.begin(), values.end(), std::back_inserter(result), [this](const Value& val) {return val.subscript(m_attr);}); + std::transform(values.begin(), values.end(), std::back_inserter(result), [this](const InternalValue& val) {return Subscript(val, m_attr);}); return result; } @@ -547,8 +736,8 @@ struct ListEvaluator : boost::static_visitor for (int64_t idx = 0; idx < size; ++ idx) { auto val = values.GetValueByIndex(idx); - if (!m_attr.isEmpty()) - result.push_back(val.subscript(m_attr)); + if (!IsEmpty(m_attr)) + result.push_back(Subscript(val, m_attr)); else result.push_back(val); } @@ -562,19 +751,81 @@ struct ListEvaluator : boost::static_visitor return ValuesList(); } - Value m_attr; + InternalValue m_attr; +}; + + +struct GenericListEvaluator : public boost::static_visitor +{ + struct ValueListAdaptor : public ListItemAccessor + { + ValueListAdaptor(const ValuesList* list) + : m_list(list) + { + } + + size_t GetSize() const override {return m_list->size();} + InternalValue GetValueByIndex(int64_t idx) const override {return (*m_list)[static_cast(idx)];}; + + const ValuesList* m_list; + }; + + template + struct StringAdaptor : public ListItemAccessor + { + using string = std::basic_string; + StringAdaptor(const string* str) + : m_str(str) + { + } + + size_t GetSize() const override {return m_str->size();} + InternalValue GetValueByIndex(int64_t idx) const override {return m_str->substr(static_cast(idx), 1);}; + + const string* m_str; + }; + + GenericListEvaluator(bool unrollStrings) + : m_unrollStrings(unrollStrings) + { + } + + GenericList operator() (const ValuesList& values) const + { + return GenericList([adaptor = ValueListAdaptor(&values)]() {return &adaptor;}); + } + + GenericList operator() (const GenericList& values) const + { + return values; + } + + template + GenericList operator() (const std::basic_string& str) const + { + return GenericList([adaptor = StringAdaptor(&str)]() {return &adaptor;}); + } + + template + GenericList operator() (U&&) const + { + return GenericList(); + } + + bool m_unrollStrings; }; +#endif struct StringJoiner : BaseVisitor<> { using BaseVisitor::operator (); - Value operator() (EmptyValue, const std::string& str) const + InternalValue operator() (EmptyValue, const std::string& str) const { return str; } - Value operator() (const std::string& left, const std::string& right) const + InternalValue operator() (const std::string& left, const std::string& right) const { return left + right; } @@ -582,18 +833,68 @@ struct StringJoiner : BaseVisitor<> } // visitors -template -auto Apply(ValType&& val, Args&& ... args) +namespace detail +{ + +template +auto ApplyUnwrapped(const InternalValue& val, Fn&& fn) +{ + auto valueRef = boost::get(&val); + auto targetString = boost::get(&val); + // auto internalValueRef = boost::get(&val); + + if (valueRef != nullptr) + return fn(valueRef->get().data()); + else if (targetString != nullptr) + return fn(*targetString); +// else if (internalValueRef != nullptr) +// return fn(internalValueRef->get()); + + return fn(val); +} +} // detail + +template +auto Apply(const InternalValue& val, Args&& ... args) { - return boost::apply_visitor(V(std::forward(args)...), std::forward(val).data()); + return detail::ApplyUnwrapped(val, [&args...](auto& val) { + return boost::apply_visitor(V(args...), val); + }); } -template -auto Apply(ValType&& val1, ValType&& val2, Args&& ... args) +template +auto Apply2(const InternalValue& val1, const InternalValue& val2, Args&& ... args) { - return boost::apply_visitor(V(std::forward(args)...), std::forward(val1).data(), std::forward(val2).data()); + return detail::ApplyUnwrapped(val1, [&val2, &args...](auto& uwVal1) { + return detail::ApplyUnwrapped(val2, [&uwVal1, &args...](auto& uwVal2) { + return boost::apply_visitor(V(args...), uwVal1, uwVal2); + }); + }); } +inline bool ConvertToBool(const InternalValue& val) +{ + return Apply(val); +} + +#if 0 +inline auto AsValueList(const InternalValue& val, InternalValue subAttr = InternalValue()) +{ + auto list = boost::get(&val); + if (!list) + return ListAdapter(); + + if (IsEmpty(subAttr)) + return *list; + + return list->ToSubscriptedList(subAttr); +} + +inline auto AsGenericList(const InternalValue& val, bool isStrict = false) +{ + return ListAdapter::CreateAdapter(val, isStrict); // Apply(val, unrollStrings); +} +#endif } // jinja2 #endif // VALUE_VISITORS_H diff --git a/test/filters_test.cpp b/test/filters_test.cpp index 778fe02c..caa7a6e1 100644 --- a/test/filters_test.cpp +++ b/test/filters_test.cpp @@ -56,5 +56,96 @@ INSTANTIATE_TEST_CASE_P(Sort, ListIteratorTest, ::testing::Values( InputOutputPair{"['Str2', 'str1', 'str3'] | sort(reverse=true)", "str3, Str2, str1"}, InputOutputPair{"['Str2', 'str1', 'str3'] | sort(case_sensitive=true)", "Str2, str1, str3"}, InputOutputPair{"['Str2', 'str1', 'str3'] | sort(case_sensitive=true, reverse=true)", "str3, str1, Str2"}, - InputOutputPair{"[3, 1, 2] | sort", "1, 2, 3"} + InputOutputPair{"[3, 1, 2] | sort", "1, 2, 3"}, + InputOutputPair{"reflectedIntVector | sort", "0, 1, 2, 3, 4, 5, 6, 7, 8, 9"} + )); + +INSTANTIATE_TEST_CASE_P(Default, FilterGenericTest, ::testing::Values( + InputOutputPair{"intValue | default(0)", "3"}, + InputOutputPair{"integerValue | default(0)", "0"}, + InputOutputPair{"integerValue | d(0)", "0"}, + InputOutputPair{"''|default('the string was empty', true)", "the string was empty"}, + InputOutputPair{"''|default(default_value='the string was empty', boolean=true)", "the string was empty"}, + InputOutputPair{"''|default('the string was empty', false)", ""}, + InputOutputPair{"'Hello World!'|default('the string was empty', true)", "Hello World!"} + )); + +INSTANTIATE_TEST_CASE_P(First, FilterGenericTest, ::testing::Values( + InputOutputPair{"[1, 2, 3, 4] | first", "1"}, + InputOutputPair{"(1, 2, 3, 4) | first", "1"}, + InputOutputPair{"intValue | first", ""}, + InputOutputPair{"intList | first", "9"}, + InputOutputPair{"stringValue | first", "r"}, + InputOutputPair{"reflectedIntVector | first", "9"} + )); + +INSTANTIATE_TEST_CASE_P(Last, FilterGenericTest, ::testing::Values( + InputOutputPair{"[1, 2, 3, 4] | last", "4"}, + InputOutputPair{"(1, 2, 3, 4) | last", "4"}, + InputOutputPair{"intValue | last", ""}, + InputOutputPair{"intList | last", "4"}, + InputOutputPair{"stringValue | last", "n"}, + InputOutputPair{"reflectedIntVector | last", "4"} + )); + +INSTANTIATE_TEST_CASE_P(Length, FilterGenericTest, ::testing::Values( + InputOutputPair{"[1, 2, 3, 4, 5] | length", "5"}, + InputOutputPair{"(1, 2, 3, 4, 5, 6) | length", "6"}, + InputOutputPair{"intValue | length", ""}, + InputOutputPair{"intList | length", "10"}, + InputOutputPair{"stringValue | length", "4"}, + InputOutputPair{"reflectedIntVector | length", "10"} + )); + +INSTANTIATE_TEST_CASE_P(Min, FilterGenericTest, ::testing::Values( + InputOutputPair{"[1, 2, 3, 4, 5] | min", "1"}, + InputOutputPair{"(1, 2, 3, 4, 5, 6) | min", "1"}, + InputOutputPair{"intValue | min", ""}, + InputOutputPair{"intList | min", "0"}, + InputOutputPair{"stringValue | min", "a"}, + InputOutputPair{"('str1', 'str2', 'str3', 'str4', 'str5', 'Str6') | min", "str1"}, + InputOutputPair{"('str1', 'str2', 'str3', 'str4', 'str5', 'Str6') | min(true)", "Str6"}, + InputOutputPair{"('str1', 'str2', 'str3', 'str4', 'str5', 'Str6') | min(case_sensitive=true)", "Str6"} + )); + +INSTANTIATE_TEST_CASE_P(Max, FilterGenericTest, ::testing::Values( + InputOutputPair{"[1, 2, 3, 4, 5] | max", "5"}, + InputOutputPair{"(1, 2, 3, 4, 5, 6) | max", "6"}, + InputOutputPair{"intValue | max", ""}, + InputOutputPair{"intList | max", "9"}, + InputOutputPair{"stringValue | max", "r"}, + InputOutputPair{"('str1', 'str2', 'str3', 'str4', 'str5', 'Str6') | max", "Str6"}, + InputOutputPair{"('str1', 'str2', 'str3', 'str4', 'str5', 'Str6') | max(true)", "str5"}, + InputOutputPair{"('str1', 'str2', 'str3', 'str4', 'str5', 'Str6') | max(case_sensitive=true)", "str5"} + )); + +INSTANTIATE_TEST_CASE_P(Reverse, ListIteratorTest, ::testing::Values( + InputOutputPair{"['str1', 'str2', 'str3'] | reverse", "str3, str2, str1"}, + InputOutputPair{"[3, 1, 2] | reverse", "2, 1, 3"}, + InputOutputPair{"reflectedIntVector | reverse", "4, 5, 3, 6, 2, 7, 1, 8, 0, 9"} + )); + +INSTANTIATE_TEST_CASE_P(Sum, FilterGenericTest, ::testing::Values( + InputOutputPair{"[1, 2, 3, 4, 5] | sum", "15"}, + InputOutputPair{"[] | sum(start=15)", "15"}, + InputOutputPair{"intValue | sum", ""}, + InputOutputPair{"intList | sum(start=10)", "55"}, + InputOutputPair{"stringValue | sum", "rain"}, + InputOutputPair{"('str1', 'str2', 'str3', 'str4', 'str5', 'Str6') | sum", + "str1str2str3str4str5Str6"}, + InputOutputPair{"('str1', 'str2', 'str3', 'str4', 'str5', 'Str6') | sum(start='Hello')", + "Hellostr1str2str3str4str5Str6"}, + InputOutputPair{"reflectedList | sum(attribute='strValue')", + "test string 0test string 1test string 2test string 3test string 4test string 5test string 6test string 7test string 8test string 9"} + )); + +INSTANTIATE_TEST_CASE_P(Unique, ListIteratorTest, ::testing::Values( + InputOutputPair{"['str1', 'str2', 'str3'] | unique", "str1, str2, str3"}, + InputOutputPair{"['str3', 'str1', 'str1'] | unique", "str3, str1"}, + InputOutputPair{"['Str2', 'str1', 'str3'] | unique", "Str2, str1, str3"}, + InputOutputPair{"['Str2', 'str2', 'str3'] | unique", "Str2, str3"}, + InputOutputPair{"['Str2', 'str1', 'str3'] | unique(case_sensitive=true)", "Str2, str1, str3"}, + InputOutputPair{"[3, 1, 2] | unique", "3, 1, 2"}, + InputOutputPair{"[3.0, 3, 1] | unique", "3, 1"} + // InputOutputPair{"reflectedList | unique(attribute='strValue')", "test string 0test string 1test string 2test string 3test string 4test string 5test string 6test string 7test string 8test string 9"} )); diff --git a/test/test_tools.h b/test/test_tools.h index 0b739f35..9d06b502 100644 --- a/test/test_tools.h +++ b/test/test_tools.h @@ -33,6 +33,7 @@ struct TestStruct inline jinja2::ValuesMap PrepareTestData() { jinja2::ValuesList testData; + TestStruct sampleStruct; for (int n = 0; n < 10; ++ n) { TestStruct s; @@ -48,9 +49,14 @@ inline jinja2::ValuesMap PrepareTestData() s.strValue = str.str(); s.wstrValue = wstr.str(); + if (testData.empty()) + sampleStruct = s; testData.push_back(jinja2::Reflect(std::move(s))); } + std::shared_ptr emptyTestStruct; + std::shared_ptr filledTestStruct = std::make_shared(sampleStruct); + return jinja2::ValuesMap { {"intValue", 3}, {"intList", jinja2::ValuesList{9, 0, 8, 1, 7, 2, 6, 3, 5, 4}}, @@ -67,6 +73,10 @@ inline jinja2::ValuesMap PrepareTestData() {"boolValue", true}, {"reflectedList", testData} }}, + {"reflectedVal", jinja2::Reflect(sampleStruct)}, + {"emptyReflectedPtrVal", jinja2::Reflect(emptyTestStruct)}, + {"filledReflectedPtrVal", jinja2::Reflect(filledTestStruct)}, + {"reflectedIntVector", jinja2::Reflect(std::vector{9, 0, 8, 1, 7, 2, 6, 3, 5, 4})}, {"reflectedList", std::move(testData)} }; }