1111#include  < algorithm> 
1212#include  < cctype> 
1313#include  < cstddef> 
14+ #include  < cstdint> 
1415#include  < cmath> 
1516#include  < exception> 
1617#include  < functional> 
@@ -233,7 +234,7 @@ class Value : public std::enable_shared_from_this<Value> {
233234      }
234235    } else  if  (is_object ()) {
235236      if  (!index.is_hashable ())
236-         throw  std::runtime_error (" Unashable  type: "   + index.dump ());
237+         throw  std::runtime_error (" Unhashable  type: "   + index.dump ());
237238      auto  it = object_->find (index.primitive_ );
238239      if  (it == object_->end ())
239240        throw  std::runtime_error (" Key not found: "   + index.dump ());
@@ -252,7 +253,7 @@ class Value : public std::enable_shared_from_this<Value> {
252253      auto  index = key.get <int >();
253254      return  array_->at (index < 0  ? array_->size () + index : index);
254255    } else  if  (object_) {
255-       if  (!key.is_hashable ()) throw  std::runtime_error (" Unashable  type: "   + dump ());
256+       if  (!key.is_hashable ()) throw  std::runtime_error (" Unhashable  type: "   + dump ());
256257      auto  it = object_->find (key.primitive_ );
257258      if  (it == object_->end ()) return  Value ();
258259      return  it->second ;
@@ -261,7 +262,7 @@ class Value : public std::enable_shared_from_this<Value> {
261262  }
262263  void  set (const  Value& key, const  Value& value) {
263264    if  (!object_) throw  std::runtime_error (" Value is not an object: "   + dump ());
264-     if  (!key.is_hashable ()) throw  std::runtime_error (" Unashable  type: "   + dump ());
265+     if  (!key.is_hashable ()) throw  std::runtime_error (" Unhashable  type: "   + dump ());
265266    (*object_)[key.primitive_ ] = value;
266267  }
267268  Value call (const  std::shared_ptr<Context> & context, ArgumentsValue & args) const  {
@@ -398,7 +399,7 @@ class Value : public std::enable_shared_from_this<Value> {
398399      }
399400      return  false ;
400401    } else  if  (object_) {
401-       if  (!value.is_hashable ()) throw  std::runtime_error (" Unashable  type: "   + value.dump ());
402+       if  (!value.is_hashable ()) throw  std::runtime_error (" Unhashable  type: "   + value.dump ());
402403      return  object_->find (value.primitive_ ) != object_->end ();
403404    } else  {
404405      throw  std::runtime_error (" contains can only be called on arrays and objects: "   + dump ());
@@ -416,7 +417,7 @@ class Value : public std::enable_shared_from_this<Value> {
416417    return  const_cast <Value*>(this )->at (index);
417418  }
418419  Value& at (const  Value & index) {
419-     if  (!index.is_hashable ()) throw  std::runtime_error (" Unashable  type: "   + dump ());
420+     if  (!index.is_hashable ()) throw  std::runtime_error (" Unhashable  type: "   + dump ());
420421    if  (is_array ()) return  array_->at (index.get <int >());
421422    if  (is_object ()) return  object_->at (index.primitive_ );
422423    throw  std::runtime_error (" Value is not an array or object: "   + dump ());
@@ -676,8 +677,8 @@ class Expression {
676677class  VariableExpr  : public  Expression  {
677678    std::string name;
678679public: 
679-     VariableExpr (const  Location & location , const  std::string& n)
680-       : Expression(location ), name(n) {}
680+     VariableExpr (const  Location & loc , const  std::string& n)
681+       : Expression(loc ), name(n) {}
681682    std::string get_name () const  { return  name; }
682683    Value do_evaluate (const  std::shared_ptr<Context> & context) const  override  {
683684        if  (!context->contains (name)) {
@@ -1200,9 +1201,9 @@ class DictExpr : public Expression {
12001201
12011202class  SliceExpr  : public  Expression  {
12021203public: 
1203-     std::shared_ptr<Expression> start, end;
1204-     SliceExpr (const  Location & loc, std::shared_ptr<Expression> && s, std::shared_ptr<Expression> && e)
1205-       : Expression(loc), start(std::move(s)), end(std::move(e)) {}
1204+     std::shared_ptr<Expression> start, end, step ;
1205+     SliceExpr (const  Location & loc, std::shared_ptr<Expression> && s, std::shared_ptr<Expression> && e, std::shared_ptr<Expression> && st =  nullptr )
1206+       : Expression(loc), start(std::move(s)), end(std::move(e)), step(std::move(st))  {}
12061207    Value do_evaluate (const  std::shared_ptr<Context> &) const  override  {
12071208        throw  std::runtime_error (" SliceExpr not implemented"  );
12081209    }
@@ -1219,18 +1220,35 @@ class SubscriptExpr : public Expression {
12191220        if  (!index) throw  std::runtime_error (" SubscriptExpr.index is null"  );
12201221        auto  target_value = base->evaluate (context);
12211222        if  (auto  slice = dynamic_cast <SliceExpr*>(index.get ())) {
1222-           auto  start = slice->start  ? slice->start ->evaluate (context).get <int64_t >() : 0 ;
1223-           auto  end = slice->end  ? slice->end ->evaluate (context).get <int64_t >() : (int64_t ) target_value.size ();
1223+           auto  len = target_value.size ();
1224+           auto  wrap = [len](int64_t  i) -> int64_t  {
1225+             if  (i < 0 ) {
1226+               return  i + len;
1227+             }
1228+             return  i;
1229+           };
1230+           int64_t  step = slice->step  ? slice->step ->evaluate (context).get <int64_t >() : 1 ;
1231+           if  (!step) {
1232+             throw  std::runtime_error (" slice step cannot be zero"  );
1233+           }
1234+           int64_t  start = slice->start  ? wrap (slice->start ->evaluate (context).get <int64_t >()) : (step < 0  ? len - 1  : 0 );
1235+           int64_t  end = slice->end  ? wrap (slice->end ->evaluate (context).get <int64_t >()) : (step < 0  ? -1  : len);
12241236          if  (target_value.is_string ()) {
12251237            std::string s = target_value.get <std::string>();
1226-             if  (start < 0 ) start = s.size () + start;
1227-             if  (end < 0 ) end = s.size () + end;
1228-             return  s.substr (start, end - start);
1238+ 
1239+             std::string result;
1240+             if  (start < end && step == 1 ) {
1241+               result = s.substr (start, end - start);
1242+             } else  {
1243+               for  (int64_t  i = start; step > 0  ? i < end : i > end; i += step) {
1244+                 result += s[i];
1245+               }
1246+             }
1247+             return  result;
1248+ 
12291249          } else  if  (target_value.is_array ()) {
1230-             if  (start < 0 ) start = target_value.size () + start;
1231-             if  (end < 0 ) end = target_value.size () + end;
12321250            auto  result = Value::array ();
1233-             for  (auto  i = start; i < end; ++i ) {
1251+             for  (int64_t  i = start; step >  0  ?  i < end : i > end; i += step ) {
12341252              result.push_back (target_value.at (i));
12351253            }
12361254            return  result;
@@ -1305,6 +1323,8 @@ class BinaryOpExpr : public Expression {
13051323              if  (name == " iterable"  ) return  l.is_iterable ();
13061324              if  (name == " sequence"  ) return  l.is_array ();
13071325              if  (name == " defined"  ) return  !l.is_null ();
1326+               if  (name == " true"  ) return  l.to_bool ();
1327+               if  (name == " false"  ) return  !l.to_bool ();
13081328              throw  std::runtime_error (" Unknown type for 'is' operator: "   + name);
13091329            };
13101330            auto  value = eval ();
@@ -1520,6 +1540,10 @@ class MethodCallExpr : public Expression {
15201540            vargs.expectArgs (" endswith method"  , {1 , 1 }, {0 , 0 });
15211541            auto  suffix = vargs.args [0 ].get <std::string>();
15221542            return  suffix.length () <= str.length () && std::equal (suffix.rbegin (), suffix.rend (), str.rbegin ());
1543+           } else  if  (method->get_name () == " startswith"  ) {
1544+             vargs.expectArgs (" startswith method"  , {1 , 1 }, {0 , 0 });
1545+             auto  prefix = vargs.args [0 ].get <std::string>();
1546+             return  prefix.length () <= str.length () && std::equal (prefix.begin (), prefix.end (), str.begin ());
15231547          } else  if  (method->get_name () == " title"  ) {
15241548            vargs.expectArgs (" title method"  , {0 , 0 }, {0 , 0 });
15251549            auto  res = str;
@@ -2082,28 +2106,37 @@ class Parser {
20822106
20832107      while  (it != end && consumeSpaces () && peekSymbols ({ " ["  , " ."   })) {
20842108        if  (!consumeToken (" ["  ).empty ()) {
2085-             std::shared_ptr<Expression> index;
2109+           std::shared_ptr<Expression> index;
2110+           auto  slice_loc = get_location ();
2111+           std::shared_ptr<Expression> start, end, step;
2112+           bool  has_first_colon = false , has_second_colon = false ;
2113+ 
2114+           if  (!peekSymbols ({ " :"   })) {
2115+             start = parseExpression ();
2116+           }
2117+ 
2118+           if  (!consumeToken (" :"  ).empty ()) {
2119+             has_first_colon = true ;
2120+             if  (!peekSymbols ({ " :"  , " ]"   })) {
2121+               end = parseExpression ();
2122+             }
20862123            if  (!consumeToken (" :"  ).empty ()) {
2087-               auto  slice_end = parseExpression ();
2088-               index = std::make_shared<SliceExpr>(slice_end->location , nullptr , std::move (slice_end));
2089-             } else  {
2090-               auto  slice_start = parseExpression ();
2091-               if  (!consumeToken (" :"  ).empty ()) {
2092-                 consumeSpaces ();
2093-                 if  (peekSymbols ({ " ]"   })) {
2094-                   index = std::make_shared<SliceExpr>(slice_start->location , std::move (slice_start), nullptr );
2095-                 } else  {
2096-                   auto  slice_end = parseExpression ();
2097-                   index = std::make_shared<SliceExpr>(slice_start->location , std::move (slice_start), std::move (slice_end));
2098-                 }
2099-               } else  {
2100-                 index = std::move (slice_start);
2124+               has_second_colon = true ;
2125+               if  (!peekSymbols ({ " ]"   })) {
2126+                 step = parseExpression ();
21012127              }
21022128            }
2103-             if  (!index) throw  std::runtime_error (" Empty index in subscript"  );
2104-             if  (consumeToken (" ]"  ).empty ()) throw  std::runtime_error (" Expected closing bracket in subscript"  );
2129+           }
2130+ 
2131+           if  ((has_first_colon || has_second_colon) && (start || end || step)) {
2132+             index = std::make_shared<SliceExpr>(slice_loc, std::move (start), std::move (end), std::move (step));
2133+           } else  {
2134+             index = std::move (start);
2135+           }
2136+           if  (!index) throw  std::runtime_error (" Empty index in subscript"  );
2137+           if  (consumeToken (" ]"  ).empty ()) throw  std::runtime_error (" Expected closing bracket in subscript"  );
21052138
2106-              value = std::make_shared<SubscriptExpr>(value->location , std::move (value), std::move (index));
2139+           value = std::make_shared<SubscriptExpr>(value->location , std::move (value), std::move (index));
21072140        } else  if  (!consumeToken (" ."  ).empty ()) {
21082141            auto  identifier = parseIdentifier ();
21092142            if  (!identifier) throw  std::runtime_error (" Expected identifier in subscript"  );
0 commit comments