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