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
156 return r.arrayproto_pop_generic(obj)
157 }
158 if _, ok := val.(*valueProperty); ok {
159
160 return r.arrayproto_pop_generic(obj)
161 }
162
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)
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
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)
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 {
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
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