Support /,*,kws in function definitions

This commit is contained in:
K. Lange 2022-09-29 17:34:05 +09:00
parent 29b9db0079
commit 7d57acd49a
12 changed files with 198 additions and 129 deletions

View File

@ -852,9 +852,15 @@ KRK_Function(locals) {
/* First, we'll populate with arguments */
size_t slot = 0;
for (short int i = 0; i < func->requiredArgs; ++i) {
for (short int i = 0; i < func->potentialPositionals; ++i) {
krk_tableSet(AS_DICT(dict),
func->requiredArgNames.values[i],
func->positionalArgNames.values[i],
krk_currentThread.stack[frame->slots + slot]);
slot++;
}
if (func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
krk_tableSet(AS_DICT(dict),
func->positionalArgNames.values[func->potentialPositionals],
krk_currentThread.stack[frame->slots + slot]);
slot++;
}
@ -864,12 +870,6 @@ KRK_Function(locals) {
krk_currentThread.stack[frame->slots + slot]);
slot++;
}
if (func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
krk_tableSet(AS_DICT(dict),
func->requiredArgNames.values[func->requiredArgs],
krk_currentThread.stack[frame->slots + slot]);
slot++;
}
if (func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) {
krk_tableSet(AS_DICT(dict),
func->keywordArgNames.values[func->keywordArgs],

View File

@ -223,6 +223,7 @@ typedef struct Compiler {
int delSatisfied; /**< Flag indicating if a 'del' target has been completed. */
size_t optionsFlags; /**< Special __options__ imports; similar to __future__ in Python */
int unnamedArgs;
} Compiler;
#define OPTIONS_FLAG_COMPILE_TIME_BUILTINS (1 << 0)
@ -344,6 +345,8 @@ static void rewindChunk(KrkChunk * out, ChunkRecorder from) {
out->constants.count = from.constants;
}
static size_t renameLocal(struct GlobalState * state, size_t ind, KrkToken name);
static void initCompiler(struct GlobalState * state, Compiler * compiler, FunctionType type) {
compiler->enclosing = state->current;
state->current = compiler;
@ -368,6 +371,7 @@ static void initCompiler(struct GlobalState * state, Compiler * compiler, Functi
compiler->properties = NULL;
compiler->annotationCount = 0;
compiler->delSatisfied = 0;
compiler->unnamedArgs = 0;
compiler->optionsFlags = compiler->enclosing ? compiler->enclosing->optionsFlags : 0;
if (type != TYPE_MODULE) {
@ -382,7 +386,9 @@ static void initCompiler(struct GlobalState * state, Compiler * compiler, Functi
local->isCaptured = 0;
local->name.start = "self";
local->name.length = 4;
renameLocal(state, 0, local->name);
state->current->codeobject->requiredArgs = 1;
state->current->codeobject->potentialPositionals = 1;
}
if (isCoroutine(type)) state->current->codeobject->obj.flags |= KRK_OBJ_FLAGS_CODEOBJECT_IS_COROUTINE;
@ -551,42 +557,50 @@ static void emitReturn(struct GlobalState * state) {
static KrkCodeObject * endCompiler(struct GlobalState * state) {
KrkCodeObject * function = state->current->codeobject;
for (size_t i = 0; i < state->current->codeobject->localNameCount; i++) {
if (state->current->codeobject->localNames[i].deathday == 0) {
state->current->codeobject->localNames[i].deathday = currentChunk()->count;
for (size_t i = 0; i < function->localNameCount; i++) {
if (function->localNames[i].deathday == 0) {
function->localNames[i].deathday = currentChunk()->count;
}
}
state->current->codeobject->localNames = GROW_ARRAY(KrkLocalEntry, state->current->codeobject->localNames, \
state->current->localNameCapacity, state->current->codeobject->localNameCount); /* Shorten this down for runtime */
function->localNames = GROW_ARRAY(KrkLocalEntry, function->localNames, \
state->current->localNameCapacity, function->localNameCount); /* Shorten this down for runtime */
if (state->current->continueCount) { state->parser.previous = state->current->continues[0].token; error("continue without loop"); }
if (state->current->breakCount) { state->parser.previous = state->current->breaks[0].token; error("break without loop"); }
emitReturn(state);
/* Attach contants for arguments */
for (int i = 0; i < function->requiredArgs; ++i) {
for (int i = 0; i < function->potentialPositionals; ++i) {
if (i < state->current->unnamedArgs) {
krk_writeValueArray(&function->positionalArgNames, NONE_VAL());
continue;
}
KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[i].name.start, state->current->locals[i].name.length));
krk_push(value);
krk_writeValueArray(&function->requiredArgNames, value);
krk_writeValueArray(&function->positionalArgNames, value);
krk_pop();
}
size_t args = function->potentialPositionals;
if (function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[args].name.start,
state->current->locals[args].name.length));
krk_push(value);
krk_writeValueArray(&function->positionalArgNames, value);
krk_pop();
args++;
}
for (int i = 0; i < function->keywordArgs; ++i) {
KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[i+function->requiredArgs].name.start,
state->current->locals[i+function->requiredArgs].name.length));
KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[i+args].name.start,
state->current->locals[i+args].name.length));
krk_push(value);
krk_writeValueArray(&function->keywordArgNames, value);
krk_pop();
}
size_t args = state->current->codeobject->requiredArgs + state->current->codeobject->keywordArgs;
if (state->current->codeobject->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[args].name.start,
state->current->locals[args].name.length));
krk_push(value);
krk_writeValueArray(&function->requiredArgNames, value);
krk_pop();
args++;
}
if (state->current->codeobject->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) {
args += function->keywordArgs;
if (function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) {
KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[args].name.start,
state->current->locals[args].name.length));
krk_push(value);
@ -595,8 +609,7 @@ static KrkCodeObject * endCompiler(struct GlobalState * state) {
args++;
}
state->current->codeobject->potentialPositionals = state->current->codeobject->requiredArgs + state->current->codeobject->keywordArgs;
state->current->codeobject->totalArguments = state->current->codeobject->potentialPositionals + !!(state->current->codeobject->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) + !!(state->current->codeobject->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS);
function->totalArguments = function->potentialPositionals + function->keywordArgs + !!(function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) + !!(function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS);
#ifndef KRK_NO_DISASSEMBLY
if ((krk_currentThread.flags & KRK_THREAD_ENABLE_DISASSEMBLY) && !state->parser.hadError) {
@ -1351,7 +1364,7 @@ static void hideLocal(struct GlobalState * state) {
state->current->locals[state->current->localCount - 1].depth = -2;
}
static void argumentDefinition(struct GlobalState * state) {
static void argumentDefinition(struct GlobalState * state, int hasCollectors) {
if (match(TOKEN_EQUAL)) {
/*
* We inline default arguments by checking if they are equal
@ -1370,13 +1383,27 @@ static void argumentDefinition(struct GlobalState * state) {
EMIT_OPERAND_OP(OP_SET_LOCAL_POP, myLocal);
endScope(state);
patchJump(jumpIndex);
state->current->codeobject->keywordArgs++;
} else {
if (state->current->codeobject->keywordArgs) {
error("non-keyword argument follows keyword argument");
return;
if (hasCollectors) {
state->current->codeobject->keywordArgs++;
} else {
state->current->codeobject->potentialPositionals++;
}
} else {
if (hasCollectors) {
size_t myLocal = state->current->localCount - 1;
EMIT_OPERAND_OP(OP_GET_LOCAL, myLocal);
int jumpIndex = emitJump(OP_TEST_ARG);
EMIT_OPERAND_OP(OP_MISSING_KW, state->current->codeobject->keywordArgs);
patchJump(jumpIndex);
state->current->codeobject->keywordArgs++;
} else {
if (state->current->codeobject->potentialPositionals != state->current->codeobject->requiredArgs) {
error("non-default argument follows default argument");
return;
}
state->current->codeobject->requiredArgs++;
state->current->codeobject->potentialPositionals++;
}
state->current->codeobject->requiredArgs++;
}
}
@ -1413,11 +1440,19 @@ static int argumentList(struct GlobalState * state, FunctionType type) {
typeHint(state, name);
}
if (check(TOKEN_EQUAL)) {
errorAtCurrent("'self' can not be a keyword argument.");
errorAtCurrent("'self' can not be a default argument.");
return 1;
}
continue;
}
if (match(TOKEN_SOLIDUS)) {
if (hasCollectors || state->current->unnamedArgs || !state->current->codeobject->potentialPositionals) {
error("Syntax error.");
return 1;
}
state->current->unnamedArgs = state->current->codeobject->potentialPositionals;
continue;
}
if (match(TOKEN_ASTERISK) || check(TOKEN_POW)) {
if (match(TOKEN_POW)) {
if (hasCollectors == 2) {
@ -1432,6 +1467,9 @@ static int argumentList(struct GlobalState * state, FunctionType type) {
return 1;
}
hasCollectors = 1;
if (check(TOKEN_COMMA)) {
continue;
}
state->current->codeobject->obj.flags |= KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS;
}
/* Collect a name, specifically "args" or "kwargs" are commont */
@ -1463,8 +1501,8 @@ static int argumentList(struct GlobalState * state, FunctionType type) {
patchJump(jumpIndex);
continue;
}
if (hasCollectors) {
error("arguments follow catch-all collector");
if (hasCollectors == 2) {
error("arguments follow catch-all keyword collector");
break;
}
ssize_t paramConstant = parseVariable(state, "Expected parameter name.");
@ -1475,7 +1513,7 @@ static int argumentList(struct GlobalState * state, FunctionType type) {
match(TOKEN_COLON);
typeHint(state, name);
}
argumentDefinition(state);
argumentDefinition(state, hasCollectors);
defineVariable(state, paramConstant);
} while (match(TOKEN_COMMA));

View File

@ -31,27 +31,19 @@ void krk_debug_dumpStack(FILE * file, KrkCallFrame * frame) {
size_t relative = i - f->slots;
/* Figure out the name of this value */
if (relative < (size_t)f->closure->function->requiredArgs) {
fprintf(file, "%s=", AS_CSTRING(f->closure->function->requiredArgNames.values[relative]));
break;
} else if (relative < (size_t)f->closure->function->requiredArgs + (size_t)f->closure->function->keywordArgs) {
fprintf(file, "%s=", AS_CSTRING(f->closure->function->keywordArgNames.values[relative - f->closure->function->requiredArgs]));
break;
} else {
int found = 0;
for (size_t j = 0; j < f->closure->function->localNameCount; ++j) {
if (relative == f->closure->function->localNames[j].id
/* Only display this name if it's currently valid */
&& f->closure->function->localNames[j].birthday <= (size_t)(f->ip - f->closure->function->chunk.code)
&& f->closure->function->localNames[j].deathday >= (size_t)(f->ip - f->closure->function->chunk.code)
) {
fprintf(file, "%s=", f->closure->function->localNames[j].name->chars);
found = 1;
break;
}
int found = 0;
for (size_t j = 0; j < f->closure->function->localNameCount; ++j) {
if (relative == f->closure->function->localNames[j].id
/* Only display this name if it's currently valid */
&& f->closure->function->localNames[j].birthday <= (size_t)(f->ip - f->closure->function->chunk.code)
&& f->closure->function->localNames[j].deathday >= (size_t)(f->ip - f->closure->function->chunk.code)
) {
fprintf(file, "%s=", f->closure->function->localNames[j].name->chars);
found = 1;
break;
}
if (found) break;
}
if (found) break;
}
krk_printValueSafe(file, *slot);
@ -69,20 +61,24 @@ void krk_disassembleCodeObject(FILE * f, KrkCodeObject * func, const char * name
KrkChunk * chunk = &func->chunk;
/* Function header */
fprintf(f, "<%s(", name);
for (int i = 0; i < func->requiredArgs; ++i) {
fprintf(f,"%s",AS_CSTRING(func->requiredArgNames.values[i]));
if (i + 1 < func->requiredArgs || func->keywordArgs || !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) || !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS)) fprintf(f,",");
}
for (int i = 0; i < func->keywordArgs; ++i) {
fprintf(f,"%s=...",AS_CSTRING(func->keywordArgNames.values[i]));
if (i + 1 < func->keywordArgs || !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) || !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS)) fprintf(f,",");
int j = 0;
for (int i = 0; i < func->potentialPositionals; ++i) {
fprintf(f,"%s",func->localNames[j].name->chars);
if (j + 1 < func->totalArguments) fprintf(f,",");
j++;
}
if (func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
fprintf(f,"*%s", AS_CSTRING(func->requiredArgNames.values[func->requiredArgs]));
if (func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) fprintf(f,",");
fprintf(f,"*%s",func->localNames[j].name->chars);
if (j + 1 < func->totalArguments) fprintf(f,",");
j++;
}
for (int i = 0; i < func->keywordArgs; ++i) {
fprintf(f,"%s=",func->localNames[j].name->chars);
if (j + 1 < func->totalArguments) fprintf(f,",");
j++;
}
if (func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) {
fprintf(f,"**%s", AS_CSTRING(func->keywordArgNames.values[func->keywordArgs]));
fprintf(f,"**%s",func->localNames[j].name->chars);
}
fprintf(f, ") from %s>\n", chunk->filename->chars);
for (size_t offset = 0; offset < chunk->count;) {
@ -233,16 +229,16 @@ static void _format_value_more(OPARGS, size_t operand) {
#define LOCAL_MORE _local_more
static void _local_more(OPARGS, size_t operand) {
if ((short int)operand < (func->requiredArgs)) {
fprintf(f, " (%s, arg)", AS_CSTRING(func->requiredArgNames.values[operand]));
} else if ((short int)operand < (func->requiredArgs + func->keywordArgs)) {
fprintf(f, " (%s, kwarg))", AS_CSTRING(func->keywordArgNames.values[operand-func->requiredArgs]));
} else {
for (size_t i = 0; i < func->localNameCount; ++i) {
if (func->localNames[i].id == operand && func->localNames[i].birthday <= *offset && func->localNames[i].deathday >= *offset) {
fprintf(f, " (%s)", func->localNames[i].name->chars);
break;
for (size_t i = 0; i < func->localNameCount; ++i) {
if (func->localNames[i].id == operand && func->localNames[i].birthday <= *offset && func->localNames[i].deathday >= *offset) {
fprintf(f, " (%s", func->localNames[i].name->chars);
if ((short int) operand < func->potentialPositionals) {
fprintf(f, ", arg");
} else if ((short int)operand < func->potentialPositionals + func->keywordArgs + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS)) {
fprintf(f, ", kwarg");
}
fprintf(f, ")");
break;
}
}
}
@ -727,17 +723,11 @@ static KrkValue _examineInternal(KrkCodeObject* func) {
} else if (jump != 0) {
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(jump);
} else if (local != -1) {
if ((short int)local < func->requiredArgs) {
newTuple->values.values[newTuple->values.count++] = func->requiredArgNames.values[local];
} else if ((short int)local < func->requiredArgs + func->keywordArgs) {
newTuple->values.values[newTuple->values.count++] = func->keywordArgNames.values[local - func->requiredArgs];
} else {
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(operand); /* Just in case */
for (size_t i = 0; i < func->localNameCount; ++i) {
if (func->localNames[i].id == (size_t)local && func->localNames[i].birthday <= offset && func->localNames[i].deathday >= offset) {
newTuple->values.values[newTuple->values.count-1] = OBJECT_VAL(func->localNames[i].name);
break;
}
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(operand); /* Just in case */
for (size_t i = 0; i < func->localNameCount; ++i) {
if (func->localNames[i].id == (size_t)local && func->localNames[i].birthday <= offset && func->localNames[i].deathday >= offset) {
newTuple->values.values[newTuple->values.count-1] = OBJECT_VAL(func->localNames[i].name);
break;
}
}
} else if (operand != -1) {

View File

@ -151,8 +151,8 @@ typedef struct {
KrkChunk chunk; /**< @brief Bytecode data */
KrkString * name; /**< @brief Name of the function */
KrkString * docstring; /**< @brief Docstring attached to the function */
KrkValueArray requiredArgNames; /**< @brief Array of names for required arguments (and *args) */
KrkValueArray keywordArgNames; /**< @brief Array of names for keyword arguments (and **kwargs) */
KrkValueArray positionalArgNames; /**< @brief Array of names for positional arguments (and *args) */
KrkValueArray keywordArgNames; /**< @brief Array of names for keyword-only arguments (and **kwargs) */
size_t localNameCapacity; /**< @brief Capacity of @ref localNames */
size_t localNameCount; /**< @brief Number of entries in @ref localNames */
KrkLocalEntry * localNames; /**< @brief Stores the names of local variables used in the function, for debugging */

View File

@ -210,7 +210,7 @@ static void freeObject(KrkObj * object) {
case KRK_OBJ_CODEOBJECT: {
KrkCodeObject * function = (KrkCodeObject*)object;
krk_freeChunk(&function->chunk);
krk_freeValueArray(&function->requiredArgNames);
krk_freeValueArray(&function->positionalArgNames);
krk_freeValueArray(&function->keywordArgNames);
FREE_ARRAY(KrkLocalEntry, function->localNames, function->localNameCount);
function->localNameCount = 0;
@ -356,7 +356,7 @@ static void blackenObject(KrkObj * object) {
krk_markObject((KrkObj*)function->qualname);
krk_markObject((KrkObj*)function->docstring);
krk_markObject((KrkObj*)function->chunk.filename);
markArray(&function->requiredArgNames);
markArray(&function->positionalArgNames);
markArray(&function->keywordArgNames);
markArray(&function->chunk.constants);
for (size_t i = 0; i < function->localNameCount; ++i) {

View File

@ -14,21 +14,21 @@ static KrkValue nativeFunctionName(KrkValue func) {
}
static KrkTuple * functionArgs(KrkCodeObject * _self) {
KrkTuple * tuple = krk_newTuple(_self->requiredArgs + _self->keywordArgs + !!(_self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) + !!(_self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS));
KrkTuple * tuple = krk_newTuple(_self->totalArguments);
krk_push(OBJECT_VAL(tuple));
for (short i = 0; i < _self->requiredArgs; ++i) {
tuple->values.values[tuple->values.count++] = _self->requiredArgNames.values[i];
for (short i = 0; i < _self->potentialPositionals; ++i) {
tuple->values.values[tuple->values.count++] = _self->positionalArgNames.values[i];
}
if (_self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
tuple->values.values[tuple->values.count++] = krk_stringFromFormat("*%S", AS_STRING(_self->positionalArgNames.values[_self->potentialPositionals]));
}
for (short i = 0; i < _self->keywordArgs; ++i) {
tuple->values.values[tuple->values.count++] = krk_stringFromFormat("%S=", AS_STRING(_self->keywordArgNames.values[i]));
}
if (_self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
tuple->values.values[tuple->values.count++] = krk_stringFromFormat("*%S", AS_STRING(_self->requiredArgNames.values[_self->requiredArgs]));
}
if (_self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) {
tuple->values.values[tuple->values.count++] = krk_stringFromFormat("**%S", AS_STRING(_self->keywordArgNames.values[_self->keywordArgs]));
}
@ -239,6 +239,18 @@ KRK_Method(codeobject,co_argcount) {
return INTEGER_VAL(self->potentialPositionals);
}
KRK_Method(codeobject,co_kwonlyargcount) {
return INTEGER_VAL(self->keywordArgs);
}
KRK_Method(codeobject,co_posonlyargcount) {
/* This is tricky because we don't store it anywhere */
for (size_t i = 0; i < self->potentialPositionals; ++i) {
if (!IS_NONE(self->positionalArgNames.values[i])) return INTEGER_VAL(i);
}
return INTEGER_VAL(0);
}
KRK_Method(codeobject,__locals__) {
krk_push(OBJECT_VAL(krk_newTuple(self->localNameCount)));
for (size_t i = 0; i < self->localNameCount; ++i) {
@ -384,6 +396,8 @@ void _createAndBind_functionClass(void) {
BIND_PROP(codeobject,co_flags);
BIND_PROP(codeobject,co_code);
BIND_PROP(codeobject,co_argcount);
BIND_PROP(codeobject,co_kwonlyargcount);
BIND_PROP(codeobject,co_posonlyargcount);
BIND_PROP(codeobject,__locals__);
BIND_PROP(codeobject,__args__);
krk_defineNative(&codeobject->methods, "__repr__", FUNC_NAME(codeobject,__str__));

View File

@ -262,12 +262,13 @@ KrkCodeObject * krk_newCodeObject(void) {
KrkCodeObject * codeobject = ALLOCATE_OBJECT(KrkCodeObject, KRK_OBJ_CODEOBJECT);
codeobject->requiredArgs = 0;
codeobject->keywordArgs = 0;
codeobject->potentialPositionals = 0;
codeobject->upvalueCount = 0;
codeobject->name = NULL;
codeobject->docstring = NULL;
codeobject->localNameCount = 0;
codeobject->localNames = NULL;
krk_initValueArray(&codeobject->requiredArgNames);
krk_initValueArray(&codeobject->positionalArgNames);
krk_initValueArray(&codeobject->keywordArgNames);
krk_initChunk(&codeobject->chunk);
return codeobject;

View File

@ -112,3 +112,4 @@ SIMPLE(OP_INHERIT)
JUMP(OP_CALL_ITER,+)
JUMP(OP_JUMP_IF_TRUE_OR_POP,+)
SIMPLE(OP_TRY_ELSE)
OPERAND(OP_MISSING_KW, NOOP)

View File

@ -5,7 +5,7 @@
#define KRK_VERSION_MAJOR 1
#define KRK_VERSION_MINOR 3
#define KRK_VERSION_PATCH 0
#define KRK_VERSION_PATCH 1
#define KRK_VERSION_LEVEL 0xF
#define KRK_VERSION_SERIAL 0x0
@ -74,7 +74,7 @@ KRK_Function(getsizeof) {
mySize += sizeof(KrkLineMap) * self->chunk.linesCapacity;
mySize += sizeof(KrkValue) * self->chunk.constants.capacity;
/* requiredArgNames */
mySize += sizeof(KrkValue) * self->requiredArgNames.capacity;
mySize += sizeof(KrkValue) * self->positionalArgNames.capacity;
/* keywordArgNames */
mySize += sizeof(KrkValue) * self->keywordArgNames.capacity;
/* Locals array */

View File

@ -368,12 +368,13 @@ int krk_isInstanceOf(KrkValue obj, const KrkClass * type) {
static inline int checkArgumentCount(const KrkClosure * closure, int argCount) {
int minArgs = closure->function->requiredArgs;
int maxArgs = minArgs + closure->function->keywordArgs;
int maxArgs = closure->function->potentialPositionals;
if (unlikely(argCount < minArgs || argCount > maxArgs)) {
krk_runtimeError(vm.exceptions->argumentError, "%s() takes %s %d argument%s (%d given)",
krk_runtimeError(vm.exceptions->argumentError, "%s() takes %s %d %sargument%s (%d given)",
closure->function->name ? closure->function->name->chars : "<unnamed>",
(minArgs == maxArgs) ? "exactly" : (argCount < minArgs ? "at least" : "at most"),
(argCount < minArgs) ? minArgs : maxArgs,
closure->function->keywordArgs ? "positional " : "",
((argCount < minArgs) ? minArgs : maxArgs) == 1 ? "" : "s",
argCount);
return 0;
@ -384,8 +385,8 @@ static inline int checkArgumentCount(const KrkClosure * closure, int argCount) {
static void multipleDefs(const KrkClosure * closure, int destination) {
krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%S'",
closure->function->name ? closure->function->name->chars : "<unnamed>",
(destination < closure->function->requiredArgs ? AS_STRING(closure->function->requiredArgNames.values[destination]) :
(destination - closure->function->requiredArgs < closure->function->keywordArgs ? AS_STRING(closure->function->keywordArgNames.values[destination - closure->function->requiredArgs]) :
(destination < closure->function->potentialPositionals ? AS_STRING(closure->function->positionalArgNames.values[destination]) :
(destination - closure->function->potentialPositionals < closure->function->keywordArgs ? AS_STRING(closure->function->keywordArgNames.values[destination - closure->function->potentialPositionals]) :
S("<unnamed>"))));
}
@ -546,6 +547,11 @@ static inline int _callManaged(KrkClosure * closure, int argCount, int returnDep
argCount++;
}
for (size_t i = 0; i < closure->function->keywordArgs; ++i) {
krk_push(KWARGS_VAL(0));
argCount++;
}
/* We're done with the positionals */
krk_currentThread.scratchSpace[0] = NONE_VAL();
@ -556,8 +562,8 @@ static inline int _callManaged(KrkClosure * closure, int argCount, int returnDep
KrkValue name = entry->key;
KrkValue value = entry->value;
/* See if we can place it */
for (int j = 0; j < (int)closure->function->requiredArgs; ++j) {
if (krk_valuesEqual(name, closure->function->requiredArgNames.values[j])) {
for (int j = 0; j < (int)closure->function->potentialPositionals; ++j) {
if (krk_valuesSame(name, closure->function->positionalArgNames.values[j])) {
if (!IS_KWARGS(krk_currentThread.stackTop[-argCount + j])) {
multipleDefs(closure,j);
goto _errorAfterPositionals;
@ -568,12 +574,12 @@ static inline int _callManaged(KrkClosure * closure, int argCount, int returnDep
}
/* See if it's a keyword arg. */
for (int j = 0; j < (int)closure->function->keywordArgs; ++j) {
if (krk_valuesEqual(name, closure->function->keywordArgNames.values[j])) {
if (!IS_KWARGS(krk_currentThread.stackTop[-argCount + j + closure->function->requiredArgs])) {
multipleDefs(closure, j + closure->function->requiredArgs);
if (krk_valuesSame(name, closure->function->keywordArgNames.values[j])) {
if (!IS_KWARGS(krk_currentThread.stackTop[-argCount + j + closure->function->potentialPositionals + !!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS)])) {
multipleDefs(closure, j + closure->function->potentialPositionals);
goto _errorAfterPositionals;
}
krk_currentThread.stackTop[-argCount + j + closure->function->requiredArgs] = value;
krk_currentThread.stackTop[-argCount + j + closure->function->potentialPositionals + !!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS)] = value;
goto _finishKwarg;
}
}
@ -603,14 +609,21 @@ _finishKwarg:
for (size_t i = 0; i < (size_t)closure->function->requiredArgs; ++i) {
if (IS_KWARGS(krk_currentThread.stackTop[-argCount + i])) {
krk_runtimeError(vm.exceptions->typeError, "%s() missing required positional argument: '%S'",
closure->function->name ? closure->function->name->chars : "<unnamed>",
AS_STRING(closure->function->requiredArgNames.values[i]));
if (i < closure->function->localNameCount) {
krk_runtimeError(vm.exceptions->typeError, "%s() %s: '%S'",
closure->function->name ? closure->function->name->chars : "<unnamed>",
"missing required positional argument",
closure->function->localNames[i].name);
} else {
krk_runtimeError(vm.exceptions->typeError, "%s() %s",
closure->function->name ? closure->function->name->chars : "<unnamed>",
"missing required positional argument");
}
goto _errorAfterKeywords;
}
}
argCountX = argCount - (!!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) + !!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS));
argCountX = argCount - closure->function->keywordArgs - (!!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) + !!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS));
} else if ((size_t)argCount > potentialPositionalArgs && (closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS)) {
KrkValue * startOfPositionals = &krk_currentThread.stackTop[-argCount];
KrkValue tmp = krk_callNativeOnStack(argCount - potentialPositionalArgs,
@ -3018,6 +3031,16 @@ _finishPopBlock:
break;
}
case OP_MISSING_KW_LONG:
THREE_BYTE_OPERAND;
case OP_MISSING_KW: {
ONE_BYTE_OPERAND;
krk_runtimeError(vm.exceptions->typeError, "%s() missing required keyword-only argument: %R",
frame->closure->function->name ? frame->closure->function->name->chars : "<unnamed>",
frame->closure->function->keywordArgNames.values[OPERAND]);
break;
}
default:
__builtin_unreachable();
}

View File

@ -32,7 +32,7 @@ try:
dis.build(template.replace('__args__','self=42'))
print('fail')
except SyntaxError as e:
print('pass' if 'keyword argument' in str(e) else 'fail')
print('pass' if 'default argument' in str(e) else 'fail')
# for that matter, neither can star args
try:

View File

@ -24,7 +24,7 @@
struct MarshalHeader {
uint8_t magic[4]; /* K R K B */
uint8_t version[4]; /* 1 0 1 1 */
uint8_t version[4]; /* 1 0 1 2 */
} __attribute__((packed));
struct FunctionHeader {
@ -33,6 +33,7 @@ struct FunctionHeader {
uint32_t qualInd;
uint16_t reqArgs;
uint16_t kwArgs;
uint16_t posArgs;
uint16_t upvalues;
uint32_t locals;
uint32_t bcSize;
@ -219,8 +220,8 @@ static int doFirstPass(FILE * out) {
if (func->docstring) internString(func->docstring);
if (func->qualname) internString(func->qualname);
for (size_t i = 0; i < (size_t)func->requiredArgs + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); ++i) {
internString(AS_STRING(func->requiredArgNames.values[i]));
for (size_t i = 0; i < (size_t)func->potentialPositionals + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); ++i) {
internString(AS_STRING(func->positionalArgNames.values[i]));
}
for (size_t i = 0; i < (size_t)func->keywordArgs + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS); ++i) {
@ -267,6 +268,7 @@ static int doSecondPass(FILE * out) {
func->qualname ? internString(func->qualname) : UINT32_MAX,
func->requiredArgs,
func->keywordArgs,
func->potentialPositionals,
func->upvalueCount,
func->localNameCount,
func->chunk.count,
@ -278,8 +280,8 @@ static int doSecondPass(FILE * out) {
fwrite(&header, 1, sizeof(struct FunctionHeader), out);
/* Argument names first */
for (size_t i = 0; i < (size_t)func->requiredArgs + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); ++i) {
WRITE_STRING(AS_STRING(func->requiredArgNames.values[i]));
for (size_t i = 0; i < (size_t)func->potentialPositionals + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); ++i) {
WRITE_STRING(AS_STRING(func->positionalArgNames.values[i]));
}
for (size_t i = 0; i < (size_t)func->keywordArgs + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS); ++i) {
@ -377,7 +379,7 @@ static int compileFile(char * fileName) {
/* Start with the primary header */
struct MarshalHeader header = {
{'K','R','K','B'},
{'1','0','1','1'},
{'1','0','1','2'},
};
fwrite(&header, 1, sizeof(header), out);
@ -466,7 +468,7 @@ static int readFile(char * fileName) {
if (memcmp(header.magic,(uint8_t[]){'K','R','K','B'},4) != 0)
return fprintf(stderr, "Invalid header.\n"), 1;
if (memcmp(header.version,(uint8_t[]){'1','0','1','1'},4) != 0)
if (memcmp(header.version,(uint8_t[]){'1','0','1','2'},4) != 0)
return fprintf(stderr, "Bytecode is for a different version.\n"), 2;
/* Read string table */
@ -544,14 +546,14 @@ static int readFile(char * fileName) {
self->keywordArgs = function.kwArgs;
self->obj.flags = function.flags;
self->upvalueCount = function.upvalues;
self->potentialPositionals = function.posArgs;
self->potentialPositionals = self->requiredArgs + self->keywordArgs;
self->totalArguments = self->potentialPositionals + !!(self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) + !!(self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS);
/* Read argument names */
DEBUGOUT(" [Required Arguments]\n");
for (size_t i = 0; i < (size_t)function.reqArgs + !!(self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); i++) {
krk_writeValueArray(&self->requiredArgNames, valueFromConstant(i,inFile));
DEBUGOUT(" [Positional Arguments]\n");
for (size_t i = 0; i < (size_t)function.posArgs + !!(self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); i++) {
krk_writeValueArray(&self->positionalArgNames, valueFromConstant(i,inFile));
}
DEBUGOUT(" [Keyword Arguments]\n");