7 #if defined(__TINYC__) || (defined(_MSC_VER) && !defined(__clang__))
8 static int __builtin_clz(
unsigned int x) {
10 while (!(x & (1 << i)) && i >= 0) i--;
20 if (argc % 2 != 0)
return krk_runtimeError(
vm.exceptions->argumentError,
"Expected even number of arguments to krk_dict_of");
25 size_t capacity = argc;
26 size_t powerOfTwoCapacity = __builtin_clz(1) - __builtin_clz(capacity);
27 if ((1UL << powerOfTwoCapacity) != capacity) powerOfTwoCapacity++;
28 capacity = (1UL << powerOfTwoCapacity);
30 for (
int ind = 0; ind < argc; ind += 2) {
45 #define CURRENT_CTYPE KrkDict *
46 #define CURRENT_NAME self
54 static int _keyvalue_pair_callback(
void * context,
const KrkValue * entries,
size_t count) {
58 _context->counter = count;
62 for (
size_t i = 0; i < count; ++i) {
63 if (_context->counter == 0) {
64 _context->counter = 1;
65 _context->key = entries[i];
66 }
else if (_context->counter == 1) {
67 _context->counter = 2;
70 _context->counter = -1;
79 static int unpackKeyValuePair(
void *
self,
const KrkValue * pairs,
size_t count) {
82 for (
size_t i = 0; i < count; ++i) {
86 if (context.counter != 2) {
87 krk_runtimeError(
vm.exceptions->valueError,
"dictionary update sequence element has invalid length");
93 KRK_Method(dict,__init__) {
94 METHOD_TAKES_AT_MOST(1);
108 KRK_Method(dict,__eq__) {
109 METHOD_TAKES_EXACTLY(1);
110 if (!IS_dict(argv[1]))
111 return NOTIMPL_VAL();
112 CHECK_ARG(1,dict,
KrkDict*,them);
113 if (self->entries.count != them->entries.count)
114 return BOOLEAN_VAL(0);
117 for (
unsigned int i = 0; i <
self->entries.capacity; ++i) {
118 if (IS_KWARGS(self->entries.entries[i].key))
continue;
120 if (!
krk_tableGet(&them->entries, self->entries.entries[i].key, &val))
return BOOLEAN_VAL(0);
124 return BOOLEAN_VAL(1);
128 KRK_Method(dict,__getitem__) {
129 METHOD_TAKES_EXACTLY(1);
138 KRK_Method(dict,__setitem__) {
139 METHOD_TAKES_EXACTLY(2);
144 KRK_Method(dict,__or__) {
145 METHOD_TAKES_EXACTLY(1);
146 CHECK_ARG(1,dict,
KrkDict*,them);
154 KRK_Method(dict,__delitem__) {
155 METHOD_TAKES_EXACTLY(1);
163 KRK_Method(dict,__len__) {
165 return INTEGER_VAL(self->entries.count);
168 KRK_Method(dict,__contains__) {
169 METHOD_TAKES_EXACTLY(1);
171 return BOOLEAN_VAL(
krk_tableGet(&self->entries, argv[1], &v));
174 KRK_Method(dict,capacity) {
176 return INTEGER_VAL(self->entries.capacity);
179 KRK_Method(dict,__repr__) {
181 if (((
KrkObj*)
self)->flags & KRK_OBJ_FLAGS_IN_REPR)
return OBJECT_VAL(S(
"{...}"));
182 ((
KrkObj*)
self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
184 pushStringBuilder(&sb,
'{');
187 size_t len =
self->entries.capacity;
188 for (
size_t i = 0; i < len; ++i) {
190 if (IS_KWARGS(entry->key))
continue;
191 if (c) pushStringBuilderStr(&sb,
", ", 2);
193 if (!krk_pushStringBuilderFormat(&sb,
"%R", entry->key))
goto _error;
194 pushStringBuilderStr(&sb,
": ", 2);
195 if (!krk_pushStringBuilderFormat(&sb,
"%R", entry->value))
goto _error;
198 pushStringBuilder(&sb,
'}');
199 ((
KrkObj*)
self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
200 return finishStringBuilder(&sb);
203 ((
KrkObj*)
self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
208 KRK_Method(dict,copy) {
216 KRK_Method(dict,clear) {
222 KRK_Method(dict,get) {
223 METHOD_TAKES_AT_LEAST(1);
224 METHOD_TAKES_AT_MOST(2);
226 if (argc > 2) out = argv[2];
231 KRK_Method(dict,setdefault) {
232 METHOD_TAKES_AT_LEAST(1);
233 METHOD_TAKES_AT_MOST(2);
235 if (argc > 2) out = argv[2];
245 KRK_Method(dict,update) {
246 METHOD_TAKES_AT_MOST(1);
249 CHECK_ARG(1,dict,
KrkDict*,other);
258 KRK_Method(dict,__ior__) {
259 METHOD_TAKES_EXACTLY(1);
260 CHECK_ARG(1,dict,
KrkDict*,other);
265 FUNC_SIG(dictkeys,__init__);
267 KRK_Method(dict,keys) {
273 return OBJECT_VAL(output);
276 FUNC_SIG(dictitems,__init__);
278 KRK_Method(dict,items) {
284 return OBJECT_VAL(output);
287 FUNC_SIG(dictvalues,__init__);
289 KRK_Method(dict,values) {
295 return OBJECT_VAL(output);
300 for (
size_t i = 0; i < capacity; ++i) {
301 if (IS_KWARGS(entries[i].key))
continue;
302 if (found == index)
return entries[i].key;
309 #define CURRENT_CTYPE struct DictItems *
311 static void _dictitems_gcscan(
KrkInstance *
self) {
315 KRK_Method(dictitems,__init__) {
316 METHOD_TAKES_EXACTLY(1);
317 CHECK_ARG(1,dict,
KrkDict*,source);
318 self->dict = argv[1];
323 KRK_Method(dictitems,__iter__) {
329 KRK_Method(dictitems,__call__) {
331 if (self->i >= AS_DICT(self->dict)->used)
return argv[0];
332 if (!IS_KWARGS(AS_DICT(self->dict)->entries[self->i].key)) {
335 outValue->
values.
values[0] = AS_DICT(self->dict)->entries[
self->i].key;
336 outValue->
values.
values[1] = AS_DICT(self->dict)->entries[
self->i].value;
345 KRK_Method(dictitems,__repr__) {
347 if (((
KrkObj*)
self)->flags & KRK_OBJ_FLAGS_IN_REPR)
return OBJECT_VAL(S(
"dictitems([...])"));
348 ((
KrkObj*)
self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
350 pushStringBuilderStr(&sb,
"dictitems([",11);
353 size_t len = AS_DICT(self->dict)->used;
354 for (
size_t i = 0; i < len; ++i) {
356 if (IS_KWARGS(entry->key))
continue;
357 if (c) pushStringBuilderStr(&sb,
", ", 2);
359 pushStringBuilder(&sb,
'(');
360 if (!krk_pushStringBuilderFormat(&sb,
"%R", entry->key))
goto _error;
361 pushStringBuilderStr(&sb,
", ", 2);
362 if (!krk_pushStringBuilderFormat(&sb,
"%R", entry->value))
goto _error;
363 pushStringBuilder(&sb,
')');
366 pushStringBuilderStr(&sb,
"])",2);
367 ((
KrkObj*)
self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
368 return finishStringBuilder(&sb);
371 ((
KrkObj*)
self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
377 #define CURRENT_CTYPE struct DictKeys *
383 KRK_Method(dictkeys,__init__) {
384 METHOD_TAKES_EXACTLY(1);
385 CHECK_ARG(1,dict,
KrkDict*,source);
386 self->dict = argv[1];
391 KRK_Method(dictkeys,__iter__) {
397 KRK_Method(dictkeys,__call__) {
400 if (self->i >= AS_DICT(self->dict)->used)
return argv[0];
401 if (!IS_KWARGS(AS_DICT(self->dict)->entries[self->i].key)) {
402 krk_push(AS_DICT(self->dict)->entries[self->i].key);
410 KRK_Method(dictkeys,__repr__) {
412 if (((
KrkObj*)
self)->flags & KRK_OBJ_FLAGS_IN_REPR)
return OBJECT_VAL(S(
"dictkeys([...])"));
413 ((
KrkObj*)
self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
415 pushStringBuilderStr(&sb,
"dictkeys([",10);
418 size_t len = AS_DICT(self->dict)->used;
419 for (
size_t i = 0; i < len; ++i) {
421 if (IS_KWARGS(entry->key))
continue;
422 if (c) pushStringBuilderStr(&sb,
", ", 2);
424 if (!krk_pushStringBuilderFormat(&sb,
"%R", entry->key))
goto _error;
427 pushStringBuilderStr(&sb,
"])",2);
428 ((
KrkObj*)
self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
429 return finishStringBuilder(&sb);
432 ((
KrkObj*)
self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
438 #define CURRENT_CTYPE struct DictValues *
440 static void _dictvalues_gcscan(
KrkInstance *
self) {
444 KRK_Method(dictvalues,__init__) {
445 METHOD_TAKES_EXACTLY(1);
446 CHECK_ARG(1,dict,
KrkDict*,source);
447 self->dict = argv[1];
452 KRK_Method(dictvalues,__iter__) {
458 KRK_Method(dictvalues,__call__) {
461 if (self->i >= AS_DICT(self->dict)->used)
return argv[0];
462 if (!IS_KWARGS(AS_DICT(self->dict)->entries[self->i].key)) {
463 krk_push(AS_DICT(self->dict)->entries[self->i].value);
471 KRK_Method(dictvalues,__repr__) {
473 if (((
KrkObj*)
self)->flags & KRK_OBJ_FLAGS_IN_REPR)
return OBJECT_VAL(S(
"dictvalues([...])"));
474 ((
KrkObj*)
self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
476 pushStringBuilderStr(&sb,
"dictvalues([",12);
479 size_t len = AS_DICT(self->dict)->used;
480 for (
size_t i = 0; i < len; ++i) {
482 if (IS_KWARGS(entry->key))
continue;
483 if (c) pushStringBuilderStr(&sb,
", ", 2);
485 if (!krk_pushStringBuilderFormat(&sb,
"%R", entry->value))
goto _error;
488 pushStringBuilderStr(&sb,
"])",2);
489 ((
KrkObj*)
self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
490 return finishStringBuilder(&sb);
493 ((
KrkObj*)
self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
499 void _createAndBind_dictClass(
void) {
500 KrkClass * dict = ADD_BASE_CLASS(
vm.baseClasses->dictClass,
"dict",
vm.baseClasses->objectClass);
504 BIND_METHOD(dict,__init__);
505 BIND_METHOD(dict,__repr__);
506 BIND_METHOD(dict,__getitem__);
507 BIND_METHOD(dict,__setitem__);
508 BIND_METHOD(dict,__or__);
509 BIND_METHOD(dict,__delitem__);
510 BIND_METHOD(dict,__len__);
511 BIND_METHOD(dict,__contains__);
512 BIND_METHOD(dict,__ior__);
513 BIND_METHOD(dict,__eq__);
514 BIND_METHOD(dict,keys);
515 BIND_METHOD(dict,items);
516 BIND_METHOD(dict,values);
517 BIND_METHOD(dict,capacity);
518 BIND_METHOD(dict,copy);
519 BIND_METHOD(dict,clear);
520 BIND_METHOD(dict,get);
521 BIND_METHOD(dict,setdefault);
522 BIND_METHOD(dict,update);
527 KRK_DOC(dict,
"Mapping of arbitrary keys to values.");
529 KrkClass * dictitems = ADD_BASE_CLASS(
vm.baseClasses->dictitemsClass,
"dictitems",
vm.baseClasses->objectClass);
531 dictitems->
_ongcscan = _dictitems_gcscan;
532 BIND_METHOD(dictitems,__init__);
533 BIND_METHOD(dictitems,__iter__);
534 BIND_METHOD(dictitems,__call__);
535 BIND_METHOD(dictitems,__repr__);
538 KrkClass * dictkeys = ADD_BASE_CLASS(
vm.baseClasses->dictkeysClass,
"dictkeys",
vm.baseClasses->objectClass);
541 BIND_METHOD(dictkeys,__init__);
542 BIND_METHOD(dictkeys,__iter__);
543 BIND_METHOD(dictkeys,__call__);
544 BIND_METHOD(dictkeys,__repr__);
547 KrkClass * dictvalues = ADD_BASE_CLASS(
vm.baseClasses->dictvaluesClass,
"dictvalues",
vm.baseClasses->objectClass);
549 dictvalues->
_ongcscan = _dictvalues_gcscan;
550 BIND_METHOD(dictvalues,__init__);
551 BIND_METHOD(dictvalues,__iter__);
552 BIND_METHOD(dictvalues,__call__);
553 BIND_METHOD(dictvalues,__repr__);
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Functions for dealing with garbage collection and memory allocation.
void krk_markValue(KrkValue value)
During a GC scan cycle, mark a value as used.
void krk_markTable(KrkTable *table)
During a GC scan cycle, mark the contents of a table as used.
NativeFn krk_GenericAlias
Special value for type hint expressions.
KrkCleanupCallback _ongcsweep
C function to call when the garbage collector is discarding an instance of this class.
KrkCleanupCallback _ongcscan
C function to call when the garbage collector visits an instance of this class in the scan phase.
size_t allocSize
Size to allocate when creating instances of this class.
KrkTable methods
General attributes table.
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
KrkTable entries
The actual table of values in the dict.
KrkValue krk_dict_of(int argc, const KrkValue argv[], int hasKw)
Create a dict object.
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
The most basic object type.
uint16_t flags
General object flags, mostly related to garbage collection.
One (key,value) pair in a table.
void krk_initTable(KrkTable *table)
Initialize a hash table.
int krk_tableGet(KrkTable *table, KrkValue key, KrkValue *value)
Obtain the value associated with a key in a table.
int krk_tableDelete(KrkTable *table, KrkValue key)
Remove a key from a hash table.
int krk_tableSet(KrkTable *table, KrkValue key, KrkValue value)
Assign a value to a key in a table.
void krk_tableAdjustCapacity(KrkTable *table, size_t capacity)
Preset the size of a table.
KrkNative * krk_defineNative(KrkTable *table, const char *name, NativeFn function)
Attach a native C function to an attribute table.
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
void krk_tableAddAll(KrkTable *from, KrkTable *to)
Add all key-value pairs from 'from' into 'to'.
void krk_freeTable(KrkTable *table)
Release resources associated with a hash table.
KrkValue currentException
Immutable sequence of arbitrary values.
KrkValueArray values
Stores the length, capacity, and actual values of the tuple.
KrkTuple * krk_newTuple(size_t length)
Create a new tuple.
Stack reference or primative value.
int krk_valuesSameOrEqual(KrkValue a, KrkValue b)
Compare two values by identity, then by equality.
Inline flexible string array.
Utilities for creating native bindings.
KrkValue krk_discardStringBuilder(struct StringBuilder *sb)
Discard the contents of a string builder.
int krk_unpackIterable(KrkValue iterable, void *context, int callback(void *, const KrkValue *, size_t))
Unpack an iterable.
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
krk_threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
#define vm
Convenience macro for namespacing.
KrkValue krk_pop(void)
Pop the top of the stack.
void krk_push(KrkValue value)
Push a stack value.
KrkValue krk_peek(int distance)
Peek down from the top of the stack.