Rewrite complex argument processor because that old stack-juggling version was awful

This commit is contained in:
K. Lange 2021-01-10 18:23:28 +09:00
parent 30cbeeb85e
commit 3532f24c75
9 changed files with 1217 additions and 217 deletions

View File

@ -34,13 +34,13 @@ const char krk_builtinsSrc[] =
" let i=0\n" " let i=0\n"
" let c=self.t.capacity()\n" " let c=self.t.capacity()\n"
" def _():\n" " def _():\n"
" let o=None\n" " let o=(False,None)\n"
" while o==None and i<c:\n" " while not o[0] and i<c:\n"
" o=self.t._key_at_index(i)\n" " o=self.t._key_at_index(i)\n"
" i++\n" " i++\n"
" if o==None:\n" " if not o[0]:\n"
" return _\n" " return _\n"
" return o\n" " return o[1]\n"
" return _\n" " return _\n"
" return KeyIterator(self)\n" " return KeyIterator(self)\n"
" def items(self):\n" " def items(self):\n"

View File

@ -33,13 +33,13 @@ class dict():
let i=0 let i=0
let c=self.t.capacity() let c=self.t.capacity()
def _(): def _():
let o=None let o=(False,None)
while o==None and i<c: while not o[0] and i<c:
o=self.t._key_at_index(i) o=self.t._key_at_index(i)
i++ i++
if o==None: if not o[0]:
return _ return _
return o return o[1]
return _ return _
return KeyIterator(self) return KeyIterator(self)
def items(self): def items(self):

View File

@ -311,7 +311,9 @@ int main(int argc, char * argv[]) {
krk_push(OBJECT_VAL(krk_copyString(argv[arg],strlen(argv[arg])))); 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))]); 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_attachNamedValue(&vm.system->fields, "argv", argList);
krk_pop();
for (int arg = optind; arg < argc + (optind == argc); ++arg) krk_pop(); for (int arg = optind; arg < argc + (optind == argc); ++arg) krk_pop();
/* Bind interrupt signal */ /* Bind interrupt signal */

18
table.c
View File

@ -34,7 +34,7 @@ KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue
KrkTableEntry * tombstone = NULL; KrkTableEntry * tombstone = NULL;
for (;;) { for (;;) {
KrkTableEntry * entry = &entries[index]; KrkTableEntry * entry = &entries[index];
if (entry->key.type == VAL_NONE) { if (entry->key.type == VAL_KWARGS) {
if (IS_NONE(entry->value)) { if (IS_NONE(entry->value)) {
return tombstone != NULL ? tombstone : entry; return tombstone != NULL ? tombstone : entry;
} else { } else {
@ -50,14 +50,14 @@ KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue
static void adjustCapacity(KrkTable * table, size_t capacity) { static void adjustCapacity(KrkTable * table, size_t capacity) {
KrkTableEntry * entries = ALLOCATE(KrkTableEntry, capacity); KrkTableEntry * entries = ALLOCATE(KrkTableEntry, capacity);
for (size_t i = 0; i < capacity; ++i) { for (size_t i = 0; i < capacity; ++i) {
entries[i].key = NONE_VAL(); entries[i].key = KWARGS_VAL(0);
entries[i].value = NONE_VAL(); entries[i].value = NONE_VAL();
} }
table->count = 0; table->count = 0;
for (size_t i = 0; i < table->capacity; ++i) { for (size_t i = 0; i < table->capacity; ++i) {
KrkTableEntry * entry = &table->entries[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); KrkTableEntry * dest = krk_findEntry(entries, capacity, entry->key);
dest->key = entry->key; dest->key = entry->key;
dest->value = entry->value; dest->value = entry->value;
@ -75,7 +75,7 @@ int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value) {
adjustCapacity(table, capacity); adjustCapacity(table, capacity);
} }
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key); 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++; if (isNewKey && IS_NONE(entry->value)) table->count++;
entry->key = key; entry->key = key;
entry->value = value; entry->value = value;
@ -85,7 +85,7 @@ int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value) {
void krk_tableAddAll(KrkTable * from, KrkTable * to) { void krk_tableAddAll(KrkTable * from, KrkTable * to) {
for (size_t i = 0; i < from->capacity; ++i) { for (size_t i = 0; i < from->capacity; ++i) {
KrkTableEntry * entry = &from->entries[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); 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) { int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value) {
if (table->count == 0) return 0; if (table->count == 0) return 0;
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key); 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; *value = entry->value;
return 1; return 1;
} }
@ -102,8 +102,8 @@ int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value) {
int krk_tableDelete(KrkTable * table, KrkValue key) { int krk_tableDelete(KrkTable * table, KrkValue key) {
if (table->count == 0) return 0; if (table->count == 0) return 0;
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key); 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;
entry->key = NONE_VAL(); entry->key = KWARGS_VAL(0);
entry->value = BOOLEAN_VAL(1); entry->value = BOOLEAN_VAL(1);
return 1; return 1;
} }
@ -114,7 +114,7 @@ KrkString * krk_tableFindString(KrkTable * table, const char * chars, size_t len
uint32_t index = hash % table->capacity; uint32_t index = hash % table->capacity;
for (;;) { for (;;) {
KrkTableEntry * entry = &table->entries[index]; KrkTableEntry * entry = &table->entries[index];
if (entry->key.type == VAL_NONE) { if (entry->key.type == VAL_KWARGS) {
if (IS_NONE(entry->value)) return NULL; if (IS_NONE(entry->value)) return NULL;
} else if (AS_STRING(entry->key)->length == length && } else if (AS_STRING(entry->key)->length == length &&
AS_STRING(entry->key)->hash == hash && AS_STRING(entry->key)->hash == hash &&

View File

@ -6,7 +6,7 @@ None None
None 5 None 5
function() missing required positional argument: 'positional2' function() missing required positional argument: 'positional2'
function() got multiple values for argument 'positional1' function() got multiple values for argument 'positional1'
function() got multiple values for argument 'keyword2' got multiple values for argument 'keyword2'
1 abc 1 abc
None 4 None 4
function() got multiple values for argument 'positional1' function() got multiple values for argument 'positional1'

View 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)

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,8 @@ void krk_printValue(FILE * f, KrkValue printable) {
fprintf(f, "{unpack list}"); fprintf(f, "{unpack list}");
} else if (AS_INTEGER(printable) == LONG_MAX-2) { } else if (AS_INTEGER(printable) == LONG_MAX-2) {
fprintf(f, "{unpack dict}"); fprintf(f, "{unpack dict}");
} else if (AS_INTEGER(printable) == LONG_MAX-3) {
fprintf(f, "{unpack nil}");
} else if (AS_INTEGER(printable) == 0) { } else if (AS_INTEGER(printable) == 0) {
fprintf(f, "{unset default}"); fprintf(f, "{unset default}");
} else { } else {

376
vm.c
View File

@ -412,7 +412,13 @@ static KrkValue _dict_key_at_index(int argc, KrkValue argv[]) {
return NONE_VAL(); return NONE_VAL();
} }
KrkTableEntry entry = AS_DICT(_dict_internal)->entries[i]; 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 */ /* First add each method of the class */
for (size_t i = 0; i < self->_class->methods.capacity; ++i) { 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), krk_writeValueArray(AS_LIST(_list_internal),
self->_class->methods.entries[i].key); self->_class->methods.entries[i].key);
} }
@ -667,7 +673,7 @@ KrkValue krk_dirObject(int argc, KrkValue argv[]) {
/* Then add each field of the instance */ /* Then add each field of the instance */
for (size_t i = 0; i < self->fields.capacity; ++i) { 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), krk_writeValueArray(AS_LIST(_list_internal),
self->fields.entries[i].key); 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]})); KrkClass * type = AS_CLASS(krk_typeOf(1, (KrkValue[]){argv[0]}));
for (size_t i = 0; i < type->methods.capacity; ++i) { 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), krk_writeValueArray(AS_LIST(_list_internal),
type->methods.entries[i].key); 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'", krk_runtimeError(vm.exceptions.typeError, "%s() got multiple values for argument '%s'",
closure->function->name ? closure->function->name->chars : "<unnamed function>", closure->function->name ? closure->function->name->chars : "<unnamed function>",
(destination < closure->function->requiredArgs ? AS_CSTRING(closure->function->requiredArgNames.values[destination]) : (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 potentialPositionalArgs = closure->function->requiredArgs + closure->function->keywordArgs;
size_t totalArguments = closure->function->requiredArgs + closure->function->keywordArgs + closure->function->collectsArguments + closure->function->collectsKeywords; 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 offsetOfExtraArgs = closure->function->requiredArgs + closure->function->keywordArgs;
size_t offsetOfExtraKeys = offsetOfExtraArgs + closure->function->collectsArguments;
size_t argCountX = argCount; size_t argCountX = argCount;
KrkValueArray positionals;
KrkTable keywords;
if (argCount && IS_KWARGS(vm.stackTop[-1])) { if (argCount && IS_KWARGS(vm.stackTop[-1])) {
/** KRK_PAUSE_GC();
* 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;
for (size_t availableSlots = argCount; availableSlots < (totalArguments); ++availableSlots) { /* This processes the existing argument list into a ValueArray and a Table with the args and keywords */
krk_push(KWARGS_VAL(0)); /* Make sure we definitely have enough space */ 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 */ /* Prepare stack space for all potential positionals, mark them unset */
for (int i = 0; i < argCount * 2; ++i) { 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)); krk_push(KWARGS_VAL(0));
} argCount++;
for (int i = 0; i < argCount * 2; ++i) {
krk_pop();
} }
/* We may have moved the stack, recalculate positions. */ /* Did we have way more arguments than we needed? Put the stack where it should be. */
startOfPositionals = vm.stack + positionalsOffset; while ((size_t)argCount > potentialPositionalArgs) {
KrkValue * endOfPositionals = vm.stack + endOffset; krk_pop();
KrkValue * startOfExtras = vm.stackTop; argCount--;
for (long i = 0; i < kwargsCount; ++i) { }
KrkValue name = endOfPositionals[i*2];
KrkValue value = endOfPositionals[i*2+1]; /* Place positional arguments */
if (IS_KWARGS(name)) { for (size_t i = 0; i < potentialPositionalArgs && i < positionals.count; ++i) {
krk_push(name); vm.stackTop[-argCount + i] = positionals.values[i];
krk_push(value); }
found++;
goto _finishArg; if (closure->function->collectsArguments) {
} size_t count = (positionals.count > potentialPositionalArgs) ? (positionals.count - potentialPositionalArgs) : 0;
/* First, see if it's a positional arg. */ KrkValue * offset = (count == 0) ? NULL : &positionals.values[potentialPositionalArgs];
for (int j = 0; j < (int)closure->function->requiredArgs; ++j) { krk_push(krk_list_of(count, offset));
if (krk_valuesEqual(name, closure->function->requiredArgNames.values[j])) { argCount++;
krk_push(INTEGER_VAL(j)); }
krk_push(value);
found++; krk_freeValueArray(&positionals);
goto _finishArg;
/* 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. */
/* 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_valuesEqual(name, closure->function->keywordArgNames.values[j])) { if (!IS_KWARGS(vm.stackTop[-argCount + j + closure->function->requiredArgs])) {
krk_push(INTEGER_VAL(j + closure->function->requiredArgs)); multipleDefs(closure, j + closure->function->requiredArgs);
krk_push(value); goto _errorAfterPositionals;
found++; }
goto _finishArg; vm.stackTop[-argCount + j + closure->function->requiredArgs] = value;
goto _finishKwarg;
}
} }
} if (!closure->function->collectsKeywords) {
/* If we got to this point, it's not a recognized argument for this function. */ krk_runtimeError(vm.exceptions.typeError, "%s() got an unexpected keyword argument '%s'",
if (closure->function->collectsKeywords) { closure->function->name ? closure->function->name->chars : "<unnamed function>",
krk_push(name); AS_CSTRING(name));
krk_push(value); goto _errorAfterPositionals;
found++; }
extraKwargs++; continue;
_finishKwarg:
entry->key = KWARGS_VAL(0);
entry->value = BOOLEAN_VAL(1);
continue; 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; /* If this function takes a **kwargs, we need to provide it as a dict */
for (long i = 0; i < found; ++i) { if (closure->function->collectsKeywords) {
/* Check for specials */ krk_push(krk_dict_of(0,NULL));
KrkValue name = startOfExtras[i*2]; argCount++;
KrkValue value = startOfExtras[i*2+1]; KrkValue _dict_internal;
if (IS_KWARGS(name)) { krk_tableGet(&AS_INSTANCE(krk_peek(0))->fields, vm.specialMethodNames[METHOD_DICT_INT], &_dict_internal);
if (AS_INTEGER(name) == LONG_MAX-1) { krk_tableAddAll(&keywords, AS_DICT(_dict_internal));
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 (destination > potentialPositionalArgs) { krk_freeTable(&keywords);
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;
}
for (long clearSlots = destination; clearSlots < startOfExtras - startOfPositionals; ++clearSlots) { for (size_t i = 0; i < (size_t)closure->function->requiredArgs; ++i) {
startOfPositionals[clearSlots] = KWARGS_VAL(0); if (IS_KWARGS(vm.stackTop[-argCount + i])) {
}
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])) {
krk_runtimeError(vm.exceptions.typeError, "%s() missing required positional argument: '%s'", krk_runtimeError(vm.exceptions.typeError, "%s() missing required positional argument: '%s'",
closure->function->name ? closure->function->name->chars : "<unnamed function>", closure->function->name ? closure->function->name->chars : "<unnamed function>",
AS_CSTRING(closure->function->requiredArgNames.values[clearSlots])); AS_CSTRING(closure->function->requiredArgNames.values[i]));
return 0; goto _errorAfterKeywords;
} }
} }
argCount = totalArguments;
KRK_RESUME_GC();
argCountX = argCount - (closure->function->collectsArguments + closure->function->collectsKeywords); argCountX = argCount - (closure->function->collectsArguments + closure->function->collectsKeywords);
while (vm.stackTop > startOfPositionals + argCount) krk_pop();
} else { } else {
/* We can't have had any kwargs. */ /* We can't have had any kwargs. */
if ((size_t)argCount > potentialPositionalArgs && closure->function->collectsArguments) { if ((size_t)argCount > potentialPositionalArgs && closure->function->collectsArguments) {
@ -1101,6 +1071,14 @@ _finishArg:
frame->outSlots = (vm.stackTop - argCount - extra) - vm.stack; frame->outSlots = (vm.stackTop - argCount - extra) - vm.stack;
frame->globals = &closure->function->globalsContext->fields; frame->globals = &closure->function->globalsContext->fields;
return 1; return 1;
_errorDuringPositionals:
krk_freeValueArray(&positionals);
_errorAfterPositionals:
krk_freeTable(&keywords);
_errorAfterKeywords:
KRK_RESUME_GC();
return 0;
} }
/** /**