Pluto icon indicating copy to clipboard operation
Pluto copied to clipboard

Add lua_resumeerror

Open cheesycod opened this issue 11 months ago • 2 comments

Luau has lua_resumeerror to resume a thread with the error as first value pushed to stack (basically a C API that does what coroutine.xresumr does in Pluto). It would be nice if Pluto supported resumeerror as well

cheesycod avatar Feb 17 '25 04:02 cheesycod

Well, what coroutine.xresume does is rethrow the error, but what you're describing sounds more like a wrapper for pcall?

Sainan avatar Mar 12 '25 10:03 Sainan

Well, what coroutine.xresume does is rethrow the error, but what you're describing sounds more like a wrapper for pcall?

I meant it for C side/embedder use-cases. Its very useful to be able to directly rethrow an error to a thread directly using a simple API without needing to undergo any performance loss of going through a table + lua function call in C code and resumeerror is the standard way that most Luau runtimes handle this so it'd be nice to have in Pluto as well

cheesycod avatar Mar 15 '25 00:03 cheesycod

I mean, I don't really know how it is in LuaU, and there seems to be absolutely 0 documentation around its C API additions, but based on what you're describing, what you want is simply lua_resume from modern versions, which is what you'll have in Pluto:

    lua_State* L = luaL_newstate();
    luaL_openlibs(L);
    auto coro = lua_newthread(L);

    lua_getglobal(coro, "error");
    lua_pushstring(coro, "Oh no!");
    int nres;
    int status = lua_resume(coro, L, 1, &nres);
    if (status != LUA_OK && status != LUA_YIELD)
    {
        std::cout << "Coroutine had an error: " << luaL_tolstring(coro, -1, NULL) << std::endl;
    }

Coroutine had an error: Oh no!

Sainan avatar May 12 '25 03:05 Sainan

int status = lua_resume(coro, L, 1, &nres); if (status != LUA_OK && status != LUA_YIELD) { std::cout << "Coroutine had an error: " << luaL_tolstring(coro, -1, NULL) << std::endl; }

Ah hmmm... the thing lua_resumeerror in luau does well is when you pcall a coroutine that yields and is then resume error'd from C side, the pcall returns the error. E.g.

local function myAsyncCoroutine() callCCode(); return coroutine.yield()

and

local ok, err = pcall(myAsyncCoroutine)

If the C code in callCCode uses resumeerror, the error is propogated to the pcall so ok becomes false and err, the error itself.

Not sure how you'd do this with just resume though

cheesycod avatar May 13 '25 19:05 cheesycod

Well, lucky for you, that is literally what coroutine.resume does:

static int luaB_coresume (lua_State *L) {
  lua_State *co = getco(L);
  int r;
  r = auxresume(L, co, lua_gettop(L) - 1);
  if (l_unlikely(r < 0)) {
    lua_pushboolean(L, 0);
    lua_insert(L, -2);
    return 2;  /* return false + error message */
  }
  else {
    lua_pushboolean(L, 1);
    lua_insert(L, -(r + 1));
    return r + 1;  /* return true + 'resume' returns */
  }
}

Sainan avatar May 14 '25 03:05 Sainan

Well, lucky for you, that is literally what coroutine.resume does:

static int luaB_coresume (lua_State *L) { lua_State co = getco(L); int r; r = auxresume(L, co, lua_gettop(L) - 1); if (l_unlikely(r < 0)) { lua_pushboolean(L, 0); lua_insert(L, -2); return 2; / return false + error message / } else { lua_pushboolean(L, 1); lua_insert(L, -(r + 1)); return r + 1; / return true + 'resume' returns */ } }

I realize this is closed and rather niche, but just to try explaining a second time, consider the following C/Rust pseudo code:

if some_async_op().await.is_ok() { lua_push(…) lua_resume(thread_state, numargs) } else { // here is the issue, you can’t resume the thread with a error status from C API, so it’s not possible for C/Rust code to directly propogate the error to a resume within C API }

coroutine.resume etc are lua functions/APIs. lua_resumeerror is the C API equivalent (kinda)

cheesycod avatar Jun 05 '25 23:06 cheesycod

Yes, you can't resume the coroutine, but you can xmove the error message from the coroutine to the main thread and continue execution there. Just take a look at how lcorolib does it.

Sainan avatar Jun 05 '25 23:06 Sainan

Yes, you can't resume the coroutine, but you can xmove the error message from the coroutine to the main thread and continue execution there. Just take a look at how lcorolib does it.

Not sure how this would work with pcall though. I think continuations would also solve this problem too depending on how Pluto implements continuations

cheesycod avatar Jun 06 '25 04:06 cheesycod