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 */
|
/* First, we'll populate with arguments */
|
||||||
size_t slot = 0;
|
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),
|
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]);
|
krk_currentThread.stack[frame->slots + slot]);
|
||||||
slot++;
|
slot++;
|
||||||
}
|
}
|
||||||
@ -864,12 +870,6 @@ KRK_Function(locals) {
|
|||||||
krk_currentThread.stack[frame->slots + slot]);
|
krk_currentThread.stack[frame->slots + slot]);
|
||||||
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) {
|
if (func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) {
|
||||||
krk_tableSet(AS_DICT(dict),
|
krk_tableSet(AS_DICT(dict),
|
||||||
func->keywordArgNames.values[func->keywordArgs],
|
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. */
|
int delSatisfied; /**< Flag indicating if a 'del' target has been completed. */
|
||||||
|
|
||||||
size_t optionsFlags; /**< Special __options__ imports; similar to __future__ in Python */
|
size_t optionsFlags; /**< Special __options__ imports; similar to __future__ in Python */
|
||||||
|
int unnamedArgs;
|
||||||
} Compiler;
|
} Compiler;
|
||||||
|
|
||||||
#define OPTIONS_FLAG_COMPILE_TIME_BUILTINS (1 << 0)
|
#define OPTIONS_FLAG_COMPILE_TIME_BUILTINS (1 << 0)
|
||||||
@ -344,6 +345,8 @@ static void rewindChunk(KrkChunk * out, ChunkRecorder from) {
|
|||||||
out->constants.count = from.constants;
|
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) {
|
static void initCompiler(struct GlobalState * state, Compiler * compiler, FunctionType type) {
|
||||||
compiler->enclosing = state->current;
|
compiler->enclosing = state->current;
|
||||||
state->current = compiler;
|
state->current = compiler;
|
||||||
@ -368,6 +371,7 @@ static void initCompiler(struct GlobalState * state, Compiler * compiler, Functi
|
|||||||
compiler->properties = NULL;
|
compiler->properties = NULL;
|
||||||
compiler->annotationCount = 0;
|
compiler->annotationCount = 0;
|
||||||
compiler->delSatisfied = 0;
|
compiler->delSatisfied = 0;
|
||||||
|
compiler->unnamedArgs = 0;
|
||||||
compiler->optionsFlags = compiler->enclosing ? compiler->enclosing->optionsFlags : 0;
|
compiler->optionsFlags = compiler->enclosing ? compiler->enclosing->optionsFlags : 0;
|
||||||
|
|
||||||
if (type != TYPE_MODULE) {
|
if (type != TYPE_MODULE) {
|
||||||
@ -382,7 +386,9 @@ static void initCompiler(struct GlobalState * state, Compiler * compiler, Functi
|
|||||||
local->isCaptured = 0;
|
local->isCaptured = 0;
|
||||||
local->name.start = "self";
|
local->name.start = "self";
|
||||||
local->name.length = 4;
|
local->name.length = 4;
|
||||||
|
renameLocal(state, 0, local->name);
|
||||||
state->current->codeobject->requiredArgs = 1;
|
state->current->codeobject->requiredArgs = 1;
|
||||||
|
state->current->codeobject->potentialPositionals = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCoroutine(type)) state->current->codeobject->obj.flags |= KRK_OBJ_FLAGS_CODEOBJECT_IS_COROUTINE;
|
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) {
|
static KrkCodeObject * endCompiler(struct GlobalState * state) {
|
||||||
KrkCodeObject * function = state->current->codeobject;
|
KrkCodeObject * function = state->current->codeobject;
|
||||||
|
|
||||||
for (size_t i = 0; i < state->current->codeobject->localNameCount; i++) {
|
for (size_t i = 0; i < function->localNameCount; i++) {
|
||||||
if (state->current->codeobject->localNames[i].deathday == 0) {
|
if (function->localNames[i].deathday == 0) {
|
||||||
state->current->codeobject->localNames[i].deathday = currentChunk()->count;
|
function->localNames[i].deathday = currentChunk()->count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state->current->codeobject->localNames = GROW_ARRAY(KrkLocalEntry, state->current->codeobject->localNames, \
|
function->localNames = GROW_ARRAY(KrkLocalEntry, function->localNames, \
|
||||||
state->current->localNameCapacity, state->current->codeobject->localNameCount); /* Shorten this down for runtime */
|
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->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"); }
|
if (state->current->breakCount) { state->parser.previous = state->current->breaks[0].token; error("break without loop"); }
|
||||||
emitReturn(state);
|
emitReturn(state);
|
||||||
|
|
||||||
/* Attach contants for arguments */
|
/* 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));
|
KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[i].name.start, state->current->locals[i].name.length));
|
||||||
krk_push(value);
|
krk_push(value);
|
||||||
krk_writeValueArray(&function->requiredArgNames, value);
|
krk_writeValueArray(&function->positionalArgNames, value);
|
||||||
krk_pop();
|
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) {
|
for (int i = 0; i < function->keywordArgs; ++i) {
|
||||||
KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[i+function->requiredArgs].name.start,
|
KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[i+args].name.start,
|
||||||
state->current->locals[i+function->requiredArgs].name.length));
|
state->current->locals[i+args].name.length));
|
||||||
krk_push(value);
|
krk_push(value);
|
||||||
krk_writeValueArray(&function->keywordArgNames, value);
|
krk_writeValueArray(&function->keywordArgNames, value);
|
||||||
krk_pop();
|
krk_pop();
|
||||||
}
|
}
|
||||||
size_t args = state->current->codeobject->requiredArgs + state->current->codeobject->keywordArgs;
|
args += function->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,
|
if (function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) {
|
||||||
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) {
|
|
||||||
KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[args].name.start,
|
KrkValue value = OBJECT_VAL(krk_copyString(state->current->locals[args].name.start,
|
||||||
state->current->locals[args].name.length));
|
state->current->locals[args].name.length));
|
||||||
krk_push(value);
|
krk_push(value);
|
||||||
@ -595,8 +609,7 @@ static KrkCodeObject * endCompiler(struct GlobalState * state) {
|
|||||||
args++;
|
args++;
|
||||||
}
|
}
|
||||||
|
|
||||||
state->current->codeobject->potentialPositionals = state->current->codeobject->requiredArgs + state->current->codeobject->keywordArgs;
|
function->totalArguments = function->potentialPositionals + function->keywordArgs + !!(function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) + !!(function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS);
|
||||||
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);
|
|
||||||
|
|
||||||
#ifndef KRK_NO_DISASSEMBLY
|
#ifndef KRK_NO_DISASSEMBLY
|
||||||
if ((krk_currentThread.flags & KRK_THREAD_ENABLE_DISASSEMBLY) && !state->parser.hadError) {
|
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;
|
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)) {
|
if (match(TOKEN_EQUAL)) {
|
||||||
/*
|
/*
|
||||||
* We inline default arguments by checking if they are 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);
|
EMIT_OPERAND_OP(OP_SET_LOCAL_POP, myLocal);
|
||||||
endScope(state);
|
endScope(state);
|
||||||
patchJump(jumpIndex);
|
patchJump(jumpIndex);
|
||||||
state->current->codeobject->keywordArgs++;
|
if (hasCollectors) {
|
||||||
} else {
|
state->current->codeobject->keywordArgs++;
|
||||||
if (state->current->codeobject->keywordArgs) {
|
} else {
|
||||||
error("non-keyword argument follows keyword argument");
|
state->current->codeobject->potentialPositionals++;
|
||||||
return;
|
}
|
||||||
|
} 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);
|
typeHint(state, name);
|
||||||
}
|
}
|
||||||
if (check(TOKEN_EQUAL)) {
|
if (check(TOKEN_EQUAL)) {
|
||||||
errorAtCurrent("'self' can not be a keyword argument.");
|
errorAtCurrent("'self' can not be a default argument.");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
continue;
|
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_ASTERISK) || check(TOKEN_POW)) {
|
||||||
if (match(TOKEN_POW)) {
|
if (match(TOKEN_POW)) {
|
||||||
if (hasCollectors == 2) {
|
if (hasCollectors == 2) {
|
||||||
@ -1432,6 +1467,9 @@ static int argumentList(struct GlobalState * state, FunctionType type) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
hasCollectors = 1;
|
hasCollectors = 1;
|
||||||
|
if (check(TOKEN_COMMA)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
state->current->codeobject->obj.flags |= KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS;
|
state->current->codeobject->obj.flags |= KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS;
|
||||||
}
|
}
|
||||||
/* Collect a name, specifically "args" or "kwargs" are commont */
|
/* Collect a name, specifically "args" or "kwargs" are commont */
|
||||||
@ -1463,8 +1501,8 @@ static int argumentList(struct GlobalState * state, FunctionType type) {
|
|||||||
patchJump(jumpIndex);
|
patchJump(jumpIndex);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (hasCollectors) {
|
if (hasCollectors == 2) {
|
||||||
error("arguments follow catch-all collector");
|
error("arguments follow catch-all keyword collector");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ssize_t paramConstant = parseVariable(state, "Expected parameter name.");
|
ssize_t paramConstant = parseVariable(state, "Expected parameter name.");
|
||||||
@ -1475,7 +1513,7 @@ static int argumentList(struct GlobalState * state, FunctionType type) {
|
|||||||
match(TOKEN_COLON);
|
match(TOKEN_COLON);
|
||||||
typeHint(state, name);
|
typeHint(state, name);
|
||||||
}
|
}
|
||||||
argumentDefinition(state);
|
argumentDefinition(state, hasCollectors);
|
||||||
defineVariable(state, paramConstant);
|
defineVariable(state, paramConstant);
|
||||||
} while (match(TOKEN_COMMA));
|
} 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;
|
size_t relative = i - f->slots;
|
||||||
|
|
||||||
/* Figure out the name of this value */
|
/* Figure out the name of this value */
|
||||||
if (relative < (size_t)f->closure->function->requiredArgs) {
|
int found = 0;
|
||||||
fprintf(file, "%s=", AS_CSTRING(f->closure->function->requiredArgNames.values[relative]));
|
for (size_t j = 0; j < f->closure->function->localNameCount; ++j) {
|
||||||
break;
|
if (relative == f->closure->function->localNames[j].id
|
||||||
} else if (relative < (size_t)f->closure->function->requiredArgs + (size_t)f->closure->function->keywordArgs) {
|
/* Only display this name if it's currently valid */
|
||||||
fprintf(file, "%s=", AS_CSTRING(f->closure->function->keywordArgNames.values[relative - f->closure->function->requiredArgs]));
|
&& f->closure->function->localNames[j].birthday <= (size_t)(f->ip - f->closure->function->chunk.code)
|
||||||
break;
|
&& f->closure->function->localNames[j].deathday >= (size_t)(f->ip - f->closure->function->chunk.code)
|
||||||
} else {
|
) {
|
||||||
int found = 0;
|
fprintf(file, "%s=", f->closure->function->localNames[j].name->chars);
|
||||||
for (size_t j = 0; j < f->closure->function->localNameCount; ++j) {
|
found = 1;
|
||||||
if (relative == f->closure->function->localNames[j].id
|
break;
|
||||||
/* 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);
|
krk_printValueSafe(file, *slot);
|
||||||
@ -69,20 +61,24 @@ void krk_disassembleCodeObject(FILE * f, KrkCodeObject * func, const char * name
|
|||||||
KrkChunk * chunk = &func->chunk;
|
KrkChunk * chunk = &func->chunk;
|
||||||
/* Function header */
|
/* Function header */
|
||||||
fprintf(f, "<%s(", name);
|
fprintf(f, "<%s(", name);
|
||||||
for (int i = 0; i < func->requiredArgs; ++i) {
|
int j = 0;
|
||||||
fprintf(f,"%s",AS_CSTRING(func->requiredArgNames.values[i]));
|
for (int i = 0; i < func->potentialPositionals; ++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,",");
|
fprintf(f,"%s",func->localNames[j].name->chars);
|
||||||
}
|
if (j + 1 < func->totalArguments) fprintf(f,",");
|
||||||
for (int i = 0; i < func->keywordArgs; ++i) {
|
j++;
|
||||||
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,",");
|
|
||||||
}
|
}
|
||||||
if (func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
|
if (func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
|
||||||
fprintf(f,"*%s", AS_CSTRING(func->requiredArgNames.values[func->requiredArgs]));
|
fprintf(f,"*%s",func->localNames[j].name->chars);
|
||||||
if (func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) fprintf(f,",");
|
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) {
|
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);
|
fprintf(f, ") from %s>\n", chunk->filename->chars);
|
||||||
for (size_t offset = 0; offset < chunk->count;) {
|
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
|
#define LOCAL_MORE _local_more
|
||||||
static void _local_more(OPARGS, size_t operand) {
|
static void _local_more(OPARGS, size_t operand) {
|
||||||
if ((short int)operand < (func->requiredArgs)) {
|
for (size_t i = 0; i < func->localNameCount; ++i) {
|
||||||
fprintf(f, " (%s, arg)", AS_CSTRING(func->requiredArgNames.values[operand]));
|
if (func->localNames[i].id == operand && func->localNames[i].birthday <= *offset && func->localNames[i].deathday >= *offset) {
|
||||||
} else if ((short int)operand < (func->requiredArgs + func->keywordArgs)) {
|
fprintf(f, " (%s", func->localNames[i].name->chars);
|
||||||
fprintf(f, " (%s, kwarg))", AS_CSTRING(func->keywordArgNames.values[operand-func->requiredArgs]));
|
if ((short int) operand < func->potentialPositionals) {
|
||||||
} else {
|
fprintf(f, ", arg");
|
||||||
for (size_t i = 0; i < func->localNameCount; ++i) {
|
} else if ((short int)operand < func->potentialPositionals + func->keywordArgs + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS)) {
|
||||||
if (func->localNames[i].id == operand && func->localNames[i].birthday <= *offset && func->localNames[i].deathday >= *offset) {
|
fprintf(f, ", kwarg");
|
||||||
fprintf(f, " (%s)", func->localNames[i].name->chars);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
fprintf(f, ")");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -727,17 +723,11 @@ static KrkValue _examineInternal(KrkCodeObject* func) {
|
|||||||
} else if (jump != 0) {
|
} else if (jump != 0) {
|
||||||
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(jump);
|
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(jump);
|
||||||
} else if (local != -1) {
|
} else if (local != -1) {
|
||||||
if ((short int)local < func->requiredArgs) {
|
newTuple->values.values[newTuple->values.count++] = INTEGER_VAL(operand); /* Just in case */
|
||||||
newTuple->values.values[newTuple->values.count++] = func->requiredArgNames.values[local];
|
for (size_t i = 0; i < func->localNameCount; ++i) {
|
||||||
} else if ((short int)local < func->requiredArgs + func->keywordArgs) {
|
if (func->localNames[i].id == (size_t)local && func->localNames[i].birthday <= offset && func->localNames[i].deathday >= offset) {
|
||||||
newTuple->values.values[newTuple->values.count++] = func->keywordArgNames.values[local - func->requiredArgs];
|
newTuple->values.values[newTuple->values.count-1] = OBJECT_VAL(func->localNames[i].name);
|
||||||
} else {
|
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) {
|
} else if (operand != -1) {
|
||||||
|
@ -151,8 +151,8 @@ typedef struct {
|
|||||||
KrkChunk chunk; /**< @brief Bytecode data */
|
KrkChunk chunk; /**< @brief Bytecode data */
|
||||||
KrkString * name; /**< @brief Name of the function */
|
KrkString * name; /**< @brief Name of the function */
|
||||||
KrkString * docstring; /**< @brief Docstring attached to the function */
|
KrkString * docstring; /**< @brief Docstring attached to the function */
|
||||||
KrkValueArray requiredArgNames; /**< @brief Array of names for required arguments (and *args) */
|
KrkValueArray positionalArgNames; /**< @brief Array of names for positional arguments (and *args) */
|
||||||
KrkValueArray keywordArgNames; /**< @brief Array of names for keyword arguments (and **kwargs) */
|
KrkValueArray keywordArgNames; /**< @brief Array of names for keyword-only arguments (and **kwargs) */
|
||||||
size_t localNameCapacity; /**< @brief Capacity of @ref localNames */
|
size_t localNameCapacity; /**< @brief Capacity of @ref localNames */
|
||||||
size_t localNameCount; /**< @brief Number of entries in @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 */
|
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: {
|
case KRK_OBJ_CODEOBJECT: {
|
||||||
KrkCodeObject * function = (KrkCodeObject*)object;
|
KrkCodeObject * function = (KrkCodeObject*)object;
|
||||||
krk_freeChunk(&function->chunk);
|
krk_freeChunk(&function->chunk);
|
||||||
krk_freeValueArray(&function->requiredArgNames);
|
krk_freeValueArray(&function->positionalArgNames);
|
||||||
krk_freeValueArray(&function->keywordArgNames);
|
krk_freeValueArray(&function->keywordArgNames);
|
||||||
FREE_ARRAY(KrkLocalEntry, function->localNames, function->localNameCount);
|
FREE_ARRAY(KrkLocalEntry, function->localNames, function->localNameCount);
|
||||||
function->localNameCount = 0;
|
function->localNameCount = 0;
|
||||||
@ -356,7 +356,7 @@ static void blackenObject(KrkObj * object) {
|
|||||||
krk_markObject((KrkObj*)function->qualname);
|
krk_markObject((KrkObj*)function->qualname);
|
||||||
krk_markObject((KrkObj*)function->docstring);
|
krk_markObject((KrkObj*)function->docstring);
|
||||||
krk_markObject((KrkObj*)function->chunk.filename);
|
krk_markObject((KrkObj*)function->chunk.filename);
|
||||||
markArray(&function->requiredArgNames);
|
markArray(&function->positionalArgNames);
|
||||||
markArray(&function->keywordArgNames);
|
markArray(&function->keywordArgNames);
|
||||||
markArray(&function->chunk.constants);
|
markArray(&function->chunk.constants);
|
||||||
for (size_t i = 0; i < function->localNameCount; ++i) {
|
for (size_t i = 0; i < function->localNameCount; ++i) {
|
||||||
|
@ -14,21 +14,21 @@ static KrkValue nativeFunctionName(KrkValue func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static KrkTuple * functionArgs(KrkCodeObject * _self) {
|
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));
|
krk_push(OBJECT_VAL(tuple));
|
||||||
|
|
||||||
for (short i = 0; i < _self->requiredArgs; ++i) {
|
for (short i = 0; i < _self->potentialPositionals; ++i) {
|
||||||
tuple->values.values[tuple->values.count++] = _self->requiredArgNames.values[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) {
|
for (short i = 0; i < _self->keywordArgs; ++i) {
|
||||||
tuple->values.values[tuple->values.count++] = krk_stringFromFormat("%S=", AS_STRING(_self->keywordArgNames.values[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) {
|
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]));
|
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);
|
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_Method(codeobject,__locals__) {
|
||||||
krk_push(OBJECT_VAL(krk_newTuple(self->localNameCount)));
|
krk_push(OBJECT_VAL(krk_newTuple(self->localNameCount)));
|
||||||
for (size_t i = 0; i < self->localNameCount; ++i) {
|
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_flags);
|
||||||
BIND_PROP(codeobject,co_code);
|
BIND_PROP(codeobject,co_code);
|
||||||
BIND_PROP(codeobject,co_argcount);
|
BIND_PROP(codeobject,co_argcount);
|
||||||
|
BIND_PROP(codeobject,co_kwonlyargcount);
|
||||||
|
BIND_PROP(codeobject,co_posonlyargcount);
|
||||||
BIND_PROP(codeobject,__locals__);
|
BIND_PROP(codeobject,__locals__);
|
||||||
BIND_PROP(codeobject,__args__);
|
BIND_PROP(codeobject,__args__);
|
||||||
krk_defineNative(&codeobject->methods, "__repr__", FUNC_NAME(codeobject,__str__));
|
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);
|
KrkCodeObject * codeobject = ALLOCATE_OBJECT(KrkCodeObject, KRK_OBJ_CODEOBJECT);
|
||||||
codeobject->requiredArgs = 0;
|
codeobject->requiredArgs = 0;
|
||||||
codeobject->keywordArgs = 0;
|
codeobject->keywordArgs = 0;
|
||||||
|
codeobject->potentialPositionals = 0;
|
||||||
codeobject->upvalueCount = 0;
|
codeobject->upvalueCount = 0;
|
||||||
codeobject->name = NULL;
|
codeobject->name = NULL;
|
||||||
codeobject->docstring = NULL;
|
codeobject->docstring = NULL;
|
||||||
codeobject->localNameCount = 0;
|
codeobject->localNameCount = 0;
|
||||||
codeobject->localNames = NULL;
|
codeobject->localNames = NULL;
|
||||||
krk_initValueArray(&codeobject->requiredArgNames);
|
krk_initValueArray(&codeobject->positionalArgNames);
|
||||||
krk_initValueArray(&codeobject->keywordArgNames);
|
krk_initValueArray(&codeobject->keywordArgNames);
|
||||||
krk_initChunk(&codeobject->chunk);
|
krk_initChunk(&codeobject->chunk);
|
||||||
return codeobject;
|
return codeobject;
|
||||||
|
@ -112,3 +112,4 @@ SIMPLE(OP_INHERIT)
|
|||||||
JUMP(OP_CALL_ITER,+)
|
JUMP(OP_CALL_ITER,+)
|
||||||
JUMP(OP_JUMP_IF_TRUE_OR_POP,+)
|
JUMP(OP_JUMP_IF_TRUE_OR_POP,+)
|
||||||
SIMPLE(OP_TRY_ELSE)
|
SIMPLE(OP_TRY_ELSE)
|
||||||
|
OPERAND(OP_MISSING_KW, NOOP)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#define KRK_VERSION_MAJOR 1
|
#define KRK_VERSION_MAJOR 1
|
||||||
#define KRK_VERSION_MINOR 3
|
#define KRK_VERSION_MINOR 3
|
||||||
#define KRK_VERSION_PATCH 0
|
#define KRK_VERSION_PATCH 1
|
||||||
#define KRK_VERSION_LEVEL 0xF
|
#define KRK_VERSION_LEVEL 0xF
|
||||||
#define KRK_VERSION_SERIAL 0x0
|
#define KRK_VERSION_SERIAL 0x0
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ KRK_Function(getsizeof) {
|
|||||||
mySize += sizeof(KrkLineMap) * self->chunk.linesCapacity;
|
mySize += sizeof(KrkLineMap) * self->chunk.linesCapacity;
|
||||||
mySize += sizeof(KrkValue) * self->chunk.constants.capacity;
|
mySize += sizeof(KrkValue) * self->chunk.constants.capacity;
|
||||||
/* requiredArgNames */
|
/* requiredArgNames */
|
||||||
mySize += sizeof(KrkValue) * self->requiredArgNames.capacity;
|
mySize += sizeof(KrkValue) * self->positionalArgNames.capacity;
|
||||||
/* keywordArgNames */
|
/* keywordArgNames */
|
||||||
mySize += sizeof(KrkValue) * self->keywordArgNames.capacity;
|
mySize += sizeof(KrkValue) * self->keywordArgNames.capacity;
|
||||||
/* Locals array */
|
/* 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) {
|
static inline int checkArgumentCount(const KrkClosure * closure, int argCount) {
|
||||||
int minArgs = closure->function->requiredArgs;
|
int minArgs = closure->function->requiredArgs;
|
||||||
int maxArgs = minArgs + closure->function->keywordArgs;
|
int maxArgs = closure->function->potentialPositionals;
|
||||||
if (unlikely(argCount < minArgs || argCount > maxArgs)) {
|
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>",
|
closure->function->name ? closure->function->name->chars : "<unnamed>",
|
||||||
(minArgs == maxArgs) ? "exactly" : (argCount < minArgs ? "at least" : "at most"),
|
(minArgs == maxArgs) ? "exactly" : (argCount < minArgs ? "at least" : "at most"),
|
||||||
(argCount < minArgs) ? minArgs : maxArgs,
|
(argCount < minArgs) ? minArgs : maxArgs,
|
||||||
|
closure->function->keywordArgs ? "positional " : "",
|
||||||
((argCount < minArgs) ? minArgs : maxArgs) == 1 ? "" : "s",
|
((argCount < minArgs) ? minArgs : maxArgs) == 1 ? "" : "s",
|
||||||
argCount);
|
argCount);
|
||||||
return 0;
|
return 0;
|
||||||
@ -384,8 +385,8 @@ static inline int checkArgumentCount(const KrkClosure * closure, int argCount) {
|
|||||||
static void multipleDefs(const KrkClosure * closure, int destination) {
|
static void multipleDefs(const KrkClosure * closure, int destination) {
|
||||||
krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%S'",
|
krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%S'",
|
||||||
closure->function->name ? closure->function->name->chars : "<unnamed>",
|
closure->function->name ? closure->function->name->chars : "<unnamed>",
|
||||||
(destination < closure->function->requiredArgs ? AS_STRING(closure->function->requiredArgNames.values[destination]) :
|
(destination < closure->function->potentialPositionals ? AS_STRING(closure->function->positionalArgNames.values[destination]) :
|
||||||
(destination - closure->function->requiredArgs < closure->function->keywordArgs ? AS_STRING(closure->function->keywordArgNames.values[destination - closure->function->requiredArgs]) :
|
(destination - closure->function->potentialPositionals < closure->function->keywordArgs ? AS_STRING(closure->function->keywordArgNames.values[destination - closure->function->potentialPositionals]) :
|
||||||
S("<unnamed>"))));
|
S("<unnamed>"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,6 +547,11 @@ static inline int _callManaged(KrkClosure * closure, int argCount, int returnDep
|
|||||||
argCount++;
|
argCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < closure->function->keywordArgs; ++i) {
|
||||||
|
krk_push(KWARGS_VAL(0));
|
||||||
|
argCount++;
|
||||||
|
}
|
||||||
|
|
||||||
/* We're done with the positionals */
|
/* We're done with the positionals */
|
||||||
krk_currentThread.scratchSpace[0] = NONE_VAL();
|
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 name = entry->key;
|
||||||
KrkValue value = entry->value;
|
KrkValue value = entry->value;
|
||||||
/* See if we can place it */
|
/* See if we can place it */
|
||||||
for (int j = 0; j < (int)closure->function->requiredArgs; ++j) {
|
for (int j = 0; j < (int)closure->function->potentialPositionals; ++j) {
|
||||||
if (krk_valuesEqual(name, closure->function->requiredArgNames.values[j])) {
|
if (krk_valuesSame(name, closure->function->positionalArgNames.values[j])) {
|
||||||
if (!IS_KWARGS(krk_currentThread.stackTop[-argCount + j])) {
|
if (!IS_KWARGS(krk_currentThread.stackTop[-argCount + j])) {
|
||||||
multipleDefs(closure,j);
|
multipleDefs(closure,j);
|
||||||
goto _errorAfterPositionals;
|
goto _errorAfterPositionals;
|
||||||
@ -568,12 +574,12 @@ static inline int _callManaged(KrkClosure * closure, int argCount, int returnDep
|
|||||||
}
|
}
|
||||||
/* See if it's a keyword arg. */
|
/* See if it's a keyword arg. */
|
||||||
for (int j = 0; j < (int)closure->function->keywordArgs; ++j) {
|
for (int j = 0; j < (int)closure->function->keywordArgs; ++j) {
|
||||||
if (krk_valuesEqual(name, closure->function->keywordArgNames.values[j])) {
|
if (krk_valuesSame(name, closure->function->keywordArgNames.values[j])) {
|
||||||
if (!IS_KWARGS(krk_currentThread.stackTop[-argCount + j + closure->function->requiredArgs])) {
|
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->requiredArgs);
|
multipleDefs(closure, j + closure->function->potentialPositionals);
|
||||||
goto _errorAfterPositionals;
|
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;
|
goto _finishKwarg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -603,14 +609,21 @@ _finishKwarg:
|
|||||||
|
|
||||||
for (size_t i = 0; i < (size_t)closure->function->requiredArgs; ++i) {
|
for (size_t i = 0; i < (size_t)closure->function->requiredArgs; ++i) {
|
||||||
if (IS_KWARGS(krk_currentThread.stackTop[-argCount + i])) {
|
if (IS_KWARGS(krk_currentThread.stackTop[-argCount + i])) {
|
||||||
krk_runtimeError(vm.exceptions->typeError, "%s() missing required positional argument: '%S'",
|
if (i < closure->function->localNameCount) {
|
||||||
closure->function->name ? closure->function->name->chars : "<unnamed>",
|
krk_runtimeError(vm.exceptions->typeError, "%s() %s: '%S'",
|
||||||
AS_STRING(closure->function->requiredArgNames.values[i]));
|
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;
|
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)) {
|
} else if ((size_t)argCount > potentialPositionalArgs && (closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS)) {
|
||||||
KrkValue * startOfPositionals = &krk_currentThread.stackTop[-argCount];
|
KrkValue * startOfPositionals = &krk_currentThread.stackTop[-argCount];
|
||||||
KrkValue tmp = krk_callNativeOnStack(argCount - potentialPositionalArgs,
|
KrkValue tmp = krk_callNativeOnStack(argCount - potentialPositionalArgs,
|
||||||
@ -3018,6 +3031,16 @@ _finishPopBlock:
|
|||||||
break;
|
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:
|
default:
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ try:
|
|||||||
dis.build(template.replace('__args__','self=42'))
|
dis.build(template.replace('__args__','self=42'))
|
||||||
print('fail')
|
print('fail')
|
||||||
except SyntaxError as e:
|
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
|
# for that matter, neither can star args
|
||||||
try:
|
try:
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
struct MarshalHeader {
|
struct MarshalHeader {
|
||||||
uint8_t magic[4]; /* K R K B */
|
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));
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct FunctionHeader {
|
struct FunctionHeader {
|
||||||
@ -33,6 +33,7 @@ struct FunctionHeader {
|
|||||||
uint32_t qualInd;
|
uint32_t qualInd;
|
||||||
uint16_t reqArgs;
|
uint16_t reqArgs;
|
||||||
uint16_t kwArgs;
|
uint16_t kwArgs;
|
||||||
|
uint16_t posArgs;
|
||||||
uint16_t upvalues;
|
uint16_t upvalues;
|
||||||
uint32_t locals;
|
uint32_t locals;
|
||||||
uint32_t bcSize;
|
uint32_t bcSize;
|
||||||
@ -219,8 +220,8 @@ static int doFirstPass(FILE * out) {
|
|||||||
if (func->docstring) internString(func->docstring);
|
if (func->docstring) internString(func->docstring);
|
||||||
if (func->qualname) internString(func->qualname);
|
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) {
|
for (size_t i = 0; i < (size_t)func->potentialPositionals + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); ++i) {
|
||||||
internString(AS_STRING(func->requiredArgNames.values[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) {
|
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->qualname ? internString(func->qualname) : UINT32_MAX,
|
||||||
func->requiredArgs,
|
func->requiredArgs,
|
||||||
func->keywordArgs,
|
func->keywordArgs,
|
||||||
|
func->potentialPositionals,
|
||||||
func->upvalueCount,
|
func->upvalueCount,
|
||||||
func->localNameCount,
|
func->localNameCount,
|
||||||
func->chunk.count,
|
func->chunk.count,
|
||||||
@ -278,8 +280,8 @@ static int doSecondPass(FILE * out) {
|
|||||||
fwrite(&header, 1, sizeof(struct FunctionHeader), out);
|
fwrite(&header, 1, sizeof(struct FunctionHeader), out);
|
||||||
|
|
||||||
/* Argument names first */
|
/* Argument names first */
|
||||||
for (size_t i = 0; i < (size_t)func->requiredArgs + !!(func->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); ++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->requiredArgNames.values[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) {
|
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 */
|
/* Start with the primary header */
|
||||||
struct MarshalHeader header = {
|
struct MarshalHeader header = {
|
||||||
{'K','R','K','B'},
|
{'K','R','K','B'},
|
||||||
{'1','0','1','1'},
|
{'1','0','1','2'},
|
||||||
};
|
};
|
||||||
|
|
||||||
fwrite(&header, 1, sizeof(header), out);
|
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)
|
if (memcmp(header.magic,(uint8_t[]){'K','R','K','B'},4) != 0)
|
||||||
return fprintf(stderr, "Invalid header.\n"), 1;
|
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;
|
return fprintf(stderr, "Bytecode is for a different version.\n"), 2;
|
||||||
|
|
||||||
/* Read string table */
|
/* Read string table */
|
||||||
@ -544,14 +546,14 @@ static int readFile(char * fileName) {
|
|||||||
self->keywordArgs = function.kwArgs;
|
self->keywordArgs = function.kwArgs;
|
||||||
self->obj.flags = function.flags;
|
self->obj.flags = function.flags;
|
||||||
self->upvalueCount = function.upvalues;
|
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);
|
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 */
|
/* Read argument names */
|
||||||
DEBUGOUT(" [Required Arguments]\n");
|
DEBUGOUT(" [Positional Arguments]\n");
|
||||||
for (size_t i = 0; i < (size_t)function.reqArgs + !!(self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); i++) {
|
for (size_t i = 0; i < (size_t)function.posArgs + !!(self->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS); i++) {
|
||||||
krk_writeValueArray(&self->requiredArgNames, valueFromConstant(i,inFile));
|
krk_writeValueArray(&self->positionalArgNames, valueFromConstant(i,inFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUGOUT(" [Keyword Arguments]\n");
|
DEBUGOUT(" [Keyword Arguments]\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user