diff options
Diffstat (limited to 'vendor/github.com/robertkrimen/otto/error.go')
-rw-r--r-- | vendor/github.com/robertkrimen/otto/error.go | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/vendor/github.com/robertkrimen/otto/error.go b/vendor/github.com/robertkrimen/otto/error.go new file mode 100644 index 000000000..41a5c10e7 --- /dev/null +++ b/vendor/github.com/robertkrimen/otto/error.go @@ -0,0 +1,252 @@ +package otto + +import ( + "errors" + "fmt" + + "github.com/robertkrimen/otto/file" +) + +type _exception struct { + value interface{} +} + +func newException(value interface{}) *_exception { + return &_exception{ + value: value, + } +} + +func (self *_exception) eject() interface{} { + value := self.value + self.value = nil // Prevent Go from holding on to the value, whatever it is + return value +} + +type _error struct { + name string + message string + trace []_frame + + offset int +} + +func (err _error) format() string { + if len(err.name) == 0 { + return err.message + } + if len(err.message) == 0 { + return err.name + } + return fmt.Sprintf("%s: %s", err.name, err.message) +} + +func (err _error) formatWithStack() string { + str := err.format() + "\n" + for _, frame := range err.trace { + str += " at " + frame.location() + "\n" + } + return str +} + +type _frame struct { + native bool + nativeFile string + nativeLine int + file *file.File + offset int + callee string +} + +var ( + nativeFrame = _frame{} +) + +type _at int + +func (fr _frame) location() string { + str := "<unknown>" + + switch { + case fr.native: + str = "<native code>" + if fr.nativeFile != "" && fr.nativeLine != 0 { + str = fmt.Sprintf("%s:%d", fr.nativeFile, fr.nativeLine) + } + case fr.file != nil: + if p := fr.file.Position(file.Idx(fr.offset)); p != nil { + path, line, column := p.Filename, p.Line, p.Column + + if path == "" { + path = "<anonymous>" + } + + str = fmt.Sprintf("%s:%d:%d", path, line, column) + } + } + + if fr.callee != "" { + str = fmt.Sprintf("%s (%s)", fr.callee, str) + } + + return str +} + +// An Error represents a runtime error, e.g. a TypeError, a ReferenceError, etc. +type Error struct { + _error +} + +// Error returns a description of the error +// +// TypeError: 'def' is not a function +// +func (err Error) Error() string { + return err.format() +} + +// String returns a description of the error and a trace of where the +// error occurred. +// +// TypeError: 'def' is not a function +// at xyz (<anonymous>:3:9) +// at <anonymous>:7:1/ +// +func (err Error) String() string { + return err.formatWithStack() +} + +func (err _error) describe(format string, in ...interface{}) string { + return fmt.Sprintf(format, in...) +} + +func (self _error) messageValue() Value { + if self.message == "" { + return Value{} + } + return toValue_string(self.message) +} + +func (rt *_runtime) typeErrorResult(throw bool) bool { + if throw { + panic(rt.panicTypeError()) + } + return false +} + +func newError(rt *_runtime, name string, stackFramesToPop int, in ...interface{}) _error { + err := _error{ + name: name, + offset: -1, + } + description := "" + length := len(in) + + if rt != nil && rt.scope != nil { + scope := rt.scope + + for i := 0; i < stackFramesToPop; i++ { + if scope.outer != nil { + scope = scope.outer + } + } + + frame := scope.frame + + if length > 0 { + if at, ok := in[length-1].(_at); ok { + in = in[0 : length-1] + if scope != nil { + frame.offset = int(at) + } + length-- + } + if length > 0 { + description, in = in[0].(string), in[1:] + } + } + + limit := rt.traceLimit + + err.trace = append(err.trace, frame) + if scope != nil { + for scope = scope.outer; scope != nil; scope = scope.outer { + if limit--; limit == 0 { + break + } + + if scope.frame.offset >= 0 { + err.trace = append(err.trace, scope.frame) + } + } + } + } else { + if length > 0 { + description, in = in[0].(string), in[1:] + } + } + err.message = err.describe(description, in...) + + return err +} + +func (rt *_runtime) panicTypeError(argumentList ...interface{}) *_exception { + return &_exception{ + value: newError(rt, "TypeError", 0, argumentList...), + } +} + +func (rt *_runtime) panicReferenceError(argumentList ...interface{}) *_exception { + return &_exception{ + value: newError(rt, "ReferenceError", 0, argumentList...), + } +} + +func (rt *_runtime) panicURIError(argumentList ...interface{}) *_exception { + return &_exception{ + value: newError(rt, "URIError", 0, argumentList...), + } +} + +func (rt *_runtime) panicSyntaxError(argumentList ...interface{}) *_exception { + return &_exception{ + value: newError(rt, "SyntaxError", 0, argumentList...), + } +} + +func (rt *_runtime) panicRangeError(argumentList ...interface{}) *_exception { + return &_exception{ + value: newError(rt, "RangeError", 0, argumentList...), + } +} + +func catchPanic(function func()) (err error) { + defer func() { + if caught := recover(); caught != nil { + if exception, ok := caught.(*_exception); ok { + caught = exception.eject() + } + switch caught := caught.(type) { + case *Error: + err = caught + return + case _error: + err = &Error{caught} + return + case Value: + if vl := caught._object(); vl != nil { + switch vl := vl.value.(type) { + case _error: + err = &Error{vl} + return + } + } + err = errors.New(caught.string()) + return + } + panic(caught) + } + }() + function() + return nil +} |