string like array access
This commit is contained in:
@@ -376,6 +376,8 @@ func unwrapReturnValue(obj object.Object) object.Object {
|
||||
|
||||
func evalIndexExpression(left, index object.Object) object.Object {
|
||||
switch {
|
||||
case left.Type() == object.STRING_OBJ && index.Type() == object.INTEGER_OBJ:
|
||||
return evalStringIndexExpression(left, index)
|
||||
case left.Type() == object.ARRAY_OBJ && index.Type() == object.INTEGER_OBJ:
|
||||
return evalArrayIndexExpression(left, index)
|
||||
case left.Type() == object.HASH_OBJ:
|
||||
@@ -385,6 +387,18 @@ func evalIndexExpression(left, index object.Object) object.Object {
|
||||
}
|
||||
}
|
||||
|
||||
func evalStringIndexExpression(str, index object.Object) object.Object {
|
||||
stringObject := str.(*object.String)
|
||||
idx := index.(*object.Integer).Value
|
||||
max := int64((len(stringObject.Value)) - 1)
|
||||
|
||||
if idx < 0 || idx > max {
|
||||
return &object.String{Value: ""}
|
||||
}
|
||||
|
||||
return &object.String{Value: string(stringObject.Value[idx])}
|
||||
}
|
||||
|
||||
func evalHashIndexExpression(hash, index object.Object) object.Object {
|
||||
hashObject := hash.(*object.Hash)
|
||||
|
||||
|
||||
@@ -647,3 +647,53 @@ func TestExamples(t *testing.T) {
|
||||
testEval(string(b))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringIndexExpressions(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected interface{}
|
||||
}{
|
||||
{
|
||||
`"abc"[0]`,
|
||||
"a",
|
||||
},
|
||||
{
|
||||
`"abc"[1]`,
|
||||
"b",
|
||||
},
|
||||
{
|
||||
`"abc"[2]`,
|
||||
"c",
|
||||
},
|
||||
{
|
||||
`let i = 0; "abc"[i];`,
|
||||
"a",
|
||||
},
|
||||
{
|
||||
`"abc"[1 + 1];`,
|
||||
"c",
|
||||
},
|
||||
{
|
||||
`let myString = "abc"; myString[0] + myString[1] + myString[2];`,
|
||||
"abc",
|
||||
},
|
||||
{
|
||||
`"abc"[3]`,
|
||||
"",
|
||||
},
|
||||
{
|
||||
`"foo"[-1]`,
|
||||
"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
evaluated := testEval(tt.input)
|
||||
str, ok := tt.expected.(string)
|
||||
if ok {
|
||||
testStringObject(t, evaluated, string(str))
|
||||
} else {
|
||||
testNullObject(t, evaluated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
14
vm/vm.go
14
vm/vm.go
@@ -297,6 +297,8 @@ func (vm *VM) Run() error {
|
||||
|
||||
func (vm *VM) executeIndexExpressions(left, index object.Object) error {
|
||||
switch {
|
||||
case left.Type() == object.STRING_OBJ && index.Type() == object.INTEGER_OBJ:
|
||||
return vm.executeStringIndex(left, index)
|
||||
case left.Type() == object.ARRAY_OBJ && index.Type() == object.INTEGER_OBJ:
|
||||
return vm.executeArrayIndex(left, index)
|
||||
case left.Type() == object.HASH_OBJ:
|
||||
@@ -567,6 +569,18 @@ func (vm *VM) pushClosure(constIndex, numFree int) error {
|
||||
return vm.push(closure)
|
||||
}
|
||||
|
||||
func (vm *VM) executeStringIndex(str, index object.Object) error {
|
||||
stringObject := str.(*object.String)
|
||||
i := index.(*object.Integer).Value
|
||||
max := int64(len(stringObject.Value) - 1)
|
||||
|
||||
if i < 0 || i > max {
|
||||
return vm.push(&object.String{Value: ""})
|
||||
}
|
||||
|
||||
return vm.push(&object.String{Value: string(stringObject.Value[i])})
|
||||
}
|
||||
|
||||
func nativeBoolToBooleanObject(input bool) *object.Boolean {
|
||||
if input {
|
||||
return True
|
||||
|
||||
@@ -317,6 +317,11 @@ func TestIndexExpressions(t *testing.T) {
|
||||
{"{1: 1, 2: 2}[2]", 2},
|
||||
{"{1: 1}[0]", Null},
|
||||
{"{}[0]", Null},
|
||||
{`"abc"[0]`, "a"},
|
||||
{`"abc"[1]`, "b"},
|
||||
{`"abc"[2]`, "c"},
|
||||
{`"abc"[3]`, ""},
|
||||
{`"abc"[-1]`, ""},
|
||||
}
|
||||
|
||||
runVmTests(t, tests)
|
||||
|
||||
Reference in New Issue
Block a user