diff --git a/doc/site/core/fn.markdown b/doc/site/core/fn.markdown index 5bd2358a..1491a881 100644 --- a/doc/site/core/fn.markdown +++ b/doc/site/core/fn.markdown @@ -18,6 +18,14 @@ you create a "bare" function when you don't want to immediately pass it as a It is a runtime error if `block` is not a function. +### **arity** + +The number of arguments the function requires. + + :::dart + IO.print(new Fn {}.arity) // 0. + IO.print(new Fn {|a, b, c| a }.arity) // 3. + ### **call**(args...) **TODO** diff --git a/doc/site/functions.markdown b/doc/site/functions.markdown index d828802d..7a4fe7f1 100644 --- a/doc/site/functions.markdown +++ b/doc/site/functions.markdown @@ -115,8 +115,8 @@ Here we're passing a function to `greet` that takes two parameters, `first` and } } -It's an error to call a function with fewer or more arguments than its -parameter list expects. +It's an error to call a function with fewer arguments than its parameter list +expects. If you pass too *many* arguments, the extras are ignored. ## Returning values diff --git a/include/wren.h b/include/wren.h index 787b5266..5739b930 100644 --- a/include/wren.h +++ b/include/wren.h @@ -97,11 +97,11 @@ WrenInterpretResult wrenInterpret(WrenVM* vm, const char* sourcePath, // global class named [className] to bind the method to. If not found, it will // be created automatically. // -// Defines a method on that class named [methodName] accepting [numParams] +// Defines a method on that class named [methodName] accepting [arity] // parameters. If a method already exists with that name and arity, it will be // replaced. When invoked, the method will call [method]. void wrenDefineMethod(WrenVM* vm, const char* className, - const char* methodName, int numParams, + const char* methodName, int arity, WrenForeignMethodFn method); // Defines a static foreign method implemented by the host application. Looks @@ -109,10 +109,10 @@ void wrenDefineMethod(WrenVM* vm, const char* className, // will be created automatically. // // Defines a static method on that class named [methodName] accepting -// [numParams] parameters. If a method already exists with that name and arity, +// [arity] parameters. If a method already exists with that name and arity, // it will be replaced. When invoked, the method will call [method]. void wrenDefineStaticMethod(WrenVM* vm, const char* className, - const char* methodName, int numParams, + const char* methodName, int arity, WrenForeignMethodFn method); // The following functions read one of the arguments passed to a foreign call. diff --git a/src/wren_core.c b/src/wren_core.c index d1601b39..b551f701 100644 --- a/src/wren_core.c +++ b/src/wren_core.c @@ -489,23 +489,6 @@ DEF_NATIVE(fiber_yield1) return PRIM_RUN_FIBER; } -static PrimitiveResult callFunction(WrenVM* vm, Value* args, int numArgs) -{ - ObjFn* fn; - if (IS_CLOSURE(args[0])) - { - fn = AS_CLOSURE(args[0])->fn; - } - else - { - fn = AS_FN(args[0]); - } - - if (numArgs < fn->numParams) RETURN_ERROR("Function expects more arguments."); - - return PRIM_CALL; -} - DEF_NATIVE(fn_instantiate) { // Return the Fn class itself. When we then call "new" on it, it will @@ -521,6 +504,28 @@ DEF_NATIVE(fn_new) RETURN_VAL(args[1]); } +DEF_NATIVE(fn_arity) +{ + RETURN_NUM(AS_FN(args[0])->arity); +} + +static PrimitiveResult callFunction(WrenVM* vm, Value* args, int numArgs) +{ + ObjFn* fn; + if (IS_CLOSURE(args[0])) + { + fn = AS_CLOSURE(args[0])->fn; + } + else + { + fn = AS_FN(args[0]); + } + + if (numArgs < fn->arity) RETURN_ERROR("Function expects more arguments."); + + return PRIM_CALL; +} + DEF_NATIVE(fn_call0) { return callFunction(vm, args, 0); } DEF_NATIVE(fn_call1) { return callFunction(vm, args, 1); } DEF_NATIVE(fn_call2) { return callFunction(vm, args, 2); } @@ -1245,6 +1250,7 @@ void wrenInitializeCore(WrenVM* vm) NATIVE(vm->fnClass->obj.classObj, " instantiate", fn_instantiate); NATIVE(vm->fnClass->obj.classObj, "new ", fn_new); + NATIVE(vm->fnClass, "arity", fn_arity); NATIVE(vm->fnClass, "call", fn_call0); NATIVE(vm->fnClass, "call ", fn_call1); NATIVE(vm->fnClass, "call ", fn_call2); @@ -1262,7 +1268,6 @@ void wrenInitializeCore(WrenVM* vm) NATIVE(vm->fnClass, "call ", fn_call14); NATIVE(vm->fnClass, "call ", fn_call15); NATIVE(vm->fnClass, "call ", fn_call16); - // TODO: "arity" getter. NATIVE(vm->fnClass, "toString", fn_toString); vm->nullClass = defineClass(vm, "Null"); diff --git a/src/wren_value.c b/src/wren_value.c index bcab27a5..8595e534 100644 --- a/src/wren_value.c +++ b/src/wren_value.c @@ -160,7 +160,7 @@ ObjFiber* wrenNewFiber(WrenVM* vm, Obj* fn) } ObjFn* wrenNewFunction(WrenVM* vm, Value* constants, int numConstants, - int numUpvalues, int numParams, + int numUpvalues, int arity, uint8_t* bytecode, int bytecodeLength, ObjString* debugSourcePath, const char* debugName, int debugNameLength, @@ -200,7 +200,7 @@ ObjFn* wrenNewFunction(WrenVM* vm, Value* constants, int numConstants, fn->constants = copiedConstants; fn->numUpvalues = numUpvalues; fn->numConstants = numConstants; - fn->numParams = numParams; + fn->arity = arity; fn->bytecodeLength = bytecodeLength; fn->debug = debug; diff --git a/src/wren_value.h b/src/wren_value.h index a29a0290..16c0f964 100644 --- a/src/wren_value.h +++ b/src/wren_value.h @@ -246,7 +246,7 @@ typedef struct // The number of parameters this function expects. Used to ensure that .call // handles a mismatch between number of parameters and arguments. This will // only be set for fns, and not ObjFns that represent methods or scripts. - int numParams; + int arity; FnDebug* debug; } ObjFn; @@ -571,7 +571,7 @@ ObjFiber* wrenNewFiber(WrenVM* vm, Obj* fn); // function will take over ownership of [bytecode] and [sourceLines]. It will // copy [constants] into its own array. ObjFn* wrenNewFunction(WrenVM* vm, Value* constants, int numConstants, - int numUpvalues, int numParams, + int numUpvalues, int arity, uint8_t* bytecode, int bytecodeLength, ObjString* debugSourcePath, const char* debugName, int debugNameLength, diff --git a/test/function/arity.wren b/test/function/arity.wren new file mode 100644 index 00000000..9e6047e4 --- /dev/null +++ b/test/function/arity.wren @@ -0,0 +1,5 @@ +IO.print(new Fn {}.arity) // expect: 0 +IO.print(new Fn {|a| a}.arity) // expect: 1 +IO.print(new Fn {|a, b| a}.arity) // expect: 2 +IO.print(new Fn {|a, b, c| a}.arity) // expect: 3 +IO.print(new Fn {|a, b, c, d| a}.arity) // expect: 4