@@ -206,6 +206,38 @@ class Value : public std::enable_shared_from_this<Value> {
206206 throw std::runtime_error (" Value is not an array: " + dump ());
207207 array_->push_back (v);
208208 }
209+ Value pop (const Value& index) {
210+ if (is_array ()) {
211+ if (array_->empty ())
212+ throw std::runtime_error (" pop from empty list" );
213+ if (index.is_null ()) {
214+ auto ret = array_->back ();
215+ array_->pop_back ();
216+ return ret;
217+ } else if (!index.is_number_integer ()) {
218+ throw std::runtime_error (" pop index must be an integer: " + index.dump ());
219+ } else {
220+ auto i = index.get <int >();
221+ if (i < 0 || i >= static_cast <int >(array_->size ()))
222+ throw std::runtime_error (" pop index out of range: " + index.dump ());
223+ auto it = array_->begin () + (i < 0 ? array_->size () + i : i);
224+ auto ret = *it;
225+ array_->erase (it);
226+ return ret;
227+ }
228+ } else if (is_object ()) {
229+ if (!index.is_hashable ())
230+ throw std::runtime_error (" Unashable type: " + index.dump ());
231+ auto it = object_->find (index.primitive_ );
232+ if (it == object_->end ())
233+ throw std::runtime_error (" Key not found: " + index.dump ());
234+ auto ret = it->second ;
235+ object_->erase (it);
236+ return ret;
237+ } else {
238+ throw std::runtime_error (" Value is not an array or object: " + dump ());
239+ }
240+ }
209241 Value get (const Value& key) {
210242 if (array_) {
211243 if (!key.is_number_integer ()) {
@@ -366,11 +398,13 @@ class Value : public std::enable_shared_from_this<Value> {
366398 throw std::runtime_error (" contains can only be called on arrays and objects: " + dump ());
367399 }
368400 }
369- Value pop (size_t index) {
401+ void erase (size_t index) {
370402 if (!array_) throw std::runtime_error (" Value is not an array: " + dump ());
371- auto value = array_->at (index);
372403 array_->erase (array_->begin () + index);
373- return value;
404+ }
405+ void erase (const std::string & key) {
406+ if (!object_) throw std::runtime_error (" Value is not an object: " + dump ());
407+ object_->erase (key);
374408 }
375409 const Value& at (const Value & index) const {
376410 return const_cast <Value*>(this )->at (index);
@@ -1345,21 +1379,15 @@ class MethodCallExpr : public Expression {
13451379 vargs.expectArgs (" append method" , {1 , 1 }, {0 , 0 });
13461380 obj.push_back (vargs.args [0 ]);
13471381 return Value ();
1382+ } else if (method->get_name () == " pop" ) {
1383+ vargs.expectArgs (" pop method" , {0 , 1 }, {0 , 0 });
1384+ return obj.pop (vargs.args .empty () ? Value () : vargs.args [0 ]);
13481385 } else if (method->get_name () == " insert" ) {
13491386 vargs.expectArgs (" insert method" , {2 , 2 }, {0 , 0 });
13501387 auto index = vargs.args [0 ].get <int64_t >();
13511388 if (index < 0 || index > (int64_t ) obj.size ()) throw std::runtime_error (" Index out of range for insert method" );
13521389 obj.insert (index, vargs.args [1 ]);
13531390 return Value ();
1354- } else if (method->get_name () == " pop" ) {
1355- vargs.expectArgs (" pop method" , {0 , 1 }, {0 , 0 });
1356- if (vargs.args .empty ()) {
1357- return obj.pop (obj.size () - 1 );
1358- } else {
1359- auto index = vargs.args [0 ].get <int64_t >();
1360- if (index < 0 || index >= (int64_t ) obj.size ()) throw std::runtime_error (" Index out of range for pop method" );
1361- return obj.pop (index);
1362- }
13631391 }
13641392 } else if (obj.is_object ()) {
13651393 if (method->get_name () == " items" ) {
@@ -1369,6 +1397,9 @@ class MethodCallExpr : public Expression {
13691397 result.push_back (Value::array ({key, obj.at (key)}));
13701398 }
13711399 return result;
1400+ } else if (method->get_name () == " pop" ) {
1401+ vargs.expectArgs (" pop method" , {1 , 1 }, {0 , 0 });
1402+ return obj.pop (vargs.args [0 ]);
13721403 } else if (method->get_name () == " get" ) {
13731404 vargs.expectArgs (" get method" , {1 , 2 }, {0 , 0 });
13741405 auto key = vargs.args [0 ];
@@ -2546,7 +2577,7 @@ inline std::shared_ptr<Context> Context::builtins() {
25462577 }));
25472578 globals.set (" namespace" , Value::callable ([=](const std::shared_ptr<Context> &, ArgumentsValue & args) {
25482579 auto ns = Value::object ();
2549- args.expectArgs (" namespace" , {0 , 0 }, {0 , std::numeric_limits<size_t >::max ()});
2580+ args.expectArgs (" namespace" , {0 , 0 }, {0 , ( std::numeric_limits<size_t >::max) ()});
25502581 for (auto & [name, value] : args.kwargs ) {
25512582 ns.set (name, value);
25522583 }
@@ -2601,7 +2632,7 @@ inline std::shared_ptr<Context> Context::builtins() {
26012632 };
26022633 // https://jinja.palletsprojects.com/en/3.0.x/templates/#jinja-filters.reject
26032634 globals.set (" reject" , Value::callable ([=](const std::shared_ptr<Context> & context, ArgumentsValue & args) {
2604- args.expectArgs (" reject" , {2 , std::numeric_limits<size_t >::max ()}, {0 , 0 });
2635+ args.expectArgs (" reject" , {2 , ( std::numeric_limits<size_t >::max) ()}, {0 , 0 });
26052636 auto & items = args.args [0 ];
26062637 auto filter_fn = context->get (args.args [1 ]);
26072638 if (filter_fn.is_null ()) throw std::runtime_error (" Undefined filter: " + args.args [1 ].dump ());
@@ -2672,7 +2703,7 @@ inline std::shared_ptr<Context> Context::builtins() {
26722703 return out;
26732704 }));
26742705 globals.set (" selectattr" , Value::callable ([=](const std::shared_ptr<Context> & context, ArgumentsValue & args) {
2675- args.expectArgs (" selectattr" , {2 , std::numeric_limits<size_t >::max ()}, {0 , 0 });
2706+ args.expectArgs (" selectattr" , {2 , ( std::numeric_limits<size_t >::max) ()}, {0 , 0 });
26762707 auto & items = args.args [0 ];
26772708 if (items.is_null ())
26782709 return Value::array ();
0 commit comments