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 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"
|
||||||
|
@ -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):
|
||||||
|
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]))));
|
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
18
table.c
@ -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 &&
|
||||||
|
@ -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'
|
||||||
|
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}");
|
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
376
vm.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user