Skip to content

Commit

Permalink
unify object creation with New methods (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkusFreitag authored Jan 17, 2022
1 parent b655395 commit bc92247
Show file tree
Hide file tree
Showing 42 changed files with 296 additions and 237 deletions.
2 changes: 1 addition & 1 deletion evaluator/assign.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

func evalAssign(a *ast.Assign, env *object.Environment) (val object.Object) {
evaluated := Eval(a.Value, env)
if isError(evaluated) {
if object.IsError(evaluated) {
return evaluated
}

Expand Down
101 changes: 35 additions & 66 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@ package evaluator
import (
"github.com/flipez/rocket-lang/ast"
"github.com/flipez/rocket-lang/object"

"fmt"
)

var (
TRUE = &object.Boolean{Value: true}
FALSE = &object.Boolean{Value: false}
NULL = &object.Null{}
)

func Eval(node ast.Node, env *object.Environment) object.Object {
Expand All @@ -28,37 +20,38 @@ func Eval(node ast.Node, env *object.Environment) object.Object {
return evalForeach(node, env)
case *ast.Return:
val := Eval(node.ReturnValue, env)
if isError(val) {
if object.IsError(val) {
return val
}
return &object.ReturnValue{Value: val}
return object.NewReturnValue(val)

// Expressions
case *ast.Integer:
return &object.Integer{Value: node.Value}
return object.NewInteger(node.Value)
case *ast.Float:
return &object.Float{Value: node.Value}
return object.NewFloat(node.Value)
case *ast.Function:
params := node.Parameters
body := node.Body
name := node.Name
function := &object.Function{Parameters: params, Env: env, Body: body}

if name != "" {
env.Set(name, function)
function := object.NewFunction(
node.Parameters,
env,
node.Body,
)

if node.Name != "" {
env.Set(node.Name, function)
}

return function
case *ast.Import:
return evalImport(node, env)
case *ast.String:
return &object.String{Value: node.Value}
return object.NewString(node.Value)
case *ast.Array:
elements := evalExpressions(node.Elements, env)
if len(elements) == 1 && isError(elements[0]) {
if len(elements) == 1 && object.IsError(elements[0]) {
return elements[0]
}
return &object.Array{Elements: elements}
return object.NewArray(elements)
case *ast.Hash:
return evalHash(node, env)

Expand All @@ -67,18 +60,18 @@ func Eval(node ast.Node, env *object.Environment) object.Object {

case *ast.Prefix:
right := Eval(node.Right, env)
if isError(right) {
if object.IsError(right) {
return right
}
return evalPrefixExpression(node.Operator, right)

case *ast.Infix:
left := Eval(node.Left, env)
if isError(left) {
if object.IsError(left) {
return left
}
right := Eval(node.Right, env)
if isError(right) {
if object.IsError(right) {
return right
}
return evalInfixExpression(node.Operator, left, right)
Expand All @@ -88,23 +81,23 @@ func Eval(node ast.Node, env *object.Environment) object.Object {

case *ast.Call:
function := Eval(node.Callable, env)
if isError(function) {
if object.IsError(function) {
return function
}
args := evalExpressions(node.Arguments, env)
if len(args) == 1 && isError(args[0]) {
if len(args) == 1 && object.IsError(args[0]) {
return args[0]
}

return applyFunction(function, args)

case *ast.Index:
left := Eval(node.Left, env)
if isError(left) {
if object.IsError(left) {
return left
}
index := Eval(node.Index, env)
if isError(index) {
if object.IsError(index) {
return index
}
return evalIndex(left, index)
Expand Down Expand Up @@ -132,7 +125,7 @@ func applyFunction(def object.Object, args []object.Object) object.Object {
return def.Fn(args...)

default:
return newError("not a function: %s", def.Type())
return object.NewErrorFormat("not a function: %s", def.Type())
}
}

Expand All @@ -159,7 +152,7 @@ func evalExpressions(exps []ast.Expression, env *object.Environment) []object.Ob

for _, e := range exps {
evaluated := Eval(e, env)
if isError(evaluated) {
if object.IsError(evaluated) {
return []object.Object{evaluated}
}
result = append(result, evaluated)
Expand All @@ -168,55 +161,31 @@ func evalExpressions(exps []ast.Expression, env *object.Environment) []object.Ob
return result
}

func isTruthy(obj object.Object) bool {
switch obj {
case NULL:
return false
case TRUE:
return true
case FALSE:
return false
default:
return true
}
}

func evalBangOperatorExpression(right object.Object) object.Object {
switch right {
case TRUE:
return FALSE
case FALSE:
return TRUE
case NULL:
return TRUE
case object.TRUE:
return object.FALSE
case object.FALSE:
return object.TRUE
case object.NULL:
return object.TRUE
default:
return FALSE
return object.FALSE
}
}

func evalMinusPrefixOperatorExpression(right object.Object) object.Object {
if right.Type() != object.INTEGER_OBJ {
return newError("unknown operator: -%s", right.Type())
return object.NewErrorFormat("unknown operator: -%s", right.Type())
}

value := right.(*object.Integer).Value
return &object.Integer{Value: -value}
return object.NewInteger(-value)
}

func nativeBoolToBooleanObject(input bool) *object.Boolean {
if input {
return TRUE
}
return FALSE
}

func newError(format string, a ...interface{}) *object.Error {
return &object.Error{Message: fmt.Sprintf(format, a...)}
}

func isError(obj object.Object) bool {
if obj != nil {
return obj.Type() == object.ERROR_OBJ
return object.TRUE
}
return false
return object.FALSE
}
16 changes: 8 additions & 8 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,12 +419,12 @@ func TestHashLiterals(t *testing.T) {
}

expected := map[object.HashKey]int64{
(&object.String{Value: "one"}).HashKey(): 1,
(&object.String{Value: "two"}).HashKey(): 2,
(&object.String{Value: "three"}).HashKey(): 3,
(&object.Integer{Value: 4}).HashKey(): 4,
TRUE.HashKey(): 5,
FALSE.HashKey(): 6,
object.NewString("one").HashKey(): 1,
object.NewString("two").HashKey(): 2,
object.NewString("three").HashKey(): 3,
object.NewInteger(4).HashKey(): 4,
object.TRUE.HashKey(): 5,
object.FALSE.HashKey(): 6,
}

if len(result.Pairs) != len(expected) {
Expand Down Expand Up @@ -556,8 +556,8 @@ func TestImportSearchPaths(t *testing.T) {
}

func testNullObject(t *testing.T, obj object.Object) bool {
if obj != NULL {
t.Errorf("object is not NULL. got=%T (%+v)", obj, obj)
if obj != object.NULL {
t.Errorf("object is not object.NULL. got=%T (%+v)", obj, obj)
return false
}
return true
Expand Down
4 changes: 2 additions & 2 deletions evaluator/foreach.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ func evalForeach(fle *ast.Foreach, env *object.Environment) object.Object {

helper, ok := val.(object.Iterable)
if !ok {
return newError("%s object doesn't implement the Iterable interface", val.Type())
return object.NewErrorFormat("%s object doesn't implement the Iterable interface", val.Type())
}

var permit []string
Expand Down Expand Up @@ -42,7 +42,7 @@ func evalForeach(fle *ast.Foreach, env *object.Environment) object.Object {
//
// If we got an error/return then we handle it.
//
if rt != nil && !isError(rt) && (rt.Type() == object.RETURN_VALUE_OBJ || rt.Type() == object.ERROR_OBJ) {
if rt != nil && !object.IsError(rt) && (rt.Type() == object.RETURN_VALUE_OBJ || rt.Type() == object.ERROR_OBJ) {
return rt
}

Expand Down
8 changes: 4 additions & 4 deletions evaluator/hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ func evalHash(node *ast.Hash, env *object.Environment) object.Object {

for keyNode, valueNode := range node.Pairs {
key := Eval(keyNode, env)
if isError(key) {
if object.IsError(key) {
return key
}

hashKey, ok := key.(object.Hashable)
if !ok {
return newError("unusable as hash key: %s", key.Type())
return object.NewErrorFormat("unusable as hash key: %s", key.Type())
}

value := Eval(valueNode, env)
if isError(value) {
if object.IsError(value) {
return value
}

hashed := hashKey.HashKey()
pairs[hashed] = object.HashPair{Key: key, Value: value}
}

return &object.Hash{Pairs: pairs}
return object.NewHash(pairs)
}
2 changes: 1 addition & 1 deletion evaluator/identifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object
return builtin
}

return newError("identifier not found: " + node.Value)
return object.NewErrorFormat("identifier not found: " + node.Value)
}
6 changes: 3 additions & 3 deletions evaluator/if.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import (
func evalIf(ie *ast.If, env *object.Environment) object.Object {
condition := Eval(ie.Condition, env)

if isError(condition) {
if object.IsError(condition) {
return condition
}
if isTruthy(condition) {
if object.IsTruthy(condition) {
return Eval(ie.Consequence, env)
} else if ie.Alternative != nil {
return Eval(ie.Alternative, env)
} else {
return NULL
return object.NULL
}
}
10 changes: 5 additions & 5 deletions evaluator/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ import (
func evalImport(ie *ast.Import, env *object.Environment) object.Object {
name := Eval(ie.Name, env)

if isError(name) {
if object.IsError(name) {
return name
}

if s, ok := name.(*object.String); ok {
attributes := EvalModule(s.Value)

if isError(attributes) {
if object.IsError(attributes) {
return attributes
}

env.Set(filepath.Base(s.Value), &object.Module{Name: s.Value, Attributes: attributes})
return &object.Null{}
env.Set(filepath.Base(s.Value), object.NewModule(s.Value, attributes))
return object.NULL
}

return newError("Import Error: invalid import path '%s'", name)
return object.NewErrorFormat("Import Error: invalid import path '%s'", name)
}
12 changes: 6 additions & 6 deletions evaluator/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func evalIndex(left, index object.Object) object.Object {
case left.Type() == object.MODULE_OBJ:
return evalModuleIndexExpression(left, index)
default:
return newError("index operator not supported: %s", left.Type())
return object.NewErrorFormat("index operator not supported: %s", left.Type())
}
}

Expand All @@ -31,22 +31,22 @@ func evalStringIndexExpression(left, index object.Object) object.Object {
max := int64(len(stringObject.Value) - 1)

if idx < 0 || idx > max {
return NULL
return object.NULL
}

return &object.String{Value: string(stringObject.Value[idx])}
return object.NewString(string(stringObject.Value[idx]))
}

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())
return object.NewErrorFormat("unusable as hash key: %s", index.Type())
}

pair, ok := hashObject.Pairs[key.HashKey()]
if !ok {
return NULL
return object.NULL
}

return pair.Value
Expand All @@ -58,7 +58,7 @@ func evalArrayIndexExpression(array, index object.Object) object.Object {
max := int64(len(arrayObject.Elements) - 1)

if idx < 0 || idx > max {
return NULL
return object.NULL
}

return arrayObject.Elements[idx]
Expand Down
Loading

1 comment on commit bc92247

@vercel
Copy link

@vercel vercel bot commented on bc92247 Jan 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.