vm.c
1 #include <assert.h>
2 #include <limits.h>
3 #include <stdarg.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <sys/stat.h>
7 
8 #include <kuroko/vm.h>
9 #include <kuroko/debug.h>
10 #include <kuroko/memory.h>
11 #include <kuroko/compiler.h>
12 #include <kuroko/object.h>
13 #include <kuroko/table.h>
14 #include <kuroko/util.h>
15 
16 #include "private.h"
17 #include "opcode_enum.h"
18 
19 /* Ensure we don't have a macro for this so we can reference a local version. */
20 #undef krk_currentThread
21 
22 /* This is macro'd to krk_vm for namespacing reasons. */
23 KrkVM vm = {0};
24 
25 #ifndef KRK_DISABLE_THREADS
26 /*
27  * Marking our little VM thread state as 'initial-exec' is
28  * the fastest way to allocate TLS data and yields virtually
29  * identical performance in the single-thread case to not
30  * having a TLS pointer, but it has some drawbacks...
31  *
32  * Despite documentation saying otherwise, a small thread-local
33  * can generally be allocated even with dlopen, but this is
34  * not guaranteed.
35  */
36 __attribute__((tls_model("initial-exec")))
38 #else
39 /* There is only one thread, so don't store it as TLS... */
41 #endif
42 
43 #if !defined(KRK_DISABLE_THREADS) && defined(__APPLE__) && defined(__aarch64__)
56 void krk_forceThreadData(void) {
57  krk_currentThread.next = NULL;
58  assert(&krk_currentThread == _macos_currentThread());
59 }
66 #define krk_currentThread (*_macos_currentThread())
67 #endif
68 
69 /*
70  * In some threading configurations, particular on Windows,
71  * we can't have executables reference our thread-local thread
72  * state object directly; in order to provide a consistent API
73  * we make @ref krk_currentThread a macro outside of the core
74  * sources that will call this function.
75  */
77  return &krk_currentThread;
78 }
79 
85 void krk_resetStack(void) {
90  krk_currentThread.flags &= ~KRK_THREAD_HAS_EXCEPTION;
92 }
93 
94 void krk_growStack(void) {
95  size_t old = krk_currentThread.stackSize;
96  size_t old_offset = krk_currentThread.stackTop - krk_currentThread.stack;
97  size_t newsize = KRK_GROW_CAPACITY(old);
98  if (krk_currentThread.flags & KRK_THREAD_DEFER_STACK_FREE) {
99  KrkValue * newStack = KRK_GROW_ARRAY(KrkValue, NULL, 0, newsize);
100  memcpy(newStack, krk_currentThread.stack, sizeof(KrkValue) * old);
101  krk_currentThread.stack = newStack;
102  krk_currentThread.flags &= ~(KRK_THREAD_DEFER_STACK_FREE);
103  } else {
104  krk_currentThread.stack = KRK_GROW_ARRAY(KrkValue, krk_currentThread.stack, old, newsize);
105  }
106  krk_currentThread.stackSize = newsize;
109 }
110 
118 inline void krk_push(KrkValue value) {
119  if (unlikely(krk_currentThread.stackTop == krk_currentThread.stackMax)) krk_growStack();
120  *krk_currentThread.stackTop++ = value;
121 }
122 
131 inline KrkValue krk_pop(void) {
133  abort();
134  }
135  return *--krk_currentThread.stackTop;
136 }
137 
138 /* Read a value `distance` units from the top of the stack without poping it. */
139 inline KrkValue krk_peek(int distance) {
140  return krk_currentThread.stackTop[-1 - distance];
141 }
142 
143 /* Exchange the value `distance` units down from the top of the stack with
144  * the value at the top of the stack. */
145 inline void krk_swap(int distance) {
148  krk_currentThread.stackTop[-1 - distance] = top;
149 }
150 
155 KrkNative * krk_defineNative(KrkTable * table, const char * name, NativeFn function) {
156  KrkNative * func = krk_newNative(function, name, 0);
157  krk_attachNamedObject(table, name, (KrkObj*)func);
158  return func;
159 }
160 
164 KrkClass * krk_makeClass(KrkInstance * module, KrkClass ** _class, const char * name, KrkClass * base) {
165  KrkString * str_Name = krk_copyString(name,strlen(name));
166  krk_push(OBJECT_VAL(str_Name));
167  *_class = krk_newClass(str_Name, base);
168  if (module) {
169  krk_push(OBJECT_VAL(*_class));
170  /* Bind it */
171  krk_attachNamedObject(&module->fields,name,(KrkObj*)*_class);
172  /* Now give it a __module__ */
173  KrkValue moduleName = NONE_VAL();
174  krk_tableGet(&module->fields, OBJECT_VAL(S("__name__")), &moduleName);
175  krk_attachNamedValue(&(*_class)->methods,"__module__",moduleName);
176  krk_pop();
177  }
178  krk_pop();
179  return *_class;
180 }
181 
188 _nonnull
189 void krk_finalizeClass(KrkClass * _class) {
190  KrkValue tmp;
191 
192  struct TypeMap {
193  KrkObj ** method;
194  KrkSpecialMethods index;
195  };
196  struct TypeMap specials[] = {
197  #define CACHED_METHOD(a,b,c) {&_class-> c, METHOD_ ## a},
198  #define SPECIAL_ATTRS(a,b)
199  #include "methods.h"
200  #undef CACHED_METHOD
201  #undef SPECIAL_ATTRS
202  {NULL, 0},
203  };
204 
205  _class->cacheIndex = 0;
206 
207  for (struct TypeMap * entry = specials; entry->method; ++entry) {
208  *entry->method = NULL;
209  KrkClass * _base = _class;
210  while (_base) {
211  if (krk_tableGet_fast(&_base->methods, AS_STRING(vm.specialMethodNames[entry->index]), &tmp)) break;
212  _base = _base->base;
213  }
214  if (_base && (IS_CLOSURE(tmp) || IS_NATIVE(tmp)) && (!(AS_OBJECT(tmp)->flags & KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD) || entry->index == METHOD_NEW)) {
215  *entry->method = AS_OBJECT(tmp);
216  }
217  }
218 
219  if (_class->base && _class->_eq != _class->base->_eq) {
220  if (_class->_hash == _class->base->_hash) {
221  _class->_hash = NULL;
222  KrkValue v;
223  if (!krk_tableGet_fast(&_class->methods, AS_STRING(vm.specialMethodNames[METHOD_HASH]), &v)) {
224  krk_tableSet(&_class->methods, vm.specialMethodNames[METHOD_HASH], NONE_VAL());
225  }
226  }
227  }
228 
229  for (size_t i = 0; i < _class->subclasses.capacity; ++i) {
230  KrkTableEntry * entry = &_class->subclasses.entries[i];
231  if (IS_KWARGS(entry->key)) continue;
232  krk_finalizeClass(AS_CLASS(entry->key));
233  }
234 }
235 
241 
242  static size_t objClasses[] = {
243  [KRK_OBJ_CODEOBJECT] = offsetof(struct BaseClasses, codeobjectClass),
244  [KRK_OBJ_NATIVE] = offsetof(struct BaseClasses, functionClass),
245  [KRK_OBJ_CLOSURE] = offsetof(struct BaseClasses, functionClass),
246  [KRK_OBJ_BOUND_METHOD] = offsetof(struct BaseClasses, methodClass),
247  [KRK_OBJ_STRING] = offsetof(struct BaseClasses, strClass),
248  [KRK_OBJ_UPVALUE] = offsetof(struct BaseClasses, CellClass),
249  [KRK_OBJ_CLASS] = offsetof(struct BaseClasses, typeClass),
250  [KRK_OBJ_TUPLE] = offsetof(struct BaseClasses, tupleClass),
251  [KRK_OBJ_BYTES] = offsetof(struct BaseClasses, bytesClass),
252  [KRK_OBJ_INSTANCE] = 0,
253  };
254 
255  switch (KRK_VAL_TYPE(of)) {
256  case KRK_VAL_INTEGER:
257  return vm.baseClasses->intClass;
258  case KRK_VAL_BOOLEAN:
259  return vm.baseClasses->boolClass;
260  case KRK_VAL_NONE:
261  return vm.baseClasses->noneTypeClass;
262  case KRK_VAL_NOTIMPL:
263  return vm.baseClasses->notImplClass;
264  case KRK_VAL_OBJECT:
265  if (IS_INSTANCE(of)) return AS_INSTANCE(of)->_class;
266  if (IS_CLASS(of) && AS_CLASS(of)->_class) return AS_CLASS(of)->_class;
267  return *(KrkClass **)((char*)vm.baseClasses + objClasses[AS_OBJECT(of)->type]);
268  default:
269  if (IS_FLOATING(of)) return vm.baseClasses->floatClass;
270  return vm.baseClasses->objectClass;
271  }
272 }
273 
282 int krk_isInstanceOf(KrkValue obj, const KrkClass * type) {
283  KrkClass * mine = krk_getType(obj);
284  while (mine) {
285  if (mine == type) return 1;
286  mine = mine->base;
287  }
288  return 0;
289 }
290 
291 static inline int checkArgumentCount(const KrkClosure * closure, int argCount) {
292  int minArgs = closure->function->requiredArgs;
293  int maxArgs = closure->function->potentialPositionals;
294  if (unlikely(argCount < minArgs || argCount > maxArgs)) {
295  krk_runtimeError(vm.exceptions->argumentError, "%s() takes %s %d %sargument%s (%d given)",
296  closure->function->name ? closure->function->name->chars : "<unnamed>",
297  (minArgs == maxArgs) ? "exactly" : (argCount < minArgs ? "at least" : "at most"),
298  (argCount < minArgs) ? minArgs : maxArgs,
299  closure->function->keywordArgs ? "positional " : "",
300  ((argCount < minArgs) ? minArgs : maxArgs) == 1 ? "" : "s",
301  argCount);
302  return 0;
303  }
304  return 1;
305 }
306 
307 static void multipleDefs(const KrkClosure * closure, int destination) {
308  krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%S'",
309  closure->function->name ? closure->function->name->chars : "<unnamed>",
310  (destination < closure->function->potentialPositionals ? AS_STRING(closure->function->positionalArgNames.values[destination]) :
311  (destination - closure->function->potentialPositionals < closure->function->keywordArgs ? AS_STRING(closure->function->keywordArgNames.values[destination - closure->function->potentialPositionals]) :
312  S("<unnamed>"))));
313 }
314 
315 static int _unpack_op(void * context, const KrkValue * values, size_t count) {
316  KrkTuple * output = context;
317  if (unlikely(output->values.count + count > output->values.capacity)) {
318  krk_runtimeError(vm.exceptions->valueError, "too many values to unpack (expected %zu)",
319  output->values.capacity);
320  return 1;
321  }
322  for (size_t i = 0; i < count; ++i) {
323  output->values.values[output->values.count++] = values[i];
324  }
325  return 0;
326 }
327 
328 static int _unpack_args(void * context, const KrkValue * values, size_t count) {
329  KrkValueArray * positionals = context;
330  if (positionals->count + count > positionals->capacity) {
331  size_t old = positionals->capacity;
332  positionals->capacity = (count == 1) ? KRK_GROW_CAPACITY(old) : (positionals->count + count);
333  positionals->values = KRK_GROW_ARRAY(KrkValue, positionals->values, old, positionals->capacity);
334  }
335 
336  for (size_t i = 0; i < count; ++i) {
337  positionals->values[positionals->count++] = values[i];
338  }
339 
340  return 0;
341 }
342 
343 int krk_processComplexArguments(int argCount, KrkValueArray * positionals, KrkTable * keywords, const char * name) {
344 #define TOP_ARGS 3
345  size_t kwargsCount = AS_INTEGER(krk_currentThread.stackTop[-TOP_ARGS]);
346  argCount--;
347 
348  /* First, process all the positionals, including any from extractions. */
349  size_t existingPositionalArgs = argCount - kwargsCount * 2;
350  for (size_t i = 0; i < existingPositionalArgs; ++i) {
351  krk_writeValueArray(positionals, krk_currentThread.stackTop[-argCount + i - TOP_ARGS]);
352  }
353 
354  size_t startOfExtras = &krk_currentThread.stackTop[-kwargsCount * 2 - TOP_ARGS] - krk_currentThread.stack;
355  /* Now unpack everything else. */
356  for (size_t i = 0; i < kwargsCount; ++i) {
357  KrkValue key = krk_currentThread.stack[startOfExtras + i*2];
358  KrkValue value = krk_currentThread.stack[startOfExtras + i*2 + 1];
359  if (IS_KWARGS(key)) {
360  if (AS_INTEGER(key) == KWARGS_LIST) { /* unpack list */
361  if (krk_unpackIterable(value,positionals,_unpack_args)) return 0;
362  } else if (AS_INTEGER(key) == KWARGS_DICT) { /* unpack dict */
363  if (!IS_dict(value)) {
364  krk_runtimeError(vm.exceptions->typeError, "%s(): **expression value is not a dict.", name);
365  return 0;
366  }
367  for (size_t i = 0; i < AS_DICT(value)->used; ++i) {
368  KrkTableEntry * entry = &AS_DICT(value)->entries[i];
369  if (!IS_KWARGS(entry->key)) {
370  if (!IS_STRING(entry->key)) {
371  krk_runtimeError(vm.exceptions->typeError, "%s(): **expression contains non-string key", name);
372  return 0;
373  }
374  if (!krk_tableSet(keywords, entry->key, entry->value)) {
375  krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%S'", name, AS_STRING(entry->key));
376  return 0;
377  }
378  }
379  }
380  } else if (AS_INTEGER(key) == KWARGS_SINGLE) { /* single value */
381  krk_writeValueArray(positionals, value);
382  }
383  } else if (IS_STRING(key)) {
384  if (!krk_tableSet(keywords, key, value)) {
385  krk_runtimeError(vm.exceptions->typeError, "%s() got multiple values for argument '%S'", name, AS_STRING(key));
386  return 0;
387  }
388  }
389  }
390  return 1;
391 }
392 
403 static inline int _callManaged(KrkClosure * closure, int argCount, int returnDepth) {
404  size_t potentialPositionalArgs = closure->function->potentialPositionals;
405  size_t totalArguments = closure->function->totalArguments;
406  size_t offsetOfExtraArgs = potentialPositionalArgs;
407  size_t argCountX = argCount;
408 
409  if (argCount && unlikely(IS_KWARGS(krk_currentThread.stackTop[-1]))) {
410 
411  KrkValue myList = krk_list_of(0,NULL,0);
412  krk_push(myList);
413  KrkValueArray * positionals;
414  positionals = AS_LIST(myList);
415 
416  KrkValue myDict = krk_dict_of(0,NULL,0);
417  krk_push(myDict);
418  KrkTable * keywords;
419  keywords = AS_DICT(myDict);
420 
421  /* This processes the existing argument list into a ValueArray and a Table with the args and keywords */
422  if (!krk_processComplexArguments(argCount, positionals, keywords, closure->function->name ? closure->function->name->chars : "<unnamed>")) return 0;
423 
424  /* Store scratch while we adjust; we can not make calls while using these scratch
425  * registers as they may be clobbered by a nested call to _callManaged. */
426  krk_currentThread.scratchSpace[0] = myList;
427  krk_currentThread.scratchSpace[1] = myDict;
428 
429  /* Pop three things, including the kwargs count */
430  krk_pop(); /* dict */
431  krk_pop(); /* list */
432  krk_pop(); /* kwargs */
433 
434  /* We popped the kwargs sentinel, which counted for one argCount */
435  argCount--;
436 
437  /* Do we already know we have too many arguments? Let's bail before doing a bunch of work. */
438  if ((positionals->count > potentialPositionalArgs) && !(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS)) {
439  checkArgumentCount(closure,positionals->count);
440  goto _errorDuringPositionals;
441  }
442 
443  /* Prepare stack space for all potential positionals, mark them unset */
444  for (size_t i = 0; i < (size_t)argCount; ++i) {
445  krk_currentThread.stackTop[-argCount + i] = KWARGS_VAL(0);
446  }
447 
448  /* Do we have a bunch of unused keyword argument slots? Fill them in. */
449  while ((size_t)argCount < potentialPositionalArgs) {
450  krk_push(KWARGS_VAL(0));
451  argCount++;
452  }
453 
454  /* Did we have way more arguments than we needed? Put the stack where it should be. */
455  while ((size_t)argCount > potentialPositionalArgs) {
456  krk_pop();
457  argCount--;
458  }
459 
460  /* Place positional arguments */
461  for (size_t i = 0; i < potentialPositionalArgs && i < positionals->count; ++i) {
462  krk_currentThread.stackTop[-argCount + i] = positionals->values[i];
463  }
464 
465  if (closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) {
466  size_t count = (positionals->count > potentialPositionalArgs) ? (positionals->count - potentialPositionalArgs) : 0;
467  KrkValue * offset = (count == 0) ? NULL : &positionals->values[potentialPositionalArgs];
468  krk_push(krk_list_of(count, offset, 0));
469  argCount++;
470  }
471 
472  for (size_t i = 0; i < closure->function->keywordArgs; ++i) {
473  krk_push(KWARGS_VAL(0));
474  argCount++;
475  }
476 
477  /* We're done with the positionals */
478  krk_currentThread.scratchSpace[0] = NONE_VAL();
479 
480  /* Now place keyword arguments */
481  for (size_t i = 0; i < keywords->used; ++i) {
482  KrkTableEntry * entry = &keywords->entries[i];
483  if (!IS_KWARGS(entry->key)) {
484  KrkValue name = entry->key;
485  KrkValue value = entry->value;
486  /* See if we can place it */
487  for (int j = 0; j < (int)closure->function->potentialPositionals; ++j) {
488  if (krk_valuesSame(name, closure->function->positionalArgNames.values[j])) {
489  if (!IS_KWARGS(krk_currentThread.stackTop[-argCount + j])) {
490  multipleDefs(closure,j);
491  goto _errorAfterPositionals;
492  }
493  krk_currentThread.stackTop[-argCount + j] = value;
494  goto _finishKwarg;
495  }
496  }
497  /* See if it's a keyword arg. */
498  for (int j = 0; j < (int)closure->function->keywordArgs; ++j) {
499  if (krk_valuesSame(name, closure->function->keywordArgNames.values[j])) {
500  if (!IS_KWARGS(krk_currentThread.stackTop[-argCount + j + closure->function->potentialPositionals + !!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS)])) {
501  multipleDefs(closure, j + closure->function->potentialPositionals);
502  goto _errorAfterPositionals;
503  }
504  krk_currentThread.stackTop[-argCount + j + closure->function->potentialPositionals + !!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS)] = value;
505  goto _finishKwarg;
506  }
507  }
508  if (!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS)) {
509  krk_runtimeError(vm.exceptions->typeError, "%s() got an unexpected keyword argument '%S'",
510  closure->function->name ? closure->function->name->chars : "<unnamed>",
511  AS_STRING(name));
512  goto _errorAfterPositionals;
513  }
514  continue;
515 _finishKwarg:
516  entry->key = KWARGS_VAL(0);
517  entry->value = BOOLEAN_VAL(1);
518  continue;
519  }
520  }
521 
522  /* If this function takes a **kwargs, we need to provide it as a dict */
523  if (closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS) {
524  krk_push(krk_dict_of(0,NULL,0));
525  argCount++;
526  krk_tableAddAll(keywords, AS_DICT(krk_peek(0)));
527  }
528 
529  /* We're done with the keywords */
530  krk_currentThread.scratchSpace[1] = NONE_VAL();
531 
532  for (size_t i = 0; i < (size_t)closure->function->requiredArgs; ++i) {
533  if (IS_KWARGS(krk_currentThread.stackTop[-argCount + i])) {
534  if (i < closure->function->localNameCount) {
535  krk_runtimeError(vm.exceptions->typeError, "%s() %s: '%S'",
536  closure->function->name ? closure->function->name->chars : "<unnamed>",
537  "missing required positional argument",
538  closure->function->localNames[i].name);
539  } else {
540  krk_runtimeError(vm.exceptions->typeError, "%s() %s",
541  closure->function->name ? closure->function->name->chars : "<unnamed>",
542  "missing required positional argument");
543  }
544  goto _errorAfterKeywords;
545  }
546  }
547 
548  argCountX = argCount - closure->function->keywordArgs - (!!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS) + !!(closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_KWS));
549  } else if ((size_t)argCount > potentialPositionalArgs && (closure->function->obj.flags & KRK_OBJ_FLAGS_CODEOBJECT_COLLECTS_ARGS)) {
550  KrkValue * startOfPositionals = &krk_currentThread.stackTop[-argCount];
551  KrkValue tmp = krk_callNativeOnStack(argCount - potentialPositionalArgs,
552  &startOfPositionals[potentialPositionalArgs], 0, krk_list_of);
553  startOfPositionals = &krk_currentThread.stackTop[-argCount];
554  startOfPositionals[offsetOfExtraArgs] = tmp;
555  argCount = potentialPositionalArgs + 1;
556  argCountX = argCount - 1;
557  while (krk_currentThread.stackTop > startOfPositionals + argCount) krk_pop();
558  }
559 
560  if (unlikely(!checkArgumentCount(closure, argCountX))) goto _errorAfterKeywords;
561 
562  while (argCount < (int)totalArguments) {
563  krk_push(KWARGS_VAL(0));
564  argCount++;
565  }
566 
567  if (unlikely(closure->function->obj.flags & (KRK_OBJ_FLAGS_CODEOBJECT_IS_GENERATOR | KRK_OBJ_FLAGS_CODEOBJECT_IS_COROUTINE))) {
568  KrkInstance * gen = krk_buildGenerator(closure, krk_currentThread.stackTop - argCount, argCount);
569  krk_currentThread.stackTop = krk_currentThread.stackTop - argCount - returnDepth;
570  krk_push(OBJECT_VAL(gen));
571  return 2;
572  }
573 
575  krk_runtimeError(vm.exceptions->baseException, "maximum recursion depth exceeded");
576  goto _errorAfterKeywords;
577  }
578 
580  frame->closure = closure;
581  frame->ip = closure->function->chunk.code;
582  frame->slots = (krk_currentThread.stackTop - argCount) - krk_currentThread.stack;
583  frame->outSlots = frame->slots - returnDepth;
584  frame->globalsOwner = closure->globalsOwner;
585  frame->globals = closure->globalsTable;
586  return 1;
587 
588 _errorDuringPositionals:
589  krk_currentThread.scratchSpace[0] = NONE_VAL();
590 _errorAfterPositionals:
591  krk_currentThread.scratchSpace[1] = NONE_VAL();
592 _errorAfterKeywords:
593  return 0;
594 }
595 
601 inline KrkValue krk_callNativeOnStack(size_t argCount, const KrkValue *stackArgs, int hasKw, NativeFn native) {
602 
606  if (unlikely(krk_currentThread.flags & KRK_THREAD_DEFER_STACK_FREE)) {
607  return native(argCount, stackArgs, hasKw);
608  }
609 
610  /* Mark the thread's stack as preserved. */
611  krk_currentThread.flags |= KRK_THREAD_DEFER_STACK_FREE;
612  size_t sizeBefore = krk_currentThread.stackSize;
613  void * stackBefore = krk_currentThread.stack;
614  KrkValue result = native(argCount, stackArgs, hasKw);
615 
616  if (unlikely(krk_currentThread.stack != stackBefore)) {
617  KRK_FREE_ARRAY(KrkValue, stackBefore, sizeBefore);
618  }
619 
620  krk_currentThread.flags &= ~(KRK_THREAD_DEFER_STACK_FREE);
621  return result;
622 }
623 
630 static void _rotate(size_t argCount) {
631  krk_push(NONE_VAL());
632  memmove(&krk_currentThread.stackTop[-argCount],&krk_currentThread.stackTop[-argCount-1],sizeof(KrkValue) * argCount);
633 }
634 
635 static inline int _callNative(KrkNative* callee, int argCount, int returnDepth) {
636  NativeFn native = (NativeFn)callee->function;
637  size_t stackOffsetAfterCall = (krk_currentThread.stackTop - krk_currentThread.stack) - argCount - returnDepth;
638  KrkValue result;
639  if (unlikely(argCount && IS_KWARGS(krk_currentThread.stackTop[-1]))) {
640  /* Prep space for our list + dictionary */
641  KrkValue myList = krk_list_of(0,NULL,0);
642  krk_push(myList);
643  KrkValue myDict = krk_dict_of(0,NULL,0);
644  krk_push(myDict);
645 
646  /* Parse kwargs stuff into the list+dict; note, this no longer pops anything, and expects
647  * our list + dict to be at the top: [kwargs] [list] [dict] */
648  if (unlikely(!krk_processComplexArguments(argCount, AS_LIST(myList), AS_DICT(myDict), callee->name))) return 0;
649 
650  /* Write the dict into the list */
651  krk_writeValueArray(AS_LIST(myList), myDict);
652 
653  /* Also add a list for storing references that get removed from the kwargs dict during mutation. */
654  KrkValue refList = krk_list_of(0,NULL,0);
655  krk_push(refList);
656  krk_writeValueArray(AS_LIST(myList), refList);
657 
658  /* Reduce the stack to just the list */
659  krk_currentThread.stack[stackOffsetAfterCall] = myList;
660  krk_currentThread.stackTop = &krk_currentThread.stack[stackOffsetAfterCall+1];
661 
662  /* Call with list as arguments */
663  result = native(AS_LIST(myList)->count-2, AS_LIST(myList)->values, 1);
664  } else {
665  result = krk_callNativeOnStack(argCount, krk_currentThread.stackTop - argCount, 0, native);
666  }
667  krk_currentThread.stackTop = &krk_currentThread.stack[stackOffsetAfterCall];
668  krk_push(result);
669  return 2;
670 }
671 
691 int krk_callValue(KrkValue callee, int argCount, int returnDepth) {
692  if (likely(IS_OBJECT(callee))) {
693  _innerObject:
694  switch (OBJECT_TYPE(callee)) {
695  case KRK_OBJ_CLOSURE: return _callManaged(AS_CLOSURE(callee), argCount, returnDepth);
696  case KRK_OBJ_NATIVE: return _callNative(AS_NATIVE(callee), argCount, returnDepth);
697  case KRK_OBJ_BOUND_METHOD: {
698  KrkBoundMethod * bound = AS_BOUND_METHOD(callee);
699  if (unlikely(!bound->method)) {
700  krk_runtimeError(vm.exceptions->argumentError, "???");
701  return 0;
702  }
703  if (unlikely(returnDepth == 0)) _rotate(argCount);
704  krk_currentThread.stackTop[-argCount - 1] = bound->receiver;
705  callee = OBJECT_VAL(bound->method);
706  argCount++;
707  returnDepth = returnDepth ? (returnDepth - 1) : 0;
708  goto _innerObject;
709  }
710  default: {
711  KrkClass * _class = krk_getType(callee);
712  if (likely(_class->_call != NULL)) {
713  if (unlikely(returnDepth == 0)) _rotate(argCount);
714  krk_currentThread.stackTop[-argCount - 1] = callee;
715  argCount++;
716  returnDepth = returnDepth ? (returnDepth - 1) : 0;
717  return (_class->_call->type == KRK_OBJ_CLOSURE) ? _callManaged((KrkClosure*)_class->_call, argCount, returnDepth) : _callNative((KrkNative*)_class->_call, argCount, returnDepth);
718  } else {
719  krk_runtimeError(vm.exceptions->typeError, "'%T' object is not callable", callee);
720  return 0;
721  }
722  }
723  }
724  }
725  krk_runtimeError(vm.exceptions->typeError, "'%T' object is not callable", callee);
726  return 0;
727 }
728 
732 KrkValue krk_callStack(int argCount) {
733  switch (krk_callValue(krk_peek(argCount), argCount, 1)) {
734  case 2: return krk_pop();
735  case 1: return krk_runNext();
736  default: return NONE_VAL();
737  }
738 }
739 
740 KrkValue krk_callDirect(KrkObj * callable, int argCount) {
741  int result = 0;
742  switch (callable->type) {
743  case KRK_OBJ_CLOSURE: result = _callManaged((KrkClosure*)callable, argCount, 0); break;
744  case KRK_OBJ_NATIVE: result = _callNative((KrkNative*)callable, argCount, 0); break;
745  default: __builtin_unreachable();
746  }
747  if (likely(result == 2)) return krk_pop();
748  else if (result == 1) return krk_runNext();
749  return NONE_VAL();
750 }
751 
756 static KrkUpvalue * captureUpvalue(int index) {
757  KrkUpvalue * prevUpvalue = NULL;
759  while (upvalue != NULL && upvalue->location > index) {
760  prevUpvalue = upvalue;
761  upvalue = upvalue->next;
762  }
763  if (upvalue != NULL && upvalue->location == index) {
764  return upvalue;
765  }
766  KrkUpvalue * createdUpvalue = krk_newUpvalue(index);
767  createdUpvalue->next = upvalue;
768  if (prevUpvalue == NULL) {
769  krk_currentThread.openUpvalues = createdUpvalue;
770  } else {
771  prevUpvalue->next = createdUpvalue;
772  }
773  return createdUpvalue;
774 }
775 
776 #define UPVALUE_LOCATION(upvalue) (upvalue->location == -1 ? &upvalue->closed : &upvalue->owner->stack[upvalue->location])
777 
782 static void closeUpvalues(int last) {
785  upvalue->closed = krk_currentThread.stack[upvalue->location];
786  upvalue->location = -1;
788  }
789 }
790 
794 void krk_attachNamedValue(KrkTable * table, const char name[], KrkValue obj) {
795  krk_push(obj);
796  krk_push(OBJECT_VAL(krk_copyString(name,strlen(name))));
797  krk_tableSet(table, krk_peek(0), krk_peek(1));
798  krk_pop();
799  krk_pop();
800 }
801 
808 void krk_attachNamedObject(KrkTable * table, const char name[], KrkObj * obj) {
809  krk_attachNamedValue(table,name,OBJECT_VAL(obj));
810 }
811 
821 int krk_isFalsey(KrkValue value) {
822  switch (KRK_VAL_TYPE(value)) {
823  case KRK_VAL_NONE: return 1;
824  case KRK_VAL_BOOLEAN: return !AS_BOOLEAN(value);
825  case KRK_VAL_INTEGER: return !AS_INTEGER(value);
826  case KRK_VAL_NOTIMPL: return 1;
827  case KRK_VAL_OBJECT: {
828  switch (AS_OBJECT(value)->type) {
829  case KRK_OBJ_STRING: return !AS_STRING(value)->codesLength;
830  case KRK_OBJ_TUPLE: return !AS_TUPLE(value)->values.count;
831  default: break;
832  }
833  break;
834  }
835  default:
836 #ifndef KRK_NO_FLOAT
837  if (IS_FLOATING(value)) return !AS_FLOATING(value);
838 #endif
839  break;
840  }
841  KrkClass * type = krk_getType(value);
842 
843  if (type->_bool) {
844  krk_push(value);
845  KrkValue result = krk_callDirect(type->_bool,1);
846  if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return 1;
847  if (!IS_BOOLEAN(result)) {
848  krk_runtimeError(vm.exceptions->typeError, "__bool__ should return bool, not %T", result);
849  return 1;
850  }
851  return !AS_INTEGER(result);
852  }
853 
854  /* If it has a length, and that length is 0, it's Falsey */
855  if (type->_len) {
856  krk_push(value);
857  KrkValue result = krk_callDirect(type->_len,1);
858  return !AS_INTEGER(result);
859  }
860  return 0; /* Assume anything else is truthy */
861 }
862 
863 void krk_setMaximumRecursionDepth(size_t maxDepth) {
865  krk_currentThread.frames = realloc(krk_currentThread.frames, maxDepth * sizeof(KrkCallFrame));
866 }
867 
868 void krk_initVM(int flags) {
869 #if !defined(KRK_DISABLE_THREADS) && defined(__APPLE__) && defined(__aarch64__)
870  krk_forceThreadData();
871 #endif
872 
873  vm.globalFlags = flags & 0xFF00;
874 
875  /* Reset current thread */
876  krk_resetStack();
879  krk_currentThread.flags = flags & 0x00FF;
880  krk_currentThread.module = NULL;
881  vm.threads = &krk_currentThread;
882  vm.threads->next = NULL;
883 
884  /* GC state */
885  vm.objects = NULL;
886  vm.bytesAllocated = 0;
887  vm.nextGC = 1024 * 1024;
888  vm.grayCount = 0;
889  vm.grayCapacity = 0;
890  vm.grayStack = NULL;
891 
892  /* Global objects */
893  vm.exceptions = calloc(1,sizeof(struct Exceptions));
894  vm.baseClasses = calloc(1,sizeof(struct BaseClasses));
895  vm.specialMethodNames = calloc(METHOD__MAX,sizeof(KrkValue));
896  krk_initTable(&vm.strings);
897  krk_initTable(&vm.modules);
898 
899  /*
900  * To make lookup faster, store these so we can don't have to keep boxing
901  * and unboxing, copying/hashing etc.
902  */
903  struct { const char * s; size_t len; } _methods[] = {
904  #define CACHED_METHOD(a,b,c) [METHOD_ ## a] = {b,sizeof(b)-1},
905  #define SPECIAL_ATTRS(a,b) [METHOD_ ## a] = {b,sizeof(b)-1},
906  #include "methods.h"
907  #undef CACHED_METHOD
908  #undef SPECIAL_ATTRS
909  };
910  for (size_t i = 0; i < METHOD__MAX; ++i) {
911  vm.specialMethodNames[i] = OBJECT_VAL(krk_copyString(_methods[i].s, _methods[i].len));
912  }
913 
914  /* Build classes for basic types */
915  _createAndBind_builtins();
916  _createAndBind_type();
917  _createAndBind_numericClasses();
918  _createAndBind_strClass();
919  _createAndBind_listClass();
920  _createAndBind_tupleClass();
921  _createAndBind_bytesClass();
922  _createAndBind_dictClass();
923  _createAndBind_functionClass();
924  _createAndBind_rangeClass();
925  _createAndBind_setClass();
926  _createAndBind_sliceClass();
928  _createAndBind_generatorClass();
929  _createAndBind_longClass();
930  _createAndBind_compilerClass();
931 
932  if (!(vm.globalFlags & KRK_GLOBAL_NO_DEFAULT_MODULES)) {
933 #ifndef KRK_NO_SYSTEM_MODULES
935 #endif
936 #ifndef KRK_DISABLE_THREADS
938 #endif
939  }
940 
941 #ifndef KRK_DISABLE_DEBUG
942  krk_debug_init();
943 #endif
944 
945 
946  /* The VM is now ready to start executing code. */
947  krk_resetStack();
948 }
949 
953 void krk_freeVM(void) {
954  krk_freeTable(&vm.strings);
955  krk_freeTable(&vm.modules);
956  if (vm.specialMethodNames) free(vm.specialMethodNames);
957  if (vm.exceptions) free(vm.exceptions);
958  if (vm.baseClasses) free(vm.baseClasses);
959  krk_freeObjects();
960 
961  if (vm.binpath) free(vm.binpath);
962  if (vm.dbgState) free(vm.dbgState);
963 
964  while (krk_currentThread.next) {
966  krk_currentThread.next = thread->next;
967  KRK_FREE_ARRAY(size_t, thread->stack, thread->stackSize);
968  free(thread->frames);
969  }
970 
971  KRK_FREE_ARRAY(size_t, krk_currentThread.stack, krk_currentThread.stackSize);
972  memset(&krk_vm,0,sizeof(krk_vm));
974  memset(&krk_currentThread,0,sizeof(KrkThreadState));
975 
976  extern void krk_freeMemoryDebugger(void);
977  krk_freeMemoryDebugger();
978 }
979 
984 const char * krk_typeName(KrkValue value) {
985  return krk_getType(value)->name->chars;
986 }
987 
988 static int _try_op(size_t methodOffset, KrkValue a, KrkValue b, KrkValue *out) {
989  KrkClass * type = krk_getType(a);
990  KrkObj * method = *(KrkObj**)((char*)type + methodOffset);
991  if (likely(method != NULL)) {
992  krk_push(a);
993  krk_push(b);
994  KrkValue result = krk_callDirect(method, 2);
995  if (likely(!IS_NOTIMPL(result))) {
996  *out = result;
997  return 1;
998  }
999  if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) {
1000  *out = NONE_VAL();
1001  return 1;
1002  }
1003  }
1004  return 0;
1005 }
1006 
1007 static KrkValue _bin_op(size_t methodOffset, size_t invOffset, const char * operator, KrkValue a, KrkValue b) {
1008  KrkValue result;
1009  if (_try_op(methodOffset, a, b, &result)) return result;
1010  if (_try_op(invOffset, b, a, &result)) return result;
1011  return krk_runtimeError(vm.exceptions->typeError,
1012  "unsupported operand types for %s: '%T' and '%T'",
1013  operator, a, b);
1014 }
1015 
1016 #define MAKE_COMPARE_OP(name,operator,inv) \
1017  _protected KrkValue krk_operator_ ## name (KrkValue a, KrkValue b) { \
1018  return _bin_op(offsetof(KrkClass,_ ## name),offsetof(KrkClass,_ ## inv), operator, a, b); \
1019  }
1020 #define MAKE_BIN_OP(name,operator,inv) \
1021  MAKE_COMPARE_OP(name,operator,inv) \
1022  _protected KrkValue krk_operator_i ## name (KrkValue a, KrkValue b) { \
1023  KrkValue result; \
1024  if (_try_op(offsetof(KrkClass,_i ## name), a, b, &result)) return result; \
1025  return krk_operator_ ## name(a,b); \
1026  }
1027 
1028 MAKE_BIN_OP(add,"+",radd)
1029 MAKE_BIN_OP(sub,"-",rsub)
1030 MAKE_BIN_OP(mul,"*",rmul)
1031 MAKE_BIN_OP(pow,"**",rpow)
1032 MAKE_BIN_OP(or,"|",ror)
1033 MAKE_BIN_OP(xor,"^",rxor)
1034 MAKE_BIN_OP(and,"&",rand)
1035 MAKE_BIN_OP(lshift,"<<",rlshift)
1036 MAKE_BIN_OP(rshift,">>",rrshift)
1037 MAKE_BIN_OP(mod,"%",rmod)
1038 MAKE_BIN_OP(truediv,"/",rtruediv)
1039 MAKE_BIN_OP(floordiv,"//",rfloordiv)
1040 MAKE_BIN_OP(matmul,"@",rmatmul)
1041 
1042 MAKE_COMPARE_OP(lt, "<", gt)
1043 MAKE_COMPARE_OP(gt, ">", lt)
1044 MAKE_COMPARE_OP(le, "<=", ge)
1045 MAKE_COMPARE_OP(ge, ">=", le)
1046 
1047 _protected
1048 KrkValue krk_operator_eq(KrkValue a, KrkValue b) {
1049  return BOOLEAN_VAL(krk_valuesEqual(a,b));
1050 }
1051 
1052 _protected
1053 KrkValue krk_operator_is(KrkValue a, KrkValue b) {
1054  return BOOLEAN_VAL(krk_valuesSame(a,b));
1055 }
1056 
1057 static KrkValue _unary_op(size_t methodOffset, const char * operator, KrkValue value) {
1058  KrkClass * type = krk_getType(value);
1059  KrkObj * method = *(KrkObj**)((char*)type + methodOffset);
1060  if (likely(method != NULL)) {
1061  krk_push(value);
1062  return krk_callDirect(method, 1);
1063  }
1064  if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) return NONE_VAL();
1065  return krk_runtimeError(vm.exceptions->typeError, "bad operand type for unary %s: '%T'", operator, value);
1066 }
1067 
1068 #define MAKE_UNARY_OP(sname,operator,op) \
1069  _protected KrkValue krk_operator_ ## operator (KrkValue value) { \
1070  return _unary_op(offsetof(KrkClass,sname),#op,value); \
1071  }
1072 
1073 MAKE_UNARY_OP(_invert,invert,~)
1074 MAKE_UNARY_OP(_negate,neg,-)
1075 MAKE_UNARY_OP(_pos,pos,+)
1076 
1088 static int handleException(void) {
1089  int stackOffset, frameOffset;
1091  for (stackOffset = (int)(krk_currentThread.stackTop - krk_currentThread.stack - 1);
1092  stackOffset >= exitSlot &&
1093  !IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_PUSH_TRY) &&
1094  !IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_PUSH_WITH) &&
1095  !IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_FILTER_EXCEPT) &&
1096  !IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_RAISE) &&
1097  !IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset], OP_END_FINALLY)
1098  ; stackOffset--);
1099  if (stackOffset < exitSlot) {
1100  if (exitSlot == 0) {
1101  /*
1102  * No exception was found and we have reached the top of the call stack.
1103  * Call dumpTraceback to present the exception to the user and reset the
1104  * VM stack state. It should still be safe to execute more code after
1105  * this reset, so the repl can throw errors and keep accepting new lines.
1106  */
1107  if (!(vm.globalFlags & KRK_GLOBAL_CLEAN_OUTPUT)) krk_dumpTraceback();
1108  }
1110 
1111  /* Ensure stack is in the expected place, as if we returned None. */
1112  closeUpvalues(exitSlot);
1114 
1115  /* If exitSlot was not 0, there was an exception during a call to runNext();
1116  * this is likely to be raised higher up the stack as an exception in the outer
1117  * call, but we don't want to print the traceback here. */
1118  return 1;
1119  }
1120 
1121  /* Find the call frame that owns this stack slot */
1122  for (frameOffset = krk_currentThread.frameCount - 1; frameOffset >= 0 && (int)krk_currentThread.frames[frameOffset].slots > stackOffset; frameOffset--);
1123  if (frameOffset == -1) {
1124  abort();
1125  }
1126 
1127  /* We found an exception handler and can reset the VM to its call frame. */
1128  closeUpvalues(stackOffset);
1129  krk_currentThread.stackTop = krk_currentThread.stack + stackOffset + 1;
1130  krk_currentThread.frameCount = frameOffset + 1;
1131 
1132  /* Clear the exception flag so we can continue executing from the handler. */
1133  krk_currentThread.flags &= ~KRK_THREAD_HAS_EXCEPTION;
1134  return 0;
1135 }
1136 
1146 int krk_loadModule(KrkString * path, KrkValue * moduleOut, KrkString * runAs, KrkValue parent) {
1147  /* See if the module is already loaded */
1148  if (krk_tableGet_fast(&vm.modules, runAs, moduleOut)) {
1149  krk_push(*moduleOut);
1150  return 1;
1151  }
1152 
1153 #ifndef KRK_NO_FILESYSTEM
1154  KrkValue modulePaths;
1155 
1156  /* Obtain __builtins__.module_paths */
1157  if (!vm.system || !krk_tableGet_fast(&vm.system->fields, S("module_paths"), &modulePaths)) {
1158  *moduleOut = NONE_VAL();
1159  krk_runtimeError(vm.exceptions->importError, "kuroko.module_paths not defined.");
1160  return 0;
1161  }
1162 
1163  if (!IS_list(modulePaths)) {
1164  *moduleOut = NONE_VAL();
1165  krk_runtimeError(vm.exceptions->importError, "kuroko.module_paths must be a list, not '%T'", modulePaths);
1166  return 0;
1167  }
1168 
1169  /* Obtain __builtins__.module_paths.__list so we can do lookups directly */
1170  int moduleCount = AS_LIST(modulePaths)->count;
1171  if (!moduleCount) {
1172  *moduleOut = NONE_VAL();
1173  krk_runtimeError(vm.exceptions->importError,
1174  "No module search directories are specified, so no modules may be imported.");
1175  return 0;
1176  }
1177 
1178  struct stat statbuf;
1179 
1180  /* First search for {path}.krk in the module search paths */
1181  for (int i = 0; i < moduleCount; ++i, krk_pop()) {
1182  int isPackage = 0;
1183  char * fileName;
1184 
1185  krk_push(AS_LIST(modulePaths)->values[i]);
1186  if (!IS_STRING(krk_peek(0))) {
1187  *moduleOut = NONE_VAL();
1188  krk_runtimeError(vm.exceptions->typeError,
1189  "Module search path must be str, not '%T'", krk_peek(0));
1190  return 0;
1191  }
1192 
1193  /* Try .../path/__init__.krk */
1194  krk_push(OBJECT_VAL(path));
1195  krk_addObjects();
1196  krk_push(OBJECT_VAL(S(KRK_PATH_SEP "__init__.krk")));
1197  krk_addObjects();
1198  fileName = AS_CSTRING(krk_peek(0));
1199  if (stat(fileName,&statbuf) == 0) {
1200  isPackage = 1;
1201  if (runAs == S("__main__")) {
1202  krk_pop(); /* concatenated name */
1203 
1204  /* Convert back to .-formatted */
1205  krk_push(krk_valueGetAttribute(OBJECT_VAL(path), "replace"));
1206  krk_push(OBJECT_VAL(S(KRK_PATH_SEP)));
1207  krk_push(OBJECT_VAL(S(".")));
1208  krk_push(krk_callStack(2));
1209  KrkValue packageName = krk_peek(0);
1210  krk_push(packageName);
1211  krk_push(OBJECT_VAL(S(".")));
1212  krk_addObjects();
1213  krk_push(OBJECT_VAL(runAs));
1214  krk_addObjects();
1215 
1216  /* Try to import that. */
1217  KrkValue dotted_main = krk_peek(0);
1218  if (!krk_importModule(AS_STRING(dotted_main),runAs)) {
1219  krk_runtimeError(vm.exceptions->importError, "No module named '%S'; '%S' is a package and cannot be executed directly",
1220  AS_STRING(dotted_main), AS_STRING(packageName));
1221  return 0;
1222  }
1223 
1224  krk_swap(2);
1225  krk_pop(); /* package name */
1226  krk_pop(); /* dotted_main */
1227  *moduleOut = krk_peek(0);
1228  return 1;
1229  }
1230  goto _normalFile;
1231  }
1232 
1233 #ifndef KRK_STATIC_ONLY
1234  /* Try .../path.so */
1235  krk_pop();
1236  krk_push(AS_LIST(modulePaths)->values[i]);
1237  krk_push(OBJECT_VAL(path));
1238  krk_addObjects(); /* Concatenate path... */
1239  krk_push(OBJECT_VAL(S(".so")));
1240  krk_addObjects(); /* and file extension */
1241  fileName = AS_CSTRING(krk_peek(0));
1242  if (stat(fileName,&statbuf) == 0) {
1243  goto _sharedObject;
1244  }
1245 #endif
1246 
1247  /* Try .../path.krk */
1248  krk_pop();
1249  krk_push(AS_LIST(modulePaths)->values[i]);
1250  krk_push(OBJECT_VAL(path));
1251  krk_addObjects(); /* Concatenate path... */
1252  krk_push(OBJECT_VAL(S(".krk")));
1253  krk_addObjects(); /* and file extension */
1254  fileName = AS_CSTRING(krk_peek(0));
1255  if (stat(fileName,&statbuf) == 0) {
1256  goto _normalFile;
1257  }
1258 
1259  /* Try next search path */
1260  continue;
1261 
1262  _normalFile: (void)0;
1263  /* Compile and run the module in a new context and exit the VM when it
1264  * returns to the current call frame; modules should return objects. */
1265  KrkInstance * enclosing = krk_currentThread.module;
1266  krk_startModule(runAs->chars);
1267  if (isPackage) {
1268  krk_attachNamedValue(&krk_currentThread.module->fields,"__ispackage__",BOOLEAN_VAL(1));
1269  /* For a module that is a package, __package__ is its own name */
1270  krk_attachNamedValue(&krk_currentThread.module->fields,"__package__",OBJECT_VAL(runAs));
1271  } else {
1272  KrkValue parentName;
1273  if (IS_INSTANCE(parent) && krk_tableGet_fast(&AS_INSTANCE(parent)->fields, S("__name__"), &parentName) && IS_STRING(parentName)) {
1274  krk_attachNamedValue(&krk_currentThread.module->fields, "__package__", parentName);
1275  } else {
1276  /* If there is no parent, or the parent doesn't have a string __name__ attribute,
1277  * set the __package__ to None, so it at least exists. */
1278  krk_attachNamedValue(&krk_currentThread.module->fields, "__package__", NONE_VAL());
1279  }
1280  }
1281  krk_runfile(fileName,fileName);
1282  *moduleOut = OBJECT_VAL(krk_currentThread.module);
1283  krk_currentThread.module = enclosing;
1284  if (!IS_OBJECT(*moduleOut) || (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
1285  if (!(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
1286  krk_runtimeError(vm.exceptions->importError,
1287  "Failed to load module '%S' from '%s'", runAs, fileName);
1288  }
1289  krk_tableDelete(&vm.modules, OBJECT_VAL(runAs));
1290  return 0;
1291  }
1292 
1293  krk_pop(); /* concatenated filename on stack */
1294  krk_push(*moduleOut);
1295  return 1;
1296 
1297 #ifndef KRK_STATIC_ONLY
1298  _sharedObject: (void)0;
1299 
1300  krk_dlRefType dlRef = krk_dlOpen(fileName);
1301  if (!dlRef) {
1302  *moduleOut = NONE_VAL();
1303  krk_runtimeError(vm.exceptions->importError,
1304  "Failed to load native module '%S' from shared object '%s'", runAs, fileName);
1305  return 0;
1306  }
1307 
1308  const char * start = path->chars;
1309  for (const char * c = start; *c; c++) {
1310  if (*c == '/') start = c + 1;
1311  }
1312 
1313  krk_push(OBJECT_VAL(S("krk_module_onload_")));
1314  krk_push(OBJECT_VAL(krk_copyString(start,strlen(start))));
1315  krk_addObjects();
1316 
1317  char * handlerName = AS_CSTRING(krk_peek(0));
1318 
1319  KrkValue (*moduleOnLoad)(KrkString * name);
1320  krk_dlSymType out = krk_dlSym(dlRef, handlerName);
1321  memcpy(&moduleOnLoad,&out,sizeof(out));
1322 
1323  if (!moduleOnLoad) {
1324  krk_dlClose(dlRef);
1325  *moduleOut = NONE_VAL();
1326  krk_runtimeError(vm.exceptions->importError,
1327  "Failed to run module initialization method '%s' from shared object '%s'",
1328  handlerName, fileName);
1329  return 0;
1330  }
1331 
1332  krk_pop(); /* onload function */
1333 
1334  *moduleOut = moduleOnLoad(runAs);
1335  if (!krk_isInstanceOf(*moduleOut, vm.baseClasses->moduleClass)) {
1336  krk_dlClose(dlRef);
1337  krk_runtimeError(vm.exceptions->importError,
1338  "Failed to load module '%S' from '%s'", runAs, fileName);
1339  return 0;
1340  }
1341 
1342  krk_push(*moduleOut);
1343  krk_swap(1);
1344 
1345  struct KrkModule * moduleAsStruct = (struct KrkModule*)AS_INSTANCE(*moduleOut);
1346  moduleAsStruct->libHandle = dlRef;
1347 
1348  krk_attachNamedObject(&AS_INSTANCE(*moduleOut)->fields, "__name__", (KrkObj*)runAs);
1349  krk_attachNamedValue(&AS_INSTANCE(*moduleOut)->fields, "__file__", krk_peek(0));
1350 
1351  krk_pop(); /* filename */
1352  krk_tableSet(&vm.modules, OBJECT_VAL(runAs), *moduleOut);
1353  return 1;
1354 #endif
1355  }
1356 
1357 #endif
1358 
1359  /* If we still haven't found anything, fail. */
1360  *moduleOut = NONE_VAL();
1361 
1362  /* Was this a __main__? */
1363  if (runAs == S("__main__")) {
1364  /* Then let's use 'path' instead, and replace all the /'s with .'s... */
1365  krk_push(krk_valueGetAttribute(OBJECT_VAL(path), "replace"));
1366  krk_push(OBJECT_VAL(S(KRK_PATH_SEP)));
1367  krk_push(OBJECT_VAL(S(".")));
1368  krk_push(krk_callStack(2));
1369  } else {
1370  krk_push(OBJECT_VAL(runAs));
1371  }
1372 
1373  krk_runtimeError(vm.exceptions->importError, "No module named '%S'", AS_STRING(krk_peek(0)));
1374 
1375  return 0;
1376 }
1377 
1378 int krk_importModule(KrkString * name, KrkString * runAs) {
1379  /* See if 'name' is clear to directly import */
1380  int isClear = 1;
1381  for (size_t i = 0; i < name->length; ++i) {
1382  if (name->chars[i] == '.') {
1383  isClear = 0;
1384  break;
1385  }
1386  }
1387 
1388  if (isClear) {
1389  KrkValue base;
1390  return krk_loadModule(name,&base,runAs,NONE_VAL());
1391  }
1392 
1393  if (name->chars[0] == '.') {
1399  KrkValue packageName;
1400  if (!krk_tableGet_fast(&krk_currentThread.module->fields, S("__package__"), &packageName) || !IS_STRING(packageName)) {
1401  /* We must have __package__ set to a string for this to make any sense. */
1402  krk_runtimeError(vm.exceptions->importError, "attempted relative import without a package context");
1403  return 0;
1404  }
1405 
1406  if (name->length == 1) {
1407  /* from . import ... */
1408  return krk_importModule(AS_STRING(packageName), AS_STRING(packageName));
1409  }
1410 
1411  if (name->chars[1] != '.') {
1412  /* from .something import ... */
1413  krk_push(packageName);
1414  krk_push(OBJECT_VAL(name));
1415  krk_addObjects();
1416 
1417  if (krk_importModule(AS_STRING(krk_peek(0)), AS_STRING(krk_peek(0)))) {
1418  krk_swap(1); /* Imported module */
1419  krk_pop(); /* Name */
1420  return 1;
1421  }
1422 
1423  return 0;
1424  }
1425 
1434  size_t dots = 0;
1435  while (name->chars[dots+1] == '.') dots++;
1436 
1437  /* We'll split the package name is str.split(__package__,'.') */
1438  krk_push(packageName);
1439  krk_push(OBJECT_VAL(S(".")));
1440  KrkValue components = krk_string_split(2,(KrkValue[]){krk_peek(1),krk_peek(0)}, 0);
1441  if (!IS_list(components)) {
1442  krk_runtimeError(vm.exceptions->importError, "internal error while calculating package path");
1443  return 0;
1444  }
1445  krk_push(components);
1446  krk_swap(2);
1447  krk_pop();
1448  krk_pop();
1449 
1450  /* If there are not enough components to "go up" through, that's an error. */
1451  if (AS_LIST(components)->count <= dots) {
1452  krk_runtimeError(vm.exceptions->importError, "attempted relative import beyond top-level package");
1453  return 0;
1454  }
1455 
1456  size_t count = AS_LIST(components)->count - dots;
1457  struct StringBuilder sb = {0};
1458 
1459  /* Now rebuild the dotted form from the remaining components... */
1460  for (size_t i = 0; i < count; i++) {
1461  KrkValue node = AS_LIST(components)->values[i];
1462  if (!IS_STRING(node)) {
1463  discardStringBuilder(&sb);
1464  krk_runtimeError(vm.exceptions->importError, "internal error while calculating package path");
1465  return 0;
1466  }
1467  pushStringBuilderStr(&sb, AS_CSTRING(node), AS_STRING(node)->length);
1468  if (i + 1 != count) {
1469  pushStringBuilder(&sb, '.');
1470  }
1471  }
1472 
1473  krk_pop(); /* components */
1474 
1475  if (name->chars[dots+1]) {
1476  /* from ..something import ... - append '.something' */
1477  pushStringBuilderStr(&sb, &name->chars[dots], name->length - dots);
1478  }
1479 
1480  krk_push(finishStringBuilder(&sb));
1481 
1482  /* Now to try to import the fully qualified module path */
1483  if (krk_importModule(AS_STRING(krk_peek(0)), AS_STRING(krk_peek(0)))) {
1484  krk_swap(1); /* Imported module */
1485  krk_pop(); /* Name */
1486  return 1;
1487  }
1488  return 0;
1489  }
1490 
1498  /* Let's split up name */
1499  krk_push(NONE_VAL()); // -1: last
1501  krk_push(NONE_VAL()); // 0: Name of current node being processed.
1502  krk_push(OBJECT_VAL(S(""))); // 1: slash/separated/path
1503  krk_push(OBJECT_VAL(S(""))); // 2: dot.separated.path
1504  krk_push(OBJECT_VAL(name)); // 3: remaining path to process
1505  krk_push(OBJECT_VAL(S("."))); // 4: string "." to search for
1506  do {
1507  KrkValue listOut = krk_string_split(3,(KrkValue[]){krk_currentThread.stack[argBase+3], krk_currentThread.stack[argBase+4], INTEGER_VAL(1)}, 0);
1508  if (!IS_INSTANCE(listOut)) return 0;
1509 
1510  /* Set node */
1511  krk_currentThread.stack[argBase+0] = AS_LIST(listOut)->values[0];
1512 
1513  /* Set remainder */
1514  if (AS_LIST(listOut)->count > 1) {
1515  krk_currentThread.stack[argBase+3] = AS_LIST(listOut)->values[1];
1516  } else {
1517  krk_currentThread.stack[argBase+3] = NONE_VAL();
1518  }
1519 
1520  /* First is /-path */
1521  krk_push(krk_currentThread.stack[argBase+1]);
1522  krk_push(krk_currentThread.stack[argBase+0]);
1523  krk_addObjects();
1524  krk_currentThread.stack[argBase+1] = krk_pop();
1525  /* Second is .-path */
1526  krk_push(krk_currentThread.stack[argBase+2]);
1527  krk_push(krk_currentThread.stack[argBase+0]);
1528  krk_addObjects();
1529  krk_currentThread.stack[argBase+2] = krk_pop();
1530 
1531  if (IS_NONE(krk_currentThread.stack[argBase+3])) {
1532  krk_pop(); /* dot */
1533  krk_pop(); /* remainder */
1534  KrkValue current;
1535  if (!krk_loadModule(AS_STRING(krk_currentThread.stack[argBase+1]), &current, runAs, krk_currentThread.stack[argBase-1])) return 0;
1536  krk_pop(); /* dot-sepaerated */
1537  krk_pop(); /* slash-separated */
1538  krk_push(current);
1539  /* last must be something if we got here, because single-level import happens elsewhere */
1540  krk_tableSet(&AS_INSTANCE(krk_currentThread.stack[argBase-1])->fields, krk_currentThread.stack[argBase+0], krk_peek(0));
1542  krk_currentThread.stackTop[-1] = current;
1543  return 1;
1544  } else {
1545  KrkValue current;
1546  if (!krk_loadModule(AS_STRING(krk_currentThread.stack[argBase+1]), &current, AS_STRING(krk_currentThread.stack[argBase+2]),NONE_VAL())) return 0;
1547  krk_push(current);
1548  if (!IS_NONE(krk_currentThread.stack[argBase-1])) {
1549  krk_tableSet(&AS_INSTANCE(krk_currentThread.stack[argBase-1])->fields, krk_currentThread.stack[argBase+0], krk_peek(0));
1550  }
1551  /* Is this a package? */
1552  KrkValue tmp;
1553  if (!krk_tableGet_fast(&AS_INSTANCE(current)->fields, S("__ispackage__"), &tmp) || !IS_BOOLEAN(tmp) || AS_BOOLEAN(tmp) != 1) {
1554  krk_runtimeError(vm.exceptions->importError, "'%S' is not a package", AS_STRING(krk_currentThread.stack[argBase+2]));
1555  return 0;
1556  }
1557  krk_currentThread.stack[argBase-1] = krk_pop();
1558  /* Now concatenate forward slash... */
1559  krk_push(krk_currentThread.stack[argBase+1]); /* Slash path */
1560  krk_push(OBJECT_VAL(S(KRK_PATH_SEP)));
1561  krk_addObjects();
1562  krk_currentThread.stack[argBase+1] = krk_pop();
1563  /* And now for the dot... */
1564  krk_push(krk_currentThread.stack[argBase+2]);
1565  krk_push(krk_currentThread.stack[argBase+4]);
1566  krk_addObjects();
1567  krk_currentThread.stack[argBase+2] = krk_pop();
1568  }
1569  } while (1);
1570 }
1571 
1573  return krk_importModule(name,name);
1574 }
1575 
1576 #define CACHE_SIZE 4096
1577 typedef struct {
1578  KrkString * name;
1579  struct KrkClass * owner;
1580  KrkValue value;
1581  size_t index;
1583 static KrkClassCacheEntry cache[CACHE_SIZE] = {0};
1584 static size_t nextCount = 1;
1585 
1586 static KrkClass * checkCache(KrkClass * type, KrkString * name, KrkValue * method) {
1587  size_t index = (name->obj.hash ^ (type->obj.hash << 4)) & (CACHE_SIZE-1);
1588  KrkClassCacheEntry * entry = &cache[index];
1589  if (entry->name == name && entry->index == type->cacheIndex) {
1590  *method = entry->value;
1591  return entry->owner;
1592  }
1593 
1594  KrkClass * _class = NULL;
1595  if (krk_tableGet_fast(&type->methods, name, method)) {
1596  _class = type;
1597  } else if (type->base) {
1598  _class = checkCache(type->base, name, method);
1599  }
1600 
1601  if (!type->cacheIndex) {
1602  type->cacheIndex = nextCount++;
1603  }
1604  entry->name = name;
1605  entry->owner = _class;
1606  entry->value = *method;
1607  entry->index = type->cacheIndex;
1608  return _class;
1609 }
1610 
1611 static void clearCache(KrkClass * type) {
1612  if (type->cacheIndex) {
1613  type->cacheIndex = 0;
1614  for (size_t i = 0; i < type->subclasses.capacity; ++i) {
1615  KrkTableEntry * entry = &type->subclasses.entries[i];
1616  if (krk_valuesSame(entry->key, KWARGS_VAL(0))) continue;
1617  clearCache(AS_CLASS(entry->key));
1618  }
1619  }
1620 }
1621 
1626 int krk_bindMethodSuper(KrkClass * originalClass, KrkString * name, KrkClass * realClass) {
1627  KrkValue method, out;
1628  KrkClass * _class = checkCache(originalClass, name, &method);
1629  if (!_class) return 0;
1630  if (IS_NATIVE(method)||IS_CLOSURE(method)) {
1631  if (AS_OBJECT(method)->flags & KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD) {
1632  out = OBJECT_VAL(krk_newBoundMethod(OBJECT_VAL(realClass), AS_OBJECT(method)));
1633  } else if (IS_NONE(krk_peek(0)) || (AS_OBJECT(method)->flags & KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD)) {
1634  out = method;
1635  } else {
1636  out = OBJECT_VAL(krk_newBoundMethod(krk_peek(0), AS_OBJECT(method)));
1637  }
1638  } else {
1639  /* Does it have a descriptor __get__? */
1640  KrkClass * type = krk_getType(method);
1641  if (type->_descget) {
1642  krk_push(method);
1643  krk_swap(1);
1644  krk_push(OBJECT_VAL(realClass));
1645  krk_push(krk_callDirect(type->_descget, 3));
1646  return 1;
1647  }
1648  out = method;
1649  }
1650  krk_pop();
1651  krk_push(out);
1652  return 1;
1653 }
1654 
1655 int krk_bindMethod(KrkClass * originalClass, KrkString * name) {
1656  return krk_bindMethodSuper(originalClass,name,originalClass);
1657 }
1658 
1659 static int valueGetMethod(KrkString * name) {
1660  KrkValue this = krk_peek(0);
1661  KrkClass * myClass = krk_getType(this);
1662  KrkValue value, method;
1663  KrkClass * _class = checkCache(myClass, name, &method);
1664 
1665  /* Class descriptors */
1666  if (_class) {
1667  KrkClass * valtype = krk_getType(method);
1668  if (valtype->_descget && valtype->_descset) {
1669  krk_push(method);
1670  krk_push(this);
1671  krk_push(OBJECT_VAL(myClass));
1672  value = krk_callDirect(valtype->_descget, 3);
1673  goto found;
1674  }
1675  }
1676 
1677  /* Fields */
1678  if (IS_INSTANCE(this)) {
1679  if (krk_tableGet_fast(&AS_INSTANCE(this)->fields, name, &value)) goto found;
1680  } else if (IS_CLASS(this)) {
1681  KrkClass * type = AS_CLASS(this);
1682  do {
1683  if (krk_tableGet_fast(&type->methods, name, &value)) {
1684  if ((IS_NATIVE(value) || IS_CLOSURE(value)) && (AS_OBJECT(value)->flags & KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD)) {
1685  goto found_method;
1686  }
1687  KrkClass * valtype = krk_getType(value);
1688  if (valtype->_descget) {
1689  krk_push(value);
1690  krk_push(NONE_VAL());
1691  krk_push(this);
1692  value = krk_callDirect(valtype->_descget, 3);
1693  }
1694  goto found;
1695  }
1696  type = type->base;
1697  } while (type);
1698  } else if (IS_CLOSURE(this)) {
1699  if (krk_tableGet_fast(&AS_CLOSURE(this)->fields, name, &value)) goto found;
1700  }
1701 
1702  /* Method from type */
1703  if (_class) {
1704  if (IS_NATIVE(method)||IS_CLOSURE(method)) {
1705  if (AS_OBJECT(method)->flags & KRK_OBJ_FLAGS_FUNCTION_IS_CLASS_METHOD) {
1706  krk_currentThread.stackTop[-1] = OBJECT_VAL(myClass);
1707  value = method;
1708  goto found_method;
1709  } else if (AS_OBJECT(method)->flags & KRK_OBJ_FLAGS_FUNCTION_IS_STATIC_METHOD) {
1710  value = method;
1711  } else {
1712  value = method;
1713  goto found_method;
1714  }
1715  } else {
1716  KrkClass * valtype = krk_getType(method);
1717  if (valtype->_descget) {
1718  krk_push(method);
1719  krk_push(this);
1720  krk_push(OBJECT_VAL(myClass));
1721  value = krk_callDirect(valtype->_descget, 3);
1722  goto found;
1723  }
1724  value = method;
1725  }
1726  goto found;
1727  }
1728 
1729  /* __getattr__ */
1730  if (myClass->_getattr) {
1731  krk_push(this);
1732  krk_push(OBJECT_VAL(name));
1733  value = krk_callDirect(myClass->_getattr, 2);
1734  goto found;
1735  }
1736 
1737  return 0;
1738 
1739 found:
1740  krk_push(value);
1741  return 2;
1742 
1743 found_method:
1744  krk_push(value);
1745  return 1;
1746 }
1747 
1748 static int valueGetProperty(KrkString * name) {
1749  switch (valueGetMethod(name)) {
1750  case 2:
1753  return 1;
1754  case 1: {
1755  KrkValue o = OBJECT_VAL(krk_newBoundMethod(krk_currentThread.stackTop[-2], AS_OBJECT(krk_currentThread.stackTop[-1])));
1756  krk_currentThread.stackTop[-2] = o;
1758  return 1;
1759  }
1760  default:
1761  return 0;
1762  }
1763 }
1764 
1766  return valueGetProperty(name);
1767 }
1768 
1770  krk_push(OBJECT_VAL(krk_copyString(name,strlen(name))));
1771  krk_push(value);
1772  if (!valueGetProperty(AS_STRING(krk_peek(1)))) {
1773  return krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", krk_peek(0), name);
1774  }
1775  krk_swap(1);
1776  krk_pop(); /* String */
1777  return krk_pop();
1778 }
1779 
1781  krk_push(OBJECT_VAL(krk_copyString(name,strlen(name))));
1782  krk_push(value);
1783  if (!valueGetProperty(AS_STRING(krk_peek(1)))) {
1784  krk_pop();
1785  krk_pop();
1786  return defaultVal;
1787  }
1788  krk_swap(1);
1789  krk_pop(); /* String */
1790  return krk_pop();
1791 }
1792 
1793 static int valueDelProperty(KrkString * name) {
1794  if (IS_INSTANCE(krk_peek(0))) {
1795  KrkInstance* instance = AS_INSTANCE(krk_peek(0));
1796  if (!krk_tableDelete(&instance->fields, OBJECT_VAL(name))) {
1797  return 0;
1798  }
1799  krk_pop(); /* the original value */
1800  return 1;
1801  } else if (IS_CLASS(krk_peek(0))) {
1802  KrkClass * _class = AS_CLASS(krk_peek(0));
1803  if (!krk_tableDelete(&_class->methods, OBJECT_VAL(name))) {
1804  return 0;
1805  }
1806  if (name->length > 1 && name->chars[0] == '_' && name->chars[1] == '_') {
1808  } else {
1809  clearCache(_class);
1810  }
1811  krk_pop(); /* the original value */
1812  return 1;
1813  } else if (IS_CLOSURE(krk_peek(0))) {
1814  KrkClosure * closure = AS_CLOSURE(krk_peek(0));
1815  if (!krk_tableDelete(&closure->fields, OBJECT_VAL(name))) {
1816  return 0;
1817  }
1818  krk_pop();
1819  return 1;
1820  }
1821  /* TODO __delattr__? Descriptor __delete__ methods? */
1822  return 0;
1823 }
1824 
1826  return valueDelProperty(name);
1827 }
1828 
1830  krk_push(OBJECT_VAL(krk_copyString(name,strlen(name))));
1831  krk_push(owner);
1832  if (!valueDelProperty(AS_STRING(krk_peek(1)))) {
1833  return krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", krk_peek(0), name);
1834  }
1835  krk_pop(); /* String */
1836  return NONE_VAL();
1837 }
1838 
1839 static int _setDescriptor(KrkValue owner, KrkClass * _class, KrkString * name, KrkValue to) {
1840  KrkValue property;
1841  _class = checkCache(_class, name, &property);
1842  if (_class) {
1843  KrkClass * type = krk_getType(property);
1844  if (type->_descset) {
1845  krk_push(property);
1846  krk_push(owner);
1847  krk_push(to);
1848  krk_push(krk_callDirect(type->_descset, 3));
1849  return 1;
1850  }
1851  }
1852  return 0;
1853 }
1854 
1855 static KrkValue setAttr_wrapper(KrkValue owner, KrkClass * _class, KrkTable * fields, KrkString * name, KrkValue to) {
1856  if (_setDescriptor(owner,_class,name,to)) return krk_pop();
1857  krk_tableSet(fields, OBJECT_VAL(name), to);
1858  return to;
1859 }
1860 
1861 _noexport
1863  return setAttr_wrapper(owner, AS_INSTANCE(owner)->_class, &AS_INSTANCE(owner)->fields, name, to);
1864 }
1865 
1866 static int valueSetProperty(KrkString * name) {
1867  KrkValue owner = krk_peek(1);
1868  KrkValue value = krk_peek(0);
1869  KrkClass * type = krk_getType(owner);
1870  if (unlikely(type->_setattr != NULL)) {
1871  krk_push(OBJECT_VAL(name));
1872  krk_swap(1);
1873  krk_push(krk_callDirect(type->_setattr, 3));
1874  return 1;
1875  }
1876  if (IS_INSTANCE(owner)) {
1877  KrkValue o = setAttr_wrapper(owner,type,&AS_INSTANCE(owner)->fields, name, value);
1878  krk_currentThread.stackTop[-1] = o;
1879  } else if (IS_CLASS(owner)) {
1880  KrkValue o = setAttr_wrapper(owner,type,&AS_CLASS(owner)->methods, name, value);
1881  krk_currentThread.stackTop[-1] = o;
1882  if (name->length > 1 && name->chars[0] == '_' && name->chars[1] == '_') {
1883  krk_finalizeClass(AS_CLASS(owner));
1884  } else {
1885  clearCache(AS_CLASS(owner));
1886  }
1887  } else if (IS_CLOSURE(owner)) {
1888  KrkValue o = setAttr_wrapper(owner,type,&AS_CLOSURE(owner)->fields, name, value);
1889  krk_currentThread.stackTop[-1] = o;
1890  } else {
1891  if (_setDescriptor(owner,type,name,value)) {
1892  krk_swap(1);
1893  krk_pop();
1894  } else {
1895  return 0;
1896  }
1897  }
1898  krk_swap(1);
1899  krk_pop();
1900  return 1;
1901 }
1902 
1904  return valueSetProperty(name);
1905 }
1906 
1908  krk_push(OBJECT_VAL(krk_copyString(name,strlen(name))));
1909  krk_push(owner);
1910  krk_push(to);
1911  if (!valueSetProperty(AS_STRING(krk_peek(2)))) {
1912  return krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", krk_peek(1), name);
1913  }
1914  krk_swap(1);
1915  krk_pop(); /* String */
1916  return krk_pop();
1917 }
1918 
1919 #define BINARY_OP(op) { KrkValue b = krk_peek(0); KrkValue a = krk_peek(1); \
1920  a = krk_operator_ ## op (a,b); \
1921  krk_currentThread.stackTop[-2] = a; krk_pop(); break; }
1922 #define INPLACE_BINARY_OP(op) { KrkValue b = krk_peek(0); KrkValue a = krk_peek(1); \
1923  a = krk_operator_i ## op (a,b); \
1924  krk_currentThread.stackTop[-2] = a; krk_pop(); break; }
1925 
1926 extern KrkValue krk_int_op_add(krk_integer_type a, krk_integer_type b);
1927 extern KrkValue krk_int_op_sub(krk_integer_type a, krk_integer_type b);
1928 
1929 /* These operations are most likely to occur on integers, so we special case them */
1930 #define LIKELY_INT_BINARY_OP(op) { KrkValue b = krk_peek(0); KrkValue a = krk_peek(1); \
1931  if (likely(IS_INTEGER(a) && IS_INTEGER(b))) a = krk_int_op_ ## op (AS_INTEGER(a), AS_INTEGER(b)); \
1932  else a = krk_operator_ ## op (a,b); \
1933  krk_currentThread.stackTop[-2] = a; krk_pop(); break; }
1934 
1935 /* Comparators like these are almost definitely going to happen on integers. */
1936 #define LIKELY_INT_COMPARE_OP(op,operator) { KrkValue b = krk_peek(0); KrkValue a = krk_peek(1); \
1937  if (likely(IS_INTEGER(a) && IS_INTEGER(b))) a = BOOLEAN_VAL(AS_INTEGER(a) operator AS_INTEGER(b)); \
1938  else a = krk_operator_ ## op (a,b); \
1939  krk_currentThread.stackTop[-2] = a; krk_pop(); break; }
1940 
1941 #define LIKELY_INT_UNARY_OP(op,operator) { KrkValue a = krk_peek(0); \
1942  if (likely(IS_INTEGER(a))) a = INTEGER_VAL(operator AS_INTEGER(a)); \
1943  else a = krk_operator_ ## op (a); \
1944  krk_currentThread.stackTop[-1] = a; break; }
1945 
1946 #define READ_BYTE() (*frame->ip++)
1947 #define READ_CONSTANT(s) (frame->closure->function->chunk.constants.values[OPERAND])
1948 #define READ_STRING(s) AS_STRING(READ_CONSTANT(s))
1949 
1950 extern FUNC_SIG(list,append);
1951 extern FUNC_SIG(dict,__setitem__);
1952 extern FUNC_SIG(set,add);
1953 extern FUNC_SIG(list,extend);
1954 extern FUNC_SIG(dict,update);
1955 extern FUNC_SIG(set,update);
1956 
1957 struct ex_unpack {
1958  KrkTuple * output;
1959  unsigned char before;
1960  unsigned char after;
1961  KrkValue list;
1962  size_t total;
1963 };
1964 
1965 static int _unpack_ex(void * context, const KrkValue * values, size_t count) {
1966  struct ex_unpack * ctx = context;
1967 
1968  KrkTuple * output = ctx->output;
1969 
1970  for (size_t i = 0; i < count; ++i) {
1971  if (ctx->total < ctx->before) {
1972  output->values.values[output->values.count++] = values[i];
1973  } else if (ctx->total >= ctx->before) {
1974  if (ctx->total == ctx->before) {
1975  output->values.values[output->values.count++] = ctx->list;
1976  }
1977  FUNC_NAME(list,append)(2,(KrkValue[]){ctx->list,values[i]},0);
1978  }
1979  ctx->total++;
1980  }
1981 
1982  return 0;
1983 }
1984 
1985 
1986 static inline void makeCollection(NativeFn func, size_t count) {
1987  KrkValue collection = krk_callNativeOnStack(count, &krk_currentThread.stackTop[-count], 0, func);
1988  if (count) {
1989  krk_currentThread.stackTop[-count] = collection;
1990  while (count > 1) {
1991  krk_pop();
1992  count--;
1993  }
1994  } else {
1995  krk_push(collection);
1996  }
1997 }
1998 
1999 static inline int doFormatString(int options) {
2000  if (options & FORMAT_OP_FORMAT) {
2001  krk_swap(1);
2002  if (options & FORMAT_OP_EQ) {
2003  krk_swap(2);
2004  }
2005  } else if (options & FORMAT_OP_EQ) {
2006  krk_swap(1);
2007  }
2008 
2009  /* Was this a repr or str call? (it can't be both) */
2010  if (options & FORMAT_OP_STR) {
2011  KrkClass * type = krk_getType(krk_peek(0));
2012  if (likely(type->_tostr != NULL)) {
2013  krk_push(krk_callDirect(type->_tostr, 1));
2014  if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return 1;
2015  } else {
2016  krk_runtimeError(vm.exceptions->typeError,
2017  "Can not convert '%T' to str", krk_peek(0));
2018  return 1;
2019  }
2020  } else if (options & FORMAT_OP_REPR) {
2021  KrkClass * type = krk_getType(krk_peek(0));
2022  if (likely(type->_reprer != NULL)) {
2023  krk_push(krk_callDirect(type->_reprer, 1));
2024  if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return 1;
2025  } else {
2026  krk_runtimeError(vm.exceptions->typeError,
2027  "Can not repr '%T'", krk_peek(0));
2028  return 1;
2029  }
2030  }
2031 
2032  if (!(options & FORMAT_OP_FORMAT)) {
2033  /* Push empty string */
2034  krk_push(OBJECT_VAL(S("")));
2035  } else {
2036  /* Swap args so value is first */
2037  krk_swap(1);
2038  }
2039 
2040  /* Get the type of the value */
2041  KrkClass * type = krk_getType(krk_peek(1));
2042 
2043  if (likely(type->_format != NULL)) {
2044  krk_push(krk_callDirect(type->_format, 2));
2045  if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) return 1;
2046  } else {
2047  krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%s'", krk_peek(1), "__format__");
2048  return 1;
2049  }
2050 
2051  if (!IS_STRING(krk_peek(0))) {
2052  krk_runtimeError(vm.exceptions->typeError, "format result is not str");
2053  return 1;
2054  }
2055 
2056  return 0;
2057 }
2058 
2059 static inline void commonMethodInvoke(size_t methodOffset, int args, const char * msgFormat) {
2060  KrkClass * type = krk_getType(krk_peek(args-1));
2061  KrkObj * method = *(KrkObj**)((char*)type + methodOffset);
2062  if (likely(method != NULL)) {
2063  krk_push(krk_callDirect(method, args));
2064  } else {
2065  krk_runtimeError(vm.exceptions->attributeError, msgFormat, krk_peek(args-1));
2066  }
2067 }
2068 
2069 int krk_isSubClass(const KrkClass * cls, const KrkClass * base) {
2070  while (cls) {
2071  if (cls == base) return 1;
2072  cls = cls->base;
2073  }
2074  return 0;
2075 }
2076 
2080 static KrkValue run(void) {
2082 
2083  while (1) {
2084  if (unlikely(krk_currentThread.flags & (KRK_THREAD_ENABLE_TRACING | KRK_THREAD_SINGLE_STEP | KRK_THREAD_SIGNALLED))) {
2085 #if !defined(KRK_NO_TRACING) && !defined(KRK_DISABLE_DEBUG)
2086  if (krk_currentThread.flags & KRK_THREAD_ENABLE_TRACING) {
2087  krk_debug_dumpStack(stderr, frame);
2089  (size_t)(frame->ip - frame->closure->function->chunk.code));
2090  }
2091 #endif
2092 
2093 #ifndef KRK_DISABLE_DEBUG
2094  if (krk_currentThread.flags & KRK_THREAD_SINGLE_STEP) {
2095  krk_debuggerHook(frame);
2096  }
2097 #endif
2098 
2099  if (krk_currentThread.flags & KRK_THREAD_SIGNALLED) {
2100  krk_currentThread.flags &= ~(KRK_THREAD_SIGNALLED); /* Clear signal flag */
2101  krk_runtimeError(vm.exceptions->keyboardInterrupt, "Keyboard interrupt.");
2102  goto _finishException;
2103  }
2104  }
2105 #ifndef KRK_DISABLE_DEBUG
2106 _resumeHook: (void)0;
2107 #endif
2108 
2109  /* Each instruction begins with one opcode byte */
2110  KrkOpCode opcode = READ_BYTE();
2111  unsigned int OPERAND = 0;
2112 
2113 /* Only GCC lets us put these on empty statements; just hope clang doesn't start complaining */
2114 #if defined(__GNUC__) && !defined(__clang__)
2115 # define FALLTHROUGH __attribute__((fallthrough));
2116 #else
2117 # define FALLTHROUGH
2118 #endif
2119 
2120 #define TWO_BYTE_OPERAND { OPERAND = OPERAND | (frame->ip[0] << 8) | frame->ip[1]; frame->ip += 2; }
2121 #define THREE_BYTE_OPERAND { OPERAND = (frame->ip[0] << 16) | (frame->ip[1] << 8); frame->ip += 2; } FALLTHROUGH
2122 #define ONE_BYTE_OPERAND { OPERAND = (OPERAND & ~0xFF) | READ_BYTE(); }
2123 
2124 _switchEntry: (void)0;
2125  switch (opcode) {
2126  case OP_CLEANUP_WITH: {
2127  /* Top of stack is a HANDLER that should have had something loaded into it if it was still valid */
2128  KrkValue handler = krk_peek(0);
2129  KrkValue exceptionObject = krk_peek(1);
2130  KrkValue contextManager = krk_peek(2);
2131  KrkClass * type = krk_getType(contextManager);
2132  krk_push(contextManager);
2133  if (AS_HANDLER_TYPE(handler) == OP_RAISE) {
2134  krk_currentThread.stackTop[-2] = HANDLER_VAL(OP_CLEANUP_WITH,AS_HANDLER_TARGET(krk_peek(1)));
2135  krk_push(OBJECT_VAL(krk_getType(exceptionObject)));
2136  krk_push(exceptionObject);
2137  KrkValue tracebackEntries = NONE_VAL();
2138  if (IS_INSTANCE(exceptionObject))
2139  krk_tableGet_fast(&AS_INSTANCE(exceptionObject)->fields, S("traceback"), &tracebackEntries);
2140  krk_push(tracebackEntries);
2141  krk_callDirect(type->_exit, 4);
2142  /* Top of stack is now either someone else's problem or a return value */
2143  if (!(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
2144  krk_pop(); /* Handler object */
2145  krk_currentThread.currentException = krk_pop(); /* Original exception */
2146  krk_currentThread.flags |= KRK_THREAD_HAS_EXCEPTION;
2147  }
2148  goto _finishException;
2149  } else {
2150  krk_push(NONE_VAL());
2151  krk_push(NONE_VAL());
2152  krk_push(NONE_VAL());
2153  krk_callDirect(type->_exit, 4);
2154  if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) goto _finishException;
2155  }
2156  if (AS_HANDLER_TYPE(handler) == OP_EXIT_LOOP) {
2157  frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(handler);
2158  OPERAND = AS_INTEGER(krk_peek(1));
2159  goto _finishPopBlock;
2160  }
2161  if (AS_HANDLER_TYPE(handler) != OP_RETURN) break;
2162  krk_pop(); /* handler */
2163  } /* fallthrough */
2164  case OP_RETURN: {
2165 _finishReturn: (void)0;
2166  KrkValue result = krk_pop();
2167  /* See if this frame had a thing */
2168  int stackOffset;
2169  for (stackOffset = (int)(krk_currentThread.stackTop - krk_currentThread.stack - 1);
2170  stackOffset >= (int)frame->slots &&
2171  !IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset],OP_PUSH_TRY) &&
2172  !IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset],OP_PUSH_WITH) &&
2173  !IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset],OP_FILTER_EXCEPT)
2174  ; stackOffset--);
2175  if (stackOffset >= (int)frame->slots) {
2176  closeUpvalues(stackOffset);
2177  krk_currentThread.stackTop = &krk_currentThread.stack[stackOffset + 1];
2178  frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(krk_peek(0));
2179  krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_RETURN,AS_HANDLER_TARGET(krk_peek(0)));
2180  krk_currentThread.stackTop[-2] = result;
2181  break;
2182  }
2183  closeUpvalues(frame->slots);
2185  if (krk_currentThread.frameCount == 0) {
2186  krk_pop();
2187  return result;
2188  }
2191  if (frame->closure->function->obj.flags & (KRK_OBJ_FLAGS_CODEOBJECT_IS_GENERATOR | KRK_OBJ_FLAGS_CODEOBJECT_IS_COROUTINE)) {
2192  krk_push(result);
2193  return KWARGS_VAL(0);
2194  }
2195  return result;
2196  }
2197  krk_push(result);
2199  break;
2200  }
2201  case OP_LESS: LIKELY_INT_COMPARE_OP(lt,<)
2202  case OP_GREATER: LIKELY_INT_COMPARE_OP(gt,>)
2203  case OP_LESS_EQUAL: LIKELY_INT_COMPARE_OP(le,<=)
2204  case OP_GREATER_EQUAL: LIKELY_INT_COMPARE_OP(ge,>=)
2205  case OP_ADD: LIKELY_INT_BINARY_OP(add)
2206  case OP_SUBTRACT: LIKELY_INT_BINARY_OP(sub)
2207  case OP_MULTIPLY: BINARY_OP(mul)
2208  case OP_DIVIDE: BINARY_OP(truediv)
2209  case OP_FLOORDIV: BINARY_OP(floordiv)
2210  case OP_MODULO: BINARY_OP(mod)
2211  case OP_BITOR: BINARY_OP(or)
2212  case OP_BITXOR: BINARY_OP(xor)
2213  case OP_BITAND: BINARY_OP(and)
2214  case OP_SHIFTLEFT: BINARY_OP(lshift)
2215  case OP_SHIFTRIGHT: BINARY_OP(rshift)
2216  case OP_POW: BINARY_OP(pow)
2217  case OP_MATMUL: BINARY_OP(matmul)
2218  case OP_EQUAL: BINARY_OP(eq);
2219  case OP_IS: BINARY_OP(is);
2220  case OP_BITNEGATE: LIKELY_INT_UNARY_OP(invert,~)
2221  case OP_NEGATE: LIKELY_INT_UNARY_OP(neg,-)
2222  case OP_POS: LIKELY_INT_UNARY_OP(pos,+)
2223  case OP_NONE: krk_push(NONE_VAL()); break;
2224  case OP_TRUE: krk_push(BOOLEAN_VAL(1)); break;
2225  case OP_FALSE: krk_push(BOOLEAN_VAL(0)); break;
2226  case OP_UNSET: krk_push(KWARGS_VAL(0)); break;
2227  case OP_NOT: krk_push(BOOLEAN_VAL(krk_isFalsey(krk_peek(0)))); /* fallthrough */
2228  case OP_SWAP_POP: krk_swap(1); /* fallthrough */
2229  case OP_POP: krk_pop(); break;
2230 
2231  case OP_INPLACE_ADD: INPLACE_BINARY_OP(add)
2232  case OP_INPLACE_SUBTRACT: INPLACE_BINARY_OP(sub)
2233  case OP_INPLACE_MULTIPLY: INPLACE_BINARY_OP(mul)
2234  case OP_INPLACE_DIVIDE: INPLACE_BINARY_OP(truediv)
2235  case OP_INPLACE_FLOORDIV: INPLACE_BINARY_OP(floordiv)
2236  case OP_INPLACE_MODULO: INPLACE_BINARY_OP(mod)
2237  case OP_INPLACE_BITOR: INPLACE_BINARY_OP(or)
2238  case OP_INPLACE_BITXOR: INPLACE_BINARY_OP(xor)
2239  case OP_INPLACE_BITAND: INPLACE_BINARY_OP(and)
2240  case OP_INPLACE_SHIFTLEFT: INPLACE_BINARY_OP(lshift)
2241  case OP_INPLACE_SHIFTRIGHT: INPLACE_BINARY_OP(rshift)
2242  case OP_INPLACE_POW: INPLACE_BINARY_OP(pow)
2243  case OP_INPLACE_MATMUL: INPLACE_BINARY_OP(matmul)
2244 
2245  case OP_RAISE: {
2246  krk_raiseException(krk_peek(0), NONE_VAL());
2247  goto _finishException;
2248  }
2249  case OP_RAISE_FROM: {
2251  goto _finishException;
2252  }
2253  case OP_CLOSE_UPVALUE:
2254  closeUpvalues((krk_currentThread.stackTop - krk_currentThread.stack)-1);
2255  krk_pop();
2256  break;
2257  case OP_INVOKE_GETTER: {
2258  commonMethodInvoke(offsetof(KrkClass,_getter), 2, "'%T' object is not subscriptable");
2259  break;
2260  }
2261  case OP_INVOKE_SETTER: {
2262  commonMethodInvoke(offsetof(KrkClass,_setter), 3, "'%T' object doesn't support item assignment");
2263  break;
2264  }
2265  case OP_INVOKE_DELETE: {
2266  commonMethodInvoke(offsetof(KrkClass,_delitem), 2, "'%T' object doesn't support item deletion");
2267  krk_pop(); /* unused result */
2268  break;
2269  }
2270  case OP_INVOKE_ITER: {
2271  commonMethodInvoke(offsetof(KrkClass,_iter), 1, "'%T' object is not iterable");
2272  break;
2273  }
2274  case OP_INVOKE_CONTAINS: {
2275  krk_swap(1); /* operands are backwards */
2276  commonMethodInvoke(offsetof(KrkClass,_contains), 2, "'%T' object can not be tested for membership");
2277  break;
2278  }
2279  case OP_INVOKE_AWAIT: {
2280  if (!krk_getAwaitable()) goto _finishException;
2281  break;
2282  }
2283  case OP_SWAP:
2284  krk_swap(1);
2285  break;
2286  case OP_TRY_ELSE: {
2287  if (IS_HANDLER(krk_peek(0))) {
2288  krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_FILTER_EXCEPT,AS_HANDLER_TARGET(krk_peek(0)));
2289  }
2290  break;
2291  }
2292  case OP_BEGIN_FINALLY: {
2293  if (IS_HANDLER(krk_peek(0))) {
2294  switch (AS_HANDLER_TYPE(krk_peek(0))) {
2295  /* We either entered the @c finally without an exception, or the exception was handled by an @c except */
2296  case OP_PUSH_TRY:
2297  case OP_FILTER_EXCEPT:
2298  krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_BEGIN_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
2299  break;
2300  /* We entered the @c finally without handling an exception. */
2301  case OP_RAISE:
2302  krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_END_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
2303  break;
2304  }
2305  }
2306  break;
2307  }
2308  case OP_END_FINALLY: {
2309  KrkValue handler = krk_peek(0);
2310  if (IS_HANDLER(handler)) {
2311  if (AS_HANDLER_TYPE(handler) == OP_RAISE || AS_HANDLER_TYPE(handler) == OP_END_FINALLY) {
2312  krk_pop(); /* handler */
2314  krk_currentThread.flags |= KRK_THREAD_HAS_EXCEPTION;
2315  goto _finishException;
2316  } else if (AS_HANDLER_TYPE(handler) == OP_EXIT_LOOP) {
2317  frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(handler);
2318  OPERAND = AS_INTEGER(krk_peek(1));
2319  goto _finishPopBlock;
2320  } else if (AS_HANDLER_TYPE(handler) == OP_RETURN) {
2321  krk_push(krk_peek(1));
2322  goto _finishReturn;
2323  }
2324  }
2325  break;
2326  }
2327  case OP_BREAKPOINT: {
2328 #ifndef KRK_DISABLE_DEBUG
2329  /* First off, halt execution. */
2331  if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) goto _finishException;
2332  goto _resumeHook;
2333 #else
2334  krk_runtimeError(vm.exceptions->baseException, "Breakpoint.");
2335  goto _finishException;
2336 #endif
2337  }
2338  case OP_YIELD: {
2339  KrkValue result = krk_peek(0);
2342  /* Do NOT restore the stack */
2343  return result;
2344  }
2345  case OP_ANNOTATE: {
2346  if (IS_CLOSURE(krk_peek(0))) {
2347  krk_swap(1);
2348  AS_CLOSURE(krk_peek(1))->annotations = krk_peek(0);
2349  krk_pop();
2350  } else if (IS_NONE(krk_peek(0))) {
2351  krk_swap(1);
2352  krk_pop();
2353  } else {
2354  krk_runtimeError(vm.exceptions->typeError, "Can not annotate '%T'.", krk_peek(0));
2355  goto _finishException;
2356  }
2357  break;
2358  }
2359 
2360  case OP_LIST_APPEND_TOP: {
2361  KrkValue list = krk_peek(1);
2362  FUNC_NAME(list,append)(2,(KrkValue[]){list,krk_peek(0)},0);
2363  krk_pop();
2364  break;
2365  }
2366  case OP_DICT_SET_TOP: {
2367  KrkValue dict = krk_peek(2);
2368  FUNC_NAME(dict,__setitem__)(3,(KrkValue[]){dict,krk_peek(1),krk_peek(0)},0);
2369  krk_pop();
2370  krk_pop();
2371  break;
2372  }
2373  case OP_SET_ADD_TOP: {
2374  KrkValue set = krk_peek(1);
2375  FUNC_NAME(set,add)(2,(KrkValue[]){set,krk_peek(0)},0);
2376  krk_pop();
2377  break;
2378  }
2379 
2380  case OP_LIST_EXTEND_TOP: {
2381  KrkValue list = krk_peek(1);
2382  FUNC_NAME(list,extend)(2,(KrkValue[]){list,krk_peek(0)},0);
2383  krk_pop();
2384  break;
2385  }
2386  case OP_DICT_UPDATE_TOP: {
2387  KrkValue dict = krk_peek(1);
2388  FUNC_NAME(dict,update)(2,(KrkValue[]){dict,krk_peek(0)},0);
2389  krk_pop();
2390  break;
2391  }
2392  case OP_SET_UPDATE_TOP: {
2393  KrkValue set = krk_peek(1);
2394  FUNC_NAME(set,update)(2,(KrkValue[]){set,krk_peek(0)},0);
2395  krk_pop();
2396  break;
2397  }
2398 
2399  case OP_TUPLE_FROM_LIST: {
2400  KrkValue list = krk_peek(0);
2401  size_t count = AS_LIST(list)->count;
2402  KrkValue tuple = OBJECT_VAL(krk_newTuple(count));
2403  krk_push(tuple);
2404  for (size_t i = 0; i < count; ++i) {
2405  AS_TUPLE(tuple)->values.values[AS_TUPLE(tuple)->values.count++] = AS_LIST(list)->values[i];
2406  }
2407  krk_swap(1);
2408  krk_pop();
2409  break;
2410  }
2411 
2412  case OP_OVERLONG_JUMP: {
2413  /* Overlong jumps replace 2-byte operand jump instructions with a zero-operand instruction that
2414  * slowly scans through a dumb table to find the intended jump target and opcode. */
2415  for (size_t i = 0; i < frame->closure->function->overlongJumpsCount; ++i) {
2416  if (frame->closure->function->overlongJumps[i].instructionOffset ==
2417  (size_t)((char*)frame->ip - (char*)frame->closure->function->chunk.code)) {
2418  OPERAND = (int)frame->closure->function->overlongJumps[i].intendedTarget << 16;
2419  opcode = frame->closure->function->overlongJumps[i].originalOpcode;
2420  goto _switchEntry;
2421  }
2422  }
2423  krk_runtimeError(vm.exceptions->valueError, "bad jump");
2424  goto _finishException;
2425  }
2426 
2427  case OP_PUSH_BUILD_CLASS: {
2428  KrkValue build_class = NONE_VAL();
2429  krk_tableGet_fast(&vm.builtins->fields, AS_STRING(vm.specialMethodNames[METHOD_BLDCLS]), &build_class);
2430  krk_push(build_class);
2431  break;
2432  }
2433 
2434  /*
2435  * Two-byte operands
2436  */
2437  case OP_JUMP_IF_FALSE_OR_POP: {
2438  TWO_BYTE_OPERAND;
2439  if (krk_valuesSame(krk_peek(0), BOOLEAN_VAL(0)) || krk_isFalsey(krk_peek(0))) frame->ip += OPERAND;
2440  else krk_pop();
2441  break;
2442  }
2443  case OP_POP_JUMP_IF_FALSE: {
2444  TWO_BYTE_OPERAND;
2445  if (krk_valuesSame(krk_peek(0), BOOLEAN_VAL(0)) || krk_isFalsey(krk_peek(0))) frame->ip += OPERAND;
2446  krk_pop();
2447  break;
2448  }
2449  case OP_JUMP_IF_TRUE_OR_POP: {
2450  TWO_BYTE_OPERAND;
2451  if (!krk_isFalsey(krk_peek(0))) frame->ip += OPERAND;
2452  else krk_pop();
2453  break;
2454  }
2455  case OP_JUMP: {
2456  TWO_BYTE_OPERAND;
2457  frame->ip += OPERAND;
2458  break;
2459  }
2460  case OP_LOOP: {
2461  TWO_BYTE_OPERAND;
2462  frame->ip -= OPERAND;
2463  break;
2464  }
2465  case OP_PUSH_TRY: {
2466  TWO_BYTE_OPERAND;
2467  uint16_t tryTarget = OPERAND + (frame->ip - frame->closure->function->chunk.code);
2468  krk_push(NONE_VAL());
2469  KrkValue handler = HANDLER_VAL(OP_PUSH_TRY, tryTarget);
2470  krk_push(handler);
2471  break;
2472  }
2473  case OP_PUSH_WITH: {
2474  TWO_BYTE_OPERAND;
2475  uint16_t cleanupTarget = OPERAND + (frame->ip - frame->closure->function->chunk.code);
2476  KrkValue contextManager = krk_peek(0);
2477  KrkClass * type = krk_getType(contextManager);
2478  if (unlikely(!type->_enter || !type->_exit)) {
2479  if (!type->_enter) krk_runtimeError(vm.exceptions->attributeError, "__enter__");
2480  else if (!type->_exit) krk_runtimeError(vm.exceptions->attributeError, "__exit__");
2481  goto _finishException;
2482  }
2483  krk_push(contextManager);
2484  krk_callDirect(type->_enter, 1);
2485  /* Ignore result; don't need to pop */
2486  krk_push(NONE_VAL());
2487  KrkValue handler = HANDLER_VAL(OP_PUSH_WITH, cleanupTarget);
2488  krk_push(handler);
2489  break;
2490  }
2491  case OP_YIELD_FROM: {
2492  TWO_BYTE_OPERAND;
2493  uint8_t * exitIp = frame->ip + OPERAND;
2494  /* Stack has [iterator] [sent value] */
2495  /* Is this a generator or something with a 'send' method? */
2496  KrkValue method = krk_valueGetAttribute_default(krk_peek(1), "send", NONE_VAL());
2497  if (!IS_NONE(method)) {
2498  krk_push(method);
2499  krk_swap(1);
2500  krk_push(krk_callStack(1));
2501  } else {
2502  krk_pop();
2503  krk_push(krk_peek(0));
2504  krk_push(krk_callStack(0));
2505  }
2506  if (!krk_valuesSame(krk_peek(0), krk_peek(1))) {
2507  /* Value to yield */
2508  break;
2509  }
2510 
2511  krk_pop();
2512 
2513  /* Does it have a final value? */
2514  method = krk_valueGetAttribute_default(krk_peek(0), "__finish__", NONE_VAL());
2515  if (!IS_NONE(method)) {
2516  krk_push(method);
2517  krk_swap(1);
2518  krk_pop();
2519  krk_push(krk_callStack(0));
2520  } else {
2521  krk_pop();
2522  krk_push(NONE_VAL());
2523  }
2524  frame->ip = exitIp;
2525  break;
2526  }
2527  case OP_CALL_ITER: {
2528  TWO_BYTE_OPERAND;
2529  KrkValue iter = krk_peek(0);
2530  krk_push(iter);
2531  krk_push(krk_callStack(0));
2532  /* krk_valuesSame() */
2533  if (krk_valuesSame(iter, krk_peek(0))) frame->ip += OPERAND;
2534  break;
2535  }
2536  case OP_LOOP_ITER: {
2537  TWO_BYTE_OPERAND;
2538  KrkValue iter = krk_peek(0);
2539  krk_push(iter);
2540  krk_push(krk_callStack(0));
2541  if (!krk_valuesSame(iter, krk_peek(0))) frame->ip -= OPERAND;
2542  break;
2543  }
2544  case OP_TEST_ARG: {
2545  TWO_BYTE_OPERAND;
2546  if (!krk_valuesSame(krk_pop(), KWARGS_VAL(0))) frame->ip += OPERAND;
2547  break;
2548  }
2549  case OP_FILTER_EXCEPT: {
2550  TWO_BYTE_OPERAND;
2551  /* "Pop exception to match with and jump if not a match" */
2552  int isMatch = 0;
2553  if (IS_CLASS(krk_peek(0)) && krk_isInstanceOf(krk_peek(2), AS_CLASS(krk_peek(0)))) {
2554  isMatch = 1;
2555  } else if (IS_TUPLE(krk_peek(0))) {
2556  for (size_t i = 0; i < AS_TUPLE(krk_peek(0))->values.count; ++i) {
2557  if (IS_CLASS(AS_TUPLE(krk_peek(0))->values.values[i]) && krk_isInstanceOf(krk_peek(2), AS_CLASS(AS_TUPLE(krk_peek(0))->values.values[i]))) {
2558  isMatch = 1;
2559  break;
2560  }
2561  }
2562  } else if (IS_NONE(krk_peek(0))) {
2563  isMatch = !IS_NONE(krk_peek(2));
2564  }
2565  if (isMatch) {
2566  /* If exception matched, set handler state. */
2567  krk_currentThread.stackTop[-2] = HANDLER_VAL(OP_FILTER_EXCEPT,AS_HANDLER_TARGET(krk_peek(1)));
2568  } else {
2569  /* If exception did not match, jump to next 'except' or 'finally' */
2570  frame->ip += OPERAND;
2571  }
2572  krk_pop();
2573  break;
2574  }
2575  case OP_ENTER_EXCEPT: {
2576  TWO_BYTE_OPERAND;
2577  switch (AS_HANDLER_TYPE(krk_peek(0))) {
2578  case OP_RETURN:
2579  case OP_END_FINALLY:
2580  case OP_EXIT_LOOP:
2581  frame->ip += OPERAND;
2582  break;
2583  case OP_RAISE_FROM:
2584  /* Exception happened while in @c finally */
2585  krk_pop(); /* handler */
2587  krk_currentThread.flags |= KRK_THREAD_HAS_EXCEPTION;
2588  goto _finishException;
2589  }
2590  break;
2591  }
2592 
2593  case OP_CONSTANT_LONG:
2594  THREE_BYTE_OPERAND;
2595  case OP_CONSTANT: {
2596  ONE_BYTE_OPERAND;
2597  KrkValue constant = frame->closure->function->chunk.constants.values[OPERAND];
2598  krk_push(constant);
2599  break;
2600  }
2601  case OP_DEFINE_GLOBAL_LONG:
2602  THREE_BYTE_OPERAND;
2603  case OP_DEFINE_GLOBAL: {
2604  ONE_BYTE_OPERAND;
2605  KrkString * name = READ_STRING(OPERAND);
2606  krk_tableSet(frame->globals, OBJECT_VAL(name), krk_peek(0));
2607  krk_pop();
2608  break;
2609  }
2610  case OP_GET_GLOBAL_LONG:
2611  THREE_BYTE_OPERAND;
2612  case OP_GET_GLOBAL: {
2613  ONE_BYTE_OPERAND;
2614  KrkString * name = READ_STRING(OPERAND);
2615  KrkValue value;
2616  if (!krk_tableGet_fast(frame->globals, name, &value)) {
2617  if (!krk_tableGet_fast(&vm.builtins->fields, name, &value)) {
2618  krk_runtimeError(vm.exceptions->nameError, "Undefined variable '%S'.", name);
2619  goto _finishException;
2620  }
2621  }
2622  krk_push(value);
2623  break;
2624  }
2625  case OP_SET_GLOBAL_LONG:
2626  THREE_BYTE_OPERAND;
2627  case OP_SET_GLOBAL: {
2628  ONE_BYTE_OPERAND;
2629  KrkString * name = READ_STRING(OPERAND);
2630  if (!krk_tableSetIfExists(frame->globals, OBJECT_VAL(name), krk_peek(0))) {
2631  krk_runtimeError(vm.exceptions->nameError, "Undefined variable '%S'.", name);
2632  goto _finishException;
2633  }
2634  break;
2635  }
2636  case OP_DEL_GLOBAL_LONG:
2637  THREE_BYTE_OPERAND;
2638  case OP_DEL_GLOBAL: {
2639  ONE_BYTE_OPERAND;
2640  KrkString * name = READ_STRING(OPERAND);
2641  if (!krk_tableDelete(frame->globals, OBJECT_VAL(name))) {
2642  krk_runtimeError(vm.exceptions->nameError, "Undefined variable '%S'.", name);
2643  goto _finishException;
2644  }
2645  break;
2646  }
2647  case OP_IMPORT_LONG:
2648  THREE_BYTE_OPERAND;
2649  case OP_IMPORT: {
2650  ONE_BYTE_OPERAND;
2651  KrkString * name = READ_STRING(OPERAND);
2652  if (!krk_doRecursiveModuleLoad(name)) {
2653  goto _finishException;
2654  }
2655  break;
2656  }
2657  case OP_GET_LOCAL_LONG:
2658  THREE_BYTE_OPERAND;
2659  case OP_GET_LOCAL: {
2660  ONE_BYTE_OPERAND;
2661  krk_push(krk_currentThread.stack[frame->slots + OPERAND]);
2662  break;
2663  }
2664  case OP_SET_LOCAL_LONG:
2665  THREE_BYTE_OPERAND;
2666  case OP_SET_LOCAL: {
2667  ONE_BYTE_OPERAND;
2668  krk_currentThread.stack[frame->slots + OPERAND] = krk_peek(0);
2669  break;
2670  }
2671  case OP_SET_LOCAL_POP_LONG:
2672  THREE_BYTE_OPERAND;
2673  case OP_SET_LOCAL_POP: {
2674  ONE_BYTE_OPERAND;
2675  krk_currentThread.stack[frame->slots + OPERAND] = krk_pop();
2676  break;
2677  }
2678  case OP_CALL_LONG:
2679  THREE_BYTE_OPERAND;
2680  case OP_CALL: {
2681  ONE_BYTE_OPERAND;
2682  if (unlikely(!krk_callValue(krk_peek(OPERAND), OPERAND, 1))) goto _finishException;
2684  break;
2685  }
2686  case OP_CALL_METHOD_LONG:
2687  THREE_BYTE_OPERAND;
2688  case OP_CALL_METHOD: {
2689  ONE_BYTE_OPERAND;
2690  if (IS_NONE(krk_peek(OPERAND+1))) {
2691  if (unlikely(!krk_callValue(krk_peek(OPERAND), OPERAND, 2))) goto _finishException;
2692  } else {
2693  if (unlikely(!krk_callValue(krk_peek(OPERAND+1), OPERAND+1, 1))) goto _finishException;
2694  }
2696  break;
2697  }
2698  case OP_EXPAND_ARGS_LONG:
2699  THREE_BYTE_OPERAND;
2700  case OP_EXPAND_ARGS: {
2701  ONE_BYTE_OPERAND;
2702  krk_push(KWARGS_VAL(KWARGS_SINGLE-OPERAND));
2703  break;
2704  }
2705  case OP_CLOSURE_LONG:
2706  THREE_BYTE_OPERAND;
2707  case OP_CLOSURE: {
2708  ONE_BYTE_OPERAND;
2709  KrkCodeObject * function = AS_codeobject(READ_CONSTANT(OPERAND));
2710  KrkClosure * closure = krk_newClosure(function, frame->globalsOwner);
2711  krk_push(OBJECT_VAL(closure));
2712  for (size_t i = 0; i < closure->upvalueCount; ++i) {
2713  int isLocal = READ_BYTE();
2714  int index = READ_BYTE();
2715  if (isLocal & 2) {
2716  index = (index << 16) | (frame->ip[0] << 8) | (frame->ip[1]);
2717  frame->ip += 2;
2718  }
2719  if (isLocal & 1) {
2720  closure->upvalues[i] = captureUpvalue(frame->slots + index);
2721  } else if (isLocal & 4) {
2722  closure->upvalues[i] = krk_newUpvalue(0);
2723  closure->upvalues[i]->closed = NONE_VAL();
2724  closure->upvalues[i]->location = -1;
2725  } else {
2726  closure->upvalues[i] = frame->closure->upvalues[index];
2727  }
2728  }
2729  break;
2730  }
2731  case OP_GET_UPVALUE_LONG:
2732  THREE_BYTE_OPERAND;
2733  case OP_GET_UPVALUE: {
2734  ONE_BYTE_OPERAND;
2735  krk_push(*UPVALUE_LOCATION(frame->closure->upvalues[OPERAND]));
2736  break;
2737  }
2738  case OP_SET_UPVALUE_LONG:
2739  THREE_BYTE_OPERAND;
2740  case OP_SET_UPVALUE: {
2741  ONE_BYTE_OPERAND;
2742  *UPVALUE_LOCATION(frame->closure->upvalues[OPERAND]) = krk_peek(0);
2743  break;
2744  }
2745  case OP_IMPORT_FROM_LONG:
2746  THREE_BYTE_OPERAND;
2747  case OP_IMPORT_FROM: {
2748  ONE_BYTE_OPERAND;
2749  KrkString * name = READ_STRING(OPERAND);
2750  if (unlikely(!valueGetProperty(name))) {
2751  /* Try to import... */
2752  KrkValue moduleName;
2753  if (!krk_tableGet(&AS_INSTANCE(krk_peek(0))->fields, vm.specialMethodNames[METHOD_NAME], &moduleName)) {
2754  krk_runtimeError(vm.exceptions->importError, "Can not import '%S' from non-module '%T' object", name, krk_peek(0));
2755  goto _finishException;
2756  }
2757  krk_push(moduleName);
2758  krk_push(OBJECT_VAL(S(".")));
2759  krk_addObjects();
2760  krk_push(OBJECT_VAL(name));
2761  krk_addObjects();
2762  if (!krk_doRecursiveModuleLoad(AS_STRING(krk_peek(0)))) {
2763  krk_currentThread.flags &= ~KRK_THREAD_HAS_EXCEPTION;
2764  krk_runtimeError(vm.exceptions->importError, "Can not import '%S' from '%S'", name, AS_STRING(moduleName));
2765  goto _finishException;
2766  }
2769  }
2770  } break;
2771  case OP_GET_PROPERTY_LONG:
2772  THREE_BYTE_OPERAND;
2773  case OP_GET_PROPERTY: {
2774  ONE_BYTE_OPERAND;
2775  KrkString * name = READ_STRING(OPERAND);
2776  if (unlikely(!valueGetProperty(name))) {
2777  krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%S'", krk_peek(0), name);
2778  goto _finishException;
2779  }
2780  break;
2781  }
2782  case OP_DEL_PROPERTY_LONG:
2783  THREE_BYTE_OPERAND;
2784  case OP_DEL_PROPERTY: {
2785  ONE_BYTE_OPERAND;
2786  KrkString * name = READ_STRING(OPERAND);
2787  if (unlikely(!valueDelProperty(name))) {
2788  krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%S'", krk_peek(0), name);
2789  goto _finishException;
2790  }
2791  break;
2792  }
2793  case OP_SET_PROPERTY_LONG:
2794  THREE_BYTE_OPERAND;
2795  case OP_SET_PROPERTY: {
2796  ONE_BYTE_OPERAND;
2797  KrkString * name = READ_STRING(OPERAND);
2798  if (unlikely(!valueSetProperty(name))) {
2799  krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%S'", krk_peek(1), name);
2800  goto _finishException;
2801  }
2802  break;
2803  }
2804  case OP_SET_NAME_LONG:
2805  THREE_BYTE_OPERAND;
2806  case OP_SET_NAME: {
2807  ONE_BYTE_OPERAND;
2809  krk_swap(1);
2810  krk_push(OBJECT_VAL(READ_STRING(OPERAND)));
2811  krk_swap(1);
2812  commonMethodInvoke(offsetof(KrkClass,_setter), 3, "'%T' object doesn't support item assignment");
2813  break;
2814  }
2815  case OP_GET_NAME_LONG:
2816  THREE_BYTE_OPERAND;
2817  case OP_GET_NAME: {
2818  ONE_BYTE_OPERAND;
2820  krk_push(OBJECT_VAL(READ_STRING(OPERAND)));
2821  commonMethodInvoke(offsetof(KrkClass,_getter), 2, "'%T' object doesn't support item assignment");
2822  break;
2823  }
2824  case OP_GET_SUPER_LONG:
2825  THREE_BYTE_OPERAND;
2826  case OP_GET_SUPER: {
2827  ONE_BYTE_OPERAND;
2828  KrkString * name = READ_STRING(OPERAND);
2829  KrkValue baseClass = krk_peek(1);
2830  if (!IS_CLASS(baseClass)) {
2831  krk_runtimeError(vm.exceptions->typeError,
2832  "super() argument 1 must be class, not %T", baseClass);
2833  goto _finishException;
2834  }
2835  if (IS_KWARGS(krk_peek(0))) {
2836  krk_runtimeError(vm.exceptions->notImplementedError,
2837  "Unbound super() reference not supported");
2838  goto _finishException;
2839  }
2840 
2841  KrkClass * obj_type;
2842  KrkValue obj = krk_peek(0);
2843 
2844  if (IS_CLASS(obj) && krk_isSubClass(AS_CLASS(obj),AS_CLASS(baseClass))) {
2845  /* Class method call */
2846  obj_type = AS_CLASS(obj);
2847  krk_pop();
2848  krk_push(NONE_VAL());
2849  } else {
2850  obj_type = krk_getType(obj);
2851  if (!krk_isInstanceOf(krk_peek(0), AS_CLASS(baseClass))) {
2852  krk_runtimeError(vm.exceptions->typeError,
2853  "'%T' object is not an instance of '%S'",
2854  krk_peek(0), AS_CLASS(baseClass)->name);
2855  goto _finishException;
2856  }
2857  }
2858  KrkClass * superclass = AS_CLASS(baseClass)->base ? AS_CLASS(baseClass)->base : vm.baseClasses->objectClass;
2859  if (!krk_bindMethodSuper(superclass, name, obj_type)) {
2860  krk_runtimeError(vm.exceptions->attributeError, "'%S' object has no attribute '%S'",
2861  superclass->name, name);
2862  goto _finishException;
2863  }
2864  /* Swap bind and superclass */
2865  krk_swap(1);
2866  /* Pop super class */
2867  krk_pop();
2868  break;
2869  }
2870  case OP_GET_METHOD_LONG:
2871  THREE_BYTE_OPERAND;
2872  case OP_GET_METHOD: {
2873  ONE_BYTE_OPERAND;
2874  KrkString * name = READ_STRING(OPERAND);
2875  int result = valueGetMethod(name);
2876  if (result == 2) {
2877  krk_push(NONE_VAL());
2878  krk_swap(2);
2879  krk_pop();
2880  } else if (unlikely(!result)) {
2881  krk_runtimeError(vm.exceptions->attributeError, "'%T' object has no attribute '%S'", krk_peek(0), name);
2882  goto _finishException;
2883  } else {
2884  krk_swap(1); /* unbound-method object */
2885  }
2886  break;
2887  }
2888  case OP_DUP_LONG:
2889  THREE_BYTE_OPERAND;
2890  case OP_DUP:
2891  ONE_BYTE_OPERAND;
2892  krk_push(krk_peek(OPERAND));
2893  break;
2894  case OP_KWARGS_LONG:
2895  THREE_BYTE_OPERAND;
2896  case OP_KWARGS: {
2897  ONE_BYTE_OPERAND;
2898  krk_push(KWARGS_VAL(OPERAND));
2899  break;
2900  }
2901  case OP_CLOSE_MANY_LONG:
2902  THREE_BYTE_OPERAND;
2903  case OP_CLOSE_MANY: {
2904  ONE_BYTE_OPERAND;
2905  closeUpvalues((krk_currentThread.stackTop - krk_currentThread.stack) - OPERAND);
2906  for (unsigned int i = 0; i < OPERAND; ++i) {
2907  krk_pop();
2908  }
2909  break;
2910  }
2911 
2912  case OP_EXIT_LOOP_LONG:
2913  THREE_BYTE_OPERAND;
2914  case OP_EXIT_LOOP: {
2915  ONE_BYTE_OPERAND;
2916 _finishPopBlock: (void)0;
2917  int stackOffset;
2918  for (stackOffset = (int)(krk_currentThread.stackTop - krk_currentThread.stack - 1);
2919  stackOffset >= (int)(frame->slots + OPERAND) &&
2920  !IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset],OP_PUSH_TRY) &&
2921  !IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset],OP_PUSH_WITH) &&
2922  !IS_HANDLER_TYPE(krk_currentThread.stack[stackOffset],OP_FILTER_EXCEPT)
2923  ; stackOffset--) krk_pop();
2924 
2925  /* Do the handler. */
2926  if (stackOffset >= (int)(frame->slots + OPERAND)) {
2927  closeUpvalues(stackOffset);
2928  uint16_t popTarget = (frame->ip - frame->closure->function->chunk.code);
2929  krk_currentThread.stackTop = &krk_currentThread.stack[stackOffset + 1];
2930  frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(krk_peek(0));
2931  krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_EXIT_LOOP, popTarget);
2932  krk_currentThread.stackTop[-2] = INTEGER_VAL(OPERAND);
2933  } else {
2934  closeUpvalues(frame->slots + OPERAND);
2935  }
2936 
2937  /* Continue normally */
2938  break;
2939  }
2940 
2941  case OP_POP_MANY_LONG:
2942  THREE_BYTE_OPERAND;
2943  case OP_POP_MANY: {
2944  ONE_BYTE_OPERAND;
2945  for (unsigned int i = 0; i < OPERAND; ++i) {
2946  krk_pop();
2947  }
2948  break;
2949  }
2950  case OP_TUPLE_LONG:
2951  THREE_BYTE_OPERAND;
2952  case OP_TUPLE: {
2953  ONE_BYTE_OPERAND;
2954  makeCollection(krk_tuple_of, OPERAND);
2955  break;
2956  }
2957  case OP_MAKE_LIST_LONG:
2958  THREE_BYTE_OPERAND;
2959  case OP_MAKE_LIST: {
2960  ONE_BYTE_OPERAND;
2961  makeCollection(krk_list_of, OPERAND);
2962  break;
2963  }
2964  case OP_MAKE_DICT_LONG:
2965  THREE_BYTE_OPERAND;
2966  case OP_MAKE_DICT: {
2967  ONE_BYTE_OPERAND;
2968  makeCollection(krk_dict_of, OPERAND);
2969  break;
2970  }
2971  case OP_MAKE_SET_LONG:
2972  THREE_BYTE_OPERAND;
2973  case OP_MAKE_SET: {
2974  ONE_BYTE_OPERAND;
2975  makeCollection(krk_set_of, OPERAND);
2976  break;
2977  }
2978  case OP_SLICE_LONG:
2979  THREE_BYTE_OPERAND;
2980  case OP_SLICE: {
2981  ONE_BYTE_OPERAND;
2982  makeCollection(krk_slice_of, OPERAND);
2983  break;
2984  }
2985  case OP_LIST_APPEND_LONG:
2986  THREE_BYTE_OPERAND;
2987  case OP_LIST_APPEND: {
2988  ONE_BYTE_OPERAND;
2989  KrkValue list = krk_currentThread.stack[frame->slots + OPERAND];
2990  FUNC_NAME(list,append)(2,(KrkValue[]){list,krk_peek(0)},0);
2991  krk_pop();
2992  break;
2993  }
2994  case OP_DICT_SET_LONG:
2995  THREE_BYTE_OPERAND;
2996  case OP_DICT_SET: {
2997  ONE_BYTE_OPERAND;
2998  KrkValue dict = krk_currentThread.stack[frame->slots + OPERAND];
2999  FUNC_NAME(dict,__setitem__)(3,(KrkValue[]){dict,krk_peek(1),krk_peek(0)},0);
3000  krk_pop();
3001  krk_pop();
3002  break;
3003  }
3004  case OP_SET_ADD_LONG:
3005  THREE_BYTE_OPERAND;
3006  case OP_SET_ADD: {
3007  ONE_BYTE_OPERAND;
3008  KrkValue set = krk_currentThread.stack[frame->slots + OPERAND];
3009  FUNC_NAME(set,add)(2,(KrkValue[]){set,krk_peek(0)},0);
3010  krk_pop();
3011  break;
3012  }
3013  case OP_REVERSE_LONG:
3014  THREE_BYTE_OPERAND;
3015  case OP_REVERSE: {
3016  ONE_BYTE_OPERAND;
3017  krk_push(NONE_VAL()); /* Storage space */
3018  for (ssize_t i = 0; i < (ssize_t)OPERAND / 2; ++i) {
3020  krk_currentThread.stackTop[-i-2] = krk_currentThread.stackTop[-(OPERAND-i)-1];
3021  krk_currentThread.stackTop[-(OPERAND-i)-1] = krk_currentThread.stackTop[-1];
3022  }
3023  krk_pop();
3024  break;
3025  }
3026  case OP_UNPACK_LONG:
3027  THREE_BYTE_OPERAND;
3028  case OP_UNPACK: {
3029  ONE_BYTE_OPERAND;
3030  KrkValue sequence = krk_peek(0);
3031  KrkTuple * values = krk_newTuple(OPERAND);
3032  krk_push(OBJECT_VAL(values));
3033  if (unlikely(krk_unpackIterable(sequence, values, _unpack_op))) {
3034  goto _finishException;
3035  }
3036  if (unlikely(values->values.count != OPERAND)) {
3037  krk_runtimeError(vm.exceptions->valueError, "not enough values to unpack (expected %u, got %zu)", OPERAND, values->values.count);
3038  goto _finishException;
3039  }
3040  if (unlikely(OPERAND == 0)) {
3041  krk_pop();
3042  krk_pop();
3043  break;
3044  }
3045  /* We no longer need the sequence */
3046  krk_swap(1);
3047  krk_pop();
3048  for (size_t i = 1; i < values->values.count; ++i) {
3049  krk_push(values->values.values[i]);
3050  }
3051  krk_currentThread.stackTop[-(ssize_t)OPERAND] = values->values.values[0];
3052  break;
3053  }
3054 
3055  case OP_FORMAT_VALUE_LONG:
3056  THREE_BYTE_OPERAND;
3057  case OP_FORMAT_VALUE: {
3058  ONE_BYTE_OPERAND;
3059  if (doFormatString(OPERAND)) goto _finishException;
3060  break;
3061  }
3062 
3063  case OP_MAKE_STRING_LONG:
3064  THREE_BYTE_OPERAND;
3065  case OP_MAKE_STRING: {
3066  ONE_BYTE_OPERAND;
3067 
3068  struct StringBuilder sb = {0};
3069 
3070  for (ssize_t i = 0; i < (ssize_t)OPERAND; ++i) {
3071  KrkValue s = krk_currentThread.stackTop[-(ssize_t)OPERAND+i];
3072  if (unlikely(!IS_STRING(s))) {
3073  discardStringBuilder(&sb);
3074  krk_runtimeError(vm.exceptions->valueError, "'%T' is not a string", s);
3075  goto _finishException;
3076  }
3077  pushStringBuilderStr(&sb, (char*)AS_STRING(s)->chars, AS_STRING(s)->length);
3078  }
3079 
3080  for (ssize_t i = 0; i < (ssize_t)OPERAND; ++i) {
3081  krk_pop();
3082  }
3083 
3084  krk_push(finishStringBuilder(&sb));
3085  break;
3086  }
3087 
3088  case OP_MISSING_KW_LONG:
3089  THREE_BYTE_OPERAND;
3090  case OP_MISSING_KW: {
3091  ONE_BYTE_OPERAND;
3092  krk_runtimeError(vm.exceptions->typeError, "%s() missing required keyword-only argument: %R",
3093  frame->closure->function->name ? frame->closure->function->name->chars : "<unnamed>",
3094  frame->closure->function->keywordArgNames.values[OPERAND]);
3095  break;
3096  }
3097 
3098  case OP_UNPACK_EX_LONG:
3099  THREE_BYTE_OPERAND;
3100  case OP_UNPACK_EX: {
3101  ONE_BYTE_OPERAND;
3102  unsigned char before = OPERAND >> 8;
3103  unsigned char after = OPERAND;
3104 
3105  KrkValue sequence = krk_peek(0);
3106  KrkTuple * values = krk_newTuple(before + after + 1);
3107  krk_push(OBJECT_VAL(values));
3108  KrkValue list = krk_list_of(0,NULL,0);
3109  krk_push(list);
3110 
3111 
3112  struct ex_unpack _context = { values, before, after, list, 0 };
3113  if (unlikely(krk_unpackIterable(sequence, &_context, _unpack_ex))) {
3114  goto _finishException;
3115  }
3116 
3117  if (values->values.count < before) {
3118  krk_runtimeError(vm.exceptions->typeError, "not enough values to unpack (expected at least %u, got %zu)",
3119  before+after, values->values.count);
3120  goto _finishException;
3121  }
3122 
3123  if (values->values.count == before) {
3124  values->values.values[values->values.count++] = list;
3125  }
3126 
3127  if (AS_LIST(list)->count < after) {
3128  krk_runtimeError(vm.exceptions->typeError, "not enough values to unpack (expected at least %u, got %zu)",
3129  before+after, values->values.count - 1 + AS_LIST(list)->count);
3130  goto _finishException;
3131  }
3132 
3133  if (after) {
3134  size_t more = after;
3135  while (more) {
3136  values->values.values[before+more] = AS_LIST(list)->values[--AS_LIST(list)->count];
3137  more--;
3138  }
3139  values->values.count += after;
3140  }
3141 
3142  /* We no longer need the sequence */
3143  krk_pop(); /* list */
3144  krk_swap(1);
3145  krk_pop();
3146  for (size_t i = 1; i < values->values.count; ++i) {
3147  krk_push(values->values.values[i]);
3148  }
3149  krk_currentThread.stackTop[-(ssize_t)(before + after + 1)] = values->values.values[0];
3150  break;
3151  }
3152 
3153 
3154  default:
3155  __builtin_unreachable();
3156  }
3157  if (unlikely(krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) {
3158 _finishException:
3159  if (!handleException()) {
3160  if (!IS_NONE(krk_currentThread.stackTop[-2])) {
3162  }
3164  frame->ip = frame->closure->function->chunk.code + AS_HANDLER_TARGET(krk_peek(0));
3165  /* Stick the exception into the exception slot */
3166  switch (AS_HANDLER_TYPE(krk_currentThread.stackTop[-1])) {
3167  /* An exception happened while handling an exception */
3168  case OP_RAISE:
3169  case OP_FILTER_EXCEPT:
3170  krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_END_FINALLY,AS_HANDLER_TARGET(krk_peek(0)));
3171  break;
3172  /* An exception happened while already in the @c finally block from handling
3173  * another exception. Bail. */
3174  case OP_END_FINALLY:
3175  krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_RAISE_FROM,AS_HANDLER_TARGET(krk_peek(0)));
3176  break;
3177  /* First exception in this chain. */
3178  default:
3179  krk_currentThread.stackTop[-1] = HANDLER_VAL(OP_RAISE,AS_HANDLER_TARGET(krk_peek(0)));
3180  break;
3181  }
3183  krk_currentThread.currentException = NONE_VAL();
3184  } else {
3185  return NONE_VAL();
3186  }
3187  }
3188  }
3189 #undef BINARY_OP
3190 #undef READ_BYTE
3191 }
3192 
3202  size_t oldExit = krk_currentThread.exitOnFrame;
3204  KrkValue result = run();
3205  krk_currentThread.exitOnFrame = oldExit;
3206  return result;
3207 }
3208 
3209 KrkInstance * krk_startModule(const char * name) {
3210  KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass);
3211  krk_currentThread.module = module;
3212  krk_attachNamedObject(&vm.modules, name, (KrkObj*)module);
3213  krk_attachNamedObject(&module->fields, "__builtins__", (KrkObj*)vm.builtins);
3214  krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)krk_copyString(name,strlen(name)));
3215  krk_attachNamedValue(&module->fields, "__annotations__", krk_dict_of(0,NULL,0));
3216  return module;
3217 }
3218 
3219 KrkValue krk_interpret(const char * src, const char * fromFile) {
3220  KrkCodeObject * function = krk_compile(src, fromFile);
3221  if (!function) {
3222  if (!krk_currentThread.frameCount) handleException();
3223  return NONE_VAL();
3224  }
3225 
3226  krk_push(OBJECT_VAL(function));
3227  krk_attachNamedObject(&krk_currentThread.module->fields, "__file__", (KrkObj*)function->chunk.filename);
3228  KrkClosure * closure = krk_newClosure(function, OBJECT_VAL(krk_currentThread.module));
3229  krk_pop();
3230 
3231  krk_push(OBJECT_VAL(closure));
3232  return krk_callStack(0);
3233 }
3234 
3235 #ifndef KRK_NO_FILESYSTEM
3236 KrkValue krk_runfile(const char * fileName, const char * fromFile) {
3237  FILE * f = fopen(fileName,"r");
3238  if (!f) {
3239  fprintf(stderr, "%s: could not open file '%s': %s\n", "kuroko", fileName, strerror(errno));
3240  return INTEGER_VAL(errno);
3241  }
3242 
3243  fseek(f, 0, SEEK_END);
3244  size_t size = ftell(f);
3245  fseek(f, 0, SEEK_SET);
3246 
3247  char * buf = malloc(size+1);
3248  if (fread(buf, 1, size, f) == 0 && size != 0) {
3249  fprintf(stderr, "%s: could not read file '%s': %s\n", "kuroko", fileName, strerror(errno));
3250  return INTEGER_VAL(errno);
3251  }
3252  fclose(f);
3253  buf[size] = '\0';
3254 
3255  KrkValue result = krk_interpret(buf, fromFile);
3256  free(buf);
3257 
3258  return result;
3259 }
3260 
3261 #endif
KrkCodeObject * krk_compile(const char *src, const char *fileName)
Compile a source string to bytecode.
Definition: compiler.c:4129
Exported methods for the source compiler.
Functions for debugging bytecode execution.
int krk_debuggerHook(KrkCallFrame *frame)
Called by the VM on single step.
Definition: debug.c:597
void krk_debug_init(void)
Initialize debugger state. Call exactly once per VM.
Definition: debug.c:699
int krk_debugBreakpointHandler(void)
Called by the VM when a breakpoint is encountered.
Definition: debug.c:663
size_t krk_disassembleInstruction(FILE *f, KrkCodeObject *func, size_t offset)
Print a disassembly of a single opcode instruction.
Definition: debug.c:415
void krk_debug_dumpStack(FILE *f, KrkCallFrame *frame)
Print the elements on the stack.
Definition: debug.c:125
_noexport void _createAndBind_exceptions(void)
Bind native methods and classes for exceptions.
Definition: exceptions.c:184
void krk_attachInnerException(KrkValue innerException)
Attach an inner exception to the current exception object.
Definition: exceptions.c:423
void krk_raiseException(KrkValue base, KrkValue cause)
Raise an exception value.
Definition: exceptions.c:435
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Definition: exceptions.c:460
void krk_dumpTraceback(void)
If there is an active exception, print a traceback to stderr.
Definition: exceptions.c:366
Functions for dealing with garbage collection and memory allocation.
void krk_freeObjects(void)
Release all objects.
Definition: memory.c:277
int krk_getAwaitable(void)
Calls await
Definition: obj_gen.c:235
Struct definitions for core object types.
Internal header.
KrkSpecialMethods
Index numbers for always-available interned strings representing important method and member names.
Definition: private.h:38
Table of classes for built-in object types.
Definition: vm.h:97
Table of basic exception types.
Definition: vm.h:63
A function that has been attached to an object to serve as a method.
Definition: object.h:295
KrkBoundMethod * krk_newBoundMethod(KrkValue receiver, KrkObj *method)
Create a new bound method.
Definition: object.c:350
KrkValue receiver
Object to pass as implicit first argument.
Definition: object.h:297
KrkObj * method
Function to call.
Definition: object.h:298
Represents a managed call state in a VM thread.
Definition: vm.h:44
size_t slots
Definition: vm.h:47
KrkTable * globals
Definition: vm.h:49
size_t outSlots
Definition: vm.h:48
KrkValue globalsOwner
Definition: vm.h:50
KrkClosure * closure
Definition: vm.h:45
uint8_t * ip
Definition: vm.h:46
Type object.
Definition: object.h:215
KrkObj * _tostr
__str__ Called to produce a string from an instance
Definition: object.h:230
KrkObj * _descget
__get__ Called when a descriptor object is bound as a property
Definition: object.h:242
KrkClass * krk_newClass(KrkString *name, KrkClass *base)
Create a new class object.
Definition: object.c:324
KrkObj * _reprer
__repr__ Called to create a reproducible string representation of an instance
Definition: object.h:229
KrkString * name
Name of the class.
Definition: object.h:219
struct KrkClass * base
Pointer to base class implementation.
Definition: object.h:221
KrkObj * _eq
__eq__ Implementation for equality check (==)
Definition: object.h:233
KrkTable subclasses
Set of classes that subclass this class.
Definition: object.h:225
KrkObj * _call
__call__ Called when an instance is called like a function
Definition: object.h:231
KrkObj * _len
__len__ Generally called by len() but may be used to determine truthiness
Definition: object.h:234
KrkObj * _exit
__exit__ Called upon exit from a with block
Definition: object.h:236
KrkClass * krk_makeClass(KrkInstance *module, KrkClass **_class, const char *name, KrkClass *base)
Convenience function for creating new types.
Definition: vm.c:164
KrkObj * _getattr
__getattr__ Overrides normal behavior for attribute access
Definition: object.h:239
KrkObj * _enter
__enter__ Called upon entry into a with block
Definition: object.h:235
KrkObj * _descset
__set__ Called when a descriptor object is assigned to as a property
Definition: object.h:243
KrkTable methods
General attributes table.
Definition: object.h:218
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
Definition: vm.c:189
struct KrkClass * _class
Metaclass.
Definition: object.h:217
int krk_bindMethod(KrkClass *_class, KrkString *name)
Perform method binding on the stack.
Definition: vm.c:1655
KrkObj * _hash
__hash__ Called when an instance is a key in a dict or an entry in a set
Definition: object.h:245
int krk_bindMethodSuper(KrkClass *baseClass, KrkString *name, KrkClass *realClass)
Bind a method with super() semantics.
Definition: vm.c:1626
Function object.
Definition: object.h:195
KrkCodeObject * function
The codeobject containing the bytecode run when this function is called.
Definition: object.h:197
KrkValue globalsOwner
Owner of the globals table for this function.
Definition: object.h:202
size_t upvalueCount
Number of entries in upvalues.
Definition: object.h:199
KrkTable * globalsTable
Pointer to globals table with owner object.
Definition: object.h:203
KrkClosure * krk_newClosure(KrkCodeObject *function, KrkValue globals)
Create a new function object.
Definition: object.c:290
KrkUpvalue ** upvalues
Array of upvalues collected from the surrounding context when the closure was created.
Definition: object.h:198
KrkInstance * krk_buildGenerator(KrkClosure *function, KrkValue *arguments, size_t argCount)
Convert a function into a generator with the given arguments.
Definition: obj_gen.c:82
KrkTable fields
Object attributes table.
Definition: object.h:201
Code object.
Definition: object.h:163
unsigned short potentialPositionals
Precalculated positional arguments for complex argument processing.
Definition: object.h:167
size_t overlongJumpsCount
Number of entries in pessimal jump table.
Definition: object.h:185
KrkChunk chunk
Bytecode data.
Definition: object.h:170
KrkValueArray positionalArgNames
Array of names for positional arguments (and *args)
Definition: object.h:173
KrkLocalEntry * localNames
Stores the names of local variables used in the function, for debugging.
Definition: object.h:177
unsigned short keywordArgs
Arity of keyword (default) arguments.
Definition: object.h:166
KrkOverlongJump * overlongJumps
Pessimal overlong jump container.
Definition: object.h:183
unsigned short requiredArgs
Arity of required (non-default) arguments.
Definition: object.h:165
KrkObj obj
Base.
Definition: object.h:164
KrkValueArray keywordArgNames
Array of names for keyword-only arguments (and **kwargs)
Definition: object.h:174
KrkString * name
Name of the function.
Definition: object.h:171
unsigned short totalArguments
Total argument cells we can fill in complex argument processing.
Definition: object.h:168
KrkValue krk_dict_of(int argc, const KrkValue argv[], int hasKw)
Create a dict object.
Definition: obj_dict.c:19
An object of a class.
Definition: object.h:281
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
Definition: object.c:343
KrkTable fields
Attributes table.
Definition: object.h:284
KrkValue krk_list_of(int argc, const KrkValue argv[], int hasKw)
Create a list object.
Definition: obj_list.c:30
KrkString * name
Name of the local.
Definition: object.h:133
Representation of a loaded module.
Definition: object.h:385
Managed binding to a C function.
Definition: object.h:309
const char * name
Name to use when repring.
Definition: object.h:312
NativeFn function
C function pointer.
Definition: object.h:311
KrkNative * krk_newNative(NativeFn function, const char *name, int type)
Create a native function binding object.
Definition: object.c:281
The most basic object type.
Definition: object.h:41
uint32_t hash
Cached hash value for table keys.
Definition: object.h:44
uint16_t flags
General object flags, mostly related to garbage collection.
Definition: object.h:43
uint16_t type
Tag indicating core type.
Definition: object.h:42
uint16_t intendedTarget
High bytes of the intended target.
Definition: object.h:153
uint8_t originalOpcode
Original jump opcode to execute.
Definition: object.h:154
uint32_t instructionOffset
Instruction (operand offset) this jump target applies to.
Definition: object.h:152
KrkValue krk_slice_of(int argc, const KrkValue argv[], int hasKw)
Create a slice object.
Definition: obj_slice.c:14
Immutable sequence of Unicode codepoints.
Definition: object.h:93
KrkObj obj
Base.
Definition: object.h:94
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
Definition: object.c:224
char * chars
UTF8 canonical data.
Definition: object.h:97
size_t length
String length in bytes.
Definition: object.h:95
One (key,value) pair in a table.
Definition: table.h:20
Simple hash table of arbitrary keys to values.
Definition: table.h:28
void krk_initTable(KrkTable *table)
Initialize a hash table.
Definition: table.c:33
int krk_tableGet(KrkTable *table, KrkValue key, KrkValue *value)
Obtain the value associated with a key in a table.
Definition: table.c:211
int krk_tableDelete(KrkTable *table, KrkValue key)
Remove a key from a hash table.
Definition: table.c:238
int krk_tableSet(KrkTable *table, KrkValue key, KrkValue value)
Assign a value to a key in a table.
Definition: table.c:148
void krk_attachNamedObject(KrkTable *table, const char name[], KrkObj *obj)
Attach an object to an attribute table.
Definition: vm.c:808
KrkTableEntry * entries
Definition: table.h:32
KrkNative * krk_defineNative(KrkTable *table, const char *name, NativeFn function)
Attach a native C function to an attribute table.
Definition: vm.c:155
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Definition: vm.c:794
void krk_tableAddAll(KrkTable *from, KrkTable *to)
Add all key-value pairs from 'from' into 'to'.
Definition: table.c:202
void krk_freeTable(KrkTable *table)
Release resources associated with a hash table.
Definition: table.c:41
int krk_tableGet_fast(KrkTable *table, struct KrkString *str, KrkValue *value)
Obtain the value associated with a string key in a table.
Definition: table.c:219
size_t capacity
Definition: table.h:30
int krk_tableSetIfExists(KrkTable *table, KrkValue key, KrkValue value)
Update the value of a table entry only if it is found.
Definition: table.c:194
size_t used
Definition: table.h:31
Execution state of a VM thread.
Definition: vm.h:152
KrkValue currentException
Definition: vm.h:164
struct KrkThreadState * next
Definition: vm.h:153
size_t stackSize
Definition: vm.h:157
size_t frameCount
Definition: vm.h:156
KrkValue * stack
Definition: vm.h:158
unsigned int maximumCallDepth
Definition: vm.h:166
KrkValue * stackMax
Definition: vm.h:167
KrkUpvalue * openUpvalues
Definition: vm.h:160
KrkValue * stackTop
Definition: vm.h:159
ssize_t exitOnFrame
Definition: vm.h:161
KrkCallFrame * frames
Definition: vm.h:155
int flags
Definition: vm.h:165
KrkValue scratchSpace[KRK_THREAD_SCRATCH_SIZE]
Definition: vm.h:169
KrkInstance * module
Definition: vm.h:163
Immutable sequence of arbitrary values.
Definition: object.h:323
KrkValueArray values
Stores the length, capacity, and actual values of the tuple.
Definition: object.h:325
KrkValue krk_tuple_of(int argc, const KrkValue argv[], int hasKw)
Create a tuple object.
Definition: obj_tuple.c:40
KrkTuple * krk_newTuple(size_t length)
Create a new tuple.
Definition: object.c:357
Storage for values referenced from nested functions.
Definition: object.h:115
int location
Stack offset or -1 if closed.
Definition: object.h:117
KrkValue closed
Heap storage for closed value.
Definition: object.h:118
struct KrkUpvalue * next
Invasive linked list pointer to next upvalue.
Definition: object.h:119
KrkUpvalue * krk_newUpvalue(int slot)
Create an upvalue slot.
Definition: object.c:315
Global VM state.
Definition: vm.h:180
void krk_freeVM(void)
Release resources from the VM.
Definition: vm.c:953
void krk_initVM(int flags)
Initialize the VM at program startup.
Definition: vm.c:868
Flexible vector of stack references.
Definition: value.h:75
size_t capacity
Definition: value.h:76
KrkValue * values
Definition: value.h:78
void krk_writeValueArray(KrkValueArray *array, KrkValue value)
Add a value to a value array.
Definition: value.c:17
size_t count
Definition: value.h:77
Stack reference or primative value.
const char * krk_typeName(KrkValue value)
Get the name of the type of a value.
Definition: vm.c:984
int krk_callValue(KrkValue callee, int argCount, int callableOnStack)
Call a callable value in the current stack context.
Definition: vm.c:691
KrkValue krk_valueSetAttribute(KrkValue owner, char *name, KrkValue to)
Set a property of an object by name.
Definition: vm.c:1907
int krk_isInstanceOf(KrkValue obj, const KrkClass *type)
Determine if a class is an instance or subclass of a given type.
Definition: vm.c:282
int krk_valuesEqual(KrkValue a, KrkValue b)
Compare two values for equality.
Definition: value.c:106
KrkValue krk_valueDelAttribute(KrkValue owner, char *name)
Delete a property of an object by name.
Definition: vm.c:1829
KrkClass * krk_getType(KrkValue value)
Get the class representing a value.
Definition: vm.c:240
static int krk_valuesSame(KrkValue a, KrkValue b)
Compare two values by identity.
Definition: value.h:141
KrkValue krk_valueGetAttribute(KrkValue value, char *name)
Obtain a property of an object by name.
Definition: vm.c:1769
int krk_isFalsey(KrkValue value)
Determine the truth of a value.
Definition: vm.c:821
KrkValue krk_set_of(int argc, const KrkValue argv[], int hasKw)
Create a set object.
Definition: obj_set.c:343
Inline flexible string array.
Definition: util.h:162
Definition: vm.c:1957
Implementation of a generic hash table.
Utilities for creating native bindings.
int krk_unpackIterable(KrkValue iterable, void *context, int callback(void *, const KrkValue *, size_t))
Unpack an iterable.
Definition: builtins.c:387
Core API for the bytecode virtual machine.
krk_threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
KrkValue krk_runNext(void)
Continue VM execution until the next exit trigger.
Definition: vm.c:3201
int krk_getAttribute(KrkString *name)
Implementation of the GET_PROPERTY instruction.
Definition: vm.c:1765
int krk_importModule(KrkString *name, KrkString *runAs)
Load the dotted name name with the final element as runAs.
Definition: vm.c:1378
void krk_resetStack(void)
Reset the current thread's stack state to the top level.
Definition: vm.c:85
int krk_setAttribute(KrkString *name)
Implementation of the SET_PROPERTY instruction.
Definition: vm.c:1903
void krk_module_init_threading(void)
Initialize the built-in 'threading' module.
Definition: threads.c:207
KrkValue krk_callStack(int argCount)
Call a callable on the stack with argCount arguments.
Definition: vm.c:732
#define vm
Convenience macro for namespacing.
Definition: vm.h:257
int krk_doRecursiveModuleLoad(KrkString *name)
Load a module by a dotted name.
Definition: vm.c:1572
KrkVM krk_vm
Singleton instance of the shared VM state.
KrkThreadState * krk_getCurrentThread(void)
Get a pointer to the current thread state.
int krk_delAttribute(KrkString *name)
Implementation of the DEL_PROPERTY instruction.
Definition: vm.c:1825
KrkValue krk_callNativeOnStack(size_t argCount, const KrkValue *stackArgs, int hasKw, NativeFn native)
Call a native function using a reference to stack arguments safely.
Definition: vm.c:601
KrkValue krk_pop(void)
Pop the top of the stack.
Definition: vm.c:131
int krk_loadModule(KrkString *path, KrkValue *moduleOut, KrkString *runAs, KrkValue parent)
Load a module from a file with a specified name.
Definition: vm.c:1146
KrkValue krk_valueGetAttribute_default(KrkValue value, char *name, KrkValue defaultVal)
See krk_valueGetAttribute.
Definition: vm.c:1780
void krk_setMaximumRecursionDepth(size_t maxDepth)
Set the maximum recursion call depth.
Definition: vm.c:863
void krk_swap(int distance)
Swap the top of the stack of the value distance slots down.
Definition: vm.c:145
KrkValue krk_interpret(const char *src, const char *fromFile)
Compile and execute a source code input.
Definition: vm.c:3219
void krk_module_init_kuroko(void)
Initialize the built-in 'kuroko' module.
Definition: sys.c:227
KrkValue krk_runfile(const char *fileName, const char *fromFile)
Load and run a source file and return when execution completes.
Definition: vm.c:3236
void krk_addObjects(void)
Concatenate two strings.
Definition: obj_str.c:941
void krk_push(KrkValue value)
Push a stack value.
Definition: vm.c:118
KrkInstance * krk_startModule(const char *name)
Set up a new module object in the current thread.
Definition: vm.c:3209
KrkValue krk_callDirect(KrkObj *callable, int argCount)
Call a closure or native function with argCount arguments.
Definition: vm.c:740
KrkValue krk_instanceSetAttribute_wrapper(KrkValue owner, KrkString *name, KrkValue to)
Set an attribute of an instance object, bypassing __setattr__.
Definition: vm.c:1862
#define KRK_CALL_FRAMES_MAX
Maximum depth of the call stack in managed-code function calls.
Definition: vm.h:20
KrkValue krk_peek(int distance)
Peek down from the top of the stack.
Definition: vm.c:139