diff --git a/docs/language_specification.txt b/docs/language_specification.txt deleted file mode 100644 index bfa71a2..0000000 --- a/docs/language_specification.txt +++ /dev/null @@ -1,86 +0,0 @@ -!true -!= -> -< ->= -<= -var five = 5; -var conta_0_L3Tr4as = "Other Variable"; -var pi = 3.1415; -var booleano = true; -var booleanoFalso = false; -var conta = five * pi; -var contaMetada = (conta / 2) - 10; - -function saySomething(name) { - return "Said: " + name; -} - -var println = function() { - return "Echo!!" -} - -saySomething("Hello " + name); - -if (five > 10) { - saySomething("Ups"); -} elseif (five == 10) { - saySomething("Its same"); -} else { - saySomething("All fine"); -} - -var statusCode = [200, 300, 400]; -var otherArray = [function () {}, "testing", 123.23, {"hello":"world"}]; - -if (statusCode[0] != 200) { - saySomething("200 status code"); -} - -var hashesResponse = {"nope":"an error happend", "ok":"everthing is ok"} - -for (index in statusCode) { - var item = statusCode[index]; -} - ------------------ -* * * * * * * * * - - -function add(x, y = 123) { - return x + y; -} - -class testing { - public construct() { - this.testing(); - this.do(10, 10); - } - - public call() { - } - - private testing() { - println("hello world"); - } - - protected do(x, y) { - return x + y; - } -} - -var a = new testing(); -a.call(); - -async { - -} - -* * * * * * - -Illegal or must be illegal - - -var testing = function add() { - return "1"; -} diff --git a/docs/todo.txt b/docs/todo.txt deleted file mode 100644 index 6267ed2..0000000 --- a/docs/todo.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Errors - -Case 1: -for(var i = 0; i <= len(b)-1; b = b +1) { puts(b[i]); } - -Case 2: -var a = "hello"; -if (a.type() == "STRING") { puts(a.split("")); } - diff --git a/evaluator/array_test.go b/evaluator/array_test.go index 2f499f0..4399f57 100644 --- a/evaluator/array_test.go +++ b/evaluator/array_test.go @@ -1,6 +1,7 @@ package evaluator import ( + "fmt" "ninja/object" "testing" ) @@ -330,46 +331,53 @@ func TestArrayMethodWrongUsage(t *testing.T) { input string expectedErrorMessage string }{ + { + `[].type(1)`, + "TypeError: array.type() takes exactly 0 argument (1 given)", + }, { `[].join([])`, - "array.join expect first argument be string. Got: ARRAY", + "TypeError: array.join() expected argument #1 to be `STRING` got `ARRAY`", }, { `[1].length(1)`, - "array.length not accept any arguments. got: [1]", + "TypeError: array.length() takes exactly 0 argument (1 given)", }, { `[].join()`, - "array.join expect exactly 1 argument. Got: 0", + "TypeError: array.join() takes exactly 1 argument (0 given)", }, { `[].push()`, - "array.push expect exactly 1 argument. Got: 0", + "TypeError: array.push() takes a minimum 1 arguments (0 given)", }, { `[1].pop(1)`, - "array.pop expect exactly 0 argument. Got: 1", + "TypeError: array.pop() takes exactly 0 argument (1 given)", }, { `[1].shift(1)`, - "array.shift expect exactly 0 argument. Got: 1", + "TypeError: array.shift() takes exactly 0 argument (1 given)", }, { `[1].slice(1, 2, 3)`, - `array.slice(start, offset) expected at least 1 argument and at max 2 arguments. Got: [1, 2, 3]`, + `TypeError: array.push() takes at least 1 arguments at most 2 (3 given)`, }, } - for _, tt := range tests { - evaluated := testEval(tt.input, t) + for i, tt := range tests { + t.Run(fmt.Sprintf("TestArrayMethodWrongUsage[%d]", i), func(t *testing.T) { + evaluated := testEval(tt.input, t) - errObj, ok := evaluated.(*object.Error) - if !ok { - t.Fatalf("no error object returned. got=%T(%+v)", evaluated, evaluated) - } + errObj, ok := evaluated.(*object.Error) + if !ok { + t.Fatalf("no error object returned. got=%T(%+v)", evaluated, evaluated) + } + + if errObj.Message != tt.expectedErrorMessage { + t.Errorf("erro expected \"%s\". Got: %s", tt.expectedErrorMessage, errObj.Message) + } + }) - if errObj.Message != tt.expectedErrorMessage { - t.Errorf("erro expected \"%s\". Got: %s", tt.expectedErrorMessage, errObj.Message) - } } } diff --git a/object/array.go b/object/array.go index 2f81fc1..86945c1 100644 --- a/object/array.go +++ b/object/array.go @@ -27,16 +27,26 @@ func (ao *Array) Inspect() string { func (s *Array) Call(objectCall *ast.ObjectCall, method string, env *Environment, args ...Object) Object { switch method { case "type": - if len(args) > 0 { - argStr := InspectObject(args...) - return NewErrorFormat("method type not accept any arguments. got: %s", argStr) + err := Check( + "array.type", args, + ExactArgs(0), + ) + + if err != nil { + return NewError(err.Error()) } + return &String{Value: ARRAY_OBJ} case "length": - if len(args) > 0 { - argStr := InspectObject(args...) - return NewErrorFormat("array.length not accept any arguments. got: %s", argStr) + err := Check( + "array.length", args, + ExactArgs(0), + ) + + if err != nil { + return NewError(err.Error()) } + return &Integer{Value: int64(len(s.Elements))} case "join": return arrayJoin(s.Elements, args...) @@ -72,15 +82,19 @@ func (s *Array) Call(objectCall *ast.ObjectCall, method string, env *Environment } func arrayJoin(elements []Object, args ...Object) Object { - if len(args) != 1 { - return NewErrorFormat("array.join expect exactly 1 argument. Got: %d", len(args)) - } - joinArgument, ok := args[0].(*String) - if !ok { - return NewErrorFormat("array.join expect first argument be string. Got: %s", args[0].Type()) + err := Check( + "array.join", args, + ExactArgs(1), + WithTypes(STRING_OBJ), + ) + + if err != nil { + return NewError(err.Error()) } + joinArgument, _ := args[0].(*String) + var out bytes.Buffer elementsString := []string{} for _, el := range elements { @@ -125,8 +139,13 @@ func arrayJoin(elements []Object, args ...Object) Object { } func arrayPush(elements []Object, args ...Object) Object { - if len(args) <= 0 { - return NewErrorFormat("array.push expect exactly 1 argument. Got: %d", len(args)) + err := Check( + "array.push", args, + MinimumArgs(1), + ) + + if err != nil { + return NewError(err.Error()) } arr := &Array{Elements: elements} @@ -139,8 +158,13 @@ func arrayPush(elements []Object, args ...Object) Object { } func arrayPop(elements []Object, args ...Object) (popValue Object, newArray Object) { - if len(args) > 0 { - return NewErrorFormat("array.pop expect exactly 0 argument. Got: %d", len(args)), nil + err := Check( + "array.pop", args, + ExactArgs(0), + ) + + if err != nil { + return NewError(err.Error()), nil } if len(elements) <= 0 { @@ -151,6 +175,15 @@ func arrayPop(elements []Object, args ...Object) (popValue Object, newArray Obje } func arrayShift(elements []Object, args ...Object) (shiftValue Object, newArray Object) { + err := Check( + "array.shift", args, + ExactArgs(0), + ) + + if err != nil { + return NewError(err.Error()), nil + } + if len(args) > 0 { return NewErrorFormat("array.shift expect exactly 0 argument. Got: %d", len(args)), nil } @@ -162,14 +195,17 @@ func arrayShift(elements []Object, args ...Object) (shiftValue Object, newArray } func arraySlice(elements []Object, args ...Object) Object { - if len(args) <= 0 || len(args) >= 3 { - return NewErrorFormat("array.slice(start, offset) expected at least 1 argument and at max 2 arguments. Got: %s", InspectObject(args...)) + err := Check( + "array.push", args, + RangeOfArgs(1, 2), + WithTypes(INTEGER_OBJ, INTEGER_OBJ), + ) + + if err != nil { + return NewError(err.Error()) } - start, ok := args[0].(*Integer) - if !ok { - return NewErrorFormat("array.slice(start, offset) first argument must be integer. Got: %s", args[0].Inspect()) - } + start, _ := args[0].(*Integer) maxLength := int64(len(elements)) offset := maxLength diff --git a/typing/typing.go b/object/typing.go similarity index 73% rename from typing/typing.go rename to object/typing.go index 8e6c18c..6054d9c 100644 --- a/typing/typing.go +++ b/object/typing.go @@ -1,14 +1,13 @@ -package typing +package object import ( "fmt" - "ninja/object" "strings" ) -type CheckFunc func(name string, args []object.Object) error +type CheckFunc func(name string, args []Object) error -func Check(name string, args []object.Object, checks ...CheckFunc) error { +func Check(name string, args []Object, checks ...CheckFunc) error { for _, check := range checks { if err := check(name, args); err != nil { return err @@ -18,7 +17,7 @@ func Check(name string, args []object.Object, checks ...CheckFunc) error { } func ExactArgs(n int) CheckFunc { - return func(name string, args []object.Object) error { + return func(name string, args []Object) error { if len(args) != n { return fmt.Errorf( "TypeError: %s() takes exactly %d argument (%d given)", @@ -29,7 +28,7 @@ func ExactArgs(n int) CheckFunc { } } func MinimumArgs(n int) CheckFunc { - return func(name string, args []object.Object) error { + return func(name string, args []Object) error { if len(args) < n { return fmt.Errorf( "TypeError: %s() takes a minimum %d arguments (%d given)", @@ -40,7 +39,7 @@ func MinimumArgs(n int) CheckFunc { } } func RangeOfArgs(n, m int) CheckFunc { - return func(name string, args []object.Object) error { + return func(name string, args []Object) error { if len(args) < n || len(args) > m { return fmt.Errorf( "TypeError: %s() takes at least %d arguments at most %d (%d given)", @@ -50,8 +49,8 @@ func RangeOfArgs(n, m int) CheckFunc { return nil } } -func WithTypes(types ...object.ObjectType) CheckFunc { - return func(name string, args []object.Object) error { +func WithTypes(types ...ObjectType) CheckFunc { + return func(name string, args []Object) error { for i, t := range types { if i < len(args) && args[i].Type() != t { return fmt.Errorf( @@ -64,8 +63,8 @@ func WithTypes(types ...object.ObjectType) CheckFunc { } } -func OneOfType(types ...object.ObjectType) CheckFunc { - return func(name string, args []object.Object) error { +func OneOfType(types ...ObjectType) CheckFunc { + return func(name string, args []Object) error { for _, vt := range types { for _, va := range args { if va.Type() == vt { diff --git a/stdlib/args.go b/stdlib/args.go index 859aa67..cfdbe0c 100644 --- a/stdlib/args.go +++ b/stdlib/args.go @@ -2,14 +2,13 @@ package stdlib import ( "ninja/object" - "ninja/typing" ) func Args(args ...object.Object) object.Object { - err := typing.Check( + err := object.Check( "args", args, - typing.ExactArgs(0), + object.ExactArgs(0), ) if err != nil { diff --git a/stdlib/first.go b/stdlib/first.go index 3097fa5..ffcdef4 100644 --- a/stdlib/first.go +++ b/stdlib/first.go @@ -2,16 +2,15 @@ package stdlib import ( "ninja/object" - "ninja/typing" ) func First(args ...object.Object) object.Object { - err := typing.Check( + err := object.Check( "first", args, - typing.ExactArgs(1), - typing.WithTypes(object.ARRAY_OBJ), - ); + object.ExactArgs(1), + object.WithTypes(object.ARRAY_OBJ), + ) if err != nil { return object.NewError(err.Error()) diff --git a/stdlib/last.go b/stdlib/last.go index 4ee6433..c7dd30d 100644 --- a/stdlib/last.go +++ b/stdlib/last.go @@ -2,15 +2,14 @@ package stdlib import ( "ninja/object" - "ninja/typing" ) func Last(args ...object.Object) object.Object { - err := typing.Check( + err := object.Check( "last", args, - typing.ExactArgs(1), - typing.WithTypes(object.ARRAY_OBJ), + object.ExactArgs(1), + object.WithTypes(object.ARRAY_OBJ), ) if err != nil { diff --git a/stdlib/len.go b/stdlib/len.go index 5a74753..789bef3 100644 --- a/stdlib/len.go +++ b/stdlib/len.go @@ -2,15 +2,14 @@ package stdlib import ( "ninja/object" - "ninja/typing" ) func Len(args ...object.Object) object.Object { - err := typing.Check( + err := object.Check( "len", args, - typing.ExactArgs(1), - typing.OneOfType(object.ARRAY_OBJ, object.STRING_OBJ), + object.ExactArgs(1), + object.OneOfType(object.ARRAY_OBJ, object.STRING_OBJ), ) if err != nil { diff --git a/stdlib/push.go b/stdlib/push.go index 52d590c..d332ea9 100644 --- a/stdlib/push.go +++ b/stdlib/push.go @@ -2,15 +2,14 @@ package stdlib import ( "ninja/object" - "ninja/typing" ) func Push(args ...object.Object) object.Object { - err := typing.Check( + err := object.Check( "push", args, - typing.ExactArgs(2), - typing.WithTypes(object.ARRAY_OBJ), + object.ExactArgs(2), + object.WithTypes(object.ARRAY_OBJ), ) if err != nil { diff --git a/stdlib/rand.go b/stdlib/rand.go index f8c146b..08072f4 100644 --- a/stdlib/rand.go +++ b/stdlib/rand.go @@ -3,13 +3,12 @@ package stdlib import ( "math/rand" "ninja/object" - "ninja/typing" ) func Rand(args ...object.Object) object.Object { - err := typing.Check( + err := object.Check( "rand", args, - typing.ExactArgs(0), + object.ExactArgs(0), ) if err != nil { diff --git a/stdlib/rest.go b/stdlib/rest.go index 90a1fc0..fbeba35 100644 --- a/stdlib/rest.go +++ b/stdlib/rest.go @@ -2,15 +2,14 @@ package stdlib import ( "ninja/object" - "ninja/typing" ) func Rest(args ...object.Object) object.Object { - err := typing.Check( + err := object.Check( "first", args, - typing.ExactArgs(1), - typing.WithTypes(object.ARRAY_OBJ), + object.ExactArgs(1), + object.WithTypes(object.ARRAY_OBJ), ) if err != nil { diff --git a/stdlib/time.go b/stdlib/time.go index faffb96..4c5f25f 100644 --- a/stdlib/time.go +++ b/stdlib/time.go @@ -2,14 +2,13 @@ package stdlib import ( "ninja/object" - "ninja/typing" "time" ) func Time(args ...object.Object) object.Object { - err := typing.Check( + err := object.Check( "first", args, - typing.ExactArgs(0), + object.ExactArgs(0), ) if err != nil {