Support /,*,kws in function definitions
This commit is contained in:
parent
29b9db0079
commit
7d57acd49a
@ -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],
|
||||
|
102
src/compiler.c
102
src/compiler.c
@ -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));
|
||||
|
||||
|
88
src/debug.c
88
src/debug.c
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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) {
|
||||
|
@ -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__));
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
51
src/vm.c
51
src/vm.c
@ -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();
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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");
|
||||
|
Loading…
Reference in New Issue
Block a user