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 }