go.ketch.com/lib/goja@v0.0.1/builtin_array.go (about)

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