diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index 064f565..0918196 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -1154,17 +1154,22 @@ func evalHashIndexExpression(hash, index object.Object) object.Object { func evalStringIndexExpression(input, index object.Object) object.Object { str := input.(*object.String).Value - idx := index.(*object.Integer).Value + idx, isInt := index.(*object.Integer) + if !isInt { + return newError("expected an integer for string index, got something else") + } + + i := idx.Value max := int64(len(str)) - if idx < 0 || idx > max { - return NULL + if i < 0 || i > max { + return newError("index out of bounds") } // Get the characters as an array of runes chars := []rune(str) // Now index - ret := chars[idx] + ret := chars[i] // And return as a string. return &object.String{Value: string(ret)} diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index deb3538..a741cd2 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -458,40 +458,66 @@ func TestStringIndexExpression(t *testing.T) { tests := []struct { input string expected interface{} + err bool }{ { "\"Steve\"[0]", "S", + false, }, { "\"Steve\"[1]", "t", + false, }, { "\"Steve\"[101]", nil, + true, }, { "\"Steve\"[-1]", nil, + true, }, { "\"狐犬\"[0]", "狐", + false, }, { "\"狐犬\"[1]", "犬", + false, + }, + { + "\"狐犬\"[\"x\"]", + "", + true, + }, + { + "\"狐犬\"[-3]", + "", + true, }, } for _, tt := range tests { evaluated := testEval(tt.input) - str, ok := tt.expected.(string) - if ok { - testStringObject(t, evaluated, str) + _, err := evaluated.(*object.Error) + + if err { + if tt.err == false { + t.Fatalf("expected error for input '%s', got %T", tt.input, evaluated) + } } else { - testNullObject(t, evaluated) + str, ok := tt.expected.(string) + if ok { + testStringObject(t, evaluated, str) + } else { + + testNullObject(t, evaluated) + } } } }