builtin_error.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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() valueString {
  10. var b valueStringBuilder
  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 *valueStringBuilder, obj *Object) valueString {
  122. var nameStr, msgStr valueString
  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 valueStringBuilder
  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 valueString) *Object {
  155. o := r.newBaseObject(r.global.ErrorPrototype, classObject)
  156. o._putProp("message", stringEmpty, true, false, true)
  157. o._putProp("name", name, true, false, true)
  158. return o.val
  159. }
  160. func (r *Runtime) initErrors() {
  161. r.global.ErrorPrototype = r.NewObject()
  162. o := r.global.ErrorPrototype.self
  163. o._putProp("message", stringEmpty, true, false, true)
  164. o._putProp("name", stringError, true, false, true)
  165. o._putProp("toString", r.newNativeFunc(r.error_toString, nil, "toString", nil, 0), true, false, true)
  166. r.global.Error = r.newNativeFuncConstruct(r.builtin_Error, "Error", r.global.ErrorPrototype, 1)
  167. r.addToGlobal("Error", r.global.Error)
  168. r.global.AggregateErrorPrototype = r.createErrorPrototype(stringAggregateError)
  169. r.global.AggregateError = r.newNativeFuncConstructProto(r.builtin_AggregateError, "AggregateError", r.global.AggregateErrorPrototype, r.global.Error, 2)
  170. r.addToGlobal("AggregateError", r.global.AggregateError)
  171. r.global.TypeErrorPrototype = r.createErrorPrototype(stringTypeError)
  172. r.global.TypeError = r.newNativeFuncConstructProto(r.builtin_Error, "TypeError", r.global.TypeErrorPrototype, r.global.Error, 1)
  173. r.addToGlobal("TypeError", r.global.TypeError)
  174. r.global.ReferenceErrorPrototype = r.createErrorPrototype(stringReferenceError)
  175. r.global.ReferenceError = r.newNativeFuncConstructProto(r.builtin_Error, "ReferenceError", r.global.ReferenceErrorPrototype, r.global.Error, 1)
  176. r.addToGlobal("ReferenceError", r.global.ReferenceError)
  177. r.global.SyntaxErrorPrototype = r.createErrorPrototype(stringSyntaxError)
  178. r.global.SyntaxError = r.newNativeFuncConstructProto(r.builtin_Error, "SyntaxError", r.global.SyntaxErrorPrototype, r.global.Error, 1)
  179. r.addToGlobal("SyntaxError", r.global.SyntaxError)
  180. r.global.RangeErrorPrototype = r.createErrorPrototype(stringRangeError)
  181. r.global.RangeError = r.newNativeFuncConstructProto(r.builtin_Error, "RangeError", r.global.RangeErrorPrototype, r.global.Error, 1)
  182. r.addToGlobal("RangeError", r.global.RangeError)
  183. r.global.EvalErrorPrototype = r.createErrorPrototype(stringEvalError)
  184. o = r.global.EvalErrorPrototype.self
  185. o._putProp("name", stringEvalError, true, false, true)
  186. r.global.EvalError = r.newNativeFuncConstructProto(r.builtin_Error, "EvalError", r.global.EvalErrorPrototype, r.global.Error, 1)
  187. r.addToGlobal("EvalError", r.global.EvalError)
  188. r.global.URIErrorPrototype = r.createErrorPrototype(stringURIError)
  189. r.global.URIError = r.newNativeFuncConstructProto(r.builtin_Error, "URIError", r.global.URIErrorPrototype, r.global.Error, 1)
  190. r.addToGlobal("URIError", r.global.URIError)
  191. r.global.GoErrorPrototype = r.createErrorPrototype(stringGoError)
  192. r.global.GoError = r.newNativeFuncConstructProto(r.builtin_Error, "GoError", r.global.GoErrorPrototype, r.global.Error, 1)
  193. r.addToGlobal("GoError", r.global.GoError)
  194. }