Rewrite complex argument processor because that old stack-juggling version was awful
This commit is contained in:
parent
30cbeeb85e
commit
3532f24c75
@ -34,13 +34,13 @@ const char krk_builtinsSrc[] =
|
||||
" let i=0\n"
|
||||
" let c=self.t.capacity()\n"
|
||||
" def _():\n"
|
||||
" let o=None\n"
|
||||
" while o==None and i<c:\n"
|
||||
" let o=(False,None)\n"
|
||||
" while not o[0] and i<c:\n"
|
||||
" o=self.t._key_at_index(i)\n"
|
||||
" i++\n"
|
||||
" if o==None:\n"
|
||||
" if not o[0]:\n"
|
||||
" return _\n"
|
||||
" return o\n"
|
||||
" return o[1]\n"
|
||||
" return _\n"
|
||||
" return KeyIterator(self)\n"
|
||||
" def items(self):\n"
|
||||
|
@ -33,13 +33,13 @@ class dict():
|
||||
let i=0
|
||||
let c=self.t.capacity()
|
||||
def _():
|
||||
let o=None
|
||||
while o==None and i<c:
|
||||
let o=(False,None)
|
||||
while not o[0] and i<c:
|
||||
o=self.t._key_at_index(i)
|
||||
i++
|
||||
if o==None:
|
||||
if not o[0]:
|
||||
return _
|
||||
return o
|
||||
return o[1]
|
||||
return _
|
||||
return KeyIterator(self)
|
||||
def items(self):
|
||||
|
2
kuroko.c
2
kuroko.c
@ -311,7 +311,9 @@ int main(int argc, char * argv[]) {
|
||||
krk_push(OBJECT_VAL(krk_copyString(argv[arg],strlen(argv[arg]))));
|
||||
}
|
||||
KrkValue argList = krk_list_of(argc - optind + (optind == argc), &vm.stackTop[-(argc - optind + (optind == argc))]);
|
||||
krk_push(argList);
|
||||
krk_attachNamedValue(&vm.system->fields, "argv", argList);
|
||||
krk_pop();
|
||||
for (int arg = optind; arg < argc + (optind == argc); ++arg) krk_pop();
|
||||
|
||||
/* Bind interrupt signal */
|
||||
|
18
table.c
18
table.c
@ -34,7 +34,7 @@ KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue
|
||||
KrkTableEntry * tombstone = NULL;
|
||||
for (;;) {
|
||||
KrkTableEntry * entry = &entries[index];
|
||||
if (entry->key.type == VAL_NONE) {
|
||||
if (entry->key.type == VAL_KWARGS) {
|
||||
if (IS_NONE(entry->value)) {
|
||||
return tombstone != NULL ? tombstone : entry;
|
||||
} else {
|
||||
@ -50,14 +50,14 @@ KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue
|
||||
static void adjustCapacity(KrkTable * table, size_t capacity) {
|
||||
KrkTableEntry * entries = ALLOCATE(KrkTableEntry, capacity);
|
||||
for (size_t i = 0; i < capacity; ++i) {
|
||||
entries[i].key = NONE_VAL();
|
||||
entries[i].key = KWARGS_VAL(0);
|
||||
entries[i].value = NONE_VAL();
|
||||
}
|
||||
|
||||
table->count = 0;
|
||||
for (size_t i = 0; i < table->capacity; ++i) {
|
||||
KrkTableEntry * entry = &table->entries[i];
|
||||
if (entry->key.type == VAL_NONE) continue;
|
||||
if (entry->key.type == VAL_KWARGS) continue;
|
||||
KrkTableEntry * dest = krk_findEntry(entries, capacity, entry->key);
|
||||
dest->key = entry->key;
|
||||
dest->value = entry->value;
|
||||
@ -75,7 +75,7 @@ int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value) {
|
||||
adjustCapacity(table, capacity);
|
||||
}
|
||||
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
|
||||
int isNewKey = entry->key.type == VAL_NONE;
|
||||
int isNewKey = entry->key.type == VAL_KWARGS;
|
||||
if (isNewKey && IS_NONE(entry->value)) table->count++;
|
||||
entry->key = key;
|
||||
entry->value = value;
|
||||
@ -85,7 +85,7 @@ int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value) {
|
||||
void krk_tableAddAll(KrkTable * from, KrkTable * to) {
|
||||
for (size_t i = 0; i < from->capacity; ++i) {
|
||||
KrkTableEntry * entry = &from->entries[i];
|
||||
if (entry->key.type != VAL_NONE) {
|
||||
if (entry->key.type != VAL_KWARGS) {
|
||||
krk_tableSet(to, entry->key, entry->value);
|
||||
}
|
||||
}
|
||||
@ -94,7 +94,7 @@ void krk_tableAddAll(KrkTable * from, KrkTable * to) {
|
||||
int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value) {
|
||||
if (table->count == 0) return 0;
|
||||
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
|
||||
if (entry->key.type == VAL_NONE) return 0;
|
||||
if (entry->key.type == VAL_KWARGS) return 0;
|
||||
*value = entry->value;
|
||||
return 1;
|
||||
}
|
||||
@ -102,8 +102,8 @@ int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value) {
|
||||
int krk_tableDelete(KrkTable * table, KrkValue key) {
|
||||
if (table->count == 0) return 0;
|
||||
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
|
||||
if (entry->key.type == VAL_NONE) return 0;
|
||||
entry->key = NONE_VAL();
|
||||
if (entry->key.type == VAL_KWARGS) return 0;
|
||||
entry->key = KWARGS_VAL(0);
|
||||
entry->value = BOOLEAN_VAL(1);
|
||||
return 1;
|
||||
}
|
||||
@ -114,7 +114,7 @@ KrkString * krk_tableFindString(KrkTable * table, const char * chars, size_t len
|
||||
uint32_t index = hash % table->capacity;
|
||||
for (;;) {
|
||||
KrkTableEntry * entry = &table->entries[index];
|
||||
if (entry->key.type == VAL_NONE) {
|
||||
if (entry->key.type == VAL_KWARGS) {
|
||||
if (IS_NONE(entry->value)) return NULL;
|
||||
} else if (AS_STRING(entry->key)->length == length &&
|
||||
AS_STRING(entry->key)->hash == hash &&
|
||||
|
@ -6,7 +6,7 @@ None None
|
||||
None 5
|
||||
function() missing required positional argument: 'positional2'
|
||||
function() got multiple values for argument 'positional1'
|
||||
function() got multiple values for argument 'keyword2'
|
||||
got multiple values for argument 'keyword2'
|
||||
1 abc
|
||||
None 4
|
||||
function() got multiple values for argument 'positional1'
|
||||
|
16
test/testMoreArgExpansions.krk
Normal file
16
test/testMoreArgExpansions.krk
Normal file
@ -0,0 +1,16 @@
|
||||
import kuroko
|
||||
let l = [x for x in range(1,1000)]
|
||||
|
||||
print(l)
|
||||
#print(kuroko.getstackstatus())
|
||||
|
||||
def foo(*args):
|
||||
#print(kuroko.getstackstatus())
|
||||
print(len(args))
|
||||
print(args)
|
||||
for i in args:
|
||||
print(i)
|
||||
|
||||
foo(*l)
|
||||
#foo(*l,*l)
|
||||
#foo(*l,*l,*l)
|
1002
test/testMoreArgExpansions.krk.expect
Normal file
1002
test/testMoreArgExpansions.krk.expect
Normal file
File diff suppressed because it is too large
Load Diff
2
value.c
2
value.c
@ -42,6 +42,8 @@ void krk_printValue(FILE * f, KrkValue printable) {
|
||||
fprintf(f, "{unpack list}");
|
||||
} else if (AS_INTEGER(printable) == LONG_MAX-2) {
|
||||
fprintf(f, "{unpack dict}");
|
||||
} else if (AS_INTEGER(printable) == LONG_MAX-3) {
|
||||
fprintf(f, "{unpack nil}");
|
||||
} else if (AS_INTEGER(printable) == 0) {
|
||||
fprintf(f, "{unset default}");
|
||||
} else {
|
||||
|
376
vm.c
376
vm.c
@ -412,7 +412,13 @@ static KrkValue _dict_key_at_index(int argc, KrkValue argv[]) {
|
||||
return NONE_VAL();
|
||||
}
|
||||
KrkTableEntry entry = AS_DICT(_dict_internal)->entries[i];
|
||||
return entry.key;
|
||||
KrkTuple * outValue = krk_newTuple(2);
|
||||
krk_push(OBJECT_VAL(outValue));
|
||||
outValue->values.values[0] = IS_KWARGS(entry.key) ? BOOLEAN_VAL(0) : BOOLEAN_VAL(1);
|
||||
outValue->values.values[1] = IS_KWARGS(entry.key) ? NONE_VAL() : entry.key;
|
||||
outValue->values.count = 2;
|
||||
krk_pop();
|
||||
return OBJECT_VAL(outValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -659,7 +665,7 @@ KrkValue krk_dirObject(int argc, KrkValue argv[]) {
|
||||
|
||||
/* First add each method of the class */
|
||||
for (size_t i = 0; i < self->_class->methods.capacity; ++i) {
|
||||
if (self->_class->methods.entries[i].key.type != VAL_NONE) {
|
||||
if (self->_class->methods.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(_list_internal),
|
||||
self->_class->methods.entries[i].key);
|
||||
}
|
||||
@ -667,7 +673,7 @@ KrkValue krk_dirObject(int argc, KrkValue argv[]) {
|
||||
|
||||
/* Then add each field of the instance */
|
||||
for (size_t i = 0; i < self->fields.capacity; ++i) {
|
||||
if (self->fields.entries[i].key.type != VAL_NONE) {
|
||||
if (self->fields.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(_list_internal),
|
||||
self->fields.entries[i].key);
|
||||
}
|
||||
@ -676,7 +682,7 @@ KrkValue krk_dirObject(int argc, KrkValue argv[]) {
|
||||
KrkClass * type = AS_CLASS(krk_typeOf(1, (KrkValue[]){argv[0]}));
|
||||
|
||||
for (size_t i = 0; i < type->methods.capacity; ++i) {
|
||||
if (type->methods.entries[i].key.type != VAL_NONE) {
|
||||
if (type->methods.entries[i].key.type != VAL_KWARGS) {
|
||||
krk_writeValueArray(AS_LIST(_list_internal),
|
||||
type->methods.entries[i].key);
|
||||
}
|
||||
@ -837,7 +843,76 @@ static void multipleDefs(KrkClosure * closure, int destination) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "%s() got multiple values for argument '%s'",
|
||||
closure->function->name ? closure->function->name->chars : "<unnamed function>",
|
||||
(destination < closure->function->requiredArgs ? AS_CSTRING(closure->function->requiredArgNames.values[destination]) :
|
||||
AS_CSTRING(closure->function->keywordArgNames.values[destination - closure->function->requiredArgs])));
|
||||
(destination - closure->function->requiredArgs < closure->function->keywordArgs ? AS_CSTRING(closure->function->keywordArgNames.values[destination - closure->function->requiredArgs]) :
|
||||
"(unnamed arg)")));
|
||||
}
|
||||
|
||||
int krk_processComplexArguments(int argCount, KrkValueArray * positionals, KrkTable * keywords) {
|
||||
size_t kwargsCount = AS_INTEGER(vm.stackTop[-1]);
|
||||
krk_pop(); /* Pop the arg counter */
|
||||
argCount--;
|
||||
|
||||
krk_initValueArray(positionals);
|
||||
krk_initTable(keywords);
|
||||
|
||||
/* First, process all the positionals, including any from extractions. */
|
||||
size_t existingPositionalArgs = argCount - kwargsCount * 2;
|
||||
for (size_t i = 0; i < existingPositionalArgs; ++i) {
|
||||
krk_writeValueArray(positionals, vm.stackTop[-argCount + i]);
|
||||
}
|
||||
|
||||
KrkValue * startOfExtras = &vm.stackTop[-kwargsCount * 2];
|
||||
/* Now unpack everything else. */
|
||||
for (size_t i = 0; i < kwargsCount; ++i) {
|
||||
KrkValue key = startOfExtras[i*2];
|
||||
KrkValue value = startOfExtras[i*2 + 1];
|
||||
if (IS_KWARGS(key)) {
|
||||
if (AS_INTEGER(key) == LONG_MAX-1) { /* unpack list */
|
||||
if (!IS_INSTANCE(value) || !AS_INSTANCE(value)->_internal || !(((KrkObj*)(AS_INSTANCE(value)->_internal))->type == OBJ_FUNCTION)) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "*expresssion value is not a list.");
|
||||
return 0;
|
||||
}
|
||||
KrkValue _list_internal = OBJECT_VAL(AS_INSTANCE(value)->_internal);
|
||||
/* Add all values from 'value' to 'positionals' */
|
||||
if (positionals->count + AS_LIST(_list_internal)->count > positionals->capacity) {
|
||||
size_t old = positionals->capacity;
|
||||
positionals->capacity = positionals->count + AS_LIST(_list_internal)->count;
|
||||
positionals->values = GROW_ARRAY(KrkValue,positionals->values,old,positionals->capacity);
|
||||
}
|
||||
KrkValue * destination = &positionals->values[positionals->count];
|
||||
memcpy(destination, AS_LIST(_list_internal)->values, AS_LIST(_list_internal)->count * sizeof(KrkValue));
|
||||
positionals->count = positionals->count + AS_LIST(_list_internal)->count;
|
||||
} else if (AS_INTEGER(key) == LONG_MAX-2) { /* unpack dict */
|
||||
if (!IS_INSTANCE(value) || !AS_INSTANCE(value)->_internal || !(((KrkObj*)(AS_INSTANCE(value)->_internal))->type == OBJ_CLASS)) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "**expresssion value is not a dict.");
|
||||
return 0;
|
||||
}
|
||||
KrkValue _dict_internal = OBJECT_VAL(AS_INSTANCE(value)->_internal);
|
||||
for (size_t i = 0; i < AS_DICT(_dict_internal)->capacity; ++i) {
|
||||
KrkTableEntry * entry = &AS_DICT(_dict_internal)->entries[i];
|
||||
if (entry->key.type != VAL_KWARGS) {
|
||||
if (!IS_STRING(entry->key)) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "**expression contains non-string key");
|
||||
return 0;
|
||||
}
|
||||
if (!krk_tableSet(keywords, entry->key, entry->value)) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "got multiple values for argument '%s'", AS_CSTRING(entry->key));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (AS_INTEGER(key) == LONG_MAX) { /* single value */
|
||||
krk_writeValueArray(positionals, value);
|
||||
}
|
||||
} else if (IS_STRING(key)) {
|
||||
if (!krk_tableSet(keywords, key, value)) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "got multiple values for argument '%s'", AS_CSTRING(key));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -855,223 +930,118 @@ static int call(KrkClosure * closure, int argCount, int extra) {
|
||||
size_t potentialPositionalArgs = closure->function->requiredArgs + closure->function->keywordArgs;
|
||||
size_t totalArguments = closure->function->requiredArgs + closure->function->keywordArgs + closure->function->collectsArguments + closure->function->collectsKeywords;
|
||||
size_t offsetOfExtraArgs = closure->function->requiredArgs + closure->function->keywordArgs;
|
||||
size_t offsetOfExtraKeys = offsetOfExtraArgs + closure->function->collectsArguments;
|
||||
size_t argCountX = argCount;
|
||||
KrkValueArray positionals;
|
||||
KrkTable keywords;
|
||||
|
||||
if (argCount && IS_KWARGS(vm.stackTop[-1])) {
|
||||
/**
|
||||
* Process keyword arguments.
|
||||
* First, we make sure there is enough space on the stack to fit all of
|
||||
* the potential arguments to this function. We need to call it with
|
||||
* all of its arguments - positional and keyword - ready to go, even
|
||||
* if they weren't specified.
|
||||
*
|
||||
* Then we go through all of the kwargs and figure out where they go,
|
||||
* building a table at the top of the stack of final offsets and values.
|
||||
*
|
||||
* Then we clear through all of the spaces that were previously
|
||||
* kwarg name/value pairs and replace them with a sentinel value.
|
||||
*
|
||||
* Then we go through our table and place values into their destination
|
||||
* spots. If we find that something is already there (because it's not
|
||||
* the expected sentinel value), we raise a TypeError indicating a
|
||||
* duplicate argument.
|
||||
*
|
||||
* Finally, we do one last pass to see if any of the sentinel values
|
||||
* indicating missing positional arguments is still there and raise
|
||||
* another TypeError to indicate missing required arguments.
|
||||
*
|
||||
* At this point we can reset the stack head and continue to the actual
|
||||
* call with all of the arguments, including the defaults, in the right
|
||||
* place for the function to pull them as locals.
|
||||
*/
|
||||
long kwargsCount = AS_INTEGER(vm.stackTop[-1]);
|
||||
krk_pop(); /* Pop the arg counter */
|
||||
argCount--;
|
||||
size_t existingPositionalArgs = argCount - kwargsCount * 2;
|
||||
int found = 0;
|
||||
int extraKwargs = 0;
|
||||
intptr_t positionalsOffset = &vm.stackTop[-argCount] - vm.stack;
|
||||
intptr_t endOffset = &vm.stackTop[-kwargsCount * 2] - vm.stack;
|
||||
KRK_PAUSE_GC();
|
||||
|
||||
for (size_t availableSlots = argCount; availableSlots < (totalArguments); ++availableSlots) {
|
||||
krk_push(KWARGS_VAL(0)); /* Make sure we definitely have enough space */
|
||||
/* This processes the existing argument list into a ValueArray and a Table with the args and keywords */
|
||||
if (!krk_processComplexArguments(argCount, &positionals, &keywords)) goto _errorDuringPositionals;
|
||||
argCount--; /* It popped the KWARGS value from the top, so we have one less argument */
|
||||
|
||||
/* Do we already know we have too many arguments? Let's bail before doing a bunch of work. */
|
||||
if ((positionals.count > potentialPositionalArgs) && (!closure->function->collectsArguments)) {
|
||||
checkArgumentCount(closure,positionals.count);
|
||||
goto _errorDuringPositionals;
|
||||
}
|
||||
|
||||
/* Expand the stack a bunch to make sure we have space */
|
||||
for (int i = 0; i < argCount * 2; ++i) {
|
||||
/* Prepare stack space for all potential positionals, mark them unset */
|
||||
for (size_t i = 0; i < (size_t)argCount; ++i) {
|
||||
vm.stackTop[-argCount + i] = KWARGS_VAL(0);
|
||||
}
|
||||
|
||||
/* Do we have a bunch of unused keyword argument slots? Fill them in. */
|
||||
while ((size_t)argCount < potentialPositionalArgs) {
|
||||
krk_push(KWARGS_VAL(0));
|
||||
}
|
||||
for (int i = 0; i < argCount * 2; ++i) {
|
||||
krk_pop();
|
||||
argCount++;
|
||||
}
|
||||
|
||||
/* We may have moved the stack, recalculate positions. */
|
||||
startOfPositionals = vm.stack + positionalsOffset;
|
||||
KrkValue * endOfPositionals = vm.stack + endOffset;
|
||||
KrkValue * startOfExtras = vm.stackTop;
|
||||
for (long i = 0; i < kwargsCount; ++i) {
|
||||
KrkValue name = endOfPositionals[i*2];
|
||||
KrkValue value = endOfPositionals[i*2+1];
|
||||
if (IS_KWARGS(name)) {
|
||||
krk_push(name);
|
||||
krk_push(value);
|
||||
found++;
|
||||
goto _finishArg;
|
||||
}
|
||||
/* First, see if it's a positional arg. */
|
||||
for (int j = 0; j < (int)closure->function->requiredArgs; ++j) {
|
||||
if (krk_valuesEqual(name, closure->function->requiredArgNames.values[j])) {
|
||||
krk_push(INTEGER_VAL(j));
|
||||
krk_push(value);
|
||||
found++;
|
||||
goto _finishArg;
|
||||
/* Did we have way more arguments than we needed? Put the stack where it should be. */
|
||||
while ((size_t)argCount > potentialPositionalArgs) {
|
||||
krk_pop();
|
||||
argCount--;
|
||||
}
|
||||
|
||||
/* Place positional arguments */
|
||||
for (size_t i = 0; i < potentialPositionalArgs && i < positionals.count; ++i) {
|
||||
vm.stackTop[-argCount + i] = positionals.values[i];
|
||||
}
|
||||
|
||||
if (closure->function->collectsArguments) {
|
||||
size_t count = (positionals.count > potentialPositionalArgs) ? (positionals.count - potentialPositionalArgs) : 0;
|
||||
KrkValue * offset = (count == 0) ? NULL : &positionals.values[potentialPositionalArgs];
|
||||
krk_push(krk_list_of(count, offset));
|
||||
argCount++;
|
||||
}
|
||||
|
||||
krk_freeValueArray(&positionals);
|
||||
|
||||
/* Now place keyword arguments */
|
||||
for (size_t i = 0; i < keywords.capacity; ++i) {
|
||||
KrkTableEntry * entry = &keywords.entries[i];
|
||||
if (entry->key.type != VAL_KWARGS) {
|
||||
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])) {
|
||||
if (!IS_KWARGS(vm.stackTop[-argCount + j])) {
|
||||
multipleDefs(closure,j);
|
||||
goto _errorAfterPositionals;
|
||||
}
|
||||
vm.stackTop[-argCount + j] = value;
|
||||
goto _finishKwarg;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 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])) {
|
||||
krk_push(INTEGER_VAL(j + closure->function->requiredArgs));
|
||||
krk_push(value);
|
||||
found++;
|
||||
goto _finishArg;
|
||||
/* 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(vm.stackTop[-argCount + j + closure->function->requiredArgs])) {
|
||||
multipleDefs(closure, j + closure->function->requiredArgs);
|
||||
goto _errorAfterPositionals;
|
||||
}
|
||||
vm.stackTop[-argCount + j + closure->function->requiredArgs] = value;
|
||||
goto _finishKwarg;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If we got to this point, it's not a recognized argument for this function. */
|
||||
if (closure->function->collectsKeywords) {
|
||||
krk_push(name);
|
||||
krk_push(value);
|
||||
found++;
|
||||
extraKwargs++;
|
||||
if (!closure->function->collectsKeywords) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "%s() got an unexpected keyword argument '%s'",
|
||||
closure->function->name ? closure->function->name->chars : "<unnamed function>",
|
||||
AS_CSTRING(name));
|
||||
goto _errorAfterPositionals;
|
||||
}
|
||||
continue;
|
||||
_finishKwarg:
|
||||
entry->key = KWARGS_VAL(0);
|
||||
entry->value = BOOLEAN_VAL(1);
|
||||
continue;
|
||||
}
|
||||
krk_runtimeError(vm.exceptions.typeError, "%s() got an unexpected keyword argument '%s'",
|
||||
closure->function->name ? closure->function->name->chars : "<unnamed function>",
|
||||
AS_CSTRING(name));
|
||||
return 0;
|
||||
_finishArg:
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t destination = existingPositionalArgs;
|
||||
for (long i = 0; i < found; ++i) {
|
||||
/* Check for specials */
|
||||
KrkValue name = startOfExtras[i*2];
|
||||
KrkValue value = startOfExtras[i*2+1];
|
||||
if (IS_KWARGS(name)) {
|
||||
if (AS_INTEGER(name) == LONG_MAX-1) {
|
||||
if (!IS_INSTANCE(value) || !AS_INSTANCE(value)->_internal || !((KrkObj*)(AS_INSTANCE(value)->_internal))->type == OBJ_FUNCTION) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "*expresssion value is not a list.");
|
||||
return 0;
|
||||
}
|
||||
KrkValue _list_internal = OBJECT_VAL(AS_INSTANCE(value)->_internal);
|
||||
for (size_t i = 0; i < AS_LIST(_list_internal)->count; ++i) {
|
||||
startOfPositionals[destination] = AS_LIST(_list_internal)->values[i];
|
||||
destination++;
|
||||
}
|
||||
startOfExtras[i*2] = KWARGS_VAL(LONG_MAX-3);
|
||||
} else if (AS_INTEGER(name) == LONG_MAX) {
|
||||
startOfPositionals[destination] = value;
|
||||
destination++;
|
||||
startOfExtras[i*2] = KWARGS_VAL(LONG_MAX-3);
|
||||
}
|
||||
}
|
||||
/* If this function takes a **kwargs, we need to provide it as a dict */
|
||||
if (closure->function->collectsKeywords) {
|
||||
krk_push(krk_dict_of(0,NULL));
|
||||
argCount++;
|
||||
KrkValue _dict_internal;
|
||||
krk_tableGet(&AS_INSTANCE(krk_peek(0))->fields, vm.specialMethodNames[METHOD_DICT_INT], &_dict_internal);
|
||||
krk_tableAddAll(&keywords, AS_DICT(_dict_internal));
|
||||
}
|
||||
|
||||
if (destination > potentialPositionalArgs) {
|
||||
if (!closure->function->collectsArguments) {
|
||||
checkArgumentCount(closure,destination);
|
||||
return 0;
|
||||
}
|
||||
krk_push(NONE_VAL()); krk_push(NONE_VAL()); krk_pop(); krk_pop();
|
||||
startOfPositionals[offsetOfExtraArgs] = krk_list_of(destination - potentialPositionalArgs,
|
||||
&startOfPositionals[potentialPositionalArgs]);
|
||||
destination = potentialPositionalArgs + 1;
|
||||
}
|
||||
krk_freeTable(&keywords);
|
||||
|
||||
for (long clearSlots = destination; clearSlots < startOfExtras - startOfPositionals; ++clearSlots) {
|
||||
startOfPositionals[clearSlots] = KWARGS_VAL(0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < found; ++i) {
|
||||
if (IS_INTEGER(startOfExtras[i*2])) {
|
||||
int destination = AS_INTEGER(startOfExtras[i*2]);
|
||||
if (!IS_KWARGS(startOfPositionals[destination])) {
|
||||
multipleDefs(closure, destination);
|
||||
return 0;
|
||||
}
|
||||
startOfPositionals[destination] = startOfExtras[i*2+1];
|
||||
} else if (IS_STRING(startOfExtras[i*2])) {
|
||||
krk_push(startOfExtras[i*2]);
|
||||
krk_push(startOfExtras[i*2+1]);
|
||||
} else if (IS_KWARGS(startOfExtras[i*2])) {
|
||||
if (AS_INTEGER(startOfExtras[i*2]) == LONG_MAX-2) {
|
||||
KrkValue _dict_internal;
|
||||
if (!IS_INSTANCE(startOfExtras[i*2+1]) || !krk_tableGet(&AS_INSTANCE(startOfExtras[i*2+1])->fields, vm.specialMethodNames[METHOD_DICT_INT], &_dict_internal)) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "**expresssion value is not a dict.");
|
||||
return 0;
|
||||
}
|
||||
for (size_t j = 0; j < AS_DICT(_dict_internal)->capacity; ++j) {
|
||||
KrkTableEntry entry = AS_DICT(_dict_internal)->entries[j];
|
||||
if (entry.key.type == VAL_NONE) continue;
|
||||
KrkValue name = entry.key;
|
||||
KrkValue value = entry.value;
|
||||
for (int j = 0; j < (int)closure->function->requiredArgNames.count; ++j) {
|
||||
if (krk_valuesEqual(name, closure->function->requiredArgNames.values[j])) {
|
||||
int destination = j;
|
||||
if (!IS_KWARGS(startOfPositionals[destination])) {
|
||||
multipleDefs(closure, destination);
|
||||
}
|
||||
startOfPositionals[destination] = value;
|
||||
goto _finishDictEntry;
|
||||
}
|
||||
}
|
||||
/* See if it's a keyword arg. */
|
||||
for (int j = 0; j < (int)closure->function->keywordArgNames.count; ++j) {
|
||||
if (krk_valuesEqual(name, closure->function->keywordArgNames.values[j])) {
|
||||
int destination = j + closure->function->requiredArgs;
|
||||
if (!IS_KWARGS(startOfPositionals[destination])) {
|
||||
multipleDefs(closure, destination);
|
||||
}
|
||||
startOfPositionals[destination] = value;
|
||||
goto _finishDictEntry;
|
||||
}
|
||||
}
|
||||
krk_push(name);
|
||||
krk_push(value);
|
||||
extraKwargs++;
|
||||
_finishDictEntry: continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#ifdef ENABLE_TRACING
|
||||
dumpStack(&vm.frames[vm.frameCount-1]);
|
||||
krk_runtimeError(vm.exceptions.typeError, "Internal error? Item at index %d from %d found is %s", i*2, found, krk_typeName(startOfExtras[i*2]));
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (extraKwargs) {
|
||||
if (!closure->function->collectsKeywords) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "%s() got an unexpected keyword argument '%s'",
|
||||
closure->function->name ? closure->function->name->chars : "<unnamed function>",
|
||||
AS_CSTRING(startOfExtras[found*2]));
|
||||
}
|
||||
krk_push(NONE_VAL()); krk_push(NONE_VAL()); krk_pop(); krk_pop();
|
||||
startOfPositionals[offsetOfExtraKeys] = krk_dict_of(extraKwargs*2,&startOfExtras[found*2]);
|
||||
}
|
||||
long clearSlots;
|
||||
for (clearSlots = destination; clearSlots < closure->function->requiredArgs; ++clearSlots) {
|
||||
if (IS_KWARGS(startOfPositionals[clearSlots])) {
|
||||
for (size_t i = 0; i < (size_t)closure->function->requiredArgs; ++i) {
|
||||
if (IS_KWARGS(vm.stackTop[-argCount + i])) {
|
||||
krk_runtimeError(vm.exceptions.typeError, "%s() missing required positional argument: '%s'",
|
||||
closure->function->name ? closure->function->name->chars : "<unnamed function>",
|
||||
AS_CSTRING(closure->function->requiredArgNames.values[clearSlots]));
|
||||
return 0;
|
||||
AS_CSTRING(closure->function->requiredArgNames.values[i]));
|
||||
goto _errorAfterKeywords;
|
||||
}
|
||||
}
|
||||
argCount = totalArguments;
|
||||
|
||||
KRK_RESUME_GC();
|
||||
argCountX = argCount - (closure->function->collectsArguments + closure->function->collectsKeywords);
|
||||
while (vm.stackTop > startOfPositionals + argCount) krk_pop();
|
||||
} else {
|
||||
/* We can't have had any kwargs. */
|
||||
if ((size_t)argCount > potentialPositionalArgs && closure->function->collectsArguments) {
|
||||
@ -1101,6 +1071,14 @@ _finishArg:
|
||||
frame->outSlots = (vm.stackTop - argCount - extra) - vm.stack;
|
||||
frame->globals = &closure->function->globalsContext->fields;
|
||||
return 1;
|
||||
|
||||
_errorDuringPositionals:
|
||||
krk_freeValueArray(&positionals);
|
||||
_errorAfterPositionals:
|
||||
krk_freeTable(&keywords);
|
||||
_errorAfterKeywords:
|
||||
KRK_RESUME_GC();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user