bool validateNum(WrenVM* vm, Value arg, const char* argName) { if (IS_NUM(arg)) return true; vm->fiber->error = wrenStringFormat(vm, "$ must be a number.", argName); return false; }
bool validateString(WrenVM* vm, Value arg, const char* argName) { if (IS_STRING(arg)) return true; vm->fiber->error = wrenStringFormat(vm, "$ must be a string.", argName); return false; }
bool validateIntValue(WrenVM* vm, double value, const char* argName) { if (trunc(value) == value) return true; vm->fiber->error = wrenStringFormat(vm, "$ must be an integer.", argName); return false; }
bool validateString(WrenVM* vm, Value* args, int index, const char* argName) { if (IS_STRING(args[index])) return true; args[0] = wrenStringFormat(vm, "$ must be a string.", argName); return false; }
bool validateFn(WrenVM* vm, Value arg, const char* argName) { if (IS_FN(arg) || IS_CLOSURE(arg)) return true; vm->fiber->error = wrenStringFormat(vm, "$ must be a function.", argName); return false; }
bool validateFn(WrenVM* vm, Value* args, int index, const char* argName) { if (IS_FN(args[index]) || IS_CLOSURE(args[index])) return true; args[0] = wrenStringFormat(vm, "$ must be a function.", argName); return false; }
bool validateNum(WrenVM* vm, Value* args, int index, const char* argName) { if (IS_NUM(args[index])) return true; args[0] = wrenStringFormat(vm, "$ must be a number.", argName); return false; }
ObjClass* wrenNewClass(WrenVM* vm, ObjClass* superclass, int numFields, ObjString* name) { // Create the metaclass. Value metaclassName = wrenStringFormat(vm, "@ metaclass", OBJ_VAL(name)); wrenPushRoot(vm, AS_OBJ(metaclassName)); ObjClass* metaclass = wrenNewSingleClass(vm, 0, AS_STRING(metaclassName)); metaclass->obj.classObj = vm->classClass; wrenPopRoot(vm); // Make sure the metaclass isn't collected when we allocate the class. wrenPushRoot(vm, (Obj*)metaclass); // Metaclasses always inherit Class and do not parallel the non-metaclass // hierarchy. wrenBindSuperclass(vm, metaclass, vm->classClass); ObjClass* classObj = wrenNewSingleClass(vm, numFields, name); // Make sure the class isn't collected while the inherited methods are being // bound. wrenPushRoot(vm, (Obj*)classObj); classObj->obj.classObj = metaclass; wrenBindSuperclass(vm, classObj, superclass); wrenPopRoot(vm); wrenPopRoot(vm); return classObj; }
bool validateIntValue(WrenVM* vm, Value* args, double value, const char* argName) { if (trunc(value) == value) return true; args[0] = wrenStringFormat(vm, "$ must be an integer.", argName); return false; }
// Transfer execution to [fiber] coming from the current fiber whose stack has // [args]. // // [isCall] is true if [fiber] is being called and not transferred. // // [hasValue] is true if a value in [args] is being passed to the new fiber. // Otherwise, `null` is implicitly being passed. static PrimitiveResult runFiber(WrenVM* vm, ObjFiber* fiber, Value* args, bool isCall, bool hasValue) { if (isCall) { if (fiber->caller != NULL) RETURN_ERROR("Fiber has already been called."); // Remember who ran it. fiber->caller = vm->fiber; } else { // Edge case: If we are transferring to ourself, immediately return the // value. We can't treat this like an actual transfer since when we set the // return below, it would overwrite the fiber being transferred to. if (fiber == vm->fiber) RETURN_VAL(hasValue ? args[1] : NULL_VAL); } if (fiber->numFrames == 0) { args[0] = wrenStringFormat(vm, "Cannot $ a finished fiber.", isCall ? "call" : "transfer to"); return PRIM_ERROR; } if (fiber->error != NULL) { args[0] = wrenStringFormat(vm, "Cannot $ an aborted fiber.", isCall ? "call" : "transfer to"); return PRIM_ERROR; } // When the calling fiber resumes, we'll store the result of the call in its // stack. If the call has two arguments (the fiber and the value), we only // need one slot for the result, so discard the other slot now. if (hasValue) vm->fiber->stackTop--; // If the fiber was paused, make yield() or transfer() return the result. if (fiber->stackTop > fiber->stack) { *(fiber->stackTop - 1) = hasValue ? args[1] : NULL_VAL; } return PRIM_RUN_FIBER; }
// Creates either the Object or Class class in the core module with [name]. static ObjClass* defineClass(WrenVM* vm, ObjModule* module, const char* name) { ObjString* nameString = AS_STRING(wrenStringFormat(vm, "$", name)); wrenPushRoot(vm, (Obj*)nameString); ObjClass* classObj = wrenNewSingleClass(vm, 0, nameString); wrenDefineVariable(vm, module, name, nameString->length, OBJ_VAL(classObj)); wrenPopRoot(vm); return classObj; }
// Validates that [value] is an integer within `[0, count)`. Also allows // negative indices which map backwards from the end. Returns the valid positive // index value. If invalid, reports an error and returns `UINT32_MAX`. static uint32_t validateIndexValue(WrenVM* vm, uint32_t count, double value, const char* argName) { if (!validateIntValue(vm, value, argName)) return UINT32_MAX; // Negative indices count from the end. if (value < 0) value = count + value; // Check bounds. if (value >= 0 && value < count) return (uint32_t)value; vm->fiber->error = wrenStringFormat(vm, "$ out of bounds.", argName); return UINT32_MAX; }