1 /* Digital Mars DMDScript source code. 2 * Copyright (c) 2000-2002 by Chromium Communications 3 * D version Copyright (c) 2004-2010 by Digital Mars 4 * Distributed under the Boost Software License, Version 1.0. 5 * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 * written by Walter Bright 7 * http://www.digitalmars.com 8 * 9 * D2 port by Dmitry Olshansky 10 * 11 * DMDScript is implemented in the D Programming Language, 12 * http://www.digitalmars.com/d/ 13 * 14 * For a C++ implementation of DMDScript, including COM support, see 15 * http://www.digitalmars.com/dscript/cppscript.html 16 */ 17 18 19 module dmdscript.darray; 20 21 //Nonstandard treatment of Infinity as array length in slice/splice functions, supported by majority of browsers 22 //also treats negative starting index in splice wrapping it around just like in slice 23 version = SliceSpliceExtension; 24 25 import std..string; 26 import std.c.stdlib; 27 import std.math; 28 29 import dmdscript.script; 30 import dmdscript.value; 31 import dmdscript.dobject; 32 import dmdscript.threadcontext; 33 import dmdscript.identifier; 34 import dmdscript.dfunction; 35 import dmdscript.text; 36 import dmdscript.property; 37 import dmdscript.errmsgs; 38 import dmdscript.dnative; 39 import dmdscript.program; 40 41 /* ===================== Darray_constructor ==================== */ 42 43 class DarrayConstructor : Dfunction 44 { 45 this() 46 { 47 super(1, Dfunction_prototype); 48 name = "Array"; 49 } 50 51 override void* Construct(CallContext *cc, Value *ret, Value[] arglist) 52 { 53 // ECMA 15.4.2 54 Darray a; 55 56 a = new Darray(); 57 if(arglist.length == 0) 58 { 59 a.ulength = 0; 60 a.length.number = 0; 61 } 62 else if(arglist.length == 1) 63 { 64 Value* v = &arglist[0]; 65 66 if(v.isNumber()) 67 { 68 d_uint32 len; 69 70 len = v.toUint32(); 71 if(cast(double)len != v.number) 72 { 73 ErrInfo errinfo; 74 75 ret.putVundefined(); 76 return RangeError(&errinfo, ERR_ARRAY_LEN_OUT_OF_BOUNDS, v.number); 77 } 78 else 79 { 80 a.ulength = len; 81 a.length.number = len; 82 /+ 83 if (len > 16) 84 { 85 //writef("setting %p dimension to %d\n", &a.proptable, len); 86 if (len > 10000) 87 len = 10000; // cap so we don't run out of memory 88 a.proptable.roots.setDim(len); 89 a.proptable.roots.zero(); 90 } 91 +/ 92 } 93 } 94 else 95 { 96 a.ulength = 1; 97 a.length.number = 1; 98 a.Put(cast(d_uint32)0, v, 0); 99 } 100 } 101 else 102 { 103 //if (arglist.length > 10) writef("Array constructor: arglist.length = %d\n", arglist.length); 104 /+ 105 if (arglist.length > 16) 106 { 107 a.proptable.roots.setDim(arglist.length); 108 a.proptable.roots.zero(); 109 } 110 +/ 111 a.ulength = cast(uint)arglist.length; 112 a.length.number = arglist.length; 113 for(uint k = 0; k < arglist.length; k++) 114 { 115 a.Put(k, &arglist[k], 0); 116 } 117 } 118 Value.copy(ret, &a.value); 119 //writef("Darray_constructor.Construct(): length = %g\n", a.length.number); 120 return null; 121 } 122 123 override void* Call(CallContext *cc, Dobject othis, Value* ret, Value[] arglist) 124 { 125 // ECMA 15.4.1 126 return Construct(cc, ret, arglist); 127 } 128 } 129 130 131 /* ===================== Darray_prototype_toString ================= */ 132 133 void *Darray_prototype_toString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 134 { 135 //writef("Darray_prototype_toString()\n"); 136 array_join(othis, ret, null); 137 return null; 138 } 139 140 /* ===================== Darray_prototype_toLocaleString ================= */ 141 142 void *Darray_prototype_toLocaleString(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 143 { 144 // ECMA v3 15.4.4.3 145 d_string separator; 146 d_string r; 147 d_uint32 len; 148 d_uint32 k; 149 Value* v; 150 151 //writef("array_join(othis = %p)\n", othis); 152 153 if(!othis.isClass(TEXT_Array)) 154 { 155 ret.putVundefined(); 156 ErrInfo errinfo; 157 return Dobject.RuntimeError(&errinfo, ERR_TLS_NOT_TRANSFERRABLE); 158 } 159 160 v = othis.Get(TEXT_length); 161 len = v ? v.toUint32() : 0; 162 163 Program prog = cc.prog; 164 if(!prog.slist) 165 { 166 // Determine what list separator is only once per thread 167 //prog.slist = list_separator(prog.lcid); 168 prog.slist = ","; 169 } 170 separator = prog.slist; 171 172 for(k = 0; k != len; k++) 173 { 174 if(k) 175 r ~= separator; 176 v = othis.Get(k); 177 if(v && !v.isUndefinedOrNull()) 178 { 179 Dobject ot; 180 181 ot = v.toObject(); 182 v = ot.Get(TEXT_toLocaleString); 183 if(v && !v.isPrimitive()) // if it's an Object 184 { 185 void* a; 186 Dobject o; 187 Value rt; 188 189 o = v.object; 190 rt.putVundefined(); 191 a = o.Call(cc, ot, &rt, null); 192 if(a) // if exception was thrown 193 return a; 194 r ~= rt.toString(); 195 } 196 } 197 } 198 199 ret.putVstring(r); 200 return null; 201 } 202 203 /* ===================== Darray_prototype_concat ================= */ 204 205 void *Darray_prototype_concat(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 206 { 207 // ECMA v3 15.4.4.4 208 Darray A; 209 Darray E; 210 Value* v; 211 d_uint32 k; 212 d_uint32 n; 213 d_uint32 a; 214 215 A = new Darray(); 216 n = 0; 217 v = &othis.value; 218 for(a = 0;; a++) 219 { 220 if(!v.isPrimitive() && v.object.isDarray()) 221 { 222 d_uint32 len; 223 224 E = cast(Darray)v.object; 225 len = E.ulength; 226 for(k = 0; k != len; k++) 227 { 228 v = E.Get(k); 229 if(v) 230 A.Put(n, v, 0); 231 n++; 232 } 233 } 234 else 235 { 236 A.Put(n, v, 0); 237 n++; 238 } 239 if(a == arglist.length) 240 break; 241 v = &arglist[a]; 242 } 243 244 A.Put(TEXT_length, n, DontEnum); 245 Value.copy(ret, &A.value); 246 return null; 247 } 248 249 /* ===================== Darray_prototype_join ================= */ 250 251 void *Darray_prototype_join(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 252 { 253 array_join(othis, ret, arglist); 254 return null; 255 } 256 257 void array_join(Dobject othis, Value* ret, Value[] arglist) 258 { 259 // ECMA 15.4.4.3 260 d_string separator; 261 d_string r; 262 d_uint32 len; 263 d_uint32 k; 264 Value* v; 265 266 //writef("array_join(othis = %p)\n", othis); 267 v = othis.Get(TEXT_length); 268 len = v ? v.toUint32() : 0; 269 if(arglist.length == 0 || arglist[0].isUndefined()) 270 separator = TEXT_comma; 271 else 272 separator = arglist[0].toString(); 273 274 for(k = 0; k != len; k++) 275 { 276 if(k) 277 r ~= separator; 278 v = othis.Get(k); 279 if(v && !v.isUndefinedOrNull()) 280 r ~= v.toString(); 281 } 282 283 ret.putVstring(r); 284 } 285 286 /* ===================== Darray_prototype_toSource ================= */ 287 288 void *Darray_prototype_toSource(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 289 { 290 d_string separator; 291 d_string r; 292 d_uint32 len; 293 d_uint32 k; 294 Value* v; 295 296 v = othis.Get(TEXT_length); 297 len = v ? v.toUint32() : 0; 298 separator = ","; 299 300 r = "[".idup; 301 for(k = 0; k != len; k++) 302 { 303 if(k) 304 r ~= separator; 305 v = othis.Get(k); 306 if(v && !v.isUndefinedOrNull()) 307 r ~= v.toSource(); 308 } 309 r ~= "]"; 310 311 ret.putVstring(r); 312 return null; 313 } 314 315 316 /* ===================== Darray_prototype_pop ================= */ 317 318 void *Darray_prototype_pop(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 319 { 320 // ECMA v3 15.4.4.6 321 Value* v; 322 d_uint32 u; 323 324 // If othis is a Darray, then we can optimize this significantly 325 v = othis.Get(TEXT_length); 326 if(!v) 327 v = &vundefined; 328 u = v.toUint32(); 329 if(u == 0) 330 { 331 othis.Put(TEXT_length, 0.0, DontEnum); 332 ret.putVundefined(); 333 } 334 else 335 { 336 v = othis.Get(u - 1); 337 if(!v) 338 v = &vundefined; 339 Value.copy(ret, v); 340 othis.Delete(u - 1); 341 othis.Put(TEXT_length, u - 1, DontEnum); 342 } 343 return null; 344 } 345 346 /* ===================== Darray_prototype_push ================= */ 347 348 void *Darray_prototype_push(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 349 { 350 // ECMA v3 15.4.4.7 351 Value* v; 352 d_uint32 u; 353 d_uint32 a; 354 355 // If othis is a Darray, then we can optimize this significantly 356 v = othis.Get(TEXT_length); 357 if(!v) 358 v = &vundefined; 359 u = v.toUint32(); 360 for(a = 0; a < arglist.length; a++) 361 { 362 othis.Put(u + a, &arglist[a], 0); 363 } 364 othis.Put(TEXT_length, u + a, DontEnum); 365 ret.putVnumber(u + a); 366 return null; 367 } 368 369 /* ===================== Darray_prototype_reverse ================= */ 370 371 void *Darray_prototype_reverse(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 372 { 373 // ECMA 15.4.4.4 374 d_uint32 a; 375 d_uint32 b; 376 Value* va; 377 Value* vb; 378 Value* v; 379 d_uint32 pivot; 380 d_uint32 len; 381 Value tmp; 382 383 v = othis.Get(TEXT_length); 384 len = v ? v.toUint32() : 0; 385 pivot = len / 2; 386 for(a = 0; a != pivot; a++) 387 { 388 b = len - a - 1; 389 //writef("a = %d, b = %d\n", a, b); 390 va = othis.Get(a); 391 if(va) 392 Value.copy(&tmp, va); 393 vb = othis.Get(b); 394 if(vb) 395 othis.Put(a, vb, 0); 396 else 397 othis.Delete(a); 398 399 if(va) 400 othis.Put(b, &tmp, 0); 401 else 402 othis.Delete(b); 403 } 404 Value.copy(ret, &othis.value); 405 return null; 406 } 407 408 /* ===================== Darray_prototype_shift ================= */ 409 410 void *Darray_prototype_shift(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 411 { 412 // ECMA v3 15.4.4.9 413 Value* v; 414 Value* result; 415 d_uint32 len; 416 d_uint32 k; 417 418 // If othis is a Darray, then we can optimize this significantly 419 //writef("shift(othis = %p)\n", othis); 420 v = othis.Get(TEXT_length); 421 if(!v) 422 v = &vundefined; 423 len = v.toUint32(); 424 425 if(len) 426 { 427 result = othis.Get(0u); 428 Value.copy(ret, result ? result : &vundefined); 429 for(k = 1; k != len; k++) 430 { 431 v = othis.Get(k); 432 if(v) 433 { 434 othis.Put(k - 1, v, 0); 435 } 436 else 437 { 438 othis.Delete(k - 1); 439 } 440 } 441 othis.Delete(len - 1); 442 len--; 443 } 444 else 445 Value.copy(ret, &vundefined); 446 447 othis.Put(TEXT_length, len, DontEnum); 448 return null; 449 } 450 451 452 /* ===================== Darray_prototype_slice ================= */ 453 454 void *Darray_prototype_slice(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 455 { 456 // ECMA v3 15.4.4.10 457 d_uint32 len; 458 d_uint32 n; 459 d_uint32 k; 460 d_uint32 r8; 461 462 Value* v; 463 Darray A; 464 465 v = othis.Get(TEXT_length); 466 if(!v) 467 v = &vundefined; 468 len = v.toUint32(); 469 470 version(SliceSpliceExtension){ 471 d_number start; 472 d_number end; 473 switch(arglist.length) 474 { 475 case 0: 476 start = vundefined.toNumber(); 477 end = len; 478 break; 479 480 case 1: 481 start = arglist[0].toNumber(); 482 end = len; 483 break; 484 485 default: 486 start = arglist[0].toNumber(); 487 if(arglist[1].isUndefined()) 488 end = len; 489 else{ 490 end = arglist[1].toNumber(); 491 } 492 break; 493 } 494 if(start < 0) 495 { 496 k = cast(uint)(len + start); 497 if(cast(d_int32)k < 0) 498 k = 0; 499 } 500 else if(start == d_number.infinity) 501 k = len; 502 else if(start == -d_number.infinity) 503 k = 0; 504 else 505 { 506 k = cast(uint)start; 507 if(len < k) 508 k = len; 509 } 510 511 if(end < 0) 512 { 513 r8 = cast(uint)(len + end); 514 if(cast(d_int32)r8 < 0) 515 r8 = 0; 516 } 517 else if(end == d_number.infinity) 518 r8 = len; 519 else if(end == -d_number.infinity) 520 r8 = 0; 521 else 522 { 523 r8 = cast(uint)end; 524 if(len < end) 525 r8 = len; 526 } 527 } 528 else{//Canonical ECMA all kinds of infinity maped to 0 529 int start; 530 int end; 531 switch(arglist.length) 532 { 533 case 0: 534 start = vundefined.toInt32(); 535 end = len; 536 break; 537 538 case 1: 539 start = arglist[0].toInt32(); 540 end = len; 541 break; 542 543 default: 544 start = arglist[0].toInt32(); 545 if(arglist[1].isUndefined()) 546 end = len; 547 else{ 548 end = arglist[1].toInt32(); 549 } 550 break; 551 } 552 if(start < 0) 553 { 554 k = cast(uint)(len + start); 555 if(cast(d_int32)k < 0) 556 k = 0; 557 } 558 else 559 { 560 k = cast(uint)start; 561 if(len < k) 562 k = len; 563 } 564 565 if(end < 0) 566 { 567 r8 = cast(uint)(len + end); 568 if(cast(d_int32)r8 < 0) 569 r8 = 0; 570 } 571 else 572 { 573 r8 = cast(uint)end; 574 if(len < end) 575 r8 = len; 576 } 577 } 578 A = new Darray(); 579 for(n = 0; k < r8; k++) 580 { 581 v = othis.Get(k); 582 if(v) 583 { 584 A.Put(n, v, 0); 585 } 586 n++; 587 } 588 589 A.Put(TEXT_length, n, DontEnum); 590 Value.copy(ret, &A.value); 591 return null; 592 } 593 594 /* ===================== Darray_prototype_sort ================= */ 595 596 static Dobject comparefn; 597 static CallContext *comparecc; 598 599 extern (C) int compare_value(const void* x, const void* y) 600 { 601 Value* vx = cast(Value*)x; 602 Value* vy = cast(Value*)y; 603 d_string sx; 604 d_string sy; 605 int cmp; 606 607 //writef("compare_value()\n"); 608 if(vx.isUndefined()) 609 { 610 cmp = (vy.isUndefined()) ? 0 : 1; 611 } 612 else if(vy.isUndefined()) 613 cmp = -1; 614 else 615 { 616 if(comparefn) 617 { 618 Value arglist[2]; 619 Value ret; 620 Value* v; 621 d_number n; 622 623 Value.copy(&arglist[0], vx); 624 Value.copy(&arglist[1], vy); 625 ret.putVundefined(); 626 comparefn.Call(comparecc, comparefn, &ret, arglist); 627 n = ret.toNumber(); 628 if(n < 0) 629 cmp = -1; 630 else if(n > 0) 631 cmp = 1; 632 else 633 cmp = 0; 634 } 635 else 636 { 637 sx = vx.toString(); 638 sy = vy.toString(); 639 cmp = std..string.cmp(sx, sy); 640 if(cmp < 0) 641 cmp = -1; 642 else if(cmp > 0) 643 cmp = 1; 644 } 645 } 646 return cmp; 647 } 648 649 void *Darray_prototype_sort(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 650 { 651 // ECMA v3 15.4.4.11 652 Value* v; 653 d_uint32 len; 654 uint u; 655 656 //writef("Array.prototype.sort()\n"); 657 v = othis.Get(TEXT_length); 658 len = v ? v.toUint32() : 0; 659 660 // This is not optimal, as isArrayIndex is done at least twice 661 // for every array member. Additionally, the qsort() by index 662 // can be avoided if we can deduce it is not a sparse array. 663 664 Property *p; 665 Value[] pvalues; 666 d_uint32[] pindices; 667 d_uint32 parraydim; 668 d_uint32 nprops; 669 670 // First, size & alloc our temp array 671 if(len < 100) 672 { // Probably not too sparse an array 673 parraydim = len; 674 } 675 else 676 { 677 parraydim = 0; 678 foreach(ref Property p; *othis.proptable) 679 { 680 if(p.attributes == 0) // don't count special properties 681 parraydim++; 682 } 683 if(parraydim > len) // could theoretically happen 684 parraydim = len; 685 } 686 687 Value[] p1 = null; 688 Value* v1; 689 version(Win32) // eh and alloca() not working under linux 690 { 691 if(parraydim < 128) 692 v1 = cast(Value*)alloca(parraydim * Value.sizeof); 693 } 694 if(v1) 695 pvalues = v1[0 .. parraydim]; 696 else 697 { 698 p1 = new Value[parraydim]; 699 pvalues = p1; 700 } 701 702 d_uint32[] p2 = null; 703 d_uint32* p3; 704 version(Win32) 705 { 706 if(parraydim < 128) 707 p3 = cast(d_uint32*)alloca(parraydim * d_uint32.sizeof); 708 } 709 if(p3) 710 pindices = p3[0 .. parraydim]; 711 else 712 { 713 p2 = new d_uint32[parraydim]; 714 pindices = p2; 715 } 716 717 // Now fill it with all the Property's that are array indices 718 nprops = 0; 719 foreach(Value key, ref Property p; *othis.proptable) 720 { 721 d_uint32 index; 722 723 if(p.attributes == 0 && key.isArrayIndex(index)) 724 { 725 pindices[nprops] = index; 726 Value.copy(&pvalues[nprops], &p.value); 727 nprops++; 728 } 729 } 730 731 synchronized 732 { 733 comparefn = null; 734 comparecc = cc; 735 if(arglist.length) 736 { 737 if(!arglist[0].isPrimitive()) 738 comparefn = arglist[0].object; 739 } 740 741 // Sort pvalues[] 742 std.c.stdlib.qsort(pvalues.ptr, nprops, Value.sizeof, &compare_value); 743 744 comparefn = null; 745 comparecc = null; 746 } 747 748 // Stuff the sorted value's back into the array 749 for(u = 0; u < nprops; u++) 750 { 751 d_uint32 index; 752 753 othis.Put(u, &pvalues[u], 0); 754 index = pindices[u]; 755 if(index >= nprops) 756 { 757 othis.Delete(index); 758 } 759 } 760 761 delete p1; 762 delete p2; 763 764 ret.putVobject(othis); 765 return null; 766 } 767 768 /* ===================== Darray_prototype_splice ================= */ 769 770 void *Darray_prototype_splice(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 771 { 772 // ECMA v3 15.4.4.12 773 d_uint32 len; 774 d_uint32 k; 775 776 Value* v; 777 Darray A; 778 d_uint32 a; 779 d_uint32 delcnt; 780 d_uint32 inscnt; 781 d_uint32 startidx; 782 783 v = othis.Get(TEXT_length); 784 if(!v) 785 v = &vundefined; 786 len = v.toUint32(); 787 788 version(SliceSpliceExtension){ 789 d_number start; 790 d_number deleteCount; 791 792 switch(arglist.length) 793 { 794 case 0: 795 start = vundefined.toNumber(); 796 deleteCount = 0; 797 break; 798 799 case 1: 800 start = arglist[0].toNumber(); 801 deleteCount = vundefined.toNumber(); 802 break; 803 804 default: 805 start = arglist[0].toNumber(); 806 deleteCount = arglist[1].toNumber(); 807 //checked later 808 break; 809 } 810 if(start == d_number.infinity) 811 startidx = len; 812 else if(start == -d_number.infinity) 813 startidx = 0; 814 else{ 815 if(start < 0) 816 { 817 startidx = cast(uint)(len + start); 818 if(cast(d_int32)startidx < 0) 819 startidx = 0; 820 } 821 else 822 startidx = cast(uint)start; 823 } 824 startidx = startidx > len ? len : startidx; 825 if(deleteCount == d_number.infinity) 826 delcnt = len; 827 else if(deleteCount == -d_number.infinity) 828 delcnt = 0; 829 else 830 delcnt = (cast(uint)deleteCount > 0) ? cast(uint) deleteCount : 0; 831 if(delcnt > len - startidx) 832 delcnt = len - startidx; 833 }else{ 834 long start; 835 d_int32 deleteCount; 836 switch(arglist.length) 837 { 838 case 0: 839 start = vundefined.toInt32(); 840 deleteCount = 0; 841 break; 842 843 case 1: 844 start = arglist[0].toInt32(); 845 deleteCount = vundefined.toInt32(); 846 break; 847 848 default: 849 start = arglist[0].toInt32(); 850 deleteCount = arglist[1].toInt32(); 851 //checked later 852 break; 853 } 854 startidx = cast(uint)start; 855 startidx = startidx > len ? len : startidx; 856 delcnt = (deleteCount > 0) ? deleteCount : 0; 857 if(delcnt > len - startidx) 858 delcnt = len - startidx; 859 } 860 861 A = new Darray(); 862 863 // If deleteCount is not specified, ECMA implies it should 864 // be 0, while "JavaScript The Definitive Guide" says it should 865 // be delete to end of array. Jscript doesn't implement splice(). 866 // We'll do it the Guide way. 867 if(arglist.length < 2) 868 delcnt = len - startidx; 869 870 //writef("Darray.splice(startidx = %d, delcnt = %d)\n", startidx, delcnt); 871 for(k = 0; k != delcnt; k++) 872 { 873 v = othis.Get(startidx + k); 874 if(v) 875 A.Put(k, v, 0); 876 } 877 878 A.Put(TEXT_length, delcnt, DontEnum); 879 inscnt = (arglist.length > 2) ? cast(uint)arglist.length - 2 : 0; 880 if(inscnt != delcnt) 881 { 882 if(inscnt <= delcnt) 883 { 884 for(k = startidx; k != (len - delcnt); k++) 885 { 886 v = othis.Get(k + delcnt); 887 if(v) 888 othis.Put(k + inscnt, v, 0); 889 else 890 othis.Delete(k + inscnt); 891 } 892 893 for(k = len; k != (len - delcnt + inscnt); k--) 894 othis.Delete(k - 1); 895 } 896 else 897 { 898 for(k = len - delcnt; k != startidx; k--) 899 { 900 v = othis.Get(k + delcnt - 1); 901 if(v) 902 othis.Put(k + inscnt - 1, v, 0); 903 else 904 othis.Delete(k + inscnt - 1); 905 } 906 } 907 } 908 k = startidx; 909 for(a = 2; a < arglist.length; a++) 910 { 911 v = &arglist[a]; 912 othis.Put(k, v, 0); 913 k++; 914 } 915 916 othis.Put(TEXT_length, len - delcnt + inscnt, DontEnum); 917 Value.copy(ret, &A.value); 918 return null; 919 } 920 921 /* ===================== Darray_prototype_unshift ================= */ 922 923 void *Darray_prototype_unshift(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 924 { 925 // ECMA v3 15.4.4.13 926 Value* v; 927 d_uint32 len; 928 d_uint32 k; 929 930 v = othis.Get(TEXT_length); 931 if(!v) 932 v = &vundefined; 933 len = v.toUint32(); 934 935 for(k = len; k>0; k--) 936 { 937 v = othis.Get(k - 1); 938 if(v) 939 othis.Put(cast(uint)(k + arglist.length - 1), v, 0); 940 else 941 othis.Delete(cast(uint)(k + arglist.length - 1)); 942 } 943 944 for(k = 0; k < arglist.length; k++) 945 { 946 othis.Put(k, &arglist[k], 0); 947 } 948 othis.Put(TEXT_length, len + arglist.length, DontEnum); 949 ret.putVnumber(len + arglist.length); 950 return null; 951 } 952 953 /* =========================== Darray_prototype =================== */ 954 955 class DarrayPrototype : Darray 956 { 957 this() 958 { 959 super(Dobject_prototype); 960 Dobject f = Dfunction_prototype; 961 962 Put(TEXT_constructor, Darray_constructor, DontEnum); 963 964 static enum NativeFunctionData nfd[] = 965 [ 966 { TEXT_toString, &Darray_prototype_toString, 0 }, 967 { TEXT_toLocaleString, &Darray_prototype_toLocaleString, 0 }, 968 { TEXT_toSource, &Darray_prototype_toSource, 0 }, 969 { TEXT_concat, &Darray_prototype_concat, 1 }, 970 { TEXT_join, &Darray_prototype_join, 1 }, 971 { TEXT_pop, &Darray_prototype_pop, 0 }, 972 { TEXT_push, &Darray_prototype_push, 1 }, 973 { TEXT_reverse, &Darray_prototype_reverse, 0 }, 974 { TEXT_shift, &Darray_prototype_shift, 0, }, 975 { TEXT_slice, &Darray_prototype_slice, 2 }, 976 { TEXT_sort, &Darray_prototype_sort, 1 }, 977 { TEXT_splice, &Darray_prototype_splice, 2 }, 978 { TEXT_unshift, &Darray_prototype_unshift, 1 }, 979 ]; 980 981 DnativeFunction.initialize(this, nfd, DontEnum); 982 } 983 } 984 985 986 /* =========================== Darray =================== */ 987 988 class Darray : Dobject 989 { 990 Value length; // length property 991 d_uint32 ulength; 992 993 this() 994 { 995 this(getPrototype()); 996 } 997 998 this(Dobject prototype) 999 { 1000 super(prototype); 1001 length.putVnumber(0); 1002 ulength = 0; 1003 classname = TEXT_Array; 1004 } 1005 1006 override Value* Put(Identifier* key, Value* value, uint attributes) 1007 { 1008 Value* result = proptable.put(&key.value, key.value.hash, value, attributes); 1009 if(!result) 1010 Put(key.value..string, value, attributes); 1011 return null; 1012 } 1013 1014 override Value* Put(d_string name, Value* v, uint attributes) 1015 { 1016 d_uint32 i; 1017 uint c; 1018 Value* result; 1019 1020 // ECMA 15.4.5.1 1021 result = proptable.put(name, v, attributes); 1022 if(!result) 1023 { 1024 if(name == TEXT_length) 1025 { 1026 i = v.toUint32(); 1027 if(i != v.toInteger()) 1028 { 1029 ErrInfo errinfo; 1030 1031 return Dobject.RangeError(&errinfo, ERR_LENGTH_INT); 1032 } 1033 if(i < ulength) 1034 { 1035 // delete all properties with keys >= i 1036 d_uint32[] todelete; 1037 1038 foreach(Value key, ref Property p; *proptable) 1039 { 1040 d_uint32 j; 1041 1042 j = key.toUint32(); 1043 if(j >= i) 1044 todelete ~= j; 1045 } 1046 foreach(d_uint32 j; todelete) 1047 { 1048 proptable.del(j); 1049 } 1050 } 1051 ulength = i; 1052 length.number = i; 1053 proptable.put(name, v, attributes | DontEnum); 1054 } 1055 1056 // if (name is an array index i) 1057 1058 i = 0; 1059 for(size_t j = 0; j < name.length; j++) 1060 { 1061 ulong k; 1062 1063 c = name[j]; 1064 if(c == '0' && i == 0 && name.length > 1) 1065 goto Lret; 1066 if(c >= '0' && c <= '9') 1067 { 1068 k = i * cast(ulong)10 + c - '0'; 1069 i = cast(d_uint32)k; 1070 if(i != k) 1071 goto Lret; // overflow 1072 } 1073 else 1074 goto Lret; 1075 } 1076 if(i >= ulength) 1077 { 1078 if(i == 0xFFFFFFFF) 1079 goto Lret; 1080 ulength = i + 1; 1081 length.number = ulength; 1082 } 1083 } 1084 Lret: 1085 return null; 1086 } 1087 1088 override Value* Put(d_string name, Dobject o, uint attributes) 1089 { 1090 return Put(name, &o.value, attributes); 1091 } 1092 1093 override Value* Put(d_string PropertyName, d_number n, uint attributes) 1094 { 1095 Value v; 1096 1097 v.putVnumber(n); 1098 return Put(PropertyName, &v, attributes); 1099 } 1100 1101 override Value* Put(d_string PropertyName, d_string string, uint attributes) 1102 { 1103 Value v; 1104 1105 v.putVstring(string); 1106 return Put(PropertyName, &v, attributes); 1107 } 1108 1109 override Value* Put(d_uint32 index, Value* vindex, Value* value, uint attributes) 1110 { 1111 if(index >= ulength) 1112 ulength = index + 1; 1113 1114 proptable.put(vindex, index ^ 0x55555555 /*Value.calcHash(index)*/, value, attributes); 1115 return null; 1116 } 1117 1118 override Value* Put(d_uint32 index, Value* value, uint attributes) 1119 { 1120 if(index >= ulength) 1121 { 1122 ulength = index + 1; 1123 length.number = ulength; 1124 } 1125 1126 proptable.put(index, value, attributes); 1127 return null; 1128 } 1129 1130 final Value* Put(d_uint32 index, d_string string, uint attributes) 1131 { 1132 if(index >= ulength) 1133 { 1134 ulength = index + 1; 1135 length.number = ulength; 1136 } 1137 1138 proptable.put(index, string, attributes); 1139 return null; 1140 } 1141 1142 override Value* Get(Identifier* id) 1143 { 1144 //writef("Darray.Get(%p, '%s')\n", &proptable, PropertyName); 1145 if(id.value..string == TEXT_length) 1146 { 1147 length.number = ulength; 1148 return &length; 1149 } 1150 else 1151 return Dobject.Get(id); 1152 } 1153 1154 override Value* Get(d_string PropertyName, uint hash) 1155 { 1156 //writef("Darray.Get(%p, '%s')\n", &proptable, PropertyName); 1157 if(PropertyName == TEXT_length) 1158 { 1159 length.number = ulength; 1160 return &length; 1161 } 1162 else 1163 return Dobject.Get(PropertyName, hash); 1164 } 1165 1166 override Value* Get(d_uint32 index) 1167 { 1168 Value* v; 1169 1170 //writef("Darray.Get(%p, %d)\n", &proptable, index); 1171 v = proptable.get(index); 1172 return v; 1173 } 1174 1175 override Value* Get(d_uint32 index, Value* vindex) 1176 { 1177 Value* v; 1178 1179 //writef("Darray.Get(%p, %d)\n", &proptable, index); 1180 v = proptable.get(vindex, index ^ 0x55555555 /*Value.calcHash(index)*/); 1181 return v; 1182 } 1183 1184 override int Delete(d_string PropertyName) 1185 { 1186 // ECMA 8.6.2.5 1187 //writef("Darray.Delete('%ls')\n", d_string_ptr(PropertyName)); 1188 if(PropertyName == TEXT_length) 1189 return 0; // can't delete 'length' property 1190 else 1191 return proptable.del(PropertyName); 1192 } 1193 1194 override int Delete(d_uint32 index) 1195 { 1196 // ECMA 8.6.2.5 1197 return proptable.del(index); 1198 } 1199 1200 1201 static Dfunction getConstructor() 1202 { 1203 return Darray_constructor; 1204 } 1205 1206 static Dobject getPrototype() 1207 { 1208 return Darray_prototype; 1209 } 1210 1211 static void initialize() 1212 { 1213 Darray_constructor = new DarrayConstructor(); 1214 Darray_prototype = new DarrayPrototype(); 1215 1216 Darray_constructor.Put(TEXT_prototype, Darray_prototype, DontEnum | ReadOnly); 1217 } 1218 } 1219