// backend.cpp (Corrected) #include "httplib.h" #include "wren.h" #include #include // A struct to hold the response data for our foreign object struct ResponseData { bool isError; int statusCode; std::string body; }; // --- Response Class Foreign Methods --- void responseAllocate(WrenVM* vm) { // This is the constructor for the Response class. ResponseData* data = (ResponseData*)wrenSetSlotNewForeign(vm, 0, 0, sizeof(ResponseData)); data->isError = false; data->statusCode = 0; } void responseIsError(WrenVM* vm) { ResponseData* data = (ResponseData*)wrenGetSlotForeign(vm, 0); wrenSetSlotBool(vm, 0, data->isError); } void responseStatusCode(WrenVM* vm) { ResponseData* data = (ResponseData*)wrenGetSlotForeign(vm, 0); wrenSetSlotDouble(vm, 0, data->statusCode); } void responseBody(WrenVM* vm) { ResponseData* data = (ResponseData*)wrenGetSlotForeign(vm, 0); wrenSetSlotBytes(vm, 0, data->body.c_str(), data->body.length()); } void responseJson(WrenVM* vm) { // For a real implementation, you would use a JSON library here. // For this example, we just return the body text. ResponseData* data = (ResponseData*)wrenGetSlotForeign(vm, 0); wrenSetSlotBytes(vm, 0, data->body.c_str(), data->body.length()); } // --- Requests Class Foreign Methods --- void requestsGet(WrenVM* vm) { const char* url = wrenGetSlotString(vm, 1); // TODO: Handle headers from slot 2. httplib::Client cli("jsonplaceholder.typicode.com"); auto res = cli.Get("/posts/1"); // CHANGED: We need two slots: one for the Response class, one for the new instance. wrenEnsureSlots(vm, 2); // CHANGED: Get the 'Response' class from the 'requests' module and put it in slot 1. wrenGetVariable(vm, "requests", "Response", 1); // CHANGED: Create a new foreign object instance of the class in slot 1. // The new instance is placed in slot 0, which becomes the return value. ResponseData* data = (ResponseData*)wrenSetSlotNewForeign(vm, 0, 1, sizeof(ResponseData)); if (res) { data->isError = false; data->statusCode = res->status; data->body = res->body; } else { data->isError = true; data->statusCode = -1; data->body = "GET request failed."; } } void requestsPost(WrenVM* vm) { const char* url = wrenGetSlotString(vm, 1); const char* body = wrenGetSlotString(vm, 2); const char* contentType = wrenGetSlotString(vm, 3); // TODO: Handle headers from slot 4. httplib::Client cli("jsonplaceholder.typicode.com"); auto res = cli.Post("/posts", body, contentType); // CHANGED: We need two slots: one for the Response class, one for the new instance. wrenEnsureSlots(vm, 2); // CHANGED: Get the 'Response' class from the 'requests' module and put it in slot 1. wrenGetVariable(vm, "requests", "Response", 1); // CHANGED: Create a new foreign object instance of the class in slot 1. // The new instance is placed in slot 0, which becomes the return value. ResponseData* data = (ResponseData*)wrenSetSlotNewForeign(vm, 0, 1, sizeof(ResponseData)); if (res) { data->isError = false; data->statusCode = res->status; data->body = res->body; } else { data->isError = true; data->statusCode = -1; data->body = "POST request failed."; } } // --- FFI Binding Functions --- WrenForeignMethodFn bindForeignMethod(WrenVM* vm, const char* module, const char* className, bool isStatic, const char* signature) { if (strcmp(module, "requests") != 0) return NULL; if (strcmp(className, "Requests") == 0 && isStatic) { if (strcmp(signature, "get_(_,_)") == 0) return requestsGet; if (strcmp(signature, "post_(_,_,_,_)") == 0) return requestsPost; } if (strcmp(className, "Response") == 0 && !isStatic) { if (strcmp(signature, "isError") == 0) return responseIsError; if (strcmp(signature, "statusCode") == 0) return responseStatusCode; if (strcmp(signature, "body") == 0) return responseBody; if (strcmp(signature, "json()") == 0) return responseJson; } return NULL; } WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) { WrenForeignClassMethods methods = {0}; if (strcmp(module, "requests") == 0) { if (strcmp(className, "Response") == 0) { methods.allocate = responseAllocate; } } return methods; }