Open BenLubar opened 11 years ago
Yes, this is something that needs work. Do you have any examples of what you're trying to achieve?
FWIW, an example, schematically:
js helper
function mkfn(obj, fn) {
var oldfn = obj[fn];
obj[fn] = function() {
var v = oldfn.apply(this, arguments);
if (v.constructor == Error) {
throw v;
};
return v;
};
}
Go errf
func (vm *VM) errf(e error) (r js.Value) {
if e == nil {
return js.UndefinedValue()
}
r, err := vm.jsvm.Run(fmt.Sprintf("new Error('%s')", template.JSEscapeString(e.Error())))
if err != nil {
log.Fatal(err)
}
return
}
Example native binding
func (vm *VM) dbArrays(o *js.Object, db *dbm.DB) {
const (
obj = "db"
method = "arrays"
)
if err := o.Set(method, func(call js.FunctionCall) (r js.Value) {
defer func() {
if e := recover(); e != nil {
r = vm.errf(fmt.Errorf("%s.%s: %v", obj, method, e))
}
}()
a, err := db.Arrays()
if err != nil {
panic(err)
}
o, err := vm.jsvm.Object(`new Object();`)
if err != nil {
panic(err)
}
vm.array(o, &a)
return o.Value()
}); err != nil {
panic(err)
}
if _, err := vm.mkfn.Call(js.UndefinedValue(), o, method); err != nil {
panic(err)
}
}
Full code: https://github.com/cznic/tmp/blob/14d211b7818be2225f12f80fa299f0176ae771cb/g/glue.go
So what you're trying to do is throw a panic from the inner Go code to the other Go code?
No, the machinery allows the javascript clients to catch errors reported by Go native functions. On May 19, 2013 6:56 PM, "Robert Krimen" notifications@github.com wrote:
So what you're trying to do is initiate a panic from the inner Go code to the other Go code?
— Reply to this email directly or view it on GitHubhttps://github.com/robertkrimen/otto/issues/17#issuecomment-18120767 .
Yes, I think a Go panic should be visible within a try { ... } catch { ... }, probably as a PanicError, with no extra work necessary.
I also think a (special) piercing panic should be possible, something that can bypass JavaScript.
My example is not about Go panicking. It's about Go errors reporting. The particular implementation reads data from a disk based database. Read errors or format corruption may occur. The native funtion needs to throw a javascript exception in that case - instead of returning, say invalid data via the javasript wrapped native function - as that cannot support multiple return values, which Go can. On May 19, 2013 8:06 PM, "Robert Krimen" notifications@github.com wrote:
Yes, I think a Go panic should be visible within a try { ... } catch { ... }, probably as a PanicError, with no extra work necessary.
I also think a (special) piercing panic should be possible, something that can bypass JavaScript.
— Reply to this email directly or view it on GitHubhttps://github.com/robertkrimen/otto/issues/17#issuecomment-18121942 .
This is partially addressed in e2e79bb6974958a59a61c5c179bd3f88645bc36a
If you panic() something of type otto.Value, then it will behave as if you did a "throw" in JavaScript.
For example: panic(Otto.ToValue("Hello, World."))
is the same as: throw "Hello, World.";
This is further addressed in 83c56dd73d07607907bdc72e0d4998023855adc7
I've added a .Call method to Otto, which allows you to call arbitrary JavaScript and return the result.
You can now do something like this in your Go code:
value, _ := call.Otto.Call("new Error", nil, "Something bad happened.")
panic(value)
If you want, a possible convenience function is:
func throw(value Value, _ error) Value {
panic(value)
return UndefinedValue()
}
With these two, you can do:
return throw(call.Otto.Call("new Error", nil, "Something bad happened.")
And it'll throw that exception in the JavaScript environment like you would expect
Looks quite good to me. Thanks!
Be careful when doing a raw panic of a complex object:
panic(someObject)
panic(valueOfAnObject)
The above may cause memory issues with the Go runtime, see #59
If panic(someObject)
uses memory even after recover()
is called, that's a Go bug.
In a
func(otto.FunctionCall) otto.Value
, there is no (documented) way to throw a JavaScript exception that the caller can see.