object_goslice.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. package goja
  2. import (
  3. "math"
  4. "math/bits"
  5. "reflect"
  6. "strconv"
  7. "github.com/dop251/goja/unistring"
  8. )
  9. type objectGoSlice struct {
  10. baseObject
  11. data *[]interface{}
  12. lengthProp valueProperty
  13. }
  14. func (o *objectGoSlice) init() {
  15. o.baseObject.init()
  16. o.class = classArray
  17. o.prototype = o.val.runtime.global.ArrayPrototype
  18. o.lengthProp.writable = true
  19. o.extensible = true
  20. o.updateLen()
  21. o.baseObject._put("length", &o.lengthProp)
  22. }
  23. func (o *objectGoSlice) updateLen() {
  24. o.lengthProp.value = intToValue(int64(len(*o.data)))
  25. }
  26. func (o *objectGoSlice) getStr(name unistring.String, receiver Value) Value {
  27. var ownProp Value
  28. if idx := strToGoIdx(name); idx >= 0 && idx < len(*o.data) {
  29. v := (*o.data)[idx]
  30. ownProp = o.val.runtime.ToValue(v)
  31. } else if name == "length" {
  32. ownProp = &o.lengthProp
  33. }
  34. return o.getStrWithOwnProp(ownProp, name, receiver)
  35. }
  36. func (o *objectGoSlice) getIdx(idx valueInt, receiver Value) Value {
  37. if idx := int64(idx); idx >= 0 && idx < int64(len(*o.data)) {
  38. v := (*o.data)[idx]
  39. return o.val.runtime.ToValue(v)
  40. }
  41. if o.prototype != nil {
  42. if receiver == nil {
  43. return o.prototype.self.getIdx(idx, o.val)
  44. }
  45. return o.prototype.self.getIdx(idx, receiver)
  46. }
  47. return nil
  48. }
  49. func (o *objectGoSlice) getOwnPropStr(name unistring.String) Value {
  50. if idx := strToGoIdx(name); idx >= 0 {
  51. if idx < len(*o.data) {
  52. v := o.val.runtime.ToValue((*o.data)[idx])
  53. return &valueProperty{
  54. value: v,
  55. writable: true,
  56. enumerable: true,
  57. }
  58. }
  59. return nil
  60. }
  61. if name == "length" {
  62. return &o.lengthProp
  63. }
  64. return nil
  65. }
  66. func (o *objectGoSlice) getOwnPropIdx(idx valueInt) Value {
  67. if idx := int64(idx); idx >= 0 && idx < int64(len(*o.data)) {
  68. v := o.val.runtime.ToValue((*o.data)[idx])
  69. return &valueProperty{
  70. value: v,
  71. writable: true,
  72. enumerable: true,
  73. }
  74. }
  75. return nil
  76. }
  77. func (o *objectGoSlice) grow(size int) {
  78. oldcap := cap(*o.data)
  79. if oldcap < size {
  80. n := make([]interface{}, size, growCap(size, len(*o.data), oldcap))
  81. copy(n, *o.data)
  82. *o.data = n
  83. } else {
  84. tail := (*o.data)[len(*o.data):size]
  85. for k := range tail {
  86. tail[k] = nil
  87. }
  88. *o.data = (*o.data)[:size]
  89. }
  90. o.updateLen()
  91. }
  92. func (o *objectGoSlice) shrink(size int) {
  93. tail := (*o.data)[size:]
  94. for k := range tail {
  95. tail[k] = nil
  96. }
  97. *o.data = (*o.data)[:size]
  98. o.updateLen()
  99. }
  100. func (o *objectGoSlice) putIdx(idx int, v Value, throw bool) {
  101. if idx >= len(*o.data) {
  102. o.grow(idx + 1)
  103. }
  104. (*o.data)[idx] = v.Export()
  105. }
  106. func (o *objectGoSlice) putLength(v uint32, throw bool) bool {
  107. if bits.UintSize == 32 && v > math.MaxInt32 {
  108. panic(rangeError("Integer value overflows 32-bit int"))
  109. }
  110. newLen := int(v)
  111. curLen := len(*o.data)
  112. if newLen > curLen {
  113. o.grow(newLen)
  114. } else if newLen < curLen {
  115. o.shrink(newLen)
  116. }
  117. return true
  118. }
  119. func (o *objectGoSlice) setOwnIdx(idx valueInt, val Value, throw bool) bool {
  120. if i := toIntStrict(int64(idx)); i >= 0 {
  121. if i >= len(*o.data) {
  122. if res, ok := o._setForeignIdx(idx, nil, val, o.val, throw); ok {
  123. return res
  124. }
  125. }
  126. o.putIdx(i, val, throw)
  127. } else {
  128. name := idx.string()
  129. if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
  130. o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name)
  131. return false
  132. } else {
  133. return res
  134. }
  135. }
  136. return true
  137. }
  138. func (o *objectGoSlice) setOwnStr(name unistring.String, val Value, throw bool) bool {
  139. if idx := strToGoIdx(name); idx >= 0 {
  140. if idx >= len(*o.data) {
  141. if res, ok := o._setForeignStr(name, nil, val, o.val, throw); ok {
  142. return res
  143. }
  144. }
  145. o.putIdx(idx, val, throw)
  146. } else {
  147. if name == "length" {
  148. return o.putLength(o.val.runtime.toLengthUint32(val), throw)
  149. }
  150. if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
  151. o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name)
  152. return false
  153. } else {
  154. return res
  155. }
  156. }
  157. return true
  158. }
  159. func (o *objectGoSlice) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
  160. return o._setForeignIdx(idx, trueValIfPresent(o.hasOwnPropertyIdx(idx)), val, receiver, throw)
  161. }
  162. func (o *objectGoSlice) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
  163. return o._setForeignStr(name, trueValIfPresent(o.hasOwnPropertyStr(name)), val, receiver, throw)
  164. }
  165. func (o *objectGoSlice) hasOwnPropertyIdx(idx valueInt) bool {
  166. if idx := int64(idx); idx >= 0 {
  167. return idx < int64(len(*o.data))
  168. }
  169. return false
  170. }
  171. func (o *objectGoSlice) hasOwnPropertyStr(name unistring.String) bool {
  172. if idx := strToIdx64(name); idx >= 0 {
  173. return idx < int64(len(*o.data))
  174. }
  175. return name == "length"
  176. }
  177. func (o *objectGoSlice) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
  178. if i := toIntStrict(int64(idx)); i >= 0 {
  179. if !o.val.runtime.checkHostObjectPropertyDescr(idx.string(), descr, throw) {
  180. return false
  181. }
  182. val := descr.Value
  183. if val == nil {
  184. val = _undefined
  185. }
  186. o.putIdx(i, val, throw)
  187. return true
  188. }
  189. o.val.runtime.typeErrorResult(throw, "Cannot define property '%d' on a Go slice", idx)
  190. return false
  191. }
  192. func (o *objectGoSlice) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
  193. if idx := strToGoIdx(name); idx >= 0 {
  194. if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
  195. return false
  196. }
  197. val := descr.Value
  198. if val == nil {
  199. val = _undefined
  200. }
  201. o.putIdx(idx, val, throw)
  202. return true
  203. }
  204. if name == "length" {
  205. return o.val.runtime.defineArrayLength(&o.lengthProp, descr, o.putLength, throw)
  206. }
  207. o.val.runtime.typeErrorResult(throw, "Cannot define property '%s' on a Go slice", name)
  208. return false
  209. }
  210. func (o *objectGoSlice) toPrimitiveNumber() Value {
  211. return o.toPrimitiveString()
  212. }
  213. func (o *objectGoSlice) toPrimitiveString() Value {
  214. return o.val.runtime.arrayproto_join(FunctionCall{
  215. This: o.val,
  216. })
  217. }
  218. func (o *objectGoSlice) toPrimitive() Value {
  219. return o.toPrimitiveString()
  220. }
  221. func (o *objectGoSlice) _deleteIdx(idx int64) {
  222. if idx < int64(len(*o.data)) {
  223. (*o.data)[idx] = nil
  224. }
  225. }
  226. func (o *objectGoSlice) deleteStr(name unistring.String, throw bool) bool {
  227. if idx := strToIdx64(name); idx >= 0 {
  228. o._deleteIdx(idx)
  229. return true
  230. }
  231. return o.baseObject.deleteStr(name, throw)
  232. }
  233. func (o *objectGoSlice) deleteIdx(i valueInt, throw bool) bool {
  234. idx := int64(i)
  235. if idx >= 0 {
  236. o._deleteIdx(idx)
  237. }
  238. return true
  239. }
  240. type goslicePropIter struct {
  241. o *objectGoSlice
  242. idx, limit int
  243. }
  244. func (i *goslicePropIter) next() (propIterItem, iterNextFunc) {
  245. if i.idx < i.limit && i.idx < len(*i.o.data) {
  246. name := strconv.Itoa(i.idx)
  247. i.idx++
  248. return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.next
  249. }
  250. return propIterItem{}, nil
  251. }
  252. func (o *objectGoSlice) iterateStringKeys() iterNextFunc {
  253. return (&goslicePropIter{
  254. o: o,
  255. limit: len(*o.data),
  256. }).next
  257. }
  258. func (o *objectGoSlice) stringKeys(_ bool, accum []Value) []Value {
  259. for i := range *o.data {
  260. accum = append(accum, asciiString(strconv.Itoa(i)))
  261. }
  262. return accum
  263. }
  264. func (o *objectGoSlice) export(*objectExportCtx) interface{} {
  265. return *o.data
  266. }
  267. func (o *objectGoSlice) exportType() reflect.Type {
  268. return reflectTypeArray
  269. }
  270. func (o *objectGoSlice) equal(other objectImpl) bool {
  271. if other, ok := other.(*objectGoSlice); ok {
  272. return o.data == other.data
  273. }
  274. return false
  275. }
  276. func (o *objectGoSlice) sortLen() int64 {
  277. return int64(len(*o.data))
  278. }
  279. func (o *objectGoSlice) sortGet(i int64) Value {
  280. return o.getIdx(valueInt(i), nil)
  281. }
  282. func (o *objectGoSlice) swap(i, j int64) {
  283. ii := valueInt(i)
  284. jj := valueInt(j)
  285. x := o.getIdx(ii, nil)
  286. y := o.getIdx(jj, nil)
  287. o.setOwnIdx(ii, y, false)
  288. o.setOwnIdx(jj, x, false)
  289. }