Skip to content

Commit

Permalink
handle with zero or only one args for command object in evaluator (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
JunNishimura committed Sep 29, 2024
1 parent b14af0f commit b8e358a
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 78 deletions.
156 changes: 98 additions & 58 deletions evaluator/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import "github.com/JunNishimura/jsop/object"

var builtins = map[string]*object.Builtin{
"+": {
Fn: func(args ...object.Object) object.Object {
if len(args) == 0 {
return newError("number of arguments to '+' must be more than 0, got %d", len(args))
Fn: func(args object.Object) object.Object {
arrayArg, ok := args.(*object.Array)
if !ok {
return newError("argument to '+' must be ARRAY, got %s", args.Type())
}
if len(arrayArg.Elements) == 0 {
return newError("number of arguments to '+' must be more than 0, got %d", len(arrayArg.Elements))
}

var result int64
for _, arg := range args {
for _, arg := range arrayArg.Elements {
if arg.Type() != object.INTEGER_OBJ {
return newError("argument to '+' must be INTEGER, got %s", arg.Type())
}
Expand All @@ -20,13 +24,17 @@ var builtins = map[string]*object.Builtin{
},
},
"-": {
Fn: func(args ...object.Object) object.Object {
if len(args) <= 1 {
return newError("number of arguments to '-' must be more than 1, got %d", len(args))
Fn: func(args object.Object) object.Object {
arrayArg, ok := args.(*object.Array)
if !ok {
return newError("argument to '-' must be ARRAY, got %s", args.Type())
}
if len(arrayArg.Elements) <= 1 {
return newError("number of arguments to '-' must be more than 1, got %d", len(arrayArg.Elements))
}

var result int64
for i, arg := range args {
for i, arg := range arrayArg.Elements {
if arg.Type() != object.INTEGER_OBJ {
return newError("argument to '-' must be INTEGER, got %s", arg.Type())
}
Expand All @@ -41,13 +49,17 @@ var builtins = map[string]*object.Builtin{
},
},
"*": {
Fn: func(args ...object.Object) object.Object {
if len(args) == 0 {
return newError("number of arguments to '*' must be more than 0, got %d", len(args))
Fn: func(args object.Object) object.Object {
arrayArg, ok := args.(*object.Array)
if !ok {
return newError("argument to '*' must be ARRAY, got %s", args.Type())
}
if len(arrayArg.Elements) == 0 {
return newError("number of arguments to '*' must be more than 0, got %d", len(arrayArg.Elements))
}

var result int64 = 1
for _, arg := range args {
for _, arg := range arrayArg.Elements {
if arg.Type() != object.INTEGER_OBJ {
return newError("argument to '*' must be INTEGER, got %s", arg.Type())
}
Expand All @@ -58,13 +70,17 @@ var builtins = map[string]*object.Builtin{
},
},
"/": {
Fn: func(args ...object.Object) object.Object {
if len(args) <= 1 {
return newError("number of arguments to '/' must be more than 1, got %d", len(args))
Fn: func(args object.Object) object.Object {
arrayArg, ok := args.(*object.Array)
if !ok {
return newError("argument to '/' must be ARRAY, got %s", args.Type())
}
if len(arrayArg.Elements) <= 1 {
return newError("number of arguments to '/' must be more than 1, got %d", len(arrayArg.Elements))
}

var result int64
for i, arg := range args {
for i, arg := range arrayArg.Elements {
if arg.Type() != object.INTEGER_OBJ {
return newError("argument to '/' must be INTEGER, got %s", arg.Type())
}
Expand All @@ -82,13 +98,17 @@ var builtins = map[string]*object.Builtin{
},
},
"==": {
Fn: func(args ...object.Object) object.Object {
if len(args) <= 1 {
return newError("number of arguments to '=' must be more than 1, got %d", len(args))
Fn: func(args object.Object) object.Object {
arrayArg, ok := args.(*object.Array)
if !ok {
return newError("argument to '==' must be ARRAY, got %s", args.Type())
}
if len(arrayArg.Elements) <= 1 {
return newError("number of arguments to '=' must be more than 1, got %d", len(arrayArg.Elements))
}

for i := 0; i < len(args)-1; i++ {
if args[i] != args[i+1] {
for i := 0; i < len(arrayArg.Elements)-1; i++ {
if arrayArg.Elements[i] != arrayArg.Elements[i+1] {
return False
}
}
Expand All @@ -97,13 +117,17 @@ var builtins = map[string]*object.Builtin{
},
},
"!=": {
Fn: func(args ...object.Object) object.Object {
if len(args) <= 1 {
return newError("number of arguments to '!=' must be more than 1, got %d", len(args))
Fn: func(args object.Object) object.Object {
arrayArg, ok := args.(*object.Array)
if !ok {
return newError("argument to '!=' must be ARRAY, got %s", args.Type())
}
if len(arrayArg.Elements) <= 1 {
return newError("number of arguments to '!=' must be more than 1, got %d", len(arrayArg.Elements))
}

for i := 0; i < len(args)-1; i++ {
if args[i] != args[i+1] {
for i := 0; i < len(arrayArg.Elements)-1; i++ {
if arrayArg.Elements[i] != arrayArg.Elements[i+1] {
return True
}
}
Expand All @@ -112,19 +136,23 @@ var builtins = map[string]*object.Builtin{
},
},
">": {
Fn: func(args ...object.Object) object.Object {
if len(args) <= 1 {
return newError("number of arguments to '>' must be more than 1, got %d", len(args))
Fn: func(args object.Object) object.Object {
arrayArg, ok := args.(*object.Array)
if !ok {
return newError("argument to '>' must be ARRAY, got %s", args.Type())
}
if len(arrayArg.Elements) <= 1 {
return newError("number of arguments to '>' must be more than 1, got %d", len(arrayArg.Elements))
}

for i := 0; i < len(args)-1; i++ {
first, ok := args[i].(*object.Integer)
for i := 0; i < len(arrayArg.Elements)-1; i++ {
first, ok := arrayArg.Elements[i].(*object.Integer)
if !ok {
return newError("argument to '>' must be INTEGER, got %s", args[i].Type())
return newError("argument to '>' must be INTEGER, got %s", arrayArg.Elements[i].Type())
}
second, ok := args[i+1].(*object.Integer)
second, ok := arrayArg.Elements[i+1].(*object.Integer)
if !ok {
return newError("argument to '>' must be INTEGER, got %s", args[i+1].Type())
return newError("argument to '>' must be INTEGER, got %s", arrayArg.Elements[i+1].Type())
}
if first.Value <= second.Value {
return False
Expand All @@ -135,19 +163,23 @@ var builtins = map[string]*object.Builtin{
},
},
"<": {
Fn: func(args ...object.Object) object.Object {
if len(args) <= 1 {
return newError("number of arguments to '<' must be more than 1, got %d", len(args))
Fn: func(args object.Object) object.Object {
arrayArg, ok := args.(*object.Array)
if !ok {
return newError("argument to '<' must be ARRAY, got %s", args.Type())
}
if len(arrayArg.Elements) <= 1 {
return newError("number of arguments to '<' must be more than 1, got %d", len(arrayArg.Elements))
}

for i := 0; i < len(args)-1; i++ {
first, ok := args[i].(*object.Integer)
for i := 0; i < len(arrayArg.Elements)-1; i++ {
first, ok := arrayArg.Elements[i].(*object.Integer)
if !ok {
return newError("argument to '<' must be INTEGER, got %s", args[i].Type())
return newError("argument to '<' must be INTEGER, got %s", arrayArg.Elements[i].Type())
}
second, ok := args[i+1].(*object.Integer)
second, ok := arrayArg.Elements[i+1].(*object.Integer)
if !ok {
return newError("argument to '<' must be INTEGER, got %s", args[i+1].Type())
return newError("argument to '<' must be INTEGER, got %s", arrayArg.Elements[i+1].Type())
}
if first.Value >= second.Value {
return False
Expand All @@ -158,19 +190,23 @@ var builtins = map[string]*object.Builtin{
},
},
">=": {
Fn: func(args ...object.Object) object.Object {
if len(args) <= 1 {
return newError("number of arguments to '>=' must be more than 1, got %d", len(args))
Fn: func(args object.Object) object.Object {
arrayArg, ok := args.(*object.Array)
if !ok {
return newError("argument to '>=' must be ARRAY, got %s", args.Type())
}
if len(arrayArg.Elements) <= 1 {
return newError("number of arguments to '>=' must be more than 1, got %d", len(arrayArg.Elements))
}

for i := 0; i < len(args)-1; i++ {
first, ok := args[i].(*object.Integer)
for i := 0; i < len(arrayArg.Elements)-1; i++ {
first, ok := arrayArg.Elements[i].(*object.Integer)
if !ok {
return newError("argument to '>=' must be INTEGER, got %s", args[i].Type())
return newError("argument to '>=' must be INTEGER, got %s", arrayArg.Elements[i].Type())
}
second, ok := args[i+1].(*object.Integer)
second, ok := arrayArg.Elements[i+1].(*object.Integer)
if !ok {
return newError("argument to '>=' must be INTEGER, got %s", args[i+1].Type())
return newError("argument to '>=' must be INTEGER, got %s", arrayArg.Elements[i+1].Type())
}
if first.Value < second.Value {
return False
Expand All @@ -181,19 +217,23 @@ var builtins = map[string]*object.Builtin{
},
},
"<=": {
Fn: func(args ...object.Object) object.Object {
if len(args) <= 1 {
return newError("number of arguments to '<=' must be more than 1, got %d", len(args))
Fn: func(args object.Object) object.Object {
arrayArg, ok := args.(*object.Array)
if !ok {
return newError("argument to '<=' must be ARRAY, got %s", args.Type())
}
if len(arrayArg.Elements) <= 1 {
return newError("number of arguments to '<=' must be more than 1, got %d", len(arrayArg.Elements))
}

for i := 0; i < len(args)-1; i++ {
first, ok := args[i].(*object.Integer)
for i := 0; i < len(arrayArg.Elements)-1; i++ {
first, ok := arrayArg.Elements[i].(*object.Integer)
if !ok {
return newError("argument to '<=' must be INTEGER, got %s", args[i].Type())
return newError("argument to '<=' must be INTEGER, got %s", arrayArg.Elements[i].Type())
}
second, ok := args[i+1].(*object.Integer)
second, ok := arrayArg.Elements[i+1].(*object.Integer)
if !ok {
return newError("argument to '<=' must be INTEGER, got %s", args[i+1].Type())
return newError("argument to '<=' must be INTEGER, got %s", arrayArg.Elements[i+1].Type())
}
if first.Value > second.Value {
return False
Expand Down
24 changes: 5 additions & 19 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,32 +128,18 @@ func evalCommandObject(command *ast.CommandObject, env *object.Environment) obje
return symbol
}

args := evalArgs(command.Args, env)
if len(args) == 1 && isError(args[0]) {
return args[0]
args := Eval(command.Args, env)
if isError(args) {
return args
}

return applyFunction(symbol, args)
}

func evalArgs(args []ast.Expression, env *object.Environment) []object.Object {
var result []object.Object

for _, arg := range args {
evaluated := Eval(arg, env)
if isError(evaluated) {
return []object.Object{evaluated}
}
result = append(result, evaluated)
}

return result
}

func applyFunction(function object.Object, args []object.Object) object.Object {
func applyFunction(function object.Object, args object.Object) object.Object {
switch funcType := function.(type) {
case *object.Builtin:
return funcType.Fn(args...)
return funcType.Fn(args)
default:
return newError("not a function: %s", function.Type())
}
Expand Down
2 changes: 1 addition & 1 deletion object/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type Error struct {
func (e *Error) Type() ObjectType { return ERROR_OBJ }
func (e *Error) Inspect() string { return "ERROR: " + e.Message }

type BuiltinFunction func(args ...Object) Object
type BuiltinFunction func(args Object) Object

type Builtin struct {
Fn BuiltinFunction
Expand Down

0 comments on commit b8e358a

Please sign in to comment.