@@ -1617,7 +1617,7 @@ namespace {
1617
1617
if (i < 0 || i >= sz) {
1618
1618
std::stringstream ss;
1619
1619
ss << " Array bounds error: " << i
1620
- << " not within [0, " << sz << " ] " ;
1620
+ << " not within [0, " << sz << " ) " ;
1621
1621
throw makeError (ast.location , ss.str ());
1622
1622
}
1623
1623
auto *thunk = array->elements [i];
@@ -1644,18 +1644,39 @@ namespace {
1644
1644
stack.pop ();
1645
1645
ast_ = objectIndex (ast.location , obj, fid);
1646
1646
goto recurse;
1647
+ } else if (target.t == Value::STRING) {
1648
+ auto *obj = static_cast <HeapString*>(target.v .h );
1649
+ assert (obj != nullptr );
1650
+ if (scratch.t != Value::DOUBLE) {
1651
+ throw makeError (ast.location ,
1652
+ " String index must be a number, got "
1653
+ + type_str (scratch) + " ." );
1654
+ }
1655
+ // TODO(dcunnin): UTF-8 support goes here.
1656
+ long sz = obj->value .length ();
1657
+ long i = (long )scratch.v .d ;
1658
+ if (i < 0 || i >= sz) {
1659
+ std::stringstream ss;
1660
+ ss << " String bounds error: " << i
1661
+ << " not within [0, " << sz << " )" ;
1662
+ throw makeError (ast.location , ss.str ());
1663
+ }
1664
+ char ch[] = {obj->value [i], ' \0 ' };
1665
+ scratch = makeString (ch);
1647
1666
} else {
1648
- std::cerr << " INTERNAL ERROR: Neither an object nor an array."
1667
+ std::cerr << " INTERNAL ERROR: Not object / array / string ."
1649
1668
<< std::endl;
1650
1669
abort ();
1651
1670
}
1652
1671
} break ;
1653
1672
1654
1673
case FRAME_INDEX_TARGET: {
1655
1674
const auto &ast = *static_cast <const Index*>(f.ast );
1656
- if (scratch.t != Value::ARRAY && scratch.t != Value::OBJECT) {
1675
+ if (scratch.t != Value::ARRAY
1676
+ && scratch.t != Value::OBJECT
1677
+ && scratch.t != Value::STRING) {
1657
1678
throw makeError (ast.location ,
1658
- " Can only index objects and arrays, got "
1679
+ " Can only index objects, strings, and arrays, got "
1659
1680
+ type_str (scratch) + " ." );
1660
1681
}
1661
1682
ast_ = ast.index ;
0 commit comments