...

Source file src/github.com/dop251/goja/builtin_array.go

Documentation: github.com/dop251/goja

     1  package goja
     2  
     3  import (
     4  	"math"
     5  	"sort"
     6  	"sync"
     7  )
     8  
     9  func (r *Runtime) newArray(prototype *Object) (a *arrayObject) {
    10  	v := &Object{runtime: r}
    11  
    12  	a = &arrayObject{}
    13  	a.class = classArray
    14  	a.val = v
    15  	a.extensible = true
    16  	v.self = a
    17  	a.prototype = prototype
    18  	a.init()
    19  	return
    20  }
    21  
    22  func (r *Runtime) newArrayObject() *arrayObject {
    23  	return r.newArray(r.getArrayPrototype())
    24  }
    25  
    26  func setArrayValues(a *arrayObject, values []Value) *arrayObject {
    27  	a.values = values
    28  	a.length = uint32(len(values))
    29  	a.objCount = len(values)
    30  	return a
    31  }
    32  
    33  func setArrayLength(a *arrayObject, l int64) *arrayObject {
    34  	a.setOwnStr("length", intToValue(l), true)
    35  	return a
    36  }
    37  
    38  func arraySpeciesCreate(obj *Object, size int64) *Object {
    39  	if isArray(obj) {
    40  		v := obj.self.getStr("constructor", nil)
    41  		if constructObj, ok := v.(*Object); ok {
    42  			v = constructObj.self.getSym(SymSpecies, nil)
    43  			if v == _null {
    44  				v = nil
    45  			}
    46  		}
    47  
    48  		if v != nil && v != _undefined {
    49  			constructObj, _ := v.(*Object)
    50  			if constructObj != nil {
    51  				if constructor := constructObj.self.assertConstructor(); constructor != nil {
    52  					return constructor([]Value{intToValue(size)}, constructObj)
    53  				}
    54  			}
    55  			panic(obj.runtime.NewTypeError("Species is not a constructor"))
    56  		}
    57  	}
    58  	return obj.runtime.newArrayLength(size)
    59  }
    60  
    61  func max(a, b int64) int64 {
    62  	if a > b {
    63  		return a
    64  	}
    65  	return b
    66  }
    67  
    68  func min(a, b int64) int64 {
    69  	if a < b {
    70  		return a
    71  	}
    72  	return b
    73  }
    74  
    75  func relToIdx(rel, l int64) int64 {
    76  	if rel >= 0 {
    77  		return min(rel, l)
    78  	}
    79  	return max(l+rel, 0)
    80  }
    81  
    82  func (r *Runtime) newArrayValues(values []Value) *Object {
    83  	return setArrayValues(r.newArrayObject(), values).val
    84  }
    85  
    86  func (r *Runtime) newArrayLength(l int64) *Object {
    87  	return setArrayLength(r.newArrayObject(), l).val
    88  }
    89  
    90  func (r *Runtime) builtin_newArray(args []Value, proto *Object) *Object {
    91  	l := len(args)
    92  	if l == 1 {
    93  		if al, ok := args[0].(valueInt); ok {
    94  			return setArrayLength(r.newArray(proto), int64(al)).val
    95  		} else if f, ok := args[0].(valueFloat); ok {
    96  			al := int64(f)
    97  			if float64(al) == float64(f) {
    98  				return r.newArrayLength(al)
    99  			} else {
   100  				panic(r.newError(r.getRangeError(), "Invalid array length"))
   101  			}
   102  		}
   103  		return setArrayValues(r.newArray(proto), []Value{args[0]}).val
   104  	} else {
   105  		argsCopy := make([]Value, l)
   106  		copy(argsCopy, args)
   107  		return setArrayValues(r.newArray(proto), argsCopy).val
   108  	}
   109  }
   110  
   111  func (r *Runtime) generic_push(obj *Object, call FunctionCall) Value {
   112  	l := toLength(obj.self.getStr("length", nil))
   113  	nl := l + int64(len(call.Arguments))
   114  	if nl >= maxInt {
   115  		r.typeErrorResult(true, "Invalid array length")
   116  		panic("unreachable")
   117  	}
   118  	for i, arg := range call.Arguments {
   119  		obj.self.setOwnIdx(valueInt(l+int64(i)), arg, true)
   120  	}
   121  	n := valueInt(nl)
   122  	obj.self.setOwnStr("length", n, true)
   123  	return n
   124  }
   125  
   126  func (r *Runtime) arrayproto_push(call FunctionCall) Value {
   127  	obj := call.This.ToObject(r)
   128  	return r.generic_push(obj, call)
   129  }
   130  
   131  func (r *Runtime) arrayproto_pop_generic(obj *Object) Value {
   132  	l := toLength(obj.self.getStr("length", nil))
   133  	if l == 0 {
   134  		obj.self.setOwnStr("length", intToValue(0), true)
   135  		return _undefined
   136  	}
   137  	idx := valueInt(l - 1)
   138  	val := obj.self.getIdx(idx, nil)
   139  	obj.self.deleteIdx(idx, true)
   140  	obj.self.setOwnStr("length", idx, true)
   141  	return val
   142  }
   143  
   144  func (r *Runtime) arrayproto_pop(call FunctionCall) Value {
   145  	obj := call.This.ToObject(r)
   146  	if a, ok := obj.self.(*arrayObject); ok {
   147  		l := a.length
   148  		var val Value
   149  		if l > 0 {
   150  			l--
   151  			if l < uint32(len(a.values)) {
   152  				val = a.values[l]
   153  			}
   154  			if val == nil {
   155  				// optimisation bail-out
   156  				return r.arrayproto_pop_generic(obj)
   157  			}
   158  			if _, ok := val.(*valueProperty); ok {
   159  				// optimisation bail-out
   160  				return r.arrayproto_pop_generic(obj)
   161  			}
   162  			//a._setLengthInt(l, false)
   163  			a.values[l] = nil
   164  			a.values = a.values[:l]
   165  		} else {
   166  			val = _undefined
   167  		}
   168  		if a.lengthProp.writable {
   169  			a.length = l
   170  		} else {
   171  			a.setLength(0, true) // will throw
   172  		}
   173  		return val
   174  	} else {
   175  		return r.arrayproto_pop_generic(obj)
   176  	}
   177  }
   178  
   179  func (r *Runtime) arrayproto_join(call FunctionCall) Value {
   180  	o := call.This.ToObject(r)
   181  	l := int(toLength(o.self.getStr("length", nil)))
   182  	var sep String
   183  	if s := call.Argument(0); s != _undefined {
   184  		sep = s.toString()
   185  	} else {
   186  		sep = asciiString(",")
   187  	}
   188  	if l == 0 {
   189  		return stringEmpty
   190  	}
   191  
   192  	var buf StringBuilder
   193  
   194  	element0 := o.self.getIdx(valueInt(0), nil)
   195  	if element0 != nil && element0 != _undefined && element0 != _null {
   196  		buf.WriteString(element0.toString())
   197  	}
   198  
   199  	for i := 1; i < l; i++ {
   200  		buf.WriteString(sep)
   201  		element := o.self.getIdx(valueInt(int64(i)), nil)
   202  		if element != nil && element != _undefined && element != _null {
   203  			buf.WriteString(element.toString())
   204  		}
   205  	}
   206  
   207  	return buf.String()
   208  }
   209  
   210  func (r *Runtime) arrayproto_toString(call FunctionCall) Value {
   211  	array := call.This.ToObject(r)
   212  	var toString func() Value
   213  	switch a := array.self.(type) {
   214  	case *objectGoSliceReflect:
   215  		toString = a.toString
   216  	case *objectGoArrayReflect:
   217  		toString = a.toString
   218  	}
   219  	if toString != nil {
   220  		return toString()
   221  	}
   222  	f := array.self.getStr("join", nil)
   223  	if fObj, ok := f.(*Object); ok {
   224  		if fcall, ok := fObj.self.assertCallable(); ok {
   225  			return fcall(FunctionCall{
   226  				This: array,
   227  			})
   228  		}
   229  	}
   230  	return r.objectproto_toString(FunctionCall{
   231  		This: array,
   232  	})
   233  }
   234  
   235  func (r *Runtime) writeItemLocaleString(item Value, buf *StringBuilder) {
   236  	if item != nil && item != _undefined && item != _null {
   237  		if f, ok := r.getVStr(item, "toLocaleString").(*Object); ok {
   238  			if c, ok := f.self.assertCallable(); ok {
   239  				strVal := c(FunctionCall{
   240  					This: item,
   241  				})
   242  				buf.WriteString(strVal.toString())
   243  				return
   244  			}
   245  		}
   246  		r.typeErrorResult(true, "Property 'toLocaleString' of object %s is not a function", item)
   247  	}
   248  }
   249  
   250  func (r *Runtime) arrayproto_toLocaleString(call FunctionCall) Value {
   251  	array := call.This.ToObject(r)
   252  	var buf StringBuilder
   253  	if a := r.checkStdArrayObj(array); a != nil {
   254  		for i, item := range a.values {
   255  			if i > 0 {
   256  				buf.WriteRune(',')
   257  			}
   258  			r.writeItemLocaleString(item, &buf)
   259  		}
   260  	} else {
   261  		length := toLength(array.self.getStr("length", nil))
   262  		for i := int64(0); i < length; i++ {
   263  			if i > 0 {
   264  				buf.WriteRune(',')
   265  			}
   266  			item := array.self.getIdx(valueInt(i), nil)
   267  			r.writeItemLocaleString(item, &buf)
   268  		}
   269  	}
   270  
   271  	return buf.String()
   272  }
   273  
   274  func isConcatSpreadable(obj *Object) bool {
   275  	spreadable := obj.self.getSym(SymIsConcatSpreadable, nil)
   276  	if spreadable != nil && spreadable != _undefined {
   277  		return spreadable.ToBoolean()
   278  	}
   279  	return isArray(obj)
   280  }
   281  
   282  func (r *Runtime) arrayproto_concat_append(a *Object, item Value) {
   283  	aLength := toLength(a.self.getStr("length", nil))
   284  	if obj, ok := item.(*Object); ok && isConcatSpreadable(obj) {
   285  		length := toLength(obj.self.getStr("length", nil))
   286  		if aLength+length >= maxInt {
   287  			panic(r.NewTypeError("Invalid array length"))
   288  		}
   289  		for i := int64(0); i < length; i++ {
   290  			v := obj.self.getIdx(valueInt(i), nil)
   291  			if v != nil {
   292  				createDataPropertyOrThrow(a, intToValue(aLength), v)
   293  			}
   294  			aLength++
   295  		}
   296  	} else {
   297  		createDataPropertyOrThrow(a, intToValue(aLength), item)
   298  		aLength++
   299  	}
   300  	a.self.setOwnStr("length", intToValue(aLength), true)
   301  }
   302  
   303  func (r *Runtime) arrayproto_concat(call FunctionCall) Value {
   304  	obj := call.This.ToObject(r)
   305  	a := arraySpeciesCreate(obj, 0)
   306  	r.arrayproto_concat_append(a, call.This.ToObject(r))
   307  	for _, item := range call.Arguments {
   308  		r.arrayproto_concat_append(a, item)
   309  	}
   310  	return a
   311  }
   312  
   313  func (r *Runtime) arrayproto_slice(call FunctionCall) Value {
   314  	o := call.This.ToObject(r)
   315  	length := toLength(o.self.getStr("length", nil))
   316  	start := relToIdx(call.Argument(0).ToInteger(), length)
   317  	var end int64
   318  	if endArg := call.Argument(1); endArg != _undefined {
   319  		end = endArg.ToInteger()
   320  	} else {
   321  		end = length
   322  	}
   323  	end = relToIdx(end, length)
   324  
   325  	count := end - start
   326  	if count < 0 {
   327  		count = 0
   328  	}
   329  
   330  	a := arraySpeciesCreate(o, count)
   331  	if src := r.checkStdArrayObj(o); src != nil {
   332  		if dst := r.checkStdArrayObjWithProto(a); dst != nil {
   333  			values := make([]Value, count)
   334  			copy(values, src.values[start:])
   335  			setArrayValues(dst, values)
   336  			return a
   337  		}
   338  	}
   339  
   340  	n := int64(0)
   341  	for start < end {
   342  		p := o.self.getIdx(valueInt(start), nil)
   343  		if p != nil {
   344  			createDataPropertyOrThrow(a, valueInt(n), p)
   345  		}
   346  		start++
   347  		n++
   348  	}
   349  	return a
   350  }
   351  
   352  func (r *Runtime) arrayproto_sort(call FunctionCall) Value {
   353  	o := call.This.ToObject(r)
   354  
   355  	var compareFn func(FunctionCall) Value
   356  	arg := call.Argument(0)
   357  	if arg != _undefined {
   358  		if arg, ok := call.Argument(0).(*Object); ok {
   359  			compareFn, _ = arg.self.assertCallable()
   360  		}
   361  		if compareFn == nil {
   362  			panic(r.NewTypeError("The comparison function must be either a function or undefined"))
   363  		}
   364  	}
   365  
   366  	var s sortable
   367  	if r.checkStdArrayObj(o) != nil {
   368  		s = o.self
   369  	} else if _, ok := o.self.(reflectValueWrapper); ok {
   370  		s = o.self
   371  	}
   372  
   373  	if s != nil {
   374  		ctx := arraySortCtx{
   375  			obj:     s,
   376  			compare: compareFn,
   377  		}
   378  
   379  		sort.Stable(&ctx)
   380  	} else {
   381  		length := toLength(o.self.getStr("length", nil))
   382  		a := make([]Value, 0, length)
   383  		for i := int64(0); i < length; i++ {
   384  			idx := valueInt(i)
   385  			if o.self.hasPropertyIdx(idx) {
   386  				a = append(a, nilSafe(o.self.getIdx(idx, nil)))
   387  			}
   388  		}
   389  		ar := r.newArrayValues(a)
   390  		ctx := arraySortCtx{
   391  			obj:     ar.self,
   392  			compare: compareFn,
   393  		}
   394  
   395  		sort.Stable(&ctx)
   396  		for i := 0; i < len(a); i++ {
   397  			o.self.setOwnIdx(valueInt(i), a[i], true)
   398  		}
   399  		for i := int64(len(a)); i < length; i++ {
   400  			o.self.deleteIdx(valueInt(i), true)
   401  		}
   402  	}
   403  	return o
   404  }
   405  
   406  func (r *Runtime) arrayproto_splice(call FunctionCall) Value {
   407  	o := call.This.ToObject(r)
   408  	length := toLength(o.self.getStr("length", nil))
   409  	actualStart := relToIdx(call.Argument(0).ToInteger(), length)
   410  	var actualDeleteCount int64
   411  	switch len(call.Arguments) {
   412  	case 0:
   413  	case 1:
   414  		actualDeleteCount = length - actualStart
   415  	default:
   416  		actualDeleteCount = min(max(call.Argument(1).ToInteger(), 0), length-actualStart)
   417  	}
   418  	itemCount := max(int64(len(call.Arguments)-2), 0)
   419  	newLength := length - actualDeleteCount + itemCount
   420  	if newLength >= maxInt {
   421  		panic(r.NewTypeError("Invalid array length"))
   422  	}
   423  	a := arraySpeciesCreate(o, actualDeleteCount)
   424  	if src := r.checkStdArrayObj(o); src != nil {
   425  		if dst := r.checkStdArrayObjWithProto(a); dst != nil {
   426  			values := make([]Value, actualDeleteCount)
   427  			copy(values, src.values[actualStart:])
   428  			setArrayValues(dst, values)
   429  		} else {
   430  			for k := int64(0); k < actualDeleteCount; k++ {
   431  				createDataPropertyOrThrow(a, intToValue(k), src.values[k+actualStart])
   432  			}
   433  			a.self.setOwnStr("length", intToValue(actualDeleteCount), true)
   434  		}
   435  		var values []Value
   436  		if itemCount < actualDeleteCount {
   437  			values = src.values
   438  			copy(values[actualStart+itemCount:], values[actualStart+actualDeleteCount:])
   439  			tail := values[newLength:]
   440  			for k := range tail {
   441  				tail[k] = nil
   442  			}
   443  			values = values[:newLength]
   444  		} else if itemCount > actualDeleteCount {
   445  			if int64(cap(src.values)) >= newLength {
   446  				values = src.values[:newLength]
   447  				copy(values[actualStart+itemCount:], values[actualStart+actualDeleteCount:length])
   448  			} else {
   449  				values = make([]Value, newLength)
   450  				copy(values, src.values[:actualStart])
   451  				copy(values[actualStart+itemCount:], src.values[actualStart+actualDeleteCount:])
   452  			}
   453  		} else {
   454  			values = src.values
   455  		}
   456  		if itemCount > 0 {
   457  			copy(values[actualStart:], call.Arguments[2:])
   458  		}
   459  		src.values = values
   460  		src.objCount = len(values)
   461  	} else {
   462  		for k := int64(0); k < actualDeleteCount; k++ {
   463  			from := valueInt(k + actualStart)
   464  			if o.self.hasPropertyIdx(from) {
   465  				createDataPropertyOrThrow(a, valueInt(k), nilSafe(o.self.getIdx(from, nil)))
   466  			}
   467  		}
   468  
   469  		if itemCount < actualDeleteCount {
   470  			for k := actualStart; k < length-actualDeleteCount; k++ {
   471  				from := valueInt(k + actualDeleteCount)
   472  				to := valueInt(k + itemCount)
   473  				if o.self.hasPropertyIdx(from) {
   474  					o.self.setOwnIdx(to, nilSafe(o.self.getIdx(from, nil)), true)
   475  				} else {
   476  					o.self.deleteIdx(to, true)
   477  				}
   478  			}
   479  
   480  			for k := length; k > length-actualDeleteCount+itemCount; k-- {
   481  				o.self.deleteIdx(valueInt(k-1), true)
   482  			}
   483  		} else if itemCount > actualDeleteCount {
   484  			for k := length - actualDeleteCount; k > actualStart; k-- {
   485  				from := valueInt(k + actualDeleteCount - 1)
   486  				to := valueInt(k + itemCount - 1)
   487  				if o.self.hasPropertyIdx(from) {
   488  					o.self.setOwnIdx(to, nilSafe(o.self.getIdx(from, nil)), true)
   489  				} else {
   490  					o.self.deleteIdx(to, true)
   491  				}
   492  			}
   493  		}
   494  
   495  		if itemCount > 0 {
   496  			for i, item := range call.Arguments[2:] {
   497  				o.self.setOwnIdx(valueInt(actualStart+int64(i)), item, true)
   498  			}
   499  		}
   500  	}
   501  
   502  	o.self.setOwnStr("length", intToValue(newLength), true)
   503  
   504  	return a
   505  }
   506  
   507  func (r *Runtime) arrayproto_unshift(call FunctionCall) Value {
   508  	o := call.This.ToObject(r)
   509  	length := toLength(o.self.getStr("length", nil))
   510  	argCount := int64(len(call.Arguments))
   511  	newLen := intToValue(length + argCount)
   512  	if argCount > 0 {
   513  		newSize := length + argCount
   514  		if newSize >= maxInt {
   515  			panic(r.NewTypeError("Invalid array length"))
   516  		}
   517  		if arr := r.checkStdArrayObjWithProto(o); arr != nil && newSize < math.MaxUint32 {
   518  			if int64(cap(arr.values)) >= newSize {
   519  				arr.values = arr.values[:newSize]
   520  				copy(arr.values[argCount:], arr.values[:length])
   521  			} else {
   522  				values := make([]Value, newSize)
   523  				copy(values[argCount:], arr.values)
   524  				arr.values = values
   525  			}
   526  			copy(arr.values, call.Arguments)
   527  			arr.objCount = int(arr.length)
   528  		} else {
   529  			for k := length - 1; k >= 0; k-- {
   530  				from := valueInt(k)
   531  				to := valueInt(k + argCount)
   532  				if o.self.hasPropertyIdx(from) {
   533  					o.self.setOwnIdx(to, nilSafe(o.self.getIdx(from, nil)), true)
   534  				} else {
   535  					o.self.deleteIdx(to, true)
   536  				}
   537  			}
   538  
   539  			for k, arg := range call.Arguments {
   540  				o.self.setOwnIdx(valueInt(int64(k)), arg, true)
   541  			}
   542  		}
   543  	}
   544  
   545  	o.self.setOwnStr("length", newLen, true)
   546  	return newLen
   547  }
   548  
   549  func (r *Runtime) arrayproto_at(call FunctionCall) Value {
   550  	o := call.This.ToObject(r)
   551  	idx := call.Argument(0).ToInteger()
   552  	length := toLength(o.self.getStr("length", nil))
   553  	if idx < 0 {
   554  		idx = length + idx
   555  	}
   556  	if idx >= length || idx < 0 {
   557  		return _undefined
   558  	}
   559  	i := valueInt(idx)
   560  	if o.self.hasPropertyIdx(i) {
   561  		return o.self.getIdx(i, nil)
   562  	}
   563  	return _undefined
   564  }
   565  
   566  func (r *Runtime) arrayproto_indexOf(call FunctionCall) Value {
   567  	o := call.This.ToObject(r)
   568  	length := toLength(o.self.getStr("length", nil))
   569  	if length == 0 {
   570  		return intToValue(-1)
   571  	}
   572  
   573  	n := call.Argument(1).ToInteger()
   574  	if n >= length {
   575  		return intToValue(-1)
   576  	}
   577  
   578  	if n < 0 {
   579  		n = max(length+n, 0)
   580  	}
   581  
   582  	searchElement := call.Argument(0)
   583  
   584  	if arr := r.checkStdArrayObj(o); arr != nil {
   585  		for i, val := range arr.values[n:] {
   586  			if searchElement.StrictEquals(val) {
   587  				return intToValue(n + int64(i))
   588  			}
   589  		}
   590  		return intToValue(-1)
   591  	}
   592  
   593  	for ; n < length; n++ {
   594  		idx := valueInt(n)
   595  		if o.self.hasPropertyIdx(idx) {
   596  			if val := o.self.getIdx(idx, nil); val != nil {
   597  				if searchElement.StrictEquals(val) {
   598  					return idx
   599  				}
   600  			}
   601  		}
   602  	}
   603  
   604  	return intToValue(-1)
   605  }
   606  
   607  func (r *Runtime) arrayproto_includes(call FunctionCall) Value {
   608  	o := call.This.ToObject(r)
   609  	length := toLength(o.self.getStr("length", nil))
   610  	if length == 0 {
   611  		return valueFalse
   612  	}
   613  
   614  	n := call.Argument(1).ToInteger()
   615  	if n >= length {
   616  		return valueFalse
   617  	}
   618  
   619  	if n < 0 {
   620  		n = max(length+n, 0)
   621  	}
   622  
   623  	searchElement := call.Argument(0)
   624  	if searchElement == _negativeZero {
   625  		searchElement = _positiveZero
   626  	}
   627  
   628  	if arr := r.checkStdArrayObj(o); arr != nil {
   629  		for _, val := range arr.values[n:] {
   630  			if searchElement.SameAs(val) {
   631  				return valueTrue
   632  			}
   633  		}
   634  		return valueFalse
   635  	}
   636  
   637  	for ; n < length; n++ {
   638  		idx := valueInt(n)
   639  		val := nilSafe(o.self.getIdx(idx, nil))
   640  		if searchElement.SameAs(val) {
   641  			return valueTrue
   642  		}
   643  	}
   644  
   645  	return valueFalse
   646  }
   647  
   648  func (r *Runtime) arrayproto_lastIndexOf(call FunctionCall) Value {
   649  	o := call.This.ToObject(r)
   650  	length := toLength(o.self.getStr("length", nil))
   651  	if length == 0 {
   652  		return intToValue(-1)
   653  	}
   654  
   655  	var fromIndex int64
   656  
   657  	if len(call.Arguments) < 2 {
   658  		fromIndex = length - 1
   659  	} else {
   660  		fromIndex = call.Argument(1).ToInteger()
   661  		if fromIndex >= 0 {
   662  			fromIndex = min(fromIndex, length-1)
   663  		} else {
   664  			fromIndex += length
   665  		}
   666  	}
   667  
   668  	searchElement := call.Argument(0)
   669  
   670  	if arr := r.checkStdArrayObj(o); arr != nil {
   671  		vals := arr.values
   672  		for k := fromIndex; k >= 0; k-- {
   673  			if v := vals[k]; v != nil && searchElement.StrictEquals(v) {
   674  				return intToValue(k)
   675  			}
   676  		}
   677  		return intToValue(-1)
   678  	}
   679  
   680  	for k := fromIndex; k >= 0; k-- {
   681  		idx := valueInt(k)
   682  		if o.self.hasPropertyIdx(idx) {
   683  			if val := o.self.getIdx(idx, nil); val != nil {
   684  				if searchElement.StrictEquals(val) {
   685  					return idx
   686  				}
   687  			}
   688  		}
   689  	}
   690  
   691  	return intToValue(-1)
   692  }
   693  
   694  func (r *Runtime) arrayproto_every(call FunctionCall) Value {
   695  	o := call.This.ToObject(r)
   696  	length := toLength(o.self.getStr("length", nil))
   697  	callbackFn := r.toCallable(call.Argument(0))
   698  	fc := FunctionCall{
   699  		This:      call.Argument(1),
   700  		Arguments: []Value{nil, nil, o},
   701  	}
   702  	for k := int64(0); k < length; k++ {
   703  		idx := valueInt(k)
   704  		if val := o.self.getIdx(idx, nil); val != nil {
   705  			fc.Arguments[0] = val
   706  			fc.Arguments[1] = idx
   707  			if !callbackFn(fc).ToBoolean() {
   708  				return valueFalse
   709  			}
   710  		}
   711  	}
   712  	return valueTrue
   713  }
   714  
   715  func (r *Runtime) arrayproto_some(call FunctionCall) Value {
   716  	o := call.This.ToObject(r)
   717  	length := toLength(o.self.getStr("length", nil))
   718  	callbackFn := r.toCallable(call.Argument(0))
   719  	fc := FunctionCall{
   720  		This:      call.Argument(1),
   721  		Arguments: []Value{nil, nil, o},
   722  	}
   723  	for k := int64(0); k < length; k++ {
   724  		idx := valueInt(k)
   725  		if val := o.self.getIdx(idx, nil); val != nil {
   726  			fc.Arguments[0] = val
   727  			fc.Arguments[1] = idx
   728  			if callbackFn(fc).ToBoolean() {
   729  				return valueTrue
   730  			}
   731  		}
   732  	}
   733  	return valueFalse
   734  }
   735  
   736  func (r *Runtime) arrayproto_forEach(call FunctionCall) Value {
   737  	o := call.This.ToObject(r)
   738  	length := toLength(o.self.getStr("length", nil))
   739  	callbackFn := r.toCallable(call.Argument(0))
   740  	fc := FunctionCall{
   741  		This:      call.Argument(1),
   742  		Arguments: []Value{nil, nil, o},
   743  	}
   744  	for k := int64(0); k < length; k++ {
   745  		idx := valueInt(k)
   746  		if val := o.self.getIdx(idx, nil); val != nil {
   747  			fc.Arguments[0] = val
   748  			fc.Arguments[1] = idx
   749  			callbackFn(fc)
   750  		}
   751  	}
   752  	return _undefined
   753  }
   754  
   755  func (r *Runtime) arrayproto_map(call FunctionCall) Value {
   756  	o := call.This.ToObject(r)
   757  	length := toLength(o.self.getStr("length", nil))
   758  	callbackFn := r.toCallable(call.Argument(0))
   759  	fc := FunctionCall{
   760  		This:      call.Argument(1),
   761  		Arguments: []Value{nil, nil, o},
   762  	}
   763  	a := arraySpeciesCreate(o, length)
   764  	if _, stdSrc := o.self.(*arrayObject); stdSrc {
   765  		if arr, ok := a.self.(*arrayObject); ok {
   766  			values := make([]Value, length)
   767  			for k := int64(0); k < length; k++ {
   768  				idx := valueInt(k)
   769  				if val := o.self.getIdx(idx, nil); val != nil {
   770  					fc.Arguments[0] = val
   771  					fc.Arguments[1] = idx
   772  					values[k] = callbackFn(fc)
   773  				}
   774  			}
   775  			setArrayValues(arr, values)
   776  			return a
   777  		}
   778  	}
   779  	for k := int64(0); k < length; k++ {
   780  		idx := valueInt(k)
   781  		if val := o.self.getIdx(idx, nil); val != nil {
   782  			fc.Arguments[0] = val
   783  			fc.Arguments[1] = idx
   784  			createDataPropertyOrThrow(a, idx, callbackFn(fc))
   785  		}
   786  	}
   787  	return a
   788  }
   789  
   790  func (r *Runtime) arrayproto_filter(call FunctionCall) Value {
   791  	o := call.This.ToObject(r)
   792  	length := toLength(o.self.getStr("length", nil))
   793  	callbackFn := call.Argument(0).ToObject(r)
   794  	if callbackFn, ok := callbackFn.self.assertCallable(); ok {
   795  		a := arraySpeciesCreate(o, 0)
   796  		fc := FunctionCall{
   797  			This:      call.Argument(1),
   798  			Arguments: []Value{nil, nil, o},
   799  		}
   800  		if _, stdSrc := o.self.(*arrayObject); stdSrc {
   801  			if arr := r.checkStdArrayObj(a); arr != nil {
   802  				var values []Value
   803  				for k := int64(0); k < length; k++ {
   804  					idx := valueInt(k)
   805  					if val := o.self.getIdx(idx, nil); val != nil {
   806  						fc.Arguments[0] = val
   807  						fc.Arguments[1] = idx
   808  						if callbackFn(fc).ToBoolean() {
   809  							values = append(values, val)
   810  						}
   811  					}
   812  				}
   813  				setArrayValues(arr, values)
   814  				return a
   815  			}
   816  		}
   817  
   818  		to := int64(0)
   819  		for k := int64(0); k < length; k++ {
   820  			idx := valueInt(k)
   821  			if val := o.self.getIdx(idx, nil); val != nil {
   822  				fc.Arguments[0] = val
   823  				fc.Arguments[1] = idx
   824  				if callbackFn(fc).ToBoolean() {
   825  					createDataPropertyOrThrow(a, intToValue(to), val)
   826  					to++
   827  				}
   828  			}
   829  		}
   830  		return a
   831  	} else {
   832  		r.typeErrorResult(true, "%s is not a function", call.Argument(0))
   833  	}
   834  	panic("unreachable")
   835  }
   836  
   837  func (r *Runtime) arrayproto_reduce(call FunctionCall) Value {
   838  	o := call.This.ToObject(r)
   839  	length := toLength(o.self.getStr("length", nil))
   840  	callbackFn := call.Argument(0).ToObject(r)
   841  	if callbackFn, ok := callbackFn.self.assertCallable(); ok {
   842  		fc := FunctionCall{
   843  			This:      _undefined,
   844  			Arguments: []Value{nil, nil, nil, o},
   845  		}
   846  
   847  		var k int64
   848  
   849  		if len(call.Arguments) >= 2 {
   850  			fc.Arguments[0] = call.Argument(1)
   851  		} else {
   852  			for ; k < length; k++ {
   853  				idx := valueInt(k)
   854  				if val := o.self.getIdx(idx, nil); val != nil {
   855  					fc.Arguments[0] = val
   856  					break
   857  				}
   858  			}
   859  			if fc.Arguments[0] == nil {
   860  				r.typeErrorResult(true, "No initial value")
   861  				panic("unreachable")
   862  			}
   863  			k++
   864  		}
   865  
   866  		for ; k < length; k++ {
   867  			idx := valueInt(k)
   868  			if val := o.self.getIdx(idx, nil); val != nil {
   869  				fc.Arguments[1] = val
   870  				fc.Arguments[2] = idx
   871  				fc.Arguments[0] = callbackFn(fc)
   872  			}
   873  		}
   874  		return fc.Arguments[0]
   875  	} else {
   876  		r.typeErrorResult(true, "%s is not a function", call.Argument(0))
   877  	}
   878  	panic("unreachable")
   879  }
   880  
   881  func (r *Runtime) arrayproto_reduceRight(call FunctionCall) Value {
   882  	o := call.This.ToObject(r)
   883  	length := toLength(o.self.getStr("length", nil))
   884  	callbackFn := call.Argument(0).ToObject(r)
   885  	if callbackFn, ok := callbackFn.self.assertCallable(); ok {
   886  		fc := FunctionCall{
   887  			This:      _undefined,
   888  			Arguments: []Value{nil, nil, nil, o},
   889  		}
   890  
   891  		k := length - 1
   892  
   893  		if len(call.Arguments) >= 2 {
   894  			fc.Arguments[0] = call.Argument(1)
   895  		} else {
   896  			for ; k >= 0; k-- {
   897  				idx := valueInt(k)
   898  				if val := o.self.getIdx(idx, nil); val != nil {
   899  					fc.Arguments[0] = val
   900  					break
   901  				}
   902  			}
   903  			if fc.Arguments[0] == nil {
   904  				r.typeErrorResult(true, "No initial value")
   905  				panic("unreachable")
   906  			}
   907  			k--
   908  		}
   909  
   910  		for ; k >= 0; k-- {
   911  			idx := valueInt(k)
   912  			if val := o.self.getIdx(idx, nil); val != nil {
   913  				fc.Arguments[1] = val
   914  				fc.Arguments[2] = idx
   915  				fc.Arguments[0] = callbackFn(fc)
   916  			}
   917  		}
   918  		return fc.Arguments[0]
   919  	} else {
   920  		r.typeErrorResult(true, "%s is not a function", call.Argument(0))
   921  	}
   922  	panic("unreachable")
   923  }
   924  
   925  func arrayproto_reverse_generic_step(o *Object, lower, upper int64) {
   926  	lowerP := valueInt(lower)
   927  	upperP := valueInt(upper)
   928  	var lowerValue, upperValue Value
   929  	lowerExists := o.self.hasPropertyIdx(lowerP)
   930  	if lowerExists {
   931  		lowerValue = nilSafe(o.self.getIdx(lowerP, nil))
   932  	}
   933  	upperExists := o.self.hasPropertyIdx(upperP)
   934  	if upperExists {
   935  		upperValue = nilSafe(o.self.getIdx(upperP, nil))
   936  	}
   937  	if lowerExists && upperExists {
   938  		o.self.setOwnIdx(lowerP, upperValue, true)
   939  		o.self.setOwnIdx(upperP, lowerValue, true)
   940  	} else if !lowerExists && upperExists {
   941  		o.self.setOwnIdx(lowerP, upperValue, true)
   942  		o.self.deleteIdx(upperP, true)
   943  	} else if lowerExists && !upperExists {
   944  		o.self.deleteIdx(lowerP, true)
   945  		o.self.setOwnIdx(upperP, lowerValue, true)
   946  	}
   947  }
   948  
   949  func (r *Runtime) arrayproto_reverse_generic(o *Object, start int64) {
   950  	l := toLength(o.self.getStr("length", nil))
   951  	middle := l / 2
   952  	for lower := start; lower != middle; lower++ {
   953  		arrayproto_reverse_generic_step(o, lower, l-lower-1)
   954  	}
   955  }
   956  
   957  func (r *Runtime) arrayproto_reverse(call FunctionCall) Value {
   958  	o := call.This.ToObject(r)
   959  	if a := r.checkStdArrayObj(o); a != nil {
   960  		l := len(a.values)
   961  		middle := l / 2
   962  		for lower := 0; lower != middle; lower++ {
   963  			upper := l - lower - 1
   964  			a.values[lower], a.values[upper] = a.values[upper], a.values[lower]
   965  		}
   966  		//TODO: go arrays
   967  	} else {
   968  		r.arrayproto_reverse_generic(o, 0)
   969  	}
   970  	return o
   971  }
   972  
   973  func (r *Runtime) arrayproto_shift(call FunctionCall) Value {
   974  	o := call.This.ToObject(r)
   975  	if a := r.checkStdArrayObjWithProto(o); a != nil {
   976  		if len(a.values) == 0 {
   977  			if !a.lengthProp.writable {
   978  				a.setLength(0, true) // will throw
   979  			}
   980  			return _undefined
   981  		}
   982  		first := a.values[0]
   983  		copy(a.values, a.values[1:])
   984  		a.values[len(a.values)-1] = nil
   985  		a.values = a.values[:len(a.values)-1]
   986  		a.length--
   987  		return first
   988  	}
   989  	length := toLength(o.self.getStr("length", nil))
   990  	if length == 0 {
   991  		o.self.setOwnStr("length", intToValue(0), true)
   992  		return _undefined
   993  	}
   994  	first := o.self.getIdx(valueInt(0), nil)
   995  	for i := int64(1); i < length; i++ {
   996  		idxFrom := valueInt(i)
   997  		idxTo := valueInt(i - 1)
   998  		if o.self.hasPropertyIdx(idxFrom) {
   999  			o.self.setOwnIdx(idxTo, nilSafe(o.self.getIdx(idxFrom, nil)), true)
  1000  		} else {
  1001  			o.self.deleteIdx(idxTo, true)
  1002  		}
  1003  	}
  1004  
  1005  	lv := valueInt(length - 1)
  1006  	o.self.deleteIdx(lv, true)
  1007  	o.self.setOwnStr("length", lv, true)
  1008  
  1009  	return first
  1010  }
  1011  
  1012  func (r *Runtime) arrayproto_values(call FunctionCall) Value {
  1013  	return r.createArrayIterator(call.This.ToObject(r), iterationKindValue)
  1014  }
  1015  
  1016  func (r *Runtime) arrayproto_keys(call FunctionCall) Value {
  1017  	return r.createArrayIterator(call.This.ToObject(r), iterationKindKey)
  1018  }
  1019  
  1020  func (r *Runtime) arrayproto_copyWithin(call FunctionCall) Value {
  1021  	o := call.This.ToObject(r)
  1022  	l := toLength(o.self.getStr("length", nil))
  1023  	var relEnd, dir int64
  1024  	to := relToIdx(call.Argument(0).ToInteger(), l)
  1025  	from := relToIdx(call.Argument(1).ToInteger(), l)
  1026  	if end := call.Argument(2); end != _undefined {
  1027  		relEnd = end.ToInteger()
  1028  	} else {
  1029  		relEnd = l
  1030  	}
  1031  	final := relToIdx(relEnd, l)
  1032  	count := min(final-from, l-to)
  1033  	if arr := r.checkStdArrayObj(o); arr != nil {
  1034  		if count > 0 {
  1035  			copy(arr.values[to:to+count], arr.values[from:from+count])
  1036  		}
  1037  		return o
  1038  	}
  1039  	if from < to && to < from+count {
  1040  		dir = -1
  1041  		from = from + count - 1
  1042  		to = to + count - 1
  1043  	} else {
  1044  		dir = 1
  1045  	}
  1046  	for count > 0 {
  1047  		if o.self.hasPropertyIdx(valueInt(from)) {
  1048  			o.self.setOwnIdx(valueInt(to), nilSafe(o.self.getIdx(valueInt(from), nil)), true)
  1049  		} else {
  1050  			o.self.deleteIdx(valueInt(to), true)
  1051  		}
  1052  		from += dir
  1053  		to += dir
  1054  		count--
  1055  	}
  1056  
  1057  	return o
  1058  }
  1059  
  1060  func (r *Runtime) arrayproto_entries(call FunctionCall) Value {
  1061  	return r.createArrayIterator(call.This.ToObject(r), iterationKindKeyValue)
  1062  }
  1063  
  1064  func (r *Runtime) arrayproto_fill(call FunctionCall) Value {
  1065  	o := call.This.ToObject(r)
  1066  	l := toLength(o.self.getStr("length", nil))
  1067  	k := relToIdx(call.Argument(1).ToInteger(), l)
  1068  	var relEnd int64
  1069  	if endArg := call.Argument(2); endArg != _undefined {
  1070  		relEnd = endArg.ToInteger()
  1071  	} else {
  1072  		relEnd = l
  1073  	}
  1074  	final := relToIdx(relEnd, l)
  1075  	value := call.Argument(0)
  1076  	if arr := r.checkStdArrayObj(o); arr != nil {
  1077  		for ; k < final; k++ {
  1078  			arr.values[k] = value
  1079  		}
  1080  	} else {
  1081  		for ; k < final; k++ {
  1082  			o.self.setOwnIdx(valueInt(k), value, true)
  1083  		}
  1084  	}
  1085  	return o
  1086  }
  1087  
  1088  func (r *Runtime) arrayproto_find(call FunctionCall) Value {
  1089  	o := call.This.ToObject(r)
  1090  	l := toLength(o.self.getStr("length", nil))
  1091  	predicate := r.toCallable(call.Argument(0))
  1092  	fc := FunctionCall{
  1093  		This:      call.Argument(1),
  1094  		Arguments: []Value{nil, nil, o},
  1095  	}
  1096  	for k := int64(0); k < l; k++ {
  1097  		idx := valueInt(k)
  1098  		kValue := o.self.getIdx(idx, nil)
  1099  		fc.Arguments[0], fc.Arguments[1] = kValue, idx
  1100  		if predicate(fc).ToBoolean() {
  1101  			return kValue
  1102  		}
  1103  	}
  1104  
  1105  	return _undefined
  1106  }
  1107  
  1108  func (r *Runtime) arrayproto_findIndex(call FunctionCall) Value {
  1109  	o := call.This.ToObject(r)
  1110  	l := toLength(o.self.getStr("length", nil))
  1111  	predicate := r.toCallable(call.Argument(0))
  1112  	fc := FunctionCall{
  1113  		This:      call.Argument(1),
  1114  		Arguments: []Value{nil, nil, o},
  1115  	}
  1116  	for k := int64(0); k < l; k++ {
  1117  		idx := valueInt(k)
  1118  		kValue := o.self.getIdx(idx, nil)
  1119  		fc.Arguments[0], fc.Arguments[1] = kValue, idx
  1120  		if predicate(fc).ToBoolean() {
  1121  			return idx
  1122  		}
  1123  	}
  1124  
  1125  	return intToValue(-1)
  1126  }
  1127  
  1128  func (r *Runtime) arrayproto_findLast(call FunctionCall) Value {
  1129  	o := call.This.ToObject(r)
  1130  	l := toLength(o.self.getStr("length", nil))
  1131  	predicate := r.toCallable(call.Argument(0))
  1132  	fc := FunctionCall{
  1133  		This:      call.Argument(1),
  1134  		Arguments: []Value{nil, nil, o},
  1135  	}
  1136  	for k := int64(l - 1); k >= 0; k-- {
  1137  		idx := valueInt(k)
  1138  		kValue := o.self.getIdx(idx, nil)
  1139  		fc.Arguments[0], fc.Arguments[1] = kValue, idx
  1140  		if predicate(fc).ToBoolean() {
  1141  			return kValue
  1142  		}
  1143  	}
  1144  
  1145  	return _undefined
  1146  }
  1147  
  1148  func (r *Runtime) arrayproto_findLastIndex(call FunctionCall) Value {
  1149  	o := call.This.ToObject(r)
  1150  	l := toLength(o.self.getStr("length", nil))
  1151  	predicate := r.toCallable(call.Argument(0))
  1152  	fc := FunctionCall{
  1153  		This:      call.Argument(1),
  1154  		Arguments: []Value{nil, nil, o},
  1155  	}
  1156  	for k := int64(l - 1); k >= 0; k-- {
  1157  		idx := valueInt(k)
  1158  		kValue := o.self.getIdx(idx, nil)
  1159  		fc.Arguments[0], fc.Arguments[1] = kValue, idx
  1160  		if predicate(fc).ToBoolean() {
  1161  			return idx
  1162  		}
  1163  	}
  1164  
  1165  	return intToValue(-1)
  1166  }
  1167  
  1168  func (r *Runtime) arrayproto_flat(call FunctionCall) Value {
  1169  	o := call.This.ToObject(r)
  1170  	l := toLength(o.self.getStr("length", nil))
  1171  	depthNum := int64(1)
  1172  	if len(call.Arguments) > 0 {
  1173  		depthNum = call.Argument(0).ToInteger()
  1174  	}
  1175  	a := arraySpeciesCreate(o, 0)
  1176  	r.flattenIntoArray(a, o, l, 0, depthNum, nil, nil)
  1177  	return a
  1178  }
  1179  
  1180  func (r *Runtime) flattenIntoArray(target, source *Object, sourceLen, start, depth int64, mapperFunction func(FunctionCall) Value, thisArg Value) int64 {
  1181  	targetIndex, sourceIndex := start, int64(0)
  1182  	for sourceIndex < sourceLen {
  1183  		p := intToValue(sourceIndex)
  1184  		if source.hasProperty(p.toString()) {
  1185  			element := nilSafe(source.get(p, source))
  1186  			if mapperFunction != nil {
  1187  				element = mapperFunction(FunctionCall{
  1188  					This:      thisArg,
  1189  					Arguments: []Value{element, p, source},
  1190  				})
  1191  			}
  1192  			var elementArray *Object
  1193  			if depth > 0 {
  1194  				if elementObj, ok := element.(*Object); ok && isArray(elementObj) {
  1195  					elementArray = elementObj
  1196  				}
  1197  			}
  1198  			if elementArray != nil {
  1199  				elementLen := toLength(elementArray.self.getStr("length", nil))
  1200  				targetIndex = r.flattenIntoArray(target, elementArray, elementLen, targetIndex, depth-1, nil, nil)
  1201  			} else {
  1202  				if targetIndex >= maxInt-1 {
  1203  					panic(r.NewTypeError("Invalid array length"))
  1204  				}
  1205  				createDataPropertyOrThrow(target, intToValue(targetIndex), element)
  1206  				targetIndex++
  1207  			}
  1208  		}
  1209  		sourceIndex++
  1210  	}
  1211  	return targetIndex
  1212  }
  1213  
  1214  func (r *Runtime) arrayproto_flatMap(call FunctionCall) Value {
  1215  	o := call.This.ToObject(r)
  1216  	l := toLength(o.self.getStr("length", nil))
  1217  	callbackFn := r.toCallable(call.Argument(0))
  1218  	thisArg := Undefined()
  1219  	if len(call.Arguments) > 1 {
  1220  		thisArg = call.Argument(1)
  1221  	}
  1222  	a := arraySpeciesCreate(o, 0)
  1223  	r.flattenIntoArray(a, o, l, 0, 1, callbackFn, thisArg)
  1224  	return a
  1225  }
  1226  
  1227  func (r *Runtime) checkStdArrayObj(obj *Object) *arrayObject {
  1228  	if arr, ok := obj.self.(*arrayObject); ok &&
  1229  		arr.propValueCount == 0 &&
  1230  		arr.length == uint32(len(arr.values)) &&
  1231  		uint32(arr.objCount) == arr.length {
  1232  
  1233  		return arr
  1234  	}
  1235  
  1236  	return nil
  1237  }
  1238  
  1239  func (r *Runtime) checkStdArrayObjWithProto(obj *Object) *arrayObject {
  1240  	if arr := r.checkStdArrayObj(obj); arr != nil {
  1241  		if p1, ok := arr.prototype.self.(*arrayObject); ok && p1.propValueCount == 0 {
  1242  			if p2, ok := p1.prototype.self.(*baseObject); ok && p2.prototype == nil {
  1243  				p2.ensurePropOrder()
  1244  				if p2.idxPropCount == 0 {
  1245  					return arr
  1246  				}
  1247  			}
  1248  		}
  1249  	}
  1250  	return nil
  1251  }
  1252  
  1253  func (r *Runtime) checkStdArray(v Value) *arrayObject {
  1254  	if obj, ok := v.(*Object); ok {
  1255  		return r.checkStdArrayObj(obj)
  1256  	}
  1257  
  1258  	return nil
  1259  }
  1260  
  1261  func (r *Runtime) checkStdArrayIter(v Value) *arrayObject {
  1262  	if arr := r.checkStdArray(v); arr != nil &&
  1263  		arr.getSym(SymIterator, nil) == r.getArrayValues() {
  1264  
  1265  		return arr
  1266  	}
  1267  
  1268  	return nil
  1269  }
  1270  
  1271  func (r *Runtime) array_from(call FunctionCall) Value {
  1272  	var mapFn func(FunctionCall) Value
  1273  	if mapFnArg := call.Argument(1); mapFnArg != _undefined {
  1274  		if mapFnObj, ok := mapFnArg.(*Object); ok {
  1275  			if fn, ok := mapFnObj.self.assertCallable(); ok {
  1276  				mapFn = fn
  1277  			}
  1278  		}
  1279  		if mapFn == nil {
  1280  			panic(r.NewTypeError("%s is not a function", mapFnArg))
  1281  		}
  1282  	}
  1283  	t := call.Argument(2)
  1284  	items := call.Argument(0)
  1285  	if mapFn == nil && call.This == r.global.Array { // mapFn may mutate the array
  1286  		if arr := r.checkStdArrayIter(items); arr != nil {
  1287  			items := make([]Value, len(arr.values))
  1288  			copy(items, arr.values)
  1289  			return r.newArrayValues(items)
  1290  		}
  1291  	}
  1292  
  1293  	var ctor func(args []Value, newTarget *Object) *Object
  1294  	if call.This != r.global.Array {
  1295  		if o, ok := call.This.(*Object); ok {
  1296  			if c := o.self.assertConstructor(); c != nil {
  1297  				ctor = c
  1298  			}
  1299  		}
  1300  	}
  1301  	var arr *Object
  1302  	if usingIterator := toMethod(r.getV(items, SymIterator)); usingIterator != nil {
  1303  		if ctor != nil {
  1304  			arr = ctor([]Value{}, nil)
  1305  		} else {
  1306  			arr = r.newArrayValues(nil)
  1307  		}
  1308  		iter := r.getIterator(items, usingIterator)
  1309  		if mapFn == nil {
  1310  			if a := r.checkStdArrayObjWithProto(arr); a != nil {
  1311  				var values []Value
  1312  				iter.iterate(func(val Value) {
  1313  					values = append(values, val)
  1314  				})
  1315  				setArrayValues(a, values)
  1316  				return arr
  1317  			}
  1318  		}
  1319  		k := int64(0)
  1320  		iter.iterate(func(val Value) {
  1321  			if mapFn != nil {
  1322  				val = mapFn(FunctionCall{This: t, Arguments: []Value{val, intToValue(k)}})
  1323  			}
  1324  			createDataPropertyOrThrow(arr, intToValue(k), val)
  1325  			k++
  1326  		})
  1327  		arr.self.setOwnStr("length", intToValue(k), true)
  1328  	} else {
  1329  		arrayLike := items.ToObject(r)
  1330  		l := toLength(arrayLike.self.getStr("length", nil))
  1331  		if ctor != nil {
  1332  			arr = ctor([]Value{intToValue(l)}, nil)
  1333  		} else {
  1334  			arr = r.newArrayValues(nil)
  1335  		}
  1336  		if mapFn == nil {
  1337  			if a := r.checkStdArrayObjWithProto(arr); a != nil {
  1338  				values := make([]Value, l)
  1339  				for k := int64(0); k < l; k++ {
  1340  					values[k] = nilSafe(arrayLike.self.getIdx(valueInt(k), nil))
  1341  				}
  1342  				setArrayValues(a, values)
  1343  				return arr
  1344  			}
  1345  		}
  1346  		for k := int64(0); k < l; k++ {
  1347  			idx := valueInt(k)
  1348  			item := arrayLike.self.getIdx(idx, nil)
  1349  			if mapFn != nil {
  1350  				item = mapFn(FunctionCall{This: t, Arguments: []Value{item, idx}})
  1351  			} else {
  1352  				item = nilSafe(item)
  1353  			}
  1354  			createDataPropertyOrThrow(arr, idx, item)
  1355  		}
  1356  		arr.self.setOwnStr("length", intToValue(l), true)
  1357  	}
  1358  
  1359  	return arr
  1360  }
  1361  
  1362  func (r *Runtime) array_isArray(call FunctionCall) Value {
  1363  	if o, ok := call.Argument(0).(*Object); ok {
  1364  		if isArray(o) {
  1365  			return valueTrue
  1366  		}
  1367  	}
  1368  	return valueFalse
  1369  }
  1370  
  1371  func (r *Runtime) array_of(call FunctionCall) Value {
  1372  	var ctor func(args []Value, newTarget *Object) *Object
  1373  	if call.This != r.global.Array {
  1374  		if o, ok := call.This.(*Object); ok {
  1375  			if c := o.self.assertConstructor(); c != nil {
  1376  				ctor = c
  1377  			}
  1378  		}
  1379  	}
  1380  	if ctor == nil {
  1381  		values := make([]Value, len(call.Arguments))
  1382  		copy(values, call.Arguments)
  1383  		return r.newArrayValues(values)
  1384  	}
  1385  	l := intToValue(int64(len(call.Arguments)))
  1386  	arr := ctor([]Value{l}, nil)
  1387  	for i, val := range call.Arguments {
  1388  		createDataPropertyOrThrow(arr, intToValue(int64(i)), val)
  1389  	}
  1390  	arr.self.setOwnStr("length", l, true)
  1391  	return arr
  1392  }
  1393  
  1394  func (r *Runtime) arrayIterProto_next(call FunctionCall) Value {
  1395  	thisObj := r.toObject(call.This)
  1396  	if iter, ok := thisObj.self.(*arrayIterObject); ok {
  1397  		return iter.next()
  1398  	}
  1399  	panic(r.NewTypeError("Method Array Iterator.prototype.next called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
  1400  }
  1401  
  1402  func createArrayProtoTemplate() *objectTemplate {
  1403  	t := newObjectTemplate()
  1404  	t.protoFactory = func(r *Runtime) *Object {
  1405  		return r.global.ObjectPrototype
  1406  	}
  1407  
  1408  	t.putStr("length", func(r *Runtime) Value { return valueProp(_positiveZero, true, false, false) })
  1409  
  1410  	t.putStr("constructor", func(r *Runtime) Value { return valueProp(r.getArray(), true, false, true) })
  1411  
  1412  	t.putStr("at", func(r *Runtime) Value { return r.methodProp(r.arrayproto_at, "at", 1) })
  1413  	t.putStr("concat", func(r *Runtime) Value { return r.methodProp(r.arrayproto_concat, "concat", 1) })
  1414  	t.putStr("copyWithin", func(r *Runtime) Value { return r.methodProp(r.arrayproto_copyWithin, "copyWithin", 2) })
  1415  	t.putStr("entries", func(r *Runtime) Value { return r.methodProp(r.arrayproto_entries, "entries", 0) })
  1416  	t.putStr("every", func(r *Runtime) Value { return r.methodProp(r.arrayproto_every, "every", 1) })
  1417  	t.putStr("fill", func(r *Runtime) Value { return r.methodProp(r.arrayproto_fill, "fill", 1) })
  1418  	t.putStr("filter", func(r *Runtime) Value { return r.methodProp(r.arrayproto_filter, "filter", 1) })
  1419  	t.putStr("find", func(r *Runtime) Value { return r.methodProp(r.arrayproto_find, "find", 1) })
  1420  	t.putStr("findIndex", func(r *Runtime) Value { return r.methodProp(r.arrayproto_findIndex, "findIndex", 1) })
  1421  	t.putStr("findLast", func(r *Runtime) Value { return r.methodProp(r.arrayproto_findLast, "findLast", 1) })
  1422  	t.putStr("findLastIndex", func(r *Runtime) Value { return r.methodProp(r.arrayproto_findLastIndex, "findLastIndex", 1) })
  1423  	t.putStr("flat", func(r *Runtime) Value { return r.methodProp(r.arrayproto_flat, "flat", 0) })
  1424  	t.putStr("flatMap", func(r *Runtime) Value { return r.methodProp(r.arrayproto_flatMap, "flatMap", 1) })
  1425  	t.putStr("forEach", func(r *Runtime) Value { return r.methodProp(r.arrayproto_forEach, "forEach", 1) })
  1426  	t.putStr("includes", func(r *Runtime) Value { return r.methodProp(r.arrayproto_includes, "includes", 1) })
  1427  	t.putStr("indexOf", func(r *Runtime) Value { return r.methodProp(r.arrayproto_indexOf, "indexOf", 1) })
  1428  	t.putStr("join", func(r *Runtime) Value { return r.methodProp(r.arrayproto_join, "join", 1) })
  1429  	t.putStr("keys", func(r *Runtime) Value { return r.methodProp(r.arrayproto_keys, "keys", 0) })
  1430  	t.putStr("lastIndexOf", func(r *Runtime) Value { return r.methodProp(r.arrayproto_lastIndexOf, "lastIndexOf", 1) })
  1431  	t.putStr("map", func(r *Runtime) Value { return r.methodProp(r.arrayproto_map, "map", 1) })
  1432  	t.putStr("pop", func(r *Runtime) Value { return r.methodProp(r.arrayproto_pop, "pop", 0) })
  1433  	t.putStr("push", func(r *Runtime) Value { return r.methodProp(r.arrayproto_push, "push", 1) })
  1434  	t.putStr("reduce", func(r *Runtime) Value { return r.methodProp(r.arrayproto_reduce, "reduce", 1) })
  1435  	t.putStr("reduceRight", func(r *Runtime) Value { return r.methodProp(r.arrayproto_reduceRight, "reduceRight", 1) })
  1436  	t.putStr("reverse", func(r *Runtime) Value { return r.methodProp(r.arrayproto_reverse, "reverse", 0) })
  1437  	t.putStr("shift", func(r *Runtime) Value { return r.methodProp(r.arrayproto_shift, "shift", 0) })
  1438  	t.putStr("slice", func(r *Runtime) Value { return r.methodProp(r.arrayproto_slice, "slice", 2) })
  1439  	t.putStr("some", func(r *Runtime) Value { return r.methodProp(r.arrayproto_some, "some", 1) })
  1440  	t.putStr("sort", func(r *Runtime) Value { return r.methodProp(r.arrayproto_sort, "sort", 1) })
  1441  	t.putStr("splice", func(r *Runtime) Value { return r.methodProp(r.arrayproto_splice, "splice", 2) })
  1442  	t.putStr("toLocaleString", func(r *Runtime) Value { return r.methodProp(r.arrayproto_toLocaleString, "toLocaleString", 0) })
  1443  	t.putStr("toString", func(r *Runtime) Value { return valueProp(r.getArrayToString(), true, false, true) })
  1444  	t.putStr("unshift", func(r *Runtime) Value { return r.methodProp(r.arrayproto_unshift, "unshift", 1) })
  1445  	t.putStr("values", func(r *Runtime) Value { return valueProp(r.getArrayValues(), true, false, true) })
  1446  
  1447  	t.putSym(SymIterator, func(r *Runtime) Value { return valueProp(r.getArrayValues(), true, false, true) })
  1448  	t.putSym(SymUnscopables, func(r *Runtime) Value {
  1449  		bl := r.newBaseObject(nil, classObject)
  1450  		bl.setOwnStr("copyWithin", valueTrue, true)
  1451  		bl.setOwnStr("entries", valueTrue, true)
  1452  		bl.setOwnStr("fill", valueTrue, true)
  1453  		bl.setOwnStr("find", valueTrue, true)
  1454  		bl.setOwnStr("findIndex", valueTrue, true)
  1455  		bl.setOwnStr("findLast", valueTrue, true)
  1456  		bl.setOwnStr("findLastIndex", valueTrue, true)
  1457  		bl.setOwnStr("flat", valueTrue, true)
  1458  		bl.setOwnStr("flatMap", valueTrue, true)
  1459  		bl.setOwnStr("includes", valueTrue, true)
  1460  		bl.setOwnStr("keys", valueTrue, true)
  1461  		bl.setOwnStr("values", valueTrue, true)
  1462  		bl.setOwnStr("groupBy", valueTrue, true)
  1463  		bl.setOwnStr("groupByToMap", valueTrue, true)
  1464  
  1465  		return valueProp(bl.val, false, false, true)
  1466  	})
  1467  
  1468  	return t
  1469  }
  1470  
  1471  var arrayProtoTemplate *objectTemplate
  1472  var arrayProtoTemplateOnce sync.Once
  1473  
  1474  func getArrayProtoTemplate() *objectTemplate {
  1475  	arrayProtoTemplateOnce.Do(func() {
  1476  		arrayProtoTemplate = createArrayProtoTemplate()
  1477  	})
  1478  	return arrayProtoTemplate
  1479  }
  1480  
  1481  func (r *Runtime) getArrayPrototype() *Object {
  1482  	ret := r.global.ArrayPrototype
  1483  	if ret == nil {
  1484  		ret = &Object{runtime: r}
  1485  		r.global.ArrayPrototype = ret
  1486  		r.newTemplatedArrayObject(getArrayProtoTemplate(), ret)
  1487  	}
  1488  	return ret
  1489  }
  1490  
  1491  func (r *Runtime) getArray() *Object {
  1492  	ret := r.global.Array
  1493  	if ret == nil {
  1494  		ret = &Object{runtime: r}
  1495  		ret.self = r.createArray(ret)
  1496  		r.global.Array = ret
  1497  	}
  1498  	return ret
  1499  }
  1500  
  1501  func (r *Runtime) createArray(val *Object) objectImpl {
  1502  	o := r.newNativeFuncConstructObj(val, r.builtin_newArray, "Array", r.getArrayPrototype(), 1)
  1503  	o._putProp("from", r.newNativeFunc(r.array_from, "from", 1), true, false, true)
  1504  	o._putProp("isArray", r.newNativeFunc(r.array_isArray, "isArray", 1), true, false, true)
  1505  	o._putProp("of", r.newNativeFunc(r.array_of, "of", 0), true, false, true)
  1506  	r.putSpeciesReturnThis(o)
  1507  
  1508  	return o
  1509  }
  1510  
  1511  func (r *Runtime) createArrayIterProto(val *Object) objectImpl {
  1512  	o := newBaseObjectObj(val, r.getIteratorPrototype(), classObject)
  1513  
  1514  	o._putProp("next", r.newNativeFunc(r.arrayIterProto_next, "next", 0), true, false, true)
  1515  	o._putSym(SymToStringTag, valueProp(asciiString(classArrayIterator), false, false, true))
  1516  
  1517  	return o
  1518  }
  1519  
  1520  func (r *Runtime) getArrayValues() *Object {
  1521  	ret := r.global.arrayValues
  1522  	if ret == nil {
  1523  		ret = r.newNativeFunc(r.arrayproto_values, "values", 0)
  1524  		r.global.arrayValues = ret
  1525  	}
  1526  	return ret
  1527  }
  1528  
  1529  func (r *Runtime) getArrayToString() *Object {
  1530  	ret := r.global.arrayToString
  1531  	if ret == nil {
  1532  		ret = r.newNativeFunc(r.arrayproto_toString, "toString", 0)
  1533  		r.global.arrayToString = ret
  1534  	}
  1535  	return ret
  1536  }
  1537  
  1538  func (r *Runtime) getArrayIteratorPrototype() *Object {
  1539  	var o *Object
  1540  	if o = r.global.ArrayIteratorPrototype; o == nil {
  1541  		o = &Object{runtime: r}
  1542  		r.global.ArrayIteratorPrototype = o
  1543  		o.self = r.createArrayIterProto(o)
  1544  	}
  1545  	return o
  1546  
  1547  }
  1548  
  1549  type sortable interface {
  1550  	sortLen() int
  1551  	sortGet(int) Value
  1552  	swap(int, int)
  1553  }
  1554  
  1555  type arraySortCtx struct {
  1556  	obj     sortable
  1557  	compare func(FunctionCall) Value
  1558  }
  1559  
  1560  func (a *arraySortCtx) sortCompare(x, y Value) int {
  1561  	if x == nil && y == nil {
  1562  		return 0
  1563  	}
  1564  
  1565  	if x == nil {
  1566  		return 1
  1567  	}
  1568  
  1569  	if y == nil {
  1570  		return -1
  1571  	}
  1572  
  1573  	if x == _undefined && y == _undefined {
  1574  		return 0
  1575  	}
  1576  
  1577  	if x == _undefined {
  1578  		return 1
  1579  	}
  1580  
  1581  	if y == _undefined {
  1582  		return -1
  1583  	}
  1584  
  1585  	if a.compare != nil {
  1586  		f := a.compare(FunctionCall{
  1587  			This:      _undefined,
  1588  			Arguments: []Value{x, y},
  1589  		}).ToFloat()
  1590  		if f > 0 {
  1591  			return 1
  1592  		}
  1593  		if f < 0 {
  1594  			return -1
  1595  		}
  1596  		if math.Signbit(f) {
  1597  			return -1
  1598  		}
  1599  		return 0
  1600  	}
  1601  	return x.toString().CompareTo(y.toString())
  1602  }
  1603  
  1604  // sort.Interface
  1605  
  1606  func (a *arraySortCtx) Len() int {
  1607  	return a.obj.sortLen()
  1608  }
  1609  
  1610  func (a *arraySortCtx) Less(j, k int) bool {
  1611  	return a.sortCompare(a.obj.sortGet(j), a.obj.sortGet(k)) < 0
  1612  }
  1613  
  1614  func (a *arraySortCtx) Swap(j, k int) {
  1615  	a.obj.swap(j, k)
  1616  }
  1617  

View as plain text