Support optional arguments by tracking separate arities

This commit is contained in:
K. Lange 2020-12-30 08:00:48 +09:00
parent 5ff31e7d96
commit 428c368a75
5 changed files with 33 additions and 7 deletions

View File

@ -62,6 +62,20 @@ greet("user")
# → Hello, user!
```
Optional arguments are supported, though as of writing they must default to `None`:
```py
def greet(name=None):
if not name:
print "Hello, world!"
else:
print "Hello, " + name + "!"
greet()
gree("user")
# → Hello, world!
# Hello, user!
```
### Variables
In a departure from Python, Kuroko has explicit variable declaration and traditional scoping rules. Variables are declared with the `let` keyword and take the value `None` if not defined at declaration time:

View File

@ -495,10 +495,16 @@ static void function(FunctionType type, size_t blockWidth) {
}
continue;
}
current->function->arity++;
if (current->function->arity > 255) errorAtCurrent("too many function parameters");
ssize_t paramConstant = parseVariable("Expect parameter name.");
defineVariable(paramConstant);
if (match(TOKEN_EQUAL)) {
consume(TOKEN_NONE,"Optional arguments can only be assigned the default value of None.");
current->function->defaultArgs++;
if (current->function->defaultArgs > 255) errorAtCurrent("too many function parameters");
} else {
current->function->requiredArgs++;
if (current->function->requiredArgs > 255) errorAtCurrent("too many function parameters");
}
} while (match(TOKEN_COMMA));
}
consume(TOKEN_RIGHT_PAREN, "Expected end of parameter list.");

View File

@ -109,7 +109,8 @@ void krk_printObject(FILE * f, KrkValue value) {
KrkFunction * krk_newFunction() {
KrkFunction * function = ALLOCATE_OBJECT(KrkFunction, OBJ_FUNCTION);
function->arity = 0;
function->requiredArgs = 0;
function->defaultArgs = 0;
function->upvalueCount = 0;
function->name = NULL;
krk_initChunk(&function->chunk);

View File

@ -57,7 +57,8 @@ typedef struct KrkUpvalue {
typedef struct {
KrkObj obj;
int arity;
short requiredArgs;
short defaultArgs;
size_t upvalueCount;
KrkChunk chunk;
KrkString * name;

10
vm.c
View File

@ -316,10 +316,14 @@ static KrkValue krk_set_tracing(int argc, KrkValue argv[]) {
}
static int call(KrkClosure * closure, int argCount) {
if (argCount != closure->function->arity) {
krk_runtimeError("Wrong number of arguments (%d expected, got %d)", closure->function->arity, argCount);
if (argCount < closure->function->requiredArgs || argCount > (closure->function->requiredArgs + closure->function->defaultArgs)) {
krk_runtimeError("Wrong number of arguments (at least %d expected, got %d)", closure->function->requiredArgs, argCount);
return 0;
}
while (argCount < (closure->function->requiredArgs + closure->function->defaultArgs)) {
krk_push(NONE_VAL());
argCount++;
}
if (vm.frameCount == FRAMES_MAX) {
krk_runtimeError("Too many call frames.");
return 0;
@ -655,7 +659,7 @@ static KrkClosure * boundNative(NativeFn method, int arity) {
/* Build a function that calls it */
KrkFunction * methodWrapper = krk_newFunction();
methodWrapper->arity = arity; /* This is WITHOUT the self reference */
methodWrapper->requiredArgs = arity; /* This is WITHOUT the self reference */
krk_writeConstant(&methodWrapper->chunk, nativeFunction, 1);
/* Stack silliness */