Skip to content
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

Call go functions expecting a func() directly, call arbitrary go functions unprepared for JS (no map as the sole parameter) #126

Open
sinni800 opened this issue May 29, 2015 · 1 comment

Comments

@sinni800
Copy link

I wonder if Otto could have a little wrapper function that would convert a function() to a go func(), regardless of parameters. I think this could be a problem with go's static nature and that there is nothing like generics, though (Reflect's call should still make this possible, I presume.)... Also probably doesn't help that JS has no function parameter and return value typing. But couldn't one just assume that it will be alright and panic if it doesn't fit?

Go:

func someevent(f func(e EvArgs)) { // code }
// give to JavaScript in some way, like set()

js:

someevent(function(e) { // do }})

EDIT: I forgot Otto does part of this, it does call arbitrary go functions with arbitrary Parameters, the function "bridge" is the only part missing.

@sinni800
Copy link
Author

I have been trying to do this myself, this is what I have.

js.Run(`
    function t() {
        var b = "hi"
        cf(thefunc, function(input) {return b + input});
    }
    t()
`)

thefunc is

func thefunc(x func(string) string) {

}

the "cf" (immediate) function is trying this:

func cf(in otto.FunctionCall) otto.Value {
    destfunc, _ := in.Argument(0).Export()
    destfuncrefl := reflect.ValueOf(destfunc)
    fmt.Println(destfunc)
}

Though destfunc comes out as an empty map, not as the actual go function... Anyone know something? in.Argument(0) is function () { [native code] } from the JS perspective.

I think my problem is that I want the original go value back...

EDIT: Going the "long" way by always having a type with the methods on won't make the methods unusable... I managed to create a function wrapper (error prone, no error checking in this preliminary version!)

func cf(in otto.FunctionCall) otto.Value {
    destobj, _ := in.Argument(0).Export()
    destobjrefl := reflect.ValueOf(destobj)
    destfunc, _ := destobjrefl.Type().MethodByName(in.Argument(1).String())
    destfuncrefl := destfunc.Func
    destfuncreflt := destfunc.Type

    arglist := make([]reflect.Value, 0, 0)

    arglist = append(arglist, destobjrefl)

    for x := 1; x < destfuncreflt.NumIn() ; x++ {
        if destfuncreflt.In(x).Kind() == reflect.Func {
            y := x
            f := reflect.MakeFunc(destfuncreflt.In(x), func (args []reflect.Value) []reflect.Value {
                funcargs := make([]interface{}, 0, 0)
                for _, v := range args {
                    val, _ := js.ToValue(v.Interface())
                    funcargs = append(funcargs, val)
                }
                outargs := make([]reflect.Value, 0)

                outarg, err := in.Argument(1+y).Call(otto.UndefinedValue(), funcargs...)

                fmt.Println(in.Argument(1+y), err)

                outarggo, _ := outarg.Export()



                if !outarg.IsUndefined(){
                    outargs = append(outargs, reflect.ValueOf(outarggo))
                }

                return outargs
            })
            arglist = append(arglist, f)
        } else {
            i, _ := in.Argument(1+x).Export()
            y := reflect.ValueOf(i)
            arglist = append(arglist, y)
        }
    }

    fmt.Println(len(arglist))
    ret := destfuncrefl.Call(arglist)
    retnorm := make([]interface{}, 0, 0)

    for _, val := range ret {
        retnorm = append(retnorm, val.Interface())
    }

    ret2, _ := js.ToValue(retnorm)

    return ret2
}

Call like this in Javascript:

cf(thefunc, "Thefunc", function(input) {return input});

First parameter is the value the function is on, second parameter is the Name of the function, third parameter and on are all parameters the function expects. If any parameter has the wrong type as it arrives in Go-land, it will panic since I didn't put any error checking in... It will also panic if a parameter was omitted. More like a proof of concept that needs work, I know, but might be a cool start.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants