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 {
|
func evalIndexExpression(left, index object.Object) object.Object {
|
||||||
switch {
|
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:
|
case left.Type() == object.ARRAY_OBJ && index.Type() == object.INTEGER_OBJ:
|
||||||
return evalArrayIndexExpression(left, index)
|
return evalArrayIndexExpression(left, index)
|
||||||
case left.Type() == object.HASH_OBJ:
|
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 {
|
func evalHashIndexExpression(hash, index object.Object) object.Object {
|
||||||
hashObject := hash.(*object.Hash)
|
hashObject := hash.(*object.Hash)
|
||||||
|
|
||||||
|
|||||||
@@ -647,3 +647,53 @@ func TestExamples(t *testing.T) {
|
|||||||
testEval(string(b))
|
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 {
|
func (vm *VM) executeIndexExpressions(left, index object.Object) error {
|
||||||
switch {
|
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:
|
case left.Type() == object.ARRAY_OBJ && index.Type() == object.INTEGER_OBJ:
|
||||||
return vm.executeArrayIndex(left, index)
|
return vm.executeArrayIndex(left, index)
|
||||||
case left.Type() == object.HASH_OBJ:
|
case left.Type() == object.HASH_OBJ:
|
||||||
@@ -567,6 +569,18 @@ func (vm *VM) pushClosure(constIndex, numFree int) error {
|
|||||||
return vm.push(closure)
|
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 {
|
func nativeBoolToBooleanObject(input bool) *object.Boolean {
|
||||||
if input {
|
if input {
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -317,6 +317,11 @@ func TestIndexExpressions(t *testing.T) {
|
|||||||
{"{1: 1, 2: 2}[2]", 2},
|
{"{1: 1, 2: 2}[2]", 2},
|
||||||
{"{1: 1}[0]", Null},
|
{"{1: 1}[0]", Null},
|
||||||
{"{}[0]", Null},
|
{"{}[0]", Null},
|
||||||
|
{`"abc"[0]`, "a"},
|
||||||
|
{`"abc"[1]`, "b"},
|
||||||
|
{`"abc"[2]`, "c"},
|
||||||
|
{`"abc"[3]`, ""},
|
||||||
|
{`"abc"[-1]`, ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
runVmTests(t, tests)
|
runVmTests(t, tests)
|
||||||
|
|||||||
Reference in New Issue
Block a user