-
-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Automatically yield when calling an AsyncFunction #2
Comments
@libitx, you'll need to experiment with using |
Thanks for the response @daurnimator (and apologies for the dupe issue). I'm a little confused as to where I even need to be looking. For example if I've added an async function like this: const foo = async function() {
// some async stuff
}
interop.push(L, foo)
lua.lua_setglobal(L, to_luastring('foo')) When I call https://github.com/fengari-lua/fengari-interop/blob/master/src/js.js#L778-L793 So it seems to me the function Any pointers you can offer would be much appreciated. I'd also be willing to put a bounty on this issue if that would be of interest to you. |
In my experience, you won't make async functions work with the
luaCode = "coroutine.wrap(function() " + luaCode + ";\n end)()";
const foo = async function() {
// some async stuff
};
const fooLua = function(L) {
foo().then(function() {
fengari.lua.lua_resume(L, null, 0);
});
fengari.lua.lua_yield(L, 0);
};
fengari.lua.lua_pushcfunction(L, fooLua);
fengari.lua.lua_setglobal(L, fengari.to_luastring('foo')); There's a little more than that to handle LUA errors, JS exceptions, rejected promises, etc, but that's the minimum to make it work. |
Thanks @lorenzos thats helpful. I've tried to follow that approach but still banging my head against a wall here. Do you mind if I share some code to see if one of you can point me in the right direction? const { lua, lauxlib, lualib, to_luastring } = require('fengari')
// Create VM state
const L = lauxlib.luaL_newstate()
lualib.luaL_openlibs(L)
// Create async extension
const hello = async function(word) {
console.log('JS', 'hello called')
return new Promise(resolve => {
setTimeout(_ => resolve(`hello ${ word }`), 10)
})
}
lua.lua_pushcfunction(L, function() {
console.log('JS', 'calling hello')
hello('world')
.then(res => {
console.log('JS', 'async resolved', res)
lua.lua_pushstring(L, to_luastring(res))
lua.lua_resume(L, null, 0)
console.log('JS', 'resumed')
})
console.log('JS', 'yielding')
lua.lua_yield(L, 0)
console.log('JS', 'yielded')
})
lua.lua_setglobal(L, to_luastring('hello'))
// Lua code
const code = `
coroutine.wrap(function()
print('Lua '..'starting')
local res = hello()
print('Lua '..res)
end)()
`
// Execute
status = lauxlib.luaL_dostring(L, to_luastring(code))
console.log('JS', 'exec status', status)
if (status === 0) {
console.log('JS', 'ok')
} else {
const err = lua.lua_tojsstring(L, -1)
console.log('JS', 'errored', err)
} I've littered quite a lot of debug statements in the above to help see where I'm going wrong. When I run the above then this is what gets spit back at me:
What I want to see is Lua print out |
I can't try on live code now, but I see a couple things in your code that needs to be fixed. First a note. Any JS code after
You can still use coroutine.wrap(function()
local res = hello("world", 123)
end)() lua.lua_pushcfunction(L, function(L) {
var arg1 = interop.tojs(L, 1) // world (string)
var arg2 = interop.tojs(L, 2) // 123 (number)
console.log('JS', 'calling hello with', arg1, arg2)
hello(arg1, arg2)
.then(res => {
// ... |
Thank you, thats super helpful. I got this working in my sample script now - with arguments. 👍 |
I have another question. Suppose my wrapped code returns some value. How would I get that out of the coroutine? In the code below the async // Lua code
const code = `
coroutine.wrap(function()
print('Lua '..'starting')
print('Lua '..hello('world'))
print('Lua '..'ending')
return 123
end)()
`
// Execute
status = lauxlib.luaL_dostring(L, to_luastring(code))
console.log('JS', 'exec status', status)
if (status === 0) {
console.log('JS', 'ok')
} else {
const err = lua.lua_tojsstring(L, -1)
console.log('JS', 'error', err)
} EDITI've kind of solved this by wrapping the Lua code in This works but does feel somewhat kludgy so please do let me know if you think there's a better approach. |
Why do you need to have a return statement exactly like that? Can't you set a global or pass a callback function to get a "return" value in JS? Anyway, instead of a poller to check when the thread is dead, I'd use a callback. For example, here's how I currently do in my project (again, this is simplified): const executeAsyncLua = (code) => {
// ...create state L, load libs, etc...
return new Promise((resolve, reject) => {
let wrappedCode = "function _script_run() " + code + ";\n end;\n _script_run();\n _script_exit_trap()";
fengari.interop.push(L, () => resolve()); // <-- Here's the thing!
fengari.lua.lua_setglobal(L, "_script_exit_trap");
wrappedCode = "coroutine.wrap(function() " + wrappedCode + ";\n end)()";
// ...load code, check syntax errors, execute, catch errors and call reject() in case...
}
}
const luaCode = '...';
executeAsyncLua(luaCode).then(() => {
// Here the script has run and finished
}); Another idea, if you still want to use the "return" statement as you showed, is to combine this with some more code wrapping trick to grab the returned value more "elegantly". Maybe wrap the original code into a function that get called, and its return value placed into a global or given into a JS callback. |
The Lua code I'm running is user-generated code - always functions that return some value. So I can't change the Lua code at all, other than perhaps wrapping it in a coroutine as we've been discussing. I could also tail the user-code with some kind of exit trap function as you suggest above. Thanks for the idea 👍 |
I don't see your hello function? |
Hi guys, I just wanted to update you on my progress re the above discussion. I have now achieved what I wanted, following the approach suggested by @lorenzos (wrapping the Lua code in a coroutine). This approach involves not using This discussion has been very helpful for me (thank you) but I don't think has moved you any closer to resolving the actual topic of this issue. 😄 But thanks all the same. |
The text was updated successfully, but these errors were encountered: