github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/array.go (about)

     1  package goja
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"math/bits"
     7  	"reflect"
     8  	"strconv"
     9  
    10  	"github.com/nuvolaris/goja/unistring"
    11  )
    12  
    13  type arrayIterObject struct {
    14  	baseObject
    15  	obj     *Object
    16  	nextIdx int64
    17  	kind    iterationKind
    18  }
    19  
    20  func (ai *arrayIterObject) next() Value {
    21  	if ai.obj == nil {
    22  		return ai.val.runtime.createIterResultObject(_undefined, true)
    23  	}
    24  	if ta, ok := ai.obj.self.(*typedArrayObject); ok {
    25  		ta.viewedArrayBuf.ensureNotDetached(true)
    26  	}
    27  	l := toLength(ai.obj.self.getStr("length", nil))
    28  	index := ai.nextIdx
    29  	if index >= l {
    30  		ai.obj = nil
    31  		return ai.val.runtime.createIterResultObject(_undefined, true)
    32  	}
    33  	ai.nextIdx++
    34  	idxVal := valueInt(index)
    35  	if ai.kind == iterationKindKey {
    36  		return ai.val.runtime.createIterResultObject(idxVal, false)
    37  	}
    38  	elementValue := nilSafe(ai.obj.self.getIdx(idxVal, nil))
    39  	var result Value
    40  	if ai.kind == iterationKindValue {
    41  		result = elementValue
    42  	} else {
    43  		result = ai.val.runtime.newArrayValues([]Value{idxVal, elementValue})
    44  	}
    45  	return ai.val.runtime.createIterResultObject(result, false)
    46  }
    47  
    48  func (r *Runtime) createArrayIterator(iterObj *Object, kind iterationKind) Value {
    49  	o := &Object{runtime: r}
    50  
    51  	ai := &arrayIterObject{
    52  		obj:  iterObj,
    53  		kind: kind,
    54  	}
    55  	ai.class = classObject
    56  	ai.val = o
    57  	ai.extensible = true
    58  	o.self = ai
    59  	ai.prototype = r.getArrayIteratorPrototype()
    60  	ai.init()
    61  
    62  	return o
    63  }
    64  
    65  type arrayObject struct {
    66  	baseObject
    67  	values         []Value
    68  	length         uint32
    69  	objCount       int
    70  	propValueCount int
    71  	lengthProp     valueProperty
    72  }
    73  
    74  func (a *arrayObject) init() {
    75  	a.baseObject.init()
    76  	a.lengthProp.writable = true
    77  
    78  	a._put("length", &a.lengthProp)
    79  }
    80  
    81  func (a *arrayObject) _setLengthInt(l uint32, throw bool) bool {
    82  	ret := true
    83  	if l <= a.length {
    84  		if a.propValueCount > 0 {
    85  			// Slow path
    86  			for i := len(a.values) - 1; i >= int(l); i-- {
    87  				if prop, ok := a.values[i].(*valueProperty); ok {
    88  					if !prop.configurable {
    89  						l = uint32(i) + 1
    90  						ret = false
    91  						break
    92  					}
    93  					a.propValueCount--
    94  				}
    95  			}
    96  		}
    97  	}
    98  	if l <= uint32(len(a.values)) {
    99  		if l >= 16 && l < uint32(cap(a.values))>>2 {
   100  			ar := make([]Value, l)
   101  			copy(ar, a.values)
   102  			a.values = ar
   103  		} else {
   104  			ar := a.values[l:len(a.values)]
   105  			for i := range ar {
   106  				ar[i] = nil
   107  			}
   108  			a.values = a.values[:l]
   109  		}
   110  	}
   111  	a.length = l
   112  	if !ret {
   113  		a.val.runtime.typeErrorResult(throw, "Cannot redefine property: length")
   114  	}
   115  	return ret
   116  }
   117  
   118  func (a *arrayObject) setLengthInt(l uint32, throw bool) bool {
   119  	if l == a.length {
   120  		return true
   121  	}
   122  	if !a.lengthProp.writable {
   123  		a.val.runtime.typeErrorResult(throw, "length is not writable")
   124  		return false
   125  	}
   126  	return a._setLengthInt(l, throw)
   127  }
   128  
   129  func (a *arrayObject) setLength(v uint32, throw bool) bool {
   130  	if !a.lengthProp.writable {
   131  		a.val.runtime.typeErrorResult(throw, "length is not writable")
   132  		return false
   133  	}
   134  	return a._setLengthInt(v, throw)
   135  }
   136  
   137  func (a *arrayObject) getIdx(idx valueInt, receiver Value) Value {
   138  	prop := a.getOwnPropIdx(idx)
   139  	if prop == nil {
   140  		if a.prototype != nil {
   141  			if receiver == nil {
   142  				return a.prototype.self.getIdx(idx, a.val)
   143  			}
   144  			return a.prototype.self.getIdx(idx, receiver)
   145  		}
   146  	}
   147  	if prop, ok := prop.(*valueProperty); ok {
   148  		if receiver == nil {
   149  			return prop.get(a.val)
   150  		}
   151  		return prop.get(receiver)
   152  	}
   153  	return prop
   154  }
   155  
   156  func (a *arrayObject) getOwnPropStr(name unistring.String) Value {
   157  	if len(a.values) > 0 {
   158  		if i := strToArrayIdx(name); i != math.MaxUint32 {
   159  			if i < uint32(len(a.values)) {
   160  				return a.values[i]
   161  			}
   162  		}
   163  	}
   164  	if name == "length" {
   165  		return a.getLengthProp()
   166  	}
   167  	return a.baseObject.getOwnPropStr(name)
   168  }
   169  
   170  func (a *arrayObject) getOwnPropIdx(idx valueInt) Value {
   171  	if i := toIdx(idx); i != math.MaxUint32 {
   172  		if i < uint32(len(a.values)) {
   173  			return a.values[i]
   174  		}
   175  		return nil
   176  	}
   177  
   178  	return a.baseObject.getOwnPropStr(idx.string())
   179  }
   180  
   181  func (a *arrayObject) sortLen() int {
   182  	return len(a.values)
   183  }
   184  
   185  func (a *arrayObject) sortGet(i int) Value {
   186  	v := a.values[i]
   187  	if p, ok := v.(*valueProperty); ok {
   188  		v = p.get(a.val)
   189  	}
   190  	return v
   191  }
   192  
   193  func (a *arrayObject) swap(i int, j int) {
   194  	a.values[i], a.values[j] = a.values[j], a.values[i]
   195  }
   196  
   197  func (a *arrayObject) getStr(name unistring.String, receiver Value) Value {
   198  	return a.getStrWithOwnProp(a.getOwnPropStr(name), name, receiver)
   199  }
   200  
   201  func (a *arrayObject) getLengthProp() *valueProperty {
   202  	a.lengthProp.value = intToValue(int64(a.length))
   203  	return &a.lengthProp
   204  }
   205  
   206  func (a *arrayObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
   207  	if i := toIdx(idx); i != math.MaxUint32 {
   208  		return a._setOwnIdx(i, val, throw)
   209  	} else {
   210  		return a.baseObject.setOwnStr(idx.string(), val, throw)
   211  	}
   212  }
   213  
   214  func (a *arrayObject) _setOwnIdx(idx uint32, val Value, throw bool) bool {
   215  	var prop Value
   216  	if idx < uint32(len(a.values)) {
   217  		prop = a.values[idx]
   218  	}
   219  
   220  	if prop == nil {
   221  		if proto := a.prototype; proto != nil {
   222  			// we know it's foreign because prototype loops are not allowed
   223  			if res, ok := proto.self.setForeignIdx(valueInt(idx), val, a.val, throw); ok {
   224  				return res
   225  			}
   226  		}
   227  		// new property
   228  		if !a.extensible {
   229  			a.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx)
   230  			return false
   231  		} else {
   232  			if idx >= a.length {
   233  				if !a.setLengthInt(idx+1, throw) {
   234  					return false
   235  				}
   236  			}
   237  			if idx >= uint32(len(a.values)) {
   238  				if !a.expand(idx) {
   239  					a.val.self.(*sparseArrayObject).add(idx, val)
   240  					return true
   241  				}
   242  			}
   243  			a.objCount++
   244  		}
   245  	} else {
   246  		if prop, ok := prop.(*valueProperty); ok {
   247  			if !prop.isWritable() {
   248  				a.val.runtime.typeErrorResult(throw)
   249  				return false
   250  			}
   251  			prop.set(a.val, val)
   252  			return true
   253  		}
   254  	}
   255  	a.values[idx] = val
   256  	return true
   257  }
   258  
   259  func (a *arrayObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
   260  	if idx := strToArrayIdx(name); idx != math.MaxUint32 {
   261  		return a._setOwnIdx(idx, val, throw)
   262  	} else {
   263  		if name == "length" {
   264  			return a.setLength(a.val.runtime.toLengthUint32(val), throw)
   265  		} else {
   266  			return a.baseObject.setOwnStr(name, val, throw)
   267  		}
   268  	}
   269  }
   270  
   271  func (a *arrayObject) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
   272  	return a._setForeignIdx(idx, a.getOwnPropIdx(idx), val, receiver, throw)
   273  }
   274  
   275  func (a *arrayObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
   276  	return a._setForeignStr(name, a.getOwnPropStr(name), val, receiver, throw)
   277  }
   278  
   279  type arrayPropIter struct {
   280  	a     *arrayObject
   281  	limit int
   282  	idx   int
   283  }
   284  
   285  func (i *arrayPropIter) next() (propIterItem, iterNextFunc) {
   286  	for i.idx < len(i.a.values) && i.idx < i.limit {
   287  		name := asciiString(strconv.Itoa(i.idx))
   288  		prop := i.a.values[i.idx]
   289  		i.idx++
   290  		if prop != nil {
   291  			return propIterItem{name: name, value: prop}, i.next
   292  		}
   293  	}
   294  
   295  	return i.a.baseObject.iterateStringKeys()()
   296  }
   297  
   298  func (a *arrayObject) iterateStringKeys() iterNextFunc {
   299  	return (&arrayPropIter{
   300  		a:     a,
   301  		limit: len(a.values),
   302  	}).next
   303  }
   304  
   305  func (a *arrayObject) stringKeys(all bool, accum []Value) []Value {
   306  	for i, prop := range a.values {
   307  		name := strconv.Itoa(i)
   308  		if prop != nil {
   309  			if !all {
   310  				if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
   311  					continue
   312  				}
   313  			}
   314  			accum = append(accum, asciiString(name))
   315  		}
   316  	}
   317  	return a.baseObject.stringKeys(all, accum)
   318  }
   319  
   320  func (a *arrayObject) hasOwnPropertyStr(name unistring.String) bool {
   321  	if idx := strToArrayIdx(name); idx != math.MaxUint32 {
   322  		return idx < uint32(len(a.values)) && a.values[idx] != nil
   323  	} else {
   324  		return a.baseObject.hasOwnPropertyStr(name)
   325  	}
   326  }
   327  
   328  func (a *arrayObject) hasOwnPropertyIdx(idx valueInt) bool {
   329  	if idx := toIdx(idx); idx != math.MaxUint32 {
   330  		return idx < uint32(len(a.values)) && a.values[idx] != nil
   331  	}
   332  	return a.baseObject.hasOwnPropertyStr(idx.string())
   333  }
   334  
   335  func (a *arrayObject) expand(idx uint32) bool {
   336  	targetLen := idx + 1
   337  	if targetLen > uint32(len(a.values)) {
   338  		if targetLen < uint32(cap(a.values)) {
   339  			a.values = a.values[:targetLen]
   340  		} else {
   341  			if idx > 4096 && (a.objCount == 0 || idx/uint32(a.objCount) > 10) {
   342  				//log.Println("Switching standard->sparse")
   343  				sa := &sparseArrayObject{
   344  					baseObject:     a.baseObject,
   345  					length:         a.length,
   346  					propValueCount: a.propValueCount,
   347  				}
   348  				sa.setValues(a.values, a.objCount+1)
   349  				sa.val.self = sa
   350  				sa.lengthProp.writable = a.lengthProp.writable
   351  				sa._put("length", &sa.lengthProp)
   352  				return false
   353  			} else {
   354  				if bits.UintSize == 32 {
   355  					if targetLen >= math.MaxInt32 {
   356  						panic(a.val.runtime.NewTypeError("Array index overflows int"))
   357  					}
   358  				}
   359  				tl := int(targetLen)
   360  				newValues := make([]Value, tl, growCap(tl, len(a.values), cap(a.values)))
   361  				copy(newValues, a.values)
   362  				a.values = newValues
   363  			}
   364  		}
   365  	}
   366  	return true
   367  }
   368  
   369  func (r *Runtime) defineArrayLength(prop *valueProperty, descr PropertyDescriptor, setter func(uint32, bool) bool, throw bool) bool {
   370  	var newLen uint32
   371  	ret := true
   372  	if descr.Value != nil {
   373  		newLen = r.toLengthUint32(descr.Value)
   374  	}
   375  
   376  	if descr.Configurable == FLAG_TRUE || descr.Enumerable == FLAG_TRUE || descr.Getter != nil || descr.Setter != nil {
   377  		ret = false
   378  		goto Reject
   379  	}
   380  
   381  	if descr.Value != nil {
   382  		oldLen := uint32(prop.value.ToInteger())
   383  		if oldLen != newLen {
   384  			ret = setter(newLen, false)
   385  		}
   386  	} else {
   387  		ret = true
   388  	}
   389  
   390  	if descr.Writable != FLAG_NOT_SET {
   391  		w := descr.Writable.Bool()
   392  		if prop.writable {
   393  			prop.writable = w
   394  		} else {
   395  			if w {
   396  				ret = false
   397  				goto Reject
   398  			}
   399  		}
   400  	}
   401  
   402  Reject:
   403  	if !ret {
   404  		r.typeErrorResult(throw, "Cannot redefine property: length")
   405  	}
   406  
   407  	return ret
   408  }
   409  
   410  func (a *arrayObject) _defineIdxProperty(idx uint32, desc PropertyDescriptor, throw bool) bool {
   411  	var existing Value
   412  	if idx < uint32(len(a.values)) {
   413  		existing = a.values[idx]
   414  	}
   415  	prop, ok := a.baseObject._defineOwnProperty(unistring.String(strconv.FormatUint(uint64(idx), 10)), existing, desc, throw)
   416  	if ok {
   417  		if idx >= a.length {
   418  			if !a.setLengthInt(idx+1, throw) {
   419  				return false
   420  			}
   421  		}
   422  		if a.expand(idx) {
   423  			a.values[idx] = prop
   424  			a.objCount++
   425  			if _, ok := prop.(*valueProperty); ok {
   426  				a.propValueCount++
   427  			}
   428  		} else {
   429  			a.val.self.(*sparseArrayObject).add(idx, prop)
   430  		}
   431  	}
   432  	return ok
   433  }
   434  
   435  func (a *arrayObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
   436  	if idx := strToArrayIdx(name); idx != math.MaxUint32 {
   437  		return a._defineIdxProperty(idx, descr, throw)
   438  	}
   439  	if name == "length" {
   440  		return a.val.runtime.defineArrayLength(a.getLengthProp(), descr, a.setLength, throw)
   441  	}
   442  	return a.baseObject.defineOwnPropertyStr(name, descr, throw)
   443  }
   444  
   445  func (a *arrayObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
   446  	if idx := toIdx(idx); idx != math.MaxUint32 {
   447  		return a._defineIdxProperty(idx, descr, throw)
   448  	}
   449  	return a.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
   450  }
   451  
   452  func (a *arrayObject) _deleteIdxProp(idx uint32, throw bool) bool {
   453  	if idx < uint32(len(a.values)) {
   454  		if v := a.values[idx]; v != nil {
   455  			if p, ok := v.(*valueProperty); ok {
   456  				if !p.configurable {
   457  					a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.toString())
   458  					return false
   459  				}
   460  				a.propValueCount--
   461  			}
   462  			a.values[idx] = nil
   463  			a.objCount--
   464  		}
   465  	}
   466  	return true
   467  }
   468  
   469  func (a *arrayObject) deleteStr(name unistring.String, throw bool) bool {
   470  	if idx := strToArrayIdx(name); idx != math.MaxUint32 {
   471  		return a._deleteIdxProp(idx, throw)
   472  	}
   473  	return a.baseObject.deleteStr(name, throw)
   474  }
   475  
   476  func (a *arrayObject) deleteIdx(idx valueInt, throw bool) bool {
   477  	if idx := toIdx(idx); idx != math.MaxUint32 {
   478  		return a._deleteIdxProp(idx, throw)
   479  	}
   480  	return a.baseObject.deleteStr(idx.string(), throw)
   481  }
   482  
   483  func (a *arrayObject) export(ctx *objectExportCtx) interface{} {
   484  	if v, exists := ctx.get(a.val); exists {
   485  		return v
   486  	}
   487  	arr := make([]interface{}, a.length)
   488  	ctx.put(a.val, arr)
   489  	if a.propValueCount == 0 && a.length == uint32(len(a.values)) && uint32(a.objCount) == a.length {
   490  		for i, v := range a.values {
   491  			if v != nil {
   492  				arr[i] = exportValue(v, ctx)
   493  			}
   494  		}
   495  	} else {
   496  		for i := uint32(0); i < a.length; i++ {
   497  			v := a.getIdx(valueInt(i), nil)
   498  			if v != nil {
   499  				arr[i] = exportValue(v, ctx)
   500  			}
   501  		}
   502  	}
   503  	return arr
   504  }
   505  
   506  func (a *arrayObject) exportType() reflect.Type {
   507  	return reflectTypeArray
   508  }
   509  
   510  func (a *arrayObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
   511  	r := a.val.runtime
   512  	if iter := a.getSym(SymIterator, nil); iter == r.global.arrayValues || iter == nil {
   513  		l := toIntStrict(int64(a.length))
   514  		if typ.Kind() == reflect.Array {
   515  			if dst.Len() != l {
   516  				return fmt.Errorf("cannot convert an Array into an array, lengths mismatch (have %d, need %d)", l, dst.Len())
   517  			}
   518  		} else {
   519  			dst.Set(reflect.MakeSlice(typ, l, l))
   520  		}
   521  		ctx.putTyped(a.val, typ, dst.Interface())
   522  		for i := 0; i < l; i++ {
   523  			if i >= len(a.values) {
   524  				break
   525  			}
   526  			val := a.values[i]
   527  			if p, ok := val.(*valueProperty); ok {
   528  				val = p.get(a.val)
   529  			}
   530  			err := r.toReflectValue(val, dst.Index(i), ctx)
   531  			if err != nil {
   532  				return fmt.Errorf("could not convert array element %v to %v at %d: %w", val, typ, i, err)
   533  			}
   534  		}
   535  		return nil
   536  	}
   537  	return a.baseObject.exportToArrayOrSlice(dst, typ, ctx)
   538  }
   539  
   540  func (a *arrayObject) setValuesFromSparse(items []sparseArrayItem, newMaxIdx int) {
   541  	a.values = make([]Value, newMaxIdx+1)
   542  	for _, item := range items {
   543  		a.values[item.idx] = item.value
   544  	}
   545  	a.objCount = len(items)
   546  }
   547  
   548  func toIdx(v valueInt) uint32 {
   549  	if v >= 0 && v < math.MaxUint32 {
   550  		return uint32(v)
   551  	}
   552  	return math.MaxUint32
   553  }