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 core.stdc.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(CallContext* cc) 46 { 47 super(cc, 1, cc.tc.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(cc); 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(cc); 71 if(cast(double)len != v.number) 72 { 73 ErrInfo errinfo; 74 75 ret.putVundefined(); 76 return RangeError(&errinfo, cc, 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(cc, 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(cc, 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, cc, 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, cc, ERR_TLS_NOT_TRANSFERRABLE); 158 } 159 160 v = othis.Get(TEXT_length); 161 len = v ? v.toUint32(cc) : 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(cc); 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(cc); 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(cc); 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(cc, n, v, 0); 231 n++; 232 } 233 } 234 else 235 { 236 A.Put(cc, n, v, 0); 237 n++; 238 } 239 if(a == arglist.length) 240 break; 241 v = &arglist[a]; 242 } 243 244 A.Put(cc, 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, cc, ret, arglist); 254 return null; 255 } 256 257 void array_join(Dobject othis, CallContext* cc, 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(cc) : 0; 269 if(arglist.length == 0 || arglist[0].isUndefined()) 270 separator = TEXT_comma; 271 else 272 separator = arglist[0].toString(cc); 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(cc); 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(cc) : 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(cc); 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(cc); 329 if(u == 0) 330 { 331 othis.Put(cc, 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(cc, 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(cc); 360 for(a = 0; a < arglist.length; a++) 361 { 362 othis.Put(cc, u + a, &arglist[a], 0); 363 } 364 othis.Put(cc, 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(cc) : 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(cc, a, vb, 0); 396 else 397 othis.Delete(a); 398 399 if(va) 400 othis.Put(cc, 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(cc); 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(cc, 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(cc, 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(cc); 469 470 version(SliceSpliceExtension){ 471 d_number start; 472 d_number end; 473 switch(arglist.length) 474 { 475 case 0: 476 start = vundefined.toNumber(cc); 477 end = len; 478 break; 479 480 case 1: 481 start = arglist[0].toNumber(cc); 482 end = len; 483 break; 484 485 default: 486 start = arglist[0].toNumber(cc); 487 if(arglist[1].isUndefined()) 488 end = len; 489 else{ 490 end = arglist[1].toNumber(cc); 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(cc); 579 for(n = 0; k < r8; k++) 580 { 581 v = othis.Get(k); 582 if(v) 583 { 584 A.Put(cc, n, v, 0); 585 } 586 n++; 587 } 588 589 A.Put(cc, TEXT_length, n, DontEnum); 590 Value.copy(ret, &A.value); 591 return null; 592 } 593 594 /* ===================== Darray_prototype_sort ================= */ 595 596 597 void *Darray_prototype_sort(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 598 { 599 // ECMA v3 15.4.4.11 600 Value* v; 601 d_uint32 len; 602 uint u; 603 604 //writef("Array.prototype.sort()\n"); 605 v = othis.Get(TEXT_length); 606 len = v ? v.toUint32(cc) : 0; 607 608 // This is not optimal, as isArrayIndex is done at least twice 609 // for every array member. Additionally, the qsort() by index 610 // can be avoided if we can deduce it is not a sparse array. 611 612 Property *p; 613 Value[] pvalues; 614 d_uint32[] pindices; 615 d_uint32 parraydim; 616 d_uint32 nprops; 617 618 // First, size & alloc our temp array 619 if(len < 100) 620 { // Probably not too sparse an array 621 parraydim = len; 622 } 623 else 624 { 625 parraydim = 0; 626 foreach(ref Property p; *othis.proptable) 627 { 628 if(p.attributes == 0) // don't count special properties 629 parraydim++; 630 } 631 if(parraydim > len) // could theoretically happen 632 parraydim = len; 633 } 634 635 Value[] p1 = null; 636 Value* v1; 637 version(Win32) // eh and alloca() not working under linux 638 { 639 if(parraydim < 128) 640 v1 = cast(Value*)alloca(parraydim * Value.sizeof); 641 } 642 if(v1) 643 pvalues = v1[0 .. parraydim]; 644 else 645 { 646 p1 = new Value[parraydim]; 647 pvalues = p1; 648 } 649 650 d_uint32[] p2 = null; 651 d_uint32* p3; 652 version(Win32) 653 { 654 if(parraydim < 128) 655 p3 = cast(d_uint32*)alloca(parraydim * d_uint32.sizeof); 656 } 657 if(p3) 658 pindices = p3[0 .. parraydim]; 659 else 660 { 661 p2 = new d_uint32[parraydim]; 662 pindices = p2; 663 } 664 665 // Now fill it with all the Property's that are array indices 666 nprops = 0; 667 foreach(Value key, ref Property p; *othis.proptable) 668 { 669 d_uint32 index; 670 671 if(p.attributes == 0 && key.isArrayIndex(cc, index)) 672 { 673 pindices[nprops] = index; 674 Value.copy(&pvalues[nprops], &p.value); 675 nprops++; 676 } 677 } 678 679 synchronized 680 { 681 Dobject comparefn; 682 683 if(arglist.length) 684 { 685 if(!arglist[0].isPrimitive()) 686 comparefn = arglist[0].object; 687 } 688 689 690 bool compare_value(ref Value vx, ref Value vy) 691 { 692 d_string sx; 693 d_string sy; 694 int cmp; 695 696 //writef("compare_value()\n"); 697 if(vx.isUndefined()) 698 { 699 cmp = (vy.isUndefined()) ? 0 : 1; 700 } 701 else if(vy.isUndefined()) 702 cmp = -1; 703 else 704 { 705 if(comparefn) 706 { 707 Value[2] arglist; 708 Value ret; 709 Value* v; 710 d_number n; 711 712 Value.copy(&arglist[0], &vx); 713 Value.copy(&arglist[1], &vy); 714 ret.putVundefined(); 715 comparefn.Call(cc, comparefn, &ret, arglist); 716 n = ret.toNumber(cc); 717 if(n < 0) 718 cmp = -1; 719 else if(n > 0) 720 cmp = 1; 721 else 722 cmp = 0; 723 } 724 else 725 { 726 sx = vx.toString(cc); 727 sy = vy.toString(cc); 728 cmp = std..string.cmp(sx, sy); 729 if(cmp < 0) 730 cmp = -1; 731 else if(cmp > 0) 732 cmp = 1; 733 } 734 } 735 return cmp < 0; 736 } 737 738 // Sort pvalues[] 739 import std.algorithm.sorting : sort; 740 pvalues[0 .. nprops].sort!compare_value(); 741 } 742 743 // Stuff the sorted value's back into the array 744 for(u = 0; u < nprops; u++) 745 { 746 d_uint32 index; 747 748 othis.Put(cc, u, &pvalues[u], 0); 749 index = pindices[u]; 750 if(index >= nprops) 751 { 752 othis.Delete(index); 753 } 754 } 755 756 destroy(p1); 757 destroy(p2); 758 759 ret.putVobject(othis); 760 return null; 761 } 762 763 /* ===================== Darray_prototype_splice ================= */ 764 765 void *Darray_prototype_splice(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 766 { 767 // ECMA v3 15.4.4.12 768 d_uint32 len; 769 d_uint32 k; 770 771 Value* v; 772 Darray A; 773 d_uint32 a; 774 d_uint32 delcnt; 775 d_uint32 inscnt; 776 d_uint32 startidx; 777 778 v = othis.Get(TEXT_length); 779 if(!v) 780 v = &vundefined; 781 len = v.toUint32(cc); 782 783 version(SliceSpliceExtension){ 784 d_number start; 785 d_number deleteCount; 786 787 switch(arglist.length) 788 { 789 case 0: 790 start = vundefined.toNumber(cc); 791 deleteCount = 0; 792 break; 793 794 case 1: 795 start = arglist[0].toNumber(cc); 796 deleteCount = vundefined.toNumber(cc); 797 break; 798 799 default: 800 start = arglist[0].toNumber(cc); 801 deleteCount = arglist[1].toNumber(cc); 802 //checked later 803 break; 804 } 805 if(start == d_number.infinity) 806 startidx = len; 807 else if(start == -d_number.infinity) 808 startidx = 0; 809 else{ 810 if(start < 0) 811 { 812 startidx = cast(uint)(len + start); 813 if(cast(d_int32)startidx < 0) 814 startidx = 0; 815 } 816 else 817 startidx = cast(uint)start; 818 } 819 startidx = startidx > len ? len : startidx; 820 if(deleteCount == d_number.infinity) 821 delcnt = len; 822 else if(deleteCount == -d_number.infinity) 823 delcnt = 0; 824 else 825 delcnt = (cast(uint)deleteCount > 0) ? cast(uint) deleteCount : 0; 826 if(delcnt > len - startidx) 827 delcnt = len - startidx; 828 }else{ 829 long start; 830 d_int32 deleteCount; 831 switch(arglist.length) 832 { 833 case 0: 834 start = vundefined.toInt32(); 835 deleteCount = 0; 836 break; 837 838 case 1: 839 start = arglist[0].toInt32(); 840 deleteCount = vundefined.toInt32(); 841 break; 842 843 default: 844 start = arglist[0].toInt32(); 845 deleteCount = arglist[1].toInt32(); 846 //checked later 847 break; 848 } 849 startidx = cast(uint)start; 850 startidx = startidx > len ? len : startidx; 851 delcnt = (deleteCount > 0) ? deleteCount : 0; 852 if(delcnt > len - startidx) 853 delcnt = len - startidx; 854 } 855 856 A = new Darray(cc); 857 858 // If deleteCount is not specified, ECMA implies it should 859 // be 0, while "JavaScript The Definitive Guide" says it should 860 // be delete to end of array. Jscript doesn't implement splice(). 861 // We'll do it the Guide way. 862 if(arglist.length < 2) 863 delcnt = len - startidx; 864 865 //writef("Darray.splice(startidx = %d, delcnt = %d)\n", startidx, delcnt); 866 for(k = 0; k != delcnt; k++) 867 { 868 v = othis.Get(startidx + k); 869 if(v) 870 A.Put(cc, k, v, 0); 871 } 872 873 A.Put(cc, TEXT_length, delcnt, DontEnum); 874 inscnt = (arglist.length > 2) ? cast(uint)arglist.length - 2 : 0; 875 if(inscnt != delcnt) 876 { 877 if(inscnt <= delcnt) 878 { 879 for(k = startidx; k != (len - delcnt); k++) 880 { 881 v = othis.Get(k + delcnt); 882 if(v) 883 othis.Put(cc, k + inscnt, v, 0); 884 else 885 othis.Delete(k + inscnt); 886 } 887 888 for(k = len; k != (len - delcnt + inscnt); k--) 889 othis.Delete(k - 1); 890 } 891 else 892 { 893 for(k = len - delcnt; k != startidx; k--) 894 { 895 v = othis.Get(k + delcnt - 1); 896 if(v) 897 othis.Put(cc, k + inscnt - 1, v, 0); 898 else 899 othis.Delete(k + inscnt - 1); 900 } 901 } 902 } 903 k = startidx; 904 for(a = 2; a < arglist.length; a++) 905 { 906 v = &arglist[a]; 907 othis.Put(cc, k, v, 0); 908 k++; 909 } 910 911 othis.Put(cc, TEXT_length, len - delcnt + inscnt, DontEnum); 912 Value.copy(ret, &A.value); 913 return null; 914 } 915 916 /* ===================== Darray_prototype_unshift ================= */ 917 918 void *Darray_prototype_unshift(Dobject pthis, CallContext *cc, Dobject othis, Value *ret, Value[] arglist) 919 { 920 // ECMA v3 15.4.4.13 921 Value* v; 922 d_uint32 len; 923 d_uint32 k; 924 925 v = othis.Get(TEXT_length); 926 if(!v) 927 v = &vundefined; 928 len = v.toUint32(cc); 929 930 for(k = len; k>0; k--) 931 { 932 v = othis.Get(k - 1); 933 if(v) 934 othis.Put(cc, cast(uint)(k + arglist.length - 1), v, 0); 935 else 936 othis.Delete(cast(uint)(k + arglist.length - 1)); 937 } 938 939 for(k = 0; k < arglist.length; k++) 940 { 941 othis.Put(cc, k, &arglist[k], 0); 942 } 943 othis.Put(cc, TEXT_length, len + arglist.length, DontEnum); 944 ret.putVnumber(len + arglist.length); 945 return null; 946 } 947 948 /* =========================== Darray_prototype =================== */ 949 950 class DarrayPrototype : Darray 951 { 952 this(CallContext* cc) 953 { 954 super(cc, cc.tc.Dobject_prototype); 955 Dobject f = cc.tc.Dfunction_prototype; 956 957 Put(cc, TEXT_constructor, cc.tc.Darray_constructor, DontEnum); 958 959 static enum NativeFunctionData[] nfd = 960 [ 961 { TEXT_toString, &Darray_prototype_toString, 0 }, 962 { TEXT_toLocaleString, &Darray_prototype_toLocaleString, 0 }, 963 { TEXT_toSource, &Darray_prototype_toSource, 0 }, 964 { TEXT_concat, &Darray_prototype_concat, 1 }, 965 { TEXT_join, &Darray_prototype_join, 1 }, 966 { TEXT_pop, &Darray_prototype_pop, 0 }, 967 { TEXT_push, &Darray_prototype_push, 1 }, 968 { TEXT_reverse, &Darray_prototype_reverse, 0 }, 969 { TEXT_shift, &Darray_prototype_shift, 0, }, 970 { TEXT_slice, &Darray_prototype_slice, 2 }, 971 { TEXT_sort, &Darray_prototype_sort, 1 }, 972 { TEXT_splice, &Darray_prototype_splice, 2 }, 973 { TEXT_unshift, &Darray_prototype_unshift, 1 }, 974 ]; 975 976 DnativeFunction.initialize(this, cc, nfd, DontEnum); 977 } 978 } 979 980 981 /* =========================== Darray =================== */ 982 983 class Darray : Dobject 984 { 985 Value length; // length property 986 d_uint32 ulength; 987 988 this(CallContext* cc) 989 { 990 this(cc, getPrototype(cc)); 991 } 992 993 this(CallContext* cc, Dobject prototype) 994 { 995 super(cc, prototype); 996 length.putVnumber(0); 997 ulength = 0; 998 classname = TEXT_Array; 999 } 1000 1001 override Value* Put(CallContext* cc, Identifier* key, Value* value, uint attributes) 1002 { 1003 Value* result = proptable.put(&key.value, key.value.hash, value, attributes); 1004 if(!result) 1005 Put(cc, key.value..string, value, attributes); 1006 return null; 1007 } 1008 1009 override Value* Put(CallContext* cc, d_string name, Value* v, uint attributes) 1010 { 1011 d_uint32 i; 1012 uint c; 1013 Value* result; 1014 1015 // ECMA 15.4.5.1 1016 result = proptable.put(name, v, attributes); 1017 if(!result) 1018 { 1019 if(name == TEXT_length) 1020 { 1021 i = v.toUint32(cc); 1022 if(i != v.toInteger(cc)) 1023 { 1024 ErrInfo errinfo; 1025 1026 return Dobject.RangeError(&errinfo, cc, ERR_LENGTH_INT); 1027 } 1028 if(i < ulength) 1029 { 1030 // delete all properties with keys >= i 1031 d_uint32[] todelete; 1032 1033 foreach(Value key, ref Property p; *proptable) 1034 { 1035 d_uint32 j; 1036 1037 j = key.toUint32(cc); 1038 if(j >= i) 1039 todelete ~= j; 1040 } 1041 foreach(d_uint32 j; todelete) 1042 { 1043 proptable.del(j); 1044 } 1045 } 1046 ulength = i; 1047 length.number = i; 1048 proptable.put(name, v, attributes | DontEnum); 1049 } 1050 1051 // if (name is an array index i) 1052 1053 i = 0; 1054 for(size_t j = 0; j < name.length; j++) 1055 { 1056 ulong k; 1057 1058 c = name[j]; 1059 if(c == '0' && i == 0 && name.length > 1) 1060 goto Lret; 1061 if(c >= '0' && c <= '9') 1062 { 1063 k = i * cast(ulong)10 + c - '0'; 1064 i = cast(d_uint32)k; 1065 if(i != k) 1066 goto Lret; // overflow 1067 } 1068 else 1069 goto Lret; 1070 } 1071 if(i >= ulength) 1072 { 1073 if(i == 0xFFFFFFFF) 1074 goto Lret; 1075 ulength = i + 1; 1076 length.number = ulength; 1077 } 1078 } 1079 Lret: 1080 return null; 1081 } 1082 1083 override Value* Put(CallContext* cc, d_string name, Dobject o, uint attributes) 1084 { 1085 return Put(cc, name, &o.value, attributes); 1086 } 1087 1088 override Value* Put(CallContext* cc, d_string PropertyName, d_number n, uint attributes) 1089 { 1090 Value v; 1091 1092 v.putVnumber(n); 1093 return Put(cc, PropertyName, &v, attributes); 1094 } 1095 1096 override Value* Put(CallContext* cc, d_string PropertyName, d_string string, uint attributes) 1097 { 1098 Value v; 1099 1100 v.putVstring(string); 1101 return Put(cc, PropertyName, &v, attributes); 1102 } 1103 1104 override Value* Put(CallContext* cc, d_uint32 index, Value* vindex, Value* value, uint attributes) 1105 { 1106 if(index >= ulength) 1107 ulength = index + 1; 1108 1109 proptable.put(vindex, index ^ 0x55555555 /*Value.calcHash(index)*/, value, attributes); 1110 return null; 1111 } 1112 1113 override Value* Put(CallContext* cc, d_uint32 index, Value* value, uint attributes) 1114 { 1115 if(index >= ulength) 1116 { 1117 ulength = index + 1; 1118 length.number = ulength; 1119 } 1120 1121 proptable.put(index, value, attributes); 1122 return null; 1123 } 1124 1125 final Value* Put(CallContext* cc, d_uint32 index, d_string string, uint attributes) 1126 { 1127 if(index >= ulength) 1128 { 1129 ulength = index + 1; 1130 length.number = ulength; 1131 } 1132 1133 proptable.put(index, string, attributes); 1134 return null; 1135 } 1136 1137 override Value* Get(Identifier* id) 1138 { 1139 //writef("Darray.Get(%p, '%s')\n", &proptable, PropertyName); 1140 if(id.value..string == TEXT_length) 1141 { 1142 length.number = ulength; 1143 return &length; 1144 } 1145 else 1146 return Dobject.Get(id); 1147 } 1148 1149 override Value* Get(d_string PropertyName, uint hash) 1150 { 1151 //writef("Darray.Get(%p, '%s')\n", &proptable, PropertyName); 1152 if(PropertyName == TEXT_length) 1153 { 1154 length.number = ulength; 1155 return &length; 1156 } 1157 else 1158 return Dobject.Get(PropertyName, hash); 1159 } 1160 1161 override Value* Get(d_uint32 index) 1162 { 1163 Value* v; 1164 1165 //writef("Darray.Get(%p, %d)\n", &proptable, index); 1166 v = proptable.get(index); 1167 return v; 1168 } 1169 1170 override Value* Get(d_uint32 index, Value* vindex) 1171 { 1172 Value* v; 1173 1174 //writef("Darray.Get(%p, %d)\n", &proptable, index); 1175 v = proptable.get(vindex, index ^ 0x55555555 /*Value.calcHash(index)*/); 1176 return v; 1177 } 1178 1179 override int Delete(d_string PropertyName) 1180 { 1181 // ECMA 8.6.2.5 1182 //writef("Darray.Delete('%ls')\n", d_string_ptr(PropertyName)); 1183 if(PropertyName == TEXT_length) 1184 return 0; // can't delete 'length' property 1185 else 1186 return proptable.del(PropertyName); 1187 } 1188 1189 override int Delete(d_uint32 index) 1190 { 1191 // ECMA 8.6.2.5 1192 return proptable.del(index); 1193 } 1194 1195 1196 static Dfunction getConstructor(CallContext* cc) 1197 { 1198 return cc.tc.Darray_constructor; 1199 } 1200 1201 static Dobject getPrototype(CallContext* cc) 1202 { 1203 return cc.tc.Darray_prototype; 1204 } 1205 1206 static void initialize(CallContext* cc) 1207 { 1208 cc.tc.Darray_constructor = new DarrayConstructor(cc); 1209 cc.tc.Darray_prototype = new DarrayPrototype(cc); 1210 1211 cc.tc.Darray_constructor.Put(cc, TEXT_prototype, cc.tc.Darray_prototype, DontEnum | ReadOnly); 1212 } 1213 } 1214