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