Changeset 798 in webkit for trunk/JavaScriptCore/kjs/array_object.cpp
- Timestamp:
- Mar 21, 2002, 4:31:57 PM (23 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/array_object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 18 20 */ 19 21 20 #include "kjs.h" 22 #include "value.h" 23 #include "object.h" 24 #include "types.h" 25 #include "interpreter.h" 21 26 #include "operations.h" 22 #include "types.h"23 27 #include "array_object.h" 28 #include "internal.h" 29 #include "error_object.h" 30 31 #include "array_object.lut.h" 32 24 33 #include <stdio.h> 34 #include <assert.h> 25 35 26 36 using namespace KJS; 27 37 28 ArrayObject::ArrayObject(const Object &funcProto, 29 const Object &arrayProto) 30 : ConstructorImp(funcProto, 1) 31 { 38 // ------------------------------ ArrayInstanceImp ----------------------------- 39 40 const ClassInfo ArrayInstanceImp::info = {"Array", 0, 0, 0}; 41 42 ArrayInstanceImp::ArrayInstanceImp(const Object &proto) 43 : ObjectImp(proto) 44 { 45 } 46 47 // Special implementation of [[Put]] - see ECMA 15.4.5.1 48 void ArrayInstanceImp::put(ExecState *exec, const UString &propertyName, const Value &value, int attr) 49 { 50 if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) 51 return; 52 53 if (hasProperty(exec,propertyName)) { 54 if (propertyName == "length") { 55 Value len = get(exec,"length"); 56 unsigned int oldLen = len.toUInt32(exec); 57 unsigned int newLen = value.toUInt32(exec); 58 // shrink array 59 for (unsigned int u = newLen; u < oldLen; u++) { 60 UString p = UString::from(u); 61 if (hasProperty(exec, p, false)) 62 deleteProperty(exec, p); 63 } 64 ObjectImp::put(exec, "length", Number(newLen), DontEnum | DontDelete); 65 return; 66 } 67 // put(p, v); 68 } // } else 69 ObjectImp::put(exec, propertyName, value, attr); 70 71 // array index ? 72 unsigned int idx; 73 if (!sscanf(propertyName.cstring().c_str(), "%u", &idx)) /* TODO */ 74 return; 75 76 // do we need to update/create the length property ? 77 if (hasProperty(exec, "length", false)) { 78 Value len = get(exec, "length"); 79 if (idx < len.toUInt32(exec)) 80 return; 81 } 82 83 ObjectImp::put(exec, "length", Number(idx+1), DontDelete | DontEnum); 84 } 85 86 void ArrayInstanceImp::putDirect(ExecState *exec, const UString &propertyName, const Value &value, int attr) 87 { 88 ObjectImp::put(exec,propertyName,value,attr); 89 } 90 // ------------------------------ ArrayPrototypeImp ---------------------------- 91 92 const ClassInfo ArrayPrototypeImp::info = {"Array", &ArrayInstanceImp::info, &arrayTable, 0}; 93 94 /* Source for array_object.lut.h 95 @begin arrayTable 13 96 toString ArrayProtoFuncImp::ToString DontEnum|Function 0 97 toLocaleString ArrayProtoFuncImp::ToLocaleString DontEnum|Function 0 98 concat ArrayProtoFuncImp::Concat DontEnum|Function 1 99 join ArrayProtoFuncImp::Join DontEnum|Function 1 100 pop ArrayProtoFuncImp::Pop DontEnum|Function 0 101 push ArrayProtoFuncImp::Push DontEnum|Function 1 102 reverse ArrayProtoFuncImp::Reverse DontEnum|Function 0 103 shift ArrayProtoFuncImp::Shift DontEnum|Function 0 104 slice ArrayProtoFuncImp::Slice DontEnum|Function 2 105 sort ArrayProtoFuncImp::Sort DontEnum|Function 1 106 splice ArrayProtoFuncImp::Splice DontEnum|Function 2 107 unshift ArrayProtoFuncImp::UnShift DontEnum|Function 1 108 @end 109 */ 110 111 // ECMA 15.4.4 112 ArrayPrototypeImp::ArrayPrototypeImp(ExecState *exec, 113 ObjectPrototypeImp *objProto) 114 : ArrayInstanceImp(Object(objProto)) 115 { 116 Value protect(this); 117 setInternalValue(Null()); 118 119 // The constructor will be added later, by InterpreterImp, once ArrayObjectImp has been constructed. 120 put(exec,"length", Number(0), DontEnum | DontDelete); 121 } 122 123 Value ArrayPrototypeImp::get(ExecState *exec, const UString &propertyName) const 124 { 125 //fprintf( stderr, "ArrayPrototypeImp::get(%s)\n", propertyName.ascii() ); 126 return lookupGetFunction<ArrayProtoFuncImp, ArrayInstanceImp>( exec, propertyName, &arrayTable, this ); 127 } 128 129 // ------------------------------ ArrayProtoFuncImp ---------------------------- 130 131 ArrayProtoFuncImp::ArrayProtoFuncImp(ExecState *exec, int i, int len) 132 : InternalFunctionImp( 133 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp()) 134 ), id(i) 135 { 136 Value protect(this); 137 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); 138 } 139 140 bool ArrayProtoFuncImp::implementsCall() const 141 { 142 return true; 143 } 144 145 // ECMA 15.4.4 146 Value ArrayProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args) 147 { 148 unsigned int length = thisObj.get(exec,"length").toUInt32(exec); 149 150 Value result; 151 switch (id) { 152 case ToLocaleString: 153 // TODO - see 15.4.4.3 154 // fall through 155 case ToString: 156 157 if (!thisObj.inherits(&ArrayInstanceImp::info)) { 158 Object err = Error::create(exec,TypeError); 159 exec->setException(err); 160 return err; 161 } 162 163 // fall through 164 165 case Join: { 166 UString separator = ","; 167 UString str = ""; 168 169 if (args.size() > 0) 170 separator = args[0].toString(exec); 171 for (unsigned int k = 0; k < length; k++) { 172 if (k >= 1) 173 str += separator; 174 Value element = thisObj.get(exec,UString::from(k)); 175 if (element.type() != UndefinedType && element.type() != NullType) 176 str += element.toString(exec); 177 } 178 result = String(str); 179 break; 180 } 181 case Concat: { 182 Object arr = Object::dynamicCast(exec->interpreter()->builtinArray().construct(exec,List::empty())); 183 int n = 0; 184 Value curArg = thisObj; 185 Object curObj = Object::dynamicCast(thisObj); 186 ListIterator it = args.begin(); 187 for (;;) { 188 if (curArg.type() == ObjectType && 189 curObj.inherits(&ArrayInstanceImp::info)) { 190 unsigned int k = 0; 191 if (n > 0) 192 length = curObj.get(exec,"length").toUInt32(exec); 193 while (k < length) { 194 UString p = UString::from(k); 195 if (curObj.hasProperty(exec,p)) 196 arr.put(exec,UString::from(n), curObj.get(exec,p)); 197 n++; 198 k++; 199 } 200 } else { 201 arr.put(exec,UString::from(n), curArg); 202 n++; 203 } 204 if (it == args.end()) 205 break; 206 curArg = *it; 207 curObj = Object::dynamicCast(it++); // may be 0 208 } 209 arr.put(exec,"length", Number(n), DontEnum | DontDelete); 210 211 result = arr; 212 break; 213 } 214 case Pop:{ 215 216 if (length == 0) { 217 thisObj.put(exec, "length", Number(length), DontEnum | DontDelete); 218 result = Undefined(); 219 } else { 220 UString str = UString::from(length - 1); 221 result = thisObj.get(exec,str); 222 thisObj.deleteProperty(exec, str); 223 thisObj.put(exec, "length", Number(length - 1), DontEnum | DontDelete); 224 } 225 break; 226 } 227 case Push: { 228 for (int n = 0; n < args.size(); n++) 229 thisObj.put(exec,UString::from(length + n), args[n]); 230 length += args.size(); 231 thisObj.put(exec,"length", Number(length), DontEnum | DontDelete); 232 result = Number(length); 233 break; 234 } 235 case Reverse: { 236 237 unsigned int middle = length / 2; 238 239 for (unsigned int k = 0; k < middle; k++) { 240 UString str = UString::from(k); 241 UString str2 = UString::from(length - k - 1); 242 Value obj = thisObj.get(exec,str); 243 Value obj2 = thisObj.get(exec,str2); 244 if (thisObj.hasProperty(exec,str2)) { 245 if (thisObj.hasProperty(exec,str)) { 246 thisObj.put(exec, str, obj2); 247 thisObj.put(exec, str2, obj); 248 } else { 249 thisObj.put(exec, str, obj2); 250 thisObj.deleteProperty(exec, str2); 251 } 252 } else { 253 if (thisObj.hasProperty(exec, str)) { 254 thisObj.deleteProperty(exec, str); 255 thisObj.put(exec, str2, obj); 256 } else { 257 // why delete something that's not there ? Strange. 258 thisObj.deleteProperty(exec, str); 259 thisObj.deleteProperty(exec, str2); 260 } 261 } 262 } 263 result = thisObj; 264 break; 265 } 266 case Shift: { 267 if (length == 0) { 268 thisObj.put(exec, "length", Number(length), DontEnum | DontDelete); 269 result = Undefined(); 270 } else { 271 result = thisObj.get(exec, "0"); 272 for(unsigned int k = 1; k < length; k++) { 273 UString str = UString::from(k); 274 UString str2 = UString::from(k-1); 275 if (thisObj.hasProperty(exec, str)) { 276 Value obj = thisObj.get(exec, str); 277 thisObj.put(exec, str2, obj); 278 } else 279 thisObj.deleteProperty(exec, str2); 280 } 281 thisObj.deleteProperty(exec, UString::from(length - 1)); 282 thisObj.put(exec, "length", Number(length - 1), DontEnum | DontDelete); 283 } 284 break; 285 } 286 case Slice: { 287 // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10 288 289 // We return a new array 290 Object resObj = Object::dynamicCast(exec->interpreter()->builtinArray().construct(exec,List::empty())); 291 result = resObj; 292 int begin = args[0].toUInt32(exec); 293 if ( begin < 0 ) 294 begin = maxInt( begin + length, 0 ); 295 else 296 begin = minInt( begin, length ); 297 int end = length; 298 if (args[1].type() != UndefinedType) 299 { 300 end = args[1].toUInt32(exec); 301 if ( end < 0 ) 302 end = maxInt( end + length, 0 ); 303 else 304 end = minInt( end, length ); 305 } 306 307 //printf( "Slicing from %d to %d \n", begin, end ); 308 for(unsigned int k = 0; k < (unsigned int) end-begin; k++) { 309 UString str = UString::from(k+begin); 310 if (thisObj.hasProperty(exec,str)) { 311 UString str2 = UString::from(k); 312 Value obj = thisObj.get(exec, str); 313 resObj.put(exec, str2, obj); 314 } 315 } 316 resObj.put(exec, "length", Number(end - begin), DontEnum | DontDelete); 317 break; 318 } 319 case Sort:{ 320 #if 0 321 printf("KJS Array::Sort length=%d\n", length); 322 for ( unsigned int i = 0 ; i<length ; ++i ) 323 printf("KJS Array::Sort: %d: %s\n", i, thisObj.get(UString::from(i)).toString().value().ascii() ); 324 #endif 325 Object sortFunction; 326 bool useSortFunction = (args[0].type() != UndefinedType); 327 if (useSortFunction) 328 { 329 sortFunction = args[0].toObject(exec); 330 if (!sortFunction.implementsCall()) 331 useSortFunction = false; 332 } 333 334 if (length == 0) { 335 thisObj.put(exec, "length", Number(0), DontEnum | DontDelete); 336 result = Undefined(); 337 break; 338 } 339 340 // "Min" sort. Not the fastest, but definitely less code than heapsort 341 // or quicksort, and much less swapping than bubblesort/insertionsort. 342 for ( unsigned int i = 0 ; i<length-1 ; ++i ) 343 { 344 Value iObj = thisObj.get(exec,UString::from(i)); 345 unsigned int themin = i; 346 Value minObj = iObj; 347 for ( unsigned int j = i+1 ; j<length ; ++j ) 348 { 349 Value jObj = thisObj.get(exec,UString::from(j)); 350 int cmp; 351 if ( useSortFunction ) 352 { 353 List l; 354 l.append(jObj); 355 l.append(minObj); 356 Object thisObj = exec->interpreter()->globalObject(); 357 cmp = sortFunction.call(exec,thisObj, l ).toInt32(exec); 358 } 359 else 360 cmp = (jObj.toString(exec) < minObj.toString(exec)) ? -1 : 1; 361 if ( cmp < 0 ) 362 { 363 themin = j; 364 minObj = jObj; 365 } 366 } 367 // Swap themin and i 368 if ( themin > i ) 369 { 370 //printf("KJS Array::Sort: swapping %d and %d\n", i, themin ); 371 thisObj.put( exec, UString::from(i), minObj ); 372 thisObj.put( exec, UString::from(themin), iObj ); 373 } 374 } 375 #if 0 376 printf("KJS Array::Sort -- Resulting array:\n"); 377 for ( unsigned int i = 0 ; i<length ; ++i ) 378 printf("KJS Array::Sort: %d: %s\n", i, thisObj.get(UString::from(i)).toString().value().ascii() ); 379 #endif 380 result = thisObj; 381 break; 382 } 383 case Splice: { 384 // 15.4.4.12 - oh boy this is huge 385 Object resObj = Object::dynamicCast(exec->interpreter()->builtinArray().construct(exec,List::empty())); 386 result = resObj; 387 int begin = args[0].toUInt32(exec); 388 if ( begin < 0 ) 389 begin = maxInt( begin + length, 0 ); 390 else 391 begin = minInt( begin, length ); 392 unsigned int deleteCount = minInt( maxInt( args[1].toUInt32(exec), 0 ), length - begin ); 393 394 //printf( "Splicing from %d, deleteCount=%d \n", begin, deleteCount ); 395 for(unsigned int k = 0; k < deleteCount; k++) { 396 UString str = UString::from(k+begin); 397 if (thisObj.hasProperty(exec,str)) { 398 UString str2 = UString::from(k); 399 Value obj = thisObj.get(exec, str); 400 resObj.put(exec, str2, obj); 401 } 402 } 403 resObj.put(exec, "length", Number(deleteCount), DontEnum | DontDelete); 404 405 unsigned int additionalArgs = maxInt( args.size() - 2, 0 ); 406 if ( additionalArgs != deleteCount ) 407 { 408 if ( additionalArgs < deleteCount ) 409 { 410 for ( unsigned int k = begin; k < length - deleteCount; ++k ) 411 { 412 UString str = UString::from(k+deleteCount); 413 UString str2 = UString::from(k+additionalArgs); 414 if (thisObj.hasProperty(exec,str)) { 415 Value obj = thisObj.get(exec, str); 416 thisObj.put(exec, str2, obj); 417 } 418 else 419 thisObj.deleteProperty(exec, str2); 420 } 421 for ( unsigned int k = length ; k > length - deleteCount + additionalArgs; --k ) 422 thisObj.deleteProperty(exec, UString::from(k-1)); 423 } 424 else 425 { 426 for ( unsigned int k = length - deleteCount; (int)k > begin; --k ) 427 { 428 UString str = UString::from(k+deleteCount-1); 429 UString str2 = UString::from(k+additionalArgs-1); 430 if (thisObj.hasProperty(exec,str)) { 431 Value obj = thisObj.get(exec, str); 432 thisObj.put(exec, str2, obj); 433 } 434 else 435 thisObj.deleteProperty(exec, str2); 436 } 437 } 438 } 439 for ( unsigned int k = 0; k < additionalArgs; ++k ) 440 { 441 thisObj.put(exec, UString::from(k+begin), args[k+2]); 442 } 443 thisObj.put(exec, "length", Number(length - deleteCount + additionalArgs), DontEnum | DontDelete); 444 break; 445 } 446 case UnShift: { // 15.4.4.13 447 unsigned int nrArgs = args.size(); 448 for ( unsigned int k = length; k > 0; --k ) 449 { 450 UString str = UString::from(k-1); 451 UString str2 = UString::from(k+nrArgs-1); 452 if (thisObj.hasProperty(exec,str)) { 453 Value obj = thisObj.get(exec, str); 454 thisObj.put(exec, str2, obj); 455 } else { 456 thisObj.deleteProperty(exec, str2); 457 } 458 } 459 for ( unsigned int k = 0; k < nrArgs; ++k ) 460 thisObj.put(exec, UString::from(k), args[k]); 461 result = Number(length + nrArgs); 462 thisObj.put(exec, "length", result, DontEnum | DontDelete); 463 break; 464 } 465 default: 466 assert(0); 467 break; 468 } 469 return result; 470 } 471 472 // ------------------------------ ArrayObjectImp ------------------------------- 473 474 ArrayObjectImp::ArrayObjectImp(ExecState *exec, 475 FunctionPrototypeImp *funcProto, 476 ArrayPrototypeImp *arrayProto) 477 : InternalFunctionImp(funcProto) 478 { 479 Value protect(this); 32 480 // ECMA 15.4.3.1 Array.prototype 33 setPrototypeProperty(arrayProto); 34 } 35 36 // ECMA 15.6.1 37 Completion ArrayObject::execute(const List &args) 38 { 39 // equivalent to 'new Array(....)' 40 KJSO result = construct(args); 41 42 return Completion(ReturnValue, result); 43 } 44 45 // ECMA 15.6.2 46 Object ArrayObject::construct(const List &args) 47 { 48 Object result = Object::create(ArrayClass); 481 put(exec,"prototype", Object(arrayProto), DontEnum|DontDelete|ReadOnly); 482 483 // no. of arguments for constructor 484 put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum); 485 } 486 487 bool ArrayObjectImp::implementsConstruct() const 488 { 489 return true; 490 } 491 492 // ECMA 15.4.2 493 Object ArrayObjectImp::construct(ExecState *exec, const List &args) 494 { 495 Object result(new ArrayInstanceImp(exec->interpreter()->builtinArrayPrototype())); 49 496 50 497 unsigned int len; 51 498 ListIterator it = args.begin(); 52 499 // a single argument might denote the array size 53 if (args.size() == 1 && it-> isA(NumberType))54 len = it->toUInt32( );500 if (args.size() == 1 && it->type() == NumberType) 501 len = it->toUInt32(exec); 55 502 else { 56 503 // initialize array 57 504 len = args.size(); 58 505 for (unsigned int u = 0; it != args.end(); it++, u++) 59 result.put( UString::from(u), *it);506 result.put(exec, UString::from(u), *it); 60 507 } 61 508 62 509 // array size 63 result.put("length", len, DontEnum | DontDelete); 510 result.put(exec, "length", Number(len), DontEnum | DontDelete); 511 static_cast<ArrayInstanceImp*>(result.imp())->putDirect(exec, "length", Number(len), DontEnum | DontDelete); 64 512 65 513 return result; 66 514 } 67 515 68 // ECMA 15.6.4 69 ArrayPrototype::ArrayPrototype(const Object& proto) 70 : ObjectImp(ArrayClass, Null(), proto) 71 { 72 // The constructor will be added later in ArrayObject's constructor 73 74 put("length", 0u, DontEnum | DontDelete); 75 } 76 77 KJSO ArrayPrototype::get(const UString &p) const 78 { 79 int id; 80 if(p == "toString") 81 id = ArrayProtoFunc::ToString; 82 else if(p == "toLocaleString") 83 id = ArrayProtoFunc::ToLocaleString; 84 else if(p == "concat") 85 id = ArrayProtoFunc::Concat; 86 else if (p == "join") 87 id = ArrayProtoFunc::Join; 88 else if(p == "pop") 89 id = ArrayProtoFunc::Pop; 90 else if(p == "push") 91 id = ArrayProtoFunc::Push; 92 else if(p == "reverse") 93 id = ArrayProtoFunc::Reverse; 94 else if(p == "shift") 95 id = ArrayProtoFunc::Shift; 96 else if(p == "slice") 97 id = ArrayProtoFunc::Slice; 98 else if(p == "sort") 99 id = ArrayProtoFunc::Sort; 100 else if(p == "splice") 101 id = ArrayProtoFunc::Splice; 102 else if(p == "unshift") 103 id = ArrayProtoFunc::UnShift; 104 else 105 return Imp::get(p); 106 107 return Function(new ArrayProtoFunc(id)); 108 } 109 110 // ECMA 15.4.4 111 Completion ArrayProtoFunc::execute(const List &args) 112 { 113 KJSO result, obj, obj2; 114 Object thisObj = Object::dynamicCast(thisValue()); 115 unsigned int length = thisObj.get("length").toUInt32(); 116 unsigned int middle; 117 UString str = "", str2; 118 UString separator = ","; 119 120 switch (id) { 121 case ToLocaleString: 122 /* TODO */ 123 // fall trough 124 case ToString: 125 if (!thisObj.getClass() == ArrayClass) { 126 result = Error::create(TypeError); 127 break; 128 } 129 // fall trough 130 case Join: 131 { 132 if (!args[0].isA(UndefinedType)) 133 separator = args[0].toString().value(); 134 for (unsigned int k = 0; k < length; k++) { 135 if (k >= 1) 136 str += separator; 137 obj = thisObj.get(UString::from(k)); 138 if (!obj.isA(UndefinedType) && !obj.isA(NullType)) 139 str += obj.toString().value(); 140 } 141 } 142 result = String(str); 143 break; 144 case Concat: { 145 result = Object::create(ArrayClass); 146 int n = 0; 147 obj = thisObj; 148 ListIterator it = args.begin(); 149 for (;;) { 150 if (obj.isA(ObjectType) && 151 static_cast<Object&>(obj).getClass() == ArrayClass) { 152 unsigned int k = 0; 153 if (n > 0) 154 length = obj.get("length").toUInt32(); 155 while (k < length) { 156 UString p = UString::from(k); 157 if (obj.hasProperty(p)) 158 result.put(UString::from(n), obj.get(p)); 159 n++; 160 k++; 161 } 162 } else { 163 result.put(UString::from(n), obj); 164 n++; 165 } 166 if (it == args.end()) 167 break; 168 obj = it++; 169 } 170 result.put("length", Number(n), DontEnum | DontDelete); 171 } 172 break; 173 case Pop: 174 if (length == 0) { 175 thisObj.put("length", Number(length), DontEnum | DontDelete); 176 result = Undefined(); 177 } else { 178 str = UString::from(length - 1); 179 result = thisObj.get(str); 180 thisObj.deleteProperty(str); 181 thisObj.put("length", length - 1, DontEnum | DontDelete); 182 } 183 break; 184 case Push: 185 { 186 for (int n = 0; n < args.size(); n++) 187 thisObj.put(UString::from(length + n), args[n]); 188 length += args.size(); 189 thisObj.put("length", length, DontEnum | DontDelete); 190 result = Number(length); 191 } 192 break; 193 case Reverse: 194 { 195 middle = length / 2; 196 for (unsigned int k = 0; k < middle; k++) { 197 str = UString::from(k); 198 str2 = UString::from(length - k - 1); 199 obj = thisObj.get(str); 200 obj2 = thisObj.get(str2); 201 if (thisObj.hasProperty(str2)) { 202 if (thisObj.hasProperty(str)) { 203 thisObj.put(str, obj2); 204 thisObj.put(str2, obj); 205 } else { 206 thisObj.put(str, obj2); 207 thisObj.deleteProperty(str2); 208 } 209 } else { 210 if (thisObj.hasProperty(str)) { 211 thisObj.deleteProperty(str); 212 thisObj.put(str2, obj); 213 } else { 214 // why delete something that's not there ? Strange. 215 thisObj.deleteProperty(str); 216 thisObj.deleteProperty(str2); 217 } 218 } 219 } 220 } 221 result = thisObj; 222 break; 223 case Shift: 224 if (length == 0) { 225 thisObj.put("length", Number(length), DontEnum | DontDelete); 226 result = Undefined(); 227 } else { 228 result = thisObj.get("0"); 229 for(unsigned int k = 1; k < length; k++) { 230 str = UString::from(k); 231 str2 = UString::from(k-1); 232 if (thisObj.hasProperty(str)) { 233 obj = thisObj.get(str); 234 thisObj.put(str2, obj); 235 } else 236 thisObj.deleteProperty(str2); 237 } 238 thisObj.deleteProperty(UString::from(length - 1)); 239 thisObj.put("length", length - 1, DontEnum | DontDelete); 240 } 241 break; 242 case Slice: // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 243 { 244 result = Object::create(ArrayClass); // We return a new array 245 int begin = args[0].toUInt32(); 246 int end = length; 247 if (!args[1].isA(UndefinedType)) 248 { 249 end = args[1].toUInt32(); 250 if ( end < 0 ) 251 end += length; 252 } 253 // safety tests 254 if ( begin < 0 || end < 0 || begin >= end ) { 255 result.put("length", Number(0), DontEnum | DontDelete); 256 break; 257 } 258 //printf( "Slicing from %d to %d \n", begin, end ); 259 for(unsigned int k = 0; k < (unsigned int) end-begin; k++) { 260 str = UString::from(k+begin); 261 str2 = UString::from(k); 262 if (thisObj.hasProperty(str)) { 263 obj = thisObj.get(str); 264 result.put(str2, obj); 265 } 266 } 267 result.put("length", end - begin, DontEnum | DontDelete); 268 break; 269 } 270 case Sort: 271 { 272 #if 0 273 printf("KJS Array::Sort length=%d\n", length); 274 for ( unsigned int i = 0 ; i<length ; ++i ) 275 printf("KJS Array::Sort: %d: %s\n", i, thisObj.get(UString::from(i)).toString().value().ascii() ); 276 #endif 277 Object sortFunction; 278 bool useSortFunction = !args[0].isA(UndefinedType); 279 if (useSortFunction) 280 { 281 sortFunction = args[0].toObject(); 282 if (!sortFunction.implementsCall()) 283 useSortFunction = false; 284 } 285 286 if (length == 0) { 287 thisObj.put("length", Number(0), DontEnum | DontDelete); 288 result = Undefined(); 289 break; 290 } 291 292 // "Min" sort. Not the fastest, but definitely less code than heapsort 293 // or quicksort, and much less swapping than bubblesort/insertionsort. 294 for ( unsigned int i = 0 ; i<length-1 ; ++i ) 295 { 296 KJSO iObj = thisObj.get(UString::from(i)); 297 unsigned int themin = i; 298 KJSO minObj = iObj; 299 for ( unsigned int j = i+1 ; j<length ; ++j ) 300 { 301 KJSO jObj = thisObj.get(UString::from(j)); 302 int cmp; 303 if ( useSortFunction ) 304 { 305 List l; 306 l.append(jObj); 307 l.append(minObj); 308 cmp = sortFunction.executeCall( Global::current(), &l ).toInt32(); 309 } 310 else 311 cmp = ( jObj.toString().value() < minObj.toString().value() ) ? -1 : 1; 312 if ( cmp < 0 ) 313 { 314 themin = j; 315 minObj = jObj; 316 } 317 } 318 // Swap themin and i 319 if ( themin > i ) 320 { 321 //printf("KJS Array::Sort: swapping %d and %d\n", i, themin ); 322 thisObj.put( UString::from(i), minObj ); 323 thisObj.put( UString::from(themin), iObj ); 324 } 325 } 326 #if 0 327 printf("KJS Array::Sort -- Resulting array:\n"); 328 for ( unsigned int i = 0 ; i<length ; ++i ) 329 printf("KJS Array::Sort: %d: %s\n", i, thisObj.get(UString::from(i)).toString().value().ascii() ); 330 #endif 331 result = thisObj; 332 break; 333 } 334 // TODO Splice 335 // TODO Unshift 336 default: 337 result = Undefined(); 338 } 339 340 return Completion(ReturnValue, result); 341 } 516 bool ArrayObjectImp::implementsCall() const 517 { 518 return true; 519 } 520 521 // ECMA 15.6.1 522 Value ArrayObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 523 { 524 // equivalent to 'new Array(....)' 525 return construct(exec,args); 526 } 527
Note:
See TracChangeset
for help on using the changeset viewer.