diff --git a/evaluator/builtins.go b/evaluator/builtins.go deleted file mode 100644 index 79a588a..0000000 --- a/evaluator/builtins.go +++ /dev/null @@ -1,97 +0,0 @@ -package evaluator - -import ( - "fmt" - "github.com/flipez/rocket-lang/object" - "os" -) - -var builtins = map[string]*object.Builtin{ - "len": &object.Builtin{ - Fn: func(args ...object.Object) object.Object { - if len(args) != 1 { - return newError("wrong number of arguments. got=%d, want=1", len(args)) - } - - switch arg := args[0].(type) { - case *object.Array: - return &object.Integer{Value: int64(len(arg.Elements))} - case *object.String: - return &object.Integer{Value: int64(len(arg.Value))} - default: - return newError("argument to `len` not supported, got %s", args[0].Type()) - } - }, - }, - "puts": &object.Builtin{ - Fn: func(args ...object.Object) object.Object { - for _, arg := range args { - fmt.Println(arg.Inspect()) - } - - return nil - }, - }, - "exit": &object.Builtin{ - Fn: func(args ...object.Object) object.Object { - if len(args) != 1 { - return newError("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()) - } - - os.Exit(int(args[0].(*object.Integer).Value)) - - return nil - }, - }, - "raise": &object.Builtin{ - Fn: func(args ...object.Object) object.Object { - if len(args) != 2 { - return newError("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()) - } - if args[1].Type() != object.STRING_OBJ { - return newError("second argument to `raise` must be STRING, got=%s", args[1].Type()) - } - - fmt.Printf("🔥 RocketLang raised an error: %s\n", args[1].Inspect()) - os.Exit(int(args[0].(*object.Integer).Value)) - - return nil - }, - }, - "open": &object.Builtin{ - Fn: func(args ...object.Object) object.Object { - path := "" - mode := "r" - - if len(args) < 1 { - return newError("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()) - } - - if len(args) > 1 { - switch args[1].(type) { - case *object.String: - mode = args[1].(*object.String).Value - default: - return newError("argument mode to `file` not supported, got=%s", args[1].Type()) - } - } - - file := &object.File{Filename: path} - file.Open(mode) - return (file) - }, - }, -} diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index 16ee96b..f52aafc 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -3,6 +3,7 @@ package evaluator import ( "github.com/flipez/rocket-lang/ast" "github.com/flipez/rocket-lang/object" + "github.com/flipez/rocket-lang/stdlib" "fmt" ) @@ -246,7 +247,7 @@ func evalIdentifier(node *ast.Identifier, env *object.Environment) object.Object return val } - if builtin, ok := builtins[node.Value]; ok { + if builtin, ok := stdlib.Builtins[node.Value]; ok { return builtin } diff --git a/object/builtin.go b/object/builtin.go index 285db4e..b9ef010 100644 --- a/object/builtin.go +++ b/object/builtin.go @@ -1,9 +1,12 @@ package object type Builtin struct { - Fn func(args ...Object) Object + Name string + Fn BuiltinFunction } +type BuiltinFunction func(args ...Object) Object + func (b *Builtin) Type() ObjectType { return BUILTIN_OBJ } func (b *Builtin) Inspect() string { return "builtin function" } func (b *Builtin) InvokeMethod(method string, env Environment, args ...Object) Object { return nil } diff --git a/stdlib/exit.go b/stdlib/exit.go new file mode 100644 index 0000000..74afff0 --- /dev/null +++ b/stdlib/exit.go @@ -0,0 +1,20 @@ +package stdlib + +import ( + "os" + + "github.com/flipez/rocket-lang/object" +) + +func exitFunction(args ...object.Object) object.Object { + if len(args) != 1 { + return newError("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()) + } + + os.Exit(int(args[0].(*object.Integer).Value)) + + return nil +} diff --git a/stdlib/len.go b/stdlib/len.go new file mode 100644 index 0000000..6977b41 --- /dev/null +++ b/stdlib/len.go @@ -0,0 +1,20 @@ +package stdlib + +import ( + "github.com/flipez/rocket-lang/object" +) + +func lenFunction(args ...object.Object) object.Object { + if len(args) != 1 { + return newError("wrong number of arguments. got=%d, want=1", len(args)) + } + + switch arg := args[0].(type) { + case *object.Array: + return &object.Integer{Value: int64(len(arg.Elements))} + case *object.String: + return &object.Integer{Value: int64(len(arg.Value))} + default: + return newError("argument to `len` not supported, got %s", args[0].Type()) + } +} diff --git a/stdlib/open.go b/stdlib/open.go new file mode 100644 index 0000000..deabcc6 --- /dev/null +++ b/stdlib/open.go @@ -0,0 +1,34 @@ +package stdlib + +import ( + "github.com/flipez/rocket-lang/object" +) + +func openFunction(args ...object.Object) object.Object { + path := "" + mode := "r" + + if len(args) < 1 { + return newError("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()) + } + + if len(args) > 1 { + switch args[1].(type) { + case *object.String: + mode = args[1].(*object.String).Value + default: + return newError("argument mode to `file` not supported, got=%s", args[1].Type()) + } + } + + file := &object.File{Filename: path} + file.Open(mode) + return (file) +} diff --git a/stdlib/puts.go b/stdlib/puts.go new file mode 100644 index 0000000..ca99c13 --- /dev/null +++ b/stdlib/puts.go @@ -0,0 +1,15 @@ +package stdlib + +import ( + "fmt" + + "github.com/flipez/rocket-lang/object" +) + +func putsFunction(args ...object.Object) object.Object { + for _, arg := range args { + fmt.Println(arg.Inspect()) + } + + return nil +} diff --git a/stdlib/raise.go b/stdlib/raise.go new file mode 100644 index 0000000..06c248d --- /dev/null +++ b/stdlib/raise.go @@ -0,0 +1,25 @@ +package stdlib + +import ( + "fmt" + "os" + + "github.com/flipez/rocket-lang/object" +) + +func raiseFunction(args ...object.Object) object.Object { + if len(args) != 2 { + return newError("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()) + } + if args[1].Type() != object.STRING_OBJ { + return newError("second argument to `raise` must be STRING, got=%s", args[1].Type()) + } + + fmt.Printf("🔥 RocketLang raised an error: %s\n", args[1].Inspect()) + os.Exit(int(args[0].(*object.Integer).Value)) + + return nil +} diff --git a/stdlib/std.go b/stdlib/std.go new file mode 100644 index 0000000..343f3e1 --- /dev/null +++ b/stdlib/std.go @@ -0,0 +1,31 @@ +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("len", lenFunction) + RegisterFunction("puts", putsFunction) + RegisterFunction("exit", exitFunction) + RegisterFunction("raise", raiseFunction) + RegisterFunction("open", openFunction) +} + +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...)} +}