object_goslice.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. package goja
  2. import (
  3. "reflect"
  4. "strconv"
  5. )
  6. type objectGoSlice struct {
  7. baseObject
  8. data *[]interface{}
  9. lengthProp valueProperty
  10. sliceExtensible bool
  11. }
  12. func (o *objectGoSlice) init() {
  13. o.baseObject.init()
  14. o.class = classArray
  15. o.prototype = o.val.runtime.global.ArrayPrototype
  16. o.lengthProp.writable = o.sliceExtensible
  17. o._setLen()
  18. o.baseObject._put("length", &o.lengthProp)
  19. }
  20. func (o *objectGoSlice) _setLen() {
  21. o.lengthProp.value = intToValue(int64(len(*o.data)))
  22. }
  23. func (o *objectGoSlice) getIdx(idx int64) Value {
  24. if idx < int64(len(*o.data)) {
  25. return o.val.runtime.ToValue((*o.data)[idx])
  26. }
  27. return nil
  28. }
  29. func (o *objectGoSlice) _get(n Value) Value {
  30. if idx := toIdx(n); idx >= 0 {
  31. return o.getIdx(idx)
  32. }
  33. return nil
  34. }
  35. func (o *objectGoSlice) _getStr(name string) Value {
  36. if idx := strToIdx(name); idx >= 0 {
  37. return o.getIdx(idx)
  38. }
  39. return nil
  40. }
  41. func (o *objectGoSlice) get(n Value) Value {
  42. if v := o._get(n); v != nil {
  43. return v
  44. }
  45. return o.baseObject._getStr(n.String())
  46. }
  47. func (o *objectGoSlice) getStr(name string) Value {
  48. if v := o._getStr(name); v != nil {
  49. return v
  50. }
  51. return o.baseObject._getStr(name)
  52. }
  53. func (o *objectGoSlice) getProp(n Value) Value {
  54. if v := o._get(n); v != nil {
  55. return v
  56. }
  57. return o.baseObject.getPropStr(n.String())
  58. }
  59. func (o *objectGoSlice) getPropStr(name string) Value {
  60. if v := o._getStr(name); v != nil {
  61. return v
  62. }
  63. return o.baseObject.getPropStr(name)
  64. }
  65. func (o *objectGoSlice) getOwnProp(name string) Value {
  66. if v := o._getStr(name); v != nil {
  67. return &valueProperty{
  68. value: v,
  69. writable: true,
  70. enumerable: true,
  71. }
  72. }
  73. return o.baseObject.getOwnProp(name)
  74. }
  75. func (o *objectGoSlice) grow(size int64) {
  76. newcap := int64(cap(*o.data))
  77. if newcap < size {
  78. // Use the same algorithm as in runtime.growSlice
  79. doublecap := newcap + newcap
  80. if size > doublecap {
  81. newcap = size
  82. } else {
  83. if len(*o.data) < 1024 {
  84. newcap = doublecap
  85. } else {
  86. for newcap < size {
  87. newcap += newcap / 4
  88. }
  89. }
  90. }
  91. n := make([]interface{}, size, newcap)
  92. copy(n, *o.data)
  93. *o.data = n
  94. } else {
  95. *o.data = (*o.data)[:size]
  96. }
  97. o._setLen()
  98. }
  99. func (o *objectGoSlice) putIdx(idx int64, v Value, throw bool) {
  100. if idx >= int64(len(*o.data)) {
  101. if !o.sliceExtensible {
  102. o.val.runtime.typeErrorResult(throw, "Cannot extend Go slice")
  103. return
  104. }
  105. o.grow(idx + 1)
  106. }
  107. (*o.data)[idx] = v.Export()
  108. }
  109. func (o *objectGoSlice) put(n Value, val Value, throw bool) {
  110. if idx := toIdx(n); idx >= 0 {
  111. o.putIdx(idx, val, throw)
  112. return
  113. }
  114. // TODO: length
  115. o.baseObject.put(n, val, throw)
  116. }
  117. func (o *objectGoSlice) putStr(name string, val Value, throw bool) {
  118. if idx := strToIdx(name); idx >= 0 {
  119. o.putIdx(idx, val, throw)
  120. return
  121. }
  122. // TODO: length
  123. o.baseObject.putStr(name, val, throw)
  124. }
  125. func (o *objectGoSlice) _has(n Value) bool {
  126. if idx := toIdx(n); idx >= 0 {
  127. return idx < int64(len(*o.data))
  128. }
  129. return false
  130. }
  131. func (o *objectGoSlice) _hasStr(name string) bool {
  132. if idx := strToIdx(name); idx >= 0 {
  133. return idx < int64(len(*o.data))
  134. }
  135. return false
  136. }
  137. func (o *objectGoSlice) hasProperty(n Value) bool {
  138. if o._has(n) {
  139. return true
  140. }
  141. return o.baseObject.hasProperty(n)
  142. }
  143. func (o *objectGoSlice) hasPropertyStr(name string) bool {
  144. if o._hasStr(name) {
  145. return true
  146. }
  147. return o.baseObject.hasPropertyStr(name)
  148. }
  149. func (o *objectGoSlice) hasOwnProperty(n Value) bool {
  150. if o._has(n) {
  151. return true
  152. }
  153. return o.baseObject.hasOwnProperty(n)
  154. }
  155. func (o *objectGoSlice) hasOwnPropertyStr(name string) bool {
  156. if o._hasStr(name) {
  157. return true
  158. }
  159. return o.baseObject.hasOwnPropertyStr(name)
  160. }
  161. func (o *objectGoSlice) _putProp(name string, value Value, writable, enumerable, configurable bool) Value {
  162. o.putStr(name, value, false)
  163. return value
  164. }
  165. func (o *objectGoSlice) defineOwnProperty(n Value, descr propertyDescr, throw bool) bool {
  166. if idx := toIdx(n); idx >= 0 {
  167. if !o.val.runtime.checkHostObjectPropertyDescr(n.String(), descr, throw) {
  168. return false
  169. }
  170. val := descr.Value
  171. if val == nil {
  172. val = _undefined
  173. }
  174. o.putIdx(idx, val, throw)
  175. return true
  176. }
  177. return o.baseObject.defineOwnProperty(n, descr, throw)
  178. }
  179. func (o *objectGoSlice) toPrimitiveNumber() Value {
  180. return o.toPrimitiveString()
  181. }
  182. func (o *objectGoSlice) toPrimitiveString() Value {
  183. return o.val.runtime.arrayproto_join(FunctionCall{
  184. This: o.val,
  185. })
  186. }
  187. func (o *objectGoSlice) toPrimitive() Value {
  188. return o.toPrimitiveString()
  189. }
  190. func (o *objectGoSlice) deleteStr(name string, throw bool) bool {
  191. if idx := strToIdx(name); idx >= 0 && idx < int64(len(*o.data)) {
  192. (*o.data)[idx] = nil
  193. return true
  194. }
  195. return o.baseObject.deleteStr(name, throw)
  196. }
  197. func (o *objectGoSlice) delete(name Value, throw bool) bool {
  198. if idx := toIdx(name); idx >= 0 && idx < int64(len(*o.data)) {
  199. (*o.data)[idx] = nil
  200. return true
  201. }
  202. return o.baseObject.delete(name, throw)
  203. }
  204. type goslicePropIter struct {
  205. o *objectGoSlice
  206. recursive bool
  207. idx, limit int
  208. }
  209. func (i *goslicePropIter) next() (propIterItem, iterNextFunc) {
  210. if i.idx < i.limit && i.idx < len(*i.o.data) {
  211. name := strconv.Itoa(i.idx)
  212. i.idx++
  213. return propIterItem{name: name, enumerable: _ENUM_TRUE}, i.next
  214. }
  215. if i.recursive {
  216. return i.o.prototype.self._enumerate(i.recursive)()
  217. }
  218. return propIterItem{}, nil
  219. }
  220. func (o *objectGoSlice) enumerate(all, recursive bool) iterNextFunc {
  221. return (&propFilterIter{
  222. wrapped: o._enumerate(recursive),
  223. all: all,
  224. seen: make(map[string]bool),
  225. }).next
  226. }
  227. func (o *objectGoSlice) _enumerate(recursive bool) iterNextFunc {
  228. return (&goslicePropIter{
  229. o: o,
  230. recursive: recursive,
  231. limit: len(*o.data),
  232. }).next
  233. }
  234. func (o *objectGoSlice) export() interface{} {
  235. return *o.data
  236. }
  237. func (o *objectGoSlice) exportType() reflect.Type {
  238. return reflectTypeArray
  239. }
  240. func (o *objectGoSlice) equal(other objectImpl) bool {
  241. if other, ok := other.(*objectGoSlice); ok {
  242. return o.data == other.data
  243. }
  244. return false
  245. }
  246. func (o *objectGoSlice) sortLen() int64 {
  247. return int64(len(*o.data))
  248. }
  249. func (o *objectGoSlice) sortGet(i int64) Value {
  250. return o.get(intToValue(i))
  251. }
  252. func (o *objectGoSlice) swap(i, j int64) {
  253. ii := intToValue(i)
  254. jj := intToValue(j)
  255. x := o.get(ii)
  256. y := o.get(jj)
  257. o.put(ii, y, false)
  258. o.put(jj, x, false)
  259. }