ceifa / wasmoon

A real lua 5.4 VM with JS bindings made with webassembly
MIT License
449 stars 29 forks source link

When returning Promise to Lua (from JS function), getting "null function or function signature mismatch" #91

Closed pnemere closed 8 months ago

pnemere commented 9 months ago

Hi! I'm trying to make an async call from a JS function that is called from Lua.

I'm doing this to fetch data required for calculations in Lua and don't know if I need to load this data before calling the Lua lib. I have tried to load all possible data before calling to Lua and that worked fine, but I would now like to only load what's actually going to be used by Lua code.

I see there is a a PromiseTypeExtension https://github.com/ceifa/wasmoon/blob/main/src/type-extensions/promise.ts so I assumed I could return a Promise from my function to Lua, and have it all resolve by the time the Promise from doString() has resolved but it doesn't work for me. I end up with these errors:

null function or function signature mismatch

If I return a promise from my function, or mark it async. I saw your example posted in a few places showing how to register a sleep function that calls setTimeout. All of the following result in the same error above for me:

this._lua.global.set("sleep", (ms: number) => {
      return new Promise(resolve => setTimeout(resolve, ms));
    });

Of course adding async does the same...

this._lua.global.set("sleep", async (ms: number) => {
      return new Promise(resolve => setTimeout(resolve, ms));
    });

So I'm not sure how you were able to get this working. I see you have injectObjects: true in lua initing code:

const luaOpts = {
      openStandardLibs: true,
      injectObjects: true,
      enableProxy: false,
      traceAllocations: false,
    };
factory.createEngine(luaOpts);

For me, injectObjects doesn't seem to make a difference if it's set to true or false.

Here are some examples of my attempts at returning Promises for data, here getData() returns a Promise

this._lua.global.set("getdata", (column: string) => {
      return this.getData(column);
    });

And of course variations of that:

this._lua.global.set("getdata", async (column: string) => {
      return this.getData(column);
    });
this._lua.global.set("getdata", async (column: string) => {
      return await this.getData(column);
    });

All give back:

null function or function signature mismatch

The error seems to come from lower level than wasmoon - something in WASM probably bailing due to getting a Promise as a return value!

At this point I'm a bit stuck, because the PromiseTypeExtension isn't well documented, and I'm not sure of the intent of its use. By looking at the code and sleep example I assumed I should at least be able to modify my Lua code to call :await() for the value but that doesn't change the error.

I have tried various other options, to return a straight array in the Promise. If I call resolve() I get a different error where the table(s) found in Lua end up being a nil:

this._lua.global.set("getdata", async (column: string) => {
      return new Promise(resolve => {return ([[1,2,3],[10,20,30]]);});
    });

null function or function signature mismatch

But if I call resolve() from within the Promise:

this._lua.global.set("getdata", async (column: string) => {
      new Promise(resolve => {resolve([[1,2,3],[10,20,30]]);});
    });

The table returned ends up being nil within Lua. I'm not sure why this last one differs.

Could you please comment based on what the intended use for PromiseTypeExtension was and wether you saw this error with your experiments calling sleep()? At this point I may be forced to do some static analysis on the Lua code to work out what to load before running it (which won't be that reliable!).

Thanks!

pnemere commented 9 months ago

If it helps, in Firefox the error I get is:

indirect call signature mismatch

Instead of:

null function or function signature mismatch

pnemere commented 9 months ago

After a lot of messing around it appears I have solved this. Firstly, I was using v 1.14 not the latest code, and I found that because I was working in Angular I was getting issues related to #90 too. I may have solved this so will have a fork to merge back if testing goes well!

ceifa commented 8 months ago

Fixed on 1.15.1