builtin_error.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  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].ToString(), true, false, true)
  106. }
  107. if len(args) > 1 && args[1] != _undefined {
  108. if options, ok := args[1].(*Object); ok {
  109. if options.hasProperty(asciiString("cause")) {
  110. obj.defineOwnPropertyStr("cause", PropertyDescriptor{
  111. Writable: FLAG_TRUE,
  112. Enumerable: FLAG_FALSE,
  113. Configurable: FLAG_TRUE,
  114. Value: options.Get("cause"),
  115. }, true)
  116. }
  117. }
  118. }
  119. return obj.val
  120. }
  121. func (r *Runtime) builtin_AggregateError(args []Value, proto *Object) *Object {
  122. obj := r.newErrorObject(proto, classError)
  123. if len(args) > 1 && args[1] != nil && args[1] != _undefined {
  124. obj._putProp("message", args[1].toString(), true, false, true)
  125. }
  126. var errors []Value
  127. if len(args) > 0 {
  128. errors = r.iterableToList(args[0], nil)
  129. }
  130. obj._putProp("errors", r.newArrayValues(errors), true, false, true)
  131. if len(args) > 2 && args[2] != _undefined {
  132. if options, ok := args[2].(*Object); ok {
  133. if options.hasProperty(asciiString("cause")) {
  134. obj.defineOwnPropertyStr("cause", PropertyDescriptor{
  135. Writable: FLAG_TRUE,
  136. Enumerable: FLAG_FALSE,
  137. Configurable: FLAG_TRUE,
  138. Value: options.Get("cause"),
  139. }, true)
  140. }
  141. }
  142. }
  143. return obj.val
  144. }
  145. func writeErrorString(sb *StringBuilder, obj *Object) String {
  146. var nameStr, msgStr String
  147. name := obj.self.getStr("name", nil)
  148. if name == nil || name == _undefined {
  149. nameStr = asciiString("Error")
  150. } else {
  151. nameStr = name.toString()
  152. }
  153. msg := obj.self.getStr("message", nil)
  154. if msg == nil || msg == _undefined {
  155. msgStr = stringEmpty
  156. } else {
  157. msgStr = msg.toString()
  158. }
  159. if nameStr.Length() == 0 {
  160. return msgStr
  161. }
  162. if msgStr.Length() == 0 {
  163. return nameStr
  164. }
  165. sb.WriteString(nameStr)
  166. sb.WriteString(asciiString(": "))
  167. sb.WriteString(msgStr)
  168. return nil
  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. func (r *Runtime) createErrorPrototype(name String, ctor *Object) *Object {
  179. o := r.newBaseObject(r.getErrorPrototype(), classObject)
  180. o._putProp("message", stringEmpty, true, false, true)
  181. o._putProp("name", name, true, false, true)
  182. o._putProp("constructor", ctor, true, false, true)
  183. return o.val
  184. }
  185. func (r *Runtime) getErrorPrototype() *Object {
  186. ret := r.global.ErrorPrototype
  187. if ret == nil {
  188. ret = r.NewObject()
  189. r.global.ErrorPrototype = ret
  190. o := ret.self
  191. o._putProp("message", stringEmpty, true, false, true)
  192. o._putProp("name", stringError, true, false, true)
  193. o._putProp("toString", r.newNativeFunc(r.error_toString, "toString", 0), true, false, true)
  194. o._putProp("constructor", r.getError(), true, false, true)
  195. }
  196. return ret
  197. }
  198. func (r *Runtime) getError() *Object {
  199. ret := r.global.Error
  200. if ret == nil {
  201. ret = &Object{runtime: r}
  202. r.global.Error = ret
  203. r.newNativeFuncConstruct(ret, r.builtin_Error, "Error", r.getErrorPrototype(), 1)
  204. }
  205. return ret
  206. }
  207. func (r *Runtime) getAggregateError() *Object {
  208. ret := r.global.AggregateError
  209. if ret == nil {
  210. ret = &Object{runtime: r}
  211. r.global.AggregateError = ret
  212. r.newNativeFuncConstructProto(ret, r.builtin_AggregateError, "AggregateError", r.createErrorPrototype(stringAggregateError, ret), r.getError(), 2)
  213. }
  214. return ret
  215. }
  216. func (r *Runtime) getTypeError() *Object {
  217. ret := r.global.TypeError
  218. if ret == nil {
  219. ret = &Object{runtime: r}
  220. r.global.TypeError = ret
  221. r.newNativeFuncConstructProto(ret, r.builtin_Error, "TypeError", r.createErrorPrototype(stringTypeError, ret), r.getError(), 1)
  222. }
  223. return ret
  224. }
  225. func (r *Runtime) getReferenceError() *Object {
  226. ret := r.global.ReferenceError
  227. if ret == nil {
  228. ret = &Object{runtime: r}
  229. r.global.ReferenceError = ret
  230. r.newNativeFuncConstructProto(ret, r.builtin_Error, "ReferenceError", r.createErrorPrototype(stringReferenceError, ret), r.getError(), 1)
  231. }
  232. return ret
  233. }
  234. func (r *Runtime) getSyntaxError() *Object {
  235. ret := r.global.SyntaxError
  236. if ret == nil {
  237. ret = &Object{runtime: r}
  238. r.global.SyntaxError = ret
  239. r.newNativeFuncConstructProto(ret, r.builtin_Error, "SyntaxError", r.createErrorPrototype(stringSyntaxError, ret), r.getError(), 1)
  240. }
  241. return ret
  242. }
  243. func (r *Runtime) getRangeError() *Object {
  244. ret := r.global.RangeError
  245. if ret == nil {
  246. ret = &Object{runtime: r}
  247. r.global.RangeError = ret
  248. r.newNativeFuncConstructProto(ret, r.builtin_Error, "RangeError", r.createErrorPrototype(stringRangeError, ret), r.getError(), 1)
  249. }
  250. return ret
  251. }
  252. func (r *Runtime) getEvalError() *Object {
  253. ret := r.global.EvalError
  254. if ret == nil {
  255. ret = &Object{runtime: r}
  256. r.global.EvalError = ret
  257. r.newNativeFuncConstructProto(ret, r.builtin_Error, "EvalError", r.createErrorPrototype(stringEvalError, ret), r.getError(), 1)
  258. }
  259. return ret
  260. }
  261. func (r *Runtime) getURIError() *Object {
  262. ret := r.global.URIError
  263. if ret == nil {
  264. ret = &Object{runtime: r}
  265. r.global.URIError = ret
  266. r.newNativeFuncConstructProto(ret, r.builtin_Error, "URIError", r.createErrorPrototype(stringURIError, ret), r.getError(), 1)
  267. }
  268. return ret
  269. }
  270. func (r *Runtime) getGoError() *Object {
  271. ret := r.global.GoError
  272. if ret == nil {
  273. ret = &Object{runtime: r}
  274. r.global.GoError = ret
  275. r.newNativeFuncConstructProto(ret, r.builtin_Error, "GoError", r.createErrorPrototype(stringGoError, ret), r.getError(), 1)
  276. }
  277. return ret
  278. }