@@ -1291,6 +1291,12 @@ class UnaryOpExpr : public Expression {
12911291 }
12921292};
12931293
1294+ static bool in (const Value & value, const Value & container) {
1295+ return (((container.is_array () || container.is_object ()) && container.contains (value)) ||
1296+ (value.is_string () && container.is_string () &&
1297+ container.to_str ().find (value.to_str ()) != std::string::npos));
1298+ };
1299+
12941300class BinaryOpExpr : public Expression {
12951301public:
12961302 enum class Op { StrConcat, Add, Sub, Mul, MulMul, Div, DivDiv, Mod, Eq, Ne, Lt, Gt, Le, Ge, And, Or, In, NotIn, Is, IsNot };
@@ -1355,13 +1361,8 @@ class BinaryOpExpr : public Expression {
13551361 case Op::Gt: return l > r;
13561362 case Op::Le: return l <= r;
13571363 case Op::Ge: return l >= r;
1358- case Op::In: return (((r.is_array () || r.is_object ()) && r.contains (l)) ||
1359- (l.is_string () && r.is_string () &&
1360- r.to_str ().find (l.to_str ()) != std::string::npos));
1361- case Op::NotIn:
1362- return !(((r.is_array () || r.is_object ()) && r.contains (l)) ||
1363- (l.is_string () && r.is_string () &&
1364- r.to_str ().find (l.to_str ()) != std::string::npos));
1364+ case Op::In: return in (l, r);
1365+ case Op::NotIn: return !in (l, r);
13651366 default : break ;
13661367 }
13671368 throw std::runtime_error (" Unknown binary operator" );
@@ -1500,6 +1501,13 @@ class MethodCallExpr : public Expression {
15001501 } else if (method->get_name () == " pop" ) {
15011502 vargs.expectArgs (" pop method" , {1 , 1 }, {0 , 0 });
15021503 return obj.pop (vargs.args [0 ]);
1504+ } else if (method->get_name () == " keys" ) {
1505+ vargs.expectArgs (" keys method" , {0 , 0 }, {0 , 0 });
1506+ auto result = Value::array ();
1507+ for (const auto & key : obj.keys ()) {
1508+ result.push_back (Value (key));
1509+ }
1510+ return result;
15031511 } else if (method->get_name () == " get" ) {
15041512 vargs.expectArgs (" get method" , {1 , 2 }, {0 , 0 });
15051513 auto key = vargs.args [0 ];
@@ -2792,6 +2800,9 @@ inline std::shared_ptr<Context> Context::builtins() {
27922800 if (!items.is_array ()) throw std::runtime_error (" object is not iterable" );
27932801 return items;
27942802 }));
2803+ globals.set (" in" , simple_function (" in" , { " item" , " items" }, [](const std::shared_ptr<Context> &, Value & args) -> Value {
2804+ return in (args.at (" item" ), args.at (" items" ));
2805+ }));
27952806 globals.set (" unique" , simple_function (" unique" , { " items" }, [](const std::shared_ptr<Context> &, Value & args) -> Value {
27962807 auto & items = args.at (" items" );
27972808 if (!items.is_array ()) throw std::runtime_error (" object is not iterable" );
0 commit comments