diff --git a/src/vm/wren_core.c b/src/vm/wren_core.c index b839bea2..e9745702 100644 --- a/src/vm/wren_core.c +++ b/src/vm/wren_core.c @@ -50,7 +50,7 @@ DEF_PRIMITIVE(class_toString) DEF_PRIMITIVE(fiber_new) { - if (!validateFn(vm, args[1], "Argument")) return PRIM_FIBER; + if (!validateFn(vm, args[1], "Argument")) return false; ObjFiber* newFiber = wrenNewFiber(vm, AS_OBJ(args[1])); @@ -70,7 +70,7 @@ DEF_PRIMITIVE(fiber_abort) vm->fiber->error = args[1]; // If the error is explicitly null, it's not really an abort. - return IS_NULL(args[1]) ? PRIM_VALUE : PRIM_FIBER; + return IS_NULL(args[1]); } // Transfer execution to [fiber] coming from the current fiber whose stack has @@ -80,8 +80,8 @@ DEF_PRIMITIVE(fiber_abort) // // [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) +static bool runFiber(WrenVM* vm, ObjFiber* fiber, Value* args, bool isCall, + bool hasValue) { if (isCall) { @@ -95,14 +95,14 @@ static PrimitiveResult runFiber(WrenVM* vm, ObjFiber* fiber, Value* args, { vm->fiber->error = wrenStringFormat(vm, "Cannot $ a finished fiber.", isCall ? "call" : "transfer to"); - return PRIM_FIBER; + return false; } if (!IS_NULL(fiber->error)) { vm->fiber->error = wrenStringFormat(vm, "Cannot $ an aborted fiber.", isCall ? "call" : "transfer to"); - return PRIM_FIBER; + return false; } // When the calling fiber resumes, we'll store the result of the call in its @@ -117,8 +117,7 @@ static PrimitiveResult runFiber(WrenVM* vm, ObjFiber* fiber, Value* args, } vm->fiber = fiber; - - return PRIM_FIBER; + return false; } DEF_PRIMITIVE(fiber_call) @@ -151,7 +150,7 @@ DEF_PRIMITIVE(fiber_suspend) { // Switching to a null fiber tells the interpreter to stop and exit. vm->fiber = NULL; - return PRIM_FIBER; + return false; } DEF_PRIMITIVE(fiber_transfer) @@ -166,10 +165,9 @@ DEF_PRIMITIVE(fiber_transfer1) DEF_PRIMITIVE(fiber_transferError) { - PrimitiveResult result = runFiber(vm, AS_FIBER(args[0]), args, false, true); - if (result == PRIM_FIBER) vm->fiber->error = args[1]; - - return result; + runFiber(vm, AS_FIBER(args[0]), args, false, true); + vm->fiber->error = args[1]; + return false; } DEF_PRIMITIVE(fiber_try) @@ -192,7 +190,7 @@ DEF_PRIMITIVE(fiber_try) vm->fiber->stackTop[-1] = NULL_VAL; } - return PRIM_FIBER; + return false; } DEF_PRIMITIVE(fiber_yield) @@ -210,7 +208,7 @@ DEF_PRIMITIVE(fiber_yield) vm->fiber->stackTop[-1] = NULL_VAL; } - return PRIM_FIBER; + return false; } DEF_PRIMITIVE(fiber_yield1) @@ -234,12 +232,12 @@ DEF_PRIMITIVE(fiber_yield1) current->stackTop--; } - return PRIM_FIBER; + return false; } DEF_PRIMITIVE(fn_new) { - if (!validateFn(vm, args[1], "Argument")) return PRIM_FIBER; + if (!validateFn(vm, args[1], "Argument")) return false; // The block argument is already a function, so just return it. RETURN_VAL(args[1]); @@ -284,7 +282,7 @@ DEF_PRIMITIVE(list_insert) // count + 1 here so you can "insert" at the very end. uint32_t index = validateIndex(vm, args[1], list->elements.count + 1, "Index"); - if (index == UINT32_MAX) return PRIM_FIBER; + if (index == UINT32_MAX) return false; wrenListInsert(vm, list, args[2], index); RETURN_VAL(args[2]); @@ -301,7 +299,7 @@ DEF_PRIMITIVE(list_iterate) RETURN_NUM(0); } - if (!validateInt(vm, args[1], "Iterator")) return PRIM_FIBER; + if (!validateInt(vm, args[1], "Iterator")) return false; // Stop if we're out of bounds. double index = AS_NUM(args[1]); @@ -315,7 +313,7 @@ DEF_PRIMITIVE(list_iteratorValue) { ObjList* list = AS_LIST(args[0]); uint32_t index = validateIndex(vm, args[1], list->elements.count, "Iterator"); - if (index == UINT32_MAX) return PRIM_FIBER; + if (index == UINT32_MAX) return false; RETURN_VAL(list->elements.data[index]); } @@ -324,7 +322,7 @@ DEF_PRIMITIVE(list_removeAt) { ObjList* list = AS_LIST(args[0]); uint32_t index = validateIndex(vm, args[1], list->elements.count, "Index"); - if (index == UINT32_MAX) return PRIM_FIBER; + if (index == UINT32_MAX) return false; RETURN_VAL(wrenListRemoveAt(vm, list, index)); } @@ -337,7 +335,7 @@ DEF_PRIMITIVE(list_subscript) { uint32_t index = validateIndex(vm, args[1], list->elements.count, "Subscript"); - if (index == UINT32_MAX) return PRIM_FIBER; + if (index == UINT32_MAX) return false; RETURN_VAL(list->elements.data[index]); } @@ -350,7 +348,7 @@ DEF_PRIMITIVE(list_subscript) int step; uint32_t count = list->elements.count; uint32_t start = calculateRange(vm, AS_RANGE(args[1]), &count, &step); - if (start == UINT32_MAX) return PRIM_FIBER; + if (start == UINT32_MAX) return false; ObjList* result = wrenNewList(vm, count); for (uint32_t i = 0; i < count; i++) @@ -366,7 +364,7 @@ DEF_PRIMITIVE(list_subscriptSetter) ObjList* list = AS_LIST(args[0]); uint32_t index = validateIndex(vm, args[1], list->elements.count, "Subscript"); - if (index == UINT32_MAX) return PRIM_FIBER; + if (index == UINT32_MAX) return false; list->elements.data[index] = args[2]; RETURN_VAL(args[2]); @@ -379,7 +377,7 @@ DEF_PRIMITIVE(map_new) DEF_PRIMITIVE(map_subscript) { - if (!validateKey(vm, args[1])) return PRIM_FIBER; + if (!validateKey(vm, args[1])) return false; ObjMap* map = AS_MAP(args[0]); Value value = wrenMapGet(map, args[1]); @@ -390,7 +388,7 @@ DEF_PRIMITIVE(map_subscript) DEF_PRIMITIVE(map_subscriptSetter) { - if (!validateKey(vm, args[1])) return PRIM_FIBER; + if (!validateKey(vm, args[1])) return false; wrenMapSet(vm, AS_MAP(args[0]), args[1], args[2]); RETURN_VAL(args[2]); @@ -404,7 +402,7 @@ DEF_PRIMITIVE(map_clear) DEF_PRIMITIVE(map_containsKey) { - if (!validateKey(vm, args[1])) return PRIM_FIBER; + if (!validateKey(vm, args[1])) return false; RETURN_BOOL(!IS_UNDEFINED(wrenMapGet(AS_MAP(args[0]), args[1]))); } @@ -426,7 +424,7 @@ DEF_PRIMITIVE(map_iterate) // Otherwise, start one past the last entry we stopped at. if (!IS_NULL(args[1])) { - if (!validateInt(vm, args[1], "Iterator")) return PRIM_FIBER; + if (!validateInt(vm, args[1], "Iterator")) return false; if (AS_NUM(args[1]) < 0) RETURN_FALSE; index = (uint32_t)AS_NUM(args[1]); @@ -449,7 +447,7 @@ DEF_PRIMITIVE(map_iterate) DEF_PRIMITIVE(map_remove) { - if (!validateKey(vm, args[1])) return PRIM_FIBER; + if (!validateKey(vm, args[1])) return false; RETURN_VAL(wrenMapRemoveKey(vm, AS_MAP(args[0]), args[1])); } @@ -458,7 +456,7 @@ DEF_PRIMITIVE(map_keyIteratorValue) { ObjMap* map = AS_MAP(args[0]); uint32_t index = validateIndex(vm, args[1], map->capacity, "Iterator"); - if (index == UINT32_MAX) return PRIM_FIBER; + if (index == UINT32_MAX) return false; MapEntry* entry = &map->entries[index]; if (IS_UNDEFINED(entry->key)) @@ -473,7 +471,7 @@ DEF_PRIMITIVE(map_valueIteratorValue) { ObjMap* map = AS_MAP(args[0]); uint32_t index = validateIndex(vm, args[1], map->capacity, "Iterator"); - if (index == UINT32_MAX) return PRIM_FIBER; + if (index == UINT32_MAX) return false; MapEntry* entry = &map->entries[index]; if (IS_UNDEFINED(entry->key)) @@ -496,7 +494,7 @@ DEF_PRIMITIVE(null_toString) DEF_PRIMITIVE(num_fromString) { - if (!validateString(vm, args[1], "Argument")) return PRIM_FIBER; + if (!validateString(vm, args[1], "Argument")) return false; ObjString* string = AS_STRING(args[1]); @@ -513,7 +511,7 @@ DEF_PRIMITIVE(num_fromString) if (errno == ERANGE) { vm->fiber->error = CONST_STRING(vm, "Number literal is too large."); - return PRIM_FIBER; + return false; } // We must have consumed the entire string. Otherwise, it contains non-number @@ -532,7 +530,7 @@ DEF_PRIMITIVE(num_pi) #define DEF_NUM_INFIX(name, op, type) \ DEF_PRIMITIVE(num_##name) \ { \ - if (!validateNum(vm, args[1], "Right operand")) return PRIM_FIBER; \ + if (!validateNum(vm, args[1], "Right operand")) return false; \ RETURN_##type(AS_NUM(args[0]) op AS_NUM(args[1])); \ } @@ -549,7 +547,7 @@ DEF_NUM_INFIX(gte, >=, BOOL) #define DEF_NUM_BITWISE(name, op) \ DEF_PRIMITIVE(num_bitwise##name) \ { \ - if (!validateNum(vm, args[1], "Right operand")) return PRIM_FIBER; \ + if (!validateNum(vm, args[1], "Right operand")) return false; \ uint32_t left = (uint32_t)AS_NUM(args[0]); \ uint32_t right = (uint32_t)AS_NUM(args[1]); \ RETURN_NUM(left op right); \ @@ -582,7 +580,7 @@ DEF_NUM_FN(tan, tan) DEF_PRIMITIVE(num_mod) { - if (!validateNum(vm, args[1], "Right operand")) return PRIM_FIBER; + if (!validateNum(vm, args[1], "Right operand")) return false; RETURN_NUM(fmod(AS_NUM(args[0]), AS_NUM(args[1]))); } @@ -606,7 +604,7 @@ DEF_PRIMITIVE(num_bitwiseNot) DEF_PRIMITIVE(num_dotDot) { - if (!validateNum(vm, args[1], "Right hand side of range")) return PRIM_FIBER; + if (!validateNum(vm, args[1], "Right hand side of range")) return false; double from = AS_NUM(args[0]); double to = AS_NUM(args[1]); @@ -615,7 +613,7 @@ DEF_PRIMITIVE(num_dotDot) DEF_PRIMITIVE(num_dotDotDot) { - if (!validateNum(vm, args[1], "Right hand side of range")) return PRIM_FIBER; + if (!validateNum(vm, args[1], "Right hand side of range")) return false; double from = AS_NUM(args[0]); double to = AS_NUM(args[1]); @@ -770,7 +768,7 @@ DEF_PRIMITIVE(range_iterate) // Start the iteration. if (IS_NULL(args[1])) RETURN_NUM(range->from); - if (!validateNum(vm, args[1], "Iterator")) return PRIM_FIBER; + if (!validateNum(vm, args[1], "Iterator")) return false; double iterator = AS_NUM(args[1]); @@ -817,7 +815,7 @@ DEF_PRIMITIVE(range_toString) DEF_PRIMITIVE(string_fromCodePoint) { - if (!validateInt(vm, args[1], "Code point")) return PRIM_FIBER; + if (!validateInt(vm, args[1], "Code point")) return false; int codePoint = (int)AS_NUM(args[1]); if (codePoint < 0) @@ -837,7 +835,7 @@ DEF_PRIMITIVE(string_byteAt) ObjString* string = AS_STRING(args[0]); uint32_t index = validateIndex(vm, args[1], string->length, "Index"); - if (index == UINT32_MAX) return PRIM_FIBER; + if (index == UINT32_MAX) return false; RETURN_NUM((uint8_t)string->value[index]); } @@ -852,7 +850,7 @@ DEF_PRIMITIVE(string_codePointAt) ObjString* string = AS_STRING(args[0]); uint32_t index = validateIndex(vm, args[1], string->length, "Index"); - if (index == UINT32_MAX) return PRIM_FIBER; + if (index == UINT32_MAX) return false; // If we are in the middle of a UTF-8 sequence, indicate that. const uint8_t* bytes = (uint8_t*)string->value; @@ -865,7 +863,7 @@ DEF_PRIMITIVE(string_codePointAt) DEF_PRIMITIVE(string_contains) { - if (!validateString(vm, args[1], "Argument")) return PRIM_FIBER; + if (!validateString(vm, args[1], "Argument")) return false; ObjString* string = AS_STRING(args[0]); ObjString* search = AS_STRING(args[1]); @@ -875,7 +873,7 @@ DEF_PRIMITIVE(string_contains) DEF_PRIMITIVE(string_endsWith) { - if (!validateString(vm, args[1], "Argument")) return PRIM_FIBER; + if (!validateString(vm, args[1], "Argument")) return false; ObjString* string = AS_STRING(args[0]); ObjString* search = AS_STRING(args[1]); @@ -889,7 +887,7 @@ DEF_PRIMITIVE(string_endsWith) DEF_PRIMITIVE(string_indexOf) { - if (!validateString(vm, args[1], "Argument")) return PRIM_FIBER; + if (!validateString(vm, args[1], "Argument")) return false; ObjString* string = AS_STRING(args[0]); ObjString* search = AS_STRING(args[1]); @@ -909,7 +907,7 @@ DEF_PRIMITIVE(string_iterate) RETURN_NUM(0); } - if (!validateInt(vm, args[1], "Iterator")) return PRIM_FIBER; + if (!validateInt(vm, args[1], "Iterator")) return false; if (AS_NUM(args[1]) < 0) RETURN_FALSE; uint32_t index = (uint32_t)AS_NUM(args[1]); @@ -935,7 +933,7 @@ DEF_PRIMITIVE(string_iterateByte) RETURN_NUM(0); } - if (!validateInt(vm, args[1], "Iterator")) return PRIM_FIBER; + if (!validateInt(vm, args[1], "Iterator")) return false; if (AS_NUM(args[1]) < 0) RETURN_FALSE; uint32_t index = (uint32_t)AS_NUM(args[1]); @@ -951,14 +949,14 @@ DEF_PRIMITIVE(string_iteratorValue) { ObjString* string = AS_STRING(args[0]); uint32_t index = validateIndex(vm, args[1], string->length, "Iterator"); - if (index == UINT32_MAX) return PRIM_FIBER; + if (index == UINT32_MAX) return false; RETURN_VAL(wrenStringCodePointAt(vm, string, index)); } DEF_PRIMITIVE(string_startsWith) { - if (!validateString(vm, args[1], "Argument")) return PRIM_FIBER; + if (!validateString(vm, args[1], "Argument")) return false; ObjString* string = AS_STRING(args[0]); ObjString* search = AS_STRING(args[1]); @@ -971,7 +969,7 @@ DEF_PRIMITIVE(string_startsWith) DEF_PRIMITIVE(string_plus) { - if (!validateString(vm, args[1], "Right operand")) return PRIM_FIBER; + if (!validateString(vm, args[1], "Right operand")) return false; RETURN_VAL(wrenStringFormat(vm, "@@", args[0], args[1])); } @@ -982,7 +980,7 @@ DEF_PRIMITIVE(string_subscript) if (IS_NUM(args[1])) { int index = validateIndex(vm, args[1], string->length, "Subscript"); - if (index == -1) return PRIM_FIBER; + if (index == -1) return false; RETURN_VAL(wrenStringCodePointAt(vm, string, index)); } @@ -995,7 +993,7 @@ DEF_PRIMITIVE(string_subscript) int step; uint32_t count = string->length; int start = calculateRange(vm, AS_RANGE(args[1]), &count, &step); - if (start == -1) return PRIM_FIBER; + if (start == -1) return false; RETURN_VAL(wrenNewStringFromRange(vm, string, start, count, step)); } diff --git a/src/vm/wren_meta.c b/src/vm/wren_meta.c index dee94e87..312c1762 100644 --- a/src/vm/wren_meta.c +++ b/src/vm/wren_meta.c @@ -10,10 +10,10 @@ DEF_PRIMITIVE(meta_eval) { - if (!validateString(vm, args[1], "Source code")) return PRIM_FIBER; + if (!validateString(vm, args[1], "Source code")) return false; // Eval the code in the module where the calling function was defined. - Value callingFn = OBJ_VAL(vm->fiber->frames[vm->fiber->numFrames - 1].fn); + Value callingFn = OBJ_VAL(vm->fiber->frames[vm->fiber->numFrames - 1].fn); ObjModule* module = IS_FN(callingFn) ? AS_FN(callingFn)->module : AS_CLOSURE(callingFn)->fn->module; @@ -30,13 +30,13 @@ DEF_PRIMITIVE(meta_eval) ObjFiber* evalFiber = wrenNewFiber(vm, (Obj*)fn); // Remember what fiber to return to. - evalFiber->caller = vm->fiber; + evalFiber->caller = vm->fiber; // Switch to the fiber. vm->fiber = evalFiber; wrenPopRoot(vm); - return PRIM_FIBER; + return false; } void wrenLoadMetaLibrary(WrenVM* vm) diff --git a/src/vm/wren_primitive.h b/src/vm/wren_primitive.h index 2a1d601b..8e536ffb 100644 --- a/src/vm/wren_primitive.h +++ b/src/vm/wren_primitive.h @@ -19,9 +19,9 @@ // the actual type signature of a primitive function and makes it clear which C // functions are invoked as primitives. #define DEF_PRIMITIVE(name) \ - static PrimitiveResult prim_##name(WrenVM* vm, Value* args) + static bool prim_##name(WrenVM* vm, Value* args) -#define RETURN_VAL(value) do { args[0] = value; return PRIM_VALUE; } while (0) +#define RETURN_VAL(value) do { args[0] = value; return true; } while (0) #define RETURN_OBJ(obj) RETURN_VAL(OBJ_VAL(obj)) #define RETURN_BOOL(value) RETURN_VAL(BOOL_VAL(value)) @@ -32,8 +32,8 @@ #define RETURN_ERROR(msg) \ do { \ - vm->fiber->error = wrenStringFormat(vm, "$", msg); \ - return PRIM_FIBER; \ + vm->fiber->error = wrenNewString(vm, msg, sizeof(msg) - 1); \ + return false; \ } while (0); // Validates that the given [arg] is a function. Returns true if it is. If not, diff --git a/src/vm/wren_value.h b/src/vm/wren_value.h index eb52aa60..61b893b5 100644 --- a/src/vm/wren_value.h +++ b/src/vm/wren_value.h @@ -246,18 +246,13 @@ typedef struct sObjFiber bool callerIsTrying; } ObjFiber; -typedef enum -{ - // A normal value has been returned. - PRIM_VALUE, - - // A fiber is being switched to. Also used for runtime errors (which also - // change which fiber is being executed). - PRIM_FIBER - -} PrimitiveResult; - -typedef PrimitiveResult (*Primitive)(WrenVM* vm, Value* args); +// The type of a primitive function. +// +// Primitives are similiar to foreign functions, but have more direct access to +// VM internals. It is passed the arguments in [args]. If it returns a value, +// it places it in `args[0]` and returns `true`. If it causes a runtime error +// or modifies the running fiber, it returns `false`. +typedef bool (*Primitive)(WrenVM* vm, Value* args); // TODO: See if it's actually a perf improvement to have this in a separate // struct instead of in ObjFn. diff --git a/src/vm/wren_vm.c b/src/vm/wren_vm.c index 17cc2a13..c2c8e8e1 100644 --- a/src/vm/wren_vm.c +++ b/src/vm/wren_vm.c @@ -922,30 +922,22 @@ static WrenInterpretResult runInterpreter(WrenVM* vm, register ObjFiber* fiber) switch (method->type) { case METHOD_PRIMITIVE: - { - // After calling this, the result will be in the first arg slot. - switch (method->fn.primitive(vm, args)) + if (method->fn.primitive(vm, args)) { - case PRIM_VALUE: - // The result is now in the first arg slot. Discard the other - // stack slots. - fiber->stackTop -= numArgs - 1; - break; + // The result is now in the first arg slot. Discard the other + // stack slots. + fiber->stackTop -= numArgs - 1; + } else { + // An error or fiber switch occurred. + STORE_FRAME(); - case PRIM_FIBER: - STORE_FRAME(); - - // If we don't have a fiber to switch to, stop interpreting. - if (vm->fiber == NULL) return WREN_RESULT_SUCCESS; - if (!IS_NULL(vm->fiber->error)) RUNTIME_ERROR(); - - fiber = vm->fiber; - - LOAD_FRAME(); - break; + // If we don't have a fiber to switch to, stop interpreting. + fiber = vm->fiber; + if (fiber == NULL) return WREN_RESULT_SUCCESS; + if (!IS_NULL(fiber->error)) RUNTIME_ERROR(); + LOAD_FRAME(); } break; - } case METHOD_FOREIGN: callForeign(vm, fiber, method->fn.foreign, numArgs);