Ignore:
Timestamp:
Mar 21, 2002, 4:31:57 PM (23 years ago)
Author:
mjs
Message:

Merged changes from LABYRINTH_KDE_3_MERGE branch.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/array_object.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
     
    1617 *  License along with this library; if not, write to the Free Software
    1718 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     19 *
    1820 */
    1921
    20 #include "kjs.h"
     22#include "value.h"
     23#include "object.h"
     24#include "types.h"
     25#include "interpreter.h"
    2126#include "operations.h"
    22 #include "types.h"
    2327#include "array_object.h"
     28#include "internal.h"
     29#include "error_object.h"
     30
     31#include "array_object.lut.h"
     32
    2433#include <stdio.h>
     34#include <assert.h>
    2535
    2636using namespace KJS;
    2737
    28 ArrayObject::ArrayObject(const Object &funcProto,
    29                          const Object &arrayProto)
    30     : ConstructorImp(funcProto, 1)
    31 {
     38// ------------------------------ ArrayInstanceImp -----------------------------
     39
     40const ClassInfo ArrayInstanceImp::info = {"Array", 0, 0, 0};
     41
     42ArrayInstanceImp::ArrayInstanceImp(const Object &proto)
     43  : ObjectImp(proto)
     44{
     45}
     46
     47// Special implementation of [[Put]] - see ECMA 15.4.5.1
     48void 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
     86void ArrayInstanceImp::putDirect(ExecState *exec, const UString &propertyName, const Value &value, int attr)
     87{
     88  ObjectImp::put(exec,propertyName,value,attr);
     89}
     90// ------------------------------ ArrayPrototypeImp ----------------------------
     91
     92const 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
     112ArrayPrototypeImp::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
     123Value 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
     131ArrayProtoFuncImp::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
     140bool ArrayProtoFuncImp::implementsCall() const
     141{
     142  return true;
     143}
     144
     145// ECMA 15.4.4
     146Value 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
     474ArrayObjectImp::ArrayObjectImp(ExecState *exec,
     475                               FunctionPrototypeImp *funcProto,
     476                               ArrayPrototypeImp *arrayProto)
     477  : InternalFunctionImp(funcProto)
     478{
     479  Value protect(this);
    32480  // 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
     487bool ArrayObjectImp::implementsConstruct() const
     488{
     489  return true;
     490}
     491
     492// ECMA 15.4.2
     493Object ArrayObjectImp::construct(ExecState *exec, const List &args)
     494{
     495  Object result(new ArrayInstanceImp(exec->interpreter()->builtinArrayPrototype()));
    49496
    50497  unsigned int len;
    51498  ListIterator it = args.begin();
    52499  // 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);
    55502  else {
    56503    // initialize array
    57504    len = args.size();
    58505    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);
    60507  }
    61508
    62509  // 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);
    64512
    65513  return result;
    66514}
    67515
    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 }
     516bool ArrayObjectImp::implementsCall() const
     517{
     518  return true;
     519}
     520
     521// ECMA 15.6.1
     522Value 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.