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