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