Support optional arguments by tracking separate arities
This commit is contained in:
parent
5ff31e7d96
commit
428c368a75
14
README.md
14
README.md
@ -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:
|
||||
|
10
compiler.c
10
compiler.c
@ -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.");
|
||||
|
3
object.c
3
object.c
@ -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);
|
||||
|
3
object.h
3
object.h
@ -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
10
vm.c
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user