aboutsummaryrefslogtreecommitdiff
path: root/evaluator
diff options
context:
space:
mode:
Diffstat (limited to 'evaluator')
-rw-r--r--evaluator/evaluator.go45
-rw-r--r--evaluator/evaluator_test.go79
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)
+ }
+ }
+}