diff --git a/src/include/wren.h b/src/include/wren.h index 7b3b0cc3..74aed11c 100644 --- a/src/include/wren.h +++ b/src/include/wren.h @@ -162,12 +162,30 @@ typedef struct int heapGrowthPercent; } WrenConfiguration; -typedef enum { +typedef enum +{ WREN_RESULT_SUCCESS, WREN_RESULT_COMPILE_ERROR, WREN_RESULT_RUNTIME_ERROR } WrenInterpretResult; +// The type of an object stored in a slot. +// +// This is not necessarily the object's *class*, but instead its low level +// representation type. +typedef enum +{ + WREN_TYPE_BOOL, + WREN_TYPE_NUM, + WREN_TYPE_FOREIGN, + WREN_TYPE_LIST, + WREN_TYPE_NULL, + WREN_TYPE_STRING, + + // The object is of a type that isn't accessible by the C API. + WREN_TYPE_UNKNOWN +} WrenType; + // Initializes [configuration] with all of its default values. // // Call this before setting the particular fields you care about. @@ -263,6 +281,9 @@ int wrenGetSlotCount(WrenVM* vm); // It is an error to call this from a finalizer. void wrenEnsureSlots(WrenVM* vm, int numSlots); +// Gets the type of the object in [slot]. +WrenType wrenGetSlotType(WrenVM* vm, int slot); + // Reads a boolean value from [slot]. // // It is an error to call this if the slot does not contain a boolean value. diff --git a/src/vm/wren_vm.c b/src/vm/wren_vm.c index 3f65a34d..4440970d 100644 --- a/src/vm/wren_vm.c +++ b/src/vm/wren_vm.c @@ -1512,6 +1512,20 @@ static void validateApiSlot(WrenVM* vm, int slot) ASSERT(slot < wrenGetSlotCount(vm), "Not that many slots."); } +// Gets the type of the object in [slot]. +WrenType wrenGetSlotType(WrenVM* vm, int slot) +{ + validateApiSlot(vm, slot); + if (IS_BOOL(vm->apiStack[slot])) return WREN_TYPE_BOOL; + if (IS_NUM(vm->apiStack[slot])) return WREN_TYPE_NUM; + if (IS_FOREIGN(vm->apiStack[slot])) return WREN_TYPE_FOREIGN; + if (IS_LIST(vm->apiStack[slot])) return WREN_TYPE_LIST; + if (IS_NULL(vm->apiStack[slot])) return WREN_TYPE_NULL; + if (IS_STRING(vm->apiStack[slot])) return WREN_TYPE_STRING; + + return WREN_TYPE_UNKNOWN; +} + bool wrenGetSlotBool(WrenVM* vm, int slot) { validateApiSlot(vm, slot); diff --git a/test/api/main.c b/test/api/main.c index 7ec7f797..1a4b94ef 100644 --- a/test/api/main.c +++ b/test/api/main.c @@ -63,7 +63,15 @@ static WrenForeignClassMethods bindForeignClass( if (strcmp(module, "main") != 0) return methods; foreignClassBindClass(className, &methods); - + if (methods.allocate != NULL) return methods; + + slotsBindClass(className, &methods); + if (methods.allocate != NULL) return methods; + + + fprintf(stderr, + "Unknown foreign class '%s' for test '%s'\n", className, testName); + exit(1); return methods; } diff --git a/test/api/slots.c b/test/api/slots.c index 9e995b9b..16dd9c18 100644 --- a/test/api/slots.c +++ b/test/api/slots.c @@ -74,6 +74,20 @@ static void setSlots(WrenVM* vm) } } +static void slotTypes(WrenVM* vm) +{ + bool result = + wrenGetSlotType(vm, 1) == WREN_TYPE_BOOL && + wrenGetSlotType(vm, 2) == WREN_TYPE_FOREIGN && + wrenGetSlotType(vm, 3) == WREN_TYPE_LIST && + wrenGetSlotType(vm, 4) == WREN_TYPE_NULL && + wrenGetSlotType(vm, 5) == WREN_TYPE_NUM && + wrenGetSlotType(vm, 6) == WREN_TYPE_STRING && + wrenGetSlotType(vm, 7) == WREN_TYPE_UNKNOWN; + + wrenSetSlotBool(vm, 0, result); +} + static void ensure(WrenVM* vm) { int before = wrenGetSlotCount(vm); @@ -134,13 +148,24 @@ static void ensureOutsideForeign(WrenVM* vm) wrenSetSlotString(vm, 0, result); } +static void foreignClassAllocate(WrenVM* vm) +{ + wrenSetSlotNewForeign(vm, 0, 0, 4); +} + WrenForeignMethodFn slotsBindMethod(const char* signature) { if (strcmp(signature, "static Slots.noSet") == 0) return noSet; if (strcmp(signature, "static Slots.getSlots(_,_,_,_,_)") == 0) return getSlots; if (strcmp(signature, "static Slots.setSlots(_,_,_,_)") == 0) return setSlots; + if (strcmp(signature, "static Slots.slotTypes(_,_,_,_,_,_,_)") == 0) return slotTypes; if (strcmp(signature, "static Slots.ensure()") == 0) return ensure; if (strcmp(signature, "static Slots.ensureOutsideForeign()") == 0) return ensureOutsideForeign; return NULL; } + +void slotsBindClass(const char* className, WrenForeignClassMethods* methods) +{ + methods->allocate = foreignClassAllocate; +} \ No newline at end of file diff --git a/test/api/slots.h b/test/api/slots.h index cf4392fa..e6b534fc 100644 --- a/test/api/slots.h +++ b/test/api/slots.h @@ -1,3 +1,4 @@ #include "wren.h" WrenForeignMethodFn slotsBindMethod(const char* signature); +void slotsBindClass(const char* className, WrenForeignClassMethods* methods); diff --git a/test/api/slots.wren b/test/api/slots.wren index cf63988f..1159ef3a 100644 --- a/test/api/slots.wren +++ b/test/api/slots.wren @@ -2,10 +2,15 @@ class Slots { foreign static noSet foreign static getSlots(bool, num, string, bytes, value) foreign static setSlots(a, b, c, d) + foreign static slotTypes(bool, foreignObj, list, nullObj, num, string, unknown) foreign static ensure() foreign static ensureOutsideForeign() } +foreign class ForeignType { + construct new() {} +} + // If nothing is set in the return slot, it retains its previous value, the // receiver. System.print(Slots.noSet == Slots) // expect: true @@ -17,6 +22,9 @@ System.print(Slots.getSlots(true, "by\0te", 12.34, "str", value) == value) System.print(Slots.setSlots(value, 0, 0, 0) == value) // expect: true +System.print(Slots.slotTypes(false, ForeignType.new(), [], null, 1.2, "str", 1..2)) +// expect: true + System.print(Slots.ensure()) // expect: 1 -> 20 (190)