• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kjs
 

kjs

  • kjs
array_object.cpp
1/*
2 * This file is part of the KDE libraries
3 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
4 * Copyright (C) 2003 Apple Computer, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22#include "value.h"
23#include "object.h"
24#include "types.h"
25#include "interpreter.h"
26#include "operations.h"
27#include "array_object.h"
28#include "internal.h"
29#include "error_object.h"
30
31#include "array_object.lut.h"
32
33#include <stdio.h>
34#include <string.h>
35#include <assert.h>
36
37#define MAX_INDEX 4294967294U // 2^32-2
38
39using namespace KJS;
40
41// ------------------------------ ArrayInstanceImp -----------------------------
42
43const unsigned sparseArrayCutoff = 10000;
44
45const ClassInfo ArrayInstanceImp::info = {"Array", 0, 0, 0};
46
47ArrayInstanceImp::ArrayInstanceImp(ObjectImp *proto, unsigned initialLength)
48 : ObjectImp(proto)
49 , length(initialLength)
50 , storageLength(initialLength < sparseArrayCutoff ? initialLength : 0)
51 , capacity(storageLength)
52 , storage(capacity ? (ValueImp **)calloc(capacity, sizeof(ValueImp *)) : 0)
53{
54}
55
56ArrayInstanceImp::ArrayInstanceImp(ObjectImp *proto, const List &list)
57 : ObjectImp(proto)
58 , length(list.size())
59 , storageLength(length)
60 , capacity(storageLength)
61 , storage(capacity ? (ValueImp **)malloc(sizeof(ValueImp *) * capacity) : 0)
62{
63 ListIterator it = list.begin();
64 unsigned l = length;
65 for (unsigned i = 0; i < l; ++i) {
66 storage[i] = (it++).imp();
67 }
68}
69
70ArrayInstanceImp::~ArrayInstanceImp()
71{
72 free(storage);
73}
74
75Value ArrayInstanceImp::get(ExecState *exec, const Identifier &propertyName) const
76{
77 if (propertyName == lengthPropertyName)
78 return Number(length);
79
80 bool ok;
81 unsigned index = propertyName.toArrayIndex(&ok);
82 if (ok) {
83 if (index >= length)
84 return Undefined();
85 if (index < storageLength) {
86 ValueImp *v = storage[index];
87 return v ? Value(v) : Undefined();
88 }
89 }
90
91 return ObjectImp::get(exec, propertyName);
92}
93
94Value ArrayInstanceImp::getPropertyByIndex(ExecState *exec,
95 unsigned index) const
96{
97 if (index > MAX_INDEX)
98 return ObjectImp::get(exec, Identifier::from(index));
99 if (index >= length)
100 return Undefined();
101 if (index < storageLength) {
102 ValueImp *v = storage[index];
103 return v ? Value(v) : Undefined();
104 }
105
106 return ObjectImp::get(exec, Identifier::from(index));
107}
108
109// Special implementation of [[Put]] - see ECMA 15.4.5.1
110void ArrayInstanceImp::put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr)
111{
112 if (propertyName == lengthPropertyName) {
113 unsigned int newLen = value.toUInt32(exec);
114 if (value.toNumber(exec) != double(newLen)) {
115 Object err = Error::create(exec, RangeError, "Invalid array length.");
116 exec->setException(err);
117 return;
118 }
119 setLength(newLen, exec);
120 return;
121 }
122
123 bool ok;
124 unsigned index = propertyName.toArrayIndex(&ok);
125 if (ok) {
126 putPropertyByIndex(exec, index, value, attr);
127 return;
128 }
129
130 ObjectImp::put(exec, propertyName, value, attr);
131}
132
133void ArrayInstanceImp::putPropertyByIndex(ExecState *exec, unsigned index,
134 const Value &value, int attr)
135{
136 if (index < sparseArrayCutoff && index >= storageLength) {
137 resizeStorage(index + 1);
138 }
139
140 if (index >= length && index <= MAX_INDEX) {
141 length = index + 1;
142 }
143
144 if (index < storageLength) {
145 storage[index] = value.imp();
146 return;
147 }
148
149 assert(index >= sparseArrayCutoff);
150 ObjectImp::put(exec, Identifier::from(index), value, attr);
151}
152
153bool ArrayInstanceImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
154{
155 if (propertyName == lengthPropertyName)
156 return true;
157
158 bool ok;
159 unsigned index = propertyName.toArrayIndex(&ok);
160 if (ok) {
161 if (index >= length)
162 return false;
163 if (index < storageLength) {
164 ValueImp *v = storage[index];
165 return v && v != UndefinedImp::staticUndefined;
166 }
167 }
168
169 return ObjectImp::hasProperty(exec, propertyName);
170}
171
172bool ArrayInstanceImp::hasPropertyByIndex(ExecState *exec, unsigned index) const
173{
174 if (index > MAX_INDEX)
175 return ObjectImp::hasProperty(exec, Identifier::from(index));
176 if (index >= length)
177 return false;
178 if (index < storageLength) {
179 ValueImp *v = storage[index];
180 return v && v != UndefinedImp::staticUndefined;
181 }
182
183 return ObjectImp::hasProperty(exec, Identifier::from(index));
184}
185
186bool ArrayInstanceImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
187{
188 if (propertyName == lengthPropertyName)
189 return false;
190
191 bool ok;
192 unsigned index = propertyName.toArrayIndex(&ok);
193 if (ok) {
194 if (index >= length)
195 return true;
196 if (index < storageLength) {
197 storage[index] = 0;
198 return true;
199 }
200 }
201
202 return ObjectImp::deleteProperty(exec, propertyName);
203}
204
205bool ArrayInstanceImp::deletePropertyByIndex(ExecState *exec, unsigned index)
206{
207 if (index > MAX_INDEX)
208 return ObjectImp::deleteProperty(exec, Identifier::from(index));
209 if (index >= length)
210 return true;
211 if (index < storageLength) {
212 storage[index] = 0;
213 return true;
214 }
215
216 return ObjectImp::deleteProperty(exec, Identifier::from(index));
217}
218
219ReferenceList ArrayInstanceImp::propList(ExecState *exec, bool recursive)
220{
221 ReferenceList properties = ObjectImp::propList(exec,recursive);
222
223 // avoid fetching this every time through the loop
224 ValueImp *undefined = UndefinedImp::staticUndefined;
225
226 for (unsigned i = 0; i < storageLength; ++i) {
227 ValueImp *imp = storage[i];
228 if (imp && imp != undefined && !ObjectImp::hasProperty(exec,Identifier::from(i))) {
229 properties.append(Reference(this, i));
230 }
231 }
232 return properties;
233}
234
235void ArrayInstanceImp::resizeStorage(unsigned newLength)
236{
237 if (newLength < storageLength) {
238 memset(storage + newLength, 0, sizeof(ValueImp *) * (storageLength - newLength));
239 }
240 if (newLength > capacity) {
241 unsigned newCapacity;
242 if (newLength > sparseArrayCutoff) {
243 newCapacity = newLength;
244 } else {
245 newCapacity = (newLength * 3 + 1) / 2;
246 if (newCapacity > sparseArrayCutoff) {
247 newCapacity = sparseArrayCutoff;
248 }
249 }
250 storage = (ValueImp **)realloc(storage, newCapacity * sizeof (ValueImp *));
251 memset(storage + capacity, 0, sizeof(ValueImp *) * (newCapacity - capacity));
252 capacity = newCapacity;
253 }
254 storageLength = newLength;
255}
256
257void ArrayInstanceImp::setLength(unsigned newLength, ExecState *exec)
258{
259 if (newLength <= storageLength) {
260 resizeStorage(newLength);
261 }
262
263 if (newLength < length) {
264 ReferenceList sparseProperties;
265
266 _prop.addSparseArrayPropertiesToReferenceList(sparseProperties, Object(this));
267
268 ReferenceListIterator it = sparseProperties.begin();
269 while (it != sparseProperties.end()) {
270 Reference ref = it++;
271 bool ok;
272 unsigned index = ref.getPropertyName(exec).toArrayIndex(&ok);
273 if (ok && index > newLength) {
274 ref.deleteValue(exec);
275 }
276 }
277 }
278
279 length = newLength;
280}
281
282void ArrayInstanceImp::mark()
283{
284 ObjectImp::mark();
285 unsigned l = storageLength;
286 for (unsigned i = 0; i < l; ++i) {
287 ValueImp *imp = storage[i];
288 if (imp && !imp->marked())
289 imp->mark();
290 }
291}
292
293static ExecState *execForCompareByStringForQSort;
294
295static int compareByStringForQSort(const void *a, const void *b)
296{
297 ExecState *exec = execForCompareByStringForQSort;
298 ValueImp *va = *(ValueImp **)a;
299 ValueImp *vb = *(ValueImp **)b;
300 if (va->dispatchType() == UndefinedType) {
301 return vb->dispatchType() == UndefinedType ? 0 : 1;
302 }
303 if (vb->dispatchType() == UndefinedType) {
304 return -1;
305 }
306 return compare(va->dispatchToString(exec), vb->dispatchToString(exec));
307}
308
309void ArrayInstanceImp::sort(ExecState *exec)
310{
311 int lengthNotIncludingUndefined = pushUndefinedObjectsToEnd(exec);
312
313 execForCompareByStringForQSort = exec;
314 qsort(storage, lengthNotIncludingUndefined, sizeof(ValueImp *), compareByStringForQSort);
315 execForCompareByStringForQSort = 0;
316}
317
318namespace KJS {
319
320struct CompareWithCompareFunctionArguments {
321 CompareWithCompareFunctionArguments(ExecState *e, ObjectImp *cf)
322 : exec(e)
323 , compareFunction(cf)
324 , globalObject(e->dynamicInterpreter()->globalObject())
325 {
326 arguments.append(Undefined());
327 arguments.append(Undefined());
328 }
329
330 ExecState *exec;
331 ObjectImp *compareFunction;
332 List arguments;
333 Object globalObject;
334};
335
336}
337
338static CompareWithCompareFunctionArguments *compareWithCompareFunctionArguments;
339
340static int compareWithCompareFunctionForQSort(const void *a, const void *b)
341{
342 CompareWithCompareFunctionArguments *args = compareWithCompareFunctionArguments;
343
344 ValueImp *va = *(ValueImp **)a;
345 ValueImp *vb = *(ValueImp **)b;
346 if (va->dispatchType() == UndefinedType) {
347 return vb->dispatchType() == UndefinedType ? 0 : 1;
348 }
349 if (vb->dispatchType() == UndefinedType) {
350 return -1;
351 }
352
353 args->arguments.clear();
354 args->arguments.append(va);
355 args->arguments.append(vb);
356 double compareResult = args->compareFunction->call
357 (args->exec, args->globalObject, args->arguments).toNumber(args->exec);
358 return compareResult < 0 ? -1 : compareResult > 0 ? 1 : 0;
359}
360
361void ArrayInstanceImp::sort(ExecState *exec, Object &compareFunction)
362{
363 int lengthNotIncludingUndefined = pushUndefinedObjectsToEnd(exec);
364
365 CompareWithCompareFunctionArguments args(exec, compareFunction.imp());
366 compareWithCompareFunctionArguments = &args;
367 qsort(storage, lengthNotIncludingUndefined, sizeof(ValueImp *), compareWithCompareFunctionForQSort);
368 compareWithCompareFunctionArguments = 0;
369}
370
371unsigned ArrayInstanceImp::pushUndefinedObjectsToEnd(ExecState *exec)
372{
373 ValueImp *undefined = UndefinedImp::staticUndefined;
374
375 unsigned o = 0;
376
377 for (unsigned i = 0; i != storageLength; ++i) {
378 ValueImp *v = storage[i];
379 if (v && v != undefined) {
380 if (o != i)
381 storage[o] = v;
382 o++;
383 }
384 }
385
386 ReferenceList sparseProperties;
387 _prop.addSparseArrayPropertiesToReferenceList(sparseProperties, Object(this));
388 unsigned newLength = o + sparseProperties.length();
389
390 if (newLength > storageLength) {
391 resizeStorage(newLength);
392 }
393
394 ReferenceListIterator it = sparseProperties.begin();
395 while (it != sparseProperties.end()) {
396 Reference ref = it++;
397 storage[o] = ref.getValue(exec).imp();
398 ObjectImp::deleteProperty(exec, ref.getPropertyName(exec));
399 o++;
400 }
401
402 if (newLength != storageLength)
403 memset(storage + o, 0, sizeof(ValueImp *) * (storageLength - o));
404
405 return o;
406}
407
408// ------------------------------ ArrayPrototypeImp ----------------------------
409
410const ClassInfo ArrayPrototypeImp::info = {"Array", &ArrayInstanceImp::info, &arrayTable, 0};
411
412/* Source for array_object.lut.h
413@begin arrayTable 17
414 toString ArrayProtoFuncImp::ToString DontEnum|Function 0
415 toLocaleString ArrayProtoFuncImp::ToLocaleString DontEnum|Function 0
416 concat ArrayProtoFuncImp::Concat DontEnum|Function 1
417 join ArrayProtoFuncImp::Join DontEnum|Function 1
418 pop ArrayProtoFuncImp::Pop DontEnum|Function 0
419 push ArrayProtoFuncImp::Push DontEnum|Function 1
420 reverse ArrayProtoFuncImp::Reverse DontEnum|Function 0
421 shift ArrayProtoFuncImp::Shift DontEnum|Function 0
422 slice ArrayProtoFuncImp::Slice DontEnum|Function 2
423 sort ArrayProtoFuncImp::Sort DontEnum|Function 1
424 splice ArrayProtoFuncImp::Splice DontEnum|Function 2
425 unshift ArrayProtoFuncImp::UnShift DontEnum|Function 1
426@end
427*/
428
429// ECMA 15.4.4
430ArrayPrototypeImp::ArrayPrototypeImp(ExecState */*exec*/,
431 ObjectPrototypeImp *objProto)
432 : ArrayInstanceImp(objProto, 0)
433{
434 Value protect(this);
435 setInternalValue(Null());
436}
437
438Value ArrayPrototypeImp::get(ExecState *exec, const Identifier &propertyName) const
439{
440 //fprintf( stderr, "[kjs-array_object] ArrayPrototypeImp::get(%s)\n", propertyName.ascii() );
441 return lookupGetFunction<ArrayProtoFuncImp, ArrayInstanceImp>( exec, propertyName, &arrayTable, this );
442}
443
444// ------------------------------ ArrayProtoFuncImp ----------------------------
445
446ArrayProtoFuncImp::ArrayProtoFuncImp(ExecState *exec, int i, int len)
447 : InternalFunctionImp(
448 static_cast<FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype().imp())
449 ), id(i)
450{
451 Value protect(this);
452 put(exec,lengthPropertyName,Number(len),DontDelete|ReadOnly|DontEnum);
453}
454
455bool ArrayProtoFuncImp::implementsCall() const
456{
457 return true;
458}
459
460// ECMA 15.4.4
461Value ArrayProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
462{
463 unsigned int length = thisObj.get(exec,lengthPropertyName).toUInt32(exec);
464
465 Value result;
466 switch (id) {
467 case ToLocaleString:
468 case ToString:
469
470 if (!thisObj.inherits(&ArrayInstanceImp::info)) {
471 Object err = Error::create(exec,TypeError);
472 exec->setException(err);
473 return err;
474 }
475
476 // fall through
477 case Join: {
478 UString separator = ",";
479 UString str = "";
480
481 if (id == Join && args.size() > 0 && !args[0].isA(UndefinedType))
482 separator = args[0].toString(exec);
483 for (unsigned int k = 0; k < length; k++) {
484 if (k >= 1)
485 str += separator;
486
487 Value element = thisObj.get(exec, k);
488 if (element.type() == UndefinedType || element.type() == NullType)
489 continue;
490
491 bool fallback = false;
492 if (id == ToLocaleString) {
493 Object o = element.toObject(exec);
494 Object conversionFunction =
495 Object::dynamicCast(o.get(exec, toLocaleStringPropertyName));
496 if (conversionFunction.isValid() &&
497 conversionFunction.implementsCall()) {
498 str += conversionFunction.call(exec, o, List()).toString(exec);
499 } else {
500 // try toString() fallback
501 fallback = true;
502 }
503 }
504 if (id == ToString || id == Join || fallback) {
505 if (element.type() == ObjectType) {
506 Object o = Object::dynamicCast(element);
507 Object conversionFunction =
508 Object::dynamicCast(o.get(exec, toStringPropertyName));
509 if (conversionFunction.isValid() &&
510 conversionFunction.implementsCall()) {
511 str += conversionFunction.call(exec, o, List()).toString(exec);
512 } else {
513 UString msg = "Can't convert " + o.className() +
514 " object to string";
515 Object error = Error::create(exec, RangeError,
516 msg.cstring().c_str());
517 exec->setException(error);
518 return error;
519 }
520 } else {
521 str += element.toString(exec);
522 }
523 }
524 if ( exec->hadException() )
525 break;
526 }
527 result = String(str);
528 break;
529 }
530 case Concat: {
531 Object arr = Object::dynamicCast(exec->lexicalInterpreter()->builtinArray().construct(exec,List::empty()));
532 int n = 0;
533 Value curArg = thisObj;
534 Object curObj = Object::dynamicCast(thisObj);
535 ListIterator it = args.begin();
536 for (;;) {
537 if (curArg.type() == ObjectType &&
538 curObj.inherits(&ArrayInstanceImp::info)) {
539 unsigned int k = 0;
540 // Older versions tried to optimize out getting the length of thisObj
541 // by checking for n != 0, but that doesn't work if thisObj is an empty array.
542 length = curObj.get(exec,lengthPropertyName).toUInt32(exec);
543 while (k < length) {
544 if (curObj.hasProperty(exec,k))
545 arr.put(exec, n, curObj.get(exec, k));
546 n++;
547 k++;
548 }
549 } else {
550 arr.put(exec, n, curArg);
551 n++;
552 }
553 if (it == args.end())
554 break;
555 curArg = *it;
556 curObj = Object::dynamicCast(it++); // may be 0
557 }
558 arr.put(exec,lengthPropertyName, Number(n), DontEnum | DontDelete);
559
560 result = arr;
561 break;
562 }
563 case Pop:{
564 if (length == 0) {
565 thisObj.put(exec, lengthPropertyName, Number(length), DontEnum | DontDelete);
566 result = Undefined();
567 } else {
568 result = thisObj.get(exec, length - 1);
569 thisObj.put(exec, lengthPropertyName, Number(length - 1), DontEnum | DontDelete);
570 }
571 break;
572 }
573 case Push: {
574 for (int n = 0; n < args.size(); n++)
575 thisObj.put(exec, length + n, args[n]);
576 length += args.size();
577 thisObj.put(exec,lengthPropertyName, Number(length), DontEnum | DontDelete);
578 result = Number(length);
579 break;
580 }
581 case Reverse: {
582
583 unsigned int middle = length / 2;
584
585 for (unsigned int k = 0; k < middle; k++) {
586 unsigned lk1 = length - k - 1;
587 Value obj = thisObj.get(exec,k);
588 Value obj2 = thisObj.get(exec,lk1);
589 if (thisObj.hasProperty(exec,lk1)) {
590 if (thisObj.hasProperty(exec,k)) {
591 thisObj.put(exec, k, obj2);
592 thisObj.put(exec, lk1, obj);
593 } else {
594 thisObj.put(exec, k, obj2);
595 thisObj.deleteProperty(exec, lk1);
596 }
597 } else {
598 if (thisObj.hasProperty(exec, k)) {
599 thisObj.deleteProperty(exec, k);
600 thisObj.put(exec, lk1, obj);
601 } else {
602 // why delete something that's not there ? Strange.
603 thisObj.deleteProperty(exec, k);
604 thisObj.deleteProperty(exec, lk1);
605 }
606 }
607 }
608 result = thisObj;
609 break;
610 }
611 case Shift: {
612 if (length == 0) {
613 thisObj.put(exec, lengthPropertyName, Number(length), DontEnum | DontDelete);
614 result = Undefined();
615 } else {
616 result = thisObj.get(exec, 0);
617 for(unsigned int k = 1; k < length; k++) {
618 if (thisObj.hasProperty(exec, k)) {
619 Value obj = thisObj.get(exec, k);
620 thisObj.put(exec, k-1, obj);
621 } else
622 thisObj.deleteProperty(exec, k-1);
623 }
624 thisObj.deleteProperty(exec, length - 1);
625 thisObj.put(exec, lengthPropertyName, Number(length - 1), DontEnum | DontDelete);
626 }
627 break;
628 }
629 case Slice: {
630 // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
631
632 // We return a new array
633 Object resObj = Object::dynamicCast(exec->lexicalInterpreter()->builtinArray().construct(exec,List::empty()));
634 result = resObj;
635 int begin = 0;
636 if (args[0].type() != UndefinedType) {
637 begin = args[0].toInteger(exec);
638 if ( begin < 0 )
639 begin = maxInt( begin + length, 0 );
640 else
641 begin = minInt( begin, length );
642 }
643 int end = length;
644 if (args[1].type() != UndefinedType)
645 {
646 end = args[1].toInteger(exec);
647 if ( end < 0 )
648 end = maxInt( end + length, 0 );
649 else
650 end = minInt( end, length );
651 }
652
653 //printf( "Slicing from %d to %d \n", begin, end );
654 int n = 0;
655 for(int k = begin; k < end; k++, n++) {
656 if (thisObj.hasProperty(exec, k)) {
657 Value obj = thisObj.get(exec, k);
658 resObj.put(exec, n, obj);
659 }
660 }
661 resObj.put(exec, lengthPropertyName, Number(n), DontEnum | DontDelete);
662 break;
663 }
664 case Sort:{
665#if 0
666 printf("KJS Array::Sort length=%d\n", length);
667 for ( unsigned int i = 0 ; i<length ; ++i )
668 printf("KJS Array::Sort: %d: %s\n", i, thisObj.get(exec, i).toString(exec).ascii() );
669#endif
670 Object sortFunction;
671 bool useSortFunction = (args[0].type() != UndefinedType);
672 if (useSortFunction)
673 {
674 sortFunction = args[0].toObject(exec);
675 if (!sortFunction.implementsCall())
676 useSortFunction = false;
677 }
678
679 if (thisObj.imp()->classInfo() == &ArrayInstanceImp::info) {
680 if (useSortFunction)
681 ((ArrayInstanceImp *)thisObj.imp())->sort(exec, sortFunction);
682 else
683 ((ArrayInstanceImp *)thisObj.imp())->sort(exec);
684 result = thisObj;
685 break;
686 }
687
688 if (length == 0) {
689 thisObj.put(exec, lengthPropertyName, Number(0), DontEnum | DontDelete);
690 result = thisObj;
691 break;
692 }
693
694 // "Min" sort. Not the fastest, but definitely less code than heapsort
695 // or quicksort, and much less swapping than bubblesort/insertionsort.
696 for ( unsigned int i = 0 ; i<length-1 ; ++i )
697 {
698 Value iObj = thisObj.get(exec,i);
699 unsigned int themin = i;
700 Value minObj = iObj;
701 for ( unsigned int j = i+1 ; j<length ; ++j )
702 {
703 Value jObj = thisObj.get(exec,j);
704 double cmp;
705 if (jObj.type() == UndefinedType) {
706 cmp = 1; // don't check minObj because there's no need to differentiate == (0) from > (1)
707 } else if (minObj.type() == UndefinedType) {
708 cmp = -1;
709 } else if (useSortFunction) {
710 List l;
711 l.append(jObj);
712 l.append(minObj);
713 cmp = sortFunction.call(exec, exec->dynamicInterpreter()->globalObject(), l).toNumber(exec);
714 } else {
715 cmp = (jObj.toString(exec) < minObj.toString(exec)) ? -1 : 1;
716 }
717 if ( cmp < 0 )
718 {
719 themin = j;
720 minObj = jObj;
721 }
722 }
723 // Swap themin and i
724 if ( themin > i )
725 {
726 //printf("KJS Array::Sort: swapping %d and %d\n", i, themin );
727 thisObj.put( exec, i, minObj );
728 thisObj.put( exec, themin, iObj );
729 }
730 }
731#if 0
732 printf("KJS Array::Sort -- Resulting array:\n");
733 for ( unsigned int i = 0 ; i<length ; ++i )
734 printf("KJS Array::Sort: %d: %s\n", i, thisObj.get(exec, i).toString(exec).ascii() );
735#endif
736 result = thisObj;
737 break;
738 }
739 case Splice: {
740 // 15.4.4.12 - oh boy this is huge
741 Object resObj = Object::dynamicCast(exec->lexicalInterpreter()->builtinArray().construct(exec,List::empty()));
742 result = resObj;
743 int begin = args[0].toUInt32(exec);
744 if ( begin < 0 )
745 begin = maxInt( begin + length, 0 );
746 else
747 begin = minInt( begin, length );
748 unsigned int deleteCount = minInt( maxInt( args[1].toUInt32(exec), 0 ), length - begin );
749
750 //printf( "Splicing from %d, deleteCount=%d \n", begin, deleteCount );
751 for(unsigned int k = 0; k < deleteCount; k++) {
752 if (thisObj.hasProperty(exec,k+begin)) {
753 Value obj = thisObj.get(exec, k+begin);
754 resObj.put(exec, k, obj);
755 }
756 }
757 resObj.put(exec, lengthPropertyName, Number(deleteCount), DontEnum | DontDelete);
758
759 unsigned int additionalArgs = maxInt( args.size() - 2, 0 );
760 if ( additionalArgs != deleteCount )
761 {
762 if ( additionalArgs < deleteCount )
763 {
764 for ( unsigned int k = begin; k < length - deleteCount; ++k )
765 {
766 if (thisObj.hasProperty(exec,k+deleteCount)) {
767 Value obj = thisObj.get(exec, k+deleteCount);
768 thisObj.put(exec, k+additionalArgs, obj);
769 }
770 else
771 thisObj.deleteProperty(exec, k+additionalArgs);
772 }
773 for ( unsigned int k = length ; k > length - deleteCount + additionalArgs; --k )
774 thisObj.deleteProperty(exec, k-1);
775 }
776 else
777 {
778 for ( unsigned int k = length - deleteCount; (int)k > begin; --k )
779 {
780 if (thisObj.hasProperty(exec,k+deleteCount-1)) {
781 Value obj = thisObj.get(exec, k+deleteCount-1);
782 thisObj.put(exec, k+additionalArgs-1, obj);
783 }
784 else
785 thisObj.deleteProperty(exec, k+additionalArgs-1);
786 }
787 }
788 }
789 for ( unsigned int k = 0; k < additionalArgs; ++k )
790 {
791 thisObj.put(exec, k+begin, args[k+2]);
792 }
793 thisObj.put(exec, lengthPropertyName, Number(length - deleteCount + additionalArgs), DontEnum | DontDelete);
794 break;
795 }
796 case UnShift: { // 15.4.4.13
797 unsigned int nrArgs = args.size();
798 for ( unsigned int k = length; k > 0; --k )
799 {
800 if (thisObj.hasProperty(exec,k-1)) {
801 Value obj = thisObj.get(exec, k-1);
802 thisObj.put(exec, k+nrArgs-1, obj);
803 } else {
804 thisObj.deleteProperty(exec, k+nrArgs-1);
805 }
806 }
807 for ( unsigned int k = 0; k < nrArgs; ++k )
808 thisObj.put(exec, k, args[k]);
809 result = Number(length + nrArgs);
810 thisObj.put(exec, lengthPropertyName, result, DontEnum | DontDelete);
811 break;
812 }
813 default:
814 assert(0);
815 break;
816 }
817 return result;
818}
819
820// ------------------------------ ArrayObjectImp -------------------------------
821
822ArrayObjectImp::ArrayObjectImp(ExecState *exec,
823 FunctionPrototypeImp *funcProto,
824 ArrayPrototypeImp *arrayProto)
825 : InternalFunctionImp(funcProto)
826{
827 Value protect(this);
828 // ECMA 15.4.3.1 Array.prototype
829 put(exec,prototypePropertyName, Object(arrayProto), DontEnum|DontDelete|ReadOnly);
830
831 // no. of arguments for constructor
832 put(exec,lengthPropertyName, Number(1), ReadOnly|DontDelete|DontEnum);
833}
834
835bool ArrayObjectImp::implementsConstruct() const
836{
837 return true;
838}
839
840// ECMA 15.4.2
841Object ArrayObjectImp::construct(ExecState *exec, const List &args)
842{
843 // a single numeric argument denotes the array size (!)
844 if (args.size() == 1 && args[0].type() == NumberType) {
845 unsigned int n = args[0].toUInt32(exec);
846 if (n != args[0].toNumber(exec)) {
847 Object error = Error::create(exec, RangeError, "Invalid array length.");
848 exec->setException(error);
849 return error;
850 }
851 return Object(new ArrayInstanceImp(exec->lexicalInterpreter()->builtinArrayPrototype().imp(), n));
852 }
853
854 // otherwise the array is constructed with the arguments in it
855 return Object(new ArrayInstanceImp(exec->lexicalInterpreter()->builtinArrayPrototype().imp(), args));
856}
857
858bool ArrayObjectImp::implementsCall() const
859{
860 return true;
861}
862
863// ECMA 15.6.1
864Value ArrayObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
865{
866 // equivalent to 'new Array(....)'
867 return construct(exec,args);
868}
KJS::ExecState
Represents the current state of script execution.
Definition: interpreter.h:438
KJS::ExecState::dynamicInterpreter
Interpreter * dynamicInterpreter() const
Returns the interpreter associated with this execution state.
Definition: interpreter.h:452
KJS::ExecState::lexicalInterpreter
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope's global object.
Definition: interpreter.cpp:394
KJS::FunctionPrototypeImp
The initial value of Function.prototype (and thus all objects created with the Function constructor)
Definition: function_object.h:34
KJS::Identifier
Represents an Identifier for a Javascript object.
Definition: identifier.h:32
KJS::InternalFunctionImp
Base class for all function objects.
Definition: function.h:40
KJS::Interpreter::builtinArrayPrototype
Object builtinArrayPrototype() const
Returns the builtin "Array.prototype" object.
Definition: interpreter.cpp:228
KJS::Interpreter::builtinArray
Object builtinArray() const
Returns the builtin "Array" object.
Definition: interpreter.cpp:183
KJS::Interpreter::globalObject
Object & globalObject() const
Returns the object that is used as the global object during all script execution performed by this in...
Definition: interpreter.cpp:128
KJS::ListIterator
Iterator for KJS::List objects.
Definition: list.h:138
KJS::List
Native list type.
Definition: list.h:48
KJS::List::append
void append(const Value &val)
Append an object to the end of the list.
Definition: list.h:66
KJS::List::begin
ListIterator begin() const
Definition: list.h:186
KJS::List::size
int size() const
Definition: list.h:90
KJS::List::end
ListIterator end() const
Definition: list.h:187
KJS::Null
Represents an primitive Null value.
Definition: value.h:294
KJS::Number
Represents an primitive Number value.
Definition: value.h:367
KJS::Object
Represents an Object.
Definition: object.h:81
KJS::Object::deleteProperty
bool deleteProperty(ExecState *exec, const Identifier &propertyName)
Removes the specified property from the object.
Definition: object.h:684
KJS::Object::implementsCall
bool implementsCall() const
Whether or not the object implements the call() method.
Definition: object.h:699
KJS::Object::construct
Object construct(ExecState *exec, const List &args)
Creates a new object based on this object.
Definition: object.h:696
KJS::Object::put
void put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr=None)
Sets the specified property.
Definition: object.h:669
KJS::Object::call
Value call(ExecState *exec, Object &thisObj, const List &args)
Calls this object as if it is a function.
Definition: object.cpp:53
KJS::Object::hasProperty
bool hasProperty(ExecState *exec, const Identifier &propertyName) const
Checks to see whether the object (or any object in it's prototype chain) has a property with the spec...
Definition: object.h:678
KJS::Object::get
Value get(ExecState *exec, const Identifier &propertyName) const
Retrieves the specified property from the object.
Definition: object.h:663
KJS::Object::className
UString className() const
Returns the class name of the object.
Definition: object.h:660
KJS::ReferenceListIterator
An iterator for a ReferenceList.
Definition: reference_list.h:36
KJS::ReferenceList
A list of Reference objects.
Definition: reference_list.h:53
KJS::Reference
Defines a Javascript reference.
Definition: reference.h:34
KJS::Reference::getPropertyName
Identifier getPropertyName(ExecState *exec) const
Performs the GetPropertyName type conversion operation on this value (ECMA 8.7)
Definition: reference.cpp:103
KJS::Reference::getValue
Value getValue(ExecState *exec) const
Performs the GetValue type conversion operation on this value (ECMA 8.7.1)
Definition: reference.cpp:117
KJS::String
Represents an primitive String value.
Definition: value.h:340
KJS::UString
Unicode string class.
Definition: ustring.h:189
KJS::UString::ascii
char * ascii() const
Convert the Unicode string to plain ASCII chars chopping of any higher bytes.
Definition: ustring.cpp:485
KJS::UString::cstring
CString cstring() const
Definition: ustring.cpp:480
KJS::Undefined
Represents an primitive Undefined value.
Definition: value.h:269
KJS::ValueImp
ValueImp is the base type for all primitives (Undefined, Null, Boolean, String, Number) and objects i...
Definition: value.h:78
KJS::Value
Value objects are act as wrappers ("smart pointers") around ValueImp objects and their descendents.
Definition: value.h:167
KJS::Value::toString
UString toString(ExecState *exec) const
Performs the ToString type conversion operation on this value (ECMA 9.8)
Definition: value.h:246
KJS::Value::toObject
Object toObject(ExecState *exec) const
Performs the ToObject type conversion operation on this value (ECMA 9.9)
Definition: object.h:358
KJS::Value::toUInt32
unsigned int toUInt32(ExecState *exec) const
Performs the ToUInt32 type conversion operation on this value (ECMA 9.6)
Definition: value.h:236
KJS::Value::isValid
bool isValid() const
Returns whether or not this is a valid value.
Definition: value.h:181
KJS::Value::type
Type type() const
Returns the type of value.
Definition: value.h:195
KJS::Value::toNumber
double toNumber(ExecState *exec) const
Performs the ToNumber type conversion operation on this value (ECMA 9.3)
Definition: value.h:221
TDEStdAccel::end
const TDEShortcut & end()
KJS::ClassInfo
Class Information.
Definition: object.h:58

kjs

Skip menu "kjs"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kjs

Skip menu "kjs"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kjs by doxygen 1.9.4
This website is maintained by Timothy Pearson.