Skip to content

Commit

Permalink
cleanup some internals check for array method call
Browse files Browse the repository at this point in the history
  • Loading branch information
gravataLonga committed Jul 3, 2022
1 parent 6ad5188 commit 29152eb
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 174 deletions.
86 changes: 0 additions & 86 deletions docs/language_specification.txt

This file was deleted.

9 changes: 0 additions & 9 deletions docs/todo.txt

This file was deleted.

40 changes: 24 additions & 16 deletions evaluator/array_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package evaluator

import (
"fmt"
"ninja/object"
"testing"
)
Expand Down Expand Up @@ -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)
}
}
}
80 changes: 58 additions & 22 deletions object/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -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...)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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}
Expand All @@ -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 {
Expand All @@ -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
}
Expand All @@ -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
Expand Down
21 changes: 10 additions & 11 deletions typing/typing.go → object/typing.go
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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)",
Expand All @@ -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)",
Expand All @@ -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)",
Expand All @@ -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(
Expand All @@ -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 {
Expand Down
5 changes: 2 additions & 3 deletions stdlib/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit 29152eb

Please sign in to comment.