123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- 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
- }
|