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