diff options
| author | Bobby <[email protected]> | 2024-04-04 16:25:56 +0000 |
|---|---|---|
| committer | Bobby <[email protected]> | 2024-04-04 16:25:56 +0000 |
| commit | 77d0ea46b3f1de99357c7706c4c05eb44c237412 (patch) | |
| tree | d6fa8ca0a89233b26591eaed72c1017ad6190dba /evaluator | |
| parent | 3d4f24f7c4ea05471109c0b13abbc95e70c6924b (diff) | |
| download | mana-77d0ea46b3f1de99357c7706c4c05eb44c237412.tar.xz mana-77d0ea46b3f1de99357c7706c4c05eb44c237412.zip | |
arrays and array indexes
Diffstat (limited to 'evaluator')
| -rw-r--r-- | evaluator/evaluator.go | 45 | ||||
| -rw-r--r-- | evaluator/evaluator_test.go | 79 |
2 files changed, 124 insertions, 0 deletions
diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index 86d1889..913138b 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -83,6 +83,30 @@ func Eval(node ast.Node, env *object.Environment) object.Object { return &object.Function{Parameters: params, Body: body, Env: env} + case *ast.ArrayLiteral: + elements := evalExpressions(node.Elements, env) + + if len(elements) == 1 && isError(elements[0]) { + return elements[0] + } + + return &object.Array{Elements: elements} + + case *ast.IndexExpression: + left := Eval(node.Left, env) + + if isError(left) { + return left + } + + index := Eval(node.Index, env) + + if isError(index) { + return index + } + + return evalIndexExpression(left, index) + case *ast.StringLiteral: return &object.String{Value: node.Value} @@ -291,6 +315,27 @@ func evalIfExpression(ie *ast.IfExpression, env *object.Environment) object.Obje } } +func evalIndexExpression(left, index object.Object) object.Object { + switch { + case left.Type() == object.ARRAY_OBJ && index.Type() == object.INTEGER_OBJ: + return evalArrayIndexExpression(left, index) + default: + return newError("index operator not supported: %s", left.Type()) + } +} + +func evalArrayIndexExpression(array, index object.Object) object.Object { + arrayObject := array.(*object.Array) + idx := index.(*object.Integer).Value + max := int64(len(arrayObject.Elements) - 1) + + if idx < 0 || idx > max { + return NULL + } + + return arrayObject.Elements[idx] +} + func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object { if val, ok := env.Get(node.Value); ok { return val diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index 22fd80a..3c72cda 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -377,3 +377,82 @@ func TestBuiltinFunctions(t *testing.T) { } } } + +func TestArrayLiterals(t *testing.T) { + input := "[1, 2 * 2, 3 + 3]" + + evaluated := testEval(input) + + result, ok := evaluated.(*object.Array) + + if !ok { + t.Fatalf("object is not Array. got=%T (%+v)", evaluated, evaluated) + } + + if len(result.Elements) != 3 { + t.Fatalf("array has wrong num of elements. got=%d", len(result.Elements)) + } + + testIntegerObject(t, result.Elements[0], 1) + testIntegerObject(t, result.Elements[1], 4) + testIntegerObject(t, result.Elements[2], 6) +} + +func TestArrayIndexExpressions(t *testing.T) { + tests := []struct { + input string + expected interface{} + }{ + { + "[1, 2, 3][0]", + 1, + }, + { + "[1, 2, 3][1]", + 2, + }, + { + "[1, 2, 3][2]", + 3, + }, + { + "let i = 0; [1][i];", + 1, + }, + { + "[1, 2, 3][1 + 1];", + 3, + }, + { + "let myArray = [1, 2, 3]; myArray[2];", + 3, + }, + { + "let myArray = [1, 2, 3]; myArray[0] + myArray[1] + myArray[2];", + 6, + }, + { + "let myArray = [1, 2, 3]; let i = myArray[0]; myArray[i]", + 2, + }, + { + "[1, 2, 3][3]", + nil, + }, + { + "[1, 2, 3][-1]", + nil, + }, + } + + for _, tt := range tests { + evaluated := testEval(tt.input) + + switch expected := tt.expected.(type) { + case int: + testIntegerObject(t, evaluated, int64(expected)) + case nil: + testNullObject(t, evaluated) + } + } +} |
