#ifndef wren_vm_h
#define wren_vm_h
#include "wren_common.h"
#include "wren_compiler.h"
#include "wren_value.h"
#include "wren_utils.h"
#define WREN_MAX_TEMP_ROOTS 8
typedef enum
{
#define OPCODE(name, _) CODE_##name,
#include "wren_opcodes.h"
#undef OPCODE
} Code;
struct WrenHandle
{
Value value;
WrenHandle* prev;
WrenHandle* next;
};
struct WrenVM
{
ObjClass* boolClass;
ObjClass* classClass;
ObjClass* fiberClass;
ObjClass* fnClass;
ObjClass* listClass;
ObjClass* mapClass;
ObjClass* nullClass;
ObjClass* numClass;
ObjClass* objectClass;
ObjClass* rangeClass;
ObjClass* stringClass;
ObjFiber* fiber;
ObjMap* modules;
ObjModule* lastModule;
size_t bytesAllocated;
size_t nextGC;
Obj* first;
Obj** gray;
int grayCount;
int grayCapacity;
Obj* tempRoots[WREN_MAX_TEMP_ROOTS];
int numTempRoots;
WrenHandle* handles;
Value* apiStack;
WrenConfiguration config;
Compiler* compiler;
SymbolTable methodNames;
};
void* wrenReallocate(WrenVM* vm, void* memory, size_t oldSize, size_t newSize);
void wrenFinalizeForeign(WrenVM* vm, ObjForeign* foreign);
WrenHandle* wrenMakeHandle(WrenVM* vm, Value value);
ObjClosure* wrenCompileSource(WrenVM* vm, const char* module,
const char* source, bool isExpression,
bool printErrors);
Value wrenGetModuleVariable(WrenVM* vm, Value moduleName, Value variableName);
Value wrenFindVariable(WrenVM* vm, ObjModule* module, const char* name);
int wrenDeclareVariable(WrenVM* vm, ObjModule* module, const char* name,
size_t length, int line);
int wrenDefineVariable(WrenVM* vm, ObjModule* module, const char* name,
size_t length, Value value, int* line);
static inline void wrenCallFunction(WrenVM* vm, ObjFiber* fiber,
ObjClosure* closure, int numArgs)
{
if (fiber->numFrames + 1 > fiber->frameCapacity)
{
int max = fiber->frameCapacity * 2;
fiber->frames = (CallFrame*)wrenReallocate(vm, fiber->frames,
sizeof(CallFrame) * fiber->frameCapacity, sizeof(CallFrame) * max);
fiber->frameCapacity = max;
}
int stackSize = (int)(fiber->stackTop - fiber->stack);
int needed = stackSize + closure->fn->maxSlots;
wrenEnsureStack(vm, fiber, needed);
wrenAppendCallFrame(vm, fiber, closure, fiber->stackTop - numArgs);
}
void wrenPushRoot(WrenVM* vm, Obj* obj);
void wrenPopRoot(WrenVM* vm);
static inline ObjClass* wrenGetClassInline(WrenVM* vm, Value value)
{
if (IS_NUM(value)) return vm->numClass;
if (IS_OBJ(value)) return AS_OBJ(value)->classObj;
#if WREN_NAN_TAGGING
switch (GET_TAG(value))
{
case TAG_FALSE: return vm->boolClass; break;
case TAG_NAN: return vm->numClass; break;
case TAG_NULL: return vm->nullClass; break;
case TAG_TRUE: return vm->boolClass; break;
case TAG_UNDEFINED: UNREACHABLE();
}
#else
switch (value.type)
{
case VAL_FALSE: return vm->boolClass;
case VAL_NULL: return vm->nullClass;
case VAL_NUM: return vm->numClass;
case VAL_TRUE: return vm->boolClass;
case VAL_OBJ: return AS_OBJ(value)->classObj;
case VAL_UNDEFINED: UNREACHABLE();
}
#endif
UNREACHABLE();
return NULL;
}
static inline bool wrenIsLocalName(const char* name)
{
return name[0] >= 'a' && name[0] <= 'z';
}
static inline bool wrenIsFalsyValue(Value value)
{
return IS_FALSE(value) || IS_NULL(value);
}
#endif