go.ketch.com/lib/goja@v0.0.1/builtin_error.go (about)

     1  package goja
     2  
     3  import "go.ketch.com/lib/goja/unistring"
     4  
     5  const propNameStack = "stack"
     6  
     7  type errorObject struct {
     8  	baseObject
     9  	stack          []StackFrame
    10  	stackPropAdded bool
    11  }
    12  
    13  func (e *errorObject) formatStack() valueString {
    14  	var b valueStringBuilder
    15  	if name := e.getStr("name", nil); name != nil {
    16  		b.WriteString(name.toString())
    17  		b.WriteRune('\n')
    18  	} else {
    19  		b.WriteASCII("Error\n")
    20  	}
    21  
    22  	for _, frame := range e.stack {
    23  		b.WriteASCII("\tat ")
    24  		frame.WriteToValueBuilder(&b)
    25  		b.WriteRune('\n')
    26  	}
    27  	return b.String()
    28  }
    29  
    30  func (e *errorObject) addStackProp() Value {
    31  	if !e.stackPropAdded {
    32  		res := e._putProp(propNameStack, e.formatStack(), true, false, true)
    33  		if len(e.propNames) > 1 {
    34  			// reorder property names to ensure 'stack' is the first one
    35  			copy(e.propNames[1:], e.propNames)
    36  			e.propNames[0] = propNameStack
    37  		}
    38  		e.stackPropAdded = true
    39  		return res
    40  	}
    41  	return nil
    42  }
    43  
    44  func (e *errorObject) getStr(p unistring.String, receiver Value) Value {
    45  	return e.getStrWithOwnProp(e.getOwnPropStr(p), p, receiver)
    46  }
    47  
    48  func (e *errorObject) getOwnPropStr(name unistring.String) Value {
    49  	res := e.baseObject.getOwnPropStr(name)
    50  	if res == nil && name == propNameStack {
    51  		return e.addStackProp()
    52  	}
    53  
    54  	return res
    55  }
    56  
    57  func (e *errorObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
    58  	if name == propNameStack {
    59  		e.addStackProp()
    60  	}
    61  	return e.baseObject.setOwnStr(name, val, throw)
    62  }
    63  
    64  func (e *errorObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
    65  	return e._setForeignStr(name, e.getOwnPropStr(name), val, receiver, throw)
    66  }
    67  
    68  func (e *errorObject) deleteStr(name unistring.String, throw bool) bool {
    69  	if name == propNameStack {
    70  		e.addStackProp()
    71  	}
    72  	return e.baseObject.deleteStr(name, throw)
    73  }
    74  
    75  func (e *errorObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
    76  	if name == propNameStack {
    77  		e.addStackProp()
    78  	}
    79  	return e.baseObject.defineOwnPropertyStr(name, desc, throw)
    80  }
    81  
    82  func (e *errorObject) hasOwnPropertyStr(name unistring.String) bool {
    83  	if e.baseObject.hasOwnPropertyStr(name) {
    84  		return true
    85  	}
    86  
    87  	return name == propNameStack && !e.stackPropAdded
    88  }
    89  
    90  func (e *errorObject) stringKeys(all bool, accum []Value) []Value {
    91  	if all && !e.stackPropAdded {
    92  		accum = append(accum, asciiString(propNameStack))
    93  	}
    94  	return e.baseObject.stringKeys(all, accum)
    95  }
    96  
    97  func (e *errorObject) iterateStringKeys() iterNextFunc {
    98  	e.addStackProp()
    99  	return e.baseObject.iterateStringKeys()
   100  }
   101  
   102  func (e *errorObject) init() {
   103  	e.baseObject.init()
   104  	vm := e.val.runtime.vm
   105  	e.stack = vm.captureStack(make([]StackFrame, 0, len(vm.callStack)+1), 0)
   106  }
   107  
   108  func (r *Runtime) newErrorObject(proto *Object, class string) *errorObject {
   109  	obj := &Object{runtime: r}
   110  	o := &errorObject{
   111  		baseObject: baseObject{
   112  			class:      class,
   113  			val:        obj,
   114  			extensible: true,
   115  			prototype:  proto,
   116  		},
   117  	}
   118  	obj.self = o
   119  	o.init()
   120  	return o
   121  }
   122  
   123  func (r *Runtime) builtin_Error(args []Value, proto *Object) *Object {
   124  	obj := r.newErrorObject(proto, classError)
   125  	if len(args) > 0 && args[0] != _undefined {
   126  		obj._putProp("message", args[0], true, false, true)
   127  	}
   128  	return obj.val
   129  }
   130  
   131  func (r *Runtime) builtin_AggregateError(args []Value, proto *Object) *Object {
   132  	obj := r.newErrorObject(proto, classAggError)
   133  	if len(args) > 1 && args[1] != nil && args[1] != _undefined {
   134  		obj._putProp("message", args[1].toString(), true, false, true)
   135  	}
   136  	var errors []Value
   137  	if len(args) > 0 {
   138  		errors = r.iterableToList(args[0], nil)
   139  	}
   140  	obj._putProp("errors", r.newArrayValues(errors), true, false, true)
   141  
   142  	return obj.val
   143  }
   144  
   145  func (r *Runtime) createErrorPrototype(name valueString) *Object {
   146  	o := r.newBaseObject(r.global.ErrorPrototype, classObject)
   147  	o._putProp("message", stringEmpty, true, false, true)
   148  	o._putProp("name", name, true, false, true)
   149  	return o.val
   150  }
   151  
   152  func (r *Runtime) initErrors() {
   153  	r.global.ErrorPrototype = r.NewObject()
   154  	o := r.global.ErrorPrototype.self
   155  	o._putProp("message", stringEmpty, true, false, true)
   156  	o._putProp("name", stringError, true, false, true)
   157  	o._putProp("toString", r.newNativeFunc(r.error_toString, nil, "toString", nil, 0), true, false, true)
   158  
   159  	r.global.Error = r.newNativeFuncConstruct(r.builtin_Error, "Error", r.global.ErrorPrototype, 1)
   160  	r.addToGlobal("Error", r.global.Error)
   161  
   162  	r.global.AggregateErrorPrototype = r.createErrorPrototype(stringAggregateError)
   163  	r.global.AggregateError = r.newNativeFuncConstructProto(r.builtin_AggregateError, "AggregateError", r.global.AggregateErrorPrototype, r.global.Error, 2)
   164  	r.addToGlobal("AggregateError", r.global.AggregateError)
   165  
   166  	r.global.TypeErrorPrototype = r.createErrorPrototype(stringTypeError)
   167  
   168  	r.global.TypeError = r.newNativeFuncConstructProto(r.builtin_Error, "TypeError", r.global.TypeErrorPrototype, r.global.Error, 1)
   169  	r.addToGlobal("TypeError", r.global.TypeError)
   170  
   171  	r.global.ReferenceErrorPrototype = r.createErrorPrototype(stringReferenceError)
   172  
   173  	r.global.ReferenceError = r.newNativeFuncConstructProto(r.builtin_Error, "ReferenceError", r.global.ReferenceErrorPrototype, r.global.Error, 1)
   174  	r.addToGlobal("ReferenceError", r.global.ReferenceError)
   175  
   176  	r.global.SyntaxErrorPrototype = r.createErrorPrototype(stringSyntaxError)
   177  
   178  	r.global.SyntaxError = r.newNativeFuncConstructProto(r.builtin_Error, "SyntaxError", r.global.SyntaxErrorPrototype, r.global.Error, 1)
   179  	r.addToGlobal("SyntaxError", r.global.SyntaxError)
   180  
   181  	r.global.RangeErrorPrototype = r.createErrorPrototype(stringRangeError)
   182  
   183  	r.global.RangeError = r.newNativeFuncConstructProto(r.builtin_Error, "RangeError", r.global.RangeErrorPrototype, r.global.Error, 1)
   184  	r.addToGlobal("RangeError", r.global.RangeError)
   185  
   186  	r.global.EvalErrorPrototype = r.createErrorPrototype(stringEvalError)
   187  	o = r.global.EvalErrorPrototype.self
   188  	o._putProp("name", stringEvalError, true, false, true)
   189  
   190  	r.global.EvalError = r.newNativeFuncConstructProto(r.builtin_Error, "EvalError", r.global.EvalErrorPrototype, r.global.Error, 1)
   191  	r.addToGlobal("EvalError", r.global.EvalError)
   192  
   193  	r.global.URIErrorPrototype = r.createErrorPrototype(stringURIError)
   194  
   195  	r.global.URIError = r.newNativeFuncConstructProto(r.builtin_Error, "URIError", r.global.URIErrorPrototype, r.global.Error, 1)
   196  	r.addToGlobal("URIError", r.global.URIError)
   197  
   198  	r.global.GoErrorPrototype = r.createErrorPrototype(stringGoError)
   199  
   200  	r.global.GoError = r.newNativeFuncConstructProto(r.builtin_Error, "GoError", r.global.GoErrorPrototype, r.global.Error, 1)
   201  	r.addToGlobal("GoError", r.global.GoError)
   202  }