ai_old/goja/array.go
Star 767d87ac3e update throw exception
add util.load and util.save
2024-09-24 13:34:32 +08:00

566 lines
13 KiB
Go

package goja
import (
"fmt"
"math"
"math/bits"
"reflect"
"strconv"
"apigo.cc/ai/ai/goja/unistring"
)
type arrayIterObject struct {
baseObject
obj *Object
nextIdx int64
kind iterationKind
}
func (ai *arrayIterObject) next() Value {
if ai.obj == nil {
return ai.val.runtime.createIterResultObject(_undefined, true)
}
if ta, ok := ai.obj.self.(*typedArrayObject); ok {
ta.viewedArrayBuf.ensureNotDetached(true)
}
l := toLength(ai.obj.self.getStr("length", nil))
index := ai.nextIdx
if index >= l {
ai.obj = nil
return ai.val.runtime.createIterResultObject(_undefined, true)
}
ai.nextIdx++
idxVal := valueInt(index)
if ai.kind == iterationKindKey {
return ai.val.runtime.createIterResultObject(idxVal, false)
}
elementValue := nilSafe(ai.obj.self.getIdx(idxVal, nil))
var result Value
if ai.kind == iterationKindValue {
result = elementValue
} else {
result = ai.val.runtime.newArrayValues([]Value{idxVal, elementValue})
}
return ai.val.runtime.createIterResultObject(result, false)
}
func (r *Runtime) createArrayIterator(iterObj *Object, kind iterationKind) Value {
o := &Object{runtime: r}
ai := &arrayIterObject{
obj: iterObj,
kind: kind,
}
ai.class = classObject
ai.val = o
ai.extensible = true
o.self = ai
ai.prototype = r.getArrayIteratorPrototype()
ai.init()
return o
}
type arrayObject struct {
baseObject
values []Value
length uint32
objCount int
propValueCount int
lengthProp valueProperty
}
func (a *arrayObject) init() {
a.baseObject.init()
a.lengthProp.writable = true
a._put("length", &a.lengthProp)
}
func (a *arrayObject) _setLengthInt(l uint32, throw bool) bool {
ret := true
if l <= a.length {
if a.propValueCount > 0 {
// Slow path
for i := len(a.values) - 1; i >= int(l); i-- {
if prop, ok := a.values[i].(*valueProperty); ok {
if !prop.configurable {
l = uint32(i) + 1
ret = false
break
}
a.propValueCount--
}
}
}
}
if l <= uint32(len(a.values)) {
if l >= 16 && l < uint32(cap(a.values))>>2 {
ar := make([]Value, l)
copy(ar, a.values)
a.values = ar
} else {
ar := a.values[l:len(a.values)]
for i := range ar {
ar[i] = nil
}
a.values = a.values[:l]
}
}
a.length = l
if !ret {
a.val.runtime.typeErrorResult(throw, "Cannot redefine property: length")
}
return ret
}
func (a *arrayObject) setLengthInt(l uint32, throw bool) bool {
if l == a.length {
return true
}
if !a.lengthProp.writable {
a.val.runtime.typeErrorResult(throw, "length is not writable")
return false
}
return a._setLengthInt(l, throw)
}
func (a *arrayObject) setLength(v uint32, throw bool) bool {
if !a.lengthProp.writable {
a.val.runtime.typeErrorResult(throw, "length is not writable")
return false
}
return a._setLengthInt(v, throw)
}
func (a *arrayObject) getIdx(idx valueInt, receiver Value) Value {
prop := a.getOwnPropIdx(idx)
if prop == nil {
if a.prototype != nil {
if receiver == nil {
return a.prototype.self.getIdx(idx, a.val)
}
return a.prototype.self.getIdx(idx, receiver)
}
}
if prop, ok := prop.(*valueProperty); ok {
if receiver == nil {
return prop.get(a.val)
}
return prop.get(receiver)
}
return prop
}
func (a *arrayObject) getOwnPropStr(name unistring.String) Value {
if len(a.values) > 0 {
if i := strToArrayIdx(name); i != math.MaxUint32 {
if i < uint32(len(a.values)) {
return a.values[i]
}
}
}
if name == "length" {
return a.getLengthProp()
}
return a.baseObject.getOwnPropStr(name)
}
func (a *arrayObject) getOwnPropIdx(idx valueInt) Value {
if i := toIdx(idx); i != math.MaxUint32 {
if i < uint32(len(a.values)) {
return a.values[i]
}
return nil
}
return a.baseObject.getOwnPropStr(idx.string())
}
func (a *arrayObject) sortLen() int {
return len(a.values)
}
func (a *arrayObject) sortGet(i int) Value {
v := a.values[i]
if p, ok := v.(*valueProperty); ok {
v = p.get(a.val)
}
return v
}
func (a *arrayObject) swap(i int, j int) {
a.values[i], a.values[j] = a.values[j], a.values[i]
}
func (a *arrayObject) getStr(name unistring.String, receiver Value) Value {
return a.getStrWithOwnProp(a.getOwnPropStr(name), name, receiver)
}
func (a *arrayObject) getLengthProp() *valueProperty {
a.lengthProp.value = intToValue(int64(a.length))
return &a.lengthProp
}
func (a *arrayObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
if i := toIdx(idx); i != math.MaxUint32 {
return a._setOwnIdx(i, val, throw)
} else {
return a.baseObject.setOwnStr(idx.string(), val, throw)
}
}
func (a *arrayObject) _setOwnIdx(idx uint32, val Value, throw bool) bool {
var prop Value
if idx < uint32(len(a.values)) {
prop = a.values[idx]
}
if prop == nil {
if proto := a.prototype; proto != nil {
// we know it's foreign because prototype loops are not allowed
if res, ok := proto.self.setForeignIdx(valueInt(idx), val, a.val, throw); ok {
return res
}
}
// new property
if !a.extensible {
a.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx)
return false
} else {
if idx >= a.length {
if !a.setLengthInt(idx+1, throw) {
return false
}
}
if idx >= uint32(len(a.values)) {
if !a.expand(idx) {
a.val.self.(*sparseArrayObject).add(idx, val)
return true
}
}
a.objCount++
}
} else {
if prop, ok := prop.(*valueProperty); ok {
if !prop.isWritable() {
a.val.runtime.typeErrorResult(throw)
return false
}
prop.set(a.val, val)
return true
}
}
a.values[idx] = val
return true
}
func (a *arrayObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return a._setOwnIdx(idx, val, throw)
} else {
if name == "length" {
return a.setLength(a.val.runtime.toLengthUint32(val), throw)
} else {
return a.baseObject.setOwnStr(name, val, throw)
}
}
}
func (a *arrayObject) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
return a._setForeignIdx(idx, a.getOwnPropIdx(idx), val, receiver, throw)
}
func (a *arrayObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
return a._setForeignStr(name, a.getOwnPropStr(name), val, receiver, throw)
}
type arrayPropIter struct {
a *arrayObject
limit int
idx int
}
func (i *arrayPropIter) next() (propIterItem, iterNextFunc) {
for i.idx < len(i.a.values) && i.idx < i.limit {
name := asciiString(strconv.Itoa(i.idx))
prop := i.a.values[i.idx]
i.idx++
if prop != nil {
return propIterItem{name: name, value: prop}, i.next
}
}
return i.a.baseObject.iterateStringKeys()()
}
func (a *arrayObject) iterateStringKeys() iterNextFunc {
return (&arrayPropIter{
a: a,
limit: len(a.values),
}).next
}
func (a *arrayObject) stringKeys(all bool, accum []Value) []Value {
for i, prop := range a.values {
name := strconv.Itoa(i)
if prop != nil {
if !all {
if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
continue
}
}
accum = append(accum, asciiString(name))
}
}
return a.baseObject.stringKeys(all, accum)
}
func (a *arrayObject) hasOwnPropertyStr(name unistring.String) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return idx < uint32(len(a.values)) && a.values[idx] != nil
} else {
return a.baseObject.hasOwnPropertyStr(name)
}
}
func (a *arrayObject) hasOwnPropertyIdx(idx valueInt) bool {
if idx := toIdx(idx); idx != math.MaxUint32 {
return idx < uint32(len(a.values)) && a.values[idx] != nil
}
return a.baseObject.hasOwnPropertyStr(idx.string())
}
func (a *arrayObject) hasPropertyIdx(idx valueInt) bool {
if a.hasOwnPropertyIdx(idx) {
return true
}
if a.prototype != nil {
return a.prototype.self.hasPropertyIdx(idx)
}
return false
}
func (a *arrayObject) expand(idx uint32) bool {
targetLen := idx + 1
if targetLen > uint32(len(a.values)) {
if targetLen < uint32(cap(a.values)) {
a.values = a.values[:targetLen]
} else {
if idx > 4096 && (a.objCount == 0 || idx/uint32(a.objCount) > 10) {
//log.Println("Switching standard->sparse")
sa := &sparseArrayObject{
baseObject: a.baseObject,
length: a.length,
propValueCount: a.propValueCount,
}
sa.setValues(a.values, a.objCount+1)
sa.val.self = sa
sa.lengthProp.writable = a.lengthProp.writable
sa._put("length", &sa.lengthProp)
return false
} else {
if bits.UintSize == 32 {
if targetLen >= math.MaxInt32 {
panic(a.val.runtime.NewTypeError("Array index overflows int"))
}
}
tl := int(targetLen)
newValues := make([]Value, tl, growCap(tl, len(a.values), cap(a.values)))
copy(newValues, a.values)
a.values = newValues
}
}
}
return true
}
func (r *Runtime) defineArrayLength(prop *valueProperty, descr PropertyDescriptor, setter func(uint32, bool) bool, throw bool) bool {
var newLen uint32
ret := true
if descr.Value != nil {
newLen = r.toLengthUint32(descr.Value)
}
if descr.Configurable == FLAG_TRUE || descr.Enumerable == FLAG_TRUE || descr.Getter != nil || descr.Setter != nil {
ret = false
goto Reject
}
if descr.Value != nil {
oldLen := uint32(prop.value.ToInteger())
if oldLen != newLen {
ret = setter(newLen, false)
}
} else {
ret = true
}
if descr.Writable != FLAG_NOT_SET {
w := descr.Writable.Bool()
if prop.writable {
prop.writable = w
} else {
if w {
ret = false
goto Reject
}
}
}
Reject:
if !ret {
r.typeErrorResult(throw, "Cannot redefine property: length")
}
return ret
}
func (a *arrayObject) _defineIdxProperty(idx uint32, desc PropertyDescriptor, throw bool) bool {
var existing Value
if idx < uint32(len(a.values)) {
existing = a.values[idx]
}
prop, ok := a.baseObject._defineOwnProperty(unistring.String(strconv.FormatUint(uint64(idx), 10)), existing, desc, throw)
if ok {
if idx >= a.length {
if !a.setLengthInt(idx+1, throw) {
return false
}
}
if a.expand(idx) {
a.values[idx] = prop
a.objCount++
if _, ok := prop.(*valueProperty); ok {
a.propValueCount++
}
} else {
a.val.self.(*sparseArrayObject).add(idx, prop)
}
}
return ok
}
func (a *arrayObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return a._defineIdxProperty(idx, descr, throw)
}
if name == "length" {
return a.val.runtime.defineArrayLength(a.getLengthProp(), descr, a.setLength, throw)
}
return a.baseObject.defineOwnPropertyStr(name, descr, throw)
}
func (a *arrayObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
if idx := toIdx(idx); idx != math.MaxUint32 {
return a._defineIdxProperty(idx, descr, throw)
}
return a.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
}
func (a *arrayObject) _deleteIdxProp(idx uint32, throw bool) bool {
if idx < uint32(len(a.values)) {
if v := a.values[idx]; v != nil {
if p, ok := v.(*valueProperty); ok {
if !p.configurable {
a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.toString())
return false
}
a.propValueCount--
}
a.values[idx] = nil
a.objCount--
}
}
return true
}
func (a *arrayObject) deleteStr(name unistring.String, throw bool) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return a._deleteIdxProp(idx, throw)
}
return a.baseObject.deleteStr(name, throw)
}
func (a *arrayObject) deleteIdx(idx valueInt, throw bool) bool {
if idx := toIdx(idx); idx != math.MaxUint32 {
return a._deleteIdxProp(idx, throw)
}
return a.baseObject.deleteStr(idx.string(), throw)
}
func (a *arrayObject) export(ctx *objectExportCtx) interface{} {
if v, exists := ctx.get(a.val); exists {
return v
}
arr := make([]interface{}, a.length)
ctx.put(a.val, arr)
if a.propValueCount == 0 && a.length == uint32(len(a.values)) && uint32(a.objCount) == a.length {
for i, v := range a.values {
if v != nil {
arr[i] = exportValue(v, ctx)
}
}
} else {
for i := uint32(0); i < a.length; i++ {
v := a.getIdx(valueInt(i), nil)
if v != nil {
arr[i] = exportValue(v, ctx)
}
}
}
return arr
}
func (a *arrayObject) exportType() reflect.Type {
return reflectTypeArray
}
func (a *arrayObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
r := a.val.runtime
if iter := a.getSym(SymIterator, nil); iter == r.getArrayValues() || iter == nil {
l := toIntStrict(int64(a.length))
if typ.Kind() == reflect.Array {
if dst.Len() != l {
return fmt.Errorf("cannot convert an Array into an array, lengths mismatch (have %d, need %d)", l, dst.Len())
}
} else {
dst.Set(reflect.MakeSlice(typ, l, l))
}
ctx.putTyped(a.val, typ, dst.Interface())
for i := 0; i < l; i++ {
if i >= len(a.values) {
break
}
val := a.values[i]
if p, ok := val.(*valueProperty); ok {
val = p.get(a.val)
}
err := r.toReflectValue(val, dst.Index(i), ctx)
if err != nil {
return fmt.Errorf("could not convert array element %v to %v at %d: %w", val, typ, i, err)
}
}
return nil
}
return a.baseObject.exportToArrayOrSlice(dst, typ, ctx)
}
func (a *arrayObject) setValuesFromSparse(items []sparseArrayItem, newMaxIdx int) {
a.values = make([]Value, newMaxIdx+1)
for _, item := range items {
a.values[item.idx] = item.value
}
a.objCount = len(items)
}
func toIdx(v valueInt) uint32 {
if v >= 0 && v < math.MaxUint32 {
return uint32(v)
}
return math.MaxUint32
}