Abstract in-package panic/recover into a utility

This commit is contained in:
Cheer Xiao 2013-11-16 19:34:13 +08:00
parent 3accfa0cb6
commit 6227008696
5 changed files with 34 additions and 41 deletions

View File

@ -16,4 +16,3 @@
Python/Lua/... and/or error value handling a la golang)
- Support evaluating script
* All the TODO and XXX's in source :)
* Some utilities to faciliate in-package panic/recover

View File

@ -40,12 +40,12 @@ func NewEvaluator(envSlice []string) *Evaluator {
return ev
}
func (ev *Evaluator) Eval(name, text string, n parse.Node) (err *util.ContextualError) {
defer ev.recover(&err)
func (ev *Evaluator) Eval(name, text string, n parse.Node) (err error) {
defer util.Recover(&err)
defer ev.stopEval()
ev.name = name
ev.text = text
ev.evalChunk(n.(*parse.ListNode))
ev.stopEval()
return nil
}
@ -65,7 +65,7 @@ func (ev *Evaluator) pop() {
}
func (ev *Evaluator) errorfNode(n parse.Node, format string, args ...interface{}) {
panic(util.NewContextualError(ev.name, ev.text, int(n.Position()), format, args...))
util.Panic(util.NewContextualError(ev.name, ev.text, int(n.Position()), format, args...))
}
// errorf stops the evaluator. Its panic is supposed to be caught by recover.
@ -73,22 +73,6 @@ func (ev *Evaluator) errorf(format string, args...interface{}) {
ev.errorfNode(ev.nodes[len(ev.nodes) - 1], format, args...)
}
// recover is the handler that turns panics into returns from top level of
// evaluation function (currently ExecPipeline).
func (ev *Evaluator) recover(perr **util.ContextualError) {
r := recover()
if r == nil {
return
}
if _, ok := r.(*util.ContextualError); !ok {
panic(r)
}
if (ev != nil) {
ev.stopEval()
}
*perr = r.(*util.ContextualError)
}
func (ev *Evaluator) resolveVar(name string) Value {
val, ok := ev.globals[name]
if !ok {

View File

@ -47,13 +47,13 @@ func main() {
p := parse.NewParser(name)
tree, pe := p.Parse(lr.Line, false)
if pe != nil {
fmt.Print(pe.Pprint())
fmt.Print(pe.(*util.ContextualError).Pprint())
continue
}
ee := ev.Eval(name, lr.Line, tree.Root)
if ee != nil {
fmt.Println(ee.Pprint())
fmt.Println(ee.(*util.ContextualError).Pprint())
continue
}
}

View File

@ -102,7 +102,7 @@ func NewParser(name string) *Parser {
// errorf formats the error and terminates processing.
func (p *Parser) errorf(pos int, format string, args ...interface{}) {
p.Root = nil
panic(util.NewContextualError(p.Name, p.text, pos, format, args...))
util.Panic(util.NewContextualError(p.Name, p.text, pos, format, args...))
}
// expect consumes the next token and guarantees it has the required type.
@ -128,21 +128,6 @@ func (p *Parser) unexpected(token Item, context string) {
p.errorf(int(token.Pos), "unexpected %s in %s", token, context)
}
// recover is the handler that turns panics into returns from the top level of Parse.
func (p *Parser) recover(errp **util.ContextualError) {
e := recover()
if e == nil {
return
}
if _, ok := e.(*util.ContextualError); !ok {
panic(e)
}
if p != nil {
p.stopParse()
}
*errp = e.(*util.ContextualError)
}
// stopParse terminates parsing.
func (p *Parser) stopParse() {
p.lex = nil
@ -150,8 +135,9 @@ func (p *Parser) stopParse() {
// Parse parses the script to construct a representation of the script for
// execution.
func (p *Parser) Parse(text string, tab bool) (tree *Parser, err *util.ContextualError) {
defer p.recover(&err)
func (p *Parser) Parse(text string, tab bool) (tree *Parser, err error) {
defer util.Recover(&err)
defer p.stopParse()
p.text = text
p.tab = tab

24
util/exception.go Normal file
View File

@ -0,0 +1,24 @@
package util
// This file provides an exception-like mechanism.
// An exception wraps an error.
type exception struct {
err error
}
func Panic(err error) {
panic(exception{err})
}
func Recover(perr *error) {
r := recover()
if r == nil {
return
}
if exc, ok := r.(exception); ok {
*perr = exc.err
} else {
panic(r)
}
}