304 lines
6.2 KiB
Go
304 lines
6.2 KiB
Go
package goja
|
|
|
|
import (
|
|
"reflect"
|
|
"strconv"
|
|
)
|
|
|
|
type objectGoSlice struct {
|
|
baseObject
|
|
data *[]interface{}
|
|
lengthProp valueProperty
|
|
sliceExtensible bool
|
|
}
|
|
|
|
func (o *objectGoSlice) init() {
|
|
o.baseObject.init()
|
|
o.class = classArray
|
|
o.prototype = o.val.runtime.global.ArrayPrototype
|
|
o.lengthProp.writable = o.sliceExtensible
|
|
o._setLen()
|
|
o.baseObject._put("length", &o.lengthProp)
|
|
}
|
|
|
|
func (o *objectGoSlice) _setLen() {
|
|
o.lengthProp.value = intToValue(int64(len(*o.data)))
|
|
}
|
|
|
|
func (o *objectGoSlice) getIdx(idx int64) Value {
|
|
if idx < int64(len(*o.data)) {
|
|
return o.val.runtime.ToValue((*o.data)[idx])
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (o *objectGoSlice) _get(n Value) Value {
|
|
if idx := toIdx(n); idx >= 0 {
|
|
return o.getIdx(idx)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (o *objectGoSlice) _getStr(name string) Value {
|
|
if idx := strToIdx(name); idx >= 0 {
|
|
return o.getIdx(idx)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (o *objectGoSlice) get(n Value) Value {
|
|
if v := o._get(n); v != nil {
|
|
return v
|
|
}
|
|
return o.baseObject._getStr(n.String())
|
|
}
|
|
|
|
func (o *objectGoSlice) getStr(name string) Value {
|
|
if v := o._getStr(name); v != nil {
|
|
return v
|
|
}
|
|
return o.baseObject._getStr(name)
|
|
}
|
|
|
|
func (o *objectGoSlice) getProp(n Value) Value {
|
|
if v := o._get(n); v != nil {
|
|
return v
|
|
}
|
|
return o.baseObject.getPropStr(n.String())
|
|
}
|
|
|
|
func (o *objectGoSlice) getPropStr(name string) Value {
|
|
if v := o._getStr(name); v != nil {
|
|
return v
|
|
}
|
|
return o.baseObject.getPropStr(name)
|
|
}
|
|
|
|
func (o *objectGoSlice) getOwnProp(name string) Value {
|
|
if v := o._getStr(name); v != nil {
|
|
return &valueProperty{
|
|
value: v,
|
|
writable: true,
|
|
enumerable: true,
|
|
}
|
|
}
|
|
return o.baseObject.getOwnProp(name)
|
|
}
|
|
|
|
func (o *objectGoSlice) grow(size int64) {
|
|
newcap := int64(cap(*o.data))
|
|
if newcap < size {
|
|
// Use the same algorithm as in runtime.growSlice
|
|
doublecap := newcap + newcap
|
|
if size > doublecap {
|
|
newcap = size
|
|
} else {
|
|
if len(*o.data) < 1024 {
|
|
newcap = doublecap
|
|
} else {
|
|
for newcap < size {
|
|
newcap += newcap / 4
|
|
}
|
|
}
|
|
}
|
|
|
|
n := make([]interface{}, size, newcap)
|
|
copy(n, *o.data)
|
|
*o.data = n
|
|
} else {
|
|
*o.data = (*o.data)[:size]
|
|
}
|
|
o._setLen()
|
|
}
|
|
|
|
func (o *objectGoSlice) putIdx(idx int64, v Value, throw bool) {
|
|
if idx >= int64(len(*o.data)) {
|
|
if !o.sliceExtensible {
|
|
o.val.runtime.typeErrorResult(throw, "Cannot extend Go slice")
|
|
return
|
|
}
|
|
o.grow(idx + 1)
|
|
}
|
|
(*o.data)[idx] = v.Export()
|
|
}
|
|
|
|
func (o *objectGoSlice) put(n Value, val Value, throw bool) {
|
|
if idx := toIdx(n); idx >= 0 {
|
|
o.putIdx(idx, val, throw)
|
|
return
|
|
}
|
|
// TODO: length
|
|
o.baseObject.put(n, val, throw)
|
|
}
|
|
|
|
func (o *objectGoSlice) putStr(name string, val Value, throw bool) {
|
|
if idx := strToIdx(name); idx >= 0 {
|
|
o.putIdx(idx, val, throw)
|
|
return
|
|
}
|
|
// TODO: length
|
|
o.baseObject.putStr(name, val, throw)
|
|
}
|
|
|
|
func (o *objectGoSlice) _has(n Value) bool {
|
|
if idx := toIdx(n); idx >= 0 {
|
|
return idx < int64(len(*o.data))
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (o *objectGoSlice) _hasStr(name string) bool {
|
|
if idx := strToIdx(name); idx >= 0 {
|
|
return idx < int64(len(*o.data))
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (o *objectGoSlice) hasProperty(n Value) bool {
|
|
if o._has(n) {
|
|
return true
|
|
}
|
|
return o.baseObject.hasProperty(n)
|
|
}
|
|
|
|
func (o *objectGoSlice) hasPropertyStr(name string) bool {
|
|
if o._hasStr(name) {
|
|
return true
|
|
}
|
|
return o.baseObject.hasPropertyStr(name)
|
|
}
|
|
|
|
func (o *objectGoSlice) hasOwnProperty(n Value) bool {
|
|
if o._has(n) {
|
|
return true
|
|
}
|
|
return o.baseObject.hasOwnProperty(n)
|
|
}
|
|
|
|
func (o *objectGoSlice) hasOwnPropertyStr(name string) bool {
|
|
if o._hasStr(name) {
|
|
return true
|
|
}
|
|
return o.baseObject.hasOwnPropertyStr(name)
|
|
}
|
|
|
|
func (o *objectGoSlice) _putProp(name string, value Value, writable, enumerable, configurable bool) Value {
|
|
o.putStr(name, value, false)
|
|
return value
|
|
}
|
|
|
|
func (o *objectGoSlice) defineOwnProperty(n Value, descr propertyDescr, throw bool) bool {
|
|
if idx := toIdx(n); idx >= 0 {
|
|
if !o.val.runtime.checkHostObjectPropertyDescr(n.String(), descr, throw) {
|
|
return false
|
|
}
|
|
val := descr.Value
|
|
if val == nil {
|
|
val = _undefined
|
|
}
|
|
o.putIdx(idx, val, throw)
|
|
return true
|
|
}
|
|
return o.baseObject.defineOwnProperty(n, descr, throw)
|
|
}
|
|
|
|
func (o *objectGoSlice) toPrimitiveNumber() Value {
|
|
return o.toPrimitiveString()
|
|
}
|
|
|
|
func (o *objectGoSlice) toPrimitiveString() Value {
|
|
return o.val.runtime.arrayproto_join(FunctionCall{
|
|
This: o.val,
|
|
})
|
|
}
|
|
|
|
func (o *objectGoSlice) toPrimitive() Value {
|
|
return o.toPrimitiveString()
|
|
}
|
|
|
|
func (o *objectGoSlice) deleteStr(name string, throw bool) bool {
|
|
if idx := strToIdx(name); idx >= 0 && idx < int64(len(*o.data)) {
|
|
(*o.data)[idx] = nil
|
|
return true
|
|
}
|
|
return o.baseObject.deleteStr(name, throw)
|
|
}
|
|
|
|
func (o *objectGoSlice) delete(name Value, throw bool) bool {
|
|
if idx := toIdx(name); idx >= 0 && idx < int64(len(*o.data)) {
|
|
(*o.data)[idx] = nil
|
|
return true
|
|
}
|
|
return o.baseObject.delete(name, throw)
|
|
}
|
|
|
|
type goslicePropIter struct {
|
|
o *objectGoSlice
|
|
recursive bool
|
|
idx, limit int
|
|
}
|
|
|
|
func (i *goslicePropIter) next() (propIterItem, iterNextFunc) {
|
|
if i.idx < i.limit && i.idx < len(*i.o.data) {
|
|
name := strconv.Itoa(i.idx)
|
|
i.idx++
|
|
return propIterItem{name: name, enumerable: _ENUM_TRUE}, i.next
|
|
}
|
|
|
|
if i.recursive {
|
|
return i.o.prototype.self._enumerate(i.recursive)()
|
|
}
|
|
|
|
return propIterItem{}, nil
|
|
}
|
|
|
|
func (o *objectGoSlice) enumerate(all, recursive bool) iterNextFunc {
|
|
return (&propFilterIter{
|
|
wrapped: o._enumerate(recursive),
|
|
all: all,
|
|
seen: make(map[string]bool),
|
|
}).next
|
|
|
|
}
|
|
|
|
func (o *objectGoSlice) _enumerate(recursive bool) iterNextFunc {
|
|
return (&goslicePropIter{
|
|
o: o,
|
|
recursive: recursive,
|
|
limit: len(*o.data),
|
|
}).next
|
|
}
|
|
|
|
func (o *objectGoSlice) export() interface{} {
|
|
return *o.data
|
|
}
|
|
|
|
func (o *objectGoSlice) exportType() reflect.Type {
|
|
return reflectTypeArray
|
|
}
|
|
|
|
func (o *objectGoSlice) equal(other objectImpl) bool {
|
|
if other, ok := other.(*objectGoSlice); ok {
|
|
return o.data == other.data
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (o *objectGoSlice) sortLen() int64 {
|
|
return int64(len(*o.data))
|
|
}
|
|
|
|
func (o *objectGoSlice) sortGet(i int64) Value {
|
|
return o.get(intToValue(i))
|
|
}
|
|
|
|
func (o *objectGoSlice) swap(i, j int64) {
|
|
ii := intToValue(i)
|
|
jj := intToValue(j)
|
|
x := o.get(ii)
|
|
y := o.get(jj)
|
|
|
|
o.put(ii, y, false)
|
|
o.put(jj, x, false)
|
|
}
|