@@ -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 ];
@@ -1541,6 +1549,16 @@ class MethodCallExpr : public Expression {
15411549 } else if (method->get_name () == " capitalize" ) {
15421550 vargs.expectArgs (" capitalize method" , {0 , 0 }, {0 , 0 });
15431551 return Value (capitalize (str));
1552+ } else if (method->get_name () == " upper" ) {
1553+ vargs.expectArgs (" upper method" , {0 , 0 }, {0 , 0 });
1554+ auto result = str;
1555+ std::transform (result.begin (), result.end (), result.begin (), ::toupper);
1556+ return Value (result);
1557+ } else if (method->get_name () == " lower" ) {
1558+ vargs.expectArgs (" lower method" , {0 , 0 }, {0 , 0 });
1559+ auto result = str;
1560+ std::transform (result.begin (), result.end (), result.begin (), ::tolower);
1561+ return Value (result);
15441562 } else if (method->get_name () == " endswith" ) {
15451563 vargs.expectArgs (" endswith method" , {1 , 1 }, {0 , 0 });
15461564 auto suffix = vargs.args [0 ].get <std::string>();
@@ -2646,15 +2664,11 @@ inline std::shared_ptr<Context> Context::builtins() {
26462664 auto items = Value::array ();
26472665 if (args.contains (" object" )) {
26482666 auto & obj = args.at (" object" );
2649- if (obj.is_string ()) {
2650- auto json_obj = json::parse (obj.get <std::string>());
2651- for (const auto & kv : json_obj.items ()) {
2652- items.push_back (Value::array ({kv.key (), kv.value ()}));
2653- }
2654- } else if (!obj.is_null ()) {
2655- for (auto & key : obj.keys ()) {
2656- items.push_back (Value::array ({key, obj.at (key)}));
2657- }
2667+ if (!obj.is_object ()) {
2668+ throw std::runtime_error (" Can only get item pairs from a mapping" );
2669+ }
2670+ for (auto & key : obj.keys ()) {
2671+ items.push_back (Value::array ({key, obj.at (key)}));
26582672 }
26592673 }
26602674 return items;
@@ -2782,6 +2796,9 @@ inline std::shared_ptr<Context> Context::builtins() {
27822796 if (!items.is_array ()) throw std::runtime_error (" object is not iterable" );
27832797 return items;
27842798 }));
2799+ globals.set (" in" , simple_function (" in" , { " item" , " items" }, [](const std::shared_ptr<Context> &, Value & args) -> Value {
2800+ return in (args.at (" item" ), args.at (" items" ));
2801+ }));
27852802 globals.set (" unique" , simple_function (" unique" , { " items" }, [](const std::shared_ptr<Context> &, Value & args) -> Value {
27862803 auto & items = args.at (" items" );
27872804 if (!items.is_array ()) throw std::runtime_error (" object is not iterable" );
0 commit comments