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