8 #define LIST_WRAP_INDEX() \
9 if (index < 0) index += self->values.count; \
10 if (unlikely(index < 0 || index >= (krk_integer_type)self->values.count)) return krk_runtimeError(vm.exceptions->indexError, "list index out of range: %zd", (ssize_t)index)
12 #define LIST_WRAP_SOFT(val) \
13 if (val < 0) val += self->values.count; \
14 if (val < 0) val = 0; \
15 if (val > (krk_integer_type)self->values.count) val = self->values.count
18 for (
size_t i = 0; i < ((
KrkList*)
self)->values.count; ++i) {
36 AS_LIST(outList)->capacity = argc;
37 AS_LIST(outList)->values = KRK_GROW_ARRAY(
KrkValue, AS_LIST(outList)->values, 0, argc);
38 memcpy(AS_LIST(outList)->values, argv,
sizeof(
KrkValue) * argc);
39 AS_LIST(outList)->count = argc;
42 pthread_rwlock_init(&((
KrkList*)AS_OBJECT(outList))->rwlock, NULL);
46 #define CURRENT_CTYPE KrkList *
47 #define CURRENT_NAME self
49 KRK_Method(list,__getitem__) {
50 METHOD_TAKES_EXACTLY(1);
51 if (IS_INTEGER(argv[1])) {
52 CHECK_ARG(1,
int,krk_integer_type,index);
53 if (
vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_rdlock(&self->rwlock);
55 KrkValue result =
self->values.values[index];
56 if (
vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_unlock(&self->rwlock);
58 }
else if (IS_slice(argv[1])) {
59 pthread_rwlock_rdlock(&self->rwlock);
61 KRK_SLICER(argv[1],self->values.count) {
62 pthread_rwlock_unlock(&self->rwlock);
67 krk_integer_type len = end - start;
69 pthread_rwlock_unlock(&self->rwlock);
74 krk_integer_type len = 0;
75 krk_integer_type i = start;
76 while ((step < 0) ? (i > end) : (i < end)) {
90 pthread_rwlock_unlock(&self->rwlock);
94 return TYPE_ERROR(
int or slice,argv[1]);
98 KRK_Method(list,__eq__) {
99 METHOD_TAKES_EXACTLY(1);
100 if (!IS_list(argv[1]))
return NOTIMPL_VAL();
101 KrkList * them = AS_list(argv[1]);
102 if (self->values.count != them->
values.
count)
return BOOLEAN_VAL(0);
103 for (
size_t i = 0; i <
self->values.count; ++i) {
106 return BOOLEAN_VAL(1);
109 KRK_Method(list,append) {
110 METHOD_TAKES_EXACTLY(1);
111 pthread_rwlock_wrlock(&self->rwlock);
113 pthread_rwlock_unlock(&self->rwlock);
117 KRK_Method(list,insert) {
118 METHOD_TAKES_EXACTLY(2);
119 CHECK_ARG(1,
int,krk_integer_type,index);
120 pthread_rwlock_wrlock(&self->rwlock);
121 LIST_WRAP_SOFT(index);
124 &self->values.values[index+1],
125 &self->values.values[index],
126 sizeof(
KrkValue) * (self->values.count - index - 1)
128 self->values.values[index] = argv[2];
129 pthread_rwlock_unlock(&self->rwlock);
133 KRK_Method(list,__repr__) {
135 if (((
KrkObj*)
self)->flags & KRK_OBJ_FLAGS_IN_REPR)
return OBJECT_VAL(S(
"[...]"));
136 ((
KrkObj*)
self)->flags |= KRK_OBJ_FLAGS_IN_REPR;
138 pushStringBuilder(&sb,
'[');
139 pthread_rwlock_rdlock(&self->rwlock);
140 for (
size_t i = 0; i <
self->values.count; ++i) {
141 if (!krk_pushStringBuilderFormat(&sb,
"%R",self->values.values[i]))
goto _error;
142 if (i + 1 < self->values.count) {
143 pushStringBuilderStr(&sb,
", ", 2);
146 pthread_rwlock_unlock(&self->rwlock);
148 pushStringBuilder(&sb,
']');
149 ((
KrkObj*)
self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
150 return finishStringBuilder(&sb);
154 pthread_rwlock_unlock(&self->rwlock);
155 ((
KrkObj*)
self)->flags &= ~(KRK_OBJ_FLAGS_IN_REPR);
159 static int _list_extend_callback(
void * context,
const KrkValue * values,
size_t count) {
163 positionals->
capacity = (count == 1) ? KRK_GROW_CAPACITY(old) : (positionals->
count + count);
167 for (
size_t i = 0; i < count; ++i) {
168 positionals->
values[positionals->
count++] = values[i];
174 KRK_Method(list,extend) {
175 METHOD_TAKES_EXACTLY(1);
176 pthread_rwlock_wrlock(&self->rwlock);
180 other =
krk_list_of(self->values.count, self->values.values, 0);
185 pthread_rwlock_unlock(&self->rwlock);
189 KRK_Method(list,__init__) {
190 METHOD_TAKES_AT_MOST(1);
192 pthread_rwlock_init(&self->rwlock, NULL);
194 _list_extend(2,(
KrkValue[]){argv[0],argv[1]},0);
199 KRK_Method(list,__mul__) {
200 METHOD_TAKES_EXACTLY(1);
201 CHECK_ARG(1,
int,krk_integer_type,howMany);
207 for (krk_integer_type i = 0; i < howMany; i++) {
208 _list_extend(2, (
KrkValue[]){out,argv[0]},0);
214 KRK_Method(list,__len__) {
216 return INTEGER_VAL(self->values.count);
219 KRK_Method(list,__contains__) {
220 METHOD_TAKES_EXACTLY(1);
221 pthread_rwlock_rdlock(&self->rwlock);
222 for (
size_t i = 0; i <
self->values.count; ++i) {
224 pthread_rwlock_unlock(&self->rwlock);
225 return BOOLEAN_VAL(1);
229 pthread_rwlock_unlock(&self->rwlock);
230 return BOOLEAN_VAL(0);
233 KRK_Method(list,pop) {
234 METHOD_TAKES_AT_MOST(1);
235 pthread_rwlock_wrlock(&self->rwlock);
236 krk_integer_type index =
self->values.count - 1;
238 CHECK_ARG(1,
int,krk_integer_type,ind);
242 KrkValue outItem = AS_LIST(argv[0])->values[index];
243 if (index == (
long)AS_LIST(argv[0])->count-1) {
244 AS_LIST(argv[0])->count--;
245 pthread_rwlock_unlock(&self->rwlock);
249 size_t remaining = AS_LIST(argv[0])->count - index - 1;
250 memmove(&AS_LIST(argv[0])->values[index], &AS_LIST(argv[0])->values[index+1],
252 AS_LIST(argv[0])->count--;
253 pthread_rwlock_unlock(&self->rwlock);
258 KRK_Method(list,__setitem__) {
259 METHOD_TAKES_EXACTLY(2);
260 if (IS_INTEGER(argv[1])) {
261 CHECK_ARG(1,
int,krk_integer_type,index);
262 if (
vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_rdlock(&self->rwlock);
264 self->values.values[index] = argv[2];
265 if (
vm.globalFlags & KRK_GLOBAL_THREADS) pthread_rwlock_unlock(&self->rwlock);
267 }
else if (IS_slice(argv[1])) {
268 if (!IS_list(argv[2])) {
269 return TYPE_ERROR(list,argv[2]);
272 KRK_SLICER(argv[1],self->values.count) {
280 krk_integer_type len = end - start;
281 krk_integer_type newLen = (krk_integer_type)AS_LIST(argv[2])->count;
283 for (krk_integer_type i = 0; (i < len && i < newLen); ++i) {
284 AS_LIST(argv[0])->values[start+i] = AS_LIST(argv[2])->values[i];
287 while (len < newLen) {
288 FUNC_NAME(list,insert)(3, (
KrkValue[]){argv[0], INTEGER_VAL(start + len), AS_LIST(argv[2])->values[len]}, 0);
292 while (newLen < len) {
293 FUNC_NAME(list,pop)(2, (
KrkValue[]){argv[0], INTEGER_VAL(start + len - 1)}, 0);
297 return OBJECT_VAL(
self);
299 return TYPE_ERROR(
int or slice, argv[1]);
303 KRK_Method(list,__delitem__) {
304 METHOD_TAKES_EXACTLY(1);
306 if (IS_INTEGER(argv[1])) {
307 FUNC_NAME(list,pop)(2,(
KrkValue[]){argv[0],argv[1]},0);
308 }
else if (IS_slice(argv[1])) {
309 KRK_SLICER(argv[1],self->values.count) {
317 krk_integer_type len = end - start;
320 FUNC_NAME(list,pop)(2,(
KrkValue[]){argv[0],INTEGER_VAL(start)},0);
324 return TYPE_ERROR(
int or slice, argv[1]);
330 KRK_Method(list,remove) {
331 METHOD_TAKES_EXACTLY(1);
332 pthread_rwlock_wrlock(&self->rwlock);
333 for (
size_t i = 0; i <
self->values.count; ++i) {
335 pthread_rwlock_unlock(&self->rwlock);
336 return FUNC_NAME(list,pop)(2,(
KrkValue[]){argv[0], INTEGER_VAL(i)},0);
339 pthread_rwlock_unlock(&self->rwlock);
343 pthread_rwlock_unlock(&self->rwlock);
347 KRK_Method(list,clear) {
349 pthread_rwlock_wrlock(&self->rwlock);
351 pthread_rwlock_unlock(&self->rwlock);
355 KRK_Method(list,index) {
356 METHOD_TAKES_AT_LEAST(1);
357 METHOD_TAKES_AT_MOST(3);
359 krk_integer_type min = 0;
360 krk_integer_type max =
self->values.count;
363 if (IS_INTEGER(argv[2]))
364 min = AS_INTEGER(argv[2]);
366 return krk_runtimeError(
vm.exceptions->typeError,
"%s must be int, not '%T'",
"min", argv[2]);
370 if (IS_INTEGER(argv[3]))
371 max = AS_INTEGER(argv[3]);
373 return krk_runtimeError(
vm.exceptions->typeError,
"%s must be int, not '%T'",
"max", argv[3]);
376 pthread_rwlock_rdlock(&self->rwlock);
380 for (krk_integer_type i = min; i < max; ++i) {
382 pthread_rwlock_unlock(&self->rwlock);
383 return INTEGER_VAL(i);
386 pthread_rwlock_unlock(&self->rwlock);
391 pthread_rwlock_unlock(&self->rwlock);
395 KRK_Method(list,count) {
396 METHOD_TAKES_EXACTLY(1);
397 krk_integer_type count = 0;
399 pthread_rwlock_rdlock(&self->rwlock);
400 for (
size_t i = 0; i <
self->values.count; ++i) {
404 pthread_rwlock_unlock(&self->rwlock);
406 return INTEGER_VAL(count);
409 KRK_Method(list,copy) {
411 pthread_rwlock_rdlock(&self->rwlock);
413 pthread_rwlock_unlock(&self->rwlock);
418 static void reverse_values(
KrkValue * values,
size_t n) {
420 while (values < end) {
430 KRK_Method(list,reverse) {
432 pthread_rwlock_wrlock(&self->rwlock);
433 if (self->values.count > 1) reverse_values(self->values.values, self->values.count);
434 pthread_rwlock_unlock(&self->rwlock);
455 static inline void slice_advance(
struct SortSlice * slice) {
457 if (slice->values) slice->values++;
461 static inline void slice_decrement(
struct SortSlice * slice) {
463 if (slice->values) slice->values--;
469 return (
struct SortSlice){slice.keys + 1, slice.values ? slice.values + 1 : NULL};
474 return (
struct SortSlice){slice.keys + n, slice.values ? slice.values + n : NULL};
479 while (start.keys != end.keys) {
480 *buffer.keys = *start.keys;
481 if (buffer.values) *buffer.values = *start.values;
482 slice_advance(&start);
483 slice_advance(&buffer);
490 return (IS_NONE(comp) || (IS_BOOLEAN(comp) && AS_BOOLEAN(comp)));
495 while (begin.keys + 1 < end.keys && _list_sorter(*(begin.keys + 1), *begin.keys)) slice_advance(&begin);
496 return slice_next(begin);
501 while (begin.keys + 1 < end.keys && !_list_sorter(*(begin.keys + 1), *begin.keys)) slice_advance(&begin);
502 return slice_next(begin);
518 if (j.keys == end.keys)
return j;
519 if (j.keys + 1 == end.keys)
return slice_next(j);
520 if (_list_sorter(*slice_next(j).keys, *j.keys)) {
523 j = powersort_strictlyDecreasingPrefix(slice_next(begin), end);
524 reverse_values(begin.keys, j.keys - begin.keys);
525 if (begin.values) reverse_values(begin.values, j.values - begin.values);
528 j = powersort_weaklyIncreasingPrefix(slice_next(begin), end);
539 static size_t powersort_power(
size_t begin,
size_t end,
size_t beginA,
size_t beginB,
size_t endB) {
540 size_t n = end - begin;
541 unsigned long l = beginA - begin + beginB - begin;
542 unsigned long r = beginB - begin + endB - begin;
546 while (digitA == digitB) {
573 size_t n1 = mid.keys - left.keys;
574 size_t n2 = right.keys - mid.keys;
577 copy_slice(left, mid, buffer);
578 struct SortSlice c1 = buffer, e1 = slice_plus(buffer, n1);
579 struct SortSlice c2 = mid, e2 = right, o = left;
581 while (c1.keys < e1.keys && c2.keys < e2.keys) {
582 if (!_list_sorter(*c2.keys, *c1.keys)) {
584 if (o.values) *o.values = *c1.values;
588 if (o.values) *o.values = *c2.values;
594 while (c1.keys < e1.keys) {
596 if (o.values) *o.values = *c1.values;
601 copy_slice(mid, right, buffer);
603 struct SortSlice c1 = slice_plus(mid, -1), s1 = left, o = slice_plus(right, -1);
604 struct SortSlice c2 = slice_plus(buffer, n2 - 1), s2 = buffer;
606 while (c1.keys >= s1.keys && c2.keys >= s2.keys) {
607 if (!_list_sorter(*c2.keys, *c1.keys)) {
609 if (o.values) *o.values = *c2.values;
610 slice_decrement(&c2);
613 if (o.values) *o.values = *c1.values;
614 slice_decrement(&c1);
619 while (c2.keys >= s2.keys) {
621 if (o.values) *o.values = *c2.values;
622 slice_decrement(&c2);
664 for (
size_t i = 0; i < n; ++i) {
675 slice.values = slice.keys;
681 reverse_values(slice.keys, n);
682 if (slice.values) reverse_values(slice.values, n);
702 struct SortSlice begin = {slice.keys, slice.values};
703 struct SortSlice end = {slice.keys + n, slice.values ? slice.values + n : NULL};
706 struct Run a = {begin, powersort_extend_and_reverse_right(begin,end), 0};
708 while (a.end.keys < end.keys) {
710 struct Run b = {a.end, powersort_extend_and_reverse_right(a.end, end), 0};
712 a.power = powersort_power(0, n, a.start.keys - begin.keys, b.start.keys - begin.keys, b.end.keys - begin.keys);
715 while (stack[top].power > a.power) {
717 powersort_merge(top_run.begin, a.start, a.end, buffer);
718 a.start = top_run.begin;
722 a = (
struct Run){b.start, b.end, 0};
728 powersort_merge(top_run.begin, a.start, end, buffer);
729 a.start = top_run.begin;
740 KRK_Method(list,sort) {
743 if (!
krk_parseArgs(
".|$Vp", (
const char*[]){
"key",
"reverse"}, &key, &reverse))
return NONE_VAL();
745 if (self->values.count < 2)
return NONE_VAL();
747 pthread_rwlock_wrlock(&self->rwlock);
748 powersort(
self, key, reverse);
749 pthread_rwlock_unlock(&self->rwlock);
754 KRK_Method(list,__add__) {
755 METHOD_TAKES_EXACTLY(1);
756 if (!IS_list(argv[1]))
return TYPE_ERROR(list,argv[1]);
758 pthread_rwlock_rdlock(&self->rwlock);
760 pthread_rwlock_unlock(&self->rwlock);
761 FUNC_NAME(list,extend)(2,(
KrkValue[]){outList,argv[1]},0);
765 FUNC_SIG(listiterator,__init__);
767 KRK_Method(list,__iter__) {
775 return OBJECT_VAL(output);
778 #define MAKE_LIST_COMPARE(name,op) \
779 KRK_Method(list,__ ## name ## __) { \
780 METHOD_TAKES_EXACTLY(1); \
781 if (!IS_list(argv[1])) return NOTIMPL_VAL(); \
782 KrkList * them = AS_list(argv[1]); \
783 size_t lesser = self->values.count < them->values.count ? self->values.count : them->values.count; \
784 for (size_t i = 0; i < lesser; ++i) { \
785 KrkValue a = self->values.values[i]; \
786 KrkValue b = them->values.values[i]; \
787 if (krk_valuesSameOrEqual(a,b)) continue; \
788 if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return NONE_VAL(); \
789 return krk_operator_ ## name(a,b); \
791 return BOOLEAN_VAL((self->values.count op them->values.count)); \
794 MAKE_LIST_COMPARE(gt,>)
795 MAKE_LIST_COMPARE(lt,<)
796 MAKE_LIST_COMPARE(ge,>=)
797 MAKE_LIST_COMPARE(le,<=)
807 #define CURRENT_CTYPE struct ListIterator *
808 #define IS_listiterator(o) (likely(IS_INSTANCE(o) && AS_INSTANCE(o)->_class == vm.baseClasses->listiteratorClass) || krk_isInstanceOf(o,vm.baseClasses->listiteratorClass))
809 #define AS_listiterator(o) (struct ListIterator*)AS_OBJECT(o)
811 static void _listiterator_gcscan(
KrkInstance *
self) {
815 KRK_Method(listiterator,__init__) {
816 METHOD_TAKES_EXACTLY(1);
817 CHECK_ARG(1,list,
KrkList*,list);
823 FUNC_SIG(listiterator,__call__) {
824 static _unused
const char* _method_name =
"__call__";
825 if (unlikely((argc != 1)))
goto _bad;
826 if (unlikely(!IS_OBJECT(argv[0])))
goto _bad;
827 if (unlikely(AS_INSTANCE(argv[0])->_class !=
vm.baseClasses->listiteratorClass))
goto _bad;
833 size_t _counter =
self->i;
834 if (unlikely(_counter >= AS_LIST(_list)->count)) {
837 self->i = _counter + 1;
838 return AS_LIST(_list)->values[_counter];
842 if (argc != 1)
return NOT_ENOUGH_ARGS(name);
843 if (!
krk_isInstanceOf(argv[0],
vm.baseClasses->listiteratorClass))
return TYPE_ERROR(listiterator, argv[0]);
847 KRK_Function(sorted) {
848 if (argc < 1)
return krk_runtimeError(
vm.exceptions->argumentError,
"%s() takes %s %d argument%s (%d given)",
"sorted",
"at least",1,
"",argc);
851 FUNC_NAME(list,extend)(2,(
KrkValue[]){listOut,argv[0]},0);
853 FUNC_NAME(list,sort)(1,(
KrkValue[]){listOut,hasKw ? argv[1] : NONE_VAL(), hasKw ? argv[2] : NONE_VAL()},hasKw);
858 KRK_Function(reversed) {
861 if (argc != 1)
return krk_runtimeError(
vm.exceptions->argumentError,
"%s() takes %s %d argument%s (%d given)",
"reversed",
"exactly",1,
"",argc);
864 FUNC_NAME(list,extend)(2,(
KrkValue[]){listOut,argv[0]},0);
866 FUNC_NAME(list,reverse)(1,&listOut,0);
872 void _createAndBind_listClass(
void) {
873 KrkClass * list = ADD_BASE_CLASS(
vm.baseClasses->listClass,
"list",
vm.baseClasses->objectClass);
877 BIND_METHOD(list,__init__);
878 BIND_METHOD(list,__eq__);
879 BIND_METHOD(list,__getitem__);
880 BIND_METHOD(list,__setitem__);
881 BIND_METHOD(list,__delitem__);
882 BIND_METHOD(list,__len__);
883 BIND_METHOD(list,__repr__);
884 BIND_METHOD(list,__contains__);
885 BIND_METHOD(list,__iter__);
886 BIND_METHOD(list,__mul__);
887 BIND_METHOD(list,__add__);
888 BIND_METHOD(list,__lt__);
889 BIND_METHOD(list,__gt__);
890 BIND_METHOD(list,__le__);
891 BIND_METHOD(list,__ge__);
892 KRK_DOC(BIND_METHOD(list,append),
893 "@brief Add an item to the end of the list.\n"
894 "@arguments item\n\n"
895 "Adds an item to the end of a list. Appending items to a list is an amortized constant-time "
896 "operation, but may result in the reallocation of the list if not enough additional space is "
897 "available to store to the new element in the current allocation.");
898 KRK_DOC(BIND_METHOD(list,extend),
899 "@brief Add the contents of an iterable to the end of a list.\n"
900 "@argument iterable\n\n"
901 "Adds all of the elements of @p iterable to the end of the list, as if each were added individually "
902 "with @ref _list_append.");
904 "@brief Remove and return an element from the list.\n"
905 "@arguments [index]\n\n"
906 "Removes and returns the entry at the end of the list, or at @p index if provided. "
907 "Popping from the end of the list is constant-time. Popping from the head of the list "
908 "is always O(n) as the contents of the list must be shifted.");
909 KRK_DOC(BIND_METHOD(list,insert),
910 "@brief Add an entry to the list at a given offset.\n"
911 "@arguments index, val\n\n"
912 "Adds @p val to the list at offset @p index, moving all following items back. Inserting "
913 "near the beginning of a list can be costly.");
914 KRK_DOC(BIND_METHOD(list,clear),
915 "@brief Empty a list.\n\n"
916 "Removes all entries from the list.");
917 KRK_DOC(BIND_METHOD(list,index),
918 "@brief Locate an item in the list by value.\n"
919 "@arguments val,[min,[max]]\n\n"
920 "Searches for @p val in the list and returns its index if found. If @p min is provided, "
921 "the search will begin at index @p min. If @p max is also provided, the search will end "
923 "Raises @ref ValueError if the item is not found.");
924 KRK_DOC(BIND_METHOD(list,count),
925 "@brief Count instances of a value in the list.\n"
927 "Scans the list for values equal to @p val and returns the count of matching entries.");
928 KRK_DOC(BIND_METHOD(list,copy),
929 "@brief Clone a list.\n\n"
930 "Equivalent to @c list[:], creates a new list with the same items as this list.");
931 KRK_DOC(BIND_METHOD(list,remove),
932 "@brief Remove an item from the list.\n"
934 "Scans the list for an entry equivalent to @p val and removes it from the list.\n"
935 "Raises @ref ValueError if no matching entry is found.");
936 KRK_DOC(BIND_METHOD(list,reverse),
937 "@brief Reverse the contents of a list.\n\n"
938 "Reverses the elements of the list in-place.");
939 KRK_DOC(BIND_METHOD(list,sort),
940 "@brief Sort the contents of a list.\n\n"
941 "Performs an in-place sort of the elements in the list, returning @c None as a gentle reminder "
942 "that the sort is in-place. If a sorted copy is desired, use @ref sorted instead.");
946 KRK_DOC(list,
"Mutable sequence of arbitrary values.");
948 BUILTIN_FUNCTION(
"sorted", FUNC_NAME(krk,sorted),
949 "@brief Return a sorted representation of an iterable.\n"
950 "@arguments iterable\n\n"
951 "Creates a new, sorted list from the elements of @p iterable.");
952 BUILTIN_FUNCTION(
"reversed", FUNC_NAME(krk,reversed),
953 "@brief Return a reversed representation of an iterable.\n"
954 "@arguments iterable\n\n"
955 "Creates a new, reversed list from the elements of @p iterable.");
957 KrkClass * listiterator = ADD_BASE_CLASS(
vm.baseClasses->listiteratorClass,
"listiterator",
vm.baseClasses->objectClass);
959 listiterator->
_ongcscan = _listiterator_gcscan;
960 listiterator->
obj.
flags |= KRK_OBJ_FLAGS_NO_INHERIT;
961 BIND_METHOD(listiterator,__init__);
962 BIND_METHOD(listiterator,__call__);
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.
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.
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw)
Create a list object.
KrkValueArray values
Stores the length, capacity, and actual values of the list.
The most basic object type.
uint16_t flags
General object flags, mostly related to garbage collection.
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.
KrkValue currentException
KrkValue scratchSpace[KRK_THREAD_SCRATCH_SIZE]
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.
Flexible vector of stack references.
void krk_initValueArray(KrkValueArray *array)
Initialize a value array.
void krk_freeValueArray(KrkValueArray *array)
Release relesources used by a value array.
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Stack reference or primative value.
int krk_isInstanceOf(KrkValue obj, const KrkClass *type)
Determine if a class is an instance or subclass of a given type.
static int krk_valuesSame(KrkValue a, KrkValue b)
Compare two values by identity.
int krk_valuesSameOrEqual(KrkValue a, KrkValue b)
Compare two values by identity, then by equality.
Inline flexible string array.
Convience header for providing atomic operations to threads.
Utilities for creating native bindings.
#define krk_parseArgs(f, n,...)
Parse arguments to a function while accepting keyword arguments.
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.
KrkValue krk_callStack(int argCount)
Call a callable on the stack with argCount arguments.
#define vm
Convenience macro for namespacing.
KrkValue krk_operator_lt(KrkValue, KrkValue)
Compare two values, returning True if the left is less than the right.
KrkValue krk_callNativeOnStack(size_t argCount, const KrkValue *stackArgs, int hasKw, NativeFn native)
Call a native function using a reference to stack arguments safely.
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.