felixhao28 / JSCPP

A simple C++ interpreter written in JavaScript

Home Page:https://felixhao28.github.io/JSCPP/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support calling callbacks from custom classes

WayneKeenan opened this issue · comments

Hi,

I have a used case where it would be useful to be able to call a user defined function from a JSCPP defined C++ class.
'C style' would be ok, as I expect std::function based approach would required a large amount of work.

Thanks
Wayne

The support you ask for is now added to the master branch.

Example:

const _callback = function (rt: CRuntime, _this: ObjectVariable, f: FunctionPointerVariable, v: IntVariable) {
const r = f.v.target.v.target(rt, null, v);
return r;
}
rt.regFunc(_callback, type, "callback", [
rt.functionPointerType(rt.intTypeLiteral, [
rt.normalPointerType(rt.intTypeLiteral)
]),
rt.normalPointerType(rt.intTypeLiteral)
], rt.intTypeLiteral);

#include <foo>
#include <iostream>
using namespace std;
int f(int* x) {
cout << "f:" << *x << endl;
*x += 3;
return *x;
}
int main()
{
Foo foo;
cout << foo.x << ',' << foo.y << endl;
cout << foo.plusX(5) << endl;
int x = 123;
int r = foo.callback(&f,&x);
cout << "foo.callback:" << r << endl;
return 0;
}

great, thank you!

HI,

I've been trying to use this, but I want to call the callback from within the typescript defined class.
Imagine that my class is receiving background events and I want to dispatch that to the users callback.

But I'm getting an error.

For example, only changing your example _callback to just store a reference:

        var _userCallback:FunctionPointerVariable;

        const _callback = function (rt: CRuntime, _this: ObjectVariable, f: FunctionPointerVariable, v: IntVariable) {
            _userCallback=f;
        }

Then in another member function defined in the typescript class I try to call that stashed function ref, e.g.:

        const invokeUserCallback = function () {
            const v = rt.val(rt.normalPointerType(rt.intTypeLiteral), 321, false);
            _userCallback.v.target.v.target(rt, null, v);
        }

I get this error:

TypeError: undefined is not an object (evaluating 'value.t')

I tried a few ways, one was to modify the signature so the I did not need to construct a pointer to an int, but I get the same error.

Any help greatly appreciated.

Thanks, Wayne.

Sorry, the error above is not related. The issue I have is that when I setup a setTimeout in the custom TypeScript class to call the stashed call-back I see the TS function called (console output) but the user callback doesn't, I see no output to cout.

You are missing two things in your setup:

  1. rt.val produces a Variable, which takes a type and a value in that type. In your case, you are making a pointer-to-int variable (int*). Then you should do it like this:
// The actual variable to point to. Note the third argument indicates if it is a "left"(non-constant) variable.
const variable = rt.val(rt.intTypeLiteral, 321, true);
// The value of the pointer, which points to the variable above.
const pVariableVal = rt.makeNormalPointerValue(variable);
// The variable representing the pointer, with appropriate type and value and "left" property.
const v = rt.val(rt.normalPointerType(rt.intTypeLiteral), pVariableVal, false);
  1. Every C++ procedure returns a generator instead of executing right away. Calling _userCallback.v.target.v.target(rt, null, v) only returns a generator and you need to manually evaluate the generator to run the underlying C++ code.

All in all, the code should look like this:

let _userCallback: FunctionPointerVariable;
const _callback = function* (rt: CRuntime, _this: ObjectVariable, f: FunctionPointerVariable, v: IntVariable) {
    _userCallback = f;
    const r = yield* f.v.target.v.target(rt, null, v);
    return r;
}
rt.regFunc(_callback, type, "callback", [
    rt.functionPointerType(rt.intTypeLiteral, [
        rt.normalPointerType(rt.intTypeLiteral)
    ]),
    rt.normalPointerType(rt.intTypeLiteral)
], rt.intTypeLiteral);

// This is how you run a user-defined C++ procedure outside the interpretation loop.
setTimeout(() => {
    const gen = (function*() {
        const variable = rt.val(rt.intTypeLiteral, 321, true);
        const pVariableVal = rt.makeNormalPointerValue(variable);
        const v = rt.val(rt.normalPointerType(rt.intTypeLiteral), pVariableVal, false);
        const r = yield* _userCallback.v.target.v.target(rt, null, v);
        console.log(JSON.stringify(r));
    })();
    for (let v = gen.next(); !v.done; v = gen.next(v.value));
}, 1000);

That's great, thank you!