object_goslice.go 7.8 KB

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