github.com/dop251/goja@v0.0.0-20240220182346-e401ed450204/builtin_error.go (about) 1 package goja 2 3 import "github.com/dop251/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, ctor *Object) *Object { 180 o := r.newBaseObject(r.getErrorPrototype(), classObject) 181 o._putProp("message", stringEmpty, true, false, true) 182 o._putProp("name", name, true, false, true) 183 o._putProp("constructor", ctor, true, false, true) 184 return o.val 185 } 186 187 func (r *Runtime) getErrorPrototype() *Object { 188 ret := r.global.ErrorPrototype 189 if ret == nil { 190 ret = r.NewObject() 191 r.global.ErrorPrototype = ret 192 o := ret.self 193 o._putProp("message", stringEmpty, true, false, true) 194 o._putProp("name", stringError, true, false, true) 195 o._putProp("toString", r.newNativeFunc(r.error_toString, "toString", 0), true, false, true) 196 o._putProp("constructor", r.getError(), true, false, true) 197 } 198 return ret 199 } 200 201 func (r *Runtime) getError() *Object { 202 ret := r.global.Error 203 if ret == nil { 204 ret = &Object{runtime: r} 205 r.global.Error = ret 206 r.newNativeFuncConstruct(ret, r.builtin_Error, "Error", r.getErrorPrototype(), 1) 207 } 208 return ret 209 } 210 211 func (r *Runtime) getAggregateError() *Object { 212 ret := r.global.AggregateError 213 if ret == nil { 214 ret = &Object{runtime: r} 215 r.global.AggregateError = ret 216 r.newNativeFuncConstructProto(ret, r.builtin_AggregateError, "AggregateError", r.createErrorPrototype(stringAggregateError, ret), r.getError(), 2) 217 } 218 return ret 219 } 220 221 func (r *Runtime) getTypeError() *Object { 222 ret := r.global.TypeError 223 if ret == nil { 224 ret = &Object{runtime: r} 225 r.global.TypeError = ret 226 r.newNativeFuncConstructProto(ret, r.builtin_Error, "TypeError", r.createErrorPrototype(stringTypeError, ret), r.getError(), 1) 227 } 228 return ret 229 } 230 231 func (r *Runtime) getReferenceError() *Object { 232 ret := r.global.ReferenceError 233 if ret == nil { 234 ret = &Object{runtime: r} 235 r.global.ReferenceError = ret 236 r.newNativeFuncConstructProto(ret, r.builtin_Error, "ReferenceError", r.createErrorPrototype(stringReferenceError, ret), r.getError(), 1) 237 } 238 return ret 239 } 240 241 func (r *Runtime) getSyntaxError() *Object { 242 ret := r.global.SyntaxError 243 if ret == nil { 244 ret = &Object{runtime: r} 245 r.global.SyntaxError = ret 246 r.newNativeFuncConstructProto(ret, r.builtin_Error, "SyntaxError", r.createErrorPrototype(stringSyntaxError, ret), r.getError(), 1) 247 } 248 return ret 249 } 250 251 func (r *Runtime) getRangeError() *Object { 252 ret := r.global.RangeError 253 if ret == nil { 254 ret = &Object{runtime: r} 255 r.global.RangeError = ret 256 r.newNativeFuncConstructProto(ret, r.builtin_Error, "RangeError", r.createErrorPrototype(stringRangeError, ret), r.getError(), 1) 257 } 258 return ret 259 } 260 261 func (r *Runtime) getEvalError() *Object { 262 ret := r.global.EvalError 263 if ret == nil { 264 ret = &Object{runtime: r} 265 r.global.EvalError = ret 266 r.newNativeFuncConstructProto(ret, r.builtin_Error, "EvalError", r.createErrorPrototype(stringEvalError, ret), r.getError(), 1) 267 } 268 return ret 269 } 270 271 func (r *Runtime) getURIError() *Object { 272 ret := r.global.URIError 273 if ret == nil { 274 ret = &Object{runtime: r} 275 r.global.URIError = ret 276 r.newNativeFuncConstructProto(ret, r.builtin_Error, "URIError", r.createErrorPrototype(stringURIError, ret), r.getError(), 1) 277 } 278 return ret 279 } 280 281 func (r *Runtime) getGoError() *Object { 282 ret := r.global.GoError 283 if ret == nil { 284 ret = &Object{runtime: r} 285 r.global.GoError = ret 286 r.newNativeFuncConstructProto(ret, r.builtin_Error, "GoError", r.createErrorPrototype(stringGoError, ret), r.getError(), 1) 287 } 288 return ret 289 }