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

ng: implement recover #137

Open
sbinet opened this issue Dec 8, 2017 · 1 comment
Open

ng: implement recover #137

sbinet opened this issue Dec 8, 2017 · 1 comment

Comments

@sbinet
Copy link
Collaborator

sbinet commented Dec 8, 2017

No description provided.

@sbinet
Copy link
Collaborator Author

sbinet commented Jan 7, 2018

well... recover is tricky.

I started like this:

diff --git a/eval/eval.go b/eval/eval.go
index 9967e69..daff267 100644
--- a/eval/eval.go
+++ b/eval/eval.go
@@ -45,8 +46,10 @@ type Scope struct {
 
        Label bool
 
-       fct    string     // function name if this is a function scope
-       defers []deferCtx // LIFO-list of defers to run
+       fct       string     // function name if this is a function scope
+       defers    []deferCtx // LIFO-list of defers to run
+       panicking bool       // whether this function is in the middle of a panic
+       panic     interface{}
 }
 
 func (s *Scope) Lookup(name string) reflect.Value {
@@ -72,6 +75,22 @@ type deferCtx struct {
        Args []reflect.Value
 }
 
+func (d deferCtx) run(s *Scope) {
+       var ok bool
+       defer func() {
+               if ok {
+                       return
+               }
+               // deferred call panicked
+               s.panicking = true
+               s.panic = recover()
+       }()
+       d.Func.Call(d.Args)
+       ok = true
+}
+
@@ -1843,16 +1883,42 @@ func (p *Program) evalFuncLiteral(e *expr.FuncLiteral, recvt *tipe.Named) reflec
                if fscope.defers != nil {
                        fscope.defers = fscope.defers[:0]
                }
+               fscope.panicking = false
+               fscope.panic = nil
+
+               defer func() {
+                       for i := len(fscope.defers) - 1; i >= 0; i-- {
+                               d := fscope.defers[i]
+                               d.run(fscope)
+                       }
+                       if fscope.panicking {
+                               panic(Panic{fscope.panic})
+                       }
+               }()
 
                resValues := p.evalStmt(e.Body.(*stmt.Block))
                for i, v := range resValues {
                        res[i].Set(v)
                }
 
-               for i := len(fscope.defers) - 1; i >= 0; i-- {
-                       d := fscope.defers[i]
-                       d.Func.Call(d.Args)
-               }
                return res
        })
        return fn

but for this to work, I would need to have access to the current p.Cur.funcScope() from inside the interpreter's panic and recover functions (added via the addUniverse closure at the beginning of eval.go.)

one way to address this (I guess) would be to only put placeholders in addUniverse for both panic and recover, and modify prepCall to inject the func-closures for those 2 (that would close around p.Cur.funcScope)

what do you think @crawshaw ?

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

No branches or pull requests

1 participant