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