github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/builtin_error.go (about)

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