made arity checking a little saner

master
Jordan Orelli 12 years ago
parent 3bd216c75b
commit ee6c15a90f

@ -40,3 +40,5 @@ x
(define plusone (lambda (x) (+ x 1))) (define plusone (lambda (x) (+ x 1)))
(plusone 1) (plusone 1)
((lambda (x) (* x x)) 4)

@ -8,25 +8,38 @@ import (
type special func(*environment, ...interface{}) (interface{}, error) type special func(*environment, ...interface{}) (interface{}, error)
type nargsInvalidError struct { type arityError struct {
expected int expected int
received int received int
name string name string
} }
func (n nargsInvalidError) Error() string { func (n arityError) Error() string {
return fmt.Sprintf(`received %d arguments in *%v*, expected %d`, return fmt.Sprintf(`received %d arguments in *%v*, expected %d`,
n.received, n.name, n.expected) n.received, n.name, n.expected)
} }
func checkArity(arity int, args []interface{}, name string) error {
if args == nil {
if arity == 0 {
return nil
}
return arityError{arity, 0, name}
}
if len(args) != arity {
return arityError{arity, len(args), name}
}
return nil
}
// defines the built-in "define" construct. e.g.: // defines the built-in "define" construct. e.g.:
// //
// (define x 5) // (define x 5)
// //
// would create the symbol "x" and set its value to 5. // would create the symbol "x" and set its value to 5.
func define(env *environment, args ...interface{}) (interface{}, error) { func define(env *environment, args ...interface{}) (interface{}, error) {
if len(args) != 2 { if err := checkArity(2, args, "define"); err != nil {
return nil, nargsInvalidError{2, len(args), "define"} return nil, err
} }
s, ok := args[0].(symbol) s, ok := args[0].(symbol)
@ -51,8 +64,8 @@ func define(env *environment, args ...interface{}) (interface{}, error) {
// that is effectively a no-op; the input value is not evaluated, which // that is effectively a no-op; the input value is not evaluated, which
// prevents evaluation of the first element of the list, in this case 1. // prevents evaluation of the first element of the list, in this case 1.
func quote(_ *environment, args ...interface{}) (interface{}, error) { func quote(_ *environment, args ...interface{}) (interface{}, error) {
if len(args) != 1 { if err := checkArity(1, args, "quote"); err != nil {
return nil, nargsInvalidError{1, len(args), "quote"} return nil, err
} }
return args[0], nil return args[0], nil
@ -68,8 +81,8 @@ func quote(_ *environment, args ...interface{}) (interface{}, error) {
// //
// would evaluate to "bar" // would evaluate to "bar"
func _if(env *environment, args ...interface{}) (interface{}, error) { func _if(env *environment, args ...interface{}) (interface{}, error) {
if len(args) != 3 { if err := checkArity(3, args, "if"); err != nil {
return nil, nargsInvalidError{3, len(args), "if"} return nil, err
} }
v, err := eval(args[0], env) v, err := eval(args[0], env)
@ -91,8 +104,8 @@ func _if(env *environment, args ...interface{}) (interface{}, error) {
// would set the symbol x to the value 5, if and only if the symbol x was // would set the symbol x to the value 5, if and only if the symbol x was
// previously defined. // previously defined.
func set(env *environment, args ...interface{}) (interface{}, error) { func set(env *environment, args ...interface{}) (interface{}, error) {
if len(args) != 2 { if err := checkArity(2, args, "set!"); err != nil {
return nil, nargsInvalidError{2, len(args), "set!"} return nil, err
} }
s, ok := args[0].(symbol) s, ok := args[0].(symbol)
@ -149,8 +162,8 @@ func (l lambda) call(env *environment, rawArgs []interface{}) (interface{}, erro
// would evaluate to a lambda that, when executed, squares its input. // would evaluate to a lambda that, when executed, squares its input.
func mklambda(env *environment, args ...interface{}) (interface{}, error) { func mklambda(env *environment, args ...interface{}) (interface{}, error) {
debugPrint("mklambda") debugPrint("mklambda")
if len(args) != 2 { if err := checkArity(2, args, "lambda"); err != nil {
return nil, nargsInvalidError{2, len(args), "lambda"} return nil, err
} }
params, ok := args[0].(sexp) params, ok := args[0].(sexp)

Loading…
Cancel
Save