builtin_object.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. package otto
  2. import (
  3. "fmt"
  4. )
  5. // Object
  6. func builtinObject(call FunctionCall) Value {
  7. value := call.Argument(0)
  8. switch value.kind {
  9. case valueUndefined, valueNull:
  10. return objectValue(call.runtime.newObject())
  11. }
  12. return objectValue(call.runtime.toObject(value))
  13. }
  14. func builtinNewObject(obj *object, argumentList []Value) Value {
  15. value := valueOfArrayIndex(argumentList, 0)
  16. switch value.kind {
  17. case valueNull, valueUndefined:
  18. case valueNumber, valueString, valueBoolean:
  19. return objectValue(obj.runtime.toObject(value))
  20. case valueObject:
  21. return value
  22. default:
  23. }
  24. return objectValue(obj.runtime.newObject())
  25. }
  26. func builtinObjectValueOf(call FunctionCall) Value {
  27. return objectValue(call.thisObject())
  28. }
  29. func builtinObjectHasOwnProperty(call FunctionCall) Value {
  30. propertyName := call.Argument(0).string()
  31. thisObject := call.thisObject()
  32. return boolValue(thisObject.hasOwnProperty(propertyName))
  33. }
  34. func builtinObjectIsPrototypeOf(call FunctionCall) Value {
  35. value := call.Argument(0)
  36. if !value.IsObject() {
  37. return falseValue
  38. }
  39. prototype := call.toObject(value).prototype
  40. thisObject := call.thisObject()
  41. for prototype != nil {
  42. if thisObject == prototype {
  43. return trueValue
  44. }
  45. prototype = prototype.prototype
  46. }
  47. return falseValue
  48. }
  49. func builtinObjectPropertyIsEnumerable(call FunctionCall) Value {
  50. propertyName := call.Argument(0).string()
  51. thisObject := call.thisObject()
  52. prop := thisObject.getOwnProperty(propertyName)
  53. if prop != nil && prop.enumerable() {
  54. return trueValue
  55. }
  56. return falseValue
  57. }
  58. func builtinObjectToString(call FunctionCall) Value {
  59. var result string
  60. switch {
  61. case call.This.IsUndefined():
  62. result = "[object Undefined]"
  63. case call.This.IsNull():
  64. result = "[object Null]"
  65. default:
  66. result = fmt.Sprintf("[object %s]", call.thisObject().class)
  67. }
  68. return stringValue(result)
  69. }
  70. func builtinObjectToLocaleString(call FunctionCall) Value {
  71. toString := call.thisObject().get("toString")
  72. if !toString.isCallable() {
  73. panic(call.runtime.panicTypeError("Object.toLocaleString %q is not callable", toString))
  74. }
  75. return toString.call(call.runtime, call.This)
  76. }
  77. func builtinObjectGetPrototypeOf(call FunctionCall) Value {
  78. val := call.Argument(0)
  79. obj := val.object()
  80. if obj == nil {
  81. panic(call.runtime.panicTypeError("Object.GetPrototypeOf is nil"))
  82. }
  83. if obj.prototype == nil {
  84. return nullValue
  85. }
  86. return objectValue(obj.prototype)
  87. }
  88. func builtinObjectGetOwnPropertyDescriptor(call FunctionCall) Value {
  89. val := call.Argument(0)
  90. obj := val.object()
  91. if obj == nil {
  92. panic(call.runtime.panicTypeError("Object.GetOwnPropertyDescriptor is nil"))
  93. }
  94. name := call.Argument(1).string()
  95. descriptor := obj.getOwnProperty(name)
  96. if descriptor == nil {
  97. return Value{}
  98. }
  99. return objectValue(call.runtime.fromPropertyDescriptor(*descriptor))
  100. }
  101. func builtinObjectDefineProperty(call FunctionCall) Value {
  102. val := call.Argument(0)
  103. obj := val.object()
  104. if obj == nil {
  105. panic(call.runtime.panicTypeError("Object.DefineProperty is nil"))
  106. }
  107. name := call.Argument(1).string()
  108. descriptor := toPropertyDescriptor(call.runtime, call.Argument(2))
  109. obj.defineOwnProperty(name, descriptor, true)
  110. return val
  111. }
  112. func builtinObjectDefineProperties(call FunctionCall) Value {
  113. val := call.Argument(0)
  114. obj := val.object()
  115. if obj == nil {
  116. panic(call.runtime.panicTypeError("Object.DefineProperties is nil"))
  117. }
  118. properties := call.runtime.toObject(call.Argument(1))
  119. properties.enumerate(false, func(name string) bool {
  120. descriptor := toPropertyDescriptor(call.runtime, properties.get(name))
  121. obj.defineOwnProperty(name, descriptor, true)
  122. return true
  123. })
  124. return val
  125. }
  126. func builtinObjectCreate(call FunctionCall) Value {
  127. prototypeValue := call.Argument(0)
  128. if !prototypeValue.IsNull() && !prototypeValue.IsObject() {
  129. panic(call.runtime.panicTypeError("Object.Create is nil"))
  130. }
  131. obj := call.runtime.newObject()
  132. obj.prototype = prototypeValue.object()
  133. propertiesValue := call.Argument(1)
  134. if propertiesValue.IsDefined() {
  135. properties := call.runtime.toObject(propertiesValue)
  136. properties.enumerate(false, func(name string) bool {
  137. descriptor := toPropertyDescriptor(call.runtime, properties.get(name))
  138. obj.defineOwnProperty(name, descriptor, true)
  139. return true
  140. })
  141. }
  142. return objectValue(obj)
  143. }
  144. func builtinObjectIsExtensible(call FunctionCall) Value {
  145. val := call.Argument(0)
  146. if obj := val.object(); obj != nil {
  147. return boolValue(obj.extensible)
  148. }
  149. panic(call.runtime.panicTypeError("Object.IsExtensible is nil"))
  150. }
  151. func builtinObjectPreventExtensions(call FunctionCall) Value {
  152. val := call.Argument(0)
  153. if obj := val.object(); obj != nil {
  154. obj.extensible = false
  155. return val
  156. }
  157. panic(call.runtime.panicTypeError("Object.PreventExtensions is nil"))
  158. }
  159. func builtinObjectIsSealed(call FunctionCall) Value {
  160. val := call.Argument(0)
  161. if obj := val.object(); obj != nil {
  162. if obj.extensible {
  163. return boolValue(false)
  164. }
  165. result := true
  166. obj.enumerate(true, func(name string) bool {
  167. prop := obj.getProperty(name)
  168. if prop.configurable() {
  169. result = false
  170. }
  171. return true
  172. })
  173. return boolValue(result)
  174. }
  175. panic(call.runtime.panicTypeError("Object.IsSealed is nil"))
  176. }
  177. func builtinObjectSeal(call FunctionCall) Value {
  178. val := call.Argument(0)
  179. if obj := val.object(); obj != nil {
  180. obj.enumerate(true, func(name string) bool {
  181. if prop := obj.getOwnProperty(name); nil != prop && prop.configurable() {
  182. prop.configureOff()
  183. obj.defineOwnProperty(name, *prop, true)
  184. }
  185. return true
  186. })
  187. obj.extensible = false
  188. return val
  189. }
  190. panic(call.runtime.panicTypeError("Object.Seal is nil"))
  191. }
  192. func builtinObjectIsFrozen(call FunctionCall) Value {
  193. val := call.Argument(0)
  194. if obj := val.object(); obj != nil {
  195. if obj.extensible {
  196. return boolValue(false)
  197. }
  198. result := true
  199. obj.enumerate(true, func(name string) bool {
  200. prop := obj.getProperty(name)
  201. if prop.configurable() || prop.writable() {
  202. result = false
  203. }
  204. return true
  205. })
  206. return boolValue(result)
  207. }
  208. panic(call.runtime.panicTypeError("Object.IsFrozen is nil"))
  209. }
  210. func builtinObjectFreeze(call FunctionCall) Value {
  211. val := call.Argument(0)
  212. if obj := val.object(); obj != nil {
  213. obj.enumerate(true, func(name string) bool {
  214. if prop, update := obj.getOwnProperty(name), false; nil != prop {
  215. if prop.isDataDescriptor() && prop.writable() {
  216. prop.writeOff()
  217. update = true
  218. }
  219. if prop.configurable() {
  220. prop.configureOff()
  221. update = true
  222. }
  223. if update {
  224. obj.defineOwnProperty(name, *prop, true)
  225. }
  226. }
  227. return true
  228. })
  229. obj.extensible = false
  230. return val
  231. }
  232. panic(call.runtime.panicTypeError("Object.Freeze is nil"))
  233. }
  234. func builtinObjectKeys(call FunctionCall) Value {
  235. if obj, keys := call.Argument(0).object(), []Value(nil); nil != obj {
  236. obj.enumerate(false, func(name string) bool {
  237. keys = append(keys, stringValue(name))
  238. return true
  239. })
  240. return objectValue(call.runtime.newArrayOf(keys))
  241. }
  242. panic(call.runtime.panicTypeError("Object.Keys is nil"))
  243. }
  244. func builtinObjectValues(call FunctionCall) Value {
  245. if obj, values := call.Argument(0).object(), []Value(nil); nil != obj {
  246. obj.enumerate(false, func(name string) bool {
  247. values = append(values, obj.get(name))
  248. return true
  249. })
  250. return objectValue(call.runtime.newArrayOf(values))
  251. }
  252. panic(call.runtime.panicTypeError("Object.Values is nil"))
  253. }
  254. func builtinObjectGetOwnPropertyNames(call FunctionCall) Value {
  255. if obj, propertyNames := call.Argument(0).object(), []Value(nil); nil != obj {
  256. obj.enumerate(true, func(name string) bool {
  257. if obj.hasOwnProperty(name) {
  258. propertyNames = append(propertyNames, stringValue(name))
  259. }
  260. return true
  261. })
  262. return objectValue(call.runtime.newArrayOf(propertyNames))
  263. }
  264. // Default to empty array for non object types.
  265. return objectValue(call.runtime.newArray(0))
  266. }