string like array access
Some checks failed
Build / build (push) Failing after 1m25s
Test / build (push) Has been cancelled

This commit is contained in:
Chuck Smith
2024-03-15 14:14:34 -04:00
parent 997f0865f4
commit d7938e59e4
4 changed files with 83 additions and 0 deletions

View File

@@ -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)

View File

@@ -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)
}
}
}

View File

@@ -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

View File

@@ -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)