mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-12 06:38:45 +01:00
Make fibers real objects.
This commit is contained in:
@ -35,7 +35,7 @@
|
||||
|
||||
// Defines a fiber native method whose C function name is [native].
|
||||
#define DEF_FIBER_NATIVE(native) \
|
||||
static void native_##native(WrenVM* vm, Fiber* fiber, Value* args)
|
||||
static void native_##native(WrenVM* vm, ObjFiber* fiber, Value* args)
|
||||
|
||||
// TODO: Tune these.
|
||||
// The initial (and minimum) capacity of a non-empty list object.
|
||||
@ -163,6 +163,7 @@ DEF_NATIVE(list_clear)
|
||||
{
|
||||
ObjList* list = AS_LIST(args[0]);
|
||||
wrenReallocate(vm, list->elements, 0, 0);
|
||||
list->elements = NULL;
|
||||
list->capacity = 0;
|
||||
list->count = 0;
|
||||
return NULL_VAL;
|
||||
@ -276,56 +277,57 @@ DEF_NATIVE(num_negate)
|
||||
|
||||
DEF_NATIVE(num_minus)
|
||||
{
|
||||
if (!IS_NUM(args[1])) return vm->unsupported;
|
||||
// TODO: Handle unsupported operand types better.
|
||||
if (!IS_NUM(args[1])) return NULL_VAL;
|
||||
return NUM_VAL(AS_NUM(args[0]) - AS_NUM(args[1]));
|
||||
}
|
||||
|
||||
DEF_NATIVE(num_plus)
|
||||
{
|
||||
if (!IS_NUM(args[1])) return vm->unsupported;
|
||||
if (!IS_NUM(args[1])) return NULL_VAL;
|
||||
// TODO: Handle coercion to string if RHS is a string.
|
||||
return NUM_VAL(AS_NUM(args[0]) + AS_NUM(args[1]));
|
||||
}
|
||||
|
||||
DEF_NATIVE(num_multiply)
|
||||
{
|
||||
if (!IS_NUM(args[1])) return vm->unsupported;
|
||||
if (!IS_NUM(args[1])) return NULL_VAL;
|
||||
return NUM_VAL(AS_NUM(args[0]) * AS_NUM(args[1]));
|
||||
}
|
||||
|
||||
DEF_NATIVE(num_divide)
|
||||
{
|
||||
if (!IS_NUM(args[1])) return vm->unsupported;
|
||||
if (!IS_NUM(args[1])) return NULL_VAL;
|
||||
return NUM_VAL(AS_NUM(args[0]) / AS_NUM(args[1]));
|
||||
}
|
||||
|
||||
DEF_NATIVE(num_mod)
|
||||
{
|
||||
if (!IS_NUM(args[1])) return vm->unsupported;
|
||||
if (!IS_NUM(args[1])) return NULL_VAL;
|
||||
return NUM_VAL(fmod(AS_NUM(args[0]), AS_NUM(args[1])));
|
||||
}
|
||||
|
||||
DEF_NATIVE(num_lt)
|
||||
{
|
||||
if (!IS_NUM(args[1])) return vm->unsupported;
|
||||
if (!IS_NUM(args[1])) return NULL_VAL;
|
||||
return BOOL_VAL(AS_NUM(args[0]) < AS_NUM(args[1]));
|
||||
}
|
||||
|
||||
DEF_NATIVE(num_gt)
|
||||
{
|
||||
if (!IS_NUM(args[1])) return vm->unsupported;
|
||||
if (!IS_NUM(args[1])) return NULL_VAL;
|
||||
return BOOL_VAL(AS_NUM(args[0]) > AS_NUM(args[1]));
|
||||
}
|
||||
|
||||
DEF_NATIVE(num_lte)
|
||||
{
|
||||
if (!IS_NUM(args[1])) return vm->unsupported;
|
||||
if (!IS_NUM(args[1])) return NULL_VAL;
|
||||
return BOOL_VAL(AS_NUM(args[0]) <= AS_NUM(args[1]));
|
||||
}
|
||||
|
||||
DEF_NATIVE(num_gte)
|
||||
{
|
||||
if (!IS_NUM(args[1])) return vm->unsupported;
|
||||
if (!IS_NUM(args[1])) return NULL_VAL;
|
||||
return BOOL_VAL(AS_NUM(args[0]) >= AS_NUM(args[1]));
|
||||
}
|
||||
|
||||
@ -400,7 +402,7 @@ DEF_NATIVE(string_toString)
|
||||
|
||||
DEF_NATIVE(string_plus)
|
||||
{
|
||||
if (!IS_STRING(args[1])) return vm->unsupported;
|
||||
if (!IS_STRING(args[1])) return NULL_VAL;
|
||||
// TODO: Handle coercion to string of RHS.
|
||||
|
||||
const char* left = AS_CSTRING(args[0]);
|
||||
@ -536,6 +538,8 @@ void wrenInitializeCore(WrenVM* vm)
|
||||
NATIVE(vm->boolClass, "toString", bool_toString);
|
||||
NATIVE(vm->boolClass, "!", bool_not);
|
||||
|
||||
vm->fiberClass = defineClass(vm, "Fiber");
|
||||
|
||||
vm->fnClass = defineClass(vm, "Function");
|
||||
FIBER_NATIVE(vm->fnClass, "call", fn_call0);
|
||||
FIBER_NATIVE(vm->fnClass, "call ", fn_call1);
|
||||
@ -590,10 +594,6 @@ void wrenInitializeCore(WrenVM* vm)
|
||||
ObjClass* osClass = defineClass(vm, "OS");
|
||||
NATIVE(osClass->metaclass, "clock", os_clock);
|
||||
|
||||
// TODO: Make this a distinct object type.
|
||||
ObjClass* unsupportedClass = wrenNewClass(vm, vm->objectClass, 0);
|
||||
vm->unsupported = (Value)wrenNewInstance(vm, unsupportedClass);
|
||||
|
||||
wrenInterpret(vm, coreLibSource);
|
||||
|
||||
vm->listClass = AS_CLASS(findGlobal(vm, "List"));
|
||||
|
||||
@ -299,7 +299,7 @@ void wrenDebugDumpCode(WrenVM* vm, ObjFn* fn)
|
||||
}
|
||||
}
|
||||
|
||||
void wrenDebugDumpStack(Fiber* fiber)
|
||||
void wrenDebugDumpStack(ObjFiber* fiber)
|
||||
{
|
||||
printf(":: ");
|
||||
for (int i = 0; i < fiber->stackSize; i++)
|
||||
|
||||
@ -14,6 +14,6 @@
|
||||
|
||||
int wrenDebugDumpInstruction(WrenVM* vm, ObjFn* fn, int i);
|
||||
void wrenDebugDumpCode(WrenVM* vm, ObjFn* fn);
|
||||
void wrenDebugDumpStack(Fiber* fiber);
|
||||
void wrenDebugDumpStack(ObjFiber* fiber);
|
||||
|
||||
#endif
|
||||
|
||||
@ -57,6 +57,10 @@ ObjClass* wrenNewClass(WrenVM* vm, ObjClass* superclass, int numFields)
|
||||
ObjClass* metaclass = wrenNewSingleClass(vm, 0);
|
||||
metaclass->metaclass = vm->classClass;
|
||||
|
||||
// Make sure the metaclass isn't collected when we allocate the class.
|
||||
PinnedObj pinned;
|
||||
pinObj(vm, (Obj*)metaclass, &pinned);
|
||||
|
||||
// The metaclass inheritance chain mirrors the class's inheritance chain
|
||||
// except that when the latter bottoms out at "Object", the metaclass one
|
||||
// bottoms out at "Class".
|
||||
@ -69,10 +73,6 @@ ObjClass* wrenNewClass(WrenVM* vm, ObjClass* superclass, int numFields)
|
||||
wrenBindSuperclass(metaclass, superclass->metaclass);
|
||||
}
|
||||
|
||||
// Make sure it isn't collected when we allocate the metaclass.
|
||||
PinnedObj pinned;
|
||||
pinObj(vm, (Obj*)metaclass, &pinned);
|
||||
|
||||
ObjClass* classObj = wrenNewSingleClass(vm, numFields);
|
||||
classObj->metaclass = metaclass;
|
||||
wrenBindSuperclass(classObj, superclass);
|
||||
@ -97,6 +97,18 @@ ObjClosure* wrenNewClosure(WrenVM* vm, ObjFn* fn)
|
||||
return closure;
|
||||
}
|
||||
|
||||
ObjFiber* wrenNewFiber(WrenVM* vm)
|
||||
{
|
||||
ObjFiber* fiber = allocate(vm, sizeof(ObjFiber));
|
||||
initObj(vm, &fiber->obj, OBJ_FIBER);
|
||||
|
||||
fiber->stackSize = 0;
|
||||
fiber->numFrames = 0;
|
||||
fiber->openUpvalues = NULL;
|
||||
|
||||
return fiber;
|
||||
}
|
||||
|
||||
ObjFn* wrenNewFunction(WrenVM* vm)
|
||||
{
|
||||
// Allocate these before the function in case they trigger a GC which would
|
||||
@ -190,6 +202,7 @@ static ObjClass* getObjectClass(WrenVM* vm, Obj* obj)
|
||||
return classObj->metaclass;
|
||||
}
|
||||
case OBJ_CLOSURE: return vm->fnClass;
|
||||
case OBJ_FIBER: return vm->fiberClass;
|
||||
case OBJ_FN: return vm->fnClass;
|
||||
case OBJ_INSTANCE: return ((ObjInstance*)obj)->classObj;
|
||||
case OBJ_LIST: return vm->listClass;
|
||||
@ -260,6 +273,7 @@ static void printObject(Obj* obj)
|
||||
{
|
||||
case OBJ_CLASS: printf("[class %p]", obj); break;
|
||||
case OBJ_CLOSURE: printf("[closure %p]", obj); break;
|
||||
case OBJ_FIBER: printf("[fiber %p]", obj); break;
|
||||
case OBJ_FN: printf("[fn %p]", obj); break;
|
||||
case OBJ_INSTANCE: printf("[instance %p]", obj); break;
|
||||
case OBJ_LIST: printList((ObjList*)obj); break;
|
||||
@ -320,6 +334,11 @@ bool wrenIsClosure(Value value)
|
||||
return IS_OBJ(value) && AS_OBJ(value)->type == OBJ_CLOSURE;
|
||||
}
|
||||
|
||||
bool wrenIsFiber(Value value)
|
||||
{
|
||||
return IS_OBJ(value) && AS_OBJ(value)->type == OBJ_FIBER;
|
||||
}
|
||||
|
||||
bool wrenIsFn(Value value)
|
||||
{
|
||||
return IS_OBJ(value) && AS_OBJ(value)->type == OBJ_FN;
|
||||
|
||||
@ -37,6 +37,10 @@
|
||||
// and have growable symbol tables.)
|
||||
#define MAX_SYMBOLS 256
|
||||
|
||||
// TODO: Make these externally controllable.
|
||||
#define STACK_SIZE 1024
|
||||
#define MAX_CALL_FRAMES 256
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VAL_FALSE,
|
||||
@ -49,6 +53,7 @@ typedef enum
|
||||
typedef enum {
|
||||
OBJ_CLASS,
|
||||
OBJ_CLOSURE,
|
||||
OBJ_FIBER,
|
||||
OBJ_FN,
|
||||
OBJ_INSTANCE,
|
||||
OBJ_LIST,
|
||||
@ -90,26 +95,6 @@ typedef struct
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct sFiber Fiber;
|
||||
|
||||
typedef Value (*Primitive)(WrenVM* vm, Value* args);
|
||||
typedef void (*FiberPrimitive)(WrenVM* vm, Fiber* fiber, Value* args);
|
||||
|
||||
// A first-class function object. A raw ObjFn can be used and invoked directly
|
||||
// if it has no upvalues (i.e. [numUpvalues] is zero). If it does use upvalues,
|
||||
// it must be wrapped in an [ObjClosure] first. The compiler is responsible for
|
||||
// emitting code to ensure that that happens.
|
||||
typedef struct
|
||||
{
|
||||
Obj obj;
|
||||
int numConstants;
|
||||
int numUpvalues;
|
||||
unsigned char* bytecode;
|
||||
|
||||
// TODO: Flexible array?
|
||||
Value* constants;
|
||||
} ObjFn;
|
||||
|
||||
// The dynamically allocated data structure for a variable that has been used
|
||||
// by a closure. Whenever a function accesses a variable declared in an
|
||||
// enclosing function, it will get to it through this.
|
||||
@ -141,6 +126,54 @@ typedef struct sUpvalue
|
||||
struct sUpvalue* next;
|
||||
} Upvalue;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Pointer to the current (really next-to-be-executed) instruction in the
|
||||
// function's bytecode.
|
||||
unsigned char* ip;
|
||||
|
||||
// The function or closure being executed.
|
||||
Value fn;
|
||||
|
||||
// Index of the first stack slot used by this call frame. This will contain
|
||||
// the receiver, followed by the function's parameters, then local variables
|
||||
// and temporaries.
|
||||
int stackStart;
|
||||
} CallFrame;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Obj obj;
|
||||
Value stack[STACK_SIZE];
|
||||
int stackSize;
|
||||
|
||||
CallFrame frames[MAX_CALL_FRAMES];
|
||||
int numFrames;
|
||||
|
||||
// Pointer to the first node in the linked list of open upvalues that are
|
||||
// pointing to values still on the stack. The head of the list will be the
|
||||
// upvalue closest to the top of the stack, and then the list works downwards.
|
||||
Upvalue* openUpvalues;
|
||||
} ObjFiber;
|
||||
|
||||
typedef Value (*Primitive)(WrenVM* vm, Value* args);
|
||||
typedef void (*FiberPrimitive)(WrenVM* vm, ObjFiber* fiber, Value* args);
|
||||
|
||||
// A first-class function object. A raw ObjFn can be used and invoked directly
|
||||
// if it has no upvalues (i.e. [numUpvalues] is zero). If it does use upvalues,
|
||||
// it must be wrapped in an [ObjClosure] first. The compiler is responsible for
|
||||
// emitting code to ensure that that happens.
|
||||
typedef struct
|
||||
{
|
||||
Obj obj;
|
||||
int numConstants;
|
||||
int numUpvalues;
|
||||
unsigned char* bytecode;
|
||||
|
||||
// TODO: Flexible array?
|
||||
Value* constants;
|
||||
} ObjFn;
|
||||
|
||||
// An instance of a first-class function and the environment it has closed over.
|
||||
// Unlike [ObjFn], this has captured the upvalues that the function accesses.
|
||||
typedef struct
|
||||
@ -425,6 +458,9 @@ ObjClass* wrenNewClass(WrenVM* vm, ObjClass* superclass, int numFields);
|
||||
// upvalues, but assumes outside code will populate it.
|
||||
ObjClosure* wrenNewClosure(WrenVM* vm, ObjFn* fn);
|
||||
|
||||
// Creates a new fiber object.
|
||||
ObjFiber* wrenNewFiber(WrenVM* vm);
|
||||
|
||||
// Creates a new function object. Assumes the compiler will fill it in with
|
||||
// bytecode, constants, etc.
|
||||
ObjFn* wrenNewFunction(WrenVM* vm);
|
||||
@ -453,6 +489,7 @@ void wrenPrintValue(Value value);
|
||||
|
||||
bool wrenIsBool(Value value);
|
||||
bool wrenIsClosure(Value value);
|
||||
bool wrenIsFiber(Value value);
|
||||
bool wrenIsFn(Value value);
|
||||
bool wrenIsInstance(Value value);
|
||||
bool wrenIsString(Value value);
|
||||
|
||||
102
src/wren_vm.c
102
src/wren_vm.c
@ -25,14 +25,12 @@ WrenVM* wrenNewVM(WrenConfiguration* configuration)
|
||||
}
|
||||
|
||||
WrenVM* vm = reallocate(NULL, 0, sizeof(WrenVM));
|
||||
|
||||
vm->reallocate = reallocate;
|
||||
|
||||
initSymbolTable(&vm->methods);
|
||||
initSymbolTable(&vm->globalSymbols);
|
||||
|
||||
vm->fiber = reallocate(NULL, 0, sizeof(Fiber));
|
||||
vm->fiber->stackSize = 0;
|
||||
vm->fiber->numFrames = 0;
|
||||
vm->fiber->openUpvalues = NULL;
|
||||
|
||||
vm->bytesAllocated = 0;
|
||||
|
||||
vm->nextGC = 1024 * 1024 * 10;
|
||||
@ -66,10 +64,7 @@ WrenVM* wrenNewVM(WrenConfiguration* configuration)
|
||||
vm->globals[i] = NULL_VAL;
|
||||
}
|
||||
|
||||
vm->reallocate = reallocate;
|
||||
|
||||
wrenInitializeCore(vm);
|
||||
|
||||
return vm;
|
||||
}
|
||||
|
||||
@ -80,16 +75,6 @@ void wrenFreeVM(WrenVM* vm)
|
||||
free(vm);
|
||||
}
|
||||
|
||||
int wrenInterpret(WrenVM* vm, const char* source)
|
||||
{
|
||||
ObjFn* fn = wrenCompile(vm, source);
|
||||
if (fn == NULL) return 1;
|
||||
|
||||
// TODO: Return error code on runtime errors.
|
||||
interpret(vm, OBJ_VAL(fn));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void collectGarbage(WrenVM* vm);
|
||||
|
||||
void* wrenReallocate(WrenVM* vm, void* memory, size_t oldSize, size_t newSize)
|
||||
@ -234,6 +219,33 @@ static void markUpvalue(WrenVM* vm, Upvalue* upvalue)
|
||||
vm->bytesAllocated += sizeof(Upvalue);
|
||||
}
|
||||
|
||||
static void markFiber(WrenVM* vm, ObjFiber* fiber)
|
||||
{
|
||||
// Don't recurse if already marked. Avoids getting stuck in a loop on cycles.
|
||||
if (fiber->obj.flags & FLAG_MARKED) return;
|
||||
fiber->obj.flags |= FLAG_MARKED;
|
||||
|
||||
// Stack functions.
|
||||
for (int k = 0; k < fiber->numFrames; k++)
|
||||
{
|
||||
markValue(vm, fiber->frames[k].fn);
|
||||
}
|
||||
|
||||
// Stack variables.
|
||||
for (int l = 0; l < fiber->stackSize; l++)
|
||||
{
|
||||
markValue(vm, fiber->stack[l]);
|
||||
}
|
||||
|
||||
// Open upvalues.
|
||||
Upvalue* upvalue = fiber->openUpvalues;
|
||||
while (upvalue != NULL)
|
||||
{
|
||||
markUpvalue(vm, upvalue);
|
||||
upvalue = upvalue->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void markClosure(WrenVM* vm, ObjClosure* closure)
|
||||
{
|
||||
// Don't recurse if already marked. Avoids getting stuck in a loop on cycles.
|
||||
@ -284,6 +296,7 @@ static void markObj(WrenVM* vm, Obj* obj)
|
||||
{
|
||||
case OBJ_CLASS: markClass( vm, (ObjClass*) obj); break;
|
||||
case OBJ_CLOSURE: markClosure( vm, (ObjClosure*) obj); break;
|
||||
case OBJ_FIBER: markFiber( vm, (ObjFiber*) obj); break;
|
||||
case OBJ_FN: markFn( vm, (ObjFn*) obj); break;
|
||||
case OBJ_INSTANCE: markInstance(vm, (ObjInstance*)obj); break;
|
||||
case OBJ_LIST: markList( vm, (ObjList*) obj); break;
|
||||
@ -376,26 +389,6 @@ static void collectGarbage(WrenVM* vm)
|
||||
pinned = pinned->previous;
|
||||
}
|
||||
|
||||
// Stack functions.
|
||||
for (int k = 0; k < vm->fiber->numFrames; k++)
|
||||
{
|
||||
markValue(vm, vm->fiber->frames[k].fn);
|
||||
}
|
||||
|
||||
// Stack variables.
|
||||
for (int l = 0; l < vm->fiber->stackSize; l++)
|
||||
{
|
||||
markValue(vm, vm->fiber->stack[l]);
|
||||
}
|
||||
|
||||
// Open upvalues.
|
||||
Upvalue* upvalue = vm->fiber->openUpvalues;
|
||||
while (upvalue != NULL)
|
||||
{
|
||||
markUpvalue(vm, upvalue);
|
||||
upvalue = upvalue->next;
|
||||
}
|
||||
|
||||
// Collect any unmarked objects.
|
||||
Obj** obj = &vm->first;
|
||||
while (*obj != NULL)
|
||||
@ -498,7 +491,7 @@ Value findGlobal(WrenVM* vm, const char* name)
|
||||
// ensure that multiple closures closing over the same variable actually see
|
||||
// the same variable.) Otherwise, it will create a new open upvalue and add it
|
||||
// the fiber's list of upvalues.
|
||||
static Upvalue* captureUpvalue(WrenVM* vm, Fiber* fiber, int slot)
|
||||
static Upvalue* captureUpvalue(WrenVM* vm, ObjFiber* fiber, int slot)
|
||||
{
|
||||
Value* local = &fiber->stack[slot];
|
||||
|
||||
@ -541,7 +534,7 @@ static Upvalue* captureUpvalue(WrenVM* vm, Fiber* fiber, int slot)
|
||||
return createdUpvalue;
|
||||
}
|
||||
|
||||
static void closeUpvalue(Fiber* fiber)
|
||||
static void closeUpvalue(ObjFiber* fiber)
|
||||
{
|
||||
Upvalue* upvalue = fiber->openUpvalues;
|
||||
|
||||
@ -584,11 +577,8 @@ static void bindMethod(int methodType, int symbol, ObjClass* classObj,
|
||||
|
||||
// The main bytecode interpreter loop. This is where the magic happens. It is
|
||||
// also, as you can imagine, highly performance critical.
|
||||
Value interpret(WrenVM* vm, Value function)
|
||||
static Value interpret(WrenVM* vm, ObjFiber* fiber)
|
||||
{
|
||||
Fiber* fiber = vm->fiber;
|
||||
wrenCallFunction(fiber, function, 0);
|
||||
|
||||
// These macros are designed to only be invoked within this function.
|
||||
// TODO: Check for stack overflow.
|
||||
#define PUSH(value) (fiber->stack[fiber->stackSize++] = value)
|
||||
@ -1152,9 +1142,31 @@ Value interpret(WrenVM* vm, Value function)
|
||||
// the compiler generated wrong code.
|
||||
ASSERT(0, "Should not execute past end of bytecode.");
|
||||
}
|
||||
|
||||
ASSERT(0, "Should not reach end of interpret.");
|
||||
}
|
||||
|
||||
void wrenCallFunction(Fiber* fiber, Value function, int numArgs)
|
||||
int wrenInterpret(WrenVM* vm, const char* source)
|
||||
{
|
||||
ObjFiber* fiber = wrenNewFiber(vm);
|
||||
PinnedObj pinned;
|
||||
pinObj(vm, (Obj*)fiber, &pinned);
|
||||
|
||||
int result = 1;
|
||||
ObjFn* fn = wrenCompile(vm, source);
|
||||
if (fn != NULL)
|
||||
{
|
||||
wrenCallFunction(fiber, OBJ_VAL(fn), 0);
|
||||
// TODO: Return error code on runtime errors.
|
||||
interpret(vm, fiber);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
unpinObj(vm);
|
||||
return result;
|
||||
}
|
||||
|
||||
void wrenCallFunction(ObjFiber* fiber, Value function, int numArgs)
|
||||
{
|
||||
// TODO: Check for stack overflow.
|
||||
CallFrame* frame = &fiber->frames[fiber->numFrames];
|
||||
|
||||
@ -4,10 +4,6 @@
|
||||
#include "wren_common.h"
|
||||
#include "wren_value.h"
|
||||
|
||||
// TODO: Make these externally controllable.
|
||||
#define STACK_SIZE 1024
|
||||
#define MAX_CALL_FRAMES 256
|
||||
|
||||
typedef enum
|
||||
{
|
||||
// Load the constant at index [arg].
|
||||
@ -192,6 +188,7 @@ struct WrenVM
|
||||
|
||||
ObjClass* boolClass;
|
||||
ObjClass* classClass;
|
||||
ObjClass* fiberClass;
|
||||
ObjClass* fnClass;
|
||||
ObjClass* listClass;
|
||||
ObjClass* nullClass;
|
||||
@ -199,17 +196,11 @@ struct WrenVM
|
||||
ObjClass* objectClass;
|
||||
ObjClass* stringClass;
|
||||
|
||||
// The singleton values.
|
||||
Value unsupported;
|
||||
|
||||
SymbolTable globalSymbols;
|
||||
|
||||
// TODO: Using a fixed array is gross here.
|
||||
Value globals[MAX_SYMBOLS];
|
||||
|
||||
// TODO: Support more than one fiber.
|
||||
Fiber* fiber;
|
||||
|
||||
// Memory management data:
|
||||
|
||||
// TODO: Temp.
|
||||
@ -241,37 +232,6 @@ struct WrenVM
|
||||
WrenReallocateFn reallocate;
|
||||
};
|
||||
|
||||
// TODO: Move into wren_vm.c.
|
||||
typedef struct
|
||||
{
|
||||
// Pointer to the current (really next-to-be-executed) instruction in the
|
||||
// function's bytecode.
|
||||
unsigned char* ip;
|
||||
|
||||
// The function or closure being executed.
|
||||
Value fn;
|
||||
|
||||
// Index of the first stack slot used by this call frame. This will contain
|
||||
// the receiver, followed by the function's parameters, then local variables
|
||||
// and temporaries.
|
||||
int stackStart;
|
||||
} CallFrame;
|
||||
|
||||
// TODO: Move into wren_vm.c.
|
||||
struct sFiber
|
||||
{
|
||||
Value stack[STACK_SIZE];
|
||||
int stackSize;
|
||||
|
||||
CallFrame frames[MAX_CALL_FRAMES];
|
||||
int numFrames;
|
||||
|
||||
// Pointer to the first node in the linked list of open upvalues that are
|
||||
// pointing to values still on the stack. The head of the list will be the
|
||||
// upvalue closest to the top of the stack, and then the list works downwards.
|
||||
Upvalue* openUpvalues;
|
||||
};
|
||||
|
||||
void* wrenReallocate(WrenVM* vm, void* memory, size_t oldSize, size_t newSize);
|
||||
|
||||
// TODO: Make these static or prefix their names.
|
||||
@ -303,12 +263,10 @@ const char* getSymbolName(SymbolTable* symbols, int symbol);
|
||||
// Returns the global variable named [name].
|
||||
Value findGlobal(WrenVM* vm, const char* name);
|
||||
|
||||
Value interpret(WrenVM* vm, Value function);
|
||||
|
||||
// Pushes [function] onto [fiber]'s callstack and invokes it. Expects [numArgs]
|
||||
// arguments (including the receiver) to be on the top of the stack already.
|
||||
// [function] can be an `ObjFn` or `ObjClosure`.
|
||||
void wrenCallFunction(Fiber* fiber, Value function, int numArgs);
|
||||
void wrenCallFunction(ObjFiber* fiber, Value function, int numArgs);
|
||||
|
||||
// Mark [obj] as a GC root so that it doesn't get collected. Initializes
|
||||
// [pinned], which must be then passed to [unpinObj].
|
||||
|
||||
Reference in New Issue
Block a user