]>
git.saurik.com Git - apple/javascriptcore.git/blob - kjs/array_object.cpp
48b085538cc18fb5018dc6ed6076ab318ec956b3
2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
4 * Copyright (C) 2003 Peter Kelly (pmk@post.com)
5 * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
25 #include "array_object.h"
26 #include "array_object.lut.h"
28 #include "error_object.h"
30 #include "operations.h"
32 #include <wtf/Assertions.h>
33 #include <wtf/HashSet.h>
35 #include <algorithm> // for std::min
39 // ------------------------------ ArrayPrototype ----------------------------
41 const ClassInfo
ArrayPrototype::info
= {"Array", &ArrayInstance::info
, &arrayTable
};
43 /* Source for array_object.lut.h
45 toString arrayProtoFuncToString DontEnum|Function 0
46 toLocaleString arrayProtoFuncToLocaleString DontEnum|Function 0
47 concat arrayProtoFuncConcat DontEnum|Function 1
48 join arrayProtoFuncJoin DontEnum|Function 1
49 pop arrayProtoFuncPop DontEnum|Function 0
50 push arrayProtoFuncPush DontEnum|Function 1
51 reverse arrayProtoFuncReverse DontEnum|Function 0
52 shift arrayProtoFuncShift DontEnum|Function 0
53 slice arrayProtoFuncSlice DontEnum|Function 2
54 sort arrayProtoFuncSort DontEnum|Function 1
55 splice arrayProtoFuncSplice DontEnum|Function 2
56 unshift arrayProtoFuncUnShift DontEnum|Function 1
57 every arrayProtoFuncEvery DontEnum|Function 1
58 forEach arrayProtoFuncForEach DontEnum|Function 1
59 some arrayProtoFuncSome DontEnum|Function 1
60 indexOf arrayProtoFuncIndexOf DontEnum|Function 1
61 lastIndexOf arrayProtoFuncLastIndexOf DontEnum|Function 1
62 filter arrayProtoFuncFilter DontEnum|Function 1
63 map arrayProtoFuncMap DontEnum|Function 1
68 ArrayPrototype::ArrayPrototype(ExecState
*, ObjectPrototype
* objProto
)
69 : ArrayInstance(objProto
, 0)
73 bool ArrayPrototype::getOwnPropertySlot(ExecState
* exec
, const Identifier
& propertyName
, PropertySlot
& slot
)
75 return getStaticFunctionSlot
<ArrayInstance
>(exec
, &arrayTable
, this, propertyName
, slot
);
79 // ------------------------------ Array Functions ----------------------------
82 static JSValue
* getProperty(ExecState
* exec
, JSObject
* obj
, unsigned index
)
85 if (!obj
->getPropertySlot(exec
, index
, slot
))
87 return slot
.getValue(exec
, obj
, index
);
90 JSValue
* arrayProtoFuncToString(ExecState
* exec
, JSObject
* thisObj
, const List
&)
92 if (!thisObj
->inherits(&ArrayInstance::info
))
93 return throwError(exec
, TypeError
);
95 static HashSet
<JSObject
*> visitedElems
;
96 static const UString
* empty
= new UString("");
97 static const UString
* comma
= new UString(",");
98 bool alreadyVisited
= !visitedElems
.add(thisObj
).second
;
100 return jsString(*empty
);
101 UString separator
= *comma
;
102 UString str
= *empty
;
104 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
105 for (unsigned k
= 0; k
< length
; k
++) {
109 JSObject
* error
= Error::create(exec
, GeneralError
, "Out of memory");
110 exec
->setException(error
);
114 JSValue
* element
= thisObj
->get(exec
, k
);
115 if (element
->isUndefinedOrNull())
118 str
+= element
->toString(exec
);
121 JSObject
* error
= Error::create(exec
, GeneralError
, "Out of memory");
122 exec
->setException(error
);
125 if (exec
->hadException())
128 visitedElems
.remove(thisObj
);
129 return jsString(str
);
132 JSValue
* arrayProtoFuncToLocaleString(ExecState
* exec
, JSObject
* thisObj
, const List
&)
134 if (!thisObj
->inherits(&ArrayInstance::info
))
135 return throwError(exec
, TypeError
);
137 static HashSet
<JSObject
*> visitedElems
;
138 static const UString
* empty
= new UString("");
139 static const UString
* comma
= new UString(",");
140 bool alreadyVisited
= !visitedElems
.add(thisObj
).second
;
142 return jsString(*empty
);
143 UString separator
= *comma
;
144 UString str
= *empty
;
146 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
147 for (unsigned k
= 0; k
< length
; k
++) {
151 JSObject
* error
= Error::create(exec
, GeneralError
, "Out of memory");
152 exec
->setException(error
);
156 JSValue
* element
= thisObj
->get(exec
, k
);
157 if (element
->isUndefinedOrNull())
160 JSObject
* o
= element
->toObject(exec
);
161 JSValue
* conversionFunction
= o
->get(exec
, exec
->propertyNames().toLocaleString
);
162 if (conversionFunction
->isObject() && static_cast<JSObject
*>(conversionFunction
)->implementsCall())
163 str
+= static_cast<JSObject
*>(conversionFunction
)->call(exec
, o
, exec
->emptyList())->toString(exec
);
165 str
+= element
->toString(exec
);
168 JSObject
* error
= Error::create(exec
, GeneralError
, "Out of memory");
169 exec
->setException(error
);
172 if (exec
->hadException())
175 visitedElems
.remove(thisObj
);
176 return jsString(str
);
179 JSValue
* arrayProtoFuncJoin(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
181 static HashSet
<JSObject
*> visitedElems
;
182 static const UString
* empty
= new UString("");
183 static const UString
* comma
= new UString(",");
184 bool alreadyVisited
= !visitedElems
.add(thisObj
).second
;
186 return jsString(*empty
);
187 UString separator
= *comma
;
188 UString str
= *empty
;
190 if (!args
[0]->isUndefined())
191 separator
= args
[0]->toString(exec
);
193 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
194 for (unsigned k
= 0; k
< length
; k
++) {
198 JSObject
* error
= Error::create(exec
, GeneralError
, "Out of memory");
199 exec
->setException(error
);
203 JSValue
* element
= thisObj
->get(exec
, k
);
204 if (element
->isUndefinedOrNull())
207 str
+= element
->toString(exec
);
210 JSObject
* error
= Error::create(exec
, GeneralError
, "Out of memory");
211 exec
->setException(error
);
214 if (exec
->hadException())
217 visitedElems
.remove(thisObj
);
218 return jsString(str
);
221 JSValue
* arrayProtoFuncConcat(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
223 JSObject
* arr
= static_cast<JSObject
*>(exec
->lexicalGlobalObject()->arrayConstructor()->construct(exec
, exec
->emptyList()));
225 JSValue
* curArg
= thisObj
;
226 JSObject
* curObj
= static_cast<JSObject
* >(thisObj
);
227 List::const_iterator it
= args
.begin();
228 List::const_iterator end
= args
.end();
230 if (curArg
->isObject() && curObj
->inherits(&ArrayInstance::info
)) {
232 // Older versions tried to optimize out getting the length of thisObj
233 // by checking for n != 0, but that doesn't work if thisObj is an empty array.
234 unsigned length
= curObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
236 if (JSValue
* v
= getProperty(exec
, curObj
, k
))
237 arr
->put(exec
, n
, v
);
242 arr
->put(exec
, n
, curArg
);
248 curObj
= static_cast<JSObject
*>(curArg
); // may be 0
251 arr
->put(exec
, exec
->propertyNames().length
, jsNumber(n
));
255 JSValue
* arrayProtoFuncPop(ExecState
* exec
, JSObject
* thisObj
, const List
&)
258 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
260 thisObj
->put(exec
, exec
->propertyNames().length
, jsNumber(length
));
261 result
= jsUndefined();
263 result
= thisObj
->get(exec
, length
- 1);
264 thisObj
->deleteProperty(exec
, length
- 1);
265 thisObj
->put(exec
, exec
->propertyNames().length
, jsNumber(length
- 1));
270 JSValue
* arrayProtoFuncPush(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
272 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
273 for (unsigned n
= 0; n
< args
.size(); n
++)
274 thisObj
->put(exec
, length
+ n
, args
[n
]);
275 length
+= args
.size();
276 thisObj
->put(exec
, exec
->propertyNames().length
, jsNumber(length
));
277 return jsNumber(length
);
280 JSValue
* arrayProtoFuncReverse(ExecState
* exec
, JSObject
* thisObj
, const List
&)
282 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
283 unsigned middle
= length
/ 2;
285 for (unsigned k
= 0; k
< middle
; k
++) {
286 unsigned lk1
= length
- k
- 1;
287 JSValue
* obj2
= getProperty(exec
, thisObj
, lk1
);
288 JSValue
* obj
= getProperty(exec
, thisObj
, k
);
291 thisObj
->put(exec
, k
, obj2
);
293 thisObj
->deleteProperty(exec
, k
);
296 thisObj
->put(exec
, lk1
, obj
);
298 thisObj
->deleteProperty(exec
, lk1
);
303 JSValue
* arrayProtoFuncShift(ExecState
* exec
, JSObject
* thisObj
, const List
&)
307 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
309 thisObj
->put(exec
, exec
->propertyNames().length
, jsNumber(length
));
310 result
= jsUndefined();
312 result
= thisObj
->get(exec
, 0);
313 for (unsigned k
= 1; k
< length
; k
++) {
314 if (JSValue
* obj
= getProperty(exec
, thisObj
, k
))
315 thisObj
->put(exec
, k
- 1, obj
);
317 thisObj
->deleteProperty(exec
, k
- 1);
319 thisObj
->deleteProperty(exec
, length
- 1);
320 thisObj
->put(exec
, exec
->propertyNames().length
, jsNumber(length
- 1));
325 JSValue
* arrayProtoFuncSlice(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
327 // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
329 // We return a new array
330 JSObject
* resObj
= static_cast<JSObject
* >(exec
->lexicalGlobalObject()->arrayConstructor()->construct(exec
, exec
->emptyList()));
331 JSValue
* result
= resObj
;
332 double begin
= args
[0]->toInteger(exec
);
333 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
343 if (args
[1]->isUndefined())
346 end
= args
[1]->toInteger(exec
);
358 int b
= static_cast<int>(begin
);
359 int e
= static_cast<int>(end
);
360 for (int k
= b
; k
< e
; k
++, n
++) {
361 if (JSValue
* v
= getProperty(exec
, thisObj
, k
))
362 resObj
->put(exec
, n
, v
);
364 resObj
->put(exec
, exec
->propertyNames().length
, jsNumber(n
));
368 JSValue
* arrayProtoFuncSort(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
370 JSObject
* sortFunction
= 0;
371 if (!args
[0]->isUndefined()) {
372 sortFunction
= args
[0]->toObject(exec
);
373 if (!sortFunction
->implementsCall())
377 if (thisObj
->classInfo() == &ArrayInstance::info
) {
379 static_cast<ArrayInstance
*>(thisObj
)->sort(exec
, sortFunction
);
381 static_cast<ArrayInstance
*>(thisObj
)->sort(exec
);
385 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
390 // "Min" sort. Not the fastest, but definitely less code than heapsort
391 // or quicksort, and much less swapping than bubblesort/insertionsort.
392 for (unsigned i
= 0; i
< length
- 1; ++i
) {
393 JSValue
* iObj
= thisObj
->get(exec
, i
);
395 JSValue
* minObj
= iObj
;
396 for (unsigned j
= i
+ 1; j
< length
; ++j
) {
397 JSValue
* jObj
= thisObj
->get(exec
, j
);
398 double compareResult
;
399 if (jObj
->isUndefined())
400 compareResult
= 1; // don't check minObj because there's no need to differentiate == (0) from > (1)
401 else if (minObj
->isUndefined())
403 else if (sortFunction
) {
407 compareResult
= sortFunction
->call(exec
, exec
->dynamicGlobalObject(), l
)->toNumber(exec
);
409 compareResult
= (jObj
->toString(exec
) < minObj
->toString(exec
)) ? -1 : 1;
411 if (compareResult
< 0) {
418 thisObj
->put(exec
, i
, minObj
);
419 thisObj
->put(exec
, themin
, iObj
);
425 JSValue
* arrayProtoFuncSplice(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
428 JSObject
* resObj
= static_cast<JSObject
* >(exec
->lexicalGlobalObject()->arrayConstructor()->construct(exec
, exec
->emptyList()));
429 JSValue
* result
= resObj
;
430 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
432 return jsUndefined();
433 int begin
= args
[0]->toUInt32(exec
);
435 begin
= std::max
<int>(begin
+ length
, 0);
437 begin
= std::min
<int>(begin
, length
);
439 unsigned deleteCount
;
441 deleteCount
= std::min
<int>(std::max
<int>(args
[1]->toUInt32(exec
), 0), length
- begin
);
443 deleteCount
= length
- begin
;
445 for (unsigned k
= 0; k
< deleteCount
; k
++) {
446 if (JSValue
* v
= getProperty(exec
, thisObj
, k
+ begin
))
447 resObj
->put(exec
, k
, v
);
449 resObj
->put(exec
, exec
->propertyNames().length
, jsNumber(deleteCount
));
451 unsigned additionalArgs
= std::max
<int>(args
.size() - 2, 0);
452 if (additionalArgs
!= deleteCount
) {
453 if (additionalArgs
< deleteCount
) {
454 for (unsigned k
= begin
; k
< length
- deleteCount
; ++k
) {
455 if (JSValue
* v
= getProperty(exec
, thisObj
, k
+ deleteCount
))
456 thisObj
->put(exec
, k
+ additionalArgs
, v
);
458 thisObj
->deleteProperty(exec
, k
+ additionalArgs
);
460 for (unsigned k
= length
; k
> length
- deleteCount
+ additionalArgs
; --k
)
461 thisObj
->deleteProperty(exec
, k
- 1);
463 for (unsigned k
= length
- deleteCount
; (int)k
> begin
; --k
) {
464 if (JSValue
* obj
= getProperty(exec
, thisObj
, k
+ deleteCount
- 1))
465 thisObj
->put(exec
, k
+ additionalArgs
- 1, obj
);
467 thisObj
->deleteProperty(exec
, k
+ additionalArgs
- 1);
471 for (unsigned k
= 0; k
< additionalArgs
; ++k
)
472 thisObj
->put(exec
, k
+ begin
, args
[k
+ 2]);
474 thisObj
->put(exec
, exec
->propertyNames().length
, jsNumber(length
- deleteCount
+ additionalArgs
));
478 JSValue
* arrayProtoFuncUnShift(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
481 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
482 unsigned nrArgs
= args
.size();
484 for (unsigned k
= length
; k
> 0; --k
) {
485 if (JSValue
* v
= getProperty(exec
, thisObj
, k
- 1))
486 thisObj
->put(exec
, k
+ nrArgs
- 1, v
);
488 thisObj
->deleteProperty(exec
, k
+ nrArgs
- 1);
491 for (unsigned k
= 0; k
< nrArgs
; ++k
)
492 thisObj
->put(exec
, k
, args
[k
]);
493 JSValue
* result
= jsNumber(length
+ nrArgs
);
494 thisObj
->put(exec
, exec
->propertyNames().length
, result
);
498 JSValue
* arrayProtoFuncFilter(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
500 JSObject
* eachFunction
= args
[0]->toObject(exec
);
502 if (!eachFunction
->implementsCall())
503 return throwError(exec
, TypeError
);
505 JSObject
* applyThis
= args
[1]->isUndefinedOrNull() ? exec
->dynamicGlobalObject() : args
[1]->toObject(exec
);
506 JSObject
* resultArray
= static_cast<JSObject
*>(exec
->lexicalGlobalObject()->arrayConstructor()->construct(exec
, exec
->emptyList()));
508 unsigned filterIndex
= 0;
509 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
510 for (unsigned k
= 0; k
< length
&& !exec
->hadException(); ++k
) {
513 if (!thisObj
->getPropertySlot(exec
, k
, slot
))
516 JSValue
* v
= slot
.getValue(exec
, thisObj
, k
);
520 eachArguments
.append(v
);
521 eachArguments
.append(jsNumber(k
));
522 eachArguments
.append(thisObj
);
524 JSValue
* result
= eachFunction
->call(exec
, applyThis
, eachArguments
);
526 if (result
->toBoolean(exec
))
527 resultArray
->put(exec
, filterIndex
++, v
);
532 JSValue
* arrayProtoFuncMap(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
534 JSObject
* eachFunction
= args
[0]->toObject(exec
);
535 if (!eachFunction
->implementsCall())
536 return throwError(exec
, TypeError
);
538 JSObject
* applyThis
= args
[1]->isUndefinedOrNull() ? exec
->dynamicGlobalObject() : args
[1]->toObject(exec
);
540 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
543 mapArgs
.append(jsNumber(length
));
544 JSObject
* resultArray
= static_cast<JSObject
*>(exec
->lexicalGlobalObject()->arrayConstructor()->construct(exec
, mapArgs
));
546 for (unsigned k
= 0; k
< length
&& !exec
->hadException(); ++k
) {
548 if (!thisObj
->getPropertySlot(exec
, k
, slot
))
551 JSValue
* v
= slot
.getValue(exec
, thisObj
, k
);
555 eachArguments
.append(v
);
556 eachArguments
.append(jsNumber(k
));
557 eachArguments
.append(thisObj
);
559 JSValue
* result
= eachFunction
->call(exec
, applyThis
, eachArguments
);
560 resultArray
->put(exec
, k
, result
);
566 // Documentation for these three is available at:
567 // http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every
568 // http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach
569 // http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some
571 JSValue
* arrayProtoFuncEvery(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
573 JSObject
* eachFunction
= args
[0]->toObject(exec
);
575 if (!eachFunction
->implementsCall())
576 return throwError(exec
, TypeError
);
578 JSObject
* applyThis
= args
[1]->isUndefinedOrNull() ? exec
->dynamicGlobalObject() : args
[1]->toObject(exec
);
580 JSValue
* result
= jsBoolean(true);
582 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
583 for (unsigned k
= 0; k
< length
&& !exec
->hadException(); ++k
) {
586 if (!thisObj
->getPropertySlot(exec
, k
, slot
))
591 eachArguments
.append(slot
.getValue(exec
, thisObj
, k
));
592 eachArguments
.append(jsNumber(k
));
593 eachArguments
.append(thisObj
);
595 bool predicateResult
= eachFunction
->call(exec
, applyThis
, eachArguments
)->toBoolean(exec
);
597 if (!predicateResult
) {
598 result
= jsBoolean(false);
606 JSValue
* arrayProtoFuncForEach(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
608 JSObject
* eachFunction
= args
[0]->toObject(exec
);
610 if (!eachFunction
->implementsCall())
611 return throwError(exec
, TypeError
);
613 JSObject
* applyThis
= args
[1]->isUndefinedOrNull() ? exec
->dynamicGlobalObject() : args
[1]->toObject(exec
);
615 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
616 for (unsigned k
= 0; k
< length
&& !exec
->hadException(); ++k
) {
618 if (!thisObj
->getPropertySlot(exec
, k
, slot
))
622 eachArguments
.append(slot
.getValue(exec
, thisObj
, k
));
623 eachArguments
.append(jsNumber(k
));
624 eachArguments
.append(thisObj
);
626 eachFunction
->call(exec
, applyThis
, eachArguments
);
628 return jsUndefined();
631 JSValue
* arrayProtoFuncSome(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
633 JSObject
* eachFunction
= args
[0]->toObject(exec
);
635 if (!eachFunction
->implementsCall())
636 return throwError(exec
, TypeError
);
638 JSObject
* applyThis
= args
[1]->isUndefinedOrNull() ? exec
->dynamicGlobalObject() : args
[1]->toObject(exec
);
640 JSValue
* result
= jsBoolean(false);
642 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
643 for (unsigned k
= 0; k
< length
&& !exec
->hadException(); ++k
) {
645 if (!thisObj
->getPropertySlot(exec
, k
, slot
))
649 eachArguments
.append(slot
.getValue(exec
, thisObj
, k
));
650 eachArguments
.append(jsNumber(k
));
651 eachArguments
.append(thisObj
);
653 bool predicateResult
= eachFunction
->call(exec
, applyThis
, eachArguments
)->toBoolean(exec
);
655 if (predicateResult
) {
656 result
= jsBoolean(true);
663 JSValue
* arrayProtoFuncIndexOf(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
665 // JavaScript 1.5 Extension by Mozilla
666 // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf
669 double d
= args
[1]->toInteger(exec
);
670 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
677 index
= static_cast<unsigned>(d
);
680 JSValue
* searchElement
= args
[0];
681 for (; index
< length
; ++index
) {
682 JSValue
* e
= getProperty(exec
, thisObj
, index
);
685 if (strictEqual(exec
, searchElement
, e
))
686 return jsNumber(index
);
692 JSValue
* arrayProtoFuncLastIndexOf(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
694 // JavaScript 1.6 Extension by Mozilla
695 // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf
697 unsigned length
= thisObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
698 int index
= length
- 1;
699 double d
= args
[1]->toIntegerPreserveNaN(exec
);
707 index
= static_cast<int>(d
);
709 JSValue
* searchElement
= args
[0];
710 for (; index
>= 0; --index
) {
711 JSValue
* e
= getProperty(exec
, thisObj
, index
);
714 if (strictEqual(exec
, searchElement
, e
))
715 return jsNumber(index
);
721 // ------------------------------ ArrayObjectImp -------------------------------
723 ArrayObjectImp::ArrayObjectImp(ExecState
* exec
, FunctionPrototype
* funcProto
, ArrayPrototype
* arrayProto
)
724 : InternalFunctionImp(funcProto
, arrayProto
->classInfo()->className
)
726 // ECMA 15.4.3.1 Array.prototype
727 putDirect(exec
->propertyNames().prototype
, arrayProto
, DontEnum
|DontDelete
|ReadOnly
);
729 // no. of arguments for constructor
730 putDirect(exec
->propertyNames().length
, jsNumber(1), ReadOnly
|DontDelete
|DontEnum
);
733 bool ArrayObjectImp::implementsConstruct() const
739 JSObject
* ArrayObjectImp::construct(ExecState
* exec
, const List
& args
)
741 // a single numeric argument denotes the array size (!)
742 if (args
.size() == 1 && args
[0]->isNumber()) {
743 uint32_t n
= args
[0]->toUInt32(exec
);
744 if (n
!= args
[0]->toNumber(exec
))
745 return throwError(exec
, RangeError
, "Array size is not a small enough positive integer.");
746 return new ArrayInstance(exec
->lexicalGlobalObject()->arrayPrototype(), n
);
749 // otherwise the array is constructed with the arguments in it
750 return new ArrayInstance(exec
->lexicalGlobalObject()->arrayPrototype(), args
);
754 JSValue
* ArrayObjectImp::callAsFunction(ExecState
* exec
, JSObject
*, const List
& args
)
756 // equivalent to 'new Array(....)'
757 return construct(exec
,args
);