From bc922477028b588b580b91ad004bbf7c963aacd5 Mon Sep 17 00:00:00 2001 From: Markus Freitag Date: Mon, 17 Jan 2022 01:07:44 +0100 Subject: [PATCH] unify object creation with New methods (#51) --- evaluator/assign.go | 2 +- evaluator/evaluator.go | 101 +++++++++++++----------------------- evaluator/evaluator_test.go | 16 +++--- evaluator/foreach.go | 4 +- evaluator/hash.go | 8 +-- evaluator/identifier.go | 2 +- evaluator/if.go | 6 +-- evaluator/import.go | 10 ++-- evaluator/index.go | 12 ++--- evaluator/infix.go | 36 ++++++------- evaluator/module.go | 6 +-- evaluator/object_call.go | 2 +- evaluator/prefix.go | 2 +- object/array.go | 27 +++++++--- object/array_test.go | 2 +- object/boolean.go | 7 ++- object/boolean_test.go | 30 +++++++---- object/builtin.go | 7 +++ object/environment.go | 4 +- object/error.go | 10 ++++ object/error_test.go | 2 +- object/file.go | 36 +++++++------ object/float.go | 8 ++- object/float_test.go | 8 +-- object/function.go | 8 +++ object/hash.go | 13 +++-- object/hash_test.go | 2 +- object/integer.go | 10 ++-- object/integer_test.go | 8 +-- object/module.go | 4 ++ object/null.go | 2 + object/null_test.go | 6 +-- object/object.go | 33 +++++++++--- object/object_test.go | 2 +- object/return_value.go | 4 ++ object/return_value_test.go | 2 +- object/string.go | 44 +++++++++------- object/string_test.go | 11 ++-- stdlib/exit.go | 4 +- stdlib/open.go | 12 ++--- stdlib/raise.go | 6 +-- stdlib/std.go | 14 +---- 42 files changed, 296 insertions(+), 237 deletions(-) diff --git a/evaluator/assign.go b/evaluator/assign.go index 190cee0..ea69e24 100644 --- a/evaluator/assign.go +++ b/evaluator/assign.go @@ -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 } diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index f87d586..a7337c7 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -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 { @@ -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) @@ -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) @@ -88,11 +81,11 @@ 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] } @@ -100,11 +93,11 @@ func Eval(node ast.Node, env *object.Environment) object.Object { 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) @@ -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()) } } @@ -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) @@ -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 } diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index 04c45fe..af9d58f 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -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) { @@ -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 diff --git a/evaluator/foreach.go b/evaluator/foreach.go index f29e5d0..8438de3 100644 --- a/evaluator/foreach.go +++ b/evaluator/foreach.go @@ -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 @@ -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 } diff --git a/evaluator/hash.go b/evaluator/hash.go index 8f8b6e0..48fa4b6 100644 --- a/evaluator/hash.go +++ b/evaluator/hash.go @@ -10,17 +10,17 @@ 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 } @@ -28,5 +28,5 @@ func evalHash(node *ast.Hash, env *object.Environment) object.Object { pairs[hashed] = object.HashPair{Key: key, Value: value} } - return &object.Hash{Pairs: pairs} + return object.NewHash(pairs) } diff --git a/evaluator/identifier.go b/evaluator/identifier.go index 4f225c1..ef0abc6 100644 --- a/evaluator/identifier.go +++ b/evaluator/identifier.go @@ -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) } diff --git a/evaluator/if.go b/evaluator/if.go index bdb5b8c..7d176dd 100644 --- a/evaluator/if.go +++ b/evaluator/if.go @@ -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 } } diff --git a/evaluator/import.go b/evaluator/import.go index 5aa662b..1246d99 100644 --- a/evaluator/import.go +++ b/evaluator/import.go @@ -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) } diff --git a/evaluator/index.go b/evaluator/index.go index 951e957..ee3eca7 100644 --- a/evaluator/index.go +++ b/evaluator/index.go @@ -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()) } } @@ -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 @@ -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] diff --git a/evaluator/infix.go b/evaluator/infix.go index 41ca903..cad9936 100644 --- a/evaluator/infix.go +++ b/evaluator/infix.go @@ -10,16 +10,16 @@ func evalIntegerInfix(operator string, left, right object.Object) object.Object switch operator { case "+": - return &object.Integer{Value: leftVal + rightVal} + return object.NewInteger(leftVal + rightVal) case "-": - return &object.Integer{Value: leftVal - rightVal} + return object.NewInteger(leftVal - rightVal) case "*": - return &object.Integer{Value: leftVal * rightVal} + return object.NewInteger(leftVal * rightVal) case "/": if rightVal == 0 { - return newError("devision by zero not allowed") + return object.NewErrorFormat("devision by zero not allowed") } - return &object.Integer{Value: leftVal / rightVal} + return object.NewInteger(leftVal / rightVal) case "<": return nativeBoolToBooleanObject(leftVal < rightVal) case "<=": @@ -29,7 +29,7 @@ func evalIntegerInfix(operator string, left, right object.Object) object.Object case ">=": return nativeBoolToBooleanObject(leftVal >= rightVal) default: - return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type()) + return object.NewErrorFormat("unknown operator: %s %s %s", left.Type(), operator, right.Type()) } } @@ -39,16 +39,16 @@ func evalFloatInfix(operator string, left, right object.Object) object.Object { switch operator { case "+": - return &object.Float{Value: leftVal + rightVal} + return object.NewFloat(leftVal + rightVal) case "-": - return &object.Float{Value: leftVal - rightVal} + return object.NewFloat(leftVal - rightVal) case "*": - return &object.Float{Value: leftVal * rightVal} + return object.NewFloat(leftVal * rightVal) case "/": if rightVal == 0 { - return newError("devision by zero not allowed") + return object.NewErrorFormat("devision by zero not allowed") } - return &object.Float{Value: leftVal / rightVal} + return object.NewFloat(leftVal / rightVal) case "<": return nativeBoolToBooleanObject(leftVal < rightVal) case "<=": @@ -58,7 +58,7 @@ func evalFloatInfix(operator string, left, right object.Object) object.Object { case ">=": return nativeBoolToBooleanObject(leftVal >= rightVal) default: - return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type()) + return object.NewErrorFormat("unknown operator: %s %s %s", left.Type(), operator, right.Type()) } } @@ -92,13 +92,13 @@ func evalInfixExpression(operator string, left, right object.Object) object.Obje } return result case left.Type() != right.Type(): - return newError("type mismatch: %s %s %s", left.Type(), operator, right.Type()) + return object.NewErrorFormat("type mismatch: %s %s %s", left.Type(), operator, right.Type()) case left.Type() == object.STRING_OBJ && right.Type() == object.STRING_OBJ: return evalStringInfixExpression(operator, left, right) case left.Type() == object.ARRAY_OBJ && right.Type() == object.ARRAY_OBJ: return evalArrayInfixExpression(operator, left, right) default: - return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type()) + return object.NewErrorFormat("unknown operator: %s %s %s", left.Type(), operator, right.Type()) } } @@ -108,9 +108,9 @@ func evalStringInfixExpression(operator string, left, right object.Object) objec switch operator { case "+": - return &object.String{Value: leftVal + rightVal} + return object.NewString(leftVal + rightVal) default: - return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type()) + return object.NewErrorFormat("unknown operator: %s %s %s", left.Type(), operator, right.Type()) } } @@ -124,8 +124,8 @@ func evalArrayInfixExpression(operator string, left, right object.Object) object elements := make([]object.Object, length) copy(elements, leftArray.Elements) copy(elements[len(leftArray.Elements):], rightArray.Elements) - return &object.Array{Elements: elements} + return object.NewArray(elements) default: - return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type()) + return object.NewErrorFormat("unknown operator: %s %s %s", left.Type(), operator, right.Type()) } } diff --git a/evaluator/module.go b/evaluator/module.go index fca2032..c76eda3 100644 --- a/evaluator/module.go +++ b/evaluator/module.go @@ -13,13 +13,13 @@ func EvalModule(name string) object.Object { filename := utilities.FindModule(name) if filename == "" { - return newError("Import Error: no module named '%s' found", name) + return object.NewErrorFormat("Import Error: no module named '%s' found", name) } b, err := ioutil.ReadFile(filename) if err != nil { - return newError("IO Error: error reading module '%s': %s", name, err) + return object.NewErrorFormat("IO Error: error reading module '%s': %s", name, err) } l := lexer.New(string(b)) @@ -29,7 +29,7 @@ func EvalModule(name string) object.Object { module, _ := p.ParseProgram() if len(p.Errors()) != 0 { - return newError("Parse Error: %s", p.Errors()) + return object.NewErrorFormat("Parse Error: %s", p.Errors()) } env := object.NewEnvironment() diff --git a/evaluator/object_call.go b/evaluator/object_call.go index 66cdc3f..c5c7306 100644 --- a/evaluator/object_call.go +++ b/evaluator/object_call.go @@ -15,5 +15,5 @@ func evalObjectCall(call *ast.ObjectCall, env *object.Environment) object.Object } } - return newError("Failed to invoke method: %s", call.Call.(*ast.Call).Callable.String()) + return object.NewErrorFormat("Failed to invoke method: %s", call.Call.(*ast.Call).Callable.String()) } diff --git a/evaluator/prefix.go b/evaluator/prefix.go index 7dea4aa..3b1cac3 100644 --- a/evaluator/prefix.go +++ b/evaluator/prefix.go @@ -11,6 +11,6 @@ func evalPrefixExpression(operator string, right object.Object) object.Object { case "-": return evalMinusPrefixOperatorExpression(right) default: - return newError("unknown operator: %s%s", operator, right.Type()) + return object.NewErrorFormat("unknown operator: %s%s", operator, right.Type()) } } diff --git a/object/array.go b/object/array.go index 3e4b236..de8d77f 100644 --- a/object/array.go +++ b/object/array.go @@ -2,7 +2,6 @@ package object import ( "bytes" - "fmt" "hash/fnv" "strings" ) @@ -12,6 +11,18 @@ type Array struct { offset int } +func NewArray(slice []Object) *Array { + return &Array{Elements: slice} +} + +func NewArrayWithObjects(objs ...Object) *Array { + slice := make([]Object, len(objs), len(objs)) + for idx, obj := range objs { + slice[idx] = obj + } + return NewArray(slice) +} + func (ao *Array) Type() ObjectType { return ARRAY_OBJ } func (ao *Array) Inspect() string { var out bytes.Buffer @@ -47,7 +58,7 @@ func init() { }, method: func(o Object, _ []Object) Object { ao := o.(*Array) - return &Integer{Value: int64(len(ao.Elements))} + return NewInteger(int64(len(ao.Elements))) }, }, "uniq": ObjectMethod{ @@ -64,7 +75,7 @@ func init() { for _, element := range ao.Elements { helper, ok := element.(Hashable) if !ok { - return &Error{Message: fmt.Sprintf("failed because element %s is not hashable", element.Type())} + return NewErrorFormat("failed because element %s is not hashable", element.Type()) } items[helper.HashKey()] = element } @@ -77,7 +88,7 @@ func init() { idx++ } - return &Array{Elements: newElements} + return NewArray(newElements) }, }, "index": ObjectMethod{ @@ -101,7 +112,7 @@ func init() { } } - return &Integer{Value: int64(index)} + return NewInteger(int64(index)) }, }, "first": ObjectMethod{ @@ -182,7 +193,7 @@ func init() { newElements[length] = args[0] ao.Elements = newElements - return &Null{} + return NULL }, }, } @@ -200,8 +211,8 @@ func (ao *Array) Next() (Object, Object, bool) { ao.offset++ element := ao.Elements[ao.offset-1] - return element, &Integer{Value: int64(ao.offset - 1)}, true + return element, NewInteger(int64(ao.offset - 1)), true } - return nil, &Integer{Value: 0}, false + return nil, NewInteger(0), false } diff --git a/object/array_test.go b/object/array_test.go index d5f3e42..b20534b 100644 --- a/object/array_test.go +++ b/object/array_test.go @@ -27,7 +27,7 @@ func TestArrayObjectMethods(t *testing.T) { } func TestArrayInspect(t *testing.T) { - arr1 := &object.Array{Elements: []object.Object{}} + arr1 := object.NewArray(nil) if arr1.Type() != object.ARRAY_OBJ { t.Errorf("array.Type() returns wrong type") diff --git a/object/boolean.go b/object/boolean.go index ef2116e..92fcaaa 100644 --- a/object/boolean.go +++ b/object/boolean.go @@ -5,6 +5,11 @@ import ( "strconv" ) +var ( + TRUE = &Boolean{Value: true} + FALSE = &Boolean{Value: false} +) + type Boolean struct { Value bool } @@ -34,7 +39,7 @@ func init() { }, method: func(o Object, _ []Object) Object { b := o.(*Boolean) - return &String{Value: strconv.FormatBool(b.Value)} + return NewString(strconv.FormatBool(b.Value)) }, }, } diff --git a/object/boolean_test.go b/object/boolean_test.go index e89efd9..a16e279 100644 --- a/object/boolean_test.go +++ b/object/boolean_test.go @@ -1,8 +1,9 @@ package object_test import ( - "github.com/flipez/rocket-lang/object" "testing" + + "github.com/flipez/rocket-lang/object" ) func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool { @@ -21,20 +22,27 @@ func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool { func TestBooleanObjectMethods(t *testing.T) { tests := []inputTestCase{ - {`true.plz_s()`, "true"}, - {`false.plz_s()`, "false"}, - {`false.type()`, "BOOLEAN"}, - {`false.nope()`, "Failed to invoke method: nope"}, - {`(true.wat().lines().size() == true.methods().size() + 1).plz_s()`, "true"}, + // true + {"true.plz_s()", "true"}, + {"true.type()", "BOOLEAN"}, + {"true.nope()", "Failed to invoke method: nope"}, + + // false + {"false.plz_s()", "false"}, + {"false.type()", "BOOLEAN"}, + {"false.nope()", "Failed to invoke method: nope"}, + + // other + {"(true.wat().lines().size() == true.methods().size() + 1).plz_s()", "true"}, } testInput(t, tests) } func TestBooleanHashKey(t *testing.T) { - true1 := &object.Boolean{Value: true} - true2 := &object.Boolean{Value: true} - false1 := &object.Boolean{Value: false} + true1 := object.TRUE + true2 := object.TRUE + false1 := object.FALSE if true1.HashKey() != true2.HashKey() { t.Errorf("booleans with same content have different hash keys") @@ -46,8 +54,8 @@ func TestBooleanHashKey(t *testing.T) { } func TestBooleanInspect(t *testing.T) { - true1 := &object.Boolean{Value: true} - false1 := &object.Boolean{Value: false} + true1 := object.TRUE + false1 := object.FALSE if true1.Inspect() != "true" { t.Errorf("boolean inspect does not match value") diff --git a/object/builtin.go b/object/builtin.go index b9ef010..9ccee2f 100644 --- a/object/builtin.go +++ b/object/builtin.go @@ -5,6 +5,13 @@ type Builtin struct { Fn BuiltinFunction } +func NewBuiltin(name string, f BuiltinFunction) *Builtin { + return &Builtin{ + Name: name, + Fn: f, + } +} + type BuiltinFunction func(args ...Object) Object func (b *Builtin) Type() ObjectType { return BUILTIN_OBJ } diff --git a/object/environment.go b/object/environment.go index f2feeb1..13bf0ca 100644 --- a/object/environment.go +++ b/object/environment.go @@ -91,10 +91,10 @@ func (e *Environment) Exported() *Hash { for k, v := range e.store { // Replace this with checking for "Import" token if unicode.IsUpper(rune(k[0])) { - s := &String{Value: k} + s := NewString(k) pairs[s.HashKey()] = HashPair{Key: s, Value: v} } } - return &Hash{Pairs: pairs} + return NewHash(pairs) } diff --git a/object/error.go b/object/error.go index a087306..5b61b55 100644 --- a/object/error.go +++ b/object/error.go @@ -1,9 +1,19 @@ package object +import "fmt" + type Error struct { Message string } +func NewError(e interface{}) *Error { + return &Error{Message: fmt.Sprintf("%s", e)} +} + +func NewErrorFormat(format string, a ...interface{}) *Error { + return &Error{Message: fmt.Sprintf(format, a...)} +} + func (e *Error) Type() ObjectType { return ERROR_OBJ } func (e *Error) Inspect() string { return "ERROR: " + e.Message } func (e *Error) InvokeMethod(method string, env Environment, args ...Object) Object { diff --git a/object/error_test.go b/object/error_test.go index af9fcdb..e69ae4c 100644 --- a/object/error_test.go +++ b/object/error_test.go @@ -7,7 +7,7 @@ import ( ) func TestErrorType(t *testing.T) { - err := &object.Error{Message: "test"} + err := object.NewError("test") if err.Type() != object.ERROR_OBJ { t.Errorf("error.Type() returns wrong type") diff --git a/object/file.go b/object/file.go index 77ccc88..bffce5c 100644 --- a/object/file.go +++ b/object/file.go @@ -15,6 +15,10 @@ type File struct { Handle *os.File } +func NewFile(name string) *File { + return &File{Filename: name} +} + func (f *File) Type() ObjectType { return FILE_OBJ } func (f *File) Inspect() string { return fmt.Sprintf("", f.Filename) } func (f *File) Open(mode string, perm string) error { @@ -78,7 +82,7 @@ func init() { f := o.(*File) f.Handle.Close() f.Position = -1 - return &Boolean{Value: true} + return TRUE }, }, "lines": ObjectMethod{ @@ -94,10 +98,10 @@ func init() { result := make([]Object, len(lines), len(lines)) for i, line := range lines { - result[i] = &String{Value: line} + result[i] = NewString(line) } - return &Array{Elements: result} + return NewArray(result) }, }, "content": ObjectMethod{ @@ -114,7 +118,7 @@ func init() { }, method: func(o Object, _ []Object) Object { f := o.(*File) - return &Integer{Value: f.Position} + return NewInteger(f.Position) }, }, "read": ObjectMethod{ @@ -129,7 +133,7 @@ func init() { f := o.(*File) bytesAmount := args[0].(*Integer).Value if f.Handle == nil { - return &Error{Message: "Invalid file handle."} + return NewError("Invalid file handle.") } buffer := make([]byte, bytesAmount) @@ -137,10 +141,10 @@ func init() { f.Position += int64(bytesRealRead) if err != nil { - return &Error{Message: err.Error()} + return NewError(err) } - return &String{Value: string(buffer)} + return NewString(string(buffer)) }, }, "seek": ObjectMethod{ @@ -156,7 +160,7 @@ func init() { f := o.(*File) if f.Handle == nil { - return &Error{Message: "Invalid file handle."} + return NewError("Invalid file handle.") } seekAmount := args[0].(*Integer).Value @@ -165,10 +169,10 @@ func init() { f.Position = newOffset if err != nil { - return &Error{Message: err.Error()} + return NewError(err) } - return &Integer{Value: f.Position} + return NewInteger(f.Position) }, }, "write": ObjectMethod{ @@ -184,17 +188,17 @@ func init() { content := []byte(args[0].(*String).Value) if f.Handle == nil { - return &Error{Message: "Invalid file handle."} + return NewError("Invalid file handle.") } bytesWritten, err := f.Handle.Write(content) f.Position += int64(bytesWritten) if err != nil { - return &Error{Message: err.Error()} + return NewError(err) } - return &Boolean{Value: true} + return TRUE }, }, } @@ -208,15 +212,15 @@ func readFile(o Object, _ []Object) Object { f := o.(*File) f.Handle.Seek(0, 0) if f.Handle == nil { - return &Error{Message: "Invalid file handle."} + return NewError("Invalid file handle.") } file, err := ioutil.ReadAll(f.Handle) if err != nil { - return &Error{Message: err.Error()} + return NewError(err) } f.Handle.Seek(0, 0) f.Position = 0 - return &String{Value: string(file)} + return NewString(string(file)) } diff --git a/object/float.go b/object/float.go index 80bc2d9..76c6230 100644 --- a/object/float.go +++ b/object/float.go @@ -10,6 +10,10 @@ type Float struct { Value float64 } +func NewFloat(f float64) *Float { + return &Float{Value: f} +} + func (f *Float) Inspect() string { return f.toString() } func (f *Float) Type() ObjectType { return FLOAT_OBJ } func (f *Float) HashKey() HashKey { @@ -32,7 +36,7 @@ func init() { }, method: func(o Object, args []Object) Object { f := o.(*Float) - return &String{Value: f.toString()} + return NewString(f.toString()) }, }, } @@ -44,7 +48,7 @@ func (f *Float) InvokeMethod(method string, env Environment, args ...Object) Obj func (f *Float) TryInteger() Object { if i := int64(f.Value); f.Value == float64(i) { - return &Integer{Value: i} + return NewInteger(i) } return f } diff --git a/object/float_test.go b/object/float_test.go index b871e75..d045041 100644 --- a/object/float_test.go +++ b/object/float_test.go @@ -32,9 +32,9 @@ func TestFloatObjectMethods(t *testing.T) { } func TestFloatHashKey(t *testing.T) { - float1_1 := &object.Float{Value: 1.0} - float1_2 := &object.Float{Value: 1.0} - float2 := &object.Float{Value: 2.0} + float1_1 := object.NewFloat(1.0) + float1_2 := object.NewFloat(1.0) + float2 := object.NewFloat(2.0) if float1_1.HashKey() != float1_2.HashKey() { t.Errorf("float with same content have different hash keys") @@ -46,7 +46,7 @@ func TestFloatHashKey(t *testing.T) { } func TestFloatInspect(t *testing.T) { - float1 := &object.Float{Value: 1.0} + float1 := object.NewFloat(1.0) if float1.Inspect() != "1.0" { t.Errorf("float inspect does not match value") diff --git a/object/function.go b/object/function.go index 69f0527..e84f741 100644 --- a/object/function.go +++ b/object/function.go @@ -13,6 +13,14 @@ type Function struct { Env *Environment } +func NewFunction(params []*ast.Identifier, env *Environment, body *ast.Block) *Function { + return &Function{ + Parameters: params, + Env: env, + Body: body, + } +} + func (f *Function) Type() ObjectType { return FUNCTION_OBJ } func (f *Function) Inspect() string { var out bytes.Buffer diff --git a/object/hash.go b/object/hash.go index 3678ce8..78e2570 100644 --- a/object/hash.go +++ b/object/hash.go @@ -12,6 +12,13 @@ type Hash struct { offset int } +func NewHash(pairs map[HashKey]HashPair) *Hash { + if pairs == nil { + pairs = make(map[HashKey]HashPair) + } + return &Hash{Pairs: pairs} +} + type HashPair struct { Key Object Value Object @@ -68,7 +75,7 @@ func init() { i++ } - return &Array{Elements: keys} + return NewArray(keys) }, }, "values": ObjectMethod{ @@ -89,7 +96,7 @@ func init() { i++ } - return &Array{Elements: values} + return NewArray(values) }, }, } @@ -117,5 +124,5 @@ func (h *Hash) Next() (Object, Object, bool) { } } - return nil, &Integer{Value: 0}, false + return nil, NewInteger(0), false } diff --git a/object/hash_test.go b/object/hash_test.go index b92cdff..c754d02 100644 --- a/object/hash_test.go +++ b/object/hash_test.go @@ -39,7 +39,7 @@ func TestHashInspect(t *testing.T) { } func TestHashType(t *testing.T) { - hash1 := &object.Hash{Pairs: make(map[object.HashKey]object.HashPair)} + hash1 := object.NewHash(nil) if hash1.Type() != object.HASH_OBJ { t.Errorf("hash.Type() returns wrong type") diff --git a/object/integer.go b/object/integer.go index 82d3630..a673bdb 100644 --- a/object/integer.go +++ b/object/integer.go @@ -9,6 +9,10 @@ type Integer struct { Value int64 } +func NewInteger(i int64) *Integer { + return &Integer{Value: i} +} + func (i *Integer) Inspect() string { return fmt.Sprintf("%d", i.Value) } func (i *Integer) Type() ObjectType { return INTEGER_OBJ } func (i *Integer) HashKey() HashKey { @@ -45,7 +49,7 @@ func init() { base = int(args[0].(*Integer).Value) } - return &String{Value: strconv.FormatInt(i.Value, base)} + return NewString(strconv.FormatInt(i.Value, base)) }, }, "plz_f": ObjectMethod{ @@ -62,7 +66,7 @@ func init() { }, method: func(o Object, _ []Object) Object { i := o.(*Integer) - return &Float{Value: float64(i.Value)} + return NewFloat(float64(i.Value)) }, }, } @@ -73,5 +77,5 @@ func (i *Integer) InvokeMethod(method string, env Environment, args ...Object) O } func (i *Integer) ToFloat() Object { - return &Float{Value: float64(i.Value)} + return NewFloat(float64(i.Value)) } diff --git a/object/integer_test.go b/object/integer_test.go index 0f14edf..9f146af 100644 --- a/object/integer_test.go +++ b/object/integer_test.go @@ -34,9 +34,9 @@ func TestIntegerObjectMethods(t *testing.T) { } func TestIntegerHashKey(t *testing.T) { - int1_1 := &object.Integer{Value: 1} - int1_2 := &object.Integer{Value: 1} - int2 := &object.Integer{Value: 2} + int1_1 := object.NewInteger(1) + int1_2 := object.NewInteger(1) + int2 := object.NewInteger(2) if int1_1.HashKey() != int1_2.HashKey() { t.Errorf("integer with same content have different hash keys") @@ -48,7 +48,7 @@ func TestIntegerHashKey(t *testing.T) { } func TestIntegerInspect(t *testing.T) { - int1 := &object.Integer{Value: 1} + int1 := object.NewInteger(1) if int1.Inspect() != "1" { t.Errorf("integer inspect does not match value") diff --git a/object/module.go b/object/module.go index cffc97b..9f11f85 100644 --- a/object/module.go +++ b/object/module.go @@ -7,6 +7,10 @@ type Module struct { Attributes Object } +func NewModule(name string, attrs Object) *Module { + return &Module{Name: name, Attributes: attrs} +} + func (m *Module) Type() ObjectType { return MODULE_OBJ } func (m *Module) Inspect() string { return fmt.Sprintf("module(%s)", m.Name) } func (m *Module) InvokeMethod(method string, env Environment, args ...Object) Object { diff --git a/object/null.go b/object/null.go index 4209376..2b267c5 100644 --- a/object/null.go +++ b/object/null.go @@ -1,5 +1,7 @@ package object +var NULL = new(Null) + type Null struct{} func (n *Null) Type() ObjectType { return NULL_OBJ } diff --git a/object/null_test.go b/object/null_test.go index 30c47d2..a834e6b 100644 --- a/object/null_test.go +++ b/object/null_test.go @@ -7,12 +7,10 @@ import ( ) func TestNullType(t *testing.T) { - n := &object.Null{} - - if n.Type() != object.NULL_OBJ { + if object.NULL.Type() != object.NULL_OBJ { t.Errorf("null.Type() returns wrong type") } - if n.Inspect() != "null" { + if object.NULL.Inspect() != "null" { t.Errorf("null.Inspect() returns wrong type") } } diff --git a/object/object.go b/object/object.go index e965c47..f67cc40 100644 --- a/object/object.go +++ b/object/object.go @@ -129,7 +129,7 @@ func (om ObjectMethod) Usage(name string) string { func (om ObjectMethod) Call(o Object, args []Object) Object { if err := om.validateArgs(args); err != nil { - return &Error{Message: err.Error()} + return NewError(err) } return om.method(o, args) } @@ -154,10 +154,10 @@ func init() { result := make([]Object, len(oms), len(oms)) var i int for name := range oms { - result[i] = &String{Value: name} + result[i] = NewString(name) i++ } - return &Array{Elements: result} + return NewArray(result) }, }, "wat": ObjectMethod{ @@ -176,7 +176,7 @@ func init() { result[i] = fmt.Sprintf("\t%s", objectMethod.Usage(name)) i++ } - return &String{Value: fmt.Sprintf("%s supports the following methods:\n%s", o.Type(), strings.Join(result, "\n"))} + return NewString(fmt.Sprintf("%s supports the following methods:\n%s", o.Type(), strings.Join(result, "\n"))) }, }, "type": ObjectMethod{ @@ -187,7 +187,7 @@ func init() { []string{STRING_OBJ}, }, method: func(o Object, _ []Object) Object { - return &String{Value: string(o.Type())} + return NewString(string(o.Type())) }, }, } @@ -282,6 +282,27 @@ func CompareObjects(ao, bo Object) bool { return false } +func IsError(o Object) bool { + return o != nil && o.Type() == ERROR_OBJ +} + func IsNumber(o Object) bool { - return o.Type() == INTEGER_OBJ || o.Type() == FLOAT_OBJ + return o != nil && (o.Type() == INTEGER_OBJ || o.Type() == FLOAT_OBJ) +} + +func IsTruthy(o Object) bool { + switch o { + case NULL: + return false + case TRUE: + return true + case FALSE: + return false + default: + return true + } +} + +func IsFalsy(o Object) bool { + return !IsTruthy(o) } diff --git a/object/object_test.go b/object/object_test.go index 460cddb..4cdf683 100644 --- a/object/object_test.go +++ b/object/object_test.go @@ -36,7 +36,7 @@ func testInput(t *testing.T, tests []inputTestCase) { case string: arrObj, ok := evaluated.(*object.Array) if ok { - testStringObject(t, &object.String{Value: arrObj.Inspect()}, expected) + testStringObject(t, object.NewString(arrObj.Inspect()), expected) continue } strObj, ok := evaluated.(*object.String) diff --git a/object/return_value.go b/object/return_value.go index cd9d504..59e7f24 100644 --- a/object/return_value.go +++ b/object/return_value.go @@ -4,6 +4,10 @@ type ReturnValue struct { Value Object } +func NewReturnValue(o Object) *ReturnValue { + return &ReturnValue{Value: o} +} + func (rv *ReturnValue) Type() ObjectType { return RETURN_VALUE_OBJ } func (rv *ReturnValue) Inspect() string { return rv.Value.Inspect() } func (rv *ReturnValue) InvokeMethod(method string, env Environment, args ...Object) Object { diff --git a/object/return_value_test.go b/object/return_value_test.go index 44ef89c..160a6df 100644 --- a/object/return_value_test.go +++ b/object/return_value_test.go @@ -7,7 +7,7 @@ import ( ) func TestReturnValue(t *testing.T) { - rv := &object.ReturnValue{Value: &object.String{Value: "a"}} + rv := object.NewReturnValue(object.NewString("a")) if rv.Type() != object.RETURN_VALUE_OBJ { t.Errorf("returnValue.Type() returns wrong type") diff --git a/object/string.go b/object/string.go index ea20666..6bf7d42 100644 --- a/object/string.go +++ b/object/string.go @@ -12,6 +12,10 @@ type String struct { offset int } +func NewString(s string) *String { + return &String{Value: s} +} + func init() { objectMethods[STRING_OBJ] = map[string]ObjectMethod{ "count": ObjectMethod{ @@ -33,7 +37,7 @@ func init() { method: func(o Object, args []Object) Object { s := o.(*String) arg := args[0].(*String).Value - return &Integer{Value: int64(strings.Count(s.Value, arg))} + return NewInteger(int64(strings.Count(s.Value, arg))) }, }, "find": ObjectMethod{ @@ -51,7 +55,7 @@ func init() { method: func(o Object, args []Object) Object { s := o.(*String) arg := args[0].(*String).Value - return &Integer{Value: int64(strings.Index(s.Value, arg))} + return NewInteger(int64(strings.Index(s.Value, arg))) }, }, "size": ObjectMethod{ @@ -63,7 +67,7 @@ func init() { }, method: func(o Object, _ []Object) Object { s := o.(*String) - return &Integer{Value: int64(utf8.RuneCountInString(s.Value))} + return NewInteger(int64(utf8.RuneCountInString(s.Value))) }, }, "plz_i": ObjectMethod{ @@ -103,7 +107,7 @@ func init() { value = strings.TrimPrefix(value, "0x") } i, _ := strconv.ParseInt(value, base, 64) - return &Integer{Value: i} + return NewInteger(i) }, }, "replace": ObjectMethod{ @@ -121,7 +125,7 @@ func init() { s := o.(*String) oldS := args[0].(*String).Value newS := args[1].(*String).Value - return &String{Value: strings.Replace(s.Value, oldS, newS, -1)} + return NewString(strings.Replace(s.Value, oldS, newS, -1)) }, }, "reverse": ObjectMethod{ @@ -139,7 +143,7 @@ func init() { i-- out[i] = c } - return &String{Value: string(out)} + return NewString(string(out)) }, }, "reverse!": ObjectMethod{ @@ -162,7 +166,7 @@ func init() { out[i] = c } s.Value = string(out) - return &Null{} + return NULL }, }, "split": ObjectMethod{ @@ -192,9 +196,9 @@ func init() { l := len(fields) result := make([]Object, l, l) for i, txt := range fields { - result[i] = &String{Value: txt} + result[i] = NewString(txt) } - return &Array{Elements: result} + return NewArray(result) }, }, "lines": ObjectMethod{ @@ -213,9 +217,9 @@ func init() { l := len(fields) result := make([]Object, l, l) for i, txt := range fields { - result[i] = &String{Value: txt} + result[i] = NewString(txt) } - return &Array{Elements: result} + return NewArray(result) }, }, "strip": ObjectMethod{ @@ -227,7 +231,7 @@ func init() { }, method: func(o Object, _ []Object) Object { s := o.(*String) - return &String{Value: strings.TrimSpace(s.Value)} + return NewString(strings.TrimSpace(s.Value)) }, }, "strip!": ObjectMethod{ @@ -245,7 +249,7 @@ func init() { method: func(o Object, _ []Object) Object { s := o.(*String) s.Value = strings.TrimSpace(s.Value) - return &Null{} + return NULL }, }, "downcase": ObjectMethod{ @@ -257,7 +261,7 @@ func init() { }, method: func(o Object, _ []Object) Object { s := o.(*String) - return &String{Value: strings.ToLower(s.Value)} + return NewString(strings.ToLower(s.Value)) }, }, "downcase!": ObjectMethod{ @@ -275,7 +279,7 @@ func init() { method: func(o Object, _ []Object) Object { s := o.(*String) s.Value = strings.ToLower(s.Value) - return &Null{} + return NULL }, }, "upcase": ObjectMethod{ @@ -287,7 +291,7 @@ func init() { }, method: func(o Object, _ []Object) Object { s := o.(*String) - return &String{Value: strings.ToUpper(s.Value)} + return NewString(strings.ToUpper(s.Value)) }, }, "upcase!": ObjectMethod{ @@ -305,7 +309,7 @@ func init() { method: func(o Object, _ []Object) Object { s := o.(*String) s.Value = strings.ToUpper(s.Value) - return &Null{} + return NULL }, }, } @@ -333,10 +337,10 @@ func (s *String) Next() (Object, Object, bool) { s.offset++ chars := []rune(s.Value) - val := &String{Value: string(chars[s.offset-1])} + val := NewString(string(chars[s.offset-1])) - return val, &Integer{Value: int64(s.offset - 1)}, true + return val, NewInteger(int64(s.offset - 1)), true } - return nil, &Integer{Value: 0}, false + return nil, NewInteger(0), false } diff --git a/object/string_test.go b/object/string_test.go index 87276be..08b3b85 100644 --- a/object/string_test.go +++ b/object/string_test.go @@ -1,8 +1,9 @@ package object_test import ( - "github.com/flipez/rocket-lang/object" "testing" + + "github.com/flipez/rocket-lang/object" ) func testStringObject(t *testing.T, obj object.Object, expected string) bool { @@ -82,10 +83,10 @@ func TestStringObjectMethods(t *testing.T) { } func TestStringHashKey(t *testing.T) { - hello1 := &object.String{Value: "Hello World"} - hello2 := &object.String{Value: "Hello World"} - diff1 := &object.String{Value: "My name is johnny"} - diff2 := &object.String{Value: "My name is johnny"} + hello1 := object.NewString("Hello World") + hello2 := object.NewString("Hello World") + diff1 := object.NewString("My name is johnny") + diff2 := object.NewString("My name is johnny") if hello1.HashKey() != hello2.HashKey() { t.Errorf("strings with same content have different hash keys") diff --git a/stdlib/exit.go b/stdlib/exit.go index 74afff0..be69ba7 100644 --- a/stdlib/exit.go +++ b/stdlib/exit.go @@ -8,10 +8,10 @@ import ( func exitFunction(args ...object.Object) object.Object { if len(args) != 1 { - return newError("wrong number of arguments. got=%d, want=1", len(args)) + return object.NewErrorFormat("wrong number of arguments. got=%d, want=1", len(args)) } if args[0].Type() != object.INTEGER_OBJ { - return newError("argument to `exit` must be INTEGER, got=%s", args[0].Type()) + return object.NewErrorFormat("argument to `exit` must be INTEGER, got=%s", args[0].Type()) } os.Exit(int(args[0].(*object.Integer).Value)) diff --git a/stdlib/open.go b/stdlib/open.go index e49034d..6e28f6b 100644 --- a/stdlib/open.go +++ b/stdlib/open.go @@ -10,14 +10,14 @@ func openFunction(args ...object.Object) object.Object { perm := "0644" if len(args) < 1 { - return newError("wrong number of arguments. got=%d, want=1", len(args)) + return object.NewErrorFormat("wrong number of arguments. got=%d, want=1", len(args)) } switch args[0].(type) { case *object.String: path = args[0].(*object.String).Value default: - return newError("argument to `file` not supported, got=%s", args[0].Type()) + return object.NewErrorFormat("argument to `file` not supported, got=%s", args[0].Type()) } if len(args) == 2 { @@ -25,7 +25,7 @@ func openFunction(args ...object.Object) object.Object { case *object.String: mode = args[1].(*object.String).Value default: - return newError("argument mode to `file` not supported, got=%s", args[1].Type()) + return object.NewErrorFormat("argument mode to `file` not supported, got=%s", args[1].Type()) } } @@ -34,14 +34,14 @@ func openFunction(args ...object.Object) object.Object { case *object.String: perm = args[2].(*object.String).Value default: - return newError("argument perm to `file` not supported, got=%s", args[2].Type()) + return object.NewErrorFormat("argument perm to `file` not supported, got=%s", args[2].Type()) } } - file := &object.File{Filename: path} + file := object.NewFile(path) err := file.Open(mode, perm) if err != nil { - return newError(err.Error()) + return object.NewErrorFormat(err.Error()) } return (file) } diff --git a/stdlib/raise.go b/stdlib/raise.go index 06c248d..4089aae 100644 --- a/stdlib/raise.go +++ b/stdlib/raise.go @@ -9,13 +9,13 @@ import ( func raiseFunction(args ...object.Object) object.Object { if len(args) != 2 { - return newError("wrong number of arguments. got=%d, want=2", len(args)) + return object.NewErrorFormat("wrong number of arguments. got=%d, want=2", len(args)) } if args[0].Type() != object.INTEGER_OBJ { - return newError("first argument to `raise` must be INTEGER, got=%s", args[0].Type()) + return object.NewErrorFormat("first argument to `raise` must be INTEGER, got=%s", args[0].Type()) } if args[1].Type() != object.STRING_OBJ { - return newError("second argument to `raise` must be STRING, got=%s", args[1].Type()) + return object.NewErrorFormat("second argument to `raise` must be STRING, got=%s", args[1].Type()) } fmt.Printf("🔥 RocketLang raised an error: %s\n", args[1].Inspect()) diff --git a/stdlib/std.go b/stdlib/std.go index ff30710..d0e470b 100644 --- a/stdlib/std.go +++ b/stdlib/std.go @@ -1,19 +1,11 @@ package stdlib import ( - "fmt" - "github.com/flipez/rocket-lang/object" ) var Builtins = map[string]*object.Builtin{} -var ( - TRUE = &object.Boolean{Value: true} - FALSE = &object.Boolean{Value: false} - NULL = &object.Null{} -) - func init() { RegisterFunction("puts", putsFunction) RegisterFunction("exit", exitFunction) @@ -22,9 +14,5 @@ func init() { } func RegisterFunction(name string, function object.BuiltinFunction) { - Builtins[name] = &object.Builtin{Fn: function} -} - -func newError(format string, a ...interface{}) *object.Error { - return &object.Error{Message: fmt.Sprintf(format, a...)} + Builtins[name] = object.NewBuiltin(name, function) }