C-ify some more collection methods

This commit is contained in:
K. Lange 2021-01-19 22:27:05 +09:00
parent abff851af0
commit 85e7c667b4
7 changed files with 166 additions and 113 deletions

View File

@ -1,32 +1,8 @@
const char krk_builtinsSrc[] =
"# Please avoid using double quotes or escape sequences\n"
"# in this file to allow it to be easily converted to C.\n"
"class list():\n"
" 'Resizable array with direct constant-time indexing.'\n"
" def extend(i):\n"
" 'Add all entries from an iterable to the end of this list.'\n"
" if isinstance(i,list):\n"
" return self._extend_fast(i)\n"
" for v in i:\n"
" self.append(v)\n"
" return self.__len__()\n"
" def __str__(self): return self.__repr__()\n"
" def __repr__(self):\n"
" if self.__inrepr: return '[...]'\n"
" self.__inrepr=1\n"
" let b='['+', '.join([repr(i) for i in self])+']'\n"
" self.__inrepr=0\n"
" return b\n"
"\n"
"class dict():\n"
" 'Hashmap of arbitrary keys to arbitrary values.'\n"
" def __str__(self): return self.__repr__()\n"
" def __repr__(self):\n"
" if self.__inrepr: return '{...}'\n"
" self.__inrepr = 1\n"
" let b='{'+', '.join([repr(k)+': '+repr(self[k]) for k in self.keys()])+'}'\n"
" self.__inrepr = 0\n"
" return b\n"
" def keys(self):\n"
" 'Returns an iterable of the keys in this dictionary.'\n"
" class KeyIterator():\n"
@ -119,31 +95,15 @@ const char krk_builtinsSrc[] =
"\n"
"let help = Helper()\n"
"\n"
"let _licenseText = '''\n"
"Copyright (c) 2020-2021 K. Lange <klange@toaruos.org>\n"
"\n"
"Permission to use, copy, modify, and/or distribute this software for any\n"
"purpose with or without fee is hereby granted, provided that the above\n"
"copyright notice and this permission notice appear in all copies.\n"
"\n"
"THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n"
"WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n"
"MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n"
"ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n"
"WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n"
"ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n"
"OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n"
"'''\n"
"\n"
"class LicenseReader():\n"
" def __call__(self):\n"
" print(_licenseText)\n"
" from help import __licenseText\n"
" print(__licenseText)\n"
" def __repr__(self):\n"
" return 'Copyright 2020-2021 K. Lange <klange@toaruos.org>. Type `license()` for more information.'\n"
"\n"
"let license = LicenseReader()\n"
"\n"
"__builtins__.list = list\n"
"__builtins__.dict = dict\n"
"__builtins__.help = help\n"
"__builtins__.license = license\n"

View File

@ -1,31 +1,7 @@
# Please avoid using double quotes or escape sequences
# in this file to allow it to be easily converted to C.
class list():
'Resizable array with direct constant-time indexing.'
def extend(i):
'Add all entries from an iterable to the end of this list.'
if isinstance(i,list):
return self._extend_fast(i)
for v in i:
self.append(v)
return self.__len__()
def __str__(self): return self.__repr__()
def __repr__(self):
if self.__inrepr: return '[...]'
self.__inrepr=1
let b='['+', '.join([repr(i) for i in self])+']'
self.__inrepr=0
return b
class dict():
'Hashmap of arbitrary keys to arbitrary values.'
def __str__(self): return self.__repr__()
def __repr__(self):
if self.__inrepr: return '{...}'
self.__inrepr = 1
let b='{'+', '.join([repr(k)+': '+repr(self[k]) for k in self.keys()])+'}'
self.__inrepr = 0
return b
def keys(self):
'Returns an iterable of the keys in this dictionary.'
class KeyIterator():
@ -118,31 +94,15 @@ class Helper():
let help = Helper()
let _licenseText = '''
Copyright (c) 2020-2021 K. Lange <klange@toaruos.org>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
'''
class LicenseReader():
def __call__(self):
print(_licenseText)
from help import __licenseText
print(__licenseText)
def __repr__(self):
return 'Copyright 2020-2021 K. Lange <klange@toaruos.org>. Type `license()` for more information.'
let license = LicenseReader()
__builtins__.list = list
__builtins__.dict = dict
__builtins__.help = help
__builtins__.license = license

View File

@ -20,3 +20,20 @@ and attribute field names is available.
def interactive():
'''Runs the detailed help tool. Currently that means just printing a longer help string.'''
print(__introText)
let __licenseText = '''
Copyright (c) 2020-2021 K. Lange <klange@toaruos.org>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED 'AS IS' AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
'''

View File

@ -15,6 +15,7 @@ static KrkObj * allocateObject(size_t size, ObjType type) {
KrkObj * object = (KrkObj*)krk_reallocate(NULL, 0, size);
object->type = type;
object->isMarked = 0;
object->inRepr = 0;
object->next = vm.objects;
vm.objects = object;
return object;

View File

@ -44,7 +44,8 @@ typedef enum {
struct Obj {
ObjType type;
char isMarked;
unsigned char isMarked:1;
unsigned char inRepr:1;
struct Obj * next;
};

View File

@ -44,7 +44,7 @@ def find_depth(bag):
while to_scan:
let i = to_scan.pop(0)
count += 1
to_scan._extend_fast(descriptions[i])
to_scan.extend(descriptions[i])
return count
print("A shiny gold bag contains", find_depth('shiny gold'), "bags.")

168
vm.c
View File

@ -474,6 +474,50 @@ static KrkValue _dict_key_at_index(int argc, KrkValue argv[]) {
return OBJECT_VAL(outValue);
}
static KrkValue _dict_repr(int argc, KrkValue argv[]) {
KrkValue self = argv[0];
if (AS_OBJECT(self)->inRepr) return OBJECT_VAL(S("{...}"));
KrkValue _dict_internal = OBJECT_VAL(AS_INSTANCE(argv[0])->_internal);
krk_push(OBJECT_VAL(S("{")));
AS_OBJECT(self)->inRepr = 1;
size_t c = 0;
size_t len = AS_DICT(_dict_internal)->capacity;
for (size_t i = 0; i < len; ++i) {
KrkTableEntry * entry = &AS_DICT(_dict_internal)->entries[i];
if (IS_KWARGS(entry->key)) continue;
if (c > 0) {
krk_push(OBJECT_VAL(S(", ")));
addObjects();
}
c++;
KrkClass * type = AS_CLASS(krk_typeOf(1, &entry->key));
krk_push(entry->key);
krk_push(krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0));
addObjects();
krk_push(OBJECT_VAL(S(": ")));
addObjects();
type = AS_CLASS(krk_typeOf(1, &entry->value));
krk_push(entry->value);
krk_push(krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0));
addObjects();
}
AS_OBJECT(self)->inRepr = 0;
krk_push(OBJECT_VAL(S("}")));
addObjects();
return krk_pop();
}
static KrkValue _dict_nth_key_fast(size_t capacity, KrkTableEntry * entries, size_t index) {
size_t found = 0;
for (size_t i = 0; i < capacity; ++i) {
@ -552,22 +596,89 @@ static KrkValue _list_append(int argc, KrkValue argv[]) {
}
/**
* list.extend but only for lists...
* list.__repr__
*/
static KrkValue _list_extend_fast(int argc, KrkValue argv[]) {
KrkValue _list_internal_self = OBJECT_VAL(AS_INSTANCE(argv[0])->_internal);
KrkValue _list_internal_them = OBJECT_VAL(AS_INSTANCE(argv[1])->_internal);
static KrkValue _list_repr(int argc, KrkValue argv[]) {
KrkValue self = argv[0];
if (AS_OBJECT(self)->inRepr) return OBJECT_VAL(S("[...]"));
KrkValue _list_internal = OBJECT_VAL(AS_INSTANCE(argv[0])->_internal);
krk_push(OBJECT_VAL(S("[")));
size_t totalSize = AS_LIST(_list_internal_self)->count + AS_LIST(_list_internal_them)->count;
if (AS_LIST(_list_internal_self)->capacity < totalSize) {
size_t old = AS_LIST(_list_internal_self)->capacity;
AS_LIST(_list_internal_self)->capacity = totalSize;
AS_LIST(_list_internal_self)->values = GROW_ARRAY(KrkValue, AS_LIST(_list_internal_self)->values, old, totalSize);
AS_OBJECT(self)->inRepr = 1;
size_t len = AS_LIST(_list_internal)->count;
for (size_t i = 0; i < len; ++i) {
KrkClass * type = AS_CLASS(krk_typeOf(1, &AS_LIST(_list_internal)->values[i]));
krk_push(AS_LIST(_list_internal)->values[i]);
krk_push(krk_callSimple(OBJECT_VAL(type->_reprer), 1, 0));
addObjects();
if (i + 1 < len) {
krk_push(OBJECT_VAL(S(", ")));
addObjects();
}
}
memcpy(&AS_LIST(_list_internal_self)->values[AS_LIST(_list_internal_self)->count],
AS_LIST(_list_internal_them)->values, sizeof(KrkValue) * AS_LIST(_list_internal_them)->count);
AS_LIST(_list_internal_self)->count = totalSize;
return INTEGER_VAL(totalSize);
AS_OBJECT(self)->inRepr = 0;
krk_push(OBJECT_VAL(S("]")));
addObjects();
return krk_pop();
}
static KrkValue _list_extend(int argc, KrkValue argv[]) {
KrkInstance * self = AS_INSTANCE(argv[0]);
KrkValue _list_internal = OBJECT_VAL(self->_internal);
KrkValueArray * positionals = AS_LIST(_list_internal);
#define unpackArray(counter, indexer) do { \
if (positionals->count + counter > positionals->capacity) { \
size_t old = positionals->capacity; \
positionals->capacity = positionals->count + counter; \
positionals->values = GROW_ARRAY(KrkValue,positionals->values,old,positionals->capacity); \
} \
for (size_t i = 0; i < counter; ++i) { \
positionals->values[positionals->count] = indexer; \
positionals->count++; \
} \
} while (0)
KrkValue value = argv[1];
//UNPACK_ARRAY(); /* This should be a macro that does all of these things. */
if (IS_TUPLE(value)) {
unpackArray(AS_TUPLE(value)->values.count, AS_TUPLE(value)->values.values[i]);
} else if (IS_INSTANCE(value) && AS_INSTANCE(value)->_class == vm.baseClasses.listClass) {
KrkValue _list_internal = OBJECT_VAL(AS_INSTANCE(value)->_internal);
unpackArray(AS_LIST(_list_internal)->count, AS_LIST(_list_internal)->values[i]);
} else if (IS_INSTANCE(value) && AS_INSTANCE(value)->_class == vm.baseClasses.dictClass) {
KrkValue _dict_internal = OBJECT_VAL(AS_INSTANCE(value)->_internal);
unpackArray(AS_DICT(_dict_internal)->count, _dict_nth_key_fast(AS_DICT(_dict_internal)->capacity, AS_DICT(_dict_internal)->entries, i));
} else if (IS_STRING(value)) {
unpackArray(AS_STRING(value)->codesLength, _string_get(2,(KrkValue[]){value,INTEGER_VAL(i)}));
} else {
KrkClass * type = AS_CLASS(krk_typeOf(1,&argv[1]));
if (type->_iter) {
/* Create the iterator */
size_t stackOffset = vm.stackTop - vm.stack;
krk_push(argv[1]);
krk_push(krk_callSimple(OBJECT_VAL(type->_iter), 1, 0));
do {
/* Call it until it gives us itself */
krk_push(vm.stack[stackOffset]);
krk_push(krk_callSimple(krk_peek(0), 0, 1));
if (krk_valuesSame(vm.stack[stackOffset], krk_peek(0))) {
/* We're done. */
krk_pop(); /* The result of iteration */
krk_pop(); /* The iterator */
break;
}
_list_append(2, (KrkValue[]){argv[0], krk_peek(0)});
krk_pop();
} while (1);
} else {
krk_runtimeError(vm.exceptions.typeError, "'%s' object is not iterable", krk_typeName(value));
}
}
#undef unpackArray
return NONE_VAL();
}
/**
@ -3372,6 +3483,21 @@ void krk_initVM(int flags) {
krk_defineNative(&vm.baseClasses.bytesClass->methods, ".__get__", _bytes_get);
krk_defineNative(&vm.baseClasses.bytesClass->methods, ".__eq__", _bytes_eq);
krk_finalizeClass(vm.baseClasses.bytesClass);
ADD_BASE_CLASS(vm.baseClasses.listClass, "list", vm.objectClass);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__init__", _list_init);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__get__", _list_get);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__set__", _list_set);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__delitem__", _list_pop);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__len__", _list_len);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__str__", _list_repr);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__repr__", _list_repr);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__contains__", _list_contains);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__getslice__", _list_slice);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__iter__", _list_iter);
krk_defineNative(&vm.baseClasses.listClass->methods, ".append", _list_append);
krk_defineNative(&vm.baseClasses.listClass->methods, ".extend", _list_extend);
krk_defineNative(&vm.baseClasses.listClass->methods, ".pop", _list_pop);
krk_finalizeClass(vm.baseClasses.listClass);
/* Build global builtin functions. */
BUILTIN_FUNCTION("listOf", krk_list_of);
@ -3437,24 +3563,12 @@ void krk_initVM(int flags) {
/* Now we can attach the native initializers and getters/setters to
* the list and dict types by pulling them out of the global namespace,
* as they were exported by builtins.krk */
krk_tableGet(&vm.builtins->fields,OBJECT_VAL(S("list")),&val);
vm.baseClasses.listClass = AS_CLASS(val);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__init__", _list_init);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__get__", _list_get);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__set__", _list_set);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__delitem__", _list_pop);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__len__", _list_len);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__contains__", _list_contains);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__getslice__", _list_slice);
krk_defineNative(&vm.baseClasses.listClass->methods, ".__iter__", _list_iter);
krk_defineNative(&vm.baseClasses.listClass->methods, ".append", _list_append);
krk_defineNative(&vm.baseClasses.listClass->methods, ".pop", _list_pop);
krk_defineNative(&vm.baseClasses.listClass->methods, "._extend_fast", _list_extend_fast);
krk_finalizeClass(vm.baseClasses.listClass);
krk_tableGet(&vm.builtins->fields,OBJECT_VAL(S("dict")),&val);
vm.baseClasses.dictClass = AS_CLASS(val);
krk_defineNative(&vm.baseClasses.dictClass->methods, ".__init__", _dict_init);
krk_defineNative(&vm.baseClasses.dictClass->methods, ".__str__", _dict_repr);
krk_defineNative(&vm.baseClasses.dictClass->methods, ".__repr__", _dict_repr);
krk_defineNative(&vm.baseClasses.dictClass->methods, ".__get__", _dict_get);
krk_defineNative(&vm.baseClasses.dictClass->methods, ".__set__", _dict_set);
krk_defineNative(&vm.baseClasses.dictClass->methods, ".__delitem__", _dict_delitem);