builtin_error.go 7.5 KB

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