11
11
#include < algorithm>
12
12
#include < cctype>
13
13
#include < cstddef>
14
+ #include < cstdint>
14
15
#include < cmath>
15
16
#include < exception>
16
17
#include < functional>
@@ -233,7 +234,7 @@ class Value : public std::enable_shared_from_this<Value> {
233
234
}
234
235
} else if (is_object ()) {
235
236
if (!index .is_hashable ())
236
- throw std::runtime_error (" Unashable type: " + index .dump ());
237
+ throw std::runtime_error (" Unhashable type: " + index .dump ());
237
238
auto it = object_->find (index .primitive_ );
238
239
if (it == object_->end ())
239
240
throw std::runtime_error (" Key not found: " + index .dump ());
@@ -252,7 +253,7 @@ class Value : public std::enable_shared_from_this<Value> {
252
253
auto index = key.get <int >();
253
254
return array_->at (index < 0 ? array_->size () + index : index );
254
255
} 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 ());
256
257
auto it = object_->find (key.primitive_ );
257
258
if (it == object_->end ()) return Value ();
258
259
return it->second ;
@@ -261,7 +262,7 @@ class Value : public std::enable_shared_from_this<Value> {
261
262
}
262
263
void set (const Value& key, const Value& value) {
263
264
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 ());
265
266
(*object_)[key.primitive_ ] = value;
266
267
}
267
268
Value call (const std::shared_ptr<Context> & context, ArgumentsValue & args) const {
@@ -398,7 +399,7 @@ class Value : public std::enable_shared_from_this<Value> {
398
399
}
399
400
return false ;
400
401
} 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 ());
402
403
return object_->find (value.primitive_ ) != object_->end ();
403
404
} else {
404
405
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> {
416
417
return const_cast <Value*>(this )->at (index );
417
418
}
418
419
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 ());
420
421
if (is_array ()) return array_->at (index .get <int >());
421
422
if (is_object ()) return object_->at (index .primitive_ );
422
423
throw std::runtime_error (" Value is not an array or object: " + dump ());
@@ -676,8 +677,8 @@ class Expression {
676
677
class VariableExpr : public Expression {
677
678
std::string name;
678
679
public:
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) {}
681
682
std::string get_name () const { return name; }
682
683
Value do_evaluate (const std::shared_ptr<Context> & context) const override {
683
684
if (!context->contains (name)) {
@@ -1200,9 +1201,9 @@ class DictExpr : public Expression {
1200
1201
1201
1202
class SliceExpr : public Expression {
1202
1203
public:
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)) {}
1206
1207
Value do_evaluate (const std::shared_ptr<Context> &) const override {
1207
1208
throw std::runtime_error (" SliceExpr not implemented" );
1208
1209
}
@@ -1219,18 +1220,35 @@ class SubscriptExpr : public Expression {
1219
1220
if (!index ) throw std::runtime_error (" SubscriptExpr.index is null" );
1220
1221
auto target_value = base->evaluate (context);
1221
1222
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);
1224
1236
if (target_value.is_string ()) {
1225
1237
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
+
1229
1249
} else if (target_value.is_array ()) {
1230
- if (start < 0 ) start = target_value.size () + start;
1231
- if (end < 0 ) end = target_value.size () + end;
1232
1250
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 ) {
1234
1252
result.push_back (target_value.at (i));
1235
1253
}
1236
1254
return result;
@@ -1305,6 +1323,8 @@ class BinaryOpExpr : public Expression {
1305
1323
if (name == " iterable" ) return l.is_iterable ();
1306
1324
if (name == " sequence" ) return l.is_array ();
1307
1325
if (name == " defined" ) return !l.is_null ();
1326
+ if (name == " true" ) return l.to_bool ();
1327
+ if (name == " false" ) return !l.to_bool ();
1308
1328
throw std::runtime_error (" Unknown type for 'is' operator: " + name);
1309
1329
};
1310
1330
auto value = eval ();
@@ -1520,6 +1540,10 @@ class MethodCallExpr : public Expression {
1520
1540
vargs.expectArgs (" endswith method" , {1 , 1 }, {0 , 0 });
1521
1541
auto suffix = vargs.args [0 ].get <std::string>();
1522
1542
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 ());
1523
1547
} else if (method->get_name () == " title" ) {
1524
1548
vargs.expectArgs (" title method" , {0 , 0 }, {0 , 0 });
1525
1549
auto res = str;
@@ -2082,28 +2106,37 @@ class Parser {
2082
2106
2083
2107
while (it != end && consumeSpaces () && peekSymbols ({ " [" , " ." })) {
2084
2108
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
+ }
2086
2123
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 ();
2101
2127
}
2102
2128
}
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" );
2105
2138
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 ));
2107
2140
} else if (!consumeToken (" ." ).empty ()) {
2108
2141
auto identifier = parseIdentifier ();
2109
2142
if (!identifier) throw std::runtime_error (" Expected identifier in subscript" );
0 commit comments