|
3 | 3 | #include "testers.h" |
4 | 4 | #include "value_visitors.h" |
5 | 5 |
|
| 6 | +#include <boost/algorithm/string/join.hpp> |
| 7 | + |
6 | 8 | #include <cmath> |
7 | 9 |
|
8 | 10 | namespace jinja2 |
@@ -162,4 +164,150 @@ Value DictionaryCreator::Evaluate(RenderContext& context) |
162 | 164 | return result; |
163 | 165 | } |
164 | 166 |
|
| 167 | +Value CallExpression::Evaluate(RenderContext& values) |
| 168 | +{ |
| 169 | + std::string valueRef = boost::algorithm::join(m_valueRef, "."); |
| 170 | + |
| 171 | + if (valueRef == "range") |
| 172 | + return CallGlobalRange(values); |
| 173 | + else if (valueRef == "loop.cycle") |
| 174 | + return CallLoopCycle(values); |
| 175 | + |
| 176 | + return Value(); |
| 177 | +} |
| 178 | + |
| 179 | +Value CallExpression::CallGlobalRange(RenderContext& values) |
| 180 | +{ |
| 181 | + auto startExpr = ExpressionEvaluatorPtr<>(); |
| 182 | + auto stopExpr = ExpressionEvaluatorPtr<>(); |
| 183 | + auto stepExpr = ExpressionEvaluatorPtr<>(); |
| 184 | + |
| 185 | + helpers::FindParam(m_params, helpers::NoPosParam, "start", startExpr); |
| 186 | + helpers::FindParam(m_params, helpers::NoPosParam, "stop", stopExpr); |
| 187 | + helpers::FindParam(m_params, helpers::NoPosParam, "step", startExpr); |
| 188 | + |
| 189 | + switch (m_params.posParams.size()) |
| 190 | + { |
| 191 | + case 1: |
| 192 | + if (startExpr && stopExpr && stepExpr) |
| 193 | + break; |
| 194 | + else if (startExpr && stopExpr) |
| 195 | + stepExpr = m_params.posParams[0]; |
| 196 | + else if (startExpr && stepExpr) |
| 197 | + stopExpr = m_params.posParams[0]; |
| 198 | + else if (stopExpr && stepExpr) |
| 199 | + startExpr = m_params.posParams[0]; |
| 200 | + else if (startExpr) |
| 201 | + stopExpr = m_params.posParams[0]; |
| 202 | + else if (stopExpr) |
| 203 | + startExpr = m_params.posParams[0]; |
| 204 | + else if (stepExpr) |
| 205 | + stopExpr = m_params.posParams[0]; |
| 206 | + else |
| 207 | + stopExpr = m_params.posParams[0]; |
| 208 | + break; |
| 209 | + case 2: |
| 210 | + if (startExpr && stopExpr && stepExpr) |
| 211 | + break; |
| 212 | + else if (startExpr && stopExpr) |
| 213 | + break; |
| 214 | + else if (startExpr && stepExpr) |
| 215 | + break; |
| 216 | + else if (stopExpr && stepExpr) |
| 217 | + break; |
| 218 | + else if (startExpr) |
| 219 | + { |
| 220 | + stopExpr = m_params.posParams[0]; |
| 221 | + stepExpr = m_params.posParams[1]; |
| 222 | + } |
| 223 | + else if (stopExpr) |
| 224 | + { |
| 225 | + startExpr = m_params.posParams[0]; |
| 226 | + stepExpr = m_params.posParams[1]; |
| 227 | + } |
| 228 | + else if (stepExpr) |
| 229 | + { |
| 230 | + startExpr = m_params.posParams[0]; |
| 231 | + stopExpr = m_params.posParams[1]; |
| 232 | + } |
| 233 | + else |
| 234 | + { |
| 235 | + startExpr = m_params.posParams[0]; |
| 236 | + stopExpr = m_params.posParams[1]; |
| 237 | + } |
| 238 | + break; |
| 239 | + case 3: |
| 240 | + if (startExpr || stopExpr || stepExpr) |
| 241 | + break; |
| 242 | + else |
| 243 | + { |
| 244 | + startExpr = m_params.posParams[0]; |
| 245 | + stopExpr = m_params.posParams[1]; |
| 246 | + stepExpr = m_params.posParams[2]; |
| 247 | + } |
| 248 | + break; |
| 249 | + } |
| 250 | + |
| 251 | + Value startVal = startExpr ? startExpr->Evaluate(values) : Value(); |
| 252 | + Value stopVal = stopExpr ? stopExpr->Evaluate(values) : Value(); |
| 253 | + Value stepVal = stepExpr ? stepExpr->Evaluate(values) : Value(); |
| 254 | + |
| 255 | + int64_t start = boost::apply_visitor(visitors::IntegerEvaluator(), startVal.data()); |
| 256 | + int64_t stop = boost::apply_visitor(visitors::IntegerEvaluator(), stopVal.data()); |
| 257 | + int64_t step = boost::apply_visitor(visitors::IntegerEvaluator(), stepVal.data()); |
| 258 | + |
| 259 | + if (!stepExpr) |
| 260 | + { |
| 261 | + step = 1; |
| 262 | + } |
| 263 | + else |
| 264 | + { |
| 265 | + if (step == 0) |
| 266 | + return Value(); |
| 267 | + } |
| 268 | + |
| 269 | + class RangeGenerator : public ListItemAccessor |
| 270 | + { |
| 271 | + public: |
| 272 | + RangeGenerator(int64_t start, int64_t stop, int64_t step) |
| 273 | + : m_start(start) |
| 274 | + , m_stop(stop) |
| 275 | + , m_step(step) |
| 276 | + { |
| 277 | + } |
| 278 | + |
| 279 | + size_t GetSize() const override |
| 280 | + { |
| 281 | + size_t count = (m_stop - m_start); |
| 282 | + return count / m_step; |
| 283 | + } |
| 284 | + Value GetValueByIndex(int64_t idx) const |
| 285 | + { |
| 286 | + return m_start + m_step * idx; |
| 287 | + } |
| 288 | + |
| 289 | + private: |
| 290 | + int64_t m_start; |
| 291 | + int64_t m_stop; |
| 292 | + int64_t m_step; |
| 293 | + }; |
| 294 | + |
| 295 | + return GenericList([accessor = RangeGenerator(start, stop, step)]() -> const ListItemAccessor* {return &accessor;}); |
| 296 | +} |
| 297 | + |
| 298 | +Value CallExpression::CallLoopCycle(RenderContext& values) |
| 299 | +{ |
| 300 | + bool loopFound = false; |
| 301 | + auto loopValP = values.FindValue("loop", loopFound); |
| 302 | + if (!loopFound) |
| 303 | + return Value(); |
| 304 | + |
| 305 | + const ValuesMap* loop = boost::get<ValuesMap>(&loopValP->second.data()); |
| 306 | + int64_t baseIdx = boost::apply_visitor(visitors::IntegerEvaluator(), (*loop).at("index0").data()); |
| 307 | + auto idx = baseIdx % m_params.posParams.size(); |
| 308 | + return m_params.posParams[idx]->Evaluate(values); |
| 309 | +} |
| 310 | + |
| 311 | + |
| 312 | + |
165 | 313 | } |
0 commit comments