I would like to create a "re-entrant" native method, that is, I'm looking to be able to have a script call a native function, which then Eval()'s another script.
This is possible, however, if that native method is called using Object.Call or Value.Call, the This pointer is not updated, resulting in Eval() using the caller's this, not the callee's.
Here's a minimal example that demonstrates the issue
package main
import (
"fmt"
"github.com/robertkrimen/otto"
)
func main() {
var err error
v := otto.New()
// Create an object "x", with a field "y" and a method "foo" which returns this and this.y using Eval()
x, err := v.Call("new Object", nil)
if err != nil {
panic(err)
}
err = x.Object().Set("y", 1)
if err != nil {
panic(err)
}
err = x.Object().Set("foo", func(call otto.FunctionCall) otto.Value {
fmt.Print("[debug] this=")
fmt.Println(call.This.Export())
fmt.Print("[debug] this.y=")
fmt.Println(call.This.Object().Get("y"))
out, err := v.Eval("[this, this.y]")
if err != nil {
panic(err)
}
return out
})
if err != nil {
panic(err)
}
// Now call x.foo() in each possible way
fmt.Println("--- Object.Call ---")
out, err := x.Object().Call("foo")
out2, err2 := out.Export()
fmt.Print("[output] foo()=")
fmt.Println(out2, err, err2)
// --- Object.Call ---
// [debug] this=map[foo:map[] y:1] <nil>
// [debug] this.y=1 <nil>
// [output] foo()=[map[console:map[]] <nil>] <nil> <nil> // this is not set correctly
fmt.Println("--- Value.Call ---")
foo2, err := x.Object().Get("foo")
if err != nil {
panic(err)
}
out, err = foo2.Call(x)
out2, err2 = out.Export()
fmt.Print("[output] foo()=")
fmt.Println(out2, err, err2)
// --- Value.Call ---
// [debug] this=map[foo:map[] y:1] <nil>
// [debug] this.y=1 <nil>
// [output] foo()=[map[console:map[]] <nil>] <nil> <nil> // this is not set correctly
fmt.Println("--- Otto.Call ---")
err = v.Set("x", x)
if err != nil {
panic(err)
}
out, err = v.Call("x.foo", nil)
out2, err2 = out.Export()
fmt.Print("[output] foo()=")
fmt.Println(out2, err, err2)
// --- Otto.Call ---
// [debug] this=map[foo:map[] y:1] <nil>
// [debug] this.y=1 <nil>
// [output] foo()=[map[foo:map[] y:1] 1] <nil> <nil> // this is correctly!
}
I would like to create a "re-entrant" native method, that is, I'm looking to be able to have a script call a native function, which then
Eval()'s another script.This is possible, however, if that native method is called using
Object.CallorValue.Call, theThispointer is not updated, resulting inEval()using the caller'sthis, not the callee's.Here's a minimal example that demonstrates the issue