aboutsummaryrefslogtreecommitdiff
path: root/evaluator/evaluator.go
diff options
context:
space:
mode:
Diffstat (limited to 'evaluator/evaluator.go')
-rw-r--r--evaluator/evaluator.go137
1 files changed, 127 insertions, 10 deletions
diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go
index c8fa09a..50b2ab5 100644
--- a/evaluator/evaluator.go
+++ b/evaluator/evaluator.go
@@ -43,6 +43,9 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
case *ast.IntegerLiteral:
return &object.Integer{Value: node.Value}
+ case *ast.StringLiteral:
+ return &object.String{Value: node.Value}
+
case *ast.Boolean:
return nativeBoolToBooleanObject(node.Value)
@@ -89,6 +92,28 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
}
return applyFunction(function, args)
+
+ 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.HashLiteral:
+ return evalHashLiteral(node, env)
+
}
return nil
@@ -156,6 +181,8 @@ func evalInfixExpression(
switch {
case left.Type() == object.INTEGER_OBJ && right.Type() == object.INTEGER_OBJ:
return evalIntegerInfixExpression(operator, left, right)
+ case left.Type() == object.STRING_OBJ && right.Type() == object.STRING_OBJ:
+ return evalStringInfixExpression(operator, left, right)
case operator == "==":
return nativeBoolToBooleanObject(left == right)
case operator == "!=":
@@ -221,6 +248,20 @@ func evalIntegerInfixExpression(
}
}
+func evalStringInfixExpression(
+ operator string,
+ left, right object.Object,
+) object.Object {
+ if operator != "+" {
+ return newError("unknown operator: %s %s %s",
+ left.Type(), operator, right.Type())
+ }
+
+ leftVal := left.(*object.String).Value
+ rightVal := right.(*object.String).Value
+ return &object.String{Value: leftVal + rightVal}
+}
+
func evalIfExpression(
ie *ast.IfExpression,
env *object.Environment,
@@ -243,12 +284,15 @@ func evalIdentifier(
node *ast.Identifier,
env *object.Environment,
) object.Object {
- val, ok := env.Get(node.Value)
- if !ok {
- return newError("identifier not found: " + node.Value)
+ if val, ok := env.Get(node.Value); ok {
+ return val
+ }
+
+ if builtin, ok := builtins[node.Value]; ok {
+ return builtin
}
- return val
+ return newError("identifier not found: " + node.Value)
}
func isTruthy(obj object.Object) bool {
@@ -293,14 +337,19 @@ func evalExpressions(
}
func applyFunction(fn object.Object, args []object.Object) object.Object {
- function, ok := fn.(*object.Function)
- if !ok {
+ switch fn := fn.(type) {
+
+ case *object.Function:
+ extendedEnv := extendFunctionEnv(fn, args)
+ evaluated := Eval(fn.Body, extendedEnv)
+ return unwrapReturnValue(evaluated)
+
+ case *object.Builtin:
+ return fn.Fn(args...)
+
+ default:
return newError("not a function: %s", fn.Type())
}
-
- extendedEnv := extendFunctionEnv(function, args)
- evaluated := Eval(function.Body, extendedEnv)
- return unwrapReturnValue(evaluated)
}
func extendFunctionEnv(
@@ -323,3 +372,71 @@ func unwrapReturnValue(obj object.Object) object.Object {
return obj
}
+
+func evalIndexExpression(left, index object.Object) object.Object {
+ switch {
+ case left.Type() == object.ARRAY_OBJ && index.Type() == object.INTEGER_OBJ:
+ return evalArrayIndexExpression(left, index)
+ case left.Type() == object.HASH_OBJ:
+ return evalHashIndexExpression(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 evalHashLiteral(
+ node *ast.HashLiteral,
+ env *object.Environment,
+) object.Object {
+ pairs := make(map[object.HashKey]object.HashPair)
+
+ for keyNode, valueNode := range node.Pairs {
+ key := Eval(keyNode, env)
+ if isError(key) {
+ return key
+ }
+
+ hashKey, ok := key.(object.Hashable)
+ if !ok {
+ return newError("unusable as hash key: %s", key.Type())
+ }
+
+ value := Eval(valueNode, env)
+ if isError(value) {
+ return value
+ }
+
+ hashed := hashKey.HashKey()
+ pairs[hashed] = object.HashPair{Key: key, Value: value}
+ }
+
+ return &object.Hash{Pairs: pairs}
+}
+
+func evalHashIndexExpression(hash, index object.Object) object.Object {
+ hashObject := hash.(*object.Hash)
+
+ key, ok := index.(object.Hashable)
+ if !ok {
+ return newError("unusable as hash key: %s", index.Type())
+ }
+
+ pair, ok := hashObject.Pairs[key.HashKey()]
+ if !ok {
+ return NULL
+ }
+
+ return pair.Value
+}