Changeset 798 in webkit for trunk/JavaScriptCore


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

Merged changes from LABYRINTH_KDE_3_MERGE branch.

Location:
trunk/JavaScriptCore/kjs
Files:
8 added
3 deleted
49 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/Makefile.am

    r550 r798  
    44libkjs_o_LDFLAGS = -Wl,-r -nostdlib
    55libkjs_o_AR = $(OBJCXXLD) $(AM_OBJCXXFLAGS) $(OBJCXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) $(libkjs_o_LDFLAGS) -o
     6
     7INCLUDES = $(KWQ_INCLUDES)
    68
    79libkjs_o_SOURCES = \
     
    2224        function_object.cpp \
    2325        function_object.h \
    24         global_object.cpp \
    2526        grammar.cpp \
    2627        grammar.h \
    2728        internal.cpp \
    2829        internal.h \
    29         kjs.cpp \
    30         kjs.h \
     30        interpreter.cpp \
     31        interpreter.h \
    3132        lexer.cpp \
    3233        lexer.h \
     
    4748        operations.cpp \
    4849        operations.h \
     50        property_map.cpp \
     51        property_map.h \
    4952        regexp.cpp \
    5053        regexp.h \
     
    5760        ustring.cpp \
    5861        ustring.h \
     62        value.cpp \
     63        value.h \
    5964        $(NULL)
    6065
     
    7681        touch ./grammar-stamp
    7782
    78 BUILT_SOURCES = $(GRAMMAR_FILES) grammar-stamp
     83LUT_FILES = math_object.lut.h lexer.lut.h array_object.lut.h date_object.lut.h string_object.lut.h number_object.lut.h
     84
     85lexer.lut.h: keywords.table
     86        ./create_hash_table keywords.table -i > lexer.lut.h;
     87
     88array_object.lut.h: array_object.cpp
     89        ./create_hash_table array_object.cpp -i > array_object.lut.h
     90
     91math_object.lut.h: math_object.cpp
     92        ./create_hash_table math_object.cpp -i > math_object.lut.h
     93
     94date_object.lut.h: date_object.cpp
     95        ./create_hash_table date_object.cpp -i > date_object.lut.h
     96
     97number_object.lut.h: number_object.cpp
     98        ./create_hash_table number_object.cpp -i > number_object.lut.h
     99
     100string_object.lut.h: string_object.cpp
     101        ./create_hash_table string_object.cpp -i > string_object.lut.h
     102
     103
     104
     105BUILT_SOURCES = $(GRAMMAR_FILES) $(LUT_FILES) grammar-stamp
    79106
    80107CLEANFILES = $(BUILT_SOURCES)
  • 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
  • trunk/JavaScriptCore/kjs/array_object.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2124#define _ARRAY_OBJECT_H_
    2225
    23 #include "object.h"
    24 #include "function.h"
     26#include "internal.h"
     27#include "function_object.h"
    2528
    2629namespace KJS {
    2730
    28   class ArrayObject : public ConstructorImp {
     31  class ArrayInstanceImp : public ObjectImp {
    2932  public:
    30     ArrayObject(const Object &funcProto, const Object &arrayProto);
    31     Completion execute(const List &);
    32     Object construct(const List &);
     33    ArrayInstanceImp(const Object &proto);
     34
     35    virtual void put(ExecState *exec, const UString &propertyName, const Value &value, int attr = None);
     36    virtual void putDirect(ExecState *exec, const UString &propertyName, const Value &value, int attr = None);
     37
     38    virtual const ClassInfo *classInfo() const { return &info; }
     39    static const ClassInfo info;
    3340  };
    3441
    35   class ArrayPrototype : public ObjectImp {
     42 class ArrayPrototypeImp : public ArrayInstanceImp {
    3643  public:
    37     ArrayPrototype(const Object& proto);
    38     virtual KJSO get(const UString &p) const;
     44    ArrayPrototypeImp(ExecState *exec,
     45                      ObjectPrototypeImp *objProto);
     46    Value get(ExecState *exec, const UString &p) const;
     47    virtual const ClassInfo *classInfo() const { return &info; }
     48    static const ClassInfo info;
    3949  };
    4050
    41   class ArrayProtoFunc : public InternalFunctionImp {
     51  class ArrayProtoFuncImp : public InternalFunctionImp {
    4252  public:
    43     ArrayProtoFunc(int i) : id(i) { }
    44     Completion execute(const List &);
     53    ArrayProtoFuncImp(ExecState *exec, int i, int len);
     54
     55    virtual bool implementsCall() const;
     56    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     57
    4558    enum { ToString, ToLocaleString, Concat, Join, Pop, Push,
    4659           Reverse, Shift, Slice, Sort, Splice, UnShift };
     
    4962  };
    5063
     64  class ArrayObjectImp : public InternalFunctionImp {
     65  public:
     66    ArrayObjectImp(ExecState *exec,
     67                   FunctionPrototypeImp *funcProto,
     68                   ArrayPrototypeImp *arrayProto);
     69
     70    virtual bool implementsConstruct() const;
     71    virtual Object construct(ExecState *exec, const List &args);
     72    virtual bool implementsCall() const;
     73    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     74
     75  };
     76
    5177}; // namespace
    5278
  • trunk/JavaScriptCore/kjs/bool_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 "bool_object.h"
    2428#include "error_object.h"
    2529
     30#include <assert.h>
     31
    2632using namespace KJS;
    2733
    28 BooleanObject::BooleanObject(const KJSO& funcProto, const KJSO &booleanProto)
    29   : ConstructorImp(funcProto, 1)
     34// ------------------------------ BooleanInstanceImp ---------------------------
     35
     36const ClassInfo BooleanInstanceImp::info = {"Boolean", 0, 0, 0};
     37
     38BooleanInstanceImp::BooleanInstanceImp(const Object &proto)
     39  : ObjectImp(proto)
    3040{
    31   // Boolean.prototype
    32   setPrototypeProperty(booleanProto);
     41}
     42
     43// ------------------------------ BooleanPrototypeImp --------------------------
     44
     45// ECMA 15.6.4
     46
     47BooleanPrototypeImp::BooleanPrototypeImp(ExecState *exec,
     48                                         ObjectPrototypeImp *objectProto,
     49                                         FunctionPrototypeImp *funcProto)
     50  : BooleanInstanceImp(Object(objectProto))
     51{
     52  Value protect(this);
     53  // The constructor will be added later by InterpreterImp::InterpreterImp()
     54
     55  put(exec,"toString", Object(new BooleanProtoFuncImp(exec,funcProto,BooleanProtoFuncImp::ToString,0)), DontEnum);
     56  put(exec,"valueOf",  Object(new BooleanProtoFuncImp(exec,funcProto,BooleanProtoFuncImp::ValueOf,0)),  DontEnum);
     57  setInternalValue(Boolean(false));
     58}
     59
     60
     61// ------------------------------ BooleanProtoFuncImp --------------------------
     62
     63BooleanProtoFuncImp::BooleanProtoFuncImp(ExecState *exec,
     64                                         FunctionPrototypeImp *funcProto, int i, int len)
     65  : InternalFunctionImp(funcProto), id(i)
     66{
     67  Value protect(this);
     68  put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
     69}
     70
     71
     72bool BooleanProtoFuncImp::implementsCall() const
     73{
     74  return true;
     75}
     76
     77
     78// ECMA 15.6.4.2 + 15.6.4.3
     79Value BooleanProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &/*args*/)
     80{
     81  // no generic function. "this" has to be a Boolean object
     82  if (!thisObj.inherits(&BooleanInstanceImp::info)) {
     83    Object err = Error::create(exec,TypeError);
     84    exec->setException(err);
     85    return err;
     86  }
     87
     88  // execute "toString()" or "valueOf()", respectively
     89
     90  Value v = thisObj.internalValue();
     91  assert(!v.isNull());
     92
     93  if (id == ToString)
     94    return String(v.toString(exec));
     95  else
     96    return Boolean(v.toBoolean(exec)); /* TODO: optimize for bool case */
     97}
     98
     99// ------------------------------ BooleanObjectImp -----------------------------
     100
     101
     102BooleanObjectImp::BooleanObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto,
     103                                   BooleanPrototypeImp *booleanProto)
     104  : InternalFunctionImp(funcProto)
     105{
     106  Value protect(this);
     107  put(exec,"prototype", Object(booleanProto),DontEnum|DontDelete|ReadOnly);
     108
     109  // no. of arguments for constructor
     110  put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum);
     111}
     112
     113
     114bool BooleanObjectImp::implementsConstruct() const
     115{
     116  return true;
     117}
     118
     119// ECMA 15.6.2
     120Object BooleanObjectImp::construct(ExecState *exec, const List &args)
     121{
     122  Object proto = exec->interpreter()->builtinBooleanPrototype();
     123  Object obj(new BooleanInstanceImp(proto));
     124
     125  Boolean b;
     126  if (args.size() > 0)
     127    b = args.begin()->toBoolean(exec);
     128  else
     129    b = Boolean(false);
     130
     131  obj.setInternalValue(b);
     132
     133  return obj;
     134}
     135
     136bool BooleanObjectImp::implementsCall() const
     137{
     138  return true;
    33139}
    34140
    35141// ECMA 15.6.1
    36 Completion BooleanObject::execute(const List &args)
     142Value BooleanObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
    37143{
    38   Boolean b;
    39 
    40144  if (args.isEmpty())
    41     b = Boolean(false);
     145    return Boolean(false);
    42146  else
    43     b = args[0].toBoolean();
    44 
    45   return Completion(ReturnValue, b);
     147    return Boolean(args[0].toBoolean(exec)); /* TODO: optimize for bool case */
    46148}
    47149
    48 // ECMA 15.6.2
    49 Object BooleanObject::construct(const List &args)
    50 {
    51   Boolean b;
    52   if (args.size() > 0)
    53     b = args.begin()->toBoolean();
    54   else
    55     b = Boolean(false);
    56 
    57   return Object::create(BooleanClass, b);
    58 }
    59 
    60 // ECMA 15.6.4
    61 BooleanPrototype::BooleanPrototype(const Object& proto)
    62   : ObjectImp(BooleanClass, Boolean(false), proto)
    63 {
    64   // The constructor will be added later in BooleanObject's constructor
    65 }
    66 
    67 KJSO BooleanPrototype::get(const UString &p) const
    68 {
    69   if (p == "toString")
    70     return Function(new BooleanProtoFunc(ToString));
    71   else if (p == "valueOf")
    72     return Function(new BooleanProtoFunc(ValueOf));
    73   else
    74     return Imp::get(p);
    75 }
    76 
    77 BooleanProtoFunc::BooleanProtoFunc(int i)
    78   : id(i)
    79 {
    80 }
    81 
    82 // ECMA 15.6.4.2 + 15.6.4.3
    83 Completion BooleanProtoFunc::execute(const List &)
    84 {
    85   KJSO result;
    86 
    87   Object thisObj = Object::dynamicCast(thisValue());
    88 
    89   // no generic function. "this" has to be a Boolean object
    90   if (thisObj.isNull() || thisObj.getClass() != BooleanClass) {
    91     result = Error::create(TypeError);
    92     return Completion(ReturnValue, result);
    93   }
    94 
    95   // execute "toString()" or "valueOf()", respectively
    96   KJSO v = thisObj.internalValue();
    97   if (id == BooleanPrototype::ToString)
    98     result = v.toString();
    99   else
    100     result = v.toBoolean();
    101 
    102   return Completion(ReturnValue, result);
    103 }
  • trunk/JavaScriptCore/kjs/bool_object.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2124#define _BOOL_OBJECT_H_
    2225
    23 #include "object.h"
    24 #include "function.h"
     26#include "internal.h"
     27#include "function_object.h"
    2528
    2629namespace KJS {
    2730
    28   class BooleanObject : public ConstructorImp {
     31  class BooleanInstanceImp : public ObjectImp {
    2932  public:
    30     BooleanObject(const KJSO& funcProto, const KJSO &booleanProto);
    31     Completion execute(const List &);
    32     Object construct(const List &);
     33    BooleanInstanceImp(const Object &proto);
     34
     35    virtual const ClassInfo *classInfo() const { return &info; }
     36    static const ClassInfo info;
    3337  };
    3438
    35   class BooleanPrototype : public ObjectImp {
     39  /**
     40   * @internal
     41   *
     42   * The initial value of Boolean.prototype (and thus all objects created
     43   * with the Boolean constructor
     44   */
     45  class BooleanPrototypeImp : public BooleanInstanceImp {
    3646  public:
    37     BooleanPrototype(const Object& proto);
    38     virtual KJSO get(const UString &p) const;
    39     enum { ToString, ValueOf };
     47    BooleanPrototypeImp(ExecState *exec,
     48                        ObjectPrototypeImp *objectProto,
     49                        FunctionPrototypeImp *funcProto);
    4050  };
    4151
    42   class BooleanProtoFunc : public InternalFunctionImp {
     52  /**
     53   * @internal
     54   *
     55   * Class to implement all methods that are properties of the
     56   * Boolean.prototype object
     57   */
     58  class BooleanProtoFuncImp : public InternalFunctionImp {
    4359  public:
    44     BooleanProtoFunc(int i);
    45     Completion execute(const List &);
     60    BooleanProtoFuncImp(ExecState *exec,
     61                        FunctionPrototypeImp *funcProto, int i, int len);
     62
     63    virtual bool implementsCall() const;
     64    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     65
     66    enum { ToString, ValueOf };
    4667  private:
    4768    int id;
     69  };
     70
     71  /**
     72   * @internal
     73   *
     74   * The initial value of the the global variable's "Boolean" property
     75   */
     76  class BooleanObjectImp : public InternalFunctionImp {
     77    friend class BooleanProtoFuncImp;
     78  public:
     79    BooleanObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto,
     80                     BooleanPrototypeImp *booleanProto);
     81
     82    virtual bool implementsConstruct() const;
     83    virtual Object construct(ExecState *exec, const List &args);
     84
     85    virtual bool implementsCall() const;
     86    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
    4887  };
    4988
  • trunk/JavaScriptCore/kjs/collector.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    34 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1618 *  License along with this library; if not, write to the Free Software
    1719 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     20 *
     21 *  $Id$
    1822 */
    1923
    2024#include "collector.h"
    21 #include "object.h"
    2225#include "internal.h"
    2326
     
    2528#include <string.h>
    2629#include <assert.h>
     30#ifdef KJS_DEBUG_MEM
     31#include <typeinfo>
     32#endif
    2733
    2834namespace KJS {
     
    6268unsigned long Collector::filled = 0;
    6369unsigned long Collector::softLimit = KJS_MEM_INCREMENT;
     70
     71unsigned long Collector::timesFilled = 0;
     72unsigned long Collector::increaseLimitAt = 1;
     73
     74bool Collector::memLimitReached = false;
     75
    6476#ifdef KJS_DEBUG_MEM
    6577bool Collector::collecting = false;
     
    7183    return 0L;
    7284
     85  // Try and deal with memory requirements in a scalable way. Simple scripts
     86  // should only require small amounts of memory, but for complex scripts we don't
     87  // want to end up running the garbage collector hundreds of times a second.
    7388  if (filled >= softLimit) {
     89    timesFilled++;
    7490    collect();
    75     if (filled >= softLimit && softLimit < KJS_MEM_LIMIT) // we are actually using all this memory
     91
     92    if (filled >= softLimit && softLimit < KJS_MEM_LIMIT) {
     93      // Even after collection we are still using more than the limit, so increase
     94      // the limit
    7695      softLimit *= 2;
     96    }
     97    else if (timesFilled == increaseLimitAt && increaseLimitAt < 128) {
     98      // The allowed memory limit keeps getting reached (lots of objects created
     99      // and deleted). Increase it a bit so GC gets run less often.
     100      timesFilled = 0;
     101      softLimit *= 2;
     102      increaseLimitAt *= 2;
     103    }
    77104  }
    78105
    79106  void *m = malloc(s);
    80 
    81   // hack to ensure obj is protected from GC before any constructors are run
    82   // (prev = marked, next = gcallowed)
    83   static_cast<Imp*>(m)->prev = 0;
    84   static_cast<Imp*>(m)->next = 0;
     107#ifdef KJS_DEBUG_MEM
     108  //fprintf( stderr, "allocate: size=%d valueimp=%p\n",s,m);
     109#endif
     110
     111  // VI_CREATED and VI_GCALLOWED being unset ensure that value
     112  // is protected from GC before any constructors are run
     113  static_cast<ValueImp*>(m)->_flags = 0;
    85114
    86115  if (!root) {
     
    99128  if (block->filled >= block->size) {
    100129#ifdef KJS_DEBUG_MEM
    101     printf("allocating new block of size %d\n", block->size);
     130    //fprintf( stderr, "allocating new block of size %d\n", block->size);
    102131#endif
    103132    CollectorBlock *tmp = new CollectorBlock(BlockSize);
     
    116145
    117146  if (softLimit >= KJS_MEM_LIMIT) {
    118       KJScriptImp::setException("Out of memory");
     147    memLimitReached = true;
     148    fprintf(stderr,"Out of memory");
    119149  }
    120150
     
    125155 * Mark-sweep garbage collection.
    126156 */
    127 void Collector::collect()
    128 {
    129 #ifdef KJS_DEBUG_MEM
    130   printf("collecting %d objects total\n", Imp::count);
    131   collecting = true;
    132 #endif
    133 
    134   // MARK: first set all ref counts to 0 ....
     157bool Collector::collect()
     158{
     159#ifdef KJS_DEBUG_MEM
     160  fprintf(stderr,"Collector::collect()\n");
     161#endif
     162  bool deleted = false;
     163  // MARK: first unmark everything
    135164  CollectorBlock *block = root;
    136165  while (block) {
    137 #ifdef KJS_DEBUG_MEM
    138     printf("cleaning block filled %d out of %d\n", block->filled, block->size);
    139 #endif
    140     Imp **r = (Imp**)block->mem;
     166    ValueImp **r = (ValueImp**)block->mem;
    141167    assert(r);
    142168    for (int i = 0; i < block->size; i++, r++)
    143169      if (*r) {
    144         (*r)->setMarked(false);
    145       }
    146     block = block->next;
    147   }
    148 
    149   // ... increase counter for all referenced objects recursively
     170        (*r)->_flags &= ~ValueImp::VI_MARKED;
     171      }
     172    block = block->next;
     173  }
     174
     175  // mark all referenced objects recursively
    150176  // starting out from the set of root objects
    151   if (KJScriptImp::hook) {
    152     KJScriptImp *scr = KJScriptImp::hook;
     177  if (InterpreterImp::s_hook) {
     178    InterpreterImp *scr = InterpreterImp::s_hook;
    153179    do {
     180      //fprintf( stderr, "Collector marking interpreter %p\n",(void*)scr);
    154181      scr->mark();
    155182      scr = scr->next;
    156     } while (scr != KJScriptImp::hook);
     183    } while (scr != InterpreterImp::s_hook);
    157184  }
    158185
     
    160187  block = root;
    161188  while (block) {
    162     Imp **r = (Imp**)block->mem;
     189    ValueImp **r = (ValueImp**)block->mem;
    163190    assert(r);
    164191    for (int i = 0; i < block->size; i++, r++)
    165       if (*r && (*r)->created() && ((*r)->refcount || !(*r)->gcAllowed()) && !(*r)->marked())
    166         (*r)->mark();
     192    {
     193      ValueImp *imp = (*r);
     194      // Check for created=true, marked=false and (gcallowed=false or refcount>0)
     195      if (imp &&
     196          (imp->_flags & (ValueImp::VI_CREATED|ValueImp::VI_MARKED)) == ValueImp::VI_CREATED &&
     197          ( (imp->_flags & ValueImp::VI_GCALLOWED) == 0 || imp->refcount ) ) {
     198        //fprintf( stderr, "Collector marking imp=%p\n",(void*)imp);
     199        imp->mark();
     200      }
     201    }
    167202    block = block->next;
    168203  }
     
    171206  block = root;
    172207  while (block) {
    173     Imp **r = (Imp**)block->mem;
     208    ValueImp **r = (ValueImp**)block->mem;
    174209    int del = 0;
    175210    for (int i = 0; i < block->size; i++, r++) {
    176       if (*r && ((*r)->refcount == 0) && !(*r)->marked() && (*r)->gcAllowed()) {
    177         // emulate destructing part of 'operator delete()'
    178         (*r)->~Imp();
    179         free(*r);
    180         *r = 0L;
    181         del++;
     211      ValueImp *imp = (*r);
     212      // Can delete if refcount==0, created==true, gcAllowed==true, and marked==false
     213      // Make sure to update the test if you add more bits to _flags.
     214      if (imp &&
     215          !imp->refcount && imp->_flags == (ValueImp::VI_GCALLOWED | ValueImp::VI_CREATED)) {
     216        // emulate destructing part of 'operator delete()'
     217        //fprintf( stderr, "Collector::deleting ValueImp %p (%s)\n", (void*)imp, typeid(*imp).name());
     218        imp->~ValueImp();
     219        free(imp);
     220        *r = 0L;
     221        del++;
    182222      }
    183223    }
     
    185225    block->filled -= del;
    186226    block = block->next;
    187   }
    188 
    189   // delete the emtpy containers
     227    if (del)
     228      deleted = true;
     229  }
     230
     231  // delete the empty containers
    190232  block = root;
    191233  while (block) {
     
    193235    if (block->filled == 0) {
    194236      if (block->prev)
    195         block->prev->next = next;
     237        block->prev->next = next;
    196238      if (block == root)
    197         root = next;
     239        root = next;
    198240      if (next)
    199         next->prev = block->prev;
     241        next->prev = block->prev;
    200242      if (block == currentBlock) // we don't want a dangling pointer
    201         currentBlock = 0L;
     243        currentBlock = 0L;
    202244      assert(block != root);
    203245      delete block;
     
    205247    block = next;
    206248  }
    207 
    208 #ifdef KJS_DEBUG_MEM
    209   collecting = false;
    210 #endif
    211 }
     249#if 0
     250  // This is useful to track down memory leaks
     251  static int s_count = 0;
     252  fprintf(stderr, "Collector done (was run %d)\n",s_count);
     253  if (s_count++ % 50 == 2)
     254    finalCheck();
     255#endif
     256  return deleted;
     257}
     258
     259#ifdef KJS_DEBUG_MEM
     260void Collector::finalCheck()
     261{
     262  CollectorBlock *block = root;
     263  while (block) {
     264    ValueImp **r = (ValueImp**)block->mem;
     265    for (int i = 0; i < block->size; i++, r++) {
     266      if (*r ) {
     267        fprintf( stderr, "Collector::finalCheck() still having ValueImp %p (%s)  [marked:%d gcAllowed:%d created:%d refcount:%d]\n",
     268                 (void*)(*r), typeid( **r ).name(),
     269                 (bool)((*r)->_flags & ValueImp::VI_MARKED),
     270                 (bool)((*r)->_flags & ValueImp::VI_GCALLOWED),
     271                 (bool)((*r)->_flags & ValueImp::VI_CREATED),
     272                 (*r)->refcount);
     273      }
     274    }
     275    block = block->next;
     276  }
     277}
     278#endif
  • trunk/JavaScriptCore/kjs/collector.h

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    34 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1618 *  License along with this library; if not, write to the Free Software
    1719 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     20 *
     21 *  $Id$
    1822 */
    1923
     
    4044#include <stdlib.h>
    4145
     46// for DEBUG_*
     47#include "value.h"
     48#include "object.h"
     49#include "types.h"
     50#include "interpreter.h"
     51
    4252namespace KJS {
    4353
    44   class Imp;
    4554  class CollectorBlock;
    4655
     
    6675     * Run the garbage collection. This involves calling the delete operator
    6776     * on each object and freeing the used memory.
    68      * In the current implemenation this will basically free all registered
    69      * object regardless whether they are still references by others or not.
    70      *
    7177     */
    72     static void collect();
     78    static bool collect();
    7379    static int size() { return filled; }
     80    static bool outOfMemory() { return memLimitReached; }
    7481
    7582#ifdef KJS_DEBUG_MEM
     83    /** Check that nothing is left when the last interpreter gets deleted */
     84    static void finalCheck();
    7685    /**
    7786     * @internal
     
    8493    static unsigned long filled;
    8594    static unsigned long softLimit;
     95    static unsigned long timesFilled;
     96    static unsigned long increaseLimitAt;
     97    static bool memLimitReached;
    8698    enum { BlockSize = 100 };
    8799  };
  • trunk/JavaScriptCore/kjs/date_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 *
     20 *  $Id$
    1821 */
    1922
     
    4649#include <string.h>
    4750#include <stdio.h>
     51#include <stdlib.h>
    4852#include <locale.h>
    49 
    50 #include "kjs.h"
     53#include <ctype.h>
     54
    5155#include "date_object.h"
    52 
    53 namespace KJS {
    54 
    55   class DateObjectFunc : public InternalFunctionImp {
    56   public:
    57     DateObjectFunc(int i) : id(i) { };
    58     Completion execute(const List &);
    59     enum { Parse, UTC };
    60   private:
    61     int id;
    62   };
    63 
    64   class DateProtoFunc : public InternalFunctionImp {
    65   public:
    66     DateProtoFunc(int i, bool u);
    67     Completion execute(const List &);
    68     enum { ToString, ToDateString, ToTimeString, ToLocaleString,
    69            ToLocaleDateString, ToLocaleTimeString, ValueOf, GetTime,
    70            GetFullYear, GetMonth, GetDate, GetDay, GetHours, GetMinutes,
    71            GetSeconds, GetMilliSeconds, GetTimezoneOffset, SetTime,
    72            SetMilliSeconds, SetSeconds, SetMinutes, SetHours, SetDate,
    73            SetMonth, SetFullYear, ToUTCString,
    74            // non-normative properties (Appendix B)
    75            GetYear, SetYear, ToGMTString };
    76   private:
    77     int id;
    78     bool utc;
    79   };
    80 
    81   // helper functions
    82   KJSO parseDate(const String &s);
    83   KJSO timeClip(const KJSO &t);
    84 };
     56#include "error_object.h"
     57#include "operations.h"
     58
     59#include "date_object.lut.h"
    8560
    8661using namespace KJS;
    8762
    88 KJSO KJS::parseDate(const String &s)
     63// ------------------------------ DateInstanceImp ------------------------------
     64
     65const ClassInfo DateInstanceImp::info = {"Date", 0, 0, 0};
     66
     67DateInstanceImp::DateInstanceImp(const Object &proto)
     68  : ObjectImp(proto)
     69{
     70}
     71
     72// ------------------------------ DatePrototypeImp -----------------------------
     73
     74const ClassInfo DatePrototypeImp::info = {"Date", 0, &dateTable, 0};
     75
     76/* Source for date_object.lut.h
     77   We use a negative ID to denote the "UTC" variant.
     78@begin dateTable 61
     79  toString              DateProtoFuncImp::ToString              DontEnum|Function       0
     80  toUTCString           -DateProtoFuncImp::ToString             DontEnum|Function       0
     81  toDateString          DateProtoFuncImp::ToDateString          DontEnum|Function       0
     82  toTimeString          DateProtoFuncImp::ToTimeString          DontEnum|Function       0
     83  toLocaleString        DateProtoFuncImp::ToLocaleString        DontEnum|Function       0
     84  toLocaleDateString    DateProtoFuncImp::ToLocaleDateString    DontEnum|Function       0
     85  toLocaleTimeString    DateProtoFuncImp::ToLocaleTimeString    DontEnum|Function       0
     86  valueOf               DateProtoFuncImp::ValueOf               DontEnum|Function       0
     87  getTime               DateProtoFuncImp::GetTime               DontEnum|Function       0
     88  getFullYear           DateProtoFuncImp::GetFullYear           DontEnum|Function       0
     89  getUTCFullYear        -DateProtoFuncImp::GetFullYear          DontEnum|Function       0
     90  toGMTString           DateProtoFuncImp::ToGMTString           DontEnum|Function       0
     91  getMonth              DateProtoFuncImp::GetMonth              DontEnum|Function       0
     92  getUTCMonth           -DateProtoFuncImp::GetMonth             DontEnum|Function       0
     93  getDate               DateProtoFuncImp::GetDate               DontEnum|Function       0
     94  getUTCDate            -DateProtoFuncImp::GetDate              DontEnum|Function       0
     95  getDay                DateProtoFuncImp::GetDay                DontEnum|Function       0
     96  getUTCDay             -DateProtoFuncImp::GetDay               DontEnum|Function       0
     97  getHours              DateProtoFuncImp::GetHours              DontEnum|Function       0
     98  getUTCHours           -DateProtoFuncImp::GetHours             DontEnum|Function       0
     99  getMinutes            DateProtoFuncImp::GetMinutes            DontEnum|Function       0
     100  getUTCMinutes         -DateProtoFuncImp::GetMinutes           DontEnum|Function       0
     101  getSeconds            DateProtoFuncImp::GetSeconds            DontEnum|Function       0
     102  getUTCSeconds         -DateProtoFuncImp::GetSeconds           DontEnum|Function       0
     103  getMilliseconds       DateProtoFuncImp::GetMilliSeconds       DontEnum|Function       0
     104  getUTCMilliseconds    -DateProtoFuncImp::GetMilliSeconds      DontEnum|Function       0
     105  getTimezoneOffset     DateProtoFuncImp::GetTimezoneOffset     DontEnum|Function       0
     106  setTime               DateProtoFuncImp::SetTime               DontEnum|Function       1
     107  setMilliseconds       DateProtoFuncImp::SetMilliSeconds       DontEnum|Function       1
     108  setUTCMilliseconds    -DateProtoFuncImp::SetMilliSeconds      DontEnum|Function       1
     109  setSeconds            DateProtoFuncImp::SetSeconds            DontEnum|Function       2
     110  setUTCSeconds         -DateProtoFuncImp::SetSeconds           DontEnum|Function       2
     111  setMinutes            DateProtoFuncImp::SetMinutes            DontEnum|Function       3
     112  setUTCMinutes         -DateProtoFuncImp::SetMinutes           DontEnum|Function       3
     113  setHours              DateProtoFuncImp::SetHours              DontEnum|Function       4
     114  setUTCHours           -DateProtoFuncImp::SetHours             DontEnum|Function       4
     115  setDate               DateProtoFuncImp::SetDate               DontEnum|Function       1
     116  setUTCDate            -DateProtoFuncImp::SetDate              DontEnum|Function       1
     117  setMonth              DateProtoFuncImp::SetMonth              DontEnum|Function       2
     118  setUTCMonth           -DateProtoFuncImp::SetMonth             DontEnum|Function       2
     119  setFullYear           DateProtoFuncImp::SetFullYear           DontEnum|Function       3
     120  setUTCFullYear        -DateProtoFuncImp::SetFullYear          DontEnum|Function       3
     121  setYear               DateProtoFuncImp::SetYear               DontEnum|Function       1
     122  getYear               DateProtoFuncImp::GetYear               DontEnum|Function       0
     123  toGMTString           DateProtoFuncImp::ToGMTString           DontEnum|Function       0
     124@end
     125*/
     126// ECMA 15.9.4
     127
     128DatePrototypeImp::DatePrototypeImp(ExecState *,
     129                                   ObjectPrototypeImp *objectProto)
     130  : DateInstanceImp(Object(objectProto))
     131{
     132  Value protect(this);
     133  setInternalValue(Number(NaN));
     134  // The constructor will be added later, after DateObjectImp has been built
     135}
     136
     137Value DatePrototypeImp::get(ExecState *exec, const UString &propertyName) const
     138{
     139  return lookupGetFunction<DateProtoFuncImp, ObjectImp>( exec, propertyName, &dateTable, this );
     140}
     141
     142// ------------------------------ DateProtoFuncImp -----------------------------
     143
     144DateProtoFuncImp::DateProtoFuncImp(ExecState *exec, int i, int len)
     145  : InternalFunctionImp(
     146    static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
     147    ), id(abs(i)), utc(i<0)
     148  // We use a negative ID to denote the "UTC" variant.
     149{
     150  Value protect(this);
     151  put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
     152}
     153
     154bool DateProtoFuncImp::implementsCall() const
     155{
     156  return true;
     157}
     158
     159Value DateProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
     160{
     161  if ((id == ToString || id == ValueOf || id == GetTime || id == SetTime) &&
     162      !thisObj.inherits(&DateInstanceImp::info)) {
     163    // non-generic function called on non-date object
     164
     165    // ToString and ValueOf are generic according to the spec, but the mozilla
     166    // tests suggest otherwise...
     167    Object err = Error::create(exec,TypeError);
     168    exec->setException(err);
     169    return err;
     170  }
     171
     172
     173  Value result;
     174  UString s;
     175  const int bufsize=100;
     176  char timebuffer[bufsize];
     177  char *oldlocale = setlocale(LC_TIME,NULL);
     178  if (!oldlocale)
     179    oldlocale = setlocale(LC_ALL, NULL);
     180  Value v = thisObj.internalValue();
     181  double milli = v.toNumber(exec);
     182  time_t tv = (time_t) floor(milli / 1000.0);
     183  int ms = int(milli - tv * 1000.0);
     184
     185  struct tm *t;
     186  if (utc)
     187    t = gmtime(&tv);
     188  else
     189    t = localtime(&tv);
     190
     191  switch (id) {
     192  case ToString:
     193    s = ctime(&tv);
     194    result = String(s.substr(0, s.size() - 1));
     195    break;
     196  case ToDateString:
     197  case ToTimeString:
     198  case ToGMTString:
     199    setlocale(LC_TIME,"C");
     200    if (id == DateProtoFuncImp::ToDateString) {
     201      strftime(timebuffer, bufsize, "%x",t);
     202    } else if (id == DateProtoFuncImp::ToTimeString) {
     203      strftime(timebuffer, bufsize, "%X",t);
     204    } else {
     205      t = gmtime(&tv);
     206      strftime(timebuffer, bufsize, "%a, %d-%b-%y %H:%M:%S %Z", t);
     207    }
     208    setlocale(LC_TIME,oldlocale);
     209    result = String(timebuffer);
     210    break;
     211  case ToLocaleString:
     212    strftime(timebuffer, bufsize, "%c", t);
     213    result = String(timebuffer);
     214    break;
     215  case ToLocaleDateString:
     216    strftime(timebuffer, bufsize, "%x", t);
     217    result = String(timebuffer);
     218    break;
     219  case ToLocaleTimeString:
     220    strftime(timebuffer, bufsize, "%X", t);
     221    result = String(timebuffer);
     222    break;
     223  case ValueOf:
     224    result = Number(milli);
     225    break;
     226  case GetTime:
     227    result = Number(milli);
     228    break;
     229  case GetYear:
     230    // IE returns the full year even in getYear.
     231    if ( exec->interpreter()->compatMode() == Interpreter::IECompat )
     232      result = Number(1900 + t->tm_year);
     233    else
     234      result = Number(t->tm_year);
     235    break;
     236  case GetFullYear:
     237    result = Number(1900 + t->tm_year);
     238    break;
     239  case GetMonth:
     240    result = Number(t->tm_mon);
     241    break;
     242  case GetDate:
     243    result = Number(t->tm_mday);
     244    break;
     245  case GetDay:
     246    result = Number(t->tm_wday);
     247    break;
     248  case GetHours:
     249    result = Number(t->tm_hour);
     250    break;
     251  case GetMinutes:
     252    result = Number(t->tm_min);
     253    break;
     254  case GetSeconds:
     255    result = Number(t->tm_sec);
     256    break;
     257  case GetMilliSeconds:
     258    result = Number(ms);
     259    break;
     260  case GetTimezoneOffset:
     261#if defined BSD || defined(__APPLE__)
     262    result = Number(-( t->tm_gmtoff / 60 ) + ( t->tm_isdst ? 60 : 0 ));
     263#else
     264#  if defined(__BORLANDC__)
     265#error please add daylight savings offset here!
     266    result = Number(_timezone / 60 - (_daylight ? 60 : 0));
     267#  else
     268    result = Number(( timezone / 60 - ( daylight ? 60 : 0 )));
     269#  endif
     270#endif
     271    break;
     272  case SetTime:
     273    milli = roundValue(exec,args[0]);
     274    result = Number(milli);
     275    thisObj.setInternalValue(result);
     276    break;
     277  case SetMilliSeconds:
     278    ms = args[0].toInt32(exec);
     279    break;
     280  case SetSeconds:
     281    t->tm_sec = args[0].toInt32(exec);
     282    break;
     283  case SetMinutes:
     284    t->tm_min = args[0].toInt32(exec);
     285    break;
     286  case SetHours:
     287    t->tm_hour = args[0].toInt32(exec);
     288    break;
     289  case SetDate:
     290    t->tm_mday = args[0].toInt32(exec);
     291    break;
     292  case SetMonth:
     293    t->tm_mon = args[0].toInt32(exec);
     294    break;
     295  case SetFullYear:
     296    t->tm_year = args[0].toInt32(exec) - 1900;
     297    break;
     298  case SetYear:
     299    t->tm_year = args[0].toInt32(exec) >= 1900 ? args[0].toInt32(exec) - 1900 : args[0].toInt32(exec);
     300    break;
     301  }
     302
     303  if (id == SetYear || id == SetMilliSeconds || id == SetSeconds ||
     304      id == SetMinutes || id == SetHours || id == SetDate ||
     305      id == SetMonth || id == SetFullYear ) {
     306    result = Number(mktime(t) * 1000.0 + ms);
     307    thisObj.setInternalValue(result);
     308  }
     309
     310  return result;
     311}
     312
     313// ------------------------------ DateObjectImp --------------------------------
     314
     315// TODO: MakeTime (15.9.11.1) etc. ?
     316
     317DateObjectImp::DateObjectImp(ExecState *exec,
     318                             FunctionPrototypeImp *funcProto,
     319                             DatePrototypeImp *dateProto)
     320  : InternalFunctionImp(funcProto)
     321{
     322  Value protect(this);
     323  // ECMA 15.9.4.1 Date.prototype
     324  put(exec,"prototype", Object(dateProto), DontEnum|DontDelete|ReadOnly);
     325
     326  put(exec,"parse", Object(new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::Parse, 1)), DontEnum);
     327  put(exec,"UTC",   Object(new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::UTC,   7)),   DontEnum);
     328
     329  // no. of arguments for constructor
     330  put(exec,"length", Number(7), ReadOnly|DontDelete|DontEnum);
     331}
     332
     333bool DateObjectImp::implementsConstruct() const
     334{
     335  return true;
     336}
     337
     338// ECMA 15.9.3
     339Object DateObjectImp::construct(ExecState *exec, const List &args)
     340{
     341  int numArgs = args.size();
     342
     343#ifdef KJS_VERBOSE
     344  fprintf(stderr,"DateObjectImp::construct - %d args\n", numArgs);
     345#endif
     346  Value value;
     347
     348  if (numArgs == 0) { // new Date() ECMA 15.9.3.3
     349#if HAVE_SYS_TIMEB_H
     350#  if defined(__BORLANDC__)
     351    struct timeb timebuffer;
     352    ftime(&timebuffer);
     353#  else
     354    struct _timeb timebuffer;
     355    _ftime(&timebuffer);
     356#  endif
     357    double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm);
     358#else
     359    struct timeval tv;
     360    gettimeofday(&tv, 0L);
     361    double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0);
     362#endif
     363    value = Number(utc);
     364  } else if (numArgs == 1) {
     365    UString s = args[0].toString(exec);
     366    double d = s.toDouble();
     367    if (isNaN(d))
     368      value = parseDate(s);
     369    else
     370      value = Number(d);
     371  } else {
     372    struct tm t;
     373    memset(&t, 0, sizeof(t));
     374    Number y = args[0].toNumber(exec);
     375    // TODO: check for NaN
     376    int year = y.toInt32(exec);
     377    t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
     378    t.tm_mon = args[1].toInt32(exec);
     379    t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1;
     380    t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0;
     381    t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0;
     382    t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0;
     383    t.tm_isdst = -1;
     384    int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0;
     385    value = Number(mktime(&t) * 1000.0 + ms);
     386  }
     387
     388  Object proto = exec->interpreter()->builtinDatePrototype();
     389  Object ret(new DateInstanceImp(proto));
     390  ret.setInternalValue(timeClip(value));
     391  return ret;
     392}
     393
     394bool DateObjectImp::implementsCall() const
     395{
     396  return true;
     397}
     398
     399// ECMA 15.9.2
     400Value DateObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/)
     401{
     402#ifdef KJS_VERBOSE
     403  fprintf(stderr,"DateObjectImp::call - current time\n");
     404#endif
     405  time_t t = time(0L);
     406  UString s(ctime(&t));
     407
     408  // return formatted string minus trailing \n
     409  return String(s.substr(0, s.size() - 1));
     410}
     411
     412// ------------------------------ DateObjectFuncImp ----------------------------
     413
     414DateObjectFuncImp::DateObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto,
     415                                     int i, int len)
     416  : InternalFunctionImp(funcProto), id(i)
     417{
     418  Value protect(this);
     419  put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
     420}
     421
     422bool DateObjectFuncImp::implementsCall() const
     423{
     424  return true;
     425}
     426
     427// ECMA 15.9.4.2 - 3
     428Value DateObjectFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
     429{
     430  if (id == Parse) {
     431    if (args[0].type() == StringType)
     432      return parseDate(args[0].toString(exec));
     433    else
     434      return Undefined();
     435  }
     436  else { // UTC
     437    struct tm t;
     438    memset(&t, 0, sizeof(t));
     439    int n = args.size();
     440    Number y = args[0].toNumber(exec);
     441    // TODO: check for NaN
     442    int year = y.toInt32(exec);
     443    t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
     444    t.tm_mon = args[1].toInt32(exec);
     445    t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1;
     446    t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0;
     447    t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0;
     448    t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0;
     449    int ms = (n >= 7) ? args[6].toInt32(exec) : 0;
     450    return Number(mktime(&t) * 1000.0 + ms);
     451  }
     452}
     453
     454// -----------------------------------------------------------------------------
     455
     456
     457Value KJS::parseDate(const String &s)
    89458{
    90459  UString u = s.value();
     460#ifdef KJS_VERBOSE
     461  fprintf(stderr,"KJS::parseDate %s\n",u.ascii());
     462#endif
    91463  int firstSlash = u.find('/');
    92464  if ( firstSlash == -1 )
    93465  {
    94     /* TODO parse dates like "December 25, 1995 23:15:00"*/
    95     fprintf(stderr,"KJS::parseDate parsing for this format isn't implemented\n%s", u.ascii());
    96     return Number(0);
     466    time_t seconds = KRFCDate_parseDate( u );
     467#ifdef KJS_VERBOSE
     468    fprintf(stderr,"KRFCDate_parseDate returned seconds=%d\n",seconds);
     469#endif
     470    if ( seconds == -1 )
     471      return Undefined();
     472    else
     473      return Number(seconds * 1000.0);
    97474  }
    98475  else
     
    127504}
    128505
    129 KJSO KJS::timeClip(const KJSO &t)
     506///// Awful duplication from krfcdate.cpp - we don't link to kdecore
     507
     508static unsigned int ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
     509{
     510    unsigned int ret = (day - 32075)       /* days */
     511            + 1461L * (year + 4800L + (mon - 14) / 12) / 4
     512            + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
     513            - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
     514            - 2440588;
     515    ret = 24*ret + hour;     /* hours   */
     516    ret = 60*ret + minute;   /* minutes */
     517    ret = 60*ret + second;   /* seconds */
     518
     519    return ret;
     520}
     521
     522static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec";
     523
     524// we follow the recommendation of rfc2822 to consider all
     525// obsolete time zones not listed here equivalent to "-0000"
     526static const struct {
     527    const char *tzName;
     528    int tzOffset;
     529} known_zones[] = {
     530    { "UT", 0 },
     531    { "GMT", 0 },
     532    { "EST", -300 },
     533    { "EDT", -240 },
     534    { "CST", -360 },
     535    { "CDT", -300 },
     536    { "MST", -420 },
     537    { "MDT", -360 },
     538    { "PST", -480 },
     539    { "PDT", -420 },
     540    { 0, 0 }
     541};
     542
     543time_t KJS::KRFCDate_parseDate(const UString &_date)
     544{
     545     // This parse a date in the form:
     546     //     Wednesday, 09-Nov-99 23:12:40 GMT
     547     // or
     548     //     Sat, 01-Jan-2000 08:00:00 GMT
     549     // or
     550     //     Sat, 01 Jan 2000 08:00:00 GMT
     551     // or
     552     //     01 Jan 99 22:00 +0100    (exceptions in rfc822/rfc2822)
     553     // ### non RFC format, added for Javascript:
     554     //     [Wednesday] January 09 1999 23:12:40 GMT
     555     //
     556     // We ignore the weekday
     557     //
     558     time_t result = 0;
     559     int offset = 0;
     560     char *newPosStr;
     561     const char *dateString = _date.ascii();
     562     int day = 0;
     563     char monthStr[4];
     564     int month = -1; // not set yet
     565     int year = 0;
     566     int hour = 0;
     567     int minute = 0;
     568     int second = 0;
     569
     570     // Skip leading space
     571     while(*dateString && isspace(*dateString))
     572        dateString++;
     573
     574     const char *wordStart = dateString;
     575     // Check contents of first words if not number
     576     while(*dateString && !isdigit(*dateString))
     577     {
     578        if ( isspace(*dateString) && dateString - wordStart >= 3 )
     579        {
     580          monthStr[0] = tolower(*wordStart++);
     581          monthStr[1] = tolower(*wordStart++);
     582          monthStr[2] = tolower(*wordStart++);
     583          monthStr[3] = '\0';
     584          //fprintf(stderr,"KJS::parseDate found word starting with '%s'\n", monthStr);
     585          const char *str = strstr(haystack, monthStr);
     586          if (str)
     587            month = (str-haystack)/3; // Jan=00, Feb=01, Mar=02, ..
     588          while(*dateString && isspace(*dateString))
     589             dateString++;
     590          wordStart = dateString;
     591        }
     592        else
     593           dateString++;
     594     }
     595
     596     while(*dateString && isspace(*dateString))
     597        dateString++;
     598
     599     if (!*dateString)
     600        return result;  // Invalid date
     601
     602     // ' 09-Nov-99 23:12:40 GMT'
     603     day = strtol(dateString, &newPosStr, 10);
     604     dateString = newPosStr;
     605
     606     if ((day < 1) || (day > 31))
     607        return result; // Invalid date;
     608     if (!*dateString)
     609        return result;  // Invalid date
     610
     611     if (*dateString == '-')
     612        dateString++;
     613
     614     while(*dateString && isspace(*dateString))
     615        dateString++;
     616
     617     if ( month == -1 ) // not found yet
     618     {
     619        for(int i=0; i < 3;i++)
     620        {
     621           if (!*dateString || (*dateString == '-') || isspace(*dateString))
     622              return result;  // Invalid date
     623           monthStr[i] = tolower(*dateString++);
     624        }
     625        monthStr[3] = '\0';
     626
     627        newPosStr = (char*)strstr(haystack, monthStr);
     628
     629        if (!newPosStr)
     630           return result;  // Invalid date
     631
     632        month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, ..
     633
     634        if ((month < 0) || (month > 11))
     635           return result;  // Invalid date
     636
     637        while(*dateString && (*dateString != '-') && !isspace(*dateString))
     638           dateString++;
     639
     640        if (!*dateString)
     641           return result;  // Invalid date
     642
     643        // '-99 23:12:40 GMT'
     644        if ((*dateString != '-') && !isspace(*dateString))
     645           return result;  // Invalid date
     646        dateString++;
     647     }
     648
     649     if ((month < 0) || (month > 11))
     650        return result;  // Invalid date
     651
     652     // '99 23:12:40 GMT'
     653     year = strtol(dateString, &newPosStr, 10);
     654     dateString = newPosStr;
     655
     656     // Y2K: Solve 2 digit years
     657     if ((year >= 0) && (year < 50))
     658         year += 2000;
     659
     660     if ((year >= 50) && (year < 100))
     661         year += 1900;  // Y2K
     662
     663     if ((year < 1900) || (year > 2500))
     664        return result; // Invalid date
     665
     666     // Don't fail if the time is missing.
     667     if (*dateString)
     668     {
     669        // ' 23:12:40 GMT'
     670        if (!isspace(*dateString++))
     671           return result;  // Invalid date
     672
     673        hour = strtol(dateString, &newPosStr, 10);
     674        dateString = newPosStr;
     675
     676        if ((hour < 0) || (hour > 23))
     677           return result; // Invalid date
     678
     679        if (!*dateString)
     680           return result;  // Invalid date
     681
     682        // ':12:40 GMT'
     683        if (*dateString++ != ':')
     684           return result;  // Invalid date
     685
     686        minute = strtol(dateString, &newPosStr, 10);
     687        dateString = newPosStr;
     688
     689        if ((minute < 0) || (minute > 59))
     690           return result; // Invalid date
     691
     692        if (!*dateString)
     693           return result;  // Invalid date
     694
     695        // ':40 GMT'
     696        if (*dateString != ':' && !isspace(*dateString))
     697           return result;  // Invalid date
     698
     699        // seconds are optional in rfc822 + rfc2822
     700        if (*dateString ==':') {
     701           dateString++;
     702
     703           second = strtol(dateString, &newPosStr, 10);
     704           dateString = newPosStr;
     705
     706           if ((second < 0) || (second > 59))
     707              return result; // Invalid date
     708        } else {
     709           dateString++;
     710        }
     711
     712        while(*dateString && isspace(*dateString))
     713           dateString++;
     714     }
     715
     716     // don't fail if the time zone is missing, some
     717     // broken mail-/news-clients omit the time zone
     718     if (*dateString) {
     719
     720        if ((*dateString == '+') || (*dateString == '-')) {
     721           offset = strtol(dateString, &newPosStr, 10);
     722
     723           if ((offset < -9959) || (offset > 9959))
     724              return result; // Invalid date
     725
     726           int sgn = (offset < 0)? -1:1;
     727           offset = abs(offset);
     728           offset = ((offset / 100)*60 + (offset % 100))*sgn;
     729        } else {
     730           for (int i=0; known_zones[i].tzName != 0; i++) {
     731              if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
     732                 offset = known_zones[i].tzOffset;
     733                 break;
     734              }
     735           }
     736        }
     737     }
     738     if (sizeof(time_t) == 4)
     739     {
     740         if ((time_t)-1 < 0)
     741         {
     742            if (year >= 2038)
     743            {
     744               year = 2038;
     745               month = 0;
     746               day = 1;
     747               hour = 0;
     748               minute = 0;
     749               second = 0;
     750            }
     751         }
     752         else
     753         {
     754            if (year >= 2115)
     755            {
     756               year = 2115;
     757               month = 0;
     758               day = 1;
     759               hour = 0;
     760               minute = 0;
     761               second = 0;
     762            }
     763         }
     764     }
     765
     766     result = ymdhms_to_seconds(year, month+1, day, hour, minute, second);
     767
     768     // avoid negative time values
     769     if ((offset > 0) && (offset > result))
     770        offset = 0;
     771
     772     result -= offset*60;
     773
     774     // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
     775     // This is so that parse error and valid epoch 0 return values won't
     776     // be the same for sensitive applications...
     777     if (result < 1) result = 1;
     778
     779     return result;
     780}
     781
     782
     783Value KJS::timeClip(const Value &t)
    130784{
    131785  /* TODO */
     
    133787}
    134788
    135 DateObject::DateObject(const Object& funcProto, const Object &dateProto)
    136     : ConstructorImp(funcProto, 7)
    137 {
    138   // ECMA 15.9.4.1 Date.prototype
    139   setPrototypeProperty(dateProto);
    140 }
    141 
    142 // ECMA 15.9.2
    143 Completion DateObject::execute(const List &)
    144 {
    145   time_t t = time(0L);
    146   UString s(ctime(&t));
    147 
    148   // return formatted string minus trailing \n
    149   return Completion(ReturnValue, String(s.substr(0, s.size() - 1)));
    150 }
    151 
    152 // ECMA 15.9.3
    153 Object DateObject::construct(const List &args)
    154 {
    155   KJSO value;
    156 
    157   int numArgs = args.size();
    158 
    159   if (numArgs == 0) { // new Date() ECMA 15.9.3.3
    160 #if HAVE_SYS_TIMEB_H
    161 #  if defined(__BORLANDC__)
    162     struct timeb timebuffer;
    163     ftime(&timebuffer);
    164 #  else
    165     struct _timeb timebuffer;
    166     _ftime(&timebuffer);
    167 #  endif
    168     double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm);
    169 #else
    170     struct timeval tv;
    171     gettimeofday(&tv, 0L);
    172     double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0);
    173 #endif
    174     value = Number(utc);
    175   } else if (numArgs == 1) {
    176     KJSO p = args[0].toPrimitive();
    177     if (p.isA(StringType))
    178       value = parseDate(p.toString());
    179     else
    180       value = p.toNumber();
    181   } else {
    182     struct tm t;
    183     memset(&t, 0, sizeof(t));
    184     Number y = args[0].toNumber();
    185     /* TODO: check for NaN */
    186     int year = y.toInt32();
    187     t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
    188     t.tm_mon = args[1].toInt32();
    189     t.tm_mday = (numArgs >= 3) ? args[2].toInt32() : 1;
    190     t.tm_hour = (numArgs >= 4) ? args[3].toInt32() : 0;
    191     t.tm_min = (numArgs >= 5) ? args[4].toInt32() : 0;
    192     t.tm_sec = (numArgs >= 6) ? args[5].toInt32() : 0;
    193     t.tm_isdst = -1;
    194     int ms = (numArgs >= 7) ? args[6].toInt32() : 0;
    195     value = Number(mktime(&t) * 1000.0 + ms);
    196   }
    197 
    198   return Object::create(DateClass, timeClip(value));
    199 }
    200 
    201 KJSO DateObject::get(const UString &p) const
    202 {
    203   int id;
    204 
    205   if (p == "parse")
    206     id = DateObjectFunc::Parse;
    207   else if (p == "UTC")
    208     id = DateObjectFunc::UTC;
    209   else
    210     return Imp::get(p);
    211 
    212   return Function(new DateObjectFunc(id));
    213 }
    214 
    215 // ECMA 15.9.4.2 - 3
    216 Completion DateObjectFunc::execute(const List &args)
    217 {
    218   KJSO result;
    219 
    220   if (id == Parse)
    221     if (args[0].isA(StringType))
    222       result = parseDate(args[0].toString());
    223     else
    224       result = Undefined();
    225   else {
    226     struct tm t;
    227     memset(&t, 0, sizeof(t));
    228     int n = args.size();
    229     Number y = args[0].toNumber();
    230     /* TODO: check for NaN */
    231     int year = y.toInt32();
    232     t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;
    233     t.tm_mon = args[1].toInt32();
    234     t.tm_mday = (n >= 3) ? args[2].toInt32() : 1;
    235     t.tm_hour = (n >= 4) ? args[3].toInt32() : 0;
    236     t.tm_min = (n >= 5) ? args[4].toInt32() : 0;
    237     t.tm_sec = (n >= 6) ? args[5].toInt32() : 0;
    238     int ms = (n >= 7) ? args[6].toInt32() : 0;
    239     result = Number(mktime(&t) * 1000.0 + ms);
    240   }
    241 
    242   return Completion(ReturnValue, result);
    243 }
    244 
    245 // ECMA 15.9.4
    246 DatePrototype::DatePrototype(const Object& proto)
    247   : ObjectImp(DateClass, Number(NaN), proto)
    248 {
    249   // The constructor will be added later in DateObject's constructor
    250 }
    251 
    252 KJSO DatePrototype::get(const UString &p) const
    253 {
    254   int id;
    255 
    256   if (p == "toString" || p == "toUTCString")
    257     id = DateProtoFunc::ToString;
    258   else if (p == "toDateString")
    259     id = DateProtoFunc::ToDateString;
    260   else if (p == "toTimeString")
    261     id = DateProtoFunc::ToTimeString;
    262   else if (p == "toLocaleString")
    263     id = DateProtoFunc::ToLocaleString;
    264   else if (p == "toLocaleDateString")
    265     id = DateProtoFunc::ToLocaleDateString;
    266   else if (p == "toLocaleTimeString")
    267     id = DateProtoFunc::ToLocaleTimeString;
    268   else if (p == "valueOf")
    269     id = DateProtoFunc::ValueOf;
    270   else if (p == "getTime")
    271     id = DateProtoFunc::GetTime;
    272   else if (p == "getFullYear" || p == "getUTCFullYear")
    273     id = DateProtoFunc::GetFullYear;
    274   else if (p == "toGMTString")
    275     id = DateProtoFunc::ToGMTString;
    276   else if (p == "getMonth" || p == "getUTCMonth")
    277     id = DateProtoFunc::GetMonth;
    278   else if (p == "getDate" || p == "getUTCDate")
    279     id = DateProtoFunc::GetDate;
    280   else if (p == "getDay" || p == "getUTCDay")
    281     id = DateProtoFunc::GetDay;
    282   else if (p == "getHours" || p == "getUTCHours")
    283     id = DateProtoFunc::GetHours;
    284   else if (p == "getMinutes" || p == "getUTCMinutes")
    285     id = DateProtoFunc::GetMinutes;
    286   else if (p == "getSeconds" || p == "getUTCSeconds")
    287     id = DateProtoFunc::GetSeconds;
    288   else if (p == "getMilliseconds" || p == "getUTCMilliseconds")
    289     id = DateProtoFunc::GetMilliSeconds;
    290   else if (p == "getTimezoneOffset")
    291     id = DateProtoFunc::GetTimezoneOffset;
    292   else if (p == "setTime")
    293     id = DateProtoFunc::SetTime;
    294   else if (p == "setMilliseconds" || p == "setUTCMilliseconds")
    295     id = DateProtoFunc::SetMilliSeconds;
    296   else if (p == "setSeconds" || p == "setUTCSeconds")
    297     id = DateProtoFunc::SetSeconds;
    298   else if (p == "setMinutes" || p == "setUTCMinutes")
    299     id = DateProtoFunc::SetMinutes;
    300   else if (p == "setHours" || p == "setUTCHours")
    301     id = DateProtoFunc::SetHours;
    302   else if (p == "setDate" || p == "setUTCDate")
    303     id = DateProtoFunc::SetDate;
    304   else if (p == "setMonth" || p == "setUTCMonth")
    305     id = DateProtoFunc::SetMonth;
    306   else if (p == "setFullYear" || p == "setUTCFullYear")
    307     id = DateProtoFunc::SetFullYear;
    308   else if (p == "setYear" )
    309     id = DateProtoFunc::SetYear;
    310   // non-normative
    311   else if (p == "getYear")
    312     id = DateProtoFunc::GetYear;
    313   else if (p == "toGMTString")
    314     id = DateProtoFunc::ToGMTString;
    315   else
    316     return Undefined();
    317 
    318   bool utc = (p.find("UTC") >= 0) ? true : false;
    319   return Function(new DateProtoFunc(id, utc));
    320 }
    321 
    322 DateProtoFunc::DateProtoFunc(int i, bool u) : id(i), utc(u)
    323 {
    324 }
    325 
    326 Completion DateProtoFunc::execute(const List &args)
    327 {
    328   KJSO result;
    329   UString s;
    330   const int bufsize=100;
    331   char timebuffer[bufsize];
    332   char *oldlocale = setlocale(LC_TIME,NULL);
    333   if (!oldlocale)
    334     oldlocale = setlocale(LC_ALL, NULL);
    335   Object thisObj = Object::dynamicCast(thisValue());
    336   KJSO v = thisObj.internalValue();
    337   double milli = v.toNumber().value();
    338   time_t tv = (time_t) floor(milli / 1000.0);
    339   int ms = int(milli - tv * 1000.0);
    340 
    341   struct tm *t;
    342   if (utc)
    343     t = gmtime(&tv);
    344   else
    345     t = localtime(&tv);
    346 
    347   switch (id) {
    348   case ToString:
    349     s = ctime(&tv);
    350     result = String(s.substr(0, s.size() - 1));
    351     break;
    352   case ToDateString:
    353   case ToTimeString:
    354   case ToGMTString:
    355     setlocale(LC_TIME,"C");
    356     if (id == DateProtoFunc::ToDateString) {
    357       strftime(timebuffer, bufsize, "%x",t);
    358     } else if (id == DateProtoFunc::ToTimeString) {
    359       strftime(timebuffer, bufsize, "%X",t);
    360     } else {
    361       t = gmtime(&tv);
    362       strftime(timebuffer, bufsize, "%a, %d-%b-%y %H:%M:%S %Z", t);
    363     }
    364     setlocale(LC_TIME,oldlocale);
    365     result = String(timebuffer);
    366     break;
    367   case ToLocaleString:
    368     strftime(timebuffer, bufsize, "%c", t);
    369     result = String(timebuffer);
    370     break;
    371   case ToLocaleDateString:
    372     strftime(timebuffer, bufsize, "%x", t);
    373     result = String(timebuffer);
    374     break;
    375   case ToLocaleTimeString:
    376     strftime(timebuffer, bufsize, "%X", t);
    377     result = String(timebuffer);
    378     break;
    379   case ValueOf:
    380     result = Number(milli);
    381     break;
    382   case GetTime:
    383     if (thisObj.getClass() == DateClass)
    384       result = Number(milli);
    385     else
    386       result = Error::create(TypeError);
    387     break;
    388   case GetYear:
    389     result = Number(t->tm_year);
    390     break;
    391   case GetFullYear:
    392     result = Number(1900 + t->tm_year);
    393     break;
    394   case GetMonth:
    395     result = Number(t->tm_mon);
    396     break;
    397   case GetDate:
    398     result = Number(t->tm_mday);
    399     break;
    400   case GetDay:
    401     result = Number(t->tm_wday);
    402     break;
    403   case GetHours:
    404     result = Number(t->tm_hour);
    405     break;
    406   case GetMinutes:
    407     result = Number(t->tm_min);
    408     break;
    409   case GetSeconds:
    410     result = Number(t->tm_sec);
    411     break;
    412   case GetMilliSeconds:
    413     result = Undefined();
    414     break;
    415   case GetTimezoneOffset:
    416 #if defined BSD || defined(__APPLE__)
    417     result = Number(-( t->tm_gmtoff / 60 ) + ( t->tm_isdst ? 60 : 0 ));
    418 #else
    419 #  if defined(__BORLANDC__)
    420 #error please add daylight savings offset here!
    421     result = Number(_timezone / 60 - (_daylight ? 60 : 0));
    422 #  else
    423     result = Number(( timezone / 60 - ( daylight ? 60 : 0 )));
    424 #  endif
    425 #endif
    426     break;
    427   case SetTime:
    428     milli = args[0].round();
    429     result = Number(milli);
    430     thisObj.setInternalValue(result);
    431     break;
    432   case SetMilliSeconds:
    433     ms = args[0].toInt32();
    434     break;
    435   case SetSeconds:
    436     t->tm_sec = args[0].toInt32();
    437     break;
    438   case SetMinutes:
    439     t->tm_min = args[0].toInt32();
    440     break;
    441   case SetHours:
    442     t->tm_hour = args[0].toInt32();
    443     break;
    444   case SetDate:
    445     t->tm_mday = args[0].toInt32();
    446     break;
    447   case SetMonth:
    448     t->tm_mon = args[0].toInt32();
    449     break;
    450   case SetFullYear:
    451     t->tm_year = args[0].toInt32() - 1900;
    452     break;
    453   case SetYear:
    454     t->tm_year = args[0].toInt32() >= 1900 ? args[0].toInt32() - 1900 : args[0].toInt32();
    455     break;
    456   }
    457 
    458   if (id == SetYear || id == SetMilliSeconds || id == SetSeconds ||
    459       id == SetMinutes || id == SetHours || id == SetDate ||
    460       id == SetMonth || id == SetFullYear ) {
    461     result = Number(mktime(t) * 1000.0 + ms);
    462     thisObj.setInternalValue(result);
    463   }
    464 
    465   return Completion(ReturnValue, result);
    466 }
  • trunk/JavaScriptCore/kjs/date_object.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2124#define _DATE_OBJECT_H_
    2225
    23 #include "object.h"
    24 #include "function.h"
     26#include "internal.h"
     27#include "function_object.h"
    2528
    2629namespace KJS {
    2730
    28   class DateObject : public ConstructorImp {
     31  class DateInstanceImp : public ObjectImp {
    2932  public:
    30     DateObject(const Object& funcProto, const Object &dateProto);
     33    DateInstanceImp(const Object &proto);
     34
     35    virtual const ClassInfo *classInfo() const { return &info; }
     36    static const ClassInfo info;
     37  };
     38
     39  /**
     40   * @internal
     41   *
     42   * The initial value of Date.prototype (and thus all objects created
     43   * with the Date constructor
     44   */
     45  class DatePrototypeImp : public DateInstanceImp {
     46  public:
     47    DatePrototypeImp(ExecState *exec, ObjectPrototypeImp *objectProto);
     48    Value get(ExecState *exec, const UString &p) const;
     49    virtual const ClassInfo *classInfo() const { return &info; }
     50    static const ClassInfo info;
     51  };
     52
     53  /**
     54   * @internal
     55   *
     56   * Class to implement all methods that are properties of the
     57   * Date.prototype object
     58   */
     59  class DateProtoFuncImp : public InternalFunctionImp {
     60  public:
     61    DateProtoFuncImp(ExecState *exec, int i, int len);
     62
     63    virtual bool implementsCall() const;
     64    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     65
     66
     67    Completion execute(const List &);
     68    enum { ToString, ToDateString, ToTimeString, ToLocaleString,
     69           ToLocaleDateString, ToLocaleTimeString, ValueOf, GetTime,
     70           GetFullYear, GetMonth, GetDate, GetDay, GetHours, GetMinutes,
     71           GetSeconds, GetMilliSeconds, GetTimezoneOffset, SetTime,
     72           SetMilliSeconds, SetSeconds, SetMinutes, SetHours, SetDate,
     73           SetMonth, SetFullYear, ToUTCString,
     74           // non-normative properties (Appendix B)
     75           GetYear, SetYear, ToGMTString };
     76  private:
     77    int id;
     78    bool utc;
     79  };
     80
     81  /**
     82   * @internal
     83   *
     84   * The initial value of the the global variable's "Date" property
     85   */
     86  class DateObjectImp : public InternalFunctionImp {
     87  public:
     88    DateObjectImp(ExecState *exec,
     89                  FunctionPrototypeImp *funcProto,
     90                  DatePrototypeImp *dateProto);
     91
     92    virtual bool implementsConstruct() const;
     93    virtual Object construct(ExecState *exec, const List &args);
     94    virtual bool implementsCall() const;
     95    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     96
    3197    Completion execute(const List &);
    3298    Object construct(const List &);
    33     KJSO get(const UString &p) const;
    3499  };
    35100
    36   class DatePrototype : public ObjectImp {
     101  /**
     102   * @internal
     103   *
     104   * Class to implement all methods that are properties of the
     105   * Date object
     106   */
     107  class DateObjectFuncImp : public InternalFunctionImp {
    37108  public:
    38     DatePrototype(const Object& proto);
    39     virtual KJSO get(const UString &p) const;
     109    DateObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto,
     110                      int i, int len);
     111
     112    virtual bool implementsCall() const;
     113    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     114
     115    enum { Parse, UTC };
     116  private:
     117    int id;
    40118  };
     119
     120  // helper functions
     121  Value parseDate(const String &s);
     122  time_t KRFCDate_parseDate(const UString &_date);
     123  Value timeClip(const Value &t);
    41124
    42125}; // namespace
  • trunk/JavaScriptCore/kjs/debugger.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    34 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1618 *  License along with this library; if not, write to the Free Software
    1719 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     20 *
     21 *  $Id$
    1822 */
    1923
    20 #ifdef KJS_DEBUGGER
    21 
    2224#include "debugger.h"
    23 #include "kjs.h"
     25#include "value.h"
     26#include "object.h"
     27#include "types.h"
     28#include "interpreter.h"
    2429#include "internal.h"
    2530#include "ustring.h"
     
    2732using namespace KJS;
    2833
    29 Debugger::Debugger(KJScript *engine)
    30   : eng(0L),
    31     sid(-1)
     34// ------------------------------ Debugger -------------------------------------
     35
     36namespace KJS {
     37  struct AttachedInterpreter
     38  {
     39  public:
     40    AttachedInterpreter(Interpreter *i) : interp(i) {}
     41    Interpreter *interp;
     42    AttachedInterpreter *next;
     43  };
     44
     45}
     46
     47Debugger::Debugger()
    3248{
    33   attach(engine);
     49  rep = new DebuggerImp();
    3450}
    3551
    3652Debugger::~Debugger()
    3753{
    38   detach();
     54  // detach from all interpreters
     55  while (rep->interps)
     56    detach(rep->interps->interp);
     57
     58  delete rep;
    3959}
    4060
    41 void Debugger::attach(KJScript *e)
     61void Debugger::attach(Interpreter *interp)
    4262{
    43   dmode = Disabled;
    44   if (e) {
    45     if (!eng || e->rep != eng->rep) {
    46       eng = e;
    47       eng->rep->attachDebugger(this);
    48     }
    49   } else {
    50     eng = 0L;
     63  if (interp->imp()->debugger() != this)
     64    interp->imp()->setDebugger(this);
     65
     66  // add to the list of attached interpreters
     67  if (!rep->interps)
     68    rep->interps = new AttachedInterpreter(interp);
     69  else {
     70    AttachedInterpreter *ai = rep->interps;
     71    while (ai->next)
     72      ai = ai->next;
     73    ai->next = new AttachedInterpreter(interp);;
    5174  }
    52   reset();
    5375}
    5476
    55 KJScript *Debugger::engine() const
     77void Debugger::detach(Interpreter *interp)
    5678{
    57   return eng;
     79  if (interp->imp()->debugger() == this)
     80    interp->imp()->setDebugger(this);
     81
     82  // remove from the list of attached interpreters
     83  if (rep->interps->interp == interp) {
     84    AttachedInterpreter *old = rep->interps;
     85    rep->interps = rep->interps->next;
     86    delete old;
     87  }
     88
     89  AttachedInterpreter *ai = rep->interps;
     90  while (ai->next && ai->next->interp != interp)
     91    ai = ai->next;
     92  if (ai->next) {
     93    AttachedInterpreter *old = ai->next;
     94    ai->next = ai->next->next;
     95    delete old;
     96  }
    5897}
    5998
    60 void Debugger::detach()
    61 {
    62   reset();
    63   if (!eng)
    64     return;
    65   eng->rep->attachDebugger(0L);
    66   eng = 0L;
    67 }
    68 
    69 void Debugger::setMode(Mode m)
    70 {
    71   dmode = m;
    72 }
    73 
    74 Debugger::Mode Debugger::mode() const
    75 {
    76   return dmode;
    77 }
    78 
    79 // supposed to be overriden by the user
    80 bool Debugger::stopEvent()
     99bool Debugger::sourceParsed(ExecState */*exec*/, int /*sourceId*/,
     100                            const UString &/*source*/, int /*errorLine*/)
    81101{
    82102  return true;
    83103}
    84104
    85 void Debugger::callEvent(const UString &, const UString &)
     105bool Debugger::sourceUnused(ExecState */*exec*/, int /*sourceId*/)
    86106{
     107  return true;
    87108}
    88109
    89 void Debugger::returnEvent()
     110bool Debugger::exception(ExecState */*exec*/, int /*sourceId*/, int /*lineno*/,
     111                         Object &/*exceptionObj*/)
    90112{
     113  return true;
    91114}
    92115
    93 void Debugger::reset()
     116bool Debugger::atStatement(ExecState */*exec*/, int /*sourceId*/, int /*firstLine*/,
     117                           int /*lastLine*/)
    94118{
    95   l = -1;
     119  return true;
    96120}
    97121
    98 int Debugger::freeSourceId() const
     122bool Debugger::callEvent(ExecState */*exec*/, int /*sourceId*/, int /*lineno*/,
     123                         Object &/*function*/, const List &/*args*/)
    99124{
    100   return eng ? eng->rep->sourceId()+1 : -1;
     125  return true;
    101126}
    102127
    103 bool Debugger::setBreakpoint(int id, int line)
     128bool Debugger::returnEvent(ExecState */*exec*/, int /*sourceId*/, int /*lineno*/,
     129                           Object &/*function*/)
    104130{
    105   if (!eng)
    106     return false;
    107   return eng->rep->setBreakpoint(id, line, true);
     131  return true;
    108132}
    109133
    110 bool Debugger::deleteBreakpoint(int id, int line)
    111 {
    112   if (!eng)
    113     return false;
    114   return eng->rep->setBreakpoint(id, line, false);
    115 }
    116 
    117 void Debugger::clearAllBreakpoints(int id)
    118 {
    119   if (!eng)
    120     return;
    121   eng->rep->setBreakpoint(id, -1, false);
    122 }
    123 
    124 UString Debugger::varInfo(const UString &ident)
    125 {
    126   if (!eng)
    127     return UString();
    128 
    129   int dot = ident.find('.');
    130   if (dot < 0)
    131       dot = ident.size();
    132   UString sub = ident.substr(0, dot);
    133   KJSO obj;
    134   // resolve base
    135   if (sub == "this") {
    136       obj = Context::current()->thisValue();
    137   } else {
    138       const List *chain = Context::current()->pScopeChain();
    139       ListIterator scope = chain->begin();
    140       while (scope != chain->end()) {
    141           if (scope->hasProperty(ident)) {
    142               obj = scope->get(ident);
    143               break;
    144           }
    145           scope++;
    146       }
    147       if (scope == chain->end())
    148         return UString();
    149   }
    150   // look up each part of a.b.c.
    151   while (dot < ident.size()) {
    152     int olddot = dot;
    153     dot = ident.find('.', olddot+1);
    154     if (dot < 0)
    155       dot = ident.size();
    156     sub = ident.substr(olddot+1, dot-olddot-1);
    157     obj = obj.get(sub);
    158     if (!obj.isDefined())
    159       break;
    160   }
    161 
    162   return sub + "=" + objInfo(obj) + ":" + UString(obj.imp()->typeInfo()->name);
    163 }
    164 
    165 // called by varInfo() and recursively by itself on each properties
    166 UString Debugger::objInfo(const KJSO &obj) const
    167 {
    168   const char *cnames[] = { "Undefined", "Array", "String", "Boolean",
    169                            "Number", "Object", "Date", "RegExp",
    170                            "Error", "Function" };
    171   PropList *plist = obj.imp()->propList(0, 0, false);
    172   if (!plist)
    173     return obj.toString().value();
    174   else {
    175     UString result = "{";
    176     while (1) {
    177       result += plist->name + "=";
    178       KJSO p = obj.get(plist->name);
    179       result += objInfo(p) + ":";
    180       Object obj = Object::dynamicCast(p);
    181       if (obj.isNull())
    182         result += p.imp()->typeInfo()->name;
    183       else
    184         result += cnames[int(obj.getClass())];
    185       plist = plist->next;
    186       if (!plist)
    187         break;
    188       result += ",";
    189     }
    190     result += "}";
    191     return result;
    192   }
    193 }
    194 
    195 bool Debugger::setVar(const UString &ident, const KJSO &value)
    196 {
    197   if (!eng)
    198     return false;
    199   const List *chain = Context::current()->pScopeChain();
    200   ListIterator scope = chain->begin();
    201   while (scope != chain->end()) {
    202     if (scope->hasProperty(ident)) {
    203       if (!scope->canPut(ident))
    204         return false;
    205       scope->put(ident, value);
    206       return true;
    207     }
    208     scope++;
    209   }
    210   // didn't find variable
    211   return false;
    212 }
    213 
    214 // called from the scripting engine each time a statement node is hit.
    215 bool Debugger::hit(int line, bool breakPoint)
    216 {
    217   l = line;
    218   if (!eng)
    219     return true;
    220 
    221   if (!breakPoint && ( mode() == Continue || mode() == Disabled ) )
    222       return true;
    223 
    224   bool ret = stopEvent();
    225   eng->init();  // in case somebody used a different interpreter meanwhile
    226   return ret;
    227 }
    228 
    229 #endif
  • trunk/JavaScriptCore/kjs/debugger.h

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    34 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1618 *  License along with this library; if not, write to the Free Software
    1719 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     20 *
     21 *  $Id$
    1822 */
    1923
     
    2125#define _KJSDEBUGGER_H_
    2226
    23 #include "internal.h"
    24 
    2527namespace KJS {
    2628
    27   //
    28   // NOTE: this interface is not ready, yet. Do not use unless you
    29   // don't mind source and binary incompatible changes that may arise
    30   // before the final version is released.
    31   //
    32 
    33 #ifdef KJS_DEBUGGER
     29  class DebuggerImp;
     30  class Interpreter;
     31  class ExecState;
     32  class Object;
     33  class UString;
     34  class List;
     35
     36  /**
     37   * @internal
     38   *
     39   * Provides an interface which receives notification about various
     40   * script-execution related events such as statement execution and function
     41   * calls.
     42   *
     43   * WARNING: This interface is still a work in progress and is not yet
     44   * offically publicly available. It is likely to change in binary incompatible
     45   * (and possibly source incompatible) ways in future versions. It is
     46   * anticipated that at some stage the interface will be frozen and made
     47   * available for general use.
     48   */
    3449  class Debugger {
    35     friend class KJScriptImp;
    36     friend class StatementNode;
    37     friend class DeclaredFunctionImp;
    38     friend class FunctionImp;
    3950  public:
    40     /**
    41      * Available modes of the debugger.
    42      */
    43     enum Mode { Disabled = 0, Next, Step, Continue, Stop };
    44     /**
    45      * Construct a debugger and attach it to the scripting engine s.
    46      */
    47     Debugger(KJScript *s);
    48     /**
    49      * Destruct the debugger and detach from the scripting engine we
    50      * might have been attached to.
     51
     52    /**
     53     * Creates a new debugger
     54     */
     55    Debugger();
     56
     57    /**
     58     * Destroys the debugger. If the debugger is attached to any interpreters,
     59     * it is automatically detached.
    5160     */
    5261    virtual ~Debugger();
    53     /**
    54      * Attaches the debugger to specified scripting engine.
    55      */
    56     void attach(KJScript *e);
    57     /**
    58      * Returns the engine the interpreter is currently attached to. Null
    59      * if there isn't any.
    60      */
    61     KJScript* engine() const;
    62     /**
    63      * Detach the debugger from any scripting engine.
    64      */
    65     void detach();
    66     /**
    67      * Set debugger into specified mode. This will influence further behaviour
    68      * if execution of the programm is started or continued.
    69      */
    70     virtual void setMode(Mode m);
    71     /**
    72      * Returns the current operation mode.
    73      */
    74     Mode mode() const;
    75     /**
    76      * Returns the line number the debugger currently has stopped at.
    77      * -1 if the debugger is not in a break status.
    78      */
    79     int lineNumber() const { return l; }
    80     /**
    81      * Returns the source id the debugger currently has stopped at.
    82      * -1 if the debugger is not in a break status.
    83      */
    84     int sourceId() const { return sid; }
    85     /**
    86      * Sets a breakpoint in the first statement where line lies in between
    87      * the statements range. Returns true if sucessfull, false if no
    88      * matching statement could be found.
    89      */
    90     bool setBreakpoint(int id, int line);
    91     bool deleteBreakpoint(int id, int line);
    92     void clearAllBreakpoints(int id=-1);
    93     /**
    94      * Returns the value of ident out of the current context in string form
    95      */
    96     UString varInfo(const UString &ident);
    97     /**
    98      * Set variable ident to value. Returns true if successful, false if
    99      * the specified variable doesn't exist or isn't writable.
    100      */
    101     bool setVar(const UString &ident, const KJSO &value);
    102 
    103   protected:
    104     /**
    105      * Invoked in case a breakpoint or the next statement is reached in step
    106      * mode. The return value decides whether execution will continue. True
    107      * denotes continuation, false an abortion, respectively.
    108      *
    109      * The default implementation does nothing. Overload this method if
    110      * you want to process this event.
    111      */
    112     virtual bool stopEvent();
    113     /**
    114      * Returns an integer that will be assigned to the code passed
    115      * next to one of the KJScript::evaluate() methods. It's basically
    116      * a counter to will only be reset to 0 on KJScript::clear().
    117      *
    118      * This information is useful in case you evaluate multiple blocks of
    119      * code containing some function declarations. Keep a map of source id/
    120      * code pairs, query sourceId() in case of a stopEvent() and update
    121      * your debugger window with the matching source code.
    122      */
    123     int freeSourceId() const;
    124     /**
    125      * Invoked on each function call. Use together with @ref returnEvent
     62
     63    DebuggerImp *imp() const { return rep; }
     64
     65    /**
     66     * Attaches the debugger to specified interpreter. This will cause this
     67     * object to receive notification of events from the interpreter.
     68     *
     69     * If the interpreter is deleted, the debugger will automatically be
     70     * detached.
     71     *
     72     * Note: only one debugger can be attached to an interpreter at a time.
     73     * Attaching another debugger to the same interpreter will cause the
     74     * original debugger to be detached from that interpreter.
     75     *
     76     * @param interp The interpreter to attach to
     77     *
     78     * @see detach()
     79     */
     80    void attach(Interpreter *interp);
     81
     82    /**
     83     * Detach the debugger from an interpreter
     84     *
     85     * @param interp The interpreter to detach from. If 0, the debugger will be
     86     * detached from all interpreters to which it is attached.
     87     *
     88     * @see attach()
     89     */
     90    void detach(Interpreter *interp);
     91
     92    /**
     93     * Called to notify the debugger that some javascript source code has
     94     * been parsed. For calls to Interpreter::evaluate(), this will be called
     95     * with the supplied source code before any other code is parsed.
     96     * Other situations in which this may be called include creation of a
     97     * function using the Function() constructor, or the eval() function.
     98     *
     99     * The default implementation does nothing. Override this method if
     100     * you want to process this event.
     101     *
     102     * @param exec The current execution state
     103     * @param sourceId The ID of the source code (corresponds to the
     104     * sourceId supplied in other functions such as @ref atStatement()
     105     * @param source The source code that was parsed
     106     * @param errorLine The line number at which parsing encountered an
     107     * error, or -1 if the source code was valid and parsed succesfully
     108     * @return true if execution should be continue, false if it should
     109     * be aborted
     110     */
     111    virtual bool sourceParsed(ExecState *exec, int sourceId,
     112                              const UString &source, int errorLine);
     113
     114    /**
     115     * Called when all functions/programs associated with a particular
     116     * sourceId have been deleted. After this function has been called for
     117     * a particular sourceId, that sourceId will not be used again.
     118     *
     119     * The default implementation does nothing. Override this method if
     120     * you want to process this event.
     121     *
     122     * @param exec The current execution state
     123     * @param sourceId The ID of the source code (corresponds to the
     124     * sourceId supplied in other functions such as atLine()
     125     * @return true if execution should be continue, false if it should
     126     * be aborted
     127     */
     128    virtual bool sourceUnused(ExecState *exec, int sourceId);
     129
     130    /**
     131     * Called when an exception is thrown during script execution.
     132     *
     133     * The default implementation does nothing. Override this method if
     134     * you want to process this event.
     135     *
     136     * @param exec The current execution state
     137     * @param sourceId The ID of the source code being executed
     138     * @param lineno The line at which the error occurred
     139     * @param exceptionObj The exception object
     140     * @return true if execution should be continue, false if it should
     141     * be aborted
     142     */
     143    virtual bool exception(ExecState *exec, int sourceId, int lineno,
     144                           Object &exceptionObj);
     145
     146    /**
     147     * Called when a line of the script is reached (before it is executed)
     148     *
     149     * The default implementation does nothing. Override this method if
     150     * you want to process this event.
     151     *
     152     * @param exec The current execution state
     153     * @param sourceId The ID of the source code being executed
     154     * @param firstLine The starting line of the statement  that is about to be
     155     * executed
     156     * @param firstLine The ending line of the statement  that is about to be
     157     * executed (usually the same as firstLine)
     158     * @return true if execution should be continue, false if it should
     159     * be aborted
     160     */
     161    virtual bool atStatement(ExecState *exec, int sourceId, int firstLine,
     162                             int lastLine);
     163    /**
     164     * Called on each function call. Use together with @ref #returnEvent
    126165     * if you want to keep track of the call stack.
    127      */
    128     virtual void callEvent(const UString &fn = UString::null,
    129                                     const UString &s = UString::null);
    130     /**
    131      * Invoked on each function exit.
    132      */
    133     virtual void returnEvent();
     166     *
     167     * Note: This only gets called for functions that are declared in ECMAScript
     168     * source code or passed to eval(), not for internal KJS or
     169     * application-supplied functions.
     170     *
     171     * The default implementation does nothing. Override this method if
     172     * you want to process this event.
     173     *
     174     * @param exec The current execution state
     175     * @param sourceId The ID of the source code being executed
     176     * @param lineno The line that is about to be executed
     177     * @param function The function being called
     178     * @param args The arguments that were passed to the function
     179     * line is being executed
     180     * @return true if execution should be continue, false if it should
     181     * be aborted
     182     */
     183    virtual bool callEvent(ExecState *exec, int sourceId, int lineno,
     184                           Object &function, const List &args);
     185
     186    /**
     187     * Called on each function exit. The function being returned from is that
     188     * which was supplied in the last callEvent().
     189     *
     190     * Note: This only gets called for functions that are declared in ECMAScript
     191     * source code or passed to eval(), not for internal KJS or
     192     * application-supplied functions.
     193     *
     194     * The default implementation does nothing. Override this method if
     195     * you want to process this event.
     196     *
     197     * @param exec The current execution state
     198     * @param sourceId The ID of the source code being executed
     199     * @param lineno The line that is about to be executed
     200     * @param function The function being called
     201     * @return true if execution should be continue, false if it should
     202     * be aborted
     203     */
     204    virtual bool returnEvent(ExecState *exec, int sourceId, int lineno,
     205                             Object &function);
    134206
    135207  private:
    136     void reset();
    137     bool hit(int line, bool breakPoint);
    138     void setSourceId(int i) { sid = i; }
    139     UString objInfo(const KJSO &obj) const;
    140 
    141     KJScript *eng;
    142     Mode dmode;
    143     int l;
    144     int sid;
     208    DebuggerImp *rep;
    145209  };
     210
     211};
     212
    146213#endif
    147 
    148 };
    149 
    150 #endif
  • trunk/JavaScriptCore/kjs/error_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"
    23 #include "internal.h"
    2427#include "error_object.h"
    25 #include "debugger.h"
     28//#include "debugger.h"
    2629
    2730using namespace KJS;
    2831
    29 const char *ErrorObject::errName[] = {
    30   "No Error",
    31   "Error",
    32   "EvalError",
    33   "RangeError",
    34   "ReferenceError",
    35   "SyntaxError",
    36   "TypeError",
    37   "URIError"
    38 };
     32// ------------------------------ ErrorPrototypeImp ----------------------------
    3933
    40 ErrorObject::ErrorObject(const Object &funcProto, const Object &errProto,
    41                          ErrorType t)
    42   : ConstructorImp(funcProto, 1), errType(t)
     34// ECMA 15.9.4
     35ErrorPrototypeImp::ErrorPrototypeImp(ExecState *exec,
     36                                     ObjectPrototypeImp *objectProto,
     37                                     FunctionPrototypeImp *funcProto)
     38  : ObjectImp(Object(objectProto))
    4339{
    44   // ECMA 15.11.3.1 Error.prototype
    45   setPrototypeProperty(errProto);
    46   const char *n = errName[errType];
     40  Value protect(this);
     41  setInternalValue(Undefined());
     42  // The constructor will be added later in ErrorObjectImp's constructor
    4743
    48   put("name", String(n));
     44  put(exec, "name",     String("Error"), DontEnum);
     45  put(exec, "message",  String("Unknown error"), DontEnum);
     46  put(exec, "toString", Object(new ErrorProtoFuncImp(exec,funcProto)), DontEnum);
    4947}
    5048
    51 ErrorObject::ErrorObject(const Object& proto, ErrorType t,
    52                          const char *m, int l)
    53   : ConstructorImp(proto, 1), errType(t)
     49// ------------------------------ ErrorProtoFuncImp ----------------------------
     50
     51ErrorProtoFuncImp::ErrorProtoFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto)
     52  : InternalFunctionImp(funcProto)
    5453{
    55   const char *n = errName[errType];
    56 
    57   put("name", String(n));
    58   put("message", String(m));
    59   put("line", Number(l));
    60 #ifdef KJS_DEBUGGER
    61   Debugger *dbg = KJScriptImp::current()->debugger();
    62   if (dbg)
    63     put("sid", Number(dbg->sourceId()));
    64 #endif
     54  Value protect(this);
     55  put(exec,"length",Number(0),DontDelete|ReadOnly|DontEnum);
    6556}
    6657
    67 // ECMA 15.9.2
    68 Completion ErrorObject::execute(const List &args)
     58bool ErrorProtoFuncImp::implementsCall() const
    6959{
    70   // "Error()" gives the sames result as "new Error()"
    71   return Completion(ReturnValue, construct(args));
     60  return true;
    7261}
    7362
    74 // ECMA 15.9.3
    75 Object ErrorObject::construct(const List &args)
     63Value ErrorProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &/*args*/)
    7664{
    77   if (args.isEmpty() == 1 || !args[0].isDefined())
    78     return Object::create(ErrorClass, Undefined());
     65  // toString()
     66  UString s = "Error";
    7967
    80   String message = args[0].toString();
    81   return Object::create(ErrorClass, message);
    82 }
     68  Value v = thisObj.get(exec,"name");
     69  if (v.type() != UndefinedType) {
     70    s = v.toString(exec);
     71  }
    8372
    84 Object ErrorObject::create(ErrorType e, const char *m, int l)
    85 {
    86   Global global(Global::current());
    87   KJSO prot = Global::current().get("[[Error.prototype]]");
    88   assert(prot.isObject());
    89   Imp *d = new ErrorObject(Object(prot.imp()), e, m, l);
    90 
    91   return Object(d);
    92 }
    93 
    94 // ECMA 15.9.4
    95 ErrorPrototype::ErrorPrototype(const Object& proto)
    96   : ObjectImp(ErrorClass, Undefined(), proto)
    97 {
    98   // The constructor will be added later in ErrorObject's constructor
    99 }
    100 
    101 KJSO ErrorPrototype::get(const UString &p) const
    102 {
    103   const char *s;
    104 
    105   /* TODO: are these properties dynamic, i.e. should we put() them ? */
    106   if (p == "name")
    107     s = "Error";
    108   else if (p == "message")
    109     s = "Error message.";
    110   else if (p == "toString")
    111     return Function(new ErrorProtoFunc());
    112   else
    113     return Imp::get(p);
     73  v = thisObj.get(exec,"message");
     74  if (v.type() != UndefinedType) {
     75    s += ": "+v.toString(exec);
     76  }
    11477
    11578  return String(s);
    11679}
    11780
    118 Completion ErrorProtoFunc::execute(const List &)
     81// ------------------------------ ErrorObjectImp -------------------------------
     82
     83ErrorObjectImp::ErrorObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto,
     84                               ErrorPrototypeImp *errorProto)
     85  : InternalFunctionImp(funcProto)
    11986{
    120   // toString()
    121   const char *s = "Error message.";
    122 
    123   return Completion(ReturnValue, String(s));
     87  Value protect(this);
     88  // ECMA 15.11.3.1 Error.prototype
     89  put(exec, "prototype", Object(errorProto), DontEnum|DontDelete|ReadOnly);
     90  //put(exec, "name", String(n));
    12491}
    12592
     93bool ErrorObjectImp::implementsConstruct() const
     94{
     95  return true;
     96}
     97
     98// ECMA 15.9.3
     99Object ErrorObjectImp::construct(ExecState *exec, const List &args)
     100{
     101  Object proto = Object::dynamicCast(exec->interpreter()->builtinErrorPrototype());
     102  Object obj(new ObjectImp(proto));
     103
     104  if (!args.isEmpty() && args[0].type() != UndefinedType) {
     105    obj.put(exec,"message", String(args[0].toString(exec)));
     106  }
     107
     108  return obj;
     109}
     110
     111bool ErrorObjectImp::implementsCall() const
     112{
     113  return true;
     114}
     115
     116// ECMA 15.9.2
     117Value ErrorObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
     118{
     119  // "Error()" gives the sames result as "new Error()"
     120  return construct(exec,args);
     121}
     122
     123// ------------------------------ NativeErrorPrototypeImp ----------------------
     124
     125NativeErrorPrototypeImp::NativeErrorPrototypeImp(ExecState *exec, ErrorPrototypeImp *errorProto,
     126                                                 ErrorType et, UString name, UString message)
     127  : ObjectImp(Object(errorProto))
     128{
     129  Value protect(this);
     130  errType = et;
     131  put(exec,"name",String(name));
     132  put(exec,"message",String(message));
     133}
     134
     135// ------------------------------ NativeErrorImp -------------------------------
     136
     137const ClassInfo NativeErrorImp::info = {"Error", &InternalFunctionImp::info, 0, 0};
     138
     139NativeErrorImp::NativeErrorImp(ExecState *exec, FunctionPrototypeImp *funcProto,
     140                               const Object &prot)
     141  : InternalFunctionImp(funcProto), proto(0)
     142{
     143  Value protect(this);
     144  proto = static_cast<ObjectImp*>(prot.imp());
     145
     146  put(exec,"length",Number(1),DontDelete|ReadOnly|DontEnum); // ECMA 15.11.7.5
     147  put(exec,"prototype",prot);
     148}
     149
     150bool NativeErrorImp::implementsConstruct() const
     151{
     152  return true;
     153}
     154
     155Object NativeErrorImp::construct(ExecState *exec, const List &args)
     156{
     157  Object obj(new ObjectImp(Object(proto)));
     158  if (args[0].type() != UndefinedType)
     159    obj.put(exec, "message", String(args[0].toString(exec)));
     160  return obj;
     161}
     162
     163bool NativeErrorImp::implementsCall() const
     164{
     165  return true;
     166}
     167
     168Value NativeErrorImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
     169{
     170  return construct(exec,args);
     171}
     172
     173void NativeErrorImp::mark()
     174{
     175  ObjectImp::mark();
     176  if (proto && !proto->marked())
     177    proto->mark();
     178}
     179
  • trunk/JavaScriptCore/kjs/error_object.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2124#define _ERROR_OBJECT_H_
    2225
    23 #include "object.h"
    24 #include "function.h"
     26#include "internal.h"
     27#include "function_object.h"
    2528
    2629namespace KJS {
    2730
    28   class ErrorObject : public ConstructorImp {
     31  class ErrorPrototypeImp : public ObjectImp {
    2932  public:
    30     ErrorObject(const Object &funcProto, const Object &errProto,
    31                 ErrorType t = GeneralError);
    32     ErrorObject(const Object& proto, ErrorType t, const char *m, int l = -1);
    33     Completion execute(const List &);
    34     Object construct(const List &);
    35     static Object create(ErrorType e, const char *m, int ln);
     33    ErrorPrototypeImp(ExecState *exec,
     34                      ObjectPrototypeImp *objectProto,
     35                      FunctionPrototypeImp *funcProto);
     36  };
     37
     38  class ErrorProtoFuncImp : public InternalFunctionImp {
     39  public:
     40    ErrorProtoFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto);
     41    virtual bool implementsCall() const;
     42    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     43  };
     44
     45  class ErrorObjectImp : public InternalFunctionImp {
     46  public:
     47    ErrorObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto,
     48                   ErrorPrototypeImp *errorProto);
     49
     50    virtual bool implementsConstruct() const;
     51    virtual Object construct(ExecState *exec, const List &args);
     52
     53    virtual bool implementsCall() const;
     54    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     55  };
     56
     57
     58
     59
     60
     61  class NativeErrorPrototypeImp : public ObjectImp {
     62  public:
     63    NativeErrorPrototypeImp(ExecState *exec, ErrorPrototypeImp *errorProto,
     64                            ErrorType et, UString name, UString message);
    3665  private:
    3766    ErrorType errType;
    38     static const char *errName[];
    3967  };
    4068
    41   class ErrorPrototype : public ObjectImp {
     69  class NativeErrorImp : public InternalFunctionImp {
    4270  public:
    43     ErrorPrototype(const Object& proto);
    44     virtual KJSO get(const UString &p) const;
    45   };
     71    NativeErrorImp(ExecState *exec, FunctionPrototypeImp *funcProto,
     72                   const Object &prot);
    4673
    47   class ErrorProtoFunc : public InternalFunctionImp {
    48   public:
    49     ErrorProtoFunc() { }
    50     Completion execute(const List &);
     74    virtual bool implementsConstruct() const;
     75    virtual Object construct(ExecState *exec, const List &args);
     76    virtual bool implementsCall() const;
     77    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     78
     79    virtual void mark();
     80
     81    virtual const ClassInfo *classInfo() const { return &info; }
     82    static const ClassInfo info;
     83  private:
     84    ObjectImp *proto;
    5185  };
    5286
  • trunk/JavaScriptCore/kjs/function.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    34 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1719 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1820 *  Boston, MA 02111-1307, USA.
     21 *
    1922 */
    2023
    2124#include "function.h"
    2225
    23 #include "kjs.h"
    24 #include "types.h"
    2526#include "internal.h"
     27#include "function_object.h"
     28#include "lexer.h"
     29#include "nodes.h"
    2630#include "operations.h"
    27 #include "nodes.h"
    28 #ifndef NDEBUG
     31#include "debugger.h"
     32
    2933#include <stdio.h>
    30 #endif
     34#include <assert.h>
     35#include <string.h>
    3136
    3237using namespace KJS;
    3338
    34 const TypeInfo FunctionImp::info = { "Function", FunctionType,
    35                                       &ObjectImp::info, 0, 0 };
    36 const TypeInfo InternalFunctionImp::info = { "InternalFunction",
    37                                               InternalFunctionType,
    38                                               &FunctionImp::info, 0, 0 };
    39 const TypeInfo ConstructorImp::info = { "Function", ConstructorType,
    40                                          &InternalFunctionImp::info, 0, 0 };
     39// ------------------------------ FunctionImp ----------------------------------
     40
     41const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0, 0};
    4142
    4243namespace KJS {
    43 
    4444  class Parameter {
    4545  public:
     
    4949    Parameter *next;
    5050  };
    51 
    5251};
    5352
    54 FunctionImp::FunctionImp()
    55   : ObjectImp(/*TODO*/BooleanClass), param(0L)
    56 {
    57 }
    58 
    59 FunctionImp::FunctionImp(const UString &n)
    60   : ObjectImp(/*TODO*/BooleanClass), ident(n), param(0L)
    61 {
     53FunctionImp::FunctionImp(ExecState *exec, const UString &n)
     54  : InternalFunctionImp(
     55      static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
     56      ), param(0L), ident(n), argStack(0)
     57{
     58  Value protect(this);
     59  argStack = new ListImp();
     60  put(exec,"arguments",Null(),ReadOnly|DontDelete|DontEnum);
    6261}
    6362
    6463FunctionImp::~FunctionImp()
    6564{
     65  argStack->setGcAllowed();
     66  // The function shouldn't be deleted while it is still executed; argStack
     67  // should be set to 0 by the last call to popArgs()
     68  assert(argStack->isEmpty());
    6669  delete param;
    6770}
    6871
    69 KJSO FunctionImp::thisValue() const
    70 {
    71   return KJSO(Context::current()->thisValue());
     72void FunctionImp::mark()
     73{
     74  InternalFunctionImp::mark();
     75  if (argStack && !argStack->marked())
     76    argStack->mark();
     77}
     78
     79bool FunctionImp::implementsCall() const
     80{
     81  return true;
     82}
     83
     84Value FunctionImp::call(ExecState *exec, Object &thisObj, const List &args)
     85{
     86  Object globalObj = exec->interpreter()->globalObject();
     87
     88  Debugger *dbg = exec->interpreter()->imp()->debugger();
     89  int sid = -1;
     90  int lineno = -1;
     91  if (dbg) {
     92    if (inherits(&DeclaredFunctionImp::info)) {
     93      sid = static_cast<DeclaredFunctionImp*>(this)->body->sourceId();
     94      lineno = static_cast<DeclaredFunctionImp*>(this)->body->firstLine();
     95    }
     96
     97    Object func(this);
     98    int cont = dbg->callEvent(exec,sid,lineno,func,args);
     99    if (!cont) {
     100      dbg->imp()->abort();
     101      return Undefined();
     102    }
     103  }
     104
     105  // enter a new execution context
     106  ContextImp *ctx = new ContextImp(globalObj, exec, thisObj,
     107                                   codeType(), exec->context().imp(), this, args);
     108  ExecState *newExec = new ExecState(exec->interpreter(),ctx);
     109  newExec->setException(exec->exception()); // could be null
     110
     111  // In order to maintain our "arguments" property, we maintain a list of arguments
     112  // properties from earlier in the execution stack. Upon return, we restore the
     113  // previous arguments object using popArgs().
     114  // Note: this does not appear to be part of the spec
     115  if (codeType() == FunctionCode) {
     116    assert(ctx->activationObject().inherits(&ActivationImp::info));
     117    Object argsObj = static_cast<ActivationImp*>(ctx->activationObject().imp())->argumentsObject();
     118    put(newExec,"arguments", argsObj, DontDelete|DontEnum|ReadOnly);
     119    pushArgs(newExec,argsObj);
     120  }
     121
     122  // assign user supplied arguments to parameters
     123  processParameters(newExec,args);
     124  // add variable declarations (initialized to undefined)
     125  processVarDecls(newExec);
     126
     127  Completion comp = execute(newExec);
     128
     129  // if an exception occured, propogate it back to the previous execution object
     130  if (newExec->hadException())
     131    exec->setException(newExec->exception());
     132  if (codeType() == FunctionCode)
     133    popArgs(newExec);
     134  delete newExec;
     135  delete ctx;
     136
     137#ifdef KJS_VERBOSE
     138  if (comp.complType() == Throw)
     139    printInfo(exec,"throwing", comp.value());
     140  else if (comp.complType() == ReturnValue)
     141    printInfo(exec,"returning", comp.value());
     142  else
     143    fprintf(stderr, "returning: undefined\n");
     144#endif
     145
     146  if (dbg) {
     147    Object func(this);
     148    int cont = dbg->returnEvent(exec,sid,lineno,func);
     149    if (!cont) {
     150      dbg->imp()->abort();
     151      return Undefined();
     152    }
     153  }
     154
     155  if (comp.complType() == Throw) {
     156    exec->setException(comp.value());
     157    return comp.value();
     158  }
     159  else if (comp.complType() == ReturnValue)
     160    return comp.value();
     161  else
     162    return Undefined();
    72163}
    73164
     
    81172}
    82173
    83 void FunctionImp::setLength(int l)
    84 {
    85   put("length", Number(l), ReadOnly|DontDelete|DontEnum);
    86 }
    87 
    88 // ECMA 10.1.3
    89 void FunctionImp::processParameters(const List *args)
    90 {
    91   KJSO variable = Context::current()->variableObject();
    92 
    93   assert(args);
     174
     175// ECMA 10.1.3q
     176void FunctionImp::processParameters(ExecState *exec, const List &args)
     177{
     178  Object variable = exec->context().imp()->variableObject();
    94179
    95180#ifdef KJS_VERBOSE
     
    100185
    101186  if (param) {
    102     ListIterator it = args->begin();
     187    ListIterator it = args.begin();
    103188    Parameter **p = &param;
    104189    while (*p) {
    105       if (it != args->end()) {
     190      if (it != args.end()) {
    106191#ifdef KJS_VERBOSE
    107192        fprintf(stderr, "setting parameter %s ", (*p)->name.ascii());
    108         printInfo("to", *it);
     193        printInfo(exec,"to", *it);
    109194#endif
    110         variable.put((*p)->name, *it);
     195        variable.put(exec,(*p)->name, *it);
    111196        it++;
    112197      } else
    113         variable.put((*p)->name, Undefined());
     198        variable.put(exec,(*p)->name, Undefined());
    114199      p = &(*p)->next;
    115200    }
     
    117202#ifdef KJS_VERBOSE
    118203  else {
    119     for (int i = 0; i < args->size(); i++)
    120       printInfo("setting argument", (*args)[i]);
     204    for (int i = 0; i < args.size(); i++)
     205      printInfo(exec,"setting argument", args[i]);
    121206  }
    122207#endif
    123 #ifdef KJS_DEBUGGER
    124   if (KJScriptImp::current()->debugger()) {
    125     UString argStr;
    126     for (int i = 0; i < args->size(); i++) {
    127       if (i > 0)
    128         argStr += ", ";
    129       Imp *a = (*args)[i].imp();
    130       argStr += a->toString().value() + " : " + UString(a->typeInfo()->name);
    131     }
    132     UString n = name().isEmpty() ? UString( "(internal)" ) : name();
    133     KJScriptImp::current()->debugger()->callEvent(n, argStr);
    134   }
    135 #endif
    136 }
    137 
    138 // ECMA 13.2.1
    139 KJSO FunctionImp::executeCall(Imp *thisV, const List *args)
    140 {
    141   return executeCall(thisV,args,0);
    142 }
    143 
    144 KJSO FunctionImp::executeCall(Imp *thisV, const List *args, const List *extraScope)
    145 {
    146   bool dummyList = false;
    147   if (!args) {
    148     args = new List();
    149     dummyList = true;
    150   }
    151 
    152   KJScriptImp *curr = KJScriptImp::current();
    153   Context *save = curr->context();
    154 
    155   Context *ctx = new Context(codeType(), save, this, args, thisV);
    156   curr->setContext(ctx);
    157 
    158   int numScopes = 0;
    159   if (extraScope) {
    160     ListIterator scopeIt = extraScope->begin();
    161     for (; scopeIt != extraScope->end(); scopeIt++) {
    162       KJSO obj(*scopeIt);
    163       ctx->pushScope(obj);
    164       numScopes++;
    165     }
    166   }
    167 
    168   // assign user supplied arguments to parameters
    169   processParameters(args);
    170 
    171   Completion comp = execute(*args);
    172 
    173   if (dummyList)
    174     delete args;
    175 
    176   int i;
    177   for (i = 0; i < numScopes; i++)
    178     ctx->popScope();
    179 
    180   put("arguments", Null());
    181   delete ctx;
    182   curr->setContext(save);
    183 
    184 #ifdef KJS_VERBOSE
    185   if (comp.complType() == Throw)
    186     printInfo("throwing", comp.value());
    187   else if (comp.complType() == ReturnValue)
    188     printInfo("returning", comp.value());
     208}
     209
     210void FunctionImp::processVarDecls(ExecState */*exec*/)
     211{
     212}
     213
     214void FunctionImp::pushArgs(ExecState *exec, const Object &args)
     215{
     216  argStack->append(args);
     217  put(exec,"arguments",args,ReadOnly|DontDelete|DontEnum);
     218}
     219
     220void FunctionImp::popArgs(ExecState *exec)
     221{
     222  argStack->removeLast();
     223  if (argStack->isEmpty()) {
     224    put(exec,"arguments",Null(),ReadOnly|DontDelete|DontEnum);
     225  }
    189226  else
    190     fprintf(stderr, "returning: undefined\n");
    191 #endif
    192 #ifdef KJS_DEBUGGER
    193   if (KJScriptImp::current()->debugger())
    194     KJScriptImp::current()->debugger()->returnEvent();
    195 #endif
    196 
    197   if (comp.complType() == Throw)
    198     return comp.value();
    199   else if (comp.complType() == ReturnValue)
    200     return comp.value();
     227    put(exec,"arguments",argStack->at(argStack->size()-1),ReadOnly|DontDelete|DontEnum);
     228}
     229
     230// ------------------------------ DeclaredFunctionImp --------------------------
     231
     232// ### is "Function" correct here?
     233const ClassInfo DeclaredFunctionImp::info = {"Function", &FunctionImp::info, 0, 0};
     234
     235DeclaredFunctionImp::DeclaredFunctionImp(ExecState *exec, const UString &n,
     236                                         FunctionBodyNode *b, const List &sc)
     237  : FunctionImp(exec,n), body(b)
     238{
     239  Value protect(this);
     240  body->ref();
     241  setScope(sc.copy());
     242}
     243
     244DeclaredFunctionImp::~DeclaredFunctionImp()
     245{
     246  if ( body->deref() )
     247    delete body;
     248}
     249
     250bool DeclaredFunctionImp::implementsConstruct() const
     251{
     252  return true;
     253}
     254
     255// ECMA 13.2.2 [[Construct]]
     256Object DeclaredFunctionImp::construct(ExecState *exec, const List &args)
     257{
     258  Object proto;
     259  Value p = get(exec,"prototype");
     260  if (p.type() == ObjectType)
     261    proto = Object(static_cast<ObjectImp*>(p.imp()));
    201262  else
    202     return Undefined();
    203 }
    204 
    205 UString FunctionImp::name() const
    206 {
    207   return ident;
    208 }
    209 
    210 InternalFunctionImp::InternalFunctionImp()
    211 {
    212 }
    213 
    214 InternalFunctionImp::InternalFunctionImp(int l)
    215 {
    216   if (l >= 0)
    217     setLength(l);
    218 }
    219 
    220 InternalFunctionImp::InternalFunctionImp(const UString &n)
    221   : FunctionImp(n)
    222 {
    223 }
    224 
    225 String InternalFunctionImp::toString() const
    226 {
    227   if (name().isNull())
    228     return UString("(Internal function)");
     263    proto = exec->interpreter()->builtinObjectPrototype();
     264
     265  Object obj(new ObjectImp(proto));
     266
     267  Value res = call(exec,obj,args);
     268
     269  if (res.type() == ObjectType)
     270    return Object::dynamicCast(res);
    229271  else
    230     return UString("function " + name() + "()");
    231 }
    232 
    233 Completion InternalFunctionImp::execute(const List &)
    234 {
    235   return Completion(ReturnValue, Undefined());
    236 }
    237 
    238 ConstructorImp::ConstructorImp() {
    239   setPrototype(Global::current().functionPrototype());
    240   // TODO ???  put("constructor", this);
    241   setLength(1);
    242 }
    243 
    244 ConstructorImp::ConstructorImp(const UString &n)
    245   : InternalFunctionImp(n)
    246 {
    247 }
    248 
    249 ConstructorImp::ConstructorImp(const KJSO &p, int len)
    250 {
    251   setPrototype(p);
    252   // TODO ???  put("constructor", *this);
    253   setLength(len);
    254 }
    255 
    256 ConstructorImp::ConstructorImp(const UString &n, const KJSO &p, int len)
    257   : InternalFunctionImp(n)
    258 {
    259   setPrototype(p);
    260   // TODO ???  put("constructor", *this);
    261   setLength(len);
    262 }
    263 
    264 ConstructorImp::~ConstructorImp() { }
    265 
    266 Completion ConstructorImp::execute(const List &)
    267 {
    268   /* TODO */
    269   return Completion(ReturnValue, Null());
    270 }
    271 
    272 Function::Function(Imp *d)
    273   : KJSO(d)
    274 {
    275   if (d) {
    276     static_cast<FunctionImp*>(rep)->attr = ImplicitNone;
    277     assert(Global::current().hasProperty("[[Function.prototype]]"));
    278     setPrototype(Global::current().functionPrototype());
    279   }
    280 }
    281 
    282 Completion Function::execute(const List &args)
    283 {
    284   assert(rep);
    285   return static_cast<FunctionImp*>(rep)->execute(args);
    286 }
    287 
    288 bool Function::hasAttribute(FunctionAttribute a) const
    289 {
    290   assert(rep);
    291   return static_cast<FunctionImp*>(rep)->hasAttribute(a);
    292 }
    293 
    294 #if 0
    295 InternalFunction::InternalFunction(Imp *d)
    296   : Function(d)
    297 {
    298   param = 0L;
    299 }
    300 
    301 InternalFunction::~InternalFunction()
    302 {
    303 }
    304 #endif
    305 
    306 Constructor::Constructor(Imp *d)
    307   : Function(d)
    308 {
    309   if (d) {
    310     assert(Global::current().hasProperty("[[Function.prototype]]"));
    311     setPrototype(Global::current().get("[[Function.prototype]]"));
    312     put("constructor", *this);
    313     KJSO tmp(d); // protect from GC
    314     ((FunctionImp*)d)->setLength(1);
    315   }
    316 }
    317 
    318 #if 0
    319 Constructor::Constructor(const Object& proto, int len)
    320 {
    321   setPrototype(proto);
    322   put("constructor", *this);
    323   put("length", len, DontEnum);
    324 }
    325 #endif
    326 
    327 Constructor::~Constructor()
    328 {
    329 }
    330 
    331 Completion Constructor::execute(const List &)
    332 {
    333   /* TODO: call construct instead ? */
    334   return Completion(ReturnValue, Undefined());
    335 }
    336 
    337 Object Constructor::construct(const List &args)
    338 {
    339   assert(rep && rep->type() == ConstructorType);
    340   return ((ConstructorImp*)rep)->construct(args);
    341 }
    342 
    343 Constructor Constructor::dynamicCast(const KJSO &obj)
    344 {
    345   // return null object on type mismatch
    346   if (!obj.isA(ConstructorType))
    347     return Constructor(0L);
    348 
    349   return Constructor(obj.imp());
    350 }
    351 
    352 KJSO Function::thisValue() const
    353 {
    354   return KJSO(Context::current()->thisValue());
    355 }
     272    return obj;
     273}
     274
     275Completion DeclaredFunctionImp::execute(ExecState *exec)
     276{
     277  Completion result = body->execute(exec);
     278
     279  if (result.complType() == Throw || result.complType() == ReturnValue)
     280      return result;
     281  return Completion(Normal, Undefined()); // TODO: or ReturnValue ?
     282}
     283
     284void DeclaredFunctionImp::processVarDecls(ExecState *exec)
     285{
     286  body->processVarDecls(exec);
     287}
     288
     289// ------------------------------ ArgumentsImp ---------------------------------
     290
     291const ClassInfo ArgumentsImp::info = {"Arguments", 0, 0, 0};
     292
     293// ECMA 10.1.8
     294ArgumentsImp::ArgumentsImp(ExecState *exec, FunctionImp *func, const List &args)
     295  : ObjectImp(exec->interpreter()->builtinObjectPrototype())
     296{
     297  Value protect(this);
     298  put(exec,"callee", Object(func), DontEnum);
     299  put(exec,"length", Number(args.size()), DontEnum);
     300  if (!args.isEmpty()) {
     301    ListIterator arg = args.begin();
     302    for (int i = 0; arg != args.end(); arg++, i++) {
     303      put(exec,UString::from(i), *arg, DontEnum);
     304    }
     305  }
     306}
     307
     308// ------------------------------ ActivationImp --------------------------------
     309
     310const ClassInfo ActivationImp::info = {"Activation", 0, 0, 0};
     311
     312// ECMA 10.1.6
     313ActivationImp::ActivationImp(ExecState *exec, FunctionImp *f, const List &args)
     314  : ObjectImp()
     315{
     316  Value protect(this);
     317  arguments = new ArgumentsImp(exec,f, args);
     318  put(exec, "arguments", Object(arguments), Internal|DontDelete);
     319}
     320
     321ActivationImp::~ActivationImp()
     322{
     323  arguments->setGcAllowed();
     324}
     325
     326// ------------------------------ GlobalFunc -----------------------------------
     327
     328
     329GlobalFuncImp::GlobalFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, int i, int len)
     330  : InternalFunctionImp(funcProto), id(i)
     331{
     332  Value protect(this);
     333  put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
     334}
     335
     336CodeType GlobalFuncImp::codeType() const
     337{
     338  return id == Eval ? EvalCode : codeType();
     339}
     340
     341bool GlobalFuncImp::implementsCall() const
     342{
     343  return true;
     344}
     345
     346Value GlobalFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
     347{
     348  Value res;
     349
     350  static const char non_escape[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     351                                   "abcdefghijklmnopqrstuvwxyz"
     352                                   "0123456789@*_+-./";
     353
     354  if (id == Eval) { // eval()
     355    Value x = args[0];
     356    if (x.type() != StringType)
     357      return x;
     358    else {
     359      UString s = x.toString(exec);
     360
     361      int sid;
     362      int errLine;
     363      UString errMsg;
     364      ProgramNode *progNode = Parser::parse(s.data(),s.size(),&sid,&errLine,&errMsg);
     365
     366      // no program node means a syntax occurred
     367      if (!progNode) {
     368        Object err = Error::create(exec,SyntaxError,errMsg.ascii(),errLine);
     369        err.put(exec,"sid",Number(sid));
     370        exec->setException(err);
     371        return err;
     372      }
     373
     374      progNode->ref();
     375
     376      // enter a new execution context
     377      Object glob(exec->interpreter()->globalObject());
     378      Object thisVal(Object::dynamicCast(exec->context().thisValue()));
     379      ContextImp *ctx = new ContextImp(glob,
     380                                       exec,
     381                                       thisVal,
     382                                       EvalCode,
     383                                       exec->context().imp());
     384
     385      ExecState *newExec = new ExecState(exec->interpreter(),ctx);
     386      newExec->setException(exec->exception()); // could be null
     387
     388      // execute the code
     389      Completion c = progNode->execute(newExec);
     390
     391      // if an exception occured, propogate it back to the previous execution object
     392      if (newExec->hadException())
     393        exec->setException(newExec->exception());
     394      delete newExec;
     395      delete ctx;
     396
     397      if ( progNode->deref() )
     398          delete progNode;
     399      if (c.complType() == ReturnValue)
     400          return c;
     401      // ### setException() on throw?
     402      else if (c.complType() == Normal) {
     403          if (c.isValueCompletion())
     404              return c.value();
     405          else
     406              return Undefined();
     407      } else
     408          return c;
     409    }
     410  } else if (id == ParseInt) {
     411    String str = args[0].toString(exec);
     412    int radix = args[1].toInt32(exec);
     413    if (radix == 0)
     414      radix = 10;
     415    else if (radix < 2 || radix > 36) {
     416      res = Number(NaN);
     417      return res;
     418    }
     419    /* TODO: use radix */
     420    // Can't use toULong(), we want to accept floating point values too
     421    double value = str.value().toDouble( true /*tolerant*/ );
     422    if ( isNaN(value) )
     423        res = Number(NaN);
     424    else
     425        res = Number(static_cast<long>(value)); // remove floating-point part
     426  } else if (id == ParseFloat) {
     427    String str = args[0].toString(exec);
     428    res = Number(str.value().toDouble( true /*tolerant*/ ));
     429  } else if (id == IsNaN) {
     430    res = Boolean(isNaN(args[0].toNumber(exec)));
     431  } else if (id == IsFinite) {
     432    Number n = args[0].toNumber(exec);
     433    res = Boolean(!n.isNaN() && !n.isInf());
     434  } else if (id == Escape) {
     435    UString r = "", s, str = args[0].toString(exec);
     436    const UChar *c = str.data();
     437    for (int k = 0; k < str.size(); k++, c++) {
     438      int u = c->unicode();
     439      if (u > 255) {
     440        char tmp[7];
     441        sprintf(tmp, "%%u%04X", u);
     442        s = UString(tmp);
     443      } else if (strchr(non_escape, (char)u)) {
     444        s = UString(c, 1);
     445      } else {
     446        char tmp[4];
     447        sprintf(tmp, "%%%02X", u);
     448        s = UString(tmp);
     449      }
     450      r += s;
     451    }
     452    res = String(r);
     453  } else if (id == UnEscape) {
     454    UString s, str = args[0].toString(exec);
     455    int k = 0, len = str.size();
     456    while (k < len) {
     457      const UChar *c = str.data() + k;
     458      UChar u;
     459      if (*c == UChar('%') && k <= len - 6 && *(c+1) == UChar('u')) {
     460        u = Lexer::convertUnicode((c+2)->unicode(), (c+3)->unicode(),
     461                                  (c+4)->unicode(), (c+5)->unicode());
     462        c = &u;
     463        k += 5;
     464      } else if (*c == UChar('%') && k <= len - 3) {
     465        u = UChar(Lexer::convertHex((c+1)->unicode(), (c+2)->unicode()));
     466        c = &u;
     467        k += 2;
     468      }
     469      k++;
     470      s += UString(c, 1);
     471    }
     472    res = String(s);
     473  }
     474
     475  return res;
     476}
  • trunk/JavaScriptCore/kjs/function.h

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
     
    1718 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1819 *  Boston, MA 02111-1307, USA.
     20 *
     21 *  $Id$
    1922 */
    2023
     
    2225#define _KJS_FUNCTION_H_
    2326
    24 #include <assert.h>
    25 
    26 #include "object.h"
    27 #include "types.h"
     27#include "internal.h"
    2828
    2929namespace KJS {
    3030
    31   enum CodeType { GlobalCode,
    32                   EvalCode,
    33                   FunctionCode,
    34                   AnonymousCode,
    35                   HostCode };
    36 
    37   enum FunctionAttribute { ImplicitNone, ImplicitThis, ImplicitParents };
    38 
    39   class Function;
    4031  class Parameter;
    4132
    4233  /**
    43    * @short Implementation class for Functions.
     34   * @short Implementation class for internal Functions.
    4435   */
    45   class FunctionImp : public ObjectImp {
     36  class FunctionImp : public InternalFunctionImp {
    4637    friend class Function;
     38    friend class ActivationImp;
    4739  public:
    48     FunctionImp();
    49     FunctionImp(const UString &n);
     40    FunctionImp(ExecState *exec, const UString &n = UString::null);
    5041    virtual ~FunctionImp();
    51     virtual const TypeInfo* typeInfo() const { return &info; }
    52     static const TypeInfo info;
    53     virtual Completion execute(const List &) = 0;
    54     bool hasAttribute(FunctionAttribute a) const { return (attr & a) != 0; }
     42
     43    virtual void mark();
     44
     45    virtual bool implementsCall() const;
     46    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     47
     48    void addParameter(const UString &n);
    5549    virtual CodeType codeType() const = 0;
    56     KJSO thisValue() const;
    57     void addParameter(const UString &n);
    58     void setLength(int l);
    59     KJSO executeCall(Imp *thisV, const List *args);
    60     KJSO executeCall(Imp *thisV, const List *args, const List *extraScope);
    61     UString name() const;
     50
     51    virtual Completion execute(ExecState *exec) = 0;
     52    UString name() const { return ident; }
     53
     54    virtual const ClassInfo *classInfo() const { return &info; }
     55    static const ClassInfo info;
    6256  protected:
     57    Parameter *param;
    6358    UString ident;
    64     FunctionAttribute attr;
    65     Parameter *param;
     59
    6660  private:
    67     void processParameters(const List *);
     61    void processParameters(ExecState *exec, const List &);
     62    virtual void processVarDecls(ExecState *exec);
     63
     64    void pushArgs(ExecState *exec, const Object &args);
     65    void popArgs(ExecState *exec);
     66    ListImp *argStack;
    6867  };
    6968
    70   /**
    71    * @short Abstract base class for internal functions.
    72    */
    73   class InternalFunctionImp : public FunctionImp {
     69  class DeclaredFunctionImp : public FunctionImp {
    7470  public:
    75     InternalFunctionImp();
    76     InternalFunctionImp(int l);
    77     InternalFunctionImp(const UString &n);
    78     virtual ~InternalFunctionImp() { }
    79     virtual String toString() const;
    80     virtual KJSO toPrimitive(Type) const { return toString(); }
    81     virtual const TypeInfo* typeInfo() const { return &info; }
    82     static const TypeInfo info;
    83     virtual Completion execute(const List &);
    84     virtual CodeType codeType() const { return HostCode; }
     71    DeclaredFunctionImp(ExecState *exec, const UString &n,
     72                        FunctionBodyNode *b, const List &sc);
     73    ~DeclaredFunctionImp();
     74
     75    bool implementsConstruct() const;
     76    Object construct(ExecState *exec, const List &args);
     77
     78    virtual Completion execute(ExecState *exec);
     79    CodeType codeType() const { return FunctionCode; }
     80    FunctionBodyNode *body;
     81
     82    virtual const ClassInfo *classInfo() const { return &info; }
     83    static const ClassInfo info;
     84  private:
     85    virtual void processVarDecls(ExecState *exec);
    8586  };
    8687
    87   /**
    88    * @short Base class for Function objects.
    89    */
    90   class Function : public KJSO {
     88
     89
     90
     91  class ArgumentsImp : public ObjectImp {
    9192  public:
    92     Function(Imp *);
    93     virtual ~Function() { }
    94     Completion execute(const List &);
    95     bool hasAttribute(FunctionAttribute a) const;
    96     CodeType codeType() const { return HostCode; }
    97     KJSO thisValue() const;
    98   };
    99  
    100   /**
    101    * @short Implementation class for Constructors.
    102    */
    103   class ConstructorImp : public InternalFunctionImp {
    104   public:
    105     ConstructorImp();
    106     ConstructorImp(const UString &n);   /* TODO: add length */
    107     ConstructorImp(const KJSO &, int);
    108     ConstructorImp(const UString &n, const KJSO &p, int len);
    109     virtual ~ConstructorImp();
    110     virtual const TypeInfo* typeInfo() const { return &info; }
    111     static const TypeInfo info;
    112     virtual Completion execute(const List &);
    113     virtual Object construct(const List &) = 0;
     93    ArgumentsImp(ExecState *exec, FunctionImp *func, const List &args);
     94
     95    virtual const ClassInfo *classInfo() const { return &info; }
     96    static const ClassInfo info;
    11497  };
    11598
    116   /**
    117     * @short Constructor object for use with the 'new' operator
    118     */
    119   class Constructor : public Function {
     99  class ActivationImp : public ObjectImp {
    120100  public:
    121     Constructor(Imp *);
    122     virtual ~Constructor();
    123     //    Constructor(const Object& proto, int len);
    124     /**
    125      * @return @ref ConstructorType
    126      */
    127     Completion execute(const List &);
    128     Object construct(const List &args);
    129     static Constructor dynamicCast(const KJSO &obj);
     101    ActivationImp(ExecState *exec, FunctionImp *f, const List &args);
     102    ~ActivationImp();
     103
     104    Object argumentsObject() { return Object(arguments); }
     105
     106    virtual const ClassInfo *classInfo() const { return &info; }
     107    static const ClassInfo info;
     108  private:
     109    ObjectImp* arguments;
    130110  };
     111
     112  class GlobalFuncImp : public InternalFunctionImp {
     113  public:
     114    GlobalFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, int i, int len);
     115    virtual bool implementsCall() const;
     116    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     117    virtual CodeType codeType() const;
     118    enum { Eval, ParseInt, ParseFloat, IsNaN, IsFinite, Escape, UnEscape };
     119  private:
     120    int id;
     121  };
     122
     123
    131124
    132125}; // namespace
  • trunk/JavaScriptCore/kjs/function_object.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    3  *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     4 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
    45 *
    56 *  This library is free software; you can redistribute it and/or
     
    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
    2022#include "function_object.h"
    21 
     23#include "internal.h"
     24#include "function.h"
     25#include "array_object.h"
     26#include "nodes.h"
    2227#include "lexer.h"
    23 #include "nodes.h"
    24 #include "error_object.h"
    25 
    26 extern int kjsyyparse();
     28#include "debugger.h"
     29#include "object.h"
     30
     31#include <assert.h>
     32#include <stdio.h>
     33#include <string.h>
    2734
    2835using namespace KJS;
    2936
    30 FunctionObject::FunctionObject(const Object& funcProto)
    31   : ConstructorImp(funcProto, 1)
    32 {
    33   // ECMA 15.3.3.1 Function.prototype
    34   setPrototypeProperty(funcProto);
    35 }
    36 
    37 // ECMA 15.3.1 The Function Constructor Called as a Function
    38 Completion FunctionObject::execute(const List &args)
    39 {
    40   return Completion(ReturnValue, construct(args));
     37// ------------------------------ FunctionPrototypeImp -------------------------
     38
     39FunctionPrototypeImp::FunctionPrototypeImp(ExecState *exec)
     40  : InternalFunctionImp(0)
     41{
     42  Value protect(this);
     43  put(exec, "toString", Object(new FunctionProtoFuncImp(exec, this, FunctionProtoFuncImp::ToString, 0)), DontEnum);
     44  put(exec, "apply",    Object(new FunctionProtoFuncImp(exec, this, FunctionProtoFuncImp::Apply,    2)), DontEnum);
     45  put(exec, "call",     Object(new FunctionProtoFuncImp(exec, this, FunctionProtoFuncImp::Call,     1)), DontEnum);
     46}
     47
     48FunctionPrototypeImp::~FunctionPrototypeImp()
     49{
     50}
     51
     52bool FunctionPrototypeImp::implementsCall() const
     53{
     54  return true;
     55}
     56
     57// ECMA 15.3.4
     58Value FunctionPrototypeImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/)
     59{
     60  return Undefined();
     61}
     62
     63// ------------------------------ FunctionProtoFuncImp -------------------------
     64
     65FunctionProtoFuncImp::FunctionProtoFuncImp(ExecState *exec,
     66                                         FunctionPrototypeImp *funcProto, int i, int len)
     67  : InternalFunctionImp(funcProto), id(i)
     68{
     69  Value protect(this);
     70  put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
     71}
     72
     73
     74bool FunctionProtoFuncImp::implementsCall() const
     75{
     76  return true;
     77}
     78
     79Value FunctionProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
     80{
     81  Value result;
     82
     83  switch (id) {
     84  case ToString: {
     85    // ### also make this work for internal functions
     86    // ### return the text of the function body (see 15.3.4.2)
     87    if (thisObj.isNull() || !thisObj.inherits(&InternalFunctionImp::info)) {
     88#ifndef NDEBUG
     89      fprintf(stderr,"attempted toString() call on null or non-function object\n");
     90#endif
     91      Object err = Error::create(exec,TypeError);
     92      exec->setException(err);
     93      return err;
     94    }
     95    if (thisObj.inherits(&FunctionImp::info) &&
     96        !static_cast<FunctionImp*>(thisObj.imp())->name().isNull()) {
     97      result = String("function " + static_cast<FunctionImp*>(thisObj.imp())->name() + "()");
     98    }
     99    else {
     100      result = String("(Internal function)");
     101    }
     102    }
     103    break;
     104  case Apply: {
     105    Value thisArg = args[0];
     106    Value argArray = args[1];
     107    Object func = thisObj;
     108
     109    if (!func.implementsCall()) {
     110      Object err = Error::create(exec,TypeError);
     111      exec->setException(err);
     112      return err;
     113    }
     114
     115    Object applyThis;
     116    if (thisArg.isA(NullType) || thisArg.isA(UndefinedType))
     117      applyThis = exec->interpreter()->globalObject();
     118    else
     119      applyThis = thisArg.toObject(exec);
     120
     121    List applyArgs;
     122    if (!argArray.isA(NullType) && !argArray.isA(UndefinedType)) {
     123      if ((argArray.isA(ObjectType) &&
     124           Object::dynamicCast(argArray).inherits(&ArrayInstanceImp::info)) ||
     125           Object::dynamicCast(argArray).inherits(&ArgumentsImp::info)) {
     126
     127        Object argArrayObj = Object::dynamicCast(argArray);
     128        unsigned int length = argArrayObj.get(exec,"length").toUInt32(exec);
     129        for (uint i = 0; i < length; i++)
     130          applyArgs.append(argArrayObj.get(exec,UString::from(i)));
     131      }
     132      else {
     133        Object err = Error::create(exec,TypeError);
     134        exec->setException(err);
     135        return err;
     136      }
     137    }
     138    result = func.call(exec,applyThis,applyArgs);
     139    }
     140    break;
     141  case Call: {
     142    Value thisArg = args[0];
     143    Object func = thisObj;
     144
     145    if (!func.implementsCall()) {
     146      Object err = Error::create(exec,TypeError);
     147      exec->setException(err);
     148      return err;
     149    }
     150
     151    Object callThis;
     152    if (thisArg.isA(NullType) || thisArg.isA(UndefinedType))
     153      callThis = exec->interpreter()->globalObject();
     154    else
     155      callThis = thisArg.toObject(exec);
     156
     157    List callArgs = args.copy();
     158    callArgs.removeFirst();
     159    result = func.call(exec,callThis,callArgs);
     160    }
     161    break;
     162  }
     163
     164  return result;
     165}
     166
     167// ------------------------------ FunctionObjectImp ----------------------------
     168
     169FunctionObjectImp::FunctionObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto)
     170  : InternalFunctionImp(funcProto)
     171{
     172  Value protect(this);
     173  put(exec,"prototype", Object(funcProto), DontEnum|DontDelete|ReadOnly);
     174
     175  // no. of arguments for constructor
     176  put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum);
     177}
     178
     179FunctionObjectImp::~FunctionObjectImp()
     180{
     181}
     182
     183bool FunctionObjectImp::implementsConstruct() const
     184{
     185  return true;
    41186}
    42187
    43188// ECMA 15.3.2 The Function Constructor
    44 Object FunctionObject::construct(const List &args)
     189Object FunctionObjectImp::construct(ExecState *exec, const List &args)
    45190{
    46191  UString p("");
     
    50195    body = "";
    51196  } else if (argsSize == 1) {
    52     body = args[0].toString().value();
     197    body = args[0].toString(exec);
    53198  } else {
    54     p = args[0].toString().value();
     199    p = args[0].toString(exec);
    55200    for (int k = 1; k < argsSize - 1; k++)
    56       p += "," + args[k].toString().value();
    57     body = args[argsSize-1].toString().value();
    58   }
    59 
    60   Lexer::curr()->setCode(body.data(), body.size());
    61 
    62   KJScriptImp::current()->pushStack();
    63   int yp = kjsyyparse();
    64   ProgramNode *progNode = KJScriptImp::current()->progNode();
    65   KJScriptImp::current()->popStack();
    66   if (yp) {
    67     /* TODO: free nodes */
    68     return ErrorObject::create(SyntaxError,
    69                                I18N_NOOP("Syntax error in function body"), -1);
     201      p += "," + args[k].toString(exec);
     202    body = args[argsSize-1].toString(exec);
     203  }
     204
     205  // parse the source code
     206  int sid;
     207  int errLine;
     208  UString errMsg;
     209  ProgramNode *progNode = Parser::parse(body.data(),body.size(),&sid,&errLine,&errMsg);
     210
     211  // notify debugger that source has been parsed
     212  Debugger *dbg = exec->interpreter()->imp()->debugger();
     213  if (dbg) {
     214    bool cont = dbg->sourceParsed(exec,sid,body,errLine);
     215    if (!cont) {
     216      dbg->imp()->abort();
     217      return Object(new ObjectImp());
     218    }
     219  }
     220
     221  // no program node == syntax error - throw a syntax error
     222  if (!progNode) {
     223    Object err = Error::create(exec,SyntaxError,errMsg.ascii(),errLine);
     224    // we can't return a Completion(Throw) here, so just set the exception
     225    // and return it
     226    exec->setException(err);
     227    return err;
    70228  }
    71229
    72230  List scopeChain;
    73   scopeChain.append(Global::current());
     231  scopeChain.append(exec->interpreter()->globalObject());
    74232  FunctionBodyNode *bodyNode = progNode;
    75   FunctionImp *fimp = new DeclaredFunctionImp(UString::null, bodyNode,
    76                                               &scopeChain);
     233
     234  FunctionImp *fimp = new DeclaredFunctionImp(exec, UString::null, bodyNode,
     235                                              scopeChain);
    77236  Object ret(fimp); // protect from GC
    78237
     
    106265          } // else error
    107266      }
    108       return ErrorObject::create(SyntaxError,
     267      Object err = Error::create(exec,SyntaxError,
    109268                                 I18N_NOOP("Syntax error in parameter list"),
    110269                                 -1);
    111   }
    112 
    113   fimp->setLength(params);
    114   fimp->setPrototypeProperty(Global::current().functionPrototype());
     270      exec->setException(err);
     271      return err;
     272  }
     273
     274  fimp->put(exec,"length", Number(params),ReadOnly|DontDelete|DontEnum);
     275  List consArgs;
     276
     277  Object objCons = exec->interpreter()->builtinObject();
     278  Object prototype = objCons.construct(exec,List::empty());
     279  prototype.put(exec, "constructor",
     280                Object(fimp), DontEnum|DontDelete|ReadOnly);
     281  fimp->put(exec,"prototype",prototype,DontEnum|DontDelete|ReadOnly);
     282  fimp->put(exec,"arguments",Null(),DontEnum|DontDelete|ReadOnly);
    115283  return ret;
    116284}
    117285
    118 FunctionPrototype::FunctionPrototype(const Object &p)
    119     : ObjectImp(FunctionClass, Null(), p)
    120 {
    121 }
     286bool FunctionObjectImp::implementsCall() const
     287{
     288  return true;
     289}
     290
     291// ECMA 15.3.1 The Function Constructor Called as a Function
     292Value FunctionObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
     293{
     294  return construct(exec,args);
     295}
     296
  • trunk/JavaScriptCore/kjs/function_object.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2124#define _FUNCTION_OBJECT_H_
    2225
    23 #include "object.h"
     26#include "internal.h"
     27#include "object_object.h"
    2428#include "function.h"
    2529
    2630namespace KJS {
    2731
    28   class FunctionPrototype : public ObjectImp {
     32  /**
     33   * @internal
     34   *
     35   * The initial value of Function.prototype (and thus all objects created
     36   * with the Function constructor
     37   */
     38  class FunctionPrototypeImp : public InternalFunctionImp {
    2939  public:
    30     FunctionPrototype(const Object &p);
     40    FunctionPrototypeImp(ExecState *exec);
     41    virtual ~FunctionPrototypeImp();
     42
     43    virtual bool implementsCall() const;
     44    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
    3145  };
    3246
    33   class FunctionObject : public ConstructorImp {
     47  /**
     48   * @internal
     49   *
     50   * Class to implement all methods that are properties of the
     51   * Function.prototype object
     52   */
     53  class FunctionProtoFuncImp : public InternalFunctionImp {
    3454  public:
    35     FunctionObject(const Object &funcProto);
    36     Completion execute(const List &);
    37     Object construct(const List &);
     55    FunctionProtoFuncImp(ExecState *exec,
     56                        FunctionPrototypeImp *funcProto, int i, int len);
     57
     58    virtual bool implementsCall() const;
     59    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     60
     61    enum { ToString, Apply, Call };
     62  private:
     63    int id;
     64  };
     65
     66  /**
     67   * @internal
     68   *
     69   * The initial value of the the global variable's "Function" property
     70   */
     71  class FunctionObjectImp : public InternalFunctionImp {
     72  public:
     73    FunctionObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto);
     74    virtual ~FunctionObjectImp();
     75
     76    virtual bool implementsConstruct() const;
     77    virtual Object construct(ExecState *exec, const List &args);
     78    virtual bool implementsCall() const;
     79    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
    3880  };
    3981
    4082}; // namespace
    4183
    42 #endif
     84#endif // _FUNCTION_OBJECT_H_
  • trunk/JavaScriptCore/kjs/grammar.y

    r6 r798  
    1818 *  License along with this library; if not, write to the Free Software
    1919 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     20 *
     21 *  $Id$
    2022 */
    2123
     
    2426#endif
    2527#include <string.h>
    26 #include "kjs.h"
     28#include <stdlib.h>
     29#include "value.h"
     30#include "object.h"
     31#include "types.h"
     32#include "interpreter.h"
    2733#include "nodes.h"
    2834#include "lexer.h"
     35#include "internal.h"
    2936
    3037/* default values for bison */
    3138#define YYDEBUG 0
    3239#define YYMAXDEPTH 0
    33 #ifdef KJS_DEBUGGER
     40#ifdef APPLE_CHANGES
     41#else
    3442#define YYERROR_VERBOSE
    35 #define DBG(l, s, e) { l->setLoc(s.first_line, e.last_line); } // location
    36 #else
    37 #undef YYLSP_NEEDED
    38 #define DBG(l, s, e)
    3943#endif
     44#define DBG(l, s, e) { l->setLoc(s.first_line, e.last_line, Parser::sid); } // location
    4045
    4146extern int yylex();
     
    111116
    112117/* automatically inserted semicolon */
    113 %token AUTO
     118%token AUTOPLUSPLUS AUTOMINUSMINUS
    114119
    115120/* non-terminal types */
     
    163168                                     if (!l->scanRegExp()) YYABORT;
    164169                                     $$ = new RegExpNode(l->pattern,l->flags);}
     170  | DIVEQUAL /* a RegExp starting with /= ! */
     171                                   { Lexer *l = Lexer::curr();
     172                                     if (!l->scanRegExp()) YYABORT;
     173                                     $$ = new RegExpNode(UString('=')+l->pattern,l->flags);}
    165174;
    166175
     
    259268  | TYPEOF UnaryExpr               { $$ = new TypeOfNode($2); }
    260269  | PLUSPLUS UnaryExpr             { $$ = new PrefixNode(OpPlusPlus, $2); }
    261   | AUTO PLUSPLUS UnaryExpr        { $$ = new PrefixNode(OpPlusPlus, $3); }
     270  | AUTOPLUSPLUS UnaryExpr         { $$ = new PrefixNode(OpPlusPlus, $2); }
    262271  | MINUSMINUS UnaryExpr           { $$ = new PrefixNode(OpMinusMinus, $2); }
    263   | AUTO MINUSMINUS UnaryExpr      { $$ = new PrefixNode(OpMinusMinus, $3); }
     272  | AUTOMINUSMINUS UnaryExpr       { $$ = new PrefixNode(OpMinusMinus, $2); }
    264273  | '+' UnaryExpr                  { $$ = new UnaryPlusNode($2); }
    265274  | '-' UnaryExpr                  { $$ = new NegateNode($2); }
     
    390399Block:
    391400    '{' '}'                        { $$ = new BlockNode(0L); DBG($$, @2, @2); }
    392   | '{' StatementList '}'          { $$ = new BlockNode($2); DBG($$, @3, @3); }
     401  | '{' SourceElements '}'          { $$ = new BlockNode($2); DBG($$, @3, @3); }
    393402;
    394403
     
    597606
    598607FunctionBody:
    599     '{' '}'  /* TODO: spec ??? */  { $$ = new FunctionBodyNode(0L); }
    600   | '{' SourceElements '}'         { $$ = new FunctionBodyNode($2); }
     608    '{' '}'  /* TODO: spec ??? */  { $$ = new FunctionBodyNode(0L);
     609                                     DBG($$, @1, @2);}
     610  | '{' SourceElements '}'         { $$ = new FunctionBodyNode($2);
     611                                     DBG($$, @1, @3);}
    601612;
    602613
    603614Program:
    604     SourceElements                 { $$ = new ProgramNode($1);
    605                                      KJScriptImp::current()->setProgNode($$); }
     615    /* nothing, empty script */      { $$ = new ProgramNode(0L);
     616                                     Parser::progNode = $$; }
     617    | SourceElements                 { $$ = new ProgramNode($1);
     618                                     Parser::progNode = $$; }
    606619;
    607620
  • trunk/JavaScriptCore/kjs/internal.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    34 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1719 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1820 *  Boston, MA 02111-1307, USA.
     21 *
    1922 */
    2023
     24#include <stdio.h>
     25#include <math.h>
     26#include <assert.h>
     27#ifndef NDEBUG
     28#include <strings.h>      // for strdup
     29#endif
     30
     31#include "array_object.h"
     32#include "bool_object.h"
     33#include "collector.h"
     34#include "date_object.h"
     35#include "debugger.h"
     36#include "error_object.h"
     37#include "function_object.h"
    2138#include "internal.h"
    22 
    23 #include <assert.h>
    24 #include <stdio.h>
    25 
    26 #include "kjs.h"
     39#include "lexer.h"
     40#include "math_object.h"
     41#include "nodes.h"
     42#include "number_object.h"
    2743#include "object.h"
    28 #include "types.h"
     44#include "object_object.h"
    2945#include "operations.h"
    30 #include "regexp.h"
    31 #include "nodes.h"
    32 #include "lexer.h"
    33 #include "collector.h"
    34 #include "debugger.h"
     46#include "regexp_object.h"
     47#include "string_object.h"
    3548
    3649#define I18N_NOOP(s) s
     
    4053using namespace KJS;
    4154
    42 const TypeInfo UndefinedImp::info = { "Undefined", UndefinedType, 0, 0, 0 };
    43 const TypeInfo NullImp::info = { "Null", NullType, 0, 0, 0 };
    44 const TypeInfo NumberImp::info = { "Number", NumberType, 0, 0,0  };
    45 const TypeInfo StringImp::info = { "String", StringType, 0, 0, 0 };
    46 const TypeInfo BooleanImp::info = { "Boolean", BooleanType, 0, 0, 0 };
    47 const TypeInfo CompletionImp::info = { "Completion", CompletionType, 0, 0, 0 };
    48 const TypeInfo ReferenceImp::info = { "Reference", ReferenceType, 0, 0, 0 };
     55namespace KJS {
     56#ifdef WORDS_BIGENDIAN
     57  unsigned char NaN_Bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
     58  unsigned char Inf_Bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
     59#elif defined(arm)
     60  unsigned char NaN_Bytes[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 };
     61  unsigned char Inf_Bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 };
     62#else
     63  unsigned char NaN_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
     64  unsigned char Inf_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
     65#endif
     66
     67  const double NaN = *(const double*) NaN_Bytes;
     68  const double Inf = *(const double*) Inf_Bytes;
     69};
     70
     71// ------------------------------ UndefinedImp ---------------------------------
    4972
    5073UndefinedImp *UndefinedImp::staticUndefined = 0;
    5174
    52 UndefinedImp::UndefinedImp()
    53 {
    54 }
    55 
    56 KJSO UndefinedImp::toPrimitive(Type) const
    57 {
    58   return (Imp*)this;
    59 }
    60 
    61 Boolean UndefinedImp::toBoolean() const
    62 {
    63   return Boolean(false);
    64 }
    65 
    66 Number UndefinedImp::toNumber() const
    67 {
    68   return Number(NaN);
    69 }
    70 
    71 String UndefinedImp::toString() const
    72 {
    73   return String("undefined");
    74 }
    75 
    76 Object UndefinedImp::toObject() const
    77 {
    78   return Error::createObject(TypeError, I18N_NOOP("Undefined value"));
    79 }
     75Value UndefinedImp::toPrimitive(ExecState */*exec*/, Type) const
     76{
     77  return Value((ValueImp*)this);
     78}
     79
     80bool UndefinedImp::toBoolean(ExecState */*exec*/) const
     81{
     82  return false;
     83}
     84
     85double UndefinedImp::toNumber(ExecState */*exec*/) const
     86{
     87  return NaN;
     88}
     89
     90UString UndefinedImp::toString(ExecState */*exec*/) const
     91{
     92  return "undefined";
     93}
     94
     95Object UndefinedImp::toObject(ExecState *exec) const
     96{
     97  Object err = Error::create(exec, TypeError, I18N_NOOP("Undefined value"));
     98  exec->setException(err);
     99  return err;
     100}
     101
     102// ------------------------------ NullImp --------------------------------------
    80103
    81104NullImp *NullImp::staticNull = 0;
    82105
    83 NullImp::NullImp()
    84 {
    85 }
    86 
    87 KJSO NullImp::toPrimitive(Type) const
    88 {
    89   return (Imp*)this;
    90 }
    91 
    92 Boolean NullImp::toBoolean() const
    93 {
    94   return Boolean(false);
    95 }
    96 
    97 Number NullImp::toNumber() const
    98 {
    99   return Number(0);
    100 }
    101 
    102 String NullImp::toString() const
    103 {
    104   return String("null");
    105 }
    106 
    107 Object NullImp::toObject() const
    108 {
    109   return Error::createObject(TypeError, I18N_NOOP("Null value"));
    110 }
     106Value NullImp::toPrimitive(ExecState */*exec*/, Type) const
     107{
     108  return Value((ValueImp*)this);
     109}
     110
     111bool NullImp::toBoolean(ExecState */*exec*/) const
     112{
     113  return false;
     114}
     115
     116double NullImp::toNumber(ExecState */*exec*/) const
     117{
     118  return 0.0;
     119}
     120
     121UString NullImp::toString(ExecState */*exec*/) const
     122{
     123  return "null";
     124}
     125
     126Object NullImp::toObject(ExecState *exec) const
     127{
     128  Object err = Error::create(exec, TypeError, I18N_NOOP("Null value"));
     129  exec->setException(err);
     130  return err;
     131}
     132
     133// ------------------------------ BooleanImp -----------------------------------
    111134
    112135BooleanImp* BooleanImp::staticTrue = 0;
    113136BooleanImp* BooleanImp::staticFalse = 0;
    114137
    115 KJSO BooleanImp::toPrimitive(Type) const
    116 {
    117   return (Imp*)this;
    118 }
    119 
    120 Boolean BooleanImp::toBoolean() const
    121 {
    122   return Boolean((BooleanImp*)this);
    123 }
    124 
    125 Number BooleanImp::toNumber() const
    126 {
    127   return Number(val ? 1 : 0);
    128 }
    129 
    130 String BooleanImp::toString() const
    131 {
    132   return String(val ? "true" : "false");
    133 }
    134 
    135 Object BooleanImp::toObject() const
    136 {
    137   return Object::create(BooleanClass, Boolean((BooleanImp*)this));
    138 }
     138Value BooleanImp::toPrimitive(ExecState */*exec*/, Type) const
     139{
     140  return Value((ValueImp*)this);
     141}
     142
     143bool BooleanImp::toBoolean(ExecState */*exec*/) const
     144{
     145  return val;
     146}
     147
     148double BooleanImp::toNumber(ExecState */*exec*/) const
     149{
     150  return val ? 1.0 : 0.0;
     151}
     152
     153UString BooleanImp::toString(ExecState */*exec*/) const
     154{
     155  return val ? "true" : "false";
     156}
     157
     158Object BooleanImp::toObject(ExecState *exec) const
     159{
     160  List args;
     161  args.append(Boolean(const_cast<BooleanImp*>(this)));
     162  return Object::dynamicCast(exec->interpreter()->builtinBoolean().construct(exec,args));
     163}
     164
     165// ------------------------------ StringImp ------------------------------------
     166
     167StringImp::StringImp(const UString& v)
     168  : val(v)
     169{
     170}
     171
     172Value StringImp::toPrimitive(ExecState */*exec*/, Type) const
     173{
     174  return Value((ValueImp*)this);
     175}
     176
     177bool StringImp::toBoolean(ExecState */*exec*/) const
     178{
     179  return (val.size() > 0);
     180}
     181
     182double StringImp::toNumber(ExecState */*exec*/) const
     183{
     184  return val.toDouble();
     185}
     186
     187UString StringImp::toString(ExecState */*exec*/) const
     188{
     189  return val;
     190}
     191
     192Object StringImp::toObject(ExecState *exec) const
     193{
     194  List args;
     195  args.append(String(const_cast<StringImp*>(this)));
     196  return Object::dynamicCast(exec->interpreter()->builtinString().construct(exec,args));
     197}
     198
     199// ------------------------------ NumberImp ------------------------------------
    139200
    140201NumberImp::NumberImp(double v)
     
    143204}
    144205
    145 KJSO NumberImp::toPrimitive(Type) const
    146 {
    147   return (Imp*)this;
    148 }
    149 
    150 Boolean NumberImp::toBoolean() const
    151 {
    152   bool b = !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
    153 
    154   return Boolean(b);
    155 }
    156 
    157 Number NumberImp::toNumber() const
     206Value NumberImp::toPrimitive(ExecState *, Type) const
    158207{
    159208  return Number((NumberImp*)this);
    160209}
    161210
    162 String NumberImp::toString() const
    163 {
    164   return String(UString::from(val));
    165 }
    166 
    167 Object NumberImp::toObject() const
    168 {
    169   return Object::create(NumberClass, Number((NumberImp*)this));
    170 }
    171 
    172 StringImp::StringImp(const UString& v)
    173   : val(v)
    174 {
    175 }
    176 
    177 KJSO StringImp::toPrimitive(Type) const
    178 {
    179   return (Imp*)this;
    180 }
    181 
    182 Boolean StringImp::toBoolean() const
    183 {
    184   return Boolean(val.size() > 0);
    185 }
    186 
    187 Number StringImp::toNumber() const
    188 {
    189   return Number(val.toDouble());
    190 }
    191 
    192 String StringImp::toString() const
    193 {
    194   return String((StringImp*)this);
    195 }
    196 
    197 Object StringImp::toObject() const
    198 {
    199   return Object::create(StringClass, String((StringImp*)this));
    200 }
    201 
    202 ReferenceImp::ReferenceImp(const KJSO& b, const UString& p)
    203   : base(b), prop(p)
    204 {
    205 }
    206 
    207 void ReferenceImp::mark(Imp*)
    208 {
    209   Imp::mark();
    210   Imp *im = base.imp();
    211   if (im && !im->marked())
    212     im->mark();
    213 }
    214 
    215 CompletionImp::CompletionImp(Compl c, const KJSO& v, const UString& t)
    216   : comp(c), val(v), tar(t)
    217 {
    218 }
    219 
    220 void CompletionImp::mark(Imp*)
    221 {
    222   Imp::mark();
    223   Imp *im = val.imp();
    224   if (im && !im->marked())
    225     im->mark();
    226 }
    227 
    228 RegExpImp::RegExpImp()
    229   : ObjectImp(RegExpClass), reg(0L)
    230 {
    231 }
    232 
    233 RegExpImp::~RegExpImp()
    234 {
    235   delete reg;
    236 }
     211bool NumberImp::toBoolean(ExecState *) const
     212{
     213  return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
     214}
     215
     216double NumberImp::toNumber(ExecState *) const
     217{
     218  return val;
     219}
     220
     221UString NumberImp::toString(ExecState *) const
     222{
     223  return UString::from(val);
     224}
     225
     226Object NumberImp::toObject(ExecState *exec) const
     227{
     228  List args;
     229  args.append(Number(const_cast<NumberImp*>(this)));
     230  return Object::dynamicCast(exec->interpreter()->builtinNumber().construct(exec,args));
     231}
     232
     233// ------------------------------ ReferenceImp ---------------------------------
     234
     235ReferenceImp::ReferenceImp(const Value& v, const UString& p)
     236  : base(v.imp()), prop(p)
     237{
     238}
     239
     240void ReferenceImp::mark()
     241{
     242  ValueImp::mark();
     243  if (base && !base->marked())
     244    base->mark();
     245}
     246
     247Value ReferenceImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const
     248{
     249  // invalid for Reference
     250  assert(false);
     251  return Value();
     252}
     253
     254bool ReferenceImp::toBoolean(ExecState */*exec*/) const
     255{
     256  // invalid for Reference
     257  assert(false);
     258  return false;
     259}
     260
     261double ReferenceImp::toNumber(ExecState */*exec*/) const
     262{
     263  // invalid for Reference
     264  assert(false);
     265  return 0;
     266}
     267
     268UString ReferenceImp::toString(ExecState */*exec*/) const
     269{
     270  // invalid for Reference
     271  assert(false);
     272  return UString::null;
     273}
     274
     275Object ReferenceImp::toObject(ExecState */*exec*/) const
     276{
     277  // invalid for Reference
     278  assert(false);
     279  return Object();
     280}
     281
     282// ------------------------------ LabelStack -----------------------------------
     283
     284LabelStack::LabelStack(const LabelStack &other)
     285{
     286  tos = 0;
     287  *this = other;
     288}
     289
     290LabelStack &LabelStack::operator=(const LabelStack &other)
     291{
     292  clear();
     293  tos = 0;
     294  StackElem *cur = 0;
     295  StackElem *se = other.tos;
     296  while (se) {
     297    StackElem *newPrev = new StackElem;
     298    newPrev->prev = 0;
     299    newPrev->id = se->id;
     300    if (cur)
     301      cur->prev = newPrev;
     302    else
     303      tos = newPrev;
     304    cur = newPrev;
     305    se = se->prev;
     306  }
     307  return *this;
     308}
     309
     310bool LabelStack::push(const UString &id)
     311{
     312  if (id.isEmpty() || contains(id))
     313    return false;
     314
     315  StackElem *newtos = new StackElem;
     316  newtos->id = id;
     317  newtos->prev = tos;
     318  tos = newtos;
     319  return true;
     320}
     321
     322bool LabelStack::contains(const UString &id) const
     323{
     324  if (id.isEmpty())
     325    return true;
     326
     327  for (StackElem *curr = tos; curr; curr = curr->prev)
     328    if (curr->id == id)
     329      return true;
     330
     331  return false;
     332}
     333
     334void LabelStack::pop()
     335{
     336  if (tos) {
     337    StackElem *prev = tos->prev;
     338    delete tos;
     339    tos = prev;
     340  }
     341}
     342
     343LabelStack::~LabelStack()
     344{
     345  clear();
     346}
     347
     348void LabelStack::clear()
     349{
     350  StackElem *prev;
     351
     352  while (tos) {
     353    prev = tos->prev;
     354    delete tos;
     355    tos = prev;
     356  }
     357}
     358
     359// ------------------------------ CompletionImp --------------------------------
     360
     361CompletionImp::CompletionImp(ComplType c, const Value& v, const UString& t)
     362  : comp(c), val(v.imp()), tar(t)
     363{
     364}
     365
     366CompletionImp::~CompletionImp()
     367{
     368}
     369
     370void CompletionImp::mark()
     371{
     372  ValueImp::mark();
     373
     374  if (val && !val->marked())
     375    val->mark();
     376}
     377
     378Value CompletionImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const
     379{
     380  // invalid for Completion
     381  assert(false);
     382  return Value();
     383}
     384
     385bool CompletionImp::toBoolean(ExecState */*exec*/) const
     386{
     387  // invalid for Completion
     388  assert(false);
     389  return false;
     390}
     391
     392double CompletionImp::toNumber(ExecState */*exec*/) const
     393{
     394  // invalid for Completion
     395  assert(false);
     396  return 0;
     397}
     398
     399UString CompletionImp::toString(ExecState */*exec*/) const
     400{
     401  // invalid for Completion
     402  assert(false);
     403  return UString::null;
     404}
     405
     406Object CompletionImp::toObject(ExecState */*exec*/) const
     407{
     408  // invalid for Completion
     409  assert(false);
     410  return Object();
     411}
     412
     413// ------------------------------ ListImp --------------------------------------
     414
     415#ifdef KJS_DEBUG_MEM
     416int ListImp::count = 0;
     417#endif
     418
     419Value ListImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const
     420{
     421  // invalid for List
     422  assert(false);
     423  return Value();
     424}
     425
     426bool ListImp::toBoolean(ExecState */*exec*/) const
     427{
     428  // invalid for List
     429  assert(false);
     430  return false;
     431}
     432
     433double ListImp::toNumber(ExecState */*exec*/) const
     434{
     435  // invalid for List
     436  assert(false);
     437  return 0;
     438}
     439
     440UString ListImp::toString(ExecState */*exec*/) const
     441{
     442  // invalid for List
     443  assert(false);
     444  return UString::null;
     445}
     446
     447Object ListImp::toObject(ExecState */*exec*/) const
     448{
     449  // invalid for List
     450  assert(false);
     451  return Object();
     452}
     453
     454ListImp::ListImp()
     455{
     456#ifdef KJS_DEBUG_MEM
     457  count++;
     458#endif
     459
     460  hook = new ListNode(Null(), 0L, 0L);
     461  hook->next = hook;
     462  hook->prev = hook;
     463  //fprintf(stderr,"ListImp::ListImp %p hook=%p\n",this,hook);
     464}
     465
     466ListImp::~ListImp()
     467{
     468  //fprintf(stderr,"ListImp::~ListImp %p\n",this);
     469#ifdef KJS_DEBUG_MEM
     470  count--;
     471#endif
     472
     473  clear();
     474  delete hook;
     475}
     476
     477void ListImp::mark()
     478{
     479  ListNode *n = hook->next;
     480  while (n != hook) {
     481    if (!n->member->marked())
     482      n->member->mark();
     483    n = n->next;
     484  }
     485  ValueImp::mark();
     486}
     487
     488void ListImp::append(const Value& obj)
     489{
     490  ListNode *n = new ListNode(obj, hook->prev, hook);
     491  hook->prev->next = n;
     492  hook->prev = n;
     493}
     494
     495void ListImp::prepend(const Value& obj)
     496{
     497  ListNode *n = new ListNode(obj, hook, hook->next);
     498  hook->next->prev = n;
     499  hook->next = n;
     500}
     501
     502void ListImp::appendList(const List& lst)
     503{
     504  ListIterator it = lst.begin();
     505  ListIterator e = lst.end();
     506  while(it != e) {
     507    append(*it);
     508    ++it;
     509  }
     510}
     511
     512void ListImp::prependList(const List& lst)
     513{
     514  ListIterator it = lst.end();
     515  ListIterator e = lst.begin();
     516  while(it != e) {
     517    --it;
     518    prepend(*it);
     519  }
     520}
     521
     522void ListImp::removeFirst()
     523{
     524  erase(hook->next);
     525}
     526
     527void ListImp::removeLast()
     528{
     529  erase(hook->prev);
     530}
     531
     532void ListImp::remove(const Value &obj)
     533{
     534  if (obj.isNull())
     535    return;
     536  ListNode *n = hook->next;
     537  while (n != hook) {
     538    if (n->member == obj.imp()) {
     539      erase(n);
     540      return;
     541    }
     542    n = n->next;
     543  }
     544}
     545
     546void ListImp::clear()
     547{
     548  ListNode *n = hook->next;
     549  while (n != hook) {
     550    n = n->next;
     551    delete n->prev;
     552  }
     553
     554  hook->next = hook;
     555  hook->prev = hook;
     556}
     557
     558ListImp *ListImp::copy() const
     559{
     560  ListImp* newList = new ListImp;
     561
     562  ListIterator e = end();
     563  ListIterator it = begin();
     564
     565  while(it != e) {
     566    newList->append(*it);
     567    ++it;
     568  }
     569
     570  //fprintf( stderr, "ListImp::copy returning newList=%p\n", newList );
     571  return newList;
     572}
     573
     574void ListImp::erase(ListNode *n)
     575{
     576  if (n != hook) {
     577    n->next->prev = n->prev;
     578    n->prev->next = n->next;
     579    delete n;
     580  }
     581}
     582
     583bool ListImp::isEmpty() const
     584{
     585  return (hook->prev == hook);
     586}
     587
     588int ListImp::size() const
     589{
     590  int s = 0;
     591  ListNode *node = hook;
     592  while ((node = node->next) != hook)
     593    s++;
     594
     595  return s;
     596}
     597
     598Value ListImp::at(int i) const
     599{
     600  if (i < 0 || i >= size())
     601    return Undefined();
     602
     603  ListIterator it = begin();
     604  int j = 0;
     605  while ((j++ < i))
     606    it++;
     607
     608  return *it;
     609}
     610
     611ListImp *ListImp::emptyList = 0L;
     612
     613ListImp *ListImp::empty()
     614{
     615  if (!emptyList)
     616    emptyList = new ListImp();
     617  return emptyList;
     618}
     619
     620// ------------------------------ ContextImp -----------------------------------
     621
    237622
    238623// ECMA 10.2
    239 Context::Context(CodeType type, Context *callingContext,
    240                  FunctionImp *func, const List *args, Imp *thisV)
    241 {
    242   Global glob(Global::current());
     624ContextImp::ContextImp(Object &glob, ExecState *exec, Object &thisV, CodeType type,
     625                       ContextImp *_callingContext, FunctionImp *func, const List &args)
     626{
     627  codeType = type;
     628  callingCon = _callingContext;
    243629
    244630  // create and initialize activation object (ECMA 10.1.6)
    245   if (type == FunctionCode || type == AnonymousCode || type == HostCode) {
    246     activation = new ActivationImp(func, args);
     631  if (type == FunctionCode || type == AnonymousCode ) {
     632    activation = Object(new ActivationImp(exec,func,args));
    247633    variable = activation;
    248634  } else {
    249     activation = KJSO();
     635    activation = Object();
    250636    variable = glob;
    251637  }
     
    254640  switch(type) {
    255641    case EvalCode:
    256       if (callingContext) {
    257         scopeChain = callingContext->copyOfChain();
    258         variable = callingContext->variableObject();
    259         thisVal = callingContext->thisValue();
     642      if (callingCon) {
     643        scope = callingCon->scopeChain().copy();
     644        variable = callingCon->variableObject();
     645        thisVal = callingCon->thisValue();
    260646        break;
    261647      } // else same as GlobalCode
    262648    case GlobalCode:
    263       scopeChain = new List();
    264       scopeChain->append(glob);
    265       thisVal = glob.imp();
     649      scope = List();
     650      scope.append(glob);
     651      thisVal = Object(static_cast<ObjectImp*>(glob.imp()));
    266652      break;
    267653    case FunctionCode:
    268654    case AnonymousCode:
    269655      if (type == FunctionCode) {
    270         scopeChain = ((DeclaredFunctionImp*)func)->scopeChain()->copy();
    271         scopeChain->prepend(activation);
     656        scope = func->scope().copy();
     657        scope.prepend(activation);
    272658      } else {
    273         scopeChain = new List();
    274         scopeChain->append(activation);
    275         scopeChain->append(glob);
     659        scope = List();
     660        scope.append(activation);
     661        scope.append(glob);
    276662      }
    277       variable = activation; /* TODO: DontDelete ? (ECMA 10.2.3) */
    278       if (thisV->type() >= ObjectType) {
    279         thisVal = thisV;
    280       }
    281       else
    282         thisVal = glob.imp();
    283       break;
    284     case HostCode:
    285       if (thisV->type() >= ObjectType)
    286         thisVal = thisV;
    287       else
    288         thisVal = glob;
    289       variable = activation; /* TODO: DontDelete (ECMA 10.2.4) */
    290       scopeChain = new List();
    291       scopeChain->append(activation);
    292       if (func->hasAttribute(ImplicitThis))
    293         scopeChain->append(KJSO(thisVal));
    294       if (func->hasAttribute(ImplicitParents)) {
    295         /* TODO ??? */
    296       }
    297       scopeChain->append(glob);
     663      variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
     664      thisVal = thisV;
    298665      break;
    299666    }
    300 }
    301 
    302 Context::~Context()
    303 {
    304   delete scopeChain;
    305 }
    306 
    307 Context *Context::current()
    308 {
    309   return KJScriptImp::curr ? KJScriptImp::curr->con : 0L;
    310 }
    311 
    312 void Context::setCurrent(Context *c)
    313 {
    314   KJScriptImp::current()->con = c;
    315 }
    316 
    317 void Context::pushScope(const KJSO &s)
    318 {
    319   scopeChain->prepend(s);
    320 }
    321 
    322 void Context::popScope()
    323 {
    324   scopeChain->removeFirst();
    325 }
    326 
    327 List* Context::copyOfChain()
    328 {
    329   return scopeChain->copy();
    330 }
    331 
    332 
    333 AnonymousFunction::AnonymousFunction()
    334   : Function(0L)
    335 {
    336   /* TODO */
    337 }
    338 
    339 DeclaredFunctionImp::DeclaredFunctionImp(const UString &n,
    340                                          FunctionBodyNode *b, const List *sc)
    341   : ConstructorImp(n), body(b), scopes(sc->copy())
    342 {
    343 }
    344 
    345 DeclaredFunctionImp::~DeclaredFunctionImp()
    346 {
    347   delete scopes;
    348 }
    349 
    350 // step 2 of ECMA 13.2.1. rest in FunctionImp::executeCall()
    351 Completion DeclaredFunctionImp::execute(const List &)
    352 {
    353  /* TODO */
    354 
    355 #ifdef KJS_DEBUGGER
    356   Debugger *dbg = KJScriptImp::current()->debugger();
    357   int oldSourceId = -1;
    358   if (dbg) {
    359     oldSourceId = dbg->sourceId();
    360     dbg->setSourceId(body->sourceId());
    361   }
     667
     668}
     669
     670ContextImp::~ContextImp()
     671{
     672}
     673
     674void ContextImp::pushScope(const Object &s)
     675{
     676  scope.prepend(s);
     677}
     678
     679void ContextImp::popScope()
     680{
     681  scope.removeFirst();
     682}
     683
     684// ------------------------------ Parser ---------------------------------------
     685
     686ProgramNode *Parser::progNode = 0;
     687int Parser::sid = 0;
     688
     689ProgramNode *Parser::parse(const UChar *code, unsigned int length, int *sourceId,
     690                           int *errLine, UString *errMsg)
     691{
     692  if (errLine)
     693    *errLine = -1;
     694  if (errMsg)
     695    *errMsg = 0;
     696
     697  Lexer::curr()->setCode(code, length);
     698  progNode = 0;
     699  sid++;
     700  if (sourceId)
     701    *sourceId = sid;
     702  // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
     703  //extern int kjsyydebug;
     704  //kjsyydebug=1;
     705  int parseError = kjsyyparse();
     706  ProgramNode *prog = progNode;
     707  progNode = 0;
     708  sid = -1;
     709
     710  if (parseError) {
     711    int eline = Lexer::curr()->lineNo();
     712    if (errLine)
     713      *errLine = eline;
     714    if (errMsg)
     715      *errMsg = "Parse error at line " + UString::from(eline);
     716#ifndef NDEBUG
     717    fprintf(stderr, "KJS: JavaScript parse error at line %d.\n", eline);
    362718#endif
    363 
    364   Completion result = body->execute();
    365 
    366 #ifdef KJS_DEBUGGER
    367   if (dbg) {
    368     dbg->setSourceId(oldSourceId);
    369   }
    370 #endif
    371 
    372   if (result.complType() == Throw || result.complType() == ReturnValue)
    373       return result;
    374   return Completion(Normal, Undefined()); /* TODO: or ReturnValue ? */
    375 }
    376 
    377 // ECMA 13.2.2 [[Construct]]
    378 Object DeclaredFunctionImp::construct(const List &args)
    379 {
    380   Object obj(ObjectClass);
    381   KJSO p = get("prototype");
    382   if (p.isObject())
    383     obj.setPrototype(p);
    384   else
    385     obj.setPrototype(Global::current().objectPrototype());
    386 
    387   KJSO res = executeCall(obj.imp(), &args);
    388 
    389   Object v = Object::dynamicCast(res);
    390   if (v.isNull())
    391     return obj;
    392   else
    393     return v;
    394 }
    395 
    396 Completion AnonymousFunction::execute(const List &)
    397 {
    398  /* TODO */
    399   return Completion(Normal, Null());
    400 }
    401 
    402 // ECMA 10.1.8
    403 class ArgumentsObject : public ObjectImp {
    404 public:
    405   ArgumentsObject(FunctionImp *func, const List *args);
    406 };
    407 
    408 ArgumentsObject::ArgumentsObject(FunctionImp *func, const List *args)
    409   : ObjectImp(UndefClass)
    410 {
    411   put("callee", Function(func), DontEnum);
    412   if (args) {
    413     put("length", Number(args->size()), DontEnum);
    414     ListIterator arg = args->begin();
    415     for (int i = 0; arg != args->end(); arg++, i++) {
    416       put(UString::from(i), *arg, DontEnum);
    417     }
    418   }
    419 }
    420 
    421 const TypeInfo ActivationImp::info = { "Activation", ActivationType, 0, 0, 0 };
    422 
    423 // ECMA 10.1.6
    424 ActivationImp::ActivationImp(FunctionImp *f, const List *args)
    425 {
    426   KJSO aobj(new ArgumentsObject(f, args));
    427   put("arguments", aobj, DontDelete);
    428   /* TODO: this is here to get myFunc.arguments and myFunc.a1 going.
    429      I can't see this described in the spec but it's possible in browsers. */
    430   if (!f->name().isNull())
    431     f->put("arguments", aobj);
    432 }
    433 
    434 ExecutionStack::ExecutionStack()
    435   : progNode(0L), firstNode(0L), prev(0)
    436 {
    437 }
    438 
    439 ExecutionStack* ExecutionStack::push()
    440 {
    441   ExecutionStack *s = new ExecutionStack();
    442   s->prev = this;
    443 
    444   return s;
    445 }
    446 
    447 ExecutionStack* ExecutionStack::pop()
    448 {
    449   ExecutionStack *s = prev;
    450   delete this;
    451 
    452   return s;
    453 }
    454 
    455 KJScriptImp* KJScriptImp::curr = 0L;
    456 KJScriptImp* KJScriptImp::hook = 0L;
    457 int          KJScriptImp::instances = 0;
    458 int          KJScriptImp::running = 0;
    459 
    460 KJScriptImp::KJScriptImp(KJScript *s)
    461   : scr(s),
    462     initialized(false),
    463     glob(0L),
    464 #ifdef KJS_DEBUGGER
    465     dbg(0L),
    466 #endif
    467     retVal(0L)
    468 {
    469   instances++;
    470   KJScriptImp::curr = this;
    471   // are we the first interpreter instance ? Initialize some stuff
    472   if (instances == 1)
    473     globalInit();
    474   stack = new ExecutionStack();
    475   clearException();
    476   lex = new Lexer();
    477 }
    478 
    479 KJScriptImp::~KJScriptImp()
    480 {
    481   KJScriptImp::curr = this;
    482 
    483 #ifdef KJS_DEBUGGER
    484   attachDebugger(0L);
    485 #endif
    486 
    487   clear();
    488 
    489   delete lex;
    490   lex = 0L;
    491 
    492   delete stack;
    493   stack = 0L;
    494 
    495   KJScriptImp::curr = 0L;
    496   // are we the last of our kind ? Free global stuff.
    497   if (instances == 1)
    498     globalClear();
    499   instances--;
    500 }
    501 
    502 void KJScriptImp::globalInit()
    503 {
     719    delete prog;
     720    return 0;
     721  }
     722
     723  return prog;
     724}
     725
     726// ------------------------------ InterpreterImp -------------------------------
     727
     728InterpreterImp* InterpreterImp::s_hook = 0L;
     729
     730void InterpreterImp::globalInit()
     731{
     732  //fprintf( stderr, "InterpreterImp::globalInit()\n" );
    504733  UndefinedImp::staticUndefined = new UndefinedImp();
    505734  UndefinedImp::staticUndefined->ref();
     
    512741}
    513742
    514 void KJScriptImp::globalClear()
    515 {
     743void InterpreterImp::globalClear()
     744{
     745  //fprintf( stderr, "InterpreterImp::globalClear()\n" );
    516746  UndefinedImp::staticUndefined->deref();
     747  UndefinedImp::staticUndefined->setGcAllowed();
    517748  UndefinedImp::staticUndefined = 0L;
    518749  NullImp::staticNull->deref();
     750  NullImp::staticNull->setGcAllowed();
    519751  NullImp::staticNull = 0L;
    520752  BooleanImp::staticTrue->deref();
     753  BooleanImp::staticTrue->setGcAllowed();
    521754  BooleanImp::staticTrue = 0L;
    522755  BooleanImp::staticFalse->deref();
     756  BooleanImp::staticFalse->setGcAllowed();
    523757  BooleanImp::staticFalse = 0L;
    524758}
    525759
    526 void KJScriptImp::mark()
    527 {
    528   if (exVal && !exVal->marked())
    529     exVal->mark();
    530   if (retVal && !retVal->marked())
    531     retVal->mark();
    532   UndefinedImp::staticUndefined->mark();
    533   NullImp::staticNull->mark();
    534   BooleanImp::staticTrue->mark();
    535   BooleanImp::staticFalse->mark();
    536 }
    537 
    538 void KJScriptImp::init()
    539 {
    540   KJScriptImp::curr = this;
    541 
    542   clearException();
    543   retVal = 0L;
    544 
    545   if (!initialized) {
    546     // add this interpreter to the global chain
    547     // as a root set for garbage collection
    548     if (hook) {
    549       prev = hook;
    550       next = hook->next;
    551       hook->next->prev = this;
    552       hook->next = this;
    553     } else {
    554       hook = next = prev = this;
     760InterpreterImp::InterpreterImp(Interpreter *interp, const Object &glob)
     761{
     762  // add this interpreter to the global chain
     763  // as a root set for garbage collection
     764  if (s_hook) {
     765    prev = s_hook;
     766    next = s_hook->next;
     767    s_hook->next->prev = this;
     768    s_hook->next = this;
     769  } else {
     770    // This is the first interpreter
     771    s_hook = next = prev = this;
     772    globalInit();
     773  }
     774
     775  m_interpreter = interp;
     776  global = glob;
     777  globExec = new ExecState(m_interpreter,0);
     778  dbg = 0;
     779  m_compatMode = Interpreter::NativeMode;
     780
     781  // initialize properties of the global object
     782
     783  // Contructor prototype objects (Object.prototype, Array.prototype etc)
     784
     785  FunctionPrototypeImp *funcProto = new FunctionPrototypeImp(globExec);
     786  b_FunctionPrototype = Object(funcProto);
     787  ObjectPrototypeImp *objProto = new ObjectPrototypeImp(globExec,funcProto);
     788  b_ObjectPrototype = Object(objProto);
     789  funcProto->setPrototype(b_ObjectPrototype);
     790
     791  ArrayPrototypeImp *arrayProto = new ArrayPrototypeImp(globExec,objProto);
     792  b_ArrayPrototype = Object(arrayProto);
     793  StringPrototypeImp *stringProto = new StringPrototypeImp(globExec,objProto);
     794  b_StringPrototype = Object(stringProto);
     795  BooleanPrototypeImp *booleanProto = new BooleanPrototypeImp(globExec,objProto,funcProto);
     796  b_BooleanPrototype = Object(booleanProto);
     797  NumberPrototypeImp *numberProto = new NumberPrototypeImp(globExec,objProto,funcProto);
     798  b_NumberPrototype = Object(numberProto);
     799  DatePrototypeImp *dateProto = new DatePrototypeImp(globExec,objProto);
     800  b_DatePrototype = Object(dateProto);
     801  RegExpPrototypeImp *regexpProto = new RegExpPrototypeImp(globExec,objProto,funcProto);
     802  b_RegExpPrototype = Object(regexpProto);
     803  ErrorPrototypeImp *errorProto = new ErrorPrototypeImp(globExec,objProto,funcProto);
     804  b_ErrorPrototype = Object(errorProto);
     805
     806  static_cast<ObjectImp*>(global.imp())->setPrototype(b_ObjectPrototype);
     807
     808  // Constructors (Object, Array, etc.)
     809
     810  ObjectObjectImp *objectObj = new ObjectObjectImp(globExec,objProto,funcProto);
     811  b_Object = Object(objectObj);
     812  FunctionObjectImp *funcObj = new FunctionObjectImp(globExec,funcProto);
     813  b_Function = Object(funcObj);
     814  ArrayObjectImp *arrayObj = new ArrayObjectImp(globExec,funcProto,arrayProto);
     815  b_Array = Object(arrayObj);
     816  StringObjectImp *stringObj = new StringObjectImp(globExec,funcProto,stringProto);
     817  b_String = Object(stringObj);
     818  BooleanObjectImp *booleanObj = new BooleanObjectImp(globExec,funcProto,booleanProto);
     819  b_Boolean = Object(booleanObj);
     820  NumberObjectImp *numberObj = new NumberObjectImp(globExec,funcProto,numberProto);
     821  b_Number = Object(numberObj);
     822  DateObjectImp *dateObj = new DateObjectImp(globExec,funcProto,dateProto);
     823  b_Date = Object(dateObj);
     824  RegExpObjectImp *regexpObj = new RegExpObjectImp(globExec,regexpProto,funcProto);
     825  b_RegExp = Object(regexpObj);
     826  ErrorObjectImp *errorObj = new ErrorObjectImp(globExec,funcProto,errorProto);
     827  b_Error = Object(errorObj);
     828
     829  // Error object prototypes
     830  b_evalErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,EvalError,
     831                                                            "EvalError","EvalError"));
     832  b_rangeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,RangeError,
     833                                                            "RangeError","RangeError"));
     834  b_referenceErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,ReferenceError,
     835                                                            "ReferenceError","ReferenceError"));
     836  b_syntaxErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,SyntaxError,
     837                                                            "SyntaxError","SyntaxError"));
     838  b_typeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,TypeError,
     839                                                            "TypeError","TypeError"));
     840  b_uriErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,URIError,
     841                                                            "URIError","URIError"));
     842
     843  // Error objects
     844  b_evalError = Object(new NativeErrorImp(globExec,funcProto,b_evalErrorPrototype));
     845  b_rangeError = Object(new NativeErrorImp(globExec,funcProto,b_rangeErrorPrototype));
     846  b_referenceError = Object(new NativeErrorImp(globExec,funcProto,b_referenceErrorPrototype));
     847  b_syntaxError = Object(new NativeErrorImp(globExec,funcProto,b_syntaxErrorPrototype));
     848  b_typeError = Object(new NativeErrorImp(globExec,funcProto,b_typeErrorPrototype));
     849  b_uriError = Object(new NativeErrorImp(globExec,funcProto,b_uriErrorPrototype));
     850
     851  // ECMA 15.3.4.1
     852  funcProto->put(globExec,"constructor", b_Function, DontEnum);
     853
     854  global.put(globExec,"Object", b_Object, DontEnum);
     855  global.put(globExec,"Function", b_Function, DontEnum);
     856  global.put(globExec,"Array", b_Array, DontEnum);
     857  global.put(globExec,"Boolean", b_Boolean, DontEnum);
     858  global.put(globExec,"String", b_String, DontEnum);
     859  global.put(globExec,"Number", b_Number, DontEnum);
     860  global.put(globExec,"Date", b_Date, DontEnum);
     861  global.put(globExec,"RegExp", b_RegExp, DontEnum);
     862  global.put(globExec,"Error", b_Error, DontEnum);
     863  // Using Internal for those to have something != 0
     864  // (see kjs_window). Maybe DontEnum would be ok too ?
     865  global.put(globExec,"EvalError",b_evalError, Internal);
     866  global.put(globExec,"RangeError",b_rangeError, Internal);
     867  global.put(globExec,"ReferenceError",b_referenceError, Internal);
     868  global.put(globExec,"SyntaxError",b_syntaxError, Internal);
     869  global.put(globExec,"TypeError",b_typeError, Internal);
     870  global.put(globExec,"URIError",b_uriError, Internal);
     871
     872  // Set the "constructor" property of all builtin constructors
     873  objProto->put(globExec, "constructor", b_Object, DontEnum | DontDelete | ReadOnly);
     874  funcProto->put(globExec, "constructor", b_Function, DontEnum | DontDelete | ReadOnly);
     875  arrayProto->put(globExec, "constructor", b_Array, DontEnum | DontDelete | ReadOnly);
     876  booleanProto->put(globExec, "constructor", b_Boolean, DontEnum | DontDelete | ReadOnly);
     877  stringProto->put(globExec, "constructor", b_String, DontEnum | DontDelete | ReadOnly);
     878  numberProto->put(globExec, "constructor", b_Number, DontEnum | DontDelete | ReadOnly);
     879  dateProto->put(globExec, "constructor", b_Date, DontEnum | DontDelete | ReadOnly);
     880  regexpProto->put(globExec, "constructor", b_RegExp, DontEnum | DontDelete | ReadOnly);
     881  errorProto->put(globExec, "constructor", b_Error, DontEnum | DontDelete | ReadOnly);
     882  b_evalErrorPrototype.put(globExec, "constructor", b_evalError, DontEnum | DontDelete | ReadOnly);
     883  b_rangeErrorPrototype.put(globExec, "constructor", b_rangeError, DontEnum | DontDelete | ReadOnly);
     884  b_referenceErrorPrototype.put(globExec, "constructor", b_referenceError, DontEnum | DontDelete | ReadOnly);
     885  b_syntaxErrorPrototype.put(globExec, "constructor", b_syntaxError, DontEnum | DontDelete | ReadOnly);
     886  b_typeErrorPrototype.put(globExec, "constructor", b_typeError, DontEnum | DontDelete | ReadOnly);
     887  b_uriErrorPrototype.put(globExec, "constructor", b_uriError, DontEnum | DontDelete | ReadOnly);
     888
     889  // built-in values
     890  global.put(globExec,"NaN",        Number(NaN), DontEnum);
     891  global.put(globExec,"Infinity",   Number(Inf), DontEnum);
     892  global.put(globExec,"undefined",  Undefined(), DontEnum);
     893
     894  // built-in functions
     895  global.put(globExec,"eval",       Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Eval,       1)), DontEnum);
     896  global.put(globExec,"parseInt",   Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseInt,   2)), DontEnum);
     897  global.put(globExec,"parseFloat", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseFloat, 1)), DontEnum);
     898  global.put(globExec,"isNaN",      Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsNaN,      1)), DontEnum);
     899  global.put(globExec,"isFinite",   Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsFinite,   1)), DontEnum);
     900  global.put(globExec,"escape",     Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Escape,     1)), DontEnum);
     901  global.put(globExec,"unescape",   Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::UnEscape,   1)), DontEnum);
     902
     903  // built-in objects
     904  global.put(globExec,"Math", Object(new MathObjectImp(globExec,objProto)), DontEnum);
     905
     906  recursion = 0;
     907}
     908
     909InterpreterImp::~InterpreterImp()
     910{
     911  if (dbg)
     912    dbg->detach(m_interpreter);
     913  delete globExec;
     914  globExec = 0L;
     915  clear();
     916}
     917
     918void InterpreterImp::clear()
     919{
     920  //fprintf(stderr,"InterpreterImp::clear\n");
     921  // remove from global chain (see init())
     922  next->prev = prev;
     923  prev->next = next;
     924  s_hook = next;
     925  if (s_hook == this)
     926  {
     927    // This was the last interpreter
     928    s_hook = 0L;
     929    globalClear();
     930  }
     931}
     932
     933void InterpreterImp::mark()
     934{
     935  //if (exVal && !exVal->marked())
     936  //  exVal->mark();
     937  //if (retVal && !retVal->marked())
     938  //  retVal->mark();
     939  if (UndefinedImp::staticUndefined && !UndefinedImp::staticUndefined->marked())
     940    UndefinedImp::staticUndefined->mark();
     941  if (NullImp::staticNull && !NullImp::staticNull->marked())
     942    NullImp::staticNull->mark();
     943  if (BooleanImp::staticTrue && !BooleanImp::staticTrue->marked())
     944    BooleanImp::staticTrue->mark();
     945  if (BooleanImp::staticFalse && !BooleanImp::staticFalse->marked())
     946    BooleanImp::staticFalse->mark();
     947  if (ListImp::emptyList && !ListImp::emptyList->marked())
     948    ListImp::emptyList->mark();
     949  //fprintf( stderr, "InterpreterImp::mark this=%p global.imp()=%p\n", this, global.imp() );
     950  if (global.imp())
     951    global.imp()->mark();
     952  if (m_interpreter)
     953    m_interpreter->mark();
     954}
     955
     956bool InterpreterImp::checkSyntax(const UString &code)
     957{
     958  // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
     959  ProgramNode *progNode = Parser::parse(code.data(),code.size(),0,0,0);
     960  bool ok = (progNode != 0);
     961  delete progNode;
     962  return ok;
     963}
     964
     965Completion InterpreterImp::evaluate(const UString &code, const Value &thisV)
     966{
     967  // prevent against infinite recursion
     968  if (recursion >= 20) {
     969    return Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
     970  }
     971
     972  // parse the source code
     973  int sid;
     974  int errLine;
     975  UString errMsg;
     976  ProgramNode *progNode = Parser::parse(code.data(),code.size(),&sid,&errLine,&errMsg);
     977
     978  // notify debugger that source has been parsed
     979  if (dbg) {
     980    bool cont = dbg->sourceParsed(globExec,sid,code,errLine);
     981    if (!cont)
     982      return Completion(Break);
     983  }
     984
     985  // no program node means a syntax occurred
     986  if (!progNode) {
     987    Object err = Error::create(globExec,SyntaxError,errMsg.ascii(),errLine);
     988    err.put(globExec,"sid",Number(sid));
     989    return Completion(Throw,err);
     990  }
     991
     992  globExec->clearException();
     993
     994  recursion++;
     995  progNode->ref();
     996
     997  Object globalObj = globalObject();
     998  Object thisObj = globalObject();
     999
     1000  if (!thisV.isNull()) {
     1001    // "this" must be an object... use same rules as Function.prototype.apply()
     1002    if (thisV.isA(NullType) || thisV.isA(UndefinedType))
     1003      thisObj = globalObject();
     1004    else {
     1005      thisObj = thisV.toObject(globExec);
    5551006    }
    556 
    557     glob.init();
    558     con = new Context();
    559     firstN = 0L;
    560     progN = 0L;
    561     recursion = 0;
    562     errMsg = "";
    563     initialized = true;
    564 #ifdef KJS_DEBUGGER
    565     sid = -1;
    566 #endif
    567   }
    568 }
    569 
    570 void KJScriptImp::clear()
    571 {
    572   if ( recursion ) {
    573 #ifndef NDEBUG
    574       fprintf(stderr, "KJS: ignoring clear() while running\n");
    575 #endif
    576       return;
    577   }
    578   KJScriptImp *old = curr;
    579   if (initialized) {
    580     KJScriptImp::curr = this;
    581 
    582     Node::setFirstNode(firstNode());
    583     Node::deleteAllNodes();
    584     setFirstNode(0L);
    585     setProgNode(0L);
    586 
    587     clearException();
    588     retVal = 0L;
    589 
    590     delete con; con = 0L;
    591     glob.clear();
    592 
    593     Collector::collect();
    594 
    595     // remove from global chain (see init())
    596     next->prev = prev;
    597     prev->next = next;
    598     hook = next;
    599     if (hook == this)
    600       hook = 0L;
    601 
    602 #ifdef KJS_DEBUGGER
    603     sid = -1;
    604 #endif
    605 
    606     initialized = false;
    607   }
    608   if (old != this)
    609       KJScriptImp::curr = old;
    610 }
    611 
    612 bool KJScriptImp::evaluate(const UChar *code, unsigned int length, const KJSO &thisV,
    613                            bool onlyCheckSyntax)
    614 {
    615   init();
    616 
    617 #ifdef KJS_DEBUGGER
    618   sid++;
    619   if (debugger())
    620     debugger()->setSourceId(sid);
    621 #endif
    622   if (recursion > 7) {
    623     fprintf(stderr, "KJS: breaking out of recursion\n");
    624     return true;
    625   } else if (recursion > 0) {
    626 #ifndef NDEBUG
    627     fprintf(stderr, "KJS: entering recursion level %d\n", recursion);
    628 #endif
    629     pushStack();
    630   }
    631 
    632   assert(Lexer::curr());
    633   Lexer::curr()->setCode(code, length);
    634   Node::setFirstNode(firstNode());
    635   int parseError = kjsyyparse();
    636   setFirstNode(Node::firstNode());
    637 
    638   if (parseError) {
    639     errType = 99; /* TODO */
    640     errLine = Lexer::curr()->lineNo();
    641     errMsg = "Parse error at line " + UString::from(errLine);
    642 #ifndef NDEBUG
    643     fprintf(stderr, "JavaScript parse error at line %d.\n", errLine);
    644 #endif
    645     /* TODO: either clear everything or keep previously
    646        parsed function definitions */
    647     //    Node::deleteAllNodes();
    648     return false;
    649   }
    650 
    651   if (onlyCheckSyntax)
    652       return true;
    653 
    654   clearException();
    655 
    656   KJSO oldVar;
    657   if (!thisV.isNull()) {
    658     context()->setThisValue(thisV);
    659     context()->pushScope(thisV);
    660     oldVar = context()->variableObject();
    661     context()->setVariableObject(thisV);
    662   }
    663 
    664   running++;
    665   recursion++;
    666   assert(progNode());
    667   Completion res = progNode()->execute();
     1007  }
     1008
     1009  Completion res;
     1010  if (globExec->hadException()) {
     1011    // the thisArg.toObject() conversion above might have thrown an exception - if so,
     1012    // propagate it back
     1013    res = Completion(Throw,globExec->exception());
     1014  }
     1015  else {
     1016    // execute the code
     1017    ExecState *exec1 = 0;
     1018    ContextImp *ctx = new ContextImp(globalObj, exec1, thisObj);
     1019    ExecState *newExec = new ExecState(m_interpreter,ctx);
     1020
     1021    res = progNode->execute(newExec);
     1022
     1023    delete newExec;
     1024    delete ctx;
     1025  }
     1026
     1027  if (progNode->deref())
     1028    delete progNode;
    6681029  recursion--;
    669   running--;
    670 
    671   if (hadException()) {
    672     KJSO err = exception();
    673     errType = 99; /* TODO */
    674     errLine = err.get("line").toInt32();
    675     errMsg = err.get("name").toString().value() + ". ";
    676     errMsg += err.get("message").toString().value();
    677 #ifdef KJS_DEBUGGER
    678     if (dbg)
    679       dbg->setSourceId(err.get("sid").toInt32());
    680 #endif
    681     clearException();
    682   } else {
    683     errType = 0;
    684     errLine = -1;
    685     errMsg = "";
    686 
    687     // catch return value
    688     retVal = 0L;
    689     if (res.complType() == ReturnValue || !thisV.isNull())
    690         retVal = res.value().imp();
    691   }
    692 
    693   if (!thisV.isNull()) {
    694     context()->popScope();
    695     context()->setVariableObject(oldVar);
    696   }
    697 
    698   if (progNode())
    699     progNode()->deleteGlobalStatements();
    700 
    701   if (recursion > 0) {
    702     popStack();
    703   }
    704 
    705   return !errType;
    706 }
    707 
    708 void KJScriptImp::pushStack()
    709 {
    710     stack = stack->push();
    711 }
    712 
    713 void KJScriptImp::popStack()
    714 {
    715     stack = stack->pop();
    716     assert(stack);
    717 }
    718 
    719 bool KJScriptImp::call(const KJSO &scope, const UString &func, const List &args)
    720 {
    721   init();
    722   KJSO callScope(scope);
    723   if (callScope.isNull())
    724     callScope = Global::current().imp();
    725   if (!callScope.hasProperty(func)) {
    726 #ifndef NDEBUG
    727       fprintf(stderr, "couldn't resolve function name %s. call() failed\n",
    728               func.ascii());
    729 #endif
    730       return false;
    731   }
    732   KJSO v = callScope.get(func);
    733   if (!v.isA(ConstructorType)) {
    734 #ifndef NDEBUG
    735       fprintf(stderr, "%s is not a function. call() failed.\n", func.ascii());
    736 #endif
    737       return false;
    738   }
    739   running++;
    740   recursion++;
    741   static_cast<ConstructorImp*>(v.imp())->executeCall(scope.imp(), &args);
    742   recursion--;
    743   running--;
    744   return !hadException();
    745 }
    746 
    747 bool KJScriptImp::call(const KJSO &func, const KJSO &thisV,
    748                        const List &args, const List &extraScope)
    749 {
    750   init();
    751   if(!func.implementsCall())
    752     return false;
    753 
    754   running++;
    755   recursion++;
    756   retVal = func.executeCall(thisV, &args, &extraScope).imp();
    757   recursion--;
    758   running--;
    759 
    760   return !hadException();
    761 }
    762 
    763 void KJScriptImp::setException(Imp *e)
    764 {
    765   assert(curr);
    766   curr->exVal = e;
    767   curr->exMsg = "Exception"; // not very meaningful but we use !0L to test
    768 }
    769 
    770 void KJScriptImp::setException(const char *msg)
    771 {
    772   assert(curr);
    773   curr->exVal = 0L;             // will be created later on exception()
    774   curr->exMsg = msg;
    775 }
    776 
    777 KJSO KJScriptImp::exception()
    778 {
    779   assert(curr);
    780   if (!curr->exMsg)
    781     return Undefined();
    782   if (curr->exVal)
    783     return curr->exVal;
    784   return Error::create(GeneralError, curr->exMsg);
    785 }
    786 
    787 void KJScriptImp::clearException()
    788 {
    789   assert(curr);
    790   curr->exMsg = 0L;
    791   curr->exVal = 0L;
    792 }
    793 
    794 #ifdef KJS_DEBUGGER
    795 void KJScriptImp::attachDebugger(Debugger *d)
    796 {
    797   static bool detaching = false;
    798   if (detaching) // break circular detaching
    799     return;
    800 
    801   if (dbg) {
    802     detaching = true;
    803     dbg->detach();
    804     detaching = false;
    805   }
    806 
     1030
     1031  return res;
     1032}
     1033
     1034void InterpreterImp::setDebugger(Debugger *d)
     1035{
     1036  if (d)
     1037    d->detach(m_interpreter);
    8071038  dbg = d;
    8081039}
    8091040
    810 bool KJScriptImp::setBreakpoint(int id, int line, bool set)
    811 {
    812   init();
    813   return Node::setBreakpoint(firstNode(), id, line, set);
    814 }
    815 
    816 #endif
    817 
    818 bool PropList::contains(const UString &name)
    819 {
    820   PropList *p = this;
    821   while (p) {
    822     if (name == p->name)
    823       return true;
    824     p = p->next;
    825   }
    826   return false;
    827 }
    828 
    829 bool LabelStack::push(const UString &id)
    830 {
    831   if (id.isEmpty() || contains(id))
    832     return false;
    833 
    834   StackElm *newtos = new StackElm;
    835   newtos->id = id;
    836   newtos->prev = tos;
    837   tos = newtos;
     1041// ------------------------------ InternalFunctionImp --------------------------
     1042
     1043const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
     1044
     1045InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto)
     1046  : ObjectImp(Object(funcProto))
     1047{
     1048}
     1049
     1050bool InternalFunctionImp::implementsHasInstance() const
     1051{
    8381052  return true;
    8391053}
    8401054
    841 bool LabelStack::contains(const UString &id) const
    842 {
    843   if (id.isEmpty())
    844     return true;
    845 
    846   for (StackElm *curr = tos; curr; curr = curr->prev)
    847     if (curr->id == id)
    848       return true;
    849 
    850   return false;
    851 }
    852 
    853 void LabelStack::pop()
    854 {
    855   if (tos) {
    856     StackElm *prev = tos->prev;
    857     delete tos;
    858     tos = prev;
    859   }
    860 }
    861 
    862 LabelStack::~LabelStack()
    863 {
    864   StackElm *prev;
    865 
    866   while (tos) {
    867     prev = tos->prev;
    868     delete tos;
    869     tos = prev;
    870   }
    871 }
    872 
    873 // ECMA 15.3.5.3 [[HasInstance]]
    874 // see comment in header file
    875 KJSO KJS::hasInstance(const KJSO &F, const KJSO &V)
    876 {
    877   if (V.isObject()) {
    878     KJSO prot = F.get("prototype");
    879     if (!prot.isObject())
    880       return Error::create(TypeError, "Invalid prototype encountered "
    881                            "in instanceof operation.");
    882     Imp *v = V.imp();
    883     while ((v = v->prototype())) {
    884       if (v == prot.imp())
    885         return Boolean(true);
    886     }
     1055Boolean InternalFunctionImp::hasInstance(ExecState *exec, const Value &value)
     1056{
     1057  if (value.type() != ObjectType)
     1058    return Boolean(false);
     1059
     1060  Value prot = get(exec,"prototype");
     1061  if (prot.type() != ObjectType && prot.type() != NullType) {
     1062    Object err = Error::create(exec, TypeError, "Invalid prototype encountered "
     1063                               "in instanceof operation.");
     1064    exec->setException(err);
     1065    return Boolean(false);
     1066  }
     1067
     1068  Object v = Object(static_cast<ObjectImp*>(value.imp()));
     1069  while ((v = Object::dynamicCast(v.prototype())).imp()) {
     1070    if (v.imp() == prot.imp())
     1071      return Boolean(true);
    8871072  }
    8881073  return Boolean(false);
     1074}
     1075
     1076// ------------------------------ global functions -----------------------------
     1077
     1078double KJS::roundValue(ExecState *exec, const Value &v)
     1079{
     1080  if (v.type() == UndefinedType) /* TODO: see below */
     1081    return 0.0;
     1082  Number n = v.toNumber(exec);
     1083  if (n.value() == 0.0)   /* TODO: -0, NaN, Inf */
     1084    return 0.0;
     1085  double d = floor(fabs(n.value()));
     1086  if (n.value() < 0)
     1087    d *= -1;
     1088
     1089  return d;
    8891090}
    8901091
    8911092#ifndef NDEBUG
    8921093#include <stdio.h>
    893 void KJS::printInfo( const char *s, const KJSO &o )
    894 {
    895     if (o.isNull())
    896       fprintf(stderr, "%s: (null)\n", s);
    897     else {
    898       KJSO v = o;
    899       if (o.isA(ReferenceType))
    900           v = o.getValue();
    901       fprintf(stderr, "JS: %s: %s : %s (%p)\n",
    902               s,
    903               v.toString().value().ascii(),
    904               v.imp()->typeInfo()->name,
    905               (void*)v.imp());
     1094void KJS::printInfo(ExecState *exec, const char *s, const Value &o, int lineno)
     1095{
     1096  if (o.isNull())
     1097    fprintf(stderr, "KJS: %s: (null)", s);
     1098  else {
     1099    Value v = o;
     1100    if (o.isA(ReferenceType))
     1101      v = o.getValue(exec);
     1102
     1103    UString name;
     1104    switch ( v.type() ) {
     1105    case UnspecifiedType:
     1106      name = "Unspecified";
     1107      break;
     1108    case UndefinedType:
     1109      name = "Undefined";
     1110      break;
     1111    case NullType:
     1112      name = "Null";
     1113      break;
     1114    case BooleanType:
     1115      name = "Boolean";
     1116      break;
     1117    case StringType:
     1118      name = "String";
     1119      break;
     1120    case NumberType:
     1121      name = "Number";
     1122      break;
     1123    case ObjectType:
     1124      name = Object::dynamicCast(v).className();
     1125      if (name.isNull())
     1126        name = "(unknown class)";
     1127      break;
     1128    case ReferenceType:
     1129      name = "Reference";
     1130      break;
     1131    case ListType:
     1132      name = "List";
     1133      break;
     1134    case CompletionType:
     1135      name = "Completion";
     1136      break;
     1137    default:
     1138      break;
     1139    }
     1140    UString vString = v.toString(exec);
     1141    if ( vString.size() > 50 )
     1142      vString = vString.substr( 0, 50 ) + "...";
     1143    // Can't use two UString::ascii() in the same fprintf call
     1144    CString tempString( vString.cstring() );
     1145
     1146    fprintf(stderr, "KJS: %s: %s : %s (%p)",
     1147            s, tempString.c_str(), name.ascii(), (void*)v.imp());
     1148
     1149    if (lineno >= 0)
     1150      fprintf(stderr, ", line %d\n",lineno);
     1151    else
     1152      fprintf(stderr, "\n");
     1153    if (!o.isNull())
    9061154      if (o.isA(ReferenceType)) {
    907           fprintf(stderr, "JS: Was property '%s'\n", o.getPropertyName().ascii());
    908           printInfo("of", o.getBase());
     1155        fprintf(stderr, "KJS: Was property '%s'\n", o.getPropertyName(exec).ascii());
     1156        printInfo(exec,"of", o.getBase(exec));
    9091157      }
    910     }
     1158  }
    9111159}
    9121160#endif
  • trunk/JavaScriptCore/kjs/internal.h

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    3  *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     4 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1719 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1820 *  Boston, MA 02111-1307, USA.
     21 *
    1922 */
    2023
     
    2225#define _INTERNAL_H_
    2326
    24 #ifdef HAVE_CONFIG_H
    25 #include <config.h>
    26 #endif
    27 
    28 #include "kjs.h"
     27#include "ustring.h"
     28#include "value.h"
    2929#include "object.h"
    30 #include "function.h"
     30#include "types.h"
     31#include "interpreter.h"
    3132
    3233#define I18N_NOOP(s) s
     
    3435namespace KJS {
    3536
    36   class Boolean;
    37   class Number;
    38   class String;
    39   class Object;
    40   class RegExp;
    41   class Node;
     37  static const double D16 = 65536.0;
     38  static const double D32 = 4294967296.0;
     39
     40  class ProgramNode;
    4241  class FunctionBodyNode;
    43   class ProgramNode;
    44 #ifdef KJS_DEBUGGER
     42  class FunctionPrototypeImp;
     43  class FunctionImp;
    4544  class Debugger;
    46 #endif
    47 
    48   class UndefinedImp : public Imp {
    49   public:
    50     UndefinedImp();
     45
     46  // ---------------------------------------------------------------------------
     47  //                            Primitive impls
     48  // ---------------------------------------------------------------------------
     49
     50  class UndefinedImp : public ValueImp {
     51  public:
     52    UndefinedImp() {}
    5153    virtual ~UndefinedImp() { }
    52     virtual KJSO toPrimitive(Type preferred = UndefinedType) const;
    53     virtual Boolean toBoolean() const;
    54     virtual Number toNumber() const;
    55     virtual String toString() const;
    56     virtual Object toObject() const;
    57 
    58     virtual const TypeInfo* typeInfo() const { return &info; }
    59     static const TypeInfo info;
    60      
     54
     55    Type type() const { return UndefinedType; }
     56
     57    Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const;
     58    bool toBoolean(ExecState *exec) const;
     59    double toNumber(ExecState *exec) const;
     60    UString toString(ExecState *exec) const;
     61    Object toObject(ExecState *exec) const;
     62
    6163    static UndefinedImp *staticUndefined;
    6264  };
    6365
    64   class NullImp : public Imp {
    65   public:
    66     NullImp();
     66  class NullImp : public ValueImp {
     67  public:
     68    NullImp() {}
    6769    virtual ~NullImp() { }
    68     virtual KJSO toPrimitive(Type preferred = UndefinedType) const;
    69     virtual Boolean toBoolean() const;
    70     virtual Number toNumber() const;
    71     virtual String toString() const;
    72     virtual Object toObject() const;
    73 
    74     virtual const TypeInfo* typeInfo() const { return &info; }
    75     static const TypeInfo info;
     70
     71    Type type() const { return NullType; }
     72
     73    Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const;
     74    bool toBoolean(ExecState *exec) const;
     75    double toNumber(ExecState *exec) const;
     76    UString toString(ExecState *exec) const;
     77    Object toObject(ExecState *exec) const;
    7678
    7779    static NullImp *staticNull;
    7880  };
    7981
    80   class BooleanImp : public Imp {
     82  class BooleanImp : public ValueImp {
    8183  public:
    8284    virtual ~BooleanImp() { }
    8385    BooleanImp(bool v = false) : val(v) { }
    8486    bool value() const { return val; }
    85     virtual KJSO toPrimitive(Type preferred = UndefinedType) const;
    86     virtual Boolean toBoolean() const;
    87     virtual Number toNumber() const;
    88     virtual String toString() const;
    89     virtual Object toObject() const;
    90 
    91     virtual const TypeInfo* typeInfo() const { return &info; }
    92     static const TypeInfo info;
    93 
    94     static BooleanImp *staticTrue, *staticFalse;
     87
     88    Type type() const { return BooleanType; }
     89
     90    Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const;
     91    bool toBoolean(ExecState *exec) const;
     92    double toNumber(ExecState *exec) const;
     93    UString toString(ExecState *exec) const;
     94    Object toObject(ExecState *exec) const;
     95
     96    static BooleanImp *staticTrue;
     97    static BooleanImp *staticFalse;
    9598  private:
    9699    bool val;
    97100  };
    98101
    99   class NumberImp : public Imp {
     102  class StringImp : public ValueImp {
     103  public:
     104    StringImp(const UString& v);
     105    virtual ~StringImp() { }
     106    UString value() const { return val; }
     107
     108    Type type() const { return StringType; }
     109
     110    Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const;
     111    bool toBoolean(ExecState *exec) const;
     112    double toNumber(ExecState *exec) const;
     113    UString toString(ExecState *exec) const;
     114    Object toObject(ExecState *exec) const;
     115
     116  private:
     117    UString val;
     118  };
     119
     120  class NumberImp : public ValueImp {
    100121  public:
    101122    NumberImp(double v);
    102123    virtual ~NumberImp() { }
    103124    double value() const { return val; }
    104     virtual KJSO toPrimitive(Type preferred = UndefinedType) const;
    105     virtual Boolean toBoolean() const;
    106     virtual Number toNumber() const;
    107     virtual String toString() const;
    108     virtual Object toObject() const;
    109 
    110     virtual const TypeInfo* typeInfo() const { return &info; }
    111     static const TypeInfo info;
     125
     126    Type type() const { return NumberType; }
     127
     128    Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const;
     129    bool toBoolean(ExecState *exec) const;
     130    double toNumber(ExecState *exec) const;
     131    UString toString(ExecState *exec) const;
     132    Object toObject(ExecState *exec) const;
     133
    112134  private:
    113135    double val;
    114136  };
    115137
    116   class StringImp : public Imp {
    117   public:
    118     StringImp(const UString& v);
    119     virtual ~StringImp() { }
    120     UString value() const { return val; }
    121     virtual KJSO toPrimitive(Type preferred = UndefinedType) const;
    122     virtual Boolean toBoolean() const;
    123     virtual Number toNumber() const;
    124     virtual String toString() const;
    125     virtual Object toObject() const;
    126 
    127     virtual const TypeInfo* typeInfo() const { return &info; }
    128     static const TypeInfo info;
    129   private:
    130     UString val;
    131   };
    132 
    133   class ReferenceImp : public Imp {
    134   public:
    135     ReferenceImp(const KJSO& b, const UString& p);
     138  // ---------------------------------------------------------------------------
     139  //                            Internal type impls
     140  // ---------------------------------------------------------------------------
     141
     142  class ReferenceImp : public ValueImp {
     143  public:
     144
     145    ReferenceImp(const Value& v, const UString& p);
    136146    virtual ~ReferenceImp() { }
    137     virtual void mark(Imp*);
    138     KJSO getBase() const { return base; }
     147    virtual void mark();
     148
     149    Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const;
     150    bool toBoolean(ExecState *exec) const;
     151    double toNumber(ExecState *exec) const;
     152    UString toString(ExecState *exec) const;
     153    Object toObject(ExecState *exec) const;
     154
     155    Value getBase() const { return Value(base); }
    139156    UString getPropertyName() const { return prop; }
    140157
    141     virtual const TypeInfo* typeInfo() const { return &info; }
    142     static const TypeInfo info;
    143   private:
    144     KJSO base;
     158    Type type() const { return ReferenceType; }
     159
     160  private:
     161    ValueImp *base;
    145162    UString prop;
    146163  };
    147164
    148   class CompletionImp : public Imp {
    149   public:
    150     CompletionImp(Compl c, const KJSO& v, const UString& t);
    151     virtual ~CompletionImp() { }
    152     virtual void mark(Imp*);
    153     Compl completion() const { return comp; }
    154     KJSO value() const { return val; }
     165  class CompletionImp : public ValueImp {
     166  public:
     167    Type type() const { return CompletionType; }
     168
     169    CompletionImp(ComplType c, const Value& v, const UString& t);
     170    virtual ~CompletionImp();
     171    virtual void mark();
     172
     173    Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const;
     174    bool toBoolean(ExecState *exec) const;
     175    double toNumber(ExecState *exec) const;
     176    UString toString(ExecState *exec) const;
     177    Object toObject(ExecState *exec) const;
     178
     179    ComplType complType() const { return comp; }
     180    Value value() const { return Value(val); }
    155181    UString target() const { return tar; }
    156182
    157     virtual const TypeInfo* typeInfo() const { return &info; }
    158     static const TypeInfo info;
    159   private:
    160     Compl comp;
    161     KJSO val;
     183  private:
     184    ComplType comp;
     185    ValueImp * val;
    162186    UString tar;
    163187  };
    164188
    165   class RegExpImp : public ObjectImp {
    166   public:
    167     RegExpImp();
    168     ~RegExpImp();
    169     void setRegExp(RegExp *r) { reg = r; }
    170     RegExp* regExp() const { return reg; }
    171   private:
    172     RegExp *reg;
    173   };
    174 
    175   class StatementNode;
    176   class UString;
    177 
    178   class Reference : public KJSO {
    179   public:
    180     Reference(const KJSO& b, const UString &p);
    181     virtual ~Reference();
     189  /**
     190   * @internal
     191   */
     192  class ListNode {
     193    friend class List;
     194    friend class ListImp;
     195    friend class ListIterator;
     196    ListNode(Value val, ListNode *p, ListNode *n)
     197      : member(val.imp()), prev(p), next(n) {};
     198    ValueImp *member;
     199    ListNode *prev, *next;
     200  };
     201
     202  class ListImp : public ValueImp {
     203    friend class ListIterator;
     204    friend class List;
     205    friend class InterpreterImp;
     206  public:
     207    ListImp();
     208    ~ListImp();
     209
     210    Type type() const { return ListType; }
     211
     212    virtual void mark();
     213
     214    Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const;
     215    bool toBoolean(ExecState *exec) const;
     216    double toNumber(ExecState *exec) const;
     217    UString toString(ExecState *exec) const;
     218    Object toObject(ExecState *exec) const;
     219
     220    void append(const Value& val);
     221    void prepend(const Value& val);
     222    void appendList(const List& lst);
     223    void prependList(const List& lst);
     224    void removeFirst();
     225    void removeLast();
     226    void remove(const Value &val);
     227    void clear();
     228    ListImp *copy() const;
     229    ListIterator begin() const { return ListIterator(hook->next); }
     230    ListIterator end() const { return ListIterator(hook); }
     231    //    bool isEmpty() const { return (hook->prev == hook); }
     232    bool isEmpty() const;
     233    int size() const;
     234    Value at(int i) const;
     235    Value operator[](int i) const { return at(i); }
     236    static ListImp* empty();
     237
     238#ifdef KJS_DEBUG_MEM
     239    static int count;
     240#endif
     241  private:
     242    void erase(ListNode *n);
     243    ListNode *hook;
     244    static ListImp *emptyList;
    182245  };
    183246
     
    189252    LabelStack(): tos(0L) {}
    190253    ~LabelStack();
     254
     255    LabelStack(const LabelStack &other);
     256    LabelStack &operator=(const LabelStack &other);
    191257
    192258    /**
     
    204270    void pop();
    205271  private:
    206     struct StackElm {
     272    struct StackElem {
    207273      UString id;
    208       StackElm *prev;
     274      StackElem *prev;
    209275    };
    210276
    211     StackElm *tos;
    212   };
     277    StackElem *tos;
     278    void clear();
     279  };
     280
     281
     282  // ---------------------------------------------------------------------------
     283  //                            Parsing & evaluateion
     284  // ---------------------------------------------------------------------------
     285
     286  enum CodeType { GlobalCode,
     287                  EvalCode,
     288                  FunctionCode,
     289                  AnonymousCode };
    213290
    214291  /**
    215292   * @short Execution context.
    216293   */
    217   class Context {
    218   public:
    219     Context(CodeType type = GlobalCode, Context *callingContext = 0L,
    220                FunctionImp *func = 0L, const List *args = 0L, Imp *thisV = 0L);
    221     virtual ~Context();
    222     static Context *current();
    223     static void setCurrent(Context *c);
    224     const List *pScopeChain() const { return scopeChain; }
    225     void pushScope(const KJSO &s);
     294  class ContextImp {
     295  public:
     296    ContextImp(Object &glob, ExecState *exec, Object &thisV, CodeType type = GlobalCode,
     297               ContextImp *_callingContext = 0L, FunctionImp *func = 0L, const List &args = List());
     298    virtual ~ContextImp();
     299
     300    const List scopeChain() const { return scope; }
     301    Object variableObject() const { return variable; }
     302    void setVariableObject(const Object &v) { variable = v; }
     303    Object thisValue() const { return thisVal; }
     304    ContextImp *callingContext() { return callingCon; }
     305    Object activationObject() { return activation; }
     306
     307    void pushScope(const Object &s);
    226308    void popScope();
    227     List *copyOfChain();
    228     KJSO variableObject() const { return variable; }
    229     void setVariableObject( const KJSO &obj ) { variable = obj; }
    230     KJSO thisValue() const { return thisVal; }
    231     void setThisValue(const KJSO &t) { thisVal = t; }
    232309    LabelStack *seenLabels() { return &ls; }
    233   private:
     310
     311  private:
     312
     313    List scope;
     314    Object variable;
     315    Object thisVal;
     316    ContextImp *callingCon;
     317    Object activation;
     318
     319
    234320    LabelStack ls;
    235     KJSO thisVal;
    236     KJSO activation;
    237     KJSO variable;
    238     List *scopeChain;
    239   };
    240 
    241   class DeclaredFunctionImp : public ConstructorImp {
    242   public:
    243     DeclaredFunctionImp(const UString &n, FunctionBodyNode *b,
    244                         const List *sc);
    245     ~DeclaredFunctionImp();
    246     Completion execute(const List &);
    247     Object construct(const List &);
    248     CodeType codeType() const { return FunctionCode; }
    249     List *scopeChain() const { return scopes; }
    250   private:
    251     FunctionBodyNode *body;
    252     List *scopes;
    253   };
    254 
    255   class AnonymousFunction : public Function {
    256   public:
    257     AnonymousFunction();
    258     Completion execute(const List &);
    259     CodeType codeType() const { return AnonymousCode; }
    260   };
    261 
    262   class ActivationImp : public Imp {
    263   public:
    264     ActivationImp(FunctionImp *f, const List *args);
    265     virtual const TypeInfo* typeInfo() const { return &info; }
    266     static const TypeInfo info;
    267   };
    268 
    269   class ExecutionStack {
    270   public:
    271     ExecutionStack();
    272     ExecutionStack *push();
    273     ExecutionStack *pop();
    274    
    275     ProgramNode *progNode;
    276     Node *firstNode;
    277   private:
    278     ExecutionStack *prev;
    279   };
    280 
    281   class KJScriptImp {
    282     friend class ::KJScript;
    283     friend class Lexer;
    284     friend class Context;
    285     friend class Global;
     321    CodeType codeType;
     322  };
     323
     324  /**
     325   * @internal
     326   *
     327   * Parses ECMAScript source code and converts into ProgramNode objects, which
     328   * represent the root of a parse tree. This class provides a conveniant workaround
     329   * for the problem of the bison parser working in a static context.
     330   */
     331  class Parser {
     332  public:
     333    static ProgramNode *parse(const UChar *code, unsigned int length, int *sourceId = 0,
     334                              int *errLine = 0, UString *errMsg = 0);
     335
     336    static ProgramNode *progNode;
     337    static int sid;
     338  };
     339
     340  class InterpreterImp {
    286341    friend class Collector;
    287342  public:
    288     KJScriptImp(KJScript *s);
    289     ~KJScriptImp();
     343    static void globalInit();
     344    static void globalClear();
     345
     346    InterpreterImp(Interpreter *interp, const Object &glob);
     347    ~InterpreterImp();
     348
     349    Object globalObject() const { return global; }
     350    Interpreter* interpreter() const { return m_interpreter; }
     351
    290352    void mark();
    291     static KJScriptImp *current() { return curr; }
    292     static void setException(Imp *e);
    293     static void setException(const char *msg);
    294     static bool hadException();
    295     static KJSO exception();
    296     static void clearException();
    297 
    298     Context *context() const { return con; }
    299     void setContext(Context *c) { con = c; }
    300 
    301 #ifdef KJS_DEBUGGER
    302     /**
    303      * Attach debugger d to this engine. If there already was another instance
    304      * attached it will be detached.
    305      */
    306     void attachDebugger(Debugger *d);
     353
     354    ExecState *globalExec() { return globExec; }
     355    bool checkSyntax(const UString &code);
     356    Completion evaluate(const UString &code, const Value &thisV);
    307357    Debugger *debugger() const { return dbg; }
    308     int sourceId() const { return sid; }
    309     bool setBreakpoint(int id, int line, bool set);
     358    void setDebugger(Debugger *d);
     359
     360    Object builtinObject() const { return b_Object; }
     361    Object builtinFunction() const { return b_Function; }
     362    Object builtinArray() const { return b_Array; }
     363    Object builtinBoolean() const { return b_Boolean; }
     364    Object builtinString() const { return b_String; }
     365    Object builtinNumber() const { return b_Number; }
     366    Object builtinDate() const { return b_Date; }
     367    Object builtinRegExp() const { return b_RegExp; }
     368    Object builtinError() const { return b_Error; }
     369
     370    Object builtinObjectPrototype() const { return b_ObjectPrototype; }
     371    Object builtinFunctionPrototype() const { return b_FunctionPrototype; }
     372    Object builtinArrayPrototype() const { return b_ArrayPrototype; }
     373    Object builtinBooleanPrototype() const { return b_BooleanPrototype; }
     374    Object builtinStringPrototype() const { return b_StringPrototype; }
     375    Object builtinNumberPrototype() const { return b_NumberPrototype; }
     376    Object builtinDatePrototype() const { return b_DatePrototype; }
     377    Object builtinRegExpPrototype() const { return b_RegExpPrototype; }
     378    Object builtinErrorPrototype() const { return b_ErrorPrototype; }
     379
     380    Object builtinEvalError() const { return b_evalError; }
     381    Object builtinRangeError() const { return b_rangeError; }
     382    Object builtinReferenceError() const { return b_referenceError; }
     383    Object builtinSyntaxError() const { return b_syntaxError; }
     384    Object builtinTypeError() const { return b_typeError; }
     385    Object builtinURIError() const { return b_uriError; }
     386
     387    Object builtinEvalErrorPrototype() const { return b_evalErrorPrototype; }
     388    Object builtinRangeErrorPrototype() const { return b_rangeErrorPrototype; }
     389    Object builtinReferenceErrorPrototype() const { return b_referenceErrorPrototype; }
     390    Object builtinSyntaxErrorPrototype() const { return b_syntaxErrorPrototype; }
     391    Object builtinTypeErrorPrototype() const { return b_typeErrorPrototype; }
     392    Object builtinURIErrorPrototype() const { return b_uriErrorPrototype; }
     393
     394    void setCompatMode(Interpreter::CompatMode mode) { m_compatMode = mode; }
     395    Interpreter::CompatMode compatMode() const { return m_compatMode; }
     396
     397    // Chained list of interpreters (ring)
     398    static InterpreterImp* firstInterpreter() { return s_hook; }
     399    InterpreterImp *nextInterpreter() const { return next; }
     400    InterpreterImp *prevInterpreter() const { return prev; }
     401
     402  private:
     403    void clear();
     404    Interpreter *m_interpreter;
     405    Object global;
     406    Debugger *dbg;
     407
     408    // Built-in properties of the object prototype. These are accessible
     409    // from here even if they are replaced by js code (e.g. assigning to
     410    // Array.prototype)
     411
     412    Object b_Object;
     413    Object b_Function;
     414    Object b_Array;
     415    Object b_Boolean;
     416    Object b_String;
     417    Object b_Number;
     418    Object b_Date;
     419    Object b_RegExp;
     420    Object b_Error;
     421
     422    Object b_ObjectPrototype;
     423    Object b_FunctionPrototype;
     424    Object b_ArrayPrototype;
     425    Object b_BooleanPrototype;
     426    Object b_StringPrototype;
     427    Object b_NumberPrototype;
     428    Object b_DatePrototype;
     429    Object b_RegExpPrototype;
     430    Object b_ErrorPrototype;
     431
     432    Object b_evalError;
     433    Object b_rangeError;
     434    Object b_referenceError;
     435    Object b_syntaxError;
     436    Object b_typeError;
     437    Object b_uriError;
     438
     439    Object b_evalErrorPrototype;
     440    Object b_rangeErrorPrototype;
     441    Object b_referenceErrorPrototype;
     442    Object b_syntaxErrorPrototype;
     443    Object b_typeErrorPrototype;
     444    Object b_uriErrorPrototype;
     445
     446    ExecState *globExec;
     447    Interpreter::CompatMode m_compatMode;
     448
     449    // Chained list of interpreters (ring) - for collector
     450    static InterpreterImp* s_hook;
     451    InterpreterImp *next, *prev;
     452
     453    int recursion;
     454  };
     455
     456  class AttachedInterpreter;
     457  class DebuggerImp {
     458  public:
     459
     460    DebuggerImp() {
     461      interps = 0;
     462      isAborted = false;
     463    }
     464
     465    void abort() { isAborted = true; }
     466    bool aborted() const { return isAborted; }
     467
     468    AttachedInterpreter *interps;
     469    bool isAborted;
     470  };
     471
     472
     473
     474  class InternalFunctionImp : public ObjectImp {
     475  public:
     476    InternalFunctionImp(FunctionPrototypeImp *funcProto);
     477    bool implementsHasInstance() const;
     478    Boolean hasInstance(ExecState *exec, const Value &value);
     479
     480    virtual const ClassInfo *classInfo() const { return &info; }
     481    static const ClassInfo info;
     482  };
     483
     484  // helper function for toInteger, toInt32, toUInt32 and toUInt16
     485  double roundValue(ExecState *exec, const Value &v);
     486
     487#ifndef NDEBUG
     488  void printInfo(ExecState *exec, const char *s, const Value &o, int lineno = -1);
    310489#endif
    311   private:
    312     /**
    313      * Initialize global object and context. For internal use only.
    314      */
    315     void init();
    316     void clear();
    317     /**
    318      * Called when the first interpreter is instanciated. Initializes
    319      * global pointers.
    320      */
    321     void globalInit();
    322     /**
    323      * Called when the last interpreter instance is destroyed. Frees
    324      * globally allocated memory.
    325      */
    326     void globalClear();
    327     bool evaluate(const UChar *code, unsigned int length, const KJSO &thisV = KJSO(),
    328                   bool onlyCheckSyntax = false);
    329     bool call(const KJSO &scope, const UString &func, const List &args);
    330     bool call(const KJSO &func, const KJSO &thisV,
    331               const List &args, const List &extraScope);
    332 
    333   public:
    334     ProgramNode *progNode() const { return stack->progNode; }
    335     void setProgNode(ProgramNode *p) { stack->progNode = p; }
    336     Node *firstNode() const { return stack->firstNode; }
    337     void setFirstNode(Node *n) { stack->firstNode = n; }
    338     void pushStack();
    339     void popStack();
    340     KJScriptImp *next, *prev;
    341     KJScript *scr;
    342     ExecutionStack *stack;
    343 
    344   private:
    345     ProgramNode *progN;
    346     Node *firstN;
    347 
    348     static KJScriptImp *curr, *hook;
    349     static int instances; // total number of instances
    350     static int running; // total number running
    351     bool initialized;
    352     Lexer *lex;
    353     Context *con;
    354     Global glob;
    355     int errType, errLine;
    356     UString errMsg;
    357 #ifdef KJS_DEBUGGER
    358     Debugger *dbg;
    359     int sid;
    360 #endif
    361     const char *exMsg;
    362     Imp *exVal;
    363     Imp *retVal;
    364     int recursion;
    365   };
    366 
    367   inline bool KJScriptImp::hadException()
    368   {
    369     assert(curr);
    370     return curr->exMsg;
    371   }
    372 
    373   /**
    374    * @short Struct used to return the property names of an object
    375    */
    376   class PropList {
    377   public:
    378     PropList(UString nm = UString::null, PropList *nx = 0) :
    379                           name(nm), next(nx) {};
    380     ~PropList() {
    381       if(next) delete next;
    382     }
    383     /**
    384      * The property name
    385      */
    386     UString name;
    387     /**
    388      * The next property
    389      */
    390     PropList *next;
    391     bool contains(const UString &name);
    392   };
    393 
    394   /* TODO just temporary until functions are objects and this becomes
    395      a member function. Called by RelationNode for 'instanceof' operator. */
    396   KJSO hasInstance(const KJSO &F, const KJSO &V);
    397 
    398 // #define KJS_VERBOSE
    399 #ifndef NDEBUG
    400   void printInfo( const char *s, const KJSO &o );
    401 #endif
    402490
    403491}; // namespace
    404492
    405493
    406 #endif
     494#endif //  _INTERNAL_H_
  • trunk/JavaScriptCore/kjs/lexer.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
     
    1718 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1819 *  Boston, MA 02111-1307, USA.
     20 *
     21 *  $Id$
    1922 */
    2023
     
    2932#include <assert.h>
    3033
    31 #include "kjs.h"
     34#include "value.h"
     35#include "object.h"
     36#include "types.h"
     37#include "interpreter.h"
    3238#include "nodes.h"
    3339#include "lexer.h"
     
    3945using namespace KJS;
    4046
     47static Lexer *currLexer = 0;
     48
    4149#ifndef KDE_USE_FINAL
    4250#include "grammar.h"
     
    4553#include "lexer.lut.h"
    4654
    47 #ifdef KJS_DEBUGGER
    4855extern YYLTYPE yylloc;  // global bison variable holding token info
    49 #endif
    5056
    5157// a bridge for yacc from the C world to C++
     
    5864  : yylineno(0),
    5965    size8(128), size16(128), restrKeyword(false),
    60     stackToken(-1), pos(0),
     66    eatNextIdentifier(false), stackToken(-1), lastToken(-1), pos(0),
    6167    code(0), length(0),
    6268#ifndef KJS_PURE_ECMA
     
    6874  buffer8 = new char[size8];
    6975  buffer16 = new UChar[size16];
     76  currLexer = this;
    7077
    7178}
     
    7986Lexer *Lexer::curr()
    8087{
    81   assert(KJScriptImp::current());
    82   return KJScriptImp::current()->lex;
     88  if (!currLexer) {
     89    // create singleton instance
     90    currLexer = new Lexer();
     91  }
     92  return currLexer;
    8393}
    8494
     
    8898  restrKeyword = false;
    8999  delimited = false;
     100  eatNextIdentifier = false;
    90101  stackToken = -1;
     102  lastToken = -1;
    91103  pos = 0;
    92104  code = c;
    93105  length = len;
     106  skipLF = false;
     107  skipCR = false;
    94108#ifndef KJS_PURE_ECMA
    95109  bol = true;
     
    128142  done = false;
    129143  terminator = false;
     144  skipLF = false;
     145  skipCR = false;
    130146
    131147  // did we push a token on the stack previously ?
     
    138154
    139155  while (!done) {
     156    if (skipLF && current != '\n') // found \r but not \n afterwards
     157        skipLF = false;
     158    if (skipCR && current != '\r') // found \n but not \r afterwards
     159        skipCR = false;
     160    if (skipLF || skipCR) // found \r\n or \n\r -> eat the second one
     161    {
     162        skipLF = false;
     163        skipCR = false;
     164        shift(1);
     165    }
    140166    switch (state) {
    141167    case Start:
     
    316342        record8(current);
    317343        state = InOctal;
     344      } else if (isDecimalDigit(current)) {
     345        record8(current);
     346        state = InDecimal;
    318347      } else {
    319348        setDone(Number);
     
    330359      if (isOctalDigit(current)) {
    331360        record8(current);
     361      }
     362      else if (isDecimalDigit(current)) {
     363        record8(current);
     364        state = InDecimal;
    332365      } else
    333366        setDone(Octal);
     
    434467#endif
    435468
     469  if (state != Identifier && eatNextIdentifier)
     470    eatNextIdentifier = false;
     471
    436472  restrKeyword = false;
    437473  delimited = false;
    438 #ifdef KJS_DEBUGGER
    439474  yylloc.first_line = yylineno; // ???
    440475  yylloc.last_line = yylineno;
    441 #endif
    442476
    443477  switch (state) {
    444478  case Eof:
    445     return 0;
     479    token = 0;
     480    break;
    446481  case Other:
    447482    if(token == '}' || token == ';') {
    448483      delimited = true;
    449484    }
    450     return token;
     485    break;
    451486  case Identifier:
    452487    if ((token = Lookup::find(&mainTable, buffer16, pos16)) < 0) {
     488      // Lookup for keyword failed, means this is an identifier
     489      // Apply anonymous-function hack below (eat the identifier)
     490      if (eatNextIdentifier) {
     491        eatNextIdentifier = false;
     492        UString debugstr(buffer16, pos16); fprintf(stderr,"Anonymous function hack: eating identifier %s\n",debugstr.ascii());
     493        token = lex();
     494        break;
     495      }
    453496      /* TODO: close leak on parse error. same holds true for String */
    454497      kjsyylval.ustr = new UString(buffer16, pos16);
    455       return IDENT;
     498      token = IDENT;
     499      break;
    456500    }
     501
     502    eatNextIdentifier = false;
     503    // Hack for "f = function somename() { ... }", too hard to get into the grammar
     504    if (token == FUNCTION && lastToken == '=' )
     505      eatNextIdentifier = true;
     506
    457507    if (token == CONTINUE || token == BREAK ||
    458508        token == RETURN || token == THROW)
    459509      restrKeyword = true;
    460     return token;
     510    break;
    461511  case String:
    462     kjsyylval.ustr = new UString(buffer16, pos16); return STRING;
     512    kjsyylval.ustr = new UString(buffer16, pos16);
     513    token = STRING;
     514    break;
    463515  case Number:
    464516    kjsyylval.dval = dval;
    465     return NUMBER;
     517    token = NUMBER;
     518    break;
    466519  case Bad:
    467520    fprintf(stderr, "yylex: ERROR.\n");
     
    471524    return -1;
    472525  }
     526  lastToken = token;
     527  return token;
    473528}
    474529
     
    479534}
    480535
    481 bool Lexer::isLineTerminator() const
    482 {
    483   return (current == '\n' || current == '\r');
     536bool Lexer::isLineTerminator()
     537{
     538  bool cr = (current == '\r');
     539  bool lf = (current == '\n');
     540  if (cr)
     541      skipLF = true;
     542  else if (lf)
     543      skipCR = true;
     544  return cr || lf;
    484545}
    485546
     
    541602  } else if (c1 == '+' && c2 == '+') {
    542603    shift(2);
    543     if (terminator) {
    544       // automatic semicolon insertion
    545       stackToken = PLUSPLUS;
    546       return AUTO;
    547     } else
     604    if (terminator)
     605      return AUTOPLUSPLUS;
     606    else
    548607      return PLUSPLUS;
    549608  } else if (c1 == '-' && c2 == '-') {
    550609    shift(2);
    551     if (terminator) {
    552       // automatic semicolon insertion
    553       stackToken = MINUSMINUS;
    554       return AUTO;
    555     } else
     610    if (terminator)
     611      return AUTOMINUSMINUS;
     612    else
    556613      return MINUSMINUS;
    557614  } else if (c1 == '=' && c2 == '=') {
     
    716773  pos16 = 0;
    717774  bool lastWasEscape = false;
     775  bool inBrackets = false;
    718776
    719777  while (1) {
    720778    if (isLineTerminator() || current == 0)
    721779      return false;
    722     else if (current != '/' || lastWasEscape == true)
     780    else if (current != '/' || lastWasEscape == true || inBrackets == true)
    723781    {
     782        // keep track of '[' and ']'
     783        if ( !lastWasEscape ) {
     784          if ( current == '[' && !inBrackets )
     785            inBrackets = true;
     786          if ( current == ']' && inBrackets )
     787            inBrackets = false;
     788        }
    724789        record16(current);
    725790        lastWasEscape =
    726791            !lastWasEscape && (current == '\\');
    727792    }
    728     else {
     793    else { // end of regexp
    729794      pattern = UString(buffer16, pos16);
    730795      pos16 = 0;
  • trunk/JavaScriptCore/kjs/lexer.h

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
     
    1718 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1819 *  Boston, MA 02111-1307, USA.
     20 *
     21 *  $Id$
    1922 */
    2023
     
    6467                 Other,
    6568                 Bad };
    66    
     69
    6770    bool scanRegExp();
    6871    UString pattern, flags;
     
    7982    // encountered delimiter like "'" and "}" on last run
    8083    bool delimited;
     84    bool skipLF;
     85    bool skipCR;
     86    bool eatNextIdentifier;
    8187    int stackToken;
     88    int lastToken;
    8289
    8390    State state;
     
    8895
    8996    bool isWhiteSpace() const;
    90     bool isLineTerminator() const;
     97    bool isLineTerminator();
    9198    bool isHexDigit(unsigned short c) const;
    9299    bool isOctalDigit(unsigned short c) const;
     
    120127    unsigned short current, next1, next2, next3;
    121128
    122     struct keyword {
    123       const char *name;
    124       int token;
    125     };
    126 
    127129    // for future extensions
    128130    class LexerPrivate;
  • trunk/JavaScriptCore/kjs/lexer.lut.h

    r6 r798  
    1 /* automatically generated from keywords.table. DO NOT EDIT ! */
     1/* Automatically generated from keywords.table using ./create_hash_table. DO NOT EDIT ! */
     2
     3#include "lookup.h"
    24
    35namespace KJS {
    46
    5 const struct HashEntry2 mainTableEntries[] = {
    6    { "instanceof", INSTANCEOF, 0, &mainTableEntries[63] },
    7    { "var", VAR, 0, &mainTableEntries[47] },
    8    { "case", CASE, 0, &mainTableEntries[41] },
    9    { "default", DEFAULT, 0, &mainTableEntries[54] },
    10    { "while", WHILE, 0, &mainTableEntries[46] },
    11    { 0, 0, 0, 0 },
    12    { "do", DO, 0, 0 },
    13    { "typeof", TYPEOF, 0, 0 },
    14    { "continue", CONTINUE, 0, 0 },
    15    { "function", FUNCTION, 0, 0 },
    16    { "in", IN, 0, 0 },
    17    { "import", RESERVED, 0, 0 },
    18    { "delete", DELETE, 0, 0 },
    19    { "finally", FINALLY, 0, 0 },
    20    { 0, 0, 0, 0 },
    21    { "else", ELSE, 0, 0 },
    22    { "return", RETURN, 0, 0 },
    23    { "debugger", RESERVED, 0, 0 },
    24    { "const", RESERVED, 0, &mainTableEntries[48] },
    25    { "package", RESERVED, 0, 0 },
    26    { "double", RESERVED, 0, &mainTableEntries[53] },
    27    { 0, 0, 0, 0 },
    28    { "long", RESERVED, 0, 0 },
    29    { "catch", CATCH, 0, &mainTableEntries[45] },
    30    { "void", VOID, 0, &mainTableEntries[59] },
    31    { "break", BREAK, 0, &mainTableEntries[49] },
    32    { "byte", RESERVED, 0, &mainTableEntries[62] },
    33    { "enum", RESERVED, 0, &mainTableEntries[58] },
    34    { 0, 0, 0, 0 },
    35    { 0, 0, 0, 0 },
    36    { "this", THIS, 0, &mainTableEntries[50] },
    37    { "false", FALSETOKEN, 0, &mainTableEntries[44] },
    38    { "abstract", RESERVED, 0, &mainTableEntries[56] },
    39    { "null", NULLTOKEN, 0, &mainTableEntries[61] },
    40    { "with", WITH, 0, 0 },
    41    { 0, 0, 0, 0 },
    42    { 0, 0, 0, 0 },
    43    { 0, 0, 0, 0 },
    44    { "true", TRUETOKEN, 0, 0 },
    45    { "boolean", RESERVED, 0, 0 },
    46    { "for", FOR, 0, 0 },
    47    { "new", NEW, 0, &mainTableEntries[42] },
    48    { "if", IF, 0, &mainTableEntries[43] },
    49    { "switch", SWITCH, 0, &mainTableEntries[55] },
    50    { "throw", THROW, 0, &mainTableEntries[52] },
    51    { "try", TRY, 0, &mainTableEntries[64] },
    52    { "char", RESERVED, 0, 0 },
    53    { "class", RESERVED, 0, &mainTableEntries[51] },
    54    { "export", RESERVED, 0, 0 },
    55    { "extends", RESERVED, 0, &mainTableEntries[57] },
    56    { "final", RESERVED, 0, 0 },
    57    { "float", RESERVED, 0, 0 },
    58    { "goto", RESERVED, 0, 0 },
    59    { "implements", RESERVED, 0, 0 },
    60    { "int", RESERVED, 0, &mainTableEntries[66] },
    61    { "interface", RESERVED, 0, 0 },
    62    { "native", RESERVED, 0, 0 },
    63    { "private", RESERVED, 0, 0 },
    64    { "protected", RESERVED, 0, &mainTableEntries[60] },
    65    { "public", RESERVED, 0, 0 },
    66    { "short", RESERVED, 0, 0 },
    67    { "static", RESERVED, 0, 0 },
    68    { "super", RESERVED, 0, 0 },
    69    { "synchronized", RESERVED, 0, &mainTableEntries[65] },
    70    { "throws", RESERVED, 0, 0 },
    71    { "transient", RESERVED, 0, 0 },
    72    { "volatile", RESERVED, 0, 0 }
     7const struct HashEntry mainTableEntries[] = {
     8   { "instanceof", INSTANCEOF, 0, 0, &mainTableEntries[63] },
     9   { "var", VAR, 0, 0, &mainTableEntries[47] },
     10   { "case", CASE, 0, 0, &mainTableEntries[41] },
     11   { "default", DEFAULT, 0, 0, &mainTableEntries[54] },
     12   { "while", WHILE, 0, 0, &mainTableEntries[46] },
     13   { 0, 0, 0, 0, 0 },
     14   { "do", DO, 0, 0, 0 },
     15   { "typeof", TYPEOF, 0, 0, 0 },
     16   { "continue", CONTINUE, 0, 0, 0 },
     17   { "function", FUNCTION, 0, 0, 0 },
     18   { "in", IN, 0, 0, 0 },
     19   { "import", RESERVED, 0, 0, 0 },
     20   { "delete", DELETE, 0, 0, 0 },
     21   { "finally", FINALLY, 0, 0, 0 },
     22   { 0, 0, 0, 0, 0 },
     23   { "else", ELSE, 0, 0, 0 },
     24   { "return", RETURN, 0, 0, 0 },
     25   { "debugger", RESERVED, 0, 0, 0 },
     26   { "const", RESERVED, 0, 0, &mainTableEntries[48] },
     27   { "package", RESERVED, 0, 0, 0 },
     28   { "double", RESERVED, 0, 0, &mainTableEntries[53] },
     29   { 0, 0, 0, 0, 0 },
     30   { "long", RESERVED, 0, 0, 0 },
     31   { "catch", CATCH, 0, 0, &mainTableEntries[45] },
     32   { "void", VOID, 0, 0, &mainTableEntries[59] },
     33   { "break", BREAK, 0, 0, &mainTableEntries[49] },
     34   { "byte", RESERVED, 0, 0, &mainTableEntries[62] },
     35   { "enum", RESERVED, 0, 0, &mainTableEntries[58] },
     36   { 0, 0, 0, 0, 0 },
     37   { 0, 0, 0, 0, 0 },
     38   { "this", THIS, 0, 0, &mainTableEntries[50] },
     39   { "false", FALSETOKEN, 0, 0, &mainTableEntries[44] },
     40   { "abstract", RESERVED, 0, 0, &mainTableEntries[56] },
     41   { "null", NULLTOKEN, 0, 0, &mainTableEntries[61] },
     42   { "with", WITH, 0, 0, 0 },
     43   { 0, 0, 0, 0, 0 },
     44   { 0, 0, 0, 0, 0 },
     45   { 0, 0, 0, 0, 0 },
     46   { "true", TRUETOKEN, 0, 0, 0 },
     47   { "boolean", RESERVED, 0, 0, 0 },
     48   { "for", FOR, 0, 0, 0 },
     49   { "new", NEW, 0, 0, &mainTableEntries[42] },
     50   { "if", IF, 0, 0, &mainTableEntries[43] },
     51   { "switch", SWITCH, 0, 0, &mainTableEntries[55] },
     52   { "throw", THROW, 0, 0, &mainTableEntries[52] },
     53   { "try", TRY, 0, 0, &mainTableEntries[64] },
     54   { "char", RESERVED, 0, 0, 0 },
     55   { "class", RESERVED, 0, 0, &mainTableEntries[51] },
     56   { "export", RESERVED, 0, 0, 0 },
     57   { "extends", RESERVED, 0, 0, &mainTableEntries[57] },
     58   { "final", RESERVED, 0, 0, 0 },
     59   { "float", RESERVED, 0, 0, 0 },
     60   { "goto", RESERVED, 0, 0, 0 },
     61   { "implements", RESERVED, 0, 0, 0 },
     62   { "int", RESERVED, 0, 0, &mainTableEntries[66] },
     63   { "interface", RESERVED, 0, 0, 0 },
     64   { "native", RESERVED, 0, 0, 0 },
     65   { "private", RESERVED, 0, 0, 0 },
     66   { "protected", RESERVED, 0, 0, &mainTableEntries[60] },
     67   { "public", RESERVED, 0, 0, 0 },
     68   { "short", RESERVED, 0, 0, 0 },
     69   { "static", RESERVED, 0, 0, 0 },
     70   { "super", RESERVED, 0, 0, 0 },
     71   { "synchronized", RESERVED, 0, 0, &mainTableEntries[65] },
     72   { "throws", RESERVED, 0, 0, 0 },
     73   { "transient", RESERVED, 0, 0, 0 },
     74   { "volatile", RESERVED, 0, 0, 0 }
    7375};
    7476
    75 const struct HashTable2 mainTable = { 2, 67, mainTableEntries, 41 };
     77const struct HashTable mainTable = { 2, 67, mainTableEntries, 41 };
    7678
    7779}; // namespace
  • trunk/JavaScriptCore/kjs/lookup.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 *
     20 *  $Id$
    1821 */
    1922
     
    2932using namespace KJS;
    3033
    31 int Lookup::find(const struct HashTable *table,
    32                  const UChar *c, unsigned int len)
    33 {
    34   // we only know about version 1 so far
    35   if (table->type != 1) {
    36     fprintf(stderr, "Unknown hash table version.\n");
    37     return -1;
    38   }
    39 
    40   int h = hash(c, len) % table->hashSize;
    41   const HashEntry *e = &table->entries[h];
    42 
    43   // empty bucket ?
    44   if (!e->c)
    45     return -1;
    46 
    47   do {
    48     // compare strings
    49 #ifdef KJS_SWAPPED_CHAR
    50     /* TODO: not exactly as optimized as the other version ... */
    51     if (len == e->len) {
    52         const UChar *u = (const UChar*)e->c;
    53         const UChar *c2 = c;
    54         unsigned int i;
    55         for (i = 0; i < len; i++, u++, c2++)
    56             if (!(*c2 == UChar(u->low(), u->high()))) // reverse byte order
    57                 goto next;
    58         return e->value;
    59     }
    60 next:
    61 #else
    62     if ((len == e->len) && (memcmp(c, e->c, len * sizeof(UChar)) == 0))
    63         return e->value;
    64 #endif
    65     // try next bucket
    66     e = e->next;
    67   } while (e);
    68 
    69   return -1;
    70 }
    71 
    72 int Lookup::find(const struct HashTable *table, const UString &s)
    73 {
    74   return find(table, s.data(), s.size());
    75 }
    76 
    77 int Lookup::find(const struct HashTable2 *table,
    78                  const UChar *c, unsigned int len)
     34const HashEntry* Lookup::findEntry( const struct HashTable *table,
     35                              const UChar *c, unsigned int len )
    7936{
    8037  if (table->type != 2) {
    81     fprintf(stderr, "Unknown hash table version.\n");
    82     return -1;
     38    fprintf(stderr, "KJS: Unknown hash table version.\n");
     39    return 0;
    8340  }
    84 
    8541  char *ascii = new char[len+1];
    8642  unsigned int i;
     
    9450
    9551  int h = hash(ascii) % table->hashSize;
    96   const HashEntry2 *e = &table->entries[h];
     52  const HashEntry *e = &table->entries[h];
    9753
    9854  // empty bucket ?
    9955  if (!e->s) {
    10056    delete [] ascii;
    101     return -1;
     57    return 0;
    10258  }
    10359
     
    10662    if (strcmp(ascii, e->s) == 0) {
    10763      delete [] ascii;
    108       return e->value;
     64      return e;
    10965    }
    11066    // try next bucket
     
    11369
    11470  delete [] ascii;
     71  return 0;
     72}
     73
     74const HashEntry* Lookup::findEntry( const struct HashTable *table,
     75                                const UString &s )
     76{
     77  return findEntry( table, s.data(), s.size() );
     78}
     79
     80int Lookup::find(const struct HashTable *table,
     81                 const UChar *c, unsigned int len)
     82{
     83  const HashEntry *entry = findEntry( table, c, len );
     84  if (entry)
     85    return entry->value;
    11586  return -1;
    11687}
    11788
    118 int Lookup::find(const struct HashTable2 *table, const UString &s)
     89int Lookup::find(const struct HashTable *table, const UString &s)
    11990{
    12091  return find(table, s.data(), s.size());
  • trunk/JavaScriptCore/kjs/lookup.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2225
    2326#include "ustring.h"
     27#include "value.h"
     28#include <stdio.h>
    2429
    2530namespace KJS {
    2631
    27 #if 1  // obsolete version 1
     32  /**
     33   * An entry in a hash table.
     34   */
    2835  struct HashEntry {
    29     unsigned int len;
    30     const void *c; // unicode data
     36    /** s is the key (e.g. a property name) */
     37    const char *s;
     38    /** value is the result value (usually an enum value) */
    3139    int value;
     40    /** attr is a set for flags (e.g. the property flags, see object.h) */
     41    short int attr;
     42    /** params is another number. For property hashtables, it is used to
     43        denote the number of argument of the function */
     44    short int params;
     45    /** next is the pointer to the next entry for the same hash value */
    3246    const HashEntry *next;
    3347  };
    3448
     49  /**
     50   * A hash table
     51   * Usually the hashtable is generated by the create_hash_table script, from a .table file.
     52   *
     53   * The implementation uses an array of entries, "size" is the total size of that array.
     54   * The entries between 0 and hashSize-1 are the entry points
     55   * for each hash value, and the entries between hashSize and size-1
     56   * are the overflow entries for the hash values that need one.
     57   * The "next" pointer of the entry links entry points to overflow entries,
     58   * and links overflow entries between them.
     59   */
    3560  struct HashTable {
     61    /** type is a version number. Currently always 2 */
    3662    int type;
     63    /** size is the total number of entries in the hashtable, including the null entries,
     64     * i.e. the size of the "entries" array.
     65     * Used to iterate over all entries in the table */
    3766    int size;
     67    /** pointer to the array of entries
     68     * Mind that some entries in the array are null (0,0,0,0). */
    3869    const HashEntry *entries;
    39     int hashSize;
    40   };
    41 #endif
    42 
    43   // version 2
    44   struct HashEntry2 {
    45     const char *s;
    46     int value;
    47     int attr;
    48     const HashEntry2 *next;
    49   };
    50 
    51   struct HashTable2 {
    52     int type;
    53     int size;
    54     const HashEntry2 *entries;
     70    /** the maximum value for the hash. Always smaller than size. */
    5571    int hashSize;
    5672  };
     
    6177  class Lookup {
    6278  public:
    63 #if 1 // obsolete
     79    /** Find an entry in the table, and return its value (i.e. the value field of HashEntry) */
    6480    static int find(const struct HashTable *table, const UString &s);
    6581    static int find(const struct HashTable *table,
    6682                    const UChar *c, unsigned int len);
     83
     84    /**
     85     * Find an entry in the table, and return the entry
     86     * This variant gives access to the other attributes of the entry,
     87     * especially the attr field.
     88     */
     89    static const HashEntry* findEntry(const struct HashTable *table,
     90                                      const UString &s);
     91    static const HashEntry* findEntry(const struct HashTable *table,
     92                                      const UChar *c, unsigned int len);
     93
     94    /** Calculate the hash value for a given key */
     95    static unsigned int hash(const UString &key);
     96    static unsigned int hash(const UChar *c, unsigned int len);
     97    static unsigned int hash(const char *s);
     98  };
     99
     100  class ExecState;
     101  class UString;
     102  /** @internal
     103   * Helper for lookupFunction and lookupValueOrFunction */
     104  template <class FuncImp>
     105  inline Value lookupOrCreateFunction(ExecState *exec, const UString &propertyName,
     106                                      const ObjectImp *thisObj, int token, int params, int attr)
     107  {
     108      // Look for cached value in dynamic map of properties (in ObjectImp)
     109      ValueImp * cachedVal = thisObj->ObjectImp::getDirect(propertyName);
     110      /*if (cachedVal)
     111        fprintf(stderr, "lookupOrCreateFunction: Function -> looked up in ObjectImp, found type=%d\n", cachedVal->type());*/
     112      if (cachedVal)
     113        return Value(cachedVal);
     114
     115      Value val = Value(new FuncImp(exec,token, params));
     116      ObjectImp *thatObj = const_cast<ObjectImp *>(thisObj);
     117      thatObj->ObjectImp::put(exec, propertyName, val, attr);
     118      return val;
     119  }
     120
     121  /**
     122   * Helper method for property lookups
     123   *
     124   * This method does it all (looking in the hashtable, checking for function
     125   * overrides, creating the function or retrieving from cache, calling
     126   * getValueProperty in case of a non-function property, forwarding to parent if
     127   * unknown property).
     128   *
     129   * Template arguments:
     130   * @param FuncImp the class which implements this object's functions
     131   * @param ThisImp the class of "this". It must implement the getValueProperty(exec,token) method,
     132   * for non-function properties.
     133   * @param ParentImp the class of the parent, to propagate the lookup.
     134   *
     135   * Method arguments:
     136   * @param exec execution state, as usual
     137   * @param propertyName the property we're looking for
     138   * @param table the static hashtable for this class
     139   * @param thisObj "this"
     140   */
     141  template <class FuncImp, class ThisImp, class ParentImp>
     142  inline Value lookupGet(ExecState *exec, const UString &propertyName,
     143                         const HashTable* table, const ThisImp* thisObj)
     144  {
     145    const HashEntry* entry = Lookup::findEntry(table, propertyName);
     146
     147    if (!entry) // not found, forward to parent
     148      return thisObj->ParentImp::get(exec, propertyName);
     149
     150    //fprintf(stderr, "lookupGet: found value=%d attr=%d\n", entry->value, entry->attr);
     151    if (entry->attr & Function)
     152      return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr);
     153    return thisObj->getValueProperty(exec, entry->value);
     154  }
     155
     156  /**
     157   * Simplified version of lookupGet in case there are only functions.
     158   * Using this instead of lookupGet prevents 'this' from implementing a dummy getValueProperty.
     159   */
     160  template <class FuncImp, class ParentImp>
     161  inline Value lookupGetFunction(ExecState *exec, const UString &propertyName,
     162                         const HashTable* table, const ObjectImp* thisObj)
     163  {
     164    const HashEntry* entry = Lookup::findEntry(table, propertyName);
     165
     166    if (!entry) // not found, forward to parent
     167      return static_cast<const ParentImp *>(thisObj)->ParentImp::get(exec, propertyName);
     168
     169    if (entry->attr & Function)
     170      return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr);
     171
     172    fprintf(stderr, "Function bit not set! Shouldn't happen in lookupGetFunction!\n" );
     173    return Undefined();
     174  };
     175
     176  /**
     177   * Simplified version of lookupGet in case there are no functions, only "values".
     178   * Using this instead of lookupGet removes the need for a FuncImp class.
     179   */
     180  template <class ThisImp, class ParentImp>
     181  inline Value lookupGetValue(ExecState *exec, const UString &propertyName,
     182                           const HashTable* table, const ThisImp* thisObj)
     183  {
     184    const HashEntry* entry = Lookup::findEntry(table, propertyName);
     185
     186    if (!entry) // not found, forward to parent
     187      return thisObj->ParentImp::get(exec, propertyName);
     188
     189    if (entry->attr & Function)
     190      fprintf(stderr, "Function bit set! Shouldn't happen in lookupGetValue! propertyName was %s\n", propertyName.ascii() );
     191    return thisObj->getValueProperty(exec, entry->value);
     192  }
     193
     194  /**
     195   * This one is for "put".
     196   * Lookup hash entry for property to be set, and set the value.
     197   */
     198  template <class ThisImp, class ParentImp>
     199  inline void lookupPut(ExecState *exec, const UString &propertyName,
     200                        const Value& value, int attr,
     201                        const HashTable* table, const ThisImp* thisObj)
     202  {
     203    const HashEntry* entry = Lookup::findEntry(table, propertyName);
     204
     205    if (!entry) // not found: forward to parent
     206      thisObj->ParentImp::put(exec, propertyName, value, attr);
     207    else if (entry->attr & Function) // function: put as override property
     208      thisObj->ObjectImp::put(exec, propertyName, value, attr);
     209    else if (entry->attr & ReadOnly) // readonly! Can't put!
     210#ifdef KJS_VERBOSE
     211      fprintf(stderr,"WARNING: Attempt to change value of readonly property '%s'\n",propertyName.ascii());
     212#else
     213      ; // do nothing
    67214#endif
    68     static int find(const struct HashTable2 *table, const UString &s);
    69     static int find(const struct HashTable2 *table,
    70                     const UChar *c, unsigned int len);
    71     static unsigned int hash(const UChar *c, unsigned int len);
    72     static unsigned int hash(const UString &key);
    73     static unsigned int hash(const char *s);
    74   private:
    75     HashTable *table;
    76   };
    77 
     215    else
     216      thisObj->putValueProperty(exec, entry->value, value, attr);
     217  }
     218
     219  /*
     220   * List of things to do when porting an objectimp to the 'static hashtable' mechanism:
     221   * - write the hashtable source, between @begin and @end
     222   * - add a rule to build the .lut.h
     223   * - include the .lut.h
     224   * - mention the table in the classinfo (add a classinfo if necessary)
     225   * - write/update the class enum (for the tokens)
     226   * - turn get() into getValueProperty(), put() into putValueProperty(), using a switch and removing funcs
     227   * - write get() and/or put() using a template method
     228   * - cleanup old stuff (e.g. hasProperty)
     229   * - compile, test, commit ;)
     230   */
    78231}; // namespace
    79232
  • trunk/JavaScriptCore/kjs/math_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 *
     20 *  $Id$
    1821 */
    1922
    2023#include <math.h>
    2124#include <stdlib.h>
    22 
    23 #include "kjs.h"
     25#include <stdio.h>
     26#include <assert.h>
     27
     28#include "value.h"
     29#include "object.h"
    2430#include "types.h"
     31#include "interpreter.h"
    2532#include "operations.h"
    2633#include "math_object.h"
    27 #include "lookup.h"
    2834
    2935#include "math_object.lut.h"
     
    3137using namespace KJS;
    3238
    33 KJSO Math::get(const UString &p) const
    34 {
    35   int token = Lookup::find(&mathTable, p);
    36 
    37   if (token < 0)
    38     return Imp::get(p);
    39 
    40   double d;
    41   int len = 1;
     39// ------------------------------ MathObjectImp --------------------------------
     40
     41const ClassInfo MathObjectImp::info = { "Math", 0, &mathTable, 0 };
     42
     43/* Source for math_object.lut.h
     44@begin mathTable 21
     45  E             MathObjectImp::Euler    DontEnum
     46  LN2           MathObjectImp::Ln2      DontEnum
     47  LN10          MathObjectImp::Ln10     DontEnum
     48  LOG2E         MathObjectImp::Log2E    DontEnum
     49  LOG10E        MathObjectImp::Log10E   DontEnum
     50  PI            MathObjectImp::Pi       DontEnum
     51  SQRT1_2       MathObjectImp::Sqrt1_2  DontEnum
     52  SQRT2         MathObjectImp::Sqrt2    DontEnum
     53  abs           MathObjectImp::Abs      DontEnum|Function 1
     54  acos          MathObjectImp::ACos     DontEnum|Function 1
     55  asin          MathObjectImp::ASin     DontEnum|Function 1
     56  atan          MathObjectImp::ATan     DontEnum|Function 1
     57  atan2         MathObjectImp::ATan2    DontEnum|Function 2
     58  ceil          MathObjectImp::Ceil     DontEnum|Function 1
     59  cos           MathObjectImp::Cos      DontEnum|Function 1
     60  exp           MathObjectImp::Exp      DontEnum|Function 1
     61  floor         MathObjectImp::Floor    DontEnum|Function 1
     62  log           MathObjectImp::Log      DontEnum|Function 1
     63  max           MathObjectImp::Max      DontEnum|Function 2
     64  min           MathObjectImp::Min      DontEnum|Function 2
     65  pow           MathObjectImp::Pow      DontEnum|Function 2
     66  random        MathObjectImp::Random   DontEnum|Function 0
     67  round         MathObjectImp::Round    DontEnum|Function 1
     68  sin           MathObjectImp::Sin      DontEnum|Function 1
     69  sqrt          MathObjectImp::Sqrt     DontEnum|Function 1
     70  tan           MathObjectImp::Tan      DontEnum|Function 1
     71@end
     72*/
     73
     74MathObjectImp::MathObjectImp(ExecState * /*exec*/,
     75                             ObjectPrototypeImp *objProto)
     76  : ObjectImp(Object(objProto))
     77{
     78}
     79
     80// ECMA 15.8
     81Value MathObjectImp::get(ExecState *exec, const UString &propertyName) const
     82{
     83  return lookupGet<MathFuncImp, MathObjectImp, ObjectImp>( exec, propertyName, &mathTable, this );
     84}
     85
     86Value MathObjectImp::getValueProperty(ExecState *, int token) const
     87{
     88  double d = -42; // ;)
    4289  switch (token) {
    43   case Math::Euler:
     90  case Euler:
    4491    d = exp(1.0);
    4592    break;
    46   case Math::Ln2:
     93  case Ln2:
    4794    d = log(2.0);
    4895    break;
    49   case Math::Ln10:
     96  case Ln10:
    5097    d = log(10.0);
    5198    break;
    52   case Math::Log2E:
     99  case Log2E:
    53100    d = 1.0/log(2.0);
    54101    break;
    55   case Math::Log10E:
     102  case Log10E:
    56103    d = 1.0/log(10.0);
    57104    break;
    58   case Math::Pi:
     105  case Pi:
    59106    d = 2.0 * asin(1.0);
    60107    break;
    61   case Math::Sqrt1_2:
     108  case Sqrt1_2:
    62109    d = sqrt(0.5);
    63110    break;
    64   case Math::Sqrt2:
     111  case Sqrt2:
    65112    d = sqrt(2.0);
    66113    break;
    67114  default:
    68     if (token == Math::Min || token == Math::Max || token == Math::Pow)
    69       len = 2;
    70     return Function(new MathFunc(token, len));
    71   };
     115    fprintf( stderr, "Internal error in MathObjectImp: unhandled token %d\n", token );
     116    break;
     117  }
    72118
    73119  return Number(d);
    74120}
    75121
    76 bool Math::hasProperty(const UString &p, bool recursive) const
    77 {
    78   return (Lookup::find(&mathTable, p) >= 0 ||
    79           (recursive && Imp::hasProperty(p, recursive)));
    80 }
    81 
    82 Completion MathFunc::execute(const List &args)
    83 {
    84   KJSO v = args[0];
    85   Number n = v.toNumber();
     122// ------------------------------ MathObjectImp --------------------------------
     123
     124MathFuncImp::MathFuncImp(ExecState *exec, int i, int l)
     125  : InternalFunctionImp(
     126    static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
     127    ), id(i)
     128{
     129  Value protect(this);
     130  put(exec,"length",Number(l),DontDelete|ReadOnly|DontEnum);
     131}
     132
     133bool MathFuncImp::implementsCall() const
     134{
     135  return true;
     136}
     137
     138Value MathFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
     139{
     140  Value v = args[0];
     141  Number n = v.toNumber(exec);
    86142  double arg = n.value();
    87143
    88   KJSO v2 = args[1];
    89   Number n2 = v2.toNumber();
     144  Value v2 = args[1];
     145  Number n2 = v2.toNumber(exec);
    90146  double arg2 = n2.value();
    91147  double result;
    92148
    93149  switch (id) {
    94   case Math::Abs:
    95     result = ( arg < 0 ) ? (-arg) : arg;
    96     break;
    97   case Math::ACos:
     150  case MathObjectImp::Abs:
     151    result = ( arg < 0 || arg == -0) ? (-arg) : arg;
     152    break;
     153  case MathObjectImp::ACos:
    98154    result = ::acos(arg);
    99155    break;
    100   case Math::ASin:
     156  case MathObjectImp::ASin:
    101157    result = ::asin(arg);
    102158    break;
    103   case Math::ATan:
     159  case MathObjectImp::ATan:
    104160    result = ::atan(arg);
    105161    break;
    106   case Math::ATan2:
     162  case MathObjectImp::ATan2:
    107163    result = ::atan2(arg, arg2);
    108164    break;
    109   case Math::Ceil:
     165  case MathObjectImp::Ceil:
    110166    result = ::ceil(arg);
    111167    break;
    112   case Math::Cos:
     168  case MathObjectImp::Cos:
    113169    result = ::cos(arg);
    114170    break;
    115   case Math::Exp:
     171  case MathObjectImp::Exp:
    116172    result = ::exp(arg);
    117173    break;
    118   case Math::Floor:
     174  case MathObjectImp::Floor:
    119175    result = ::floor(arg);
    120176    break;
    121   case Math::Log:
     177  case MathObjectImp::Log:
    122178    result = ::log(arg);
    123179    break;
    124   case Math::Max:
    125     result = ( arg > arg2 ) ? arg : arg2;
    126     break;
    127   case Math::Min:
    128     result = ( arg < arg2 ) ? arg : arg2;
    129     break;
    130   case Math::Pow:
    131     result = ::pow(arg, arg2);
    132     break;
    133   case Math::Random:
     180  case MathObjectImp::Max: {
     181    unsigned int argsCount = args.size();
     182    result = -Inf;
     183    for ( unsigned int k = 0 ; k < argsCount ; ++k ) {
     184      double val = args[k].toNumber(exec);
     185      if ( isNaN( val ) )
     186      {
     187        result = NaN;
     188        break;
     189      }
     190      if ( val > result )
     191        result = val;
     192    }
     193    break;
     194  }
     195  case MathObjectImp::Min: {
     196    unsigned int argsCount = args.size();
     197    result = +Inf;
     198    for ( unsigned int k = 0 ; k < argsCount ; ++k ) {
     199      double val = args[k].toNumber(exec);
     200      if ( isNaN( val ) )
     201      {
     202        result = NaN;
     203        break;
     204      }
     205      if ( val < result )
     206        result = val;
     207    }
     208    break;
     209  }
     210  case MathObjectImp::Pow:
     211    // ECMA 15.8.2.1.13 (::pow takes care of most of the critera)
     212    if (KJS::isNaN(arg2))
     213      result = NaN;
     214    else if (arg2 == 0)
     215      result = 1;
     216    else if (KJS::isNaN(arg) && arg2 != 0)
     217      result = NaN;
     218    else if (::fabs(arg) > 1 && KJS::isPosInf(arg2))
     219      result = Inf;
     220    else if (::fabs(arg) > 1 && KJS::isNegInf(arg2))
     221      result = +0;
     222    else if (::fabs(arg) == 1 && KJS::isPosInf(arg2))
     223      result = NaN;
     224    else if (::fabs(arg) == 1 && KJS::isNegInf(arg2))
     225      result = NaN;
     226    else if (::fabs(arg) < 1 && KJS::isPosInf(arg2))
     227      result = +0;
     228    else if (::fabs(arg) < 1 && KJS::isNegInf(arg2))
     229      result = Inf;
     230    else
     231      result = ::pow(arg, arg2);
     232    break;
     233  case MathObjectImp::Random:
    134234    result = ::rand();
    135235    result = result / RAND_MAX;
    136236    break;
    137   case Math::Round:
     237  case MathObjectImp::Round:
    138238    if (isNaN(arg))
    139239      result = arg;
     
    145245      result = (double)(arg >= 0.0 ? int(arg + 0.5) : int(arg - 0.5));
    146246    break;
    147   case Math::Sin:
     247  case MathObjectImp::Sin:
    148248    result = ::sin(arg);
    149249    break;
    150   case Math::Sqrt:
     250  case MathObjectImp::Sqrt:
    151251    result = ::sqrt(arg);
    152252    break;
    153   case Math::Tan:
     253  case MathObjectImp::Tan:
    154254    result = ::tan(arg);
    155255    break;
     
    160260  }
    161261
    162   return Completion(ReturnValue, Number(result));
    163 }
     262  return Number(result);
     263}
  • trunk/JavaScriptCore/kjs/math_object.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2124#define _MATH_OBJECT_H_
    2225
    23 #include "object.h"
    24 #include "function.h"
     26#include "internal.h"
     27#include "function_object.h"
    2528
    2629namespace KJS {
    2730
    28   class Math : public ObjectImp {
     31  class MathObjectImp : public ObjectImp {
    2932  public:
    30     Math() : ObjectImp(BooleanClass) { }
    31     virtual KJSO get(const UString &p) const;
    32     virtual bool hasProperty(const UString &p, bool recursive = true) const;
     33    MathObjectImp(ExecState *exec,
     34                  ObjectPrototypeImp *objProto);
     35    Value get(ExecState *exec, const UString &p) const;
     36    Value getValueProperty(ExecState *exec, int token) const;
     37    virtual const ClassInfo *classInfo() const { return &info; }
     38    static const ClassInfo info;
    3339    enum { Euler, Ln2, Ln10, Log2E, Log10E, Pi, Sqrt1_2, Sqrt2,
    34            Abs, ACos, ASin, ATan, ATan2, Ceil, Cos, Pow,
    35            Exp, Floor, Log, Max, Min, Random, Round, Sin, Sqrt, Tan };
     40           Abs, ACos, ASin, ATan, ATan2, Ceil, Cos, Pow,
     41           Exp, Floor, Log, Max, Min, Random, Round, Sin, Sqrt, Tan };
    3642  };
    3743
    38   class MathFunc : public InternalFunctionImp {
     44  class MathFuncImp : public InternalFunctionImp {
    3945  public:
    40     MathFunc(int i, int l) : InternalFunctionImp(l), id(i) { }
    41     Completion execute(const List &);
     46    MathFuncImp(ExecState *exec, int i, int l);
     47    virtual bool implementsCall() const;
     48    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
    4249  private:
    4350    int id;
  • trunk/JavaScriptCore/kjs/math_object.lut.h

    r6 r798  
    1 /* automatically generated from math.table. DO NOT EDIT ! */
     1/* Automatically generated from math_object.cpp using ./create_hash_table. DO NOT EDIT ! */
     2
     3#include "lookup.h"
    24
    35namespace KJS {
    46
    5 const struct HashEntry2 mathTableEntries[] = {
    6    { "atan", Math::ATan, DontEnum|ReadOnly, &mathTableEntries[25] },
    7    { 0, 0, 0, 0 },
    8    { "SQRT2", Math::Sqrt2, DontEnum|ReadOnly, &mathTableEntries[23] },
    9    { 0, 0, 0, 0 },
    10    { 0, 0, 0, 0 },
    11    { 0, 0, 0, 0 },
    12    { "E", Math::Euler, DontEnum|ReadOnly, &mathTableEntries[21] },
    13    { "asin", Math::ASin, DontEnum|ReadOnly, &mathTableEntries[26] },
    14    { "atan2", Math::ATan2, DontEnum|ReadOnly, &mathTableEntries[31] },
    15    { "LOG2E", Math::Log2E, DontEnum|ReadOnly, &mathTableEntries[27] },
    16    { "cos", Math::Cos, DontEnum|ReadOnly, 0 },
    17    { "max", Math::Max, DontEnum|ReadOnly, &mathTableEntries[28] },
    18    { 0, 0, 0, 0 },
    19    { 0, 0, 0, 0 },
    20    { "LOG10E", Math::Log10E, DontEnum|ReadOnly, &mathTableEntries[24] },
    21    { "LN2", Math::Ln2, DontEnum|ReadOnly, &mathTableEntries[30] },
    22    { "abs", Math::Abs, DontEnum|ReadOnly, 0 },
    23    { "sqrt", Math::Sqrt, DontEnum|ReadOnly, 0 },
    24    { "exp", Math::Exp, DontEnum|ReadOnly, 0 },
    25    { 0, 0, 0, 0 },
    26    { "LN10", Math::Ln10, DontEnum|ReadOnly, &mathTableEntries[22] },
    27    { "PI", Math::Pi, DontEnum|ReadOnly, &mathTableEntries[29] },
    28    { "SQRT1_2", Math::Sqrt1_2, DontEnum|ReadOnly, 0 },
    29    { "acos", Math::ACos, DontEnum|ReadOnly, 0 },
    30    { "ceil", Math::Ceil, DontEnum|ReadOnly, 0 },
    31    { "floor", Math::Floor, DontEnum|ReadOnly, 0 },
    32    { "log", Math::Log, DontEnum|ReadOnly, 0 },
    33    { "min", Math::Min, DontEnum|ReadOnly, 0 },
    34    { "random", Math::Random, DontEnum|ReadOnly, 0 },
    35    { "round", Math::Round, DontEnum|ReadOnly, 0 },
    36    { "sin", Math::Sin, DontEnum|ReadOnly, 0 },
    37    { "tan", Math::Tan, DontEnum|ReadOnly, 0 }
     7const struct HashEntry mathTableEntries[] = {
     8   { "atan", MathObjectImp::ATan, DontEnum|Function, 1, &mathTableEntries[25] },
     9   { 0, 0, 0, 0, 0 },
     10   { "SQRT2", MathObjectImp::Sqrt2, DontEnum, 0, &mathTableEntries[23] },
     11   { 0, 0, 0, 0, 0 },
     12   { 0, 0, 0, 0, 0 },
     13   { 0, 0, 0, 0, 0 },
     14   { "E", MathObjectImp::Euler, DontEnum, 0, &mathTableEntries[21] },
     15   { "asin", MathObjectImp::ASin, DontEnum|Function, 1, &mathTableEntries[26] },
     16   { "atan2", MathObjectImp::ATan2, DontEnum|Function, 2, &mathTableEntries[32] },
     17   { "LOG2E", MathObjectImp::Log2E, DontEnum, 0, &mathTableEntries[27] },
     18   { "cos", MathObjectImp::Cos, DontEnum|Function, 1, 0 },
     19   { "max", MathObjectImp::Max, DontEnum|Function, 2, &mathTableEntries[29] },
     20   { 0, 0, 0, 0, 0 },
     21   { 0, 0, 0, 0, 0 },
     22   { "LOG10E", MathObjectImp::Log10E, DontEnum, 0, &mathTableEntries[24] },
     23   { "LN2", MathObjectImp::Ln2, DontEnum, 0, &mathTableEntries[31] },
     24   { "abs", MathObjectImp::Abs, DontEnum|Function, 1, 0 },
     25   { "sqrt", MathObjectImp::Sqrt, DontEnum|Function, 1, 0 },
     26   { "exp", MathObjectImp::Exp, DontEnum|Function, 1, 0 },
     27   { 0, 0, 0, 0, 0 },
     28   { "LN10", MathObjectImp::Ln10, DontEnum, 0, &mathTableEntries[22] },
     29   { "PI", MathObjectImp::Pi, DontEnum, 0, &mathTableEntries[28] },
     30   { "SQRT1_2", MathObjectImp::Sqrt1_2, DontEnum, 0, 0 },
     31   { "acos", MathObjectImp::ACos, DontEnum|Function, 1, 0 },
     32   { "ceil", MathObjectImp::Ceil, DontEnum|Function, 1, 0 },
     33   { "floor", MathObjectImp::Floor, DontEnum|Function, 1, 0 },
     34   { "log", MathObjectImp::Log, DontEnum|Function, 1, 0 },
     35   { "min", MathObjectImp::Min, DontEnum|Function, 2, 0 },
     36   { "pow", MathObjectImp::Pow, DontEnum|Function, 2, &mathTableEntries[30] },
     37   { "random", MathObjectImp::Random, DontEnum|Function, 0, 0 },
     38   { "round", MathObjectImp::Round, DontEnum|Function, 1, 0 },
     39   { "sin", MathObjectImp::Sin, DontEnum|Function, 1, 0 },
     40   { "tan", MathObjectImp::Tan, DontEnum|Function, 1, 0 }
    3841};
    3942
    40 const struct HashTable2 mathTable = { 2, 32, mathTableEntries, 21 };
     43const struct HashTable mathTable = { 2, 33, mathTableEntries, 21 };
    4144
    4245}; // namespace
  • trunk/JavaScriptCore/kjs/nodes.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    34 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1719 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1820 *  Boston, MA 02111-1307, USA.
     21 *
    1922 */
    2023
     
    2225
    2326#include <assert.h>
     27#include <iostream.h>
     28#include <math.h>
    2429#include <stdio.h>
    25 #include <math.h>
    26 
    27 #include "kjs.h"
     30#ifdef KJS_DEBUG_MEM
     31#include <typeinfo>
     32#endif
     33
     34#include "collector.h"
     35#include "debugger.h"
     36#include "function_object.h"
     37#include "internal.h"
     38#include "value.h"
     39#include "object.h"
     40#include "types.h"
     41#include "interpreter.h"
     42#include "lexer.h"
     43#include "operations.h"
    2844#include "ustring.h"
    29 #include "lexer.h"
    30 #include "types.h"
    31 #include "internal.h"
    32 #include "operations.h"
    33 #include "regexp_object.h"
    34 #include "debugger.h"
    3545
    3646using namespace KJS;
    3747
    38 #ifdef KJS_DEBUGGER
    39 #define KJS_BREAKPOINT if (!hitStatement()) return Completion(Normal);
    40 #define KJS_ABORTPOINT if (abortStatement()) return Completion(Normal);
    41 #else
    42 #define KJS_BREAKPOINT
    43 #define KJS_ABORTPOINT
     48#define KJS_BREAKPOINT \
     49  if (!hitStatement(exec)) \
     50    return Completion(Normal);
     51
     52#define KJS_ABORTPOINT \
     53  if (exec->interpreter()->imp()->debugger() && \
     54      exec->interpreter()->imp()->debugger()->imp()->aborted()) \
     55    return Completion(Normal);
     56
     57#define KJS_CHECKEXCEPTION \
     58  if (exec->hadException()) \
     59    return Completion(Throw, exec->exception()); \
     60  if (Collector::outOfMemory()) \
     61    return Completion(Throw, Error::create(exec,GeneralError,"Out of memory"));
     62
     63#define KJS_CHECKEXCEPTIONVALUE \
     64  if (exec->hadException()) \
     65    return exec->exception(); \
     66  if (Collector::outOfMemory()) \
     67    return Undefined(); // will be picked up by KJS_CHECKEXCEPTION
     68
     69#define KJS_CHECKEXCEPTIONLIST \
     70  if (exec->hadException()) \
     71    return List(); \
     72  if (Collector::outOfMemory()) \
     73    return List(); // will be picked up by KJS_CHECKEXCEPTION
     74
     75#ifdef KJS_DEBUG_MEM
     76std::list<Node *> Node::s_nodes;
    4477#endif
    45 
    46 int   Node::nodeCount = 0;
    47 Node* Node::first = 0;
     78// ------------------------------ Node -----------------------------------------
    4879
    4980Node::Node()
    5081{
    51   assert(Lexer::curr());
    5282  line = Lexer::curr()->lineNo();
    53   nodeCount++;
    54   //  cout << "Node()" << endl;
    55 
    56   // create a list of allocated objects. Makes
    57   // deleting (even after a parse error) quite easy
    58   next = first;
    59   prev = 0L;
    60   if (first)
    61     first->prev = this;
    62   first = this;
     83  refcount = 0;
     84#ifdef KJS_DEBUG_MEM
     85  s_nodes.push_back( this );
     86#endif
    6387}
    6488
    6589Node::~Node()
    6690{
    67   //  cout << "~Node()" << endl;
    68   if (next)
    69     next->prev = prev;
    70   if (prev)
    71     prev->next = next;
    72   nodeCount--;
    73 }
    74 
    75 void Node::deleteAllNodes()
    76 {
    77   Node *tmp, *n = first;
    78 
    79   while ((tmp = n)) {
    80     n = n->next;
    81     delete tmp;
    82   }
    83   first = 0L;
    84   //  assert(nodeCount == 0);
    85 }
    86 
    87 KJSO Node::throwError(ErrorType e, const char *msg)
    88 {
    89   return Error::create(e, msg, lineNo());
    90 }
    91 
    92 #ifdef KJS_DEBUGGER
    93 void StatementNode::setLoc(int line0, int line1)
     91#ifdef KJS_DEBUG_MEM
     92  s_nodes.remove( this );
     93#endif
     94}
     95
     96#ifdef KJS_DEBUG_MEM
     97void Node::finalCheck()
     98{
     99  fprintf( stderr, "Node::finalCheck(): list count       : %d\n", s_nodes.size() );
     100  std::list<Node *>::iterator it = s_nodes.begin();
     101  for ( uint i = 0; it != s_nodes.end() ; ++it, ++i )
     102    fprintf( stderr, "[%d] Still having node %p (%s) (refcount %d)\n", i, (void*)*it, typeid( **it ).name(), (*it)->refcount );
     103}
     104#endif
     105
     106Value Node::throwError(ExecState *exec, ErrorType e, const char *msg)
     107{
     108  Object err = Error::create(exec, e, msg, lineNo(), sourceId());
     109  exec->setException(err);
     110  return err;
     111}
     112
     113// ------------------------------ StatementNode --------------------------------
     114StatementNode::StatementNode() : l0(-1), l1(-1), sid(-1), breakPoint(false)
     115{
     116}
     117
     118StatementNode::~StatementNode()
     119{
     120}
     121
     122void StatementNode::setLoc(int line0, int line1, int sourceId)
    94123{
    95124    l0 = line0;
    96125    l1 = line1;
    97     sid = KJScriptImp::current()->sourceId();
    98 }
    99 
    100 bool StatementNode::hitStatement()
    101 {
    102   if (KJScriptImp::current()->debugger())
    103     return KJScriptImp::current()->debugger()->hit(firstLine(), breakPoint);
     126    sid = sourceId;
     127}
     128
     129// return true if the debugger wants us to stop at this point
     130bool StatementNode::hitStatement(ExecState *exec)
     131{
     132  Debugger *dbg = exec->interpreter()->imp()->debugger();
     133  if (dbg)
     134    return dbg->atStatement(exec,sid,l0,l1);
    104135  else
    105     return true;
     136    return true; // continue
    106137}
    107138
    108139// return true if the debugger wants us to stop at this point
    109 bool StatementNode::abortStatement()
    110 {
    111   if (KJScriptImp::current()->debugger() &&
    112       KJScriptImp::current()->debugger()->mode() == Debugger::Stop)
    113       return true;
    114 
    115   return false;
    116 }
    117 
    118 bool Node::setBreakpoint(Node *firstNode, int id, int line, bool set)
    119 {
    120   while (firstNode) {
    121     if (firstNode->setBreakpoint(id, line, set) && line >= 0) // line<0 for all
    122       return true;
    123     firstNode = firstNode->next;
    124   }
    125   return false;
    126 }
    127 
    128 /**
    129  * Try to set or delete a breakpoint depending on the value of set.
    130  * The call will return true if successful, i.e. if line is inside
    131  * of the statement's range. Additionally, a breakpoint had to
    132  * be set already if you tried to delete with set=false.
    133  */
    134 bool StatementNode::setBreakpoint(int id, int line, bool set)
    135 {
    136   // in our source unit and line range ?
    137   if (id != sid || ((line < l0 || line > l1) && line >= 0))
     140bool StatementNode::abortStatement(ExecState *exec)
     141{
     142  Debugger *dbg = exec->interpreter()->imp()->debugger();
     143  if (dbg)
     144    return dbg->imp()->aborted();
     145  else
    138146    return false;
    139 
    140   if (!set && !breakPoint)
    141     return false;
    142 
    143   breakPoint = set;
    144   return true;
    145 }
    146 #endif
    147 
    148 KJSO NullNode::evaluate()
     147}
     148
     149// ------------------------------ NullNode -------------------------------------
     150
     151Value NullNode::evaluate(ExecState */*exec*/)
    149152{
    150153  return Null();
    151154}
    152155
    153 KJSO BooleanNode::evaluate()
     156// ------------------------------ BooleanNode ----------------------------------
     157
     158Value BooleanNode::evaluate(ExecState */*exec*/)
    154159{
    155160  return Boolean(value);
    156161}
    157162
    158 KJSO NumberNode::evaluate()
     163// ------------------------------ NumberNode -----------------------------------
     164
     165Value NumberNode::evaluate(ExecState */*exec*/)
    159166{
    160167  return Number(value);
    161168}
    162169
    163 KJSO StringNode::evaluate()
     170// ------------------------------ StringNode -----------------------------------
     171
     172Value StringNode::evaluate(ExecState */*exec*/)
    164173{
    165174  return String(value);
    166175}
    167176
    168 KJSO RegExpNode::evaluate()
     177// ------------------------------ RegExpNode -----------------------------------
     178
     179Value RegExpNode::evaluate(ExecState *exec)
    169180{
    170181  List list;
     
    174185  list.append(f);
    175186
    176   // very ugly
    177   KJSO r = Global::current().get("RegExp");
    178   RegExpObject *r2 = (RegExpObject*)r.imp();
    179   return r2->construct(list);
    180 }
     187  Object reg = exec->interpreter()->imp()->builtinRegExp();
     188  return reg.construct(exec,list);
     189}
     190
     191// ------------------------------ ThisNode -------------------------------------
    181192
    182193// ECMA 11.1.1
    183 KJSO ThisNode::evaluate()
    184 {
    185   return Context::current()->thisValue();
    186 }
     194Value ThisNode::evaluate(ExecState *exec)
     195{
     196  return exec->context().thisValue();
     197}
     198
     199// ------------------------------ ResolveNode ----------------------------------
    187200
    188201// ECMA 11.1.2 & 10.1.4
    189 KJSO ResolveNode::evaluate()
    190 {
    191   assert(Context::current());
    192   const List *chain = Context::current()->pScopeChain();
    193   assert(chain);
    194   ListIterator scope = chain->begin();
    195 
    196   while (scope != chain->end()) {
    197     if (scope->hasProperty(ident)) {
    198 //        cout << "Resolve: found '" << ident.ascii() << "'"
    199 //          << " type " << scope->get(ident).imp()->typeInfo()->name << endl;
    200       return Reference(*scope, ident);
     202Value ResolveNode::evaluate(ExecState *exec)
     203{
     204  const List chain = exec->context().scopeChain();
     205  ListIterator scope = chain.begin();
     206
     207  while (scope != chain.end()) {
     208    ObjectImp *o = static_cast<ObjectImp*>((*scope).imp());
     209
     210    //cout << "Resolve: looking at '" << ident.ascii() << "'"
     211    //     << " in " << (void*)o << " " << o->classInfo()->className << endl;
     212    if (o->hasProperty(exec,ident)) {
     213      //cout << "Resolve: FOUND '" << ident.ascii() << "'"
     214      //     << " in " << (void*)o << " " << o->classInfo()->className << endl;
     215      return Reference(Object(o), ident);
    201216    }
    202217    scope++;
     
    204219
    205220  // identifier not found
    206 //  cout << "Resolve: didn't find '" << ident.ascii() << "'" << endl;
     221  //cout << "Resolve: didn't find '" << ident.ascii() << "'" << endl;
    207222  return Reference(Null(), ident);
    208223}
    209224
     225// ------------------------------ GroupNode ------------------------------------
     226
     227GroupNode::~GroupNode()
     228{
     229}
     230
     231void GroupNode::ref()
     232{
     233  Node::ref();
     234  if ( group )
     235    group->ref();
     236}
     237
     238bool GroupNode::deref()
     239{
     240  if ( group && group->deref() )
     241    delete group;
     242  return Node::deref();
     243}
     244
     245// ECMA 11.1.6
     246Value GroupNode::evaluate(ExecState *exec)
     247{
     248  return group->evaluate(exec);
     249}
     250
     251// ------------------------------ ElisionNode ----------------------------------
     252
     253ElisionNode::~ElisionNode()
     254{
     255}
     256
     257void ElisionNode::ref()
     258{
     259  Node::ref();
     260  if ( elision )
     261    elision->ref();
     262}
     263
     264bool ElisionNode::deref()
     265{
     266  if ( elision && elision->deref() )
     267    delete elision;
     268  return Node::deref();
     269}
     270
    210271// ECMA 11.1.4
    211 KJSO ArrayNode::evaluate()
    212 {
    213   KJSO array;
     272Value ElisionNode::evaluate(ExecState *exec)
     273{
     274  if (elision)
     275    return Number(elision->evaluate(exec).toNumber(exec) + 1);
     276  else
     277    return Number(1);
     278}
     279
     280// ------------------------------ ElementNode ----------------------------------
     281
     282ElementNode::~ElementNode()
     283{
     284}
     285
     286void ElementNode::ref()
     287{
     288  Node::ref();
     289  if ( list )
     290    list->ref();
     291  if ( elision )
     292    elision->ref();
     293  if ( node )
     294    node->ref();
     295}
     296
     297bool ElementNode::deref()
     298{
     299  if ( list && list->deref() )
     300    delete list;
     301  if ( elision && elision->deref() )
     302    delete elision;
     303  if ( node && node->deref() )
     304    delete node;
     305  return Node::deref();
     306}
     307
     308// ECMA 11.1.4
     309Value ElementNode::evaluate(ExecState *exec)
     310{
     311  Object array;
     312  Value val;
     313  int length = 0;
     314  int elisionLen = elision ? elision->evaluate(exec).toInt32(exec) : 0;
     315  KJS_CHECKEXCEPTIONVALUE
     316
     317  if (list) {
     318    array = Object(static_cast<ObjectImp*>(list->evaluate(exec).imp()));
     319    KJS_CHECKEXCEPTIONVALUE
     320    val = node->evaluate(exec).getValue(exec);
     321    length = array.get(exec,"length").toInt32(exec);
     322  } else {
     323    Value newArr = exec->interpreter()->builtinArray().construct(exec,List::empty());
     324    array = Object(static_cast<ObjectImp*>(newArr.imp()));
     325    val = node->evaluate(exec).getValue(exec);
     326    KJS_CHECKEXCEPTIONVALUE
     327  }
     328
     329  array.put(exec, UString::from(elisionLen + length), val);
     330
     331  return array;
     332}
     333
     334// ------------------------------ ArrayNode ------------------------------------
     335
     336ArrayNode::~ArrayNode()
     337{
     338}
     339
     340void ArrayNode::ref()
     341{
     342  Node::ref();
     343  if ( element )
     344    element->ref();
     345  if ( elision )
     346    elision->ref();
     347}
     348
     349bool ArrayNode::deref()
     350{
     351  if ( element && element->deref() )
     352    delete element;
     353  if ( elision && elision->deref() )
     354    delete elision;
     355  return Node::deref();
     356}
     357
     358// ECMA 11.1.4
     359Value ArrayNode::evaluate(ExecState *exec)
     360{
     361  Object array;
    214362  int length;
    215   int elisionLen = elision ? elision->evaluate().toInt32() : 0;
     363  int elisionLen = elision ? elision->evaluate(exec).toInt32(exec) : 0;
     364  KJS_CHECKEXCEPTIONVALUE
    216365
    217366  if (element) {
    218     array = element->evaluate();
    219     length = opt ? array.get("length").toInt32() : 0;
     367    array = Object(static_cast<ObjectImp*>(element->evaluate(exec).imp()));
     368    KJS_CHECKEXCEPTIONVALUE
     369    length = opt ? array.get(exec,"length").toInt32(exec) : 0;
    220370  } else {
    221     array = Object::create(ArrayClass);
     371    Value newArr = exec->interpreter()->builtinArray().construct(exec,List::empty());
     372    array = Object(static_cast<ObjectImp*>(newArr.imp()));
    222373    length = 0;
    223374  }
    224375
    225376  if (opt)
    226     array.put("length", Number(elisionLen + length), DontEnum | DontDelete);
     377    array.put(exec,"length", Number(elisionLen + length), DontEnum | DontDelete);
    227378
    228379  return array;
    229380}
    230381
    231 // ECMA 11.1.4
    232 KJSO ElementNode::evaluate()
    233 {
    234   KJSO array, val;
    235   int length = 0;
    236   int elisionLen = elision ? elision->evaluate().toInt32() : 0;
    237 
     382// ------------------------------ ObjectLiteralNode ----------------------------
     383
     384ObjectLiteralNode::~ObjectLiteralNode()
     385{
     386}
     387
     388void ObjectLiteralNode::ref()
     389{
     390  Node::ref();
     391  if ( list )
     392    list->ref();
     393}
     394
     395bool ObjectLiteralNode::deref()
     396{
     397  if ( list && list->deref() )
     398    delete list;
     399  return Node::deref();
     400}
     401
     402// ECMA 11.1.5
     403Value ObjectLiteralNode::evaluate(ExecState *exec)
     404{
     405  if (list)
     406    return list->evaluate(exec);
     407
     408  return exec->interpreter()->builtinObject().construct(exec,List::empty());
     409}
     410
     411// ------------------------------ PropertyValueNode ----------------------------
     412
     413PropertyValueNode::~PropertyValueNode()
     414{
     415}
     416
     417void PropertyValueNode::ref()
     418{
     419  Node::ref();
     420  if ( name )
     421    name->ref();
     422  if ( assign )
     423    assign->ref();
     424  if ( list )
     425    list->ref();
     426}
     427
     428bool PropertyValueNode::deref()
     429{
     430  if ( name && name->deref() )
     431    delete name;
     432  if ( assign && assign->deref() )
     433    delete assign;
     434  if ( list && list->deref() )
     435    delete list;
     436  return Node::deref();
     437}
     438
     439// ECMA 11.1.5
     440Value PropertyValueNode::evaluate(ExecState *exec)
     441{
     442  Object obj;
    238443  if (list) {
    239     array = list->evaluate();
    240     val = node->evaluate().getValue();
    241     length = array.get("length").toInt32();
    242   } else {
    243     array = Object::create(ArrayClass);
    244     val = node->evaluate().getValue();
     444    obj = Object(static_cast<ObjectImp*>(list->evaluate(exec).imp()));
     445    KJS_CHECKEXCEPTIONVALUE
    245446  }
    246 
    247   array.putArrayElement(UString::from(elisionLen + length), val);
    248 
    249   return array;
    250 }
    251 
    252 // ECMA 11.1.4
    253 KJSO ElisionNode::evaluate()
    254 {
    255   if (elision)
    256     return Number(elision->evaluate().toNumber().value() + 1);
    257   else
    258     return Number(1);
    259 }
     447  else {
     448    Value newObj = exec->interpreter()->builtinObject().construct(exec,List::empty());
     449    obj = Object(static_cast<ObjectImp*>(newObj.imp()));
     450  }
     451  Value n = name->evaluate(exec);
     452  KJS_CHECKEXCEPTIONVALUE
     453  Value a = assign->evaluate(exec);
     454  KJS_CHECKEXCEPTIONVALUE
     455  Value v = a.getValue(exec);
     456
     457  obj.put(exec,n.toString(exec), v);
     458
     459  return obj;
     460}
     461
     462// ------------------------------ PropertyNode ---------------------------------
    260463
    261464// ECMA 11.1.5
    262 KJSO ObjectLiteralNode::evaluate()
    263 {
    264   if (list)
    265     return list->evaluate();
    266 
    267   return Object::create(ObjectClass);
    268 }
    269 
    270 // ECMA 11.1.5
    271 KJSO PropertyValueNode::evaluate()
    272 {
    273   KJSO obj;
    274   if (list)
    275     obj = list->evaluate();
    276   else
    277     obj = Object::create(ObjectClass);
    278   KJSO n = name->evaluate();
    279   KJSO a = assign->evaluate();
    280   KJSO v = a.getValue();
    281 
    282   obj.put(n.toString().value(), v);
    283 
    284   return obj;
    285 }
    286 
    287 // ECMA 11.1.5
    288 KJSO PropertyNode::evaluate()
    289 {
    290   KJSO s;
     465Value PropertyNode::evaluate(ExecState */*exec*/)
     466{
     467  Value s;
    291468
    292469  if (str.isNull()) {
     
    298475}
    299476
    300 // ECMA 11.1.6
    301 KJSO GroupNode::evaluate()
    302 {
    303   return group->evaluate();
     477// ------------------------------ AccessorNode1 --------------------------------
     478
     479AccessorNode1::~AccessorNode1()
     480{
     481}
     482
     483void AccessorNode1::ref()
     484{
     485  Node::ref();
     486  if ( expr1 )
     487    expr1->ref();
     488  if ( expr2 )
     489    expr2->ref();
     490}
     491
     492bool AccessorNode1::deref()
     493{
     494  if ( expr1 && expr1->deref() )
     495    delete expr1;
     496  if ( expr2 && expr2->deref() )
     497    delete expr2;
     498  return Node::deref();
    304499}
    305500
    306501// ECMA 11.2.1a
    307 KJSO AccessorNode1::evaluate()
    308 {
    309   KJSO e1 = expr1->evaluate();
    310   KJSO v1 = e1.getValue();
    311   KJSO e2 = expr2->evaluate();
    312   KJSO v2 = e2.getValue();
    313   Object o = v1.toObject();
    314   String s = v2.toString();
     502Value AccessorNode1::evaluate(ExecState *exec)
     503{
     504  Value e1 = expr1->evaluate(exec);
     505  KJS_CHECKEXCEPTIONVALUE
     506  Value v1 = e1.getValue(exec);
     507  Value e2 = expr2->evaluate(exec);
     508  KJS_CHECKEXCEPTIONVALUE
     509  Value v2 = e2.getValue(exec);
     510  Object o = v1.toObject(exec);
     511  String s = v2.toString(exec);
    315512  return Reference(o, s.value());
    316513}
    317514
     515// ------------------------------ AccessorNode2 --------------------------------
     516
     517AccessorNode2::~AccessorNode2()
     518{
     519}
     520
     521void AccessorNode2::ref()
     522{
     523  Node::ref();
     524  if ( expr )
     525    expr->ref();
     526}
     527
     528bool AccessorNode2::deref()
     529{
     530  if ( expr && expr->deref() )
     531    delete expr;
     532  return Node::deref();
     533}
     534
    318535// ECMA 11.2.1b
    319 KJSO AccessorNode2::evaluate()
    320 {
    321   KJSO e = expr->evaluate();
    322   KJSO v = e.getValue();
    323   KJSO o = v.toObject();
     536Value AccessorNode2::evaluate(ExecState *exec)
     537{
     538  Value e = expr->evaluate(exec);
     539  KJS_CHECKEXCEPTIONVALUE
     540  Value v = e.getValue(exec);
     541  Object o = v.toObject(exec);
    324542  return Reference(o, ident);
    325543}
    326544
     545// ------------------------------ ArgumentListNode -----------------------------
     546
     547ArgumentListNode::ArgumentListNode(Node *e) : list(0L), expr(e)
     548{
     549}
     550
     551ArgumentListNode::ArgumentListNode(ArgumentListNode *l, Node *e)
     552  : list(l), expr(e)
     553{
     554}
     555
     556ArgumentListNode::~ArgumentListNode()
     557{
     558}
     559
     560void ArgumentListNode::ref()
     561{
     562  Node::ref();
     563  if ( expr )
     564    expr->ref();
     565  if ( list )
     566    list->ref();
     567}
     568
     569bool ArgumentListNode::deref()
     570{
     571  if ( expr && expr->deref() )
     572    delete expr;
     573  if ( list && list->deref() )
     574    delete list;
     575  return Node::deref();
     576}
     577
     578Value ArgumentListNode::evaluate(ExecState */*exec*/)
     579{
     580  assert(0);
     581  return Value(); // dummy, see evaluateList()
     582}
     583
     584// ECMA 11.2.4
     585List ArgumentListNode::evaluateList(ExecState *exec)
     586{
     587  List l;
     588  if (list) {
     589    l = list->evaluateList(exec);
     590    KJS_CHECKEXCEPTIONLIST
     591  }
     592
     593  Value e = expr->evaluate(exec);
     594  KJS_CHECKEXCEPTIONLIST
     595  Value v = e.getValue(exec);
     596
     597  l.append(v);
     598
     599  return l;
     600}
     601
     602// ------------------------------ ArgumentsNode --------------------------------
     603
     604ArgumentsNode::ArgumentsNode(ArgumentListNode *l) : list(l)
     605{
     606}
     607
     608ArgumentsNode::~ArgumentsNode()
     609{
     610}
     611
     612void ArgumentsNode::ref()
     613{
     614  Node::ref();
     615  if ( list )
     616    list->ref();
     617}
     618
     619bool ArgumentsNode::deref()
     620{
     621  if ( list && list->deref() )
     622    delete list;
     623  return Node::deref();
     624}
     625
     626Value ArgumentsNode::evaluate(ExecState */*exec*/)
     627{
     628  assert(0);
     629  return Value(); // dummy, see evaluateList()
     630}
     631
     632// ECMA 11.2.4
     633List ArgumentsNode::evaluateList(ExecState *exec)
     634{
     635  if (!list)
     636    return List();
     637
     638  return list->evaluateList(exec);
     639}
     640
     641// ------------------------------ NewExprNode ----------------------------------
     642
    327643// ECMA 11.2.2
    328 KJSO NewExprNode::evaluate()
    329 {
    330   KJSO e = expr->evaluate();
    331   KJSO v = e.getValue();
    332 
    333   List *argList = args ? args->evaluateList() : 0;
    334 
    335   if (!v.isObject()) {
    336     delete argList;
    337     return throwError(TypeError, "Expression is no object. Cannot be new'ed");
     644
     645NewExprNode::~NewExprNode()
     646{
     647}
     648
     649void NewExprNode::ref()
     650{
     651  Node::ref();
     652  if ( expr )
     653    expr->ref();
     654  if ( args )
     655    args->ref();
     656}
     657
     658bool NewExprNode::deref()
     659{
     660  if ( expr && expr->deref() )
     661    delete expr;
     662  if ( args && args->deref() )
     663    delete args;
     664  return Node::deref();
     665}
     666
     667Value NewExprNode::evaluate(ExecState *exec)
     668{
     669  Value e = expr->evaluate(exec);
     670  KJS_CHECKEXCEPTIONVALUE
     671  Value v = e.getValue(exec);
     672
     673  List argList;
     674  if (args) {
     675    argList = args->evaluateList(exec);
     676    KJS_CHECKEXCEPTIONVALUE
    338677  }
    339678
    340   Constructor constr = Constructor::dynamicCast(v);
    341   if (constr.isNull()) {
    342     delete argList;
    343     return throwError(TypeError, "Expression is no constructor.");
     679  if (v.type() != ObjectType) {
     680    return throwError(exec, TypeError, "Expression is no object. Cannot be new'ed");
    344681  }
    345682
    346   if (!argList)
    347     argList = new List;
    348 
    349   KJSO res = constr.construct(*argList);
    350 
    351   delete argList;
     683  Object constr = Object(static_cast<ObjectImp*>(v.imp()));
     684  if (!constr.implementsConstruct()) {
     685    return throwError(exec, TypeError, "Expression is no constructor.");
     686  }
     687
     688  Value res = constr.construct(exec,argList);
    352689
    353690  return res;
    354691}
    355692
     693// ------------------------------ FunctionCallNode -----------------------------
     694
     695FunctionCallNode::~FunctionCallNode()
     696{
     697}
     698
     699void FunctionCallNode::ref()
     700{
     701  Node::ref();
     702  if ( expr )
     703    expr->ref();
     704  if ( args )
     705    args->ref();
     706}
     707
     708bool FunctionCallNode::deref()
     709{
     710  if ( expr && expr->deref() )
     711    delete expr;
     712  if ( args && args->deref() )
     713    delete args;
     714  return Node::deref();
     715}
     716
    356717// ECMA 11.2.3
    357 KJSO FunctionCallNode::evaluate()
    358 {
    359   KJSO e = expr->evaluate();
    360 
    361   List *argList = args->evaluateList();
    362 
    363   KJSO v = e.getValue();
    364 
    365   if (!v.isObject()) {
     718Value FunctionCallNode::evaluate(ExecState *exec)
     719{
     720  Value e = expr->evaluate(exec);
     721  KJS_CHECKEXCEPTIONVALUE
     722
     723  List argList = args->evaluateList(exec);
     724
     725  KJS_CHECKEXCEPTIONVALUE
     726
     727  Value v = e.getValue(exec);
     728
     729  if (v.type() != ObjectType) {
    366730#ifndef NDEBUG
    367     printInfo("Failed function call attempt on", e);
     731    printInfo(exec, "WARNING: Failed function call attempt on", e, line);
    368732#endif
    369     delete argList;
    370     return throwError(TypeError, "Expression is no object. Cannot be called.");
     733    return throwError(exec, TypeError, "Expression is no object. Cannot be called.");
    371734  }
    372735
    373   if (!v.implementsCall()) {
     736  Object func = Object(static_cast<ObjectImp*>(v.imp()));
     737
     738  if (!func.implementsCall()) {
    374739#ifndef NDEBUG
    375     printInfo("Failed function call attempt on", e);
     740    printInfo(exec, "Failed function call attempt on", e, line);
    376741#endif
    377     delete argList;
    378     return throwError(TypeError, "Expression does not allow calls.");
     742    return throwError(exec, TypeError, "Expression does not allow calls.");
    379743  }
    380744
    381   KJSO o;
    382   if (e.isA(ReferenceType))
    383     o = e.getBase();
     745  Value thisVal;
     746  if (e.type() == ReferenceType)
     747    thisVal = e.getBase(exec);
    384748  else
    385     o = Null();
    386 
    387   if (o.isA(ActivationType))
    388     o = Null();
    389 
    390 #ifdef KJS_DEBUGGER
    391   steppingInto(true);
    392 #endif
    393 
    394   KJSO result = v.executeCall(o, argList);
    395 
    396 #ifdef KJS_DEBUGGER
    397   steppingInto(false);
    398 #endif
    399 
    400   delete argList;
     749    thisVal = Null();
     750
     751  if (thisVal.type() == ObjectType &&
     752      Object::dynamicCast(thisVal).inherits(&ActivationImp::info))
     753    thisVal = Null();
     754
     755  if (thisVal.type() != ObjectType) {
     756    // ECMA 11.2.3 says that in this situation the this value should be null.
     757    // However, section 10.2.3 says that in the case where the value provided
     758    // by the caller is null, the global object should be used. It also says
     759    // that the section does not apply to interal functions, but for simplicity
     760    // of implementation we use the global object anyway here. This guarantees
     761    // that in host objects you always get a valid object for this.
     762    // thisVal = Null();
     763    thisVal = exec->interpreter()->globalObject();
     764  }
     765
     766  Object thisObj = Object::dynamicCast(thisVal);
     767  Value result = func.call(exec,thisObj, argList);
    401768
    402769  return result;
    403770}
    404771
    405 #ifdef KJS_DEBUGGER
    406 void FunctionCallNode::steppingInto(bool in)
    407 {
    408   Debugger *dbg = KJScriptImp::current()->debugger();
    409   if (!dbg)
    410     return;
    411   if (in) {
    412     // before entering function. Don't step inside if 'Next' is chosen.
    413     previousMode = dbg->mode();
    414     if (previousMode == Debugger::Next)
    415       dbg->setMode(Debugger::Continue);
    416   } else {
    417     // restore mode after leaving function
    418     dbg->setMode(previousMode);
     772// ------------------------------ PostfixNode ----------------------------------
     773
     774PostfixNode::~PostfixNode()
     775{
     776}
     777
     778void PostfixNode::ref()
     779{
     780  Node::ref();
     781  if ( expr )
     782    expr->ref();
     783}
     784
     785bool PostfixNode::deref()
     786{
     787  if ( expr && expr->deref() )
     788    delete expr;
     789  return Node::deref();
     790}
     791
     792// ECMA 11.3
     793Value PostfixNode::evaluate(ExecState *exec)
     794{
     795  Value e = expr->evaluate(exec);
     796  KJS_CHECKEXCEPTIONVALUE
     797  Value v = e.getValue(exec);
     798  Number n = v.toNumber(exec);
     799
     800  double newValue = (oper == OpPlusPlus) ? n.value() + 1 : n.value() - 1;
     801  Value n2 = Number(newValue);
     802
     803  e.putValue(exec,n2);
     804
     805  return n;
     806}
     807
     808// ------------------------------ DeleteNode -----------------------------------
     809
     810DeleteNode::~DeleteNode()
     811{
     812}
     813
     814void DeleteNode::ref()
     815{
     816  Node::ref();
     817  if ( expr )
     818    expr->ref();
     819}
     820
     821bool DeleteNode::deref()
     822{
     823  if ( expr && expr->deref() )
     824    delete expr;
     825  return Node::deref();
     826}
     827
     828// ECMA 11.4.1
     829Value DeleteNode::evaluate(ExecState *exec)
     830{
     831  Value e = expr->evaluate(exec);
     832  KJS_CHECKEXCEPTIONVALUE
     833  if (e.type() != ReferenceType)
     834    return Boolean(true);
     835  Value b = e.getBase(exec);
     836  UString n = e.getPropertyName(exec);
     837
     838  // The spec doesn't mention what to do if the base is null... just return true
     839  if (b.type() != ObjectType) {
     840    assert(b.type() == NullType);
     841    return Boolean(true);
    419842  }
    420 }
    421 #endif
    422 
    423 KJSO ArgumentsNode::evaluate()
    424 {
    425   assert(0);
    426   return KJSO(); // dummy, see evaluateList()
    427 }
    428 
    429 // ECMA 11.2.4
    430 List* ArgumentsNode::evaluateList()
    431 {
    432   if (!list)
    433     return new List();
    434 
    435   return list->evaluateList();
    436 }
    437 
    438 KJSO ArgumentListNode::evaluate()
    439 {
    440   assert(0);
    441   return KJSO(); // dummy, see evaluateList()
    442 }
    443 
    444 // ECMA 11.2.4
    445 List* ArgumentListNode::evaluateList()
    446 {
    447   KJSO e = expr->evaluate();
    448   KJSO v = e.getValue();
    449 
    450   if (!list) {
    451     List *l = new List();
    452     l->append(v);
    453     return l;
    454   }
    455 
    456   List *l = list->evaluateList();
    457   l->append(v);
    458 
    459   return l;
    460 }
    461 
    462 // ECMA 11.8
    463 KJSO RelationalNode::evaluate()
    464 {
    465   KJSO e1 = expr1->evaluate();
    466   KJSO v1 = e1.getValue();
    467   KJSO e2 = expr2->evaluate();
    468   KJSO v2 = e2.getValue();
    469 
    470   bool b;
    471   if (oper == OpLess || oper == OpGreaterEq) {
    472     int r = relation(v1, v2);
    473     if (r < 0)
    474       b = false;
    475     else
    476       b = (oper == OpLess) ? (r == 1) : (r == 0);
    477   } else if (oper == OpGreater || oper == OpLessEq) {
    478     int r = relation(v2, v1);
    479     if (r < 0)
    480       b = false;
    481     else
    482       b = (oper == OpGreater) ? (r == 1) : (r == 0);
    483   } else if (oper == OpIn) {
    484       /* Is all of this OK for host objects? */
    485       if (!v2.isObject())
    486           return throwError( TypeError,
    487                              "Shift expression not an object into IN expression." );
    488       b = v2.hasProperty(v1.toString().value());
    489   } else {
    490     /* TODO: should apply to Function _objects_ only */
    491     if (!v2.derivedFrom("Function"))
    492       return throwError(TypeError,
    493                         "Called instanceof operator on non-function object." );
    494     return hasInstance(v2, v1); /* TODO: make object member function */
    495   }
    496 
    497   return Boolean(b);
    498 }
    499 
    500 // ECMA 11.9
    501 KJSO EqualNode::evaluate()
    502 {
    503   KJSO e1 = expr1->evaluate();
    504   KJSO e2 = expr2->evaluate();
    505   KJSO v1 = e1.getValue();
    506   KJSO v2 = e2.getValue();
    507 
    508   bool result;
    509   if (oper == OpEqEq || oper == OpNotEq) {
    510     // == and !=
    511     bool eq = equal(v1, v2);
    512     result = oper == OpEqEq ? eq : !eq;
    513   } else {
    514     // === and !==
    515     bool eq = strictEqual(v1, v2);
    516     result = oper == OpStrEq ? eq : !eq;
    517   }
    518   return Boolean(result);
    519 }
    520 
    521 // ECMA 11.10
    522 KJSO BitOperNode::evaluate()
    523 {
    524   KJSO e1 = expr1->evaluate();
    525   KJSO v1 = e1.getValue();
    526   KJSO e2 = expr2->evaluate();
    527   KJSO v2 = e2.getValue();
    528   int i1 = v1.toInt32();
    529   int i2 = v2.toInt32();
    530   int result;
    531   if (oper == OpBitAnd)
    532     result = i1 & i2;
    533   else if (oper == OpBitXOr)
    534     result = i1 ^ i2;
    535   else
    536     result = i1 | i2;
    537 
    538   return Number(result);
    539 }
    540 
    541 // ECMA 11.11
    542 KJSO BinaryLogicalNode::evaluate()
    543 {
    544   KJSO e1 = expr1->evaluate();
    545   KJSO v1 = e1.getValue();
    546   Boolean b1 = v1.toBoolean();
    547   if ((!b1.value() && oper == OpAnd) || (b1.value() && oper == OpOr))
    548     return v1;
    549 
    550   KJSO e2 = expr2->evaluate();
    551   KJSO v2 = e2.getValue();
    552 
    553   return v2;
    554 }
    555 
    556 // ECMA 11.12
    557 KJSO ConditionalNode::evaluate()
    558 {
    559   KJSO e = logical->evaluate();
    560   KJSO v = e.getValue();
    561   Boolean b = v.toBoolean();
    562 
    563   if (b.value())
    564     e = expr1->evaluate();
    565   else
    566     e = expr2->evaluate();
    567 
    568   return e.getValue();
    569 }
    570 
    571 // ECMA 11.13
    572 KJSO AssignNode::evaluate()
    573 {
    574   KJSO l, e, v;
    575   ErrorType err;
    576   if (oper == OpEqual) {
    577     l = left->evaluate();
    578     e = expr->evaluate();
    579     v = e.getValue();
    580   } else {
    581     l = left->evaluate();
    582     KJSO v1 = l.getValue();
    583     e = expr->evaluate();
    584     KJSO v2 = e.getValue();
    585     int i1 = v1.toInt32();
    586     int i2 = v2.toInt32();
    587     switch (oper) {
    588     case OpMultEq:
    589       v = mult(v1, v2, '*');
    590       break;
    591     case OpDivEq:
    592       v = mult(v1, v2, '/');
    593       break;
    594     case OpPlusEq:
    595       v = add(v1, v2, '+');
    596       break;
    597     case OpMinusEq:
    598       v = add(v1, v2, '-');
    599       break;
    600     case OpLShift:
    601       v = Number(i1 <<= i2);
    602       break;
    603     case OpRShift:
    604       v = Number(i1 >>= i2);
    605       break;
    606     case OpURShift:
    607       i1 = v1.toUInt32();
    608       v = Number(i1 >>= i2);
    609       break;
    610     case OpAndEq:
    611       v = Number(i1 &= i2);
    612       break;
    613     case OpXOrEq:
    614       v = Number(i1 ^= i2);
    615       break;
    616     case OpOrEq:
    617       v = Number(i1 |= i2);
    618       break;
    619     case OpModEq:
    620       v = Number(i1 %= i2);
    621       break;
    622     default:
    623       v = Undefined();
    624     }
    625     err = l.putValue(v);
    626   };
    627 
    628   err = l.putValue(v);
    629   if (err == NoError)
    630     return v;
    631   else
    632     return throwError(err, "Invalid reference.");
    633 }
    634 
    635 // ECMA 11.3
    636 KJSO PostfixNode::evaluate()
    637 {
    638   KJSO e = expr->evaluate();
    639   KJSO v = e.getValue();
    640   Number n = v.toNumber();
    641 
    642   double newValue = (oper == OpPlusPlus) ? n.value() + 1 : n.value() - 1;
    643   KJSO n2 = Number(newValue);
    644 
    645   e.putValue(n2);
    646 
    647   return n;
    648 }
    649 
    650 // ECMA 11.4.1
    651 KJSO DeleteNode::evaluate()
    652 {
    653   KJSO e = expr->evaluate();
    654   if (!e.isA(ReferenceType))
    655     return Boolean(true);
    656   KJSO b = e.getBase();
    657   UString n = e.getPropertyName();
    658   bool ret = b.deleteProperty(n);
     843
     844  Object o = Object(static_cast<ObjectImp*>(b.imp()));
     845
     846  bool ret = o.deleteProperty(exec,n);
    659847
    660848  return Boolean(ret);
    661849}
    662850
     851// ------------------------------ VoidNode -------------------------------------
     852
     853VoidNode::~VoidNode()
     854{
     855}
     856
     857void VoidNode::ref()
     858{
     859  Node::ref();
     860  if ( expr )
     861    expr->ref();
     862}
     863
     864bool VoidNode::deref()
     865{
     866  if ( expr && expr->deref() )
     867    delete expr;
     868  return Node::deref();
     869}
     870
    663871// ECMA 11.4.2
    664 KJSO VoidNode::evaluate()
    665 {
    666   KJSO dummy1 = expr->evaluate();
    667   KJSO dummy2 = dummy1.getValue();
     872Value VoidNode::evaluate(ExecState *exec)
     873{
     874  Value dummy1 = expr->evaluate(exec);
     875  KJS_CHECKEXCEPTIONVALUE
     876  Value dummy2 = dummy1.getValue(exec);
    668877
    669878  return Undefined();
    670879}
    671880
     881// ------------------------------ TypeOfNode -----------------------------------
     882
     883TypeOfNode::~TypeOfNode()
     884{
     885}
     886
     887void TypeOfNode::ref()
     888{
     889  Node::ref();
     890  if ( expr )
     891    expr->ref();
     892}
     893
     894bool TypeOfNode::deref()
     895{
     896  if ( expr && expr->deref() )
     897    delete expr;
     898  return Node::deref();
     899}
     900
    672901// ECMA 11.4.3
    673 KJSO TypeOfNode::evaluate()
     902Value TypeOfNode::evaluate(ExecState *exec)
    674903{
    675904  const char *s = 0L;
    676   KJSO e = expr->evaluate();
    677   if (e.isA(ReferenceType)) {
    678     KJSO b = e.getBase();
    679     if (b.isA(NullType))
     905  Value e = expr->evaluate(exec);
     906  KJS_CHECKEXCEPTIONVALUE
     907  if (e.type() == ReferenceType) {
     908    Value b = e.getBase(exec);
     909    if (b.type() == NullType)
    680910      return String("undefined");
    681911  }
    682   KJSO v = e.getValue();
     912  Value v = e.getValue(exec);
    683913  switch (v.type())
    684914    {
     
    699929      break;
    700930    default:
    701       if (v.implementsCall())
     931      if (v.type() == ObjectType && static_cast<ObjectImp*>(v.imp())->implementsCall())
    702932        s = "function";
    703933      else
     
    709939}
    710940
     941// ------------------------------ PrefixNode -----------------------------------
     942
     943PrefixNode::~PrefixNode()
     944{
     945}
     946
     947void PrefixNode::ref()
     948{
     949  Node::ref();
     950  if ( expr )
     951    expr->ref();
     952}
     953
     954bool PrefixNode::deref()
     955{
     956  if ( expr && expr->deref() )
     957    delete expr;
     958  return Node::deref();
     959}
     960
    711961// ECMA 11.4.4 and 11.4.5
    712 KJSO PrefixNode::evaluate()
    713 {
    714   KJSO e = expr->evaluate();
    715   KJSO v = e.getValue();
    716   Number n = v.toNumber();
     962Value PrefixNode::evaluate(ExecState *exec)
     963{
     964  Value e = expr->evaluate(exec);
     965  KJS_CHECKEXCEPTIONVALUE
     966  Value v = e.getValue(exec);
     967  Number n = v.toNumber(exec);
    717968
    718969  double newValue = (oper == OpPlusPlus) ? n.value() + 1 : n.value() - 1;
    719   KJSO n2 = Number(newValue);
    720 
    721   e.putValue(n2);
     970  Value n2 = Number(newValue);
     971
     972  e.putValue(exec,n2);
    722973
    723974  return n2;
    724975}
    725976
     977// ------------------------------ UnaryPlusNode --------------------------------
     978
     979UnaryPlusNode::~UnaryPlusNode()
     980{
     981}
     982
     983void UnaryPlusNode::ref()
     984{
     985  Node::ref();
     986  if ( expr )
     987    expr->ref();
     988}
     989
     990bool UnaryPlusNode::deref()
     991{
     992  if ( expr && expr->deref() )
     993    delete expr;
     994  return Node::deref();
     995}
     996
    726997// ECMA 11.4.6
    727 KJSO UnaryPlusNode::evaluate()
    728 {
    729   KJSO e = expr->evaluate();
    730   KJSO v = e.getValue();
    731 
    732   return v.toNumber();
     998Value UnaryPlusNode::evaluate(ExecState *exec)
     999{
     1000  Value e = expr->evaluate(exec);
     1001  KJS_CHECKEXCEPTIONVALUE
     1002  Value v = e.getValue(exec);
     1003
     1004  return Number(v.toNumber(exec)); /* TODO: optimize */
     1005}
     1006
     1007// ------------------------------ NegateNode -----------------------------------
     1008
     1009NegateNode::~NegateNode()
     1010{
     1011}
     1012
     1013void NegateNode::ref()
     1014{
     1015  Node::ref();
     1016  if ( expr )
     1017    expr->ref();
     1018}
     1019
     1020bool NegateNode::deref()
     1021{
     1022  if ( expr && expr->deref() )
     1023    delete expr;
     1024  return Node::deref();
    7331025}
    7341026
    7351027// ECMA 11.4.7
    736 KJSO NegateNode::evaluate()
    737 {
    738   KJSO e = expr->evaluate();
    739   KJSO v = e.getValue();
    740   Number n = v.toNumber();
     1028Value NegateNode::evaluate(ExecState *exec)
     1029{
     1030  Value e = expr->evaluate(exec);
     1031  KJS_CHECKEXCEPTIONVALUE
     1032  Value v = e.getValue(exec);
     1033  Number n = v.toNumber(exec);
    7411034
    7421035  double d = -n.value();
     
    7451038}
    7461039
     1040// ------------------------------ BitwiseNotNode -------------------------------
     1041
     1042BitwiseNotNode::~BitwiseNotNode()
     1043{
     1044}
     1045
     1046void BitwiseNotNode::ref()
     1047{
     1048  Node::ref();
     1049  if ( expr )
     1050    expr->ref();
     1051}
     1052
     1053bool BitwiseNotNode::deref()
     1054{
     1055  if ( expr && expr->deref() )
     1056    delete expr;
     1057  return Node::deref();
     1058}
     1059
    7471060// ECMA 11.4.8
    748 KJSO BitwiseNotNode::evaluate()
    749 {
    750   KJSO e = expr->evaluate();
    751   KJSO v = e.getValue();
    752   int i32 = v.toInt32();
     1061Value BitwiseNotNode::evaluate(ExecState *exec)
     1062{
     1063  Value e = expr->evaluate(exec);
     1064  KJS_CHECKEXCEPTIONVALUE
     1065  Value v = e.getValue(exec);
     1066  int i32 = v.toInt32(exec);
    7531067
    7541068  return Number(~i32);
    7551069}
    7561070
     1071// ------------------------------ LogicalNotNode -------------------------------
     1072
     1073LogicalNotNode::~LogicalNotNode()
     1074{
     1075}
     1076
     1077void LogicalNotNode::ref()
     1078{
     1079  Node::ref();
     1080  if ( expr )
     1081    expr->ref();
     1082}
     1083
     1084bool LogicalNotNode::deref()
     1085{
     1086  if ( expr && expr->deref() )
     1087    delete expr;
     1088  return Node::deref();
     1089}
     1090
    7571091// ECMA 11.4.9
    758 KJSO LogicalNotNode::evaluate()
    759 {
    760   KJSO e = expr->evaluate();
    761   KJSO v = e.getValue();
    762   Boolean b = v.toBoolean();
    763 
    764   return Boolean(!b.value());
     1092Value LogicalNotNode::evaluate(ExecState *exec)
     1093{
     1094  Value e = expr->evaluate(exec);
     1095  KJS_CHECKEXCEPTIONVALUE
     1096  Value v = e.getValue(exec);
     1097  bool b = v.toBoolean(exec);
     1098
     1099  return Boolean(!b);
     1100}
     1101
     1102// ------------------------------ MultNode -------------------------------------
     1103
     1104MultNode::~MultNode()
     1105{
     1106}
     1107
     1108void MultNode::ref()
     1109{
     1110  Node::ref();
     1111  if ( term1 )
     1112    term1->ref();
     1113  if ( term2 )
     1114    term2->ref();
     1115}
     1116
     1117bool MultNode::deref()
     1118{
     1119  if ( term1 && term1->deref() )
     1120    delete term1;
     1121  if ( term2 && term2->deref() )
     1122    delete term2;
     1123  return Node::deref();
    7651124}
    7661125
    7671126// ECMA 11.5
    768 KJSO MultNode::evaluate()
    769 {
    770   KJSO t1 = term1->evaluate();
    771   KJSO v1 = t1.getValue();
    772 
    773   KJSO t2 = term2->evaluate();
    774   KJSO v2 = t2.getValue();
    775 
    776   return mult(v1, v2, oper);
     1127Value MultNode::evaluate(ExecState *exec)
     1128{
     1129  Value t1 = term1->evaluate(exec);
     1130  KJS_CHECKEXCEPTIONVALUE
     1131  Value v1 = t1.getValue(exec);
     1132
     1133  Value t2 = term2->evaluate(exec);
     1134  KJS_CHECKEXCEPTIONVALUE
     1135  Value v2 = t2.getValue(exec);
     1136
     1137  return mult(exec,v1, v2, oper);
     1138}
     1139
     1140// ------------------------------ AddNode --------------------------------------
     1141
     1142AddNode::~AddNode()
     1143{
     1144}
     1145
     1146void AddNode::ref()
     1147{
     1148  Node::ref();
     1149  if ( term1 )
     1150    term1->ref();
     1151  if ( term2 )
     1152    term2->ref();
     1153}
     1154
     1155bool AddNode::deref()
     1156{
     1157  if ( term1 && term1->deref() )
     1158    delete term1;
     1159  if ( term2 && term2->deref() )
     1160    delete term2;
     1161  return Node::deref();
     1162}
     1163
     1164// ECMA 11.6
     1165Value AddNode::evaluate(ExecState *exec)
     1166{
     1167  Value t1 = term1->evaluate(exec);
     1168  KJS_CHECKEXCEPTIONVALUE
     1169  Value v1 = t1.getValue(exec);
     1170
     1171  Value t2 = term2->evaluate(exec);
     1172  KJS_CHECKEXCEPTIONVALUE
     1173  Value v2 = t2.getValue(exec);
     1174
     1175  return add(exec,v1, v2, oper);
     1176}
     1177
     1178// ------------------------------ ShiftNode ------------------------------------
     1179
     1180ShiftNode::~ShiftNode()
     1181{
     1182}
     1183
     1184void ShiftNode::ref()
     1185{
     1186  Node::ref();
     1187  if ( term1 )
     1188    term1->ref();
     1189  if ( term2 )
     1190    term2->ref();
     1191}
     1192
     1193bool ShiftNode::deref()
     1194{
     1195  if ( term1 && term1->deref() )
     1196    delete term1;
     1197  if ( term2 && term2->deref() )
     1198    delete term2;
     1199  return Node::deref();
    7771200}
    7781201
    7791202// ECMA 11.7
    780 KJSO ShiftNode::evaluate()
    781 {
    782   KJSO t1 = term1->evaluate();
    783   KJSO v1 = t1.getValue();
    784   KJSO t2 = term2->evaluate();
    785   KJSO v2 = t2.getValue();
    786   unsigned int i2 = v2.toUInt32();
     1203Value ShiftNode::evaluate(ExecState *exec)
     1204{
     1205  Value t1 = term1->evaluate(exec);
     1206  KJS_CHECKEXCEPTIONVALUE
     1207  Value v1 = t1.getValue(exec);
     1208  Value t2 = term2->evaluate(exec);
     1209  KJS_CHECKEXCEPTIONVALUE
     1210  Value v2 = t2.getValue(exec);
     1211  unsigned int i2 = v2.toUInt32(exec);
    7871212  i2 &= 0x1f;
    7881213
     
    7901215  switch (oper) {
    7911216  case OpLShift:
    792     result = v1.toInt32() << i2;
     1217    result = v1.toInt32(exec) << i2;
    7931218    break;
    7941219  case OpRShift:
    795     result = v1.toInt32() >> i2;
     1220    result = v1.toInt32(exec) >> i2;
    7961221    break;
    7971222  case OpURShift:
    798     result = v1.toUInt32() >> i2;
     1223    result = v1.toUInt32(exec) >> i2;
    7991224    break;
    8001225  default:
     
    8061231}
    8071232
    808 // ECMA 11.6
    809 KJSO AddNode::evaluate()
    810 {
    811   KJSO t1 = term1->evaluate();
    812   KJSO v1 = t1.getValue();
    813 
    814   KJSO t2 = term2->evaluate();
    815   KJSO v2 = t2.getValue();
    816 
    817   return add(v1, v2, oper);
     1233// ------------------------------ RelationalNode -------------------------------
     1234
     1235RelationalNode::~RelationalNode()
     1236{
     1237}
     1238
     1239void RelationalNode::ref()
     1240{
     1241  Node::ref();
     1242  if ( expr1 )
     1243    expr1->ref();
     1244  if ( expr2 )
     1245    expr2->ref();
     1246}
     1247
     1248bool RelationalNode::deref()
     1249{
     1250  if ( expr1 && expr1->deref() )
     1251    delete expr1;
     1252  if ( expr2 && expr2->deref() )
     1253    delete expr2;
     1254  return Node::deref();
     1255}
     1256
     1257// ECMA 11.8
     1258Value RelationalNode::evaluate(ExecState *exec)
     1259{
     1260  Value e1 = expr1->evaluate(exec);
     1261  KJS_CHECKEXCEPTIONVALUE
     1262  Value v1 = e1.getValue(exec);
     1263  Value e2 = expr2->evaluate(exec);
     1264  KJS_CHECKEXCEPTIONVALUE
     1265  Value v2 = e2.getValue(exec);
     1266
     1267  bool b;
     1268  if (oper == OpLess || oper == OpGreaterEq) {
     1269    int r = relation(exec, v1, v2);
     1270    if (r < 0)
     1271      b = false;
     1272    else
     1273      b = (oper == OpLess) ? (r == 1) : (r == 0);
     1274  } else if (oper == OpGreater || oper == OpLessEq) {
     1275    int r = relation(exec, v2, v1);
     1276    if (r < 0)
     1277      b = false;
     1278    else
     1279      b = (oper == OpGreater) ? (r == 1) : (r == 0);
     1280  } else if (oper == OpIn) {
     1281      // Is all of this OK for host objects?
     1282      if (v2.type() != ObjectType)
     1283          return throwError(exec,  TypeError,
     1284                             "Shift expression not an object into IN expression." );
     1285      Object o2(static_cast<ObjectImp*>(v2.imp()));
     1286      b = o2.hasProperty(exec,v1.toString(exec));
     1287  } else {
     1288    if (v2.type() != ObjectType)
     1289        return throwError(exec,  TypeError,
     1290                           "Called instanceof operator on non-object." );
     1291
     1292    Object o2(static_cast<ObjectImp*>(v2.imp()));
     1293    if (!o2.implementsHasInstance()) {
     1294      // According to the spec, only some types of objects "imlement" the [[HasInstance]] property.
     1295      // But we are supposed to throw an exception where the object does not "have" the [[HasInstance]]
     1296      // property. It seems that all object have the property, but not all implement it, so in this
     1297      // case we return false (consistent with mozilla)
     1298      return Boolean(false);
     1299      //      return throwError(exec, TypeError,
     1300      //                        "Object does not implement the [[HasInstance]] method." );
     1301    }
     1302    return o2.hasInstance(exec, v1);
     1303  }
     1304
     1305  return Boolean(b);
     1306}
     1307
     1308// ------------------------------ EqualNode ------------------------------------
     1309
     1310EqualNode::~EqualNode()
     1311{
     1312}
     1313
     1314void EqualNode::ref()
     1315{
     1316  Node::ref();
     1317  if ( expr1 )
     1318    expr1->ref();
     1319  if ( expr2 )
     1320    expr2->ref();
     1321}
     1322
     1323bool EqualNode::deref()
     1324{
     1325  if ( expr1 && expr1->deref() )
     1326    delete expr1;
     1327  if ( expr2 && expr2->deref() )
     1328    delete expr2;
     1329  return Node::deref();
     1330}
     1331
     1332// ECMA 11.9
     1333Value EqualNode::evaluate(ExecState *exec)
     1334{
     1335  Value e1 = expr1->evaluate(exec);
     1336  KJS_CHECKEXCEPTIONVALUE
     1337  Value e2 = expr2->evaluate(exec);
     1338  KJS_CHECKEXCEPTIONVALUE
     1339  Value v1 = e1.getValue(exec);
     1340  Value v2 = e2.getValue(exec);
     1341
     1342  bool result;
     1343  if (oper == OpEqEq || oper == OpNotEq) {
     1344    // == and !=
     1345    bool eq = equal(exec,v1, v2);
     1346    result = oper == OpEqEq ? eq : !eq;
     1347  } else {
     1348    // === and !==
     1349    bool eq = strictEqual(exec,v1, v2);
     1350    result = oper == OpStrEq ? eq : !eq;
     1351  }
     1352  return Boolean(result);
     1353}
     1354
     1355// ------------------------------ BitOperNode ----------------------------------
     1356
     1357BitOperNode::~BitOperNode()
     1358{
     1359}
     1360
     1361void BitOperNode::ref()
     1362{
     1363  Node::ref();
     1364  if ( expr1 )
     1365    expr1->ref();
     1366  if ( expr2 )
     1367    expr2->ref();
     1368}
     1369
     1370bool BitOperNode::deref()
     1371{
     1372  if ( expr1 && expr1->deref() )
     1373    delete expr1;
     1374  if ( expr2 && expr2->deref() )
     1375    delete expr2;
     1376  return Node::deref();
     1377}
     1378
     1379// ECMA 11.10
     1380Value BitOperNode::evaluate(ExecState *exec)
     1381{
     1382  Value e1 = expr1->evaluate(exec);
     1383  KJS_CHECKEXCEPTIONVALUE
     1384  Value v1 = e1.getValue(exec);
     1385  Value e2 = expr2->evaluate(exec);
     1386  KJS_CHECKEXCEPTIONVALUE
     1387  Value v2 = e2.getValue(exec);
     1388  int i1 = v1.toInt32(exec);
     1389  int i2 = v2.toInt32(exec);
     1390  int result;
     1391  if (oper == OpBitAnd)
     1392    result = i1 & i2;
     1393  else if (oper == OpBitXOr)
     1394    result = i1 ^ i2;
     1395  else
     1396    result = i1 | i2;
     1397
     1398  return Number(result);
     1399}
     1400
     1401// ------------------------------ BinaryLogicalNode ----------------------------
     1402
     1403BinaryLogicalNode::~BinaryLogicalNode()
     1404{
     1405}
     1406
     1407void BinaryLogicalNode::ref()
     1408{
     1409  Node::ref();
     1410  if ( expr1 )
     1411    expr1->ref();
     1412  if ( expr2 )
     1413    expr2->ref();
     1414}
     1415
     1416bool BinaryLogicalNode::deref()
     1417{
     1418  if ( expr1 && expr1->deref() )
     1419    delete expr1;
     1420  if ( expr2 && expr2->deref() )
     1421    delete expr2;
     1422  return Node::deref();
     1423}
     1424
     1425// ECMA 11.11
     1426Value BinaryLogicalNode::evaluate(ExecState *exec)
     1427{
     1428  Value e1 = expr1->evaluate(exec);
     1429  KJS_CHECKEXCEPTIONVALUE
     1430  Value v1 = e1.getValue(exec);
     1431  bool b1 = v1.toBoolean(exec);
     1432  if ((!b1 && oper == OpAnd) || (b1 && oper == OpOr))
     1433    return v1;
     1434
     1435  Value e2 = expr2->evaluate(exec);
     1436  KJS_CHECKEXCEPTIONVALUE
     1437  Value v2 = e2.getValue(exec);
     1438
     1439  return v2;
     1440}
     1441
     1442// ------------------------------ ConditionalNode ------------------------------
     1443
     1444ConditionalNode::~ConditionalNode()
     1445{
     1446}
     1447
     1448void ConditionalNode::ref()
     1449{
     1450  Node::ref();
     1451  if ( expr1 )
     1452    expr1->ref();
     1453  if ( expr2 )
     1454    expr2->ref();
     1455  if ( logical )
     1456    logical->ref();
     1457}
     1458
     1459bool ConditionalNode::deref()
     1460{
     1461  if ( expr1 && expr1->deref() )
     1462    delete expr1;
     1463  if ( expr2 && expr2->deref() )
     1464    delete expr2;
     1465  if ( logical && logical->deref() )
     1466    delete logical;
     1467  return Node::deref();
     1468}
     1469
     1470// ECMA 11.12
     1471Value ConditionalNode::evaluate(ExecState *exec)
     1472{
     1473  Value e = logical->evaluate(exec);
     1474  KJS_CHECKEXCEPTIONVALUE
     1475  Value v = e.getValue(exec);
     1476  bool b = v.toBoolean(exec);
     1477
     1478  if (b)
     1479    e = expr1->evaluate(exec);
     1480  else
     1481    e = expr2->evaluate(exec);
     1482  KJS_CHECKEXCEPTIONVALUE
     1483
     1484  return e.getValue(exec);
     1485}
     1486
     1487// ------------------------------ AssignNode -----------------------------------
     1488
     1489AssignNode::~AssignNode()
     1490{
     1491}
     1492
     1493void AssignNode::ref()
     1494{
     1495  Node::ref();
     1496  if ( left )
     1497    left->ref();
     1498  if ( expr )
     1499    expr->ref();
     1500}
     1501
     1502bool AssignNode::deref()
     1503{
     1504  if ( left && left->deref() )
     1505    delete left;
     1506  if ( expr && expr->deref() )
     1507    delete expr;
     1508  return Node::deref();
     1509}
     1510
     1511// ECMA 11.13
     1512Value AssignNode::evaluate(ExecState *exec)
     1513{
     1514
     1515  Value l, e, v;
     1516  if (oper == OpEqual) {
     1517    l = left->evaluate(exec);
     1518    KJS_CHECKEXCEPTIONVALUE
     1519    e = expr->evaluate(exec);
     1520    KJS_CHECKEXCEPTIONVALUE
     1521    v = e.getValue(exec);
     1522  } else {
     1523    l = left->evaluate(exec);
     1524    KJS_CHECKEXCEPTIONVALUE
     1525    Value v1 = l.getValue(exec);
     1526    e = expr->evaluate(exec);
     1527    KJS_CHECKEXCEPTIONVALUE
     1528    Value v2 = e.getValue(exec);
     1529    int i1 = v1.toInt32(exec);
     1530    int i2 = v2.toInt32(exec);
     1531    unsigned int ui;
     1532    switch (oper) {
     1533    case OpMultEq:
     1534      v = mult(exec, v1, v2, '*');
     1535      break;
     1536    case OpDivEq:
     1537      v = mult(exec, v1, v2, '/');
     1538      break;
     1539    case OpPlusEq:
     1540      v = add(exec, v1, v2, '+');
     1541      break;
     1542    case OpMinusEq:
     1543      v = add(exec, v1, v2, '-');
     1544      break;
     1545    case OpLShift:
     1546      v = Number(i1 <<= i2);
     1547      break;
     1548    case OpRShift:
     1549      v = Number(i1 >>= i2);
     1550      break;
     1551    case OpURShift:
     1552      ui = v1.toUInt32(exec);
     1553      v = Number(ui >>= i2);
     1554      break;
     1555    case OpAndEq:
     1556      v = Number(i1 &= i2);
     1557      break;
     1558    case OpXOrEq:
     1559      v = Number(i1 ^= i2);
     1560      break;
     1561    case OpOrEq:
     1562      v = Number(i1 |= i2);
     1563      break;
     1564    case OpModEq: {
     1565      double d1 = v1.toNumber(exec);
     1566      double d2 = v2.toNumber(exec);
     1567      v = Number(fmod(d1,d2));
     1568    }
     1569      break;
     1570    default:
     1571      v = Undefined();
     1572    }
     1573  };
     1574  l.putValue(exec,v);
     1575
     1576  KJS_CHECKEXCEPTIONVALUE
     1577
     1578  return v;
     1579}
     1580
     1581// ------------------------------ CommaNode ------------------------------------
     1582
     1583CommaNode::~CommaNode()
     1584{
     1585}
     1586
     1587void CommaNode::ref()
     1588{
     1589  Node::ref();
     1590  if ( expr1 )
     1591    expr1->ref();
     1592  if ( expr2 )
     1593    expr2->ref();
     1594}
     1595
     1596bool CommaNode::deref()
     1597{
     1598  if ( expr1 && expr1->deref() )
     1599    delete expr1;
     1600  if ( expr2 && expr2->deref() )
     1601    delete expr2;
     1602  return Node::deref();
    8181603}
    8191604
    8201605// ECMA 11.14
    821 KJSO CommaNode::evaluate()
    822 {
    823   KJSO e = expr1->evaluate();
    824   KJSO dummy = e.getValue(); // ignore return value
    825   e = expr2->evaluate();
    826 
    827   return e.getValue();
     1606Value CommaNode::evaluate(ExecState *exec)
     1607{
     1608  Value e = expr1->evaluate(exec);
     1609  KJS_CHECKEXCEPTIONVALUE
     1610  Value dummy = e.getValue(exec); // ignore return value
     1611  e = expr2->evaluate(exec);
     1612  KJS_CHECKEXCEPTIONVALUE
     1613
     1614  return e.getValue(exec);
     1615}
     1616
     1617// ------------------------------ StatListNode ---------------------------------
     1618
     1619StatListNode::~StatListNode()
     1620{
     1621}
     1622
     1623void StatListNode::ref()
     1624{
     1625  Node::ref();
     1626  if ( statement )
     1627    statement->ref();
     1628  if ( list )
     1629    list->ref();
     1630}
     1631
     1632bool StatListNode::deref()
     1633{
     1634  if ( statement && statement->deref() )
     1635    delete statement;
     1636  if ( list && list->deref() )
     1637    delete list;
     1638  return Node::deref();
    8281639}
    8291640
    8301641// ECMA 12.1
    831 Completion BlockNode::execute()
    832 {
    833   if (!statlist)
    834     return Completion(Normal);
    835 
    836   return statlist->execute();
    837 }
    838 
    839 // ECMA 12.1
    840 Completion StatListNode::execute()
     1642Completion StatListNode::execute(ExecState *exec)
    8411643{
    8421644  if (!list) {
    843     Completion c = statement->execute();
     1645    Completion c = statement->execute(exec);
    8441646    KJS_ABORTPOINT
    845     if (KJScriptImp::hadException()) {
    846       KJSO ex = KJScriptImp::exception();
    847       KJScriptImp::clearException();
     1647    if (exec->hadException()) {
     1648      Value ex = exec->exception();
     1649      exec->clearException();
    8481650      return Completion(Throw, ex);
    849     } else
     1651    }
     1652    else
    8501653      return c;
    8511654  }
    8521655
    853   Completion l = list->execute();
     1656  Completion l = list->execute(exec);
    8541657  KJS_ABORTPOINT
    8551658  if (l.complType() != Normal)
    8561659    return l;
    857   Completion e = statement->execute();
     1660  Completion e = statement->execute(exec);
    8581661  KJS_ABORTPOINT;
    859   if (KJScriptImp::hadException()) {
    860     KJSO ex = KJScriptImp::exception();
    861     KJScriptImp::clearException();
     1662
     1663  if (exec->hadException()) {
     1664    Value ex = exec->exception();
     1665    exec->clearException();
    8621666    return Completion(Throw, ex);
    8631667  }
    8641668
    865   KJSO v = e.isValueCompletion() ? e.value() : l.value();
     1669  Value v = e.isValueCompletion() ? e.value() : l.value();
    8661670
    8671671  return Completion(e.complType(), v, e.target() );
    8681672}
    8691673
     1674void StatListNode::processVarDecls(ExecState *exec)
     1675{
     1676  statement->processVarDecls(exec);
     1677
     1678  if (list)
     1679    list->processVarDecls(exec);
     1680}
     1681
     1682// ------------------------------ AssignExprNode -------------------------------
     1683
     1684AssignExprNode::~AssignExprNode()
     1685{
     1686}
     1687
     1688void AssignExprNode::ref()
     1689{
     1690  Node::ref();
     1691  if ( expr )
     1692    expr->ref();
     1693}
     1694
     1695bool AssignExprNode::deref()
     1696{
     1697  if ( expr && expr->deref() )
     1698    delete expr;
     1699  return Node::deref();
     1700}
     1701
    8701702// ECMA 12.2
    871 Completion VarStatementNode::execute()
    872 {
    873   KJS_BREAKPOINT;
    874 
    875   (void) list->evaluate(); // returns 0L
    876 
    877   return Completion(Normal);
     1703Value AssignExprNode::evaluate(ExecState *exec)
     1704{
     1705  return expr->evaluate(exec);
     1706}
     1707
     1708// ------------------------------ VarDeclNode ----------------------------------
     1709
     1710VarDeclNode::VarDeclNode(const UString *id, AssignExprNode *in)
     1711    : ident(*id), init(in)
     1712{
     1713}
     1714
     1715VarDeclNode::~VarDeclNode()
     1716{
     1717}
     1718
     1719void VarDeclNode::ref()
     1720{
     1721  Node::ref();
     1722  if ( init )
     1723    init->ref();
     1724}
     1725
     1726bool VarDeclNode::deref()
     1727{
     1728  if ( init && init->deref() )
     1729    delete init;
     1730  return Node::deref();
    8781731}
    8791732
    8801733// ECMA 12.2
    881 KJSO VarDeclNode::evaluate()
    882 {
    883   KJSO variable = Context::current()->variableObject();
    884 
    885   KJSO val, tmp;
     1734Value VarDeclNode::evaluate(ExecState *exec)
     1735{
     1736  Object variable = Object::dynamicCast(exec->context().variableObject());
     1737
     1738  Value val, tmp;
    8861739  if (init) {
    887       tmp = init->evaluate();
    888       val = tmp.getValue();
     1740      tmp = init->evaluate(exec);
     1741      KJS_CHECKEXCEPTIONVALUE
     1742      val = tmp.getValue(exec);
    8891743  } else {
    890       if ( variable.hasProperty( ident ) ) // already declared ?
    891           return KJSO();
     1744      if ( variable.hasProperty(exec, ident ) ) // already declared ?
     1745          return Value();
    8921746      val = Undefined();
    8931747  }
    894   variable.put(ident, val, DontDelete);
    895 
    896   // spec wants to return ident. But what for ? Will be ignored above.
    897   return KJSO();
    898 }
     1748
     1749#ifdef KJS_VERBOSE
     1750  printInfo(exec,(UString("new variable ")+ident).cstring().c_str(),val);
     1751#endif
     1752  // We use Internal to bypass all checks in derived objects, e.g. so that
     1753  // "var location" creates a dynamic property instead of activating window.location.
     1754  variable.put(exec, ident, val, DontDelete | Internal);
     1755
     1756  return String(ident);
     1757}
     1758
     1759void VarDeclNode::processVarDecls(ExecState *exec)
     1760{
     1761  Object variable = exec->context().variableObject();
     1762  variable.put(exec,ident, Undefined(), DontDelete);
     1763}
     1764
     1765// ------------------------------ VarDeclListNode ------------------------------
     1766
     1767VarDeclListNode::~VarDeclListNode()
     1768{
     1769}
     1770
     1771void VarDeclListNode::ref()
     1772{
     1773  Node::ref();
     1774  if ( list )
     1775    list->ref();
     1776  if ( var )
     1777    var->ref();
     1778}
     1779
     1780bool VarDeclListNode::deref()
     1781{
     1782  if ( list && list->deref() )
     1783    delete list;
     1784  if ( var && var->deref() )
     1785    delete var;
     1786  return Node::deref();
     1787}
     1788
    8991789
    9001790// ECMA 12.2
    901 KJSO VarDeclListNode::evaluate()
     1791Value VarDeclListNode::evaluate(ExecState *exec)
    9021792{
    9031793  if (list)
    904     (void) list->evaluate();
    905 
    906   (void) var->evaluate();
    907 
    908   return KJSO();
     1794    (void) list->evaluate(exec);
     1795  KJS_CHECKEXCEPTIONVALUE
     1796
     1797  (void) var->evaluate(exec);
     1798  KJS_CHECKEXCEPTIONVALUE
     1799
     1800  return Undefined();
     1801}
     1802
     1803void VarDeclListNode::processVarDecls(ExecState *exec)
     1804{
     1805  if (list)
     1806    list->processVarDecls(exec);
     1807
     1808  var->processVarDecls(exec);
     1809}
     1810
     1811// ------------------------------ VarStatementNode -----------------------------
     1812
     1813VarStatementNode::~VarStatementNode()
     1814{
     1815}
     1816
     1817void VarStatementNode::ref()
     1818{
     1819  Node::ref();
     1820  if ( list )
     1821    list->ref();
     1822}
     1823
     1824bool VarStatementNode::deref()
     1825{
     1826  if ( list && list->deref() )
     1827    delete list;
     1828  return Node::deref();
    9091829}
    9101830
    9111831// ECMA 12.2
    912 KJSO AssignExprNode::evaluate()
    913 {
    914   return expr->evaluate();
    915 }
     1832Completion VarStatementNode::execute(ExecState *exec)
     1833{
     1834  KJS_BREAKPOINT;
     1835
     1836  (void) list->evaluate(exec); // returns 0L
     1837  KJS_CHECKEXCEPTION
     1838
     1839  return Completion(Normal);
     1840}
     1841
     1842void VarStatementNode::processVarDecls(ExecState *exec)
     1843{
     1844  list->processVarDecls(exec);
     1845}
     1846
     1847// ------------------------------ BlockNode ------------------------------------
     1848
     1849BlockNode::~BlockNode()
     1850{
     1851}
     1852
     1853void BlockNode::ref()
     1854{
     1855  Node::ref();
     1856  if ( source )
     1857    source->ref();
     1858}
     1859
     1860bool BlockNode::deref()
     1861{
     1862  if ( source && source->deref() )
     1863    delete source;
     1864  return Node::deref();
     1865}
     1866
     1867// ECMA 12.1
     1868Completion BlockNode::execute(ExecState *exec)
     1869{
     1870  if (!source)
     1871    return Completion(Normal);
     1872
     1873  source->processFuncDecl(exec);
     1874
     1875  return source->execute(exec);
     1876}
     1877
     1878void BlockNode::processVarDecls(ExecState *exec)
     1879{
     1880  if (source)
     1881    source->processVarDecls(exec);
     1882}
     1883
     1884// ------------------------------ EmptyStatementNode ---------------------------
    9161885
    9171886// ECMA 12.3
    918 Completion EmptyStatementNode::execute()
     1887Completion EmptyStatementNode::execute(ExecState */*exec*/)
    9191888{
    9201889  return Completion(Normal);
    9211890}
    9221891
     1892// ------------------------------ ExprStatementNode ----------------------------
     1893
     1894ExprStatementNode::~ExprStatementNode()
     1895{
     1896}
     1897
     1898void ExprStatementNode::ref()
     1899{
     1900  Node::ref();
     1901  if ( expr )
     1902    expr->ref();
     1903}
     1904
     1905bool ExprStatementNode::deref()
     1906{
     1907  if ( expr && expr->deref() )
     1908    delete expr;
     1909  return Node::deref();
     1910}
     1911
     1912// ECMA 12.4
     1913Completion ExprStatementNode::execute(ExecState *exec)
     1914{
     1915  KJS_BREAKPOINT;
     1916
     1917  Value e = expr->evaluate(exec);
     1918  KJS_CHECKEXCEPTION
     1919  Value v = e.getValue(exec);
     1920
     1921  return Completion(Normal, v);
     1922}
     1923
     1924// ------------------------------ IfNode ---------------------------------------
     1925
     1926IfNode::~IfNode()
     1927{
     1928}
     1929
     1930void IfNode::ref()
     1931{
     1932  Node::ref();
     1933  if ( statement1 )
     1934    statement1->ref();
     1935  if ( statement2 )
     1936    statement2->ref();
     1937  if ( expr )
     1938    expr->ref();
     1939}
     1940
     1941bool IfNode::deref()
     1942{
     1943  if ( statement1 && statement1->deref() )
     1944    delete statement1;
     1945  if ( statement2 && statement2->deref() )
     1946    delete statement2;
     1947  if ( expr && expr->deref() )
     1948    delete expr;
     1949  return Node::deref();
     1950}
     1951
     1952// ECMA 12.5
     1953Completion IfNode::execute(ExecState *exec)
     1954{
     1955  KJS_BREAKPOINT;
     1956
     1957  Value e = expr->evaluate(exec);
     1958  KJS_CHECKEXCEPTION
     1959  Value v = e.getValue(exec);
     1960  bool b = v.toBoolean(exec);
     1961
     1962  // if ... then
     1963  if (b)
     1964    return statement1->execute(exec);
     1965
     1966  // no else
     1967  if (!statement2)
     1968    return Completion(Normal);
     1969
     1970  // else
     1971  return statement2->execute(exec);
     1972}
     1973
     1974void IfNode::processVarDecls(ExecState *exec)
     1975{
     1976  statement1->processVarDecls(exec);
     1977
     1978  if (statement2)
     1979    statement2->processVarDecls(exec);
     1980}
     1981
     1982// ------------------------------ DoWhileNode ----------------------------------
     1983
     1984DoWhileNode::~DoWhileNode()
     1985{
     1986}
     1987
     1988void DoWhileNode::ref()
     1989{
     1990  Node::ref();
     1991  if ( statement )
     1992    statement->ref();
     1993  if ( expr )
     1994    expr->ref();
     1995}
     1996
     1997bool DoWhileNode::deref()
     1998{
     1999  if ( statement && statement->deref() )
     2000    delete statement;
     2001  if ( expr && expr->deref() )
     2002    delete expr;
     2003  return Node::deref();
     2004}
     2005
     2006// ECMA 12.6.1
     2007Completion DoWhileNode::execute(ExecState *exec)
     2008{
     2009  KJS_BREAKPOINT;
     2010
     2011  Value be, bv;
     2012  Completion c;
     2013  Value value;
     2014
     2015  do {
     2016    // bail out on error
     2017    KJS_CHECKEXCEPTION
     2018
     2019    c = statement->execute(exec);
     2020    if (!((c.complType() == Continue) && ls.contains(c.target()))) {
     2021      if ((c.complType() == Break) && ls.contains(c.target()))
     2022        return Completion(Normal, value);
     2023      if (c.complType() != Normal)
     2024        return c;
     2025    }
     2026    be = expr->evaluate(exec);
     2027    KJS_CHECKEXCEPTION
     2028    bv = be.getValue(exec);
     2029  } while (bv.toBoolean(exec));
     2030
     2031  return Completion(Normal, value);
     2032}
     2033
     2034void DoWhileNode::processVarDecls(ExecState *exec)
     2035{
     2036  statement->processVarDecls(exec);
     2037}
     2038
     2039// ------------------------------ WhileNode ------------------------------------
     2040
     2041WhileNode::~WhileNode()
     2042{
     2043}
     2044
     2045void WhileNode::ref()
     2046{
     2047  Node::ref();
     2048  if ( statement )
     2049    statement->ref();
     2050  if ( expr )
     2051    expr->ref();
     2052}
     2053
     2054bool WhileNode::deref()
     2055{
     2056  if ( statement && statement->deref() )
     2057    delete statement;
     2058  if ( expr && expr->deref() )
     2059    delete expr;
     2060  return Node::deref();
     2061}
     2062
     2063// ECMA 12.6.2
     2064Completion WhileNode::execute(ExecState *exec)
     2065{
     2066  KJS_BREAKPOINT;
     2067
     2068  Value be, bv;
     2069  Completion c;
     2070  bool b(false);
     2071  Value value;
     2072
     2073  while (1) {
     2074    be = expr->evaluate(exec);
     2075    KJS_CHECKEXCEPTION
     2076    bv = be.getValue(exec);
     2077    b = bv.toBoolean(exec);
     2078
     2079    // bail out on error
     2080    KJS_CHECKEXCEPTION
     2081
     2082    if (!b)
     2083      return Completion(Normal, value);
     2084
     2085    c = statement->execute(exec);
     2086    if (c.isValueCompletion())
     2087      value = c.value();
     2088
     2089    if ((c.complType() == Continue) && ls.contains(c.target()))
     2090      continue;
     2091    if ((c.complType() == Break) && ls.contains(c.target()))
     2092      return Completion(Normal, value);
     2093    if (c.complType() != Normal)
     2094      return c;
     2095  }
     2096}
     2097
     2098void WhileNode::processVarDecls(ExecState *exec)
     2099{
     2100  statement->processVarDecls(exec);
     2101}
     2102
     2103// ------------------------------ ForNode --------------------------------------
     2104
     2105ForNode::~ForNode()
     2106{
     2107}
     2108
     2109void ForNode::ref()
     2110{
     2111  Node::ref();
     2112  if ( statement )
     2113    statement->ref();
     2114  if ( expr1 )
     2115    expr1->ref();
     2116  if ( expr2 )
     2117    expr2->ref();
     2118  if ( expr3 )
     2119    expr3->ref();
     2120}
     2121
     2122bool ForNode::deref()
     2123{
     2124  if ( statement && statement->deref() )
     2125    delete statement;
     2126  if ( expr1 && expr1->deref() )
     2127    delete expr1;
     2128  if ( expr2 && expr2->deref() )
     2129    delete expr2;
     2130  if ( expr3 && expr3->deref() )
     2131    delete expr3;
     2132  return Node::deref();
     2133}
     2134
    9232135// ECMA 12.6.3
    924 Completion ForNode::execute()
    925 {
    926   KJSO e, v, cval;
    927   Boolean b;
     2136Completion ForNode::execute(ExecState *exec)
     2137{
     2138  Value e, v, cval;
     2139  bool b;
    9282140
    9292141  if (expr1) {
    930     e = expr1->evaluate();
    931     v = e.getValue();
     2142    e = expr1->evaluate(exec);
     2143    KJS_CHECKEXCEPTION
     2144    v = e.getValue(exec);
    9322145  }
    9332146  while (1) {
    9342147    if (expr2) {
    935       e = expr2->evaluate();
    936       v = e.getValue();
    937       b = v.toBoolean();
    938       if (b.value() == false)
     2148      e = expr2->evaluate(exec);
     2149      KJS_CHECKEXCEPTION
     2150      v = e.getValue(exec);
     2151      b = v.toBoolean(exec);
     2152      if (b == false)
    9392153        return Completion(Normal, cval);
    9402154    }
    9412155    // bail out on error
    942     if (KJScriptImp::hadException())
    943       return Completion(Throw, KJScriptImp::exception());
    944 
    945     Completion c = stat->execute();
     2156    KJS_CHECKEXCEPTION
     2157
     2158    Completion c = statement->execute(exec);
    9462159    if (c.isValueCompletion())
    9472160      cval = c.value();
     
    9532166    }
    9542167    if (expr3) {
    955       e = expr3->evaluate();
    956       v = e.getValue();
     2168      e = expr3->evaluate(exec);
     2169      KJS_CHECKEXCEPTION
     2170      v = e.getValue(exec);
    9572171    }
    9582172  }
    9592173}
    9602174
     2175void ForNode::processVarDecls(ExecState *exec)
     2176{
     2177  if (expr1)
     2178    expr1->processVarDecls(exec);
     2179
     2180  statement->processVarDecls(exec);
     2181}
     2182
     2183// ------------------------------ ForInNode ------------------------------------
     2184
     2185ForInNode::ForInNode(Node *l, Node *e, StatementNode *s)
     2186  : init(0L), lexpr(l), expr(e), varDecl(0L), statement(s)
     2187{
     2188}
     2189
     2190ForInNode::ForInNode(const UString *i, AssignExprNode *in, Node *e, StatementNode *s)
     2191  : ident(*i), init(in), expr(e), statement(s)
     2192{
     2193  // for( var foo = bar in baz )
     2194  varDecl = new VarDeclNode(&ident, init);
     2195  lexpr = new ResolveNode(&ident);
     2196}
     2197
     2198ForInNode::~ForInNode()
     2199{
     2200}
     2201
     2202void ForInNode::ref()
     2203{
     2204  Node::ref();
     2205  if ( statement )
     2206    statement->ref();
     2207  if ( expr )
     2208    expr->ref();
     2209  if ( lexpr )
     2210    lexpr->ref();
     2211  if ( init )
     2212    init->ref();
     2213  if ( varDecl )
     2214    varDecl->ref();
     2215}
     2216
     2217bool ForInNode::deref()
     2218{
     2219  if ( statement && statement->deref() )
     2220    delete statement;
     2221  if ( expr && expr->deref() )
     2222    delete expr;
     2223  if ( lexpr && lexpr->deref() )
     2224    delete lexpr;
     2225  if ( init && init->deref() )
     2226    delete init;
     2227  if ( varDecl && varDecl->deref() )
     2228    delete varDecl;
     2229  return Node::deref();
     2230}
     2231
    9612232// ECMA 12.6.4
    962 Completion ForInNode::execute()
    963 {
    964   KJSO e, v, retval;
     2233Completion ForInNode::execute(ExecState *exec)
     2234{
     2235  Value e, retval;
     2236  Object v;
    9652237  Completion c;
    966   VarDeclNode *vd = 0;
    967   const PropList *lst, *curr;
    968 
    969   // This should be done in the constructor
    970   if (!lexpr) { // for( var foo = bar in baz )
    971     vd = new VarDeclNode(&ident, init);
    972     vd->evaluate();
    973 
    974     lexpr = new ResolveNode(&ident);
     2238  List propList;
     2239
     2240  if ( varDecl ) {
     2241    varDecl->evaluate(exec);
     2242    KJS_CHECKEXCEPTION
    9752243  }
    9762244
    977   e = expr->evaluate();
    978   v = e.getValue().toObject();
    979   curr = lst = v.imp()->propList();
    980 
    981   while (curr) {
    982     if (!v.hasProperty(curr->name)) {
    983       curr = curr->next;
     2245  e = expr->evaluate(exec);
     2246  KJS_CHECKEXCEPTION
     2247  v = e.getValue(exec).toObject(exec);
     2248  propList = v.propList(exec);
     2249
     2250  ListIterator propIt = propList.begin();
     2251
     2252  while (propIt != propList.end()) {
     2253    UString name = propIt->getPropertyName(exec);
     2254    if (!v.hasProperty(exec,name)) {
     2255      propIt++;
    9842256      continue;
    9852257    }
    9862258
    987     e = lexpr->evaluate();
    988     e.putValue(String(curr->name));
    989 
    990     c = stat->execute();
     2259    e = lexpr->evaluate(exec);
     2260    KJS_CHECKEXCEPTION
     2261    e.putValue(exec,String(name));
     2262
     2263    c = statement->execute(exec);
    9912264    if (c.isValueCompletion())
    9922265      retval = c.value();
     
    9962269        break;
    9972270      if (c.complType() != Normal) {
    998         delete lst;
    9992271        return c;
    10002272      }
    10012273    }
    10022274
    1003     curr = curr->next;
     2275    propIt++;
    10042276  }
    10052277
    1006   delete lst;
     2278  // bail out on error
     2279  KJS_CHECKEXCEPTION
     2280
    10072281  return Completion(Normal, retval);
    10082282}
    10092283
    1010 // ECMA 12.4
    1011 Completion ExprStatementNode::execute()
     2284void ForInNode::processVarDecls(ExecState *exec)
     2285{
     2286  statement->processVarDecls(exec);
     2287}
     2288
     2289// ------------------------------ ContinueNode ---------------------------------
     2290
     2291// ECMA 12.7
     2292Completion ContinueNode::execute(ExecState *exec)
    10122293{
    10132294  KJS_BREAKPOINT;
    10142295
    1015   KJSO e = expr->evaluate();
    1016   KJSO v = e.getValue();
    1017 
    1018   return Completion(Normal, v);
    1019 }
    1020 
    1021 // ECMA 12.5
    1022 Completion IfNode::execute()
    1023 {
    1024   KJS_BREAKPOINT;
    1025 
    1026   KJSO e = expr->evaluate();
    1027   KJSO v = e.getValue();
    1028   Boolean b = v.toBoolean();
    1029 
    1030   // if ... then
    1031   if (b.value())
    1032     return statement1->execute();
    1033 
    1034   // no else
    1035   if (!statement2)
    1036     return Completion(Normal);
    1037 
    1038   // else
    1039   return statement2->execute();
    1040 }
    1041 
    1042 // ECMA 12.6.1
    1043 Completion DoWhileNode::execute()
    1044 {
    1045   KJS_BREAKPOINT;
    1046 
    1047   KJSO be, bv;
    1048   Completion c;
    1049   KJSO value;
    1050 
    1051   do {
    1052     // bail out on error
    1053     if (KJScriptImp::hadException())
    1054       return Completion(Throw, KJScriptImp::exception());
    1055 
    1056     c = statement->execute();
    1057     if (!((c.complType() == Continue) && ls.contains(c.target()))) {
    1058       if ((c.complType() == Break) && ls.contains(c.target()))
    1059         return Completion(Normal, value);
    1060       if (c.complType() != Normal)
    1061         return c;
    1062     }
    1063     be = expr->evaluate();
    1064     bv = be.getValue();
    1065   } while (bv.toBoolean().value());
    1066 
    1067   return Completion(Normal, value);
    1068 }
    1069 
    1070 // ECMA 12.6.2
    1071 Completion WhileNode::execute()
    1072 {
    1073   KJS_BREAKPOINT;
    1074 
    1075   KJSO be, bv;
    1076   Completion c;
    1077   Boolean b(false);
    1078   KJSO value;
    1079 
    1080   while (1) {
    1081     be = expr->evaluate();
    1082     bv = be.getValue();
    1083     b = bv.toBoolean();
    1084 
    1085     // bail out on error
    1086     if (KJScriptImp::hadException())
    1087       return Completion(Throw, KJScriptImp::exception());
    1088 
    1089     if (!b.value())
    1090       return Completion(Normal, value);
    1091 
    1092     c = statement->execute();
    1093     if (c.isValueCompletion())
    1094       value = c.value();
    1095 
    1096     if ((c.complType() == Continue) && ls.contains(c.target()))
    1097       continue;
    1098     if ((c.complType() == Break) && ls.contains(c.target()))
    1099       return Completion(Normal, value);
    1100     if (c.complType() != Normal)
    1101       return c;
    1102   }
    1103 }
    1104 
    1105 // ECMA 12.7
    1106 Completion ContinueNode::execute()
    1107 {
    1108   KJS_BREAKPOINT;
    1109 
    1110   KJSO dummy;
    1111   return Context::current()->seenLabels()->contains(ident) ?
     2296  Value dummy;
     2297  return exec->context().imp()->seenLabels()->contains(ident) ?
    11122298    Completion(Continue, dummy, ident) :
    11132299    Completion(Throw,
    1114                throwError(SyntaxError, "Label not found in containing block"));
    1115 }
     2300               throwError(exec, SyntaxError, "Label not found in containing block"));
     2301}
     2302
     2303// ------------------------------ BreakNode ------------------------------------
    11162304
    11172305// ECMA 12.8
    1118 Completion BreakNode::execute()
     2306Completion BreakNode::execute(ExecState *exec)
    11192307{
    11202308  KJS_BREAKPOINT;
    11212309
    1122   KJSO dummy;
    1123   return Context::current()->seenLabels()->contains(ident) ?
     2310  Value dummy;
     2311  return exec->context().imp()->seenLabels()->contains(ident) ?
    11242312    Completion(Break, dummy, ident) :
    11252313    Completion(Throw,
    1126                throwError(SyntaxError, "Label not found in containing block"));
     2314               throwError(exec, SyntaxError, "Label not found in containing block"));
     2315}
     2316
     2317// ------------------------------ ReturnNode -----------------------------------
     2318
     2319ReturnNode::~ReturnNode()
     2320{
     2321}
     2322
     2323void ReturnNode::ref()
     2324{
     2325  Node::ref();
     2326  if ( value )
     2327    value->ref();
     2328}
     2329
     2330bool ReturnNode::deref()
     2331{
     2332  if ( value && value->deref() )
     2333    delete value;
     2334  return Node::deref();
    11272335}
    11282336
    11292337// ECMA 12.9
    1130 Completion ReturnNode::execute()
     2338Completion ReturnNode::execute(ExecState *exec)
    11312339{
    11322340  KJS_BREAKPOINT;
     
    11352343    return Completion(ReturnValue, Undefined());
    11362344
    1137   KJSO e = value->evaluate();
    1138   KJSO v = e.getValue();
     2345  Value e = value->evaluate(exec);
     2346  KJS_CHECKEXCEPTION
     2347  Value v = e.getValue(exec);
    11392348
    11402349  return Completion(ReturnValue, v);
    11412350}
    11422351
     2352// ------------------------------ WithNode -------------------------------------
     2353
     2354WithNode::~WithNode()
     2355{
     2356}
     2357
     2358void WithNode::ref()
     2359{
     2360  Node::ref();
     2361  if ( statement )
     2362    statement->ref();
     2363  if ( expr )
     2364    expr->ref();
     2365}
     2366
     2367bool WithNode::deref()
     2368{
     2369  if ( statement && statement->deref() )
     2370    delete statement;
     2371  if ( expr && expr->deref() )
     2372    delete expr;
     2373  return Node::deref();
     2374}
     2375
    11432376// ECMA 12.10
    1144 Completion WithNode::execute()
     2377Completion WithNode::execute(ExecState *exec)
    11452378{
    11462379  KJS_BREAKPOINT;
    11472380
    1148   KJSO e = expr->evaluate();
    1149   KJSO v = e.getValue();
    1150   Object o = v.toObject();
    1151   Context::current()->pushScope(o);
    1152   Completion res = stat->execute();
    1153   Context::current()->popScope();
     2381  Value e = expr->evaluate(exec);
     2382  KJS_CHECKEXCEPTION
     2383  Value v = e.getValue(exec);
     2384  Object o = v.toObject(exec);
     2385  KJS_CHECKEXCEPTION
     2386  exec->context().imp()->pushScope(o);
     2387  Completion res = statement->execute(exec);
     2388  exec->context().imp()->popScope();
    11542389
    11552390  return res;
     2391}
     2392
     2393void WithNode::processVarDecls(ExecState *exec)
     2394{
     2395  statement->processVarDecls(exec);
     2396}
     2397
     2398// ------------------------------ CaseClauseNode -------------------------------
     2399
     2400CaseClauseNode::~CaseClauseNode()
     2401{
     2402}
     2403
     2404void CaseClauseNode::ref()
     2405{
     2406  Node::ref();
     2407  if ( expr )
     2408    expr->ref();
     2409  if ( list )
     2410    list->ref();
     2411}
     2412
     2413bool CaseClauseNode::deref()
     2414{
     2415  if ( expr && expr->deref() )
     2416    delete expr;
     2417  if ( list && list->deref() )
     2418    delete list;
     2419  return Node::deref();
     2420}
     2421
     2422// ECMA 12.11
     2423Value CaseClauseNode::evaluate(ExecState *exec)
     2424{
     2425  Value e = expr->evaluate(exec);
     2426  KJS_CHECKEXCEPTIONVALUE
     2427  Value v = e.getValue(exec);
     2428
     2429  return v;
     2430}
     2431
     2432// ECMA 12.11
     2433Completion CaseClauseNode::evalStatements(ExecState *exec)
     2434{
     2435  if (list)
     2436    return list->execute(exec);
     2437  else
     2438    return Completion(Normal, Undefined());
     2439}
     2440
     2441void CaseClauseNode::processVarDecls(ExecState *exec)
     2442{
     2443  if (list)
     2444    list->processVarDecls(exec);
     2445}
     2446
     2447// ------------------------------ ClauseListNode -------------------------------
     2448
     2449ClauseListNode::~ClauseListNode()
     2450{
     2451}
     2452
     2453void ClauseListNode::ref()
     2454{
     2455  Node::ref();
     2456  if ( cl )
     2457    cl->ref();
     2458  if ( nx )
     2459    nx->ref();
     2460}
     2461
     2462bool ClauseListNode::deref()
     2463{
     2464  if ( cl && cl->deref() )
     2465    delete cl;
     2466  if ( nx && nx->deref() )
     2467    delete nx;
     2468  return Node::deref();
     2469}
     2470
     2471Value ClauseListNode::evaluate(ExecState */*exec*/)
     2472{
     2473  /* should never be called */
     2474  assert(false);
     2475  return Value();
    11562476}
    11572477
     
    11672487}
    11682488
     2489void ClauseListNode::processVarDecls(ExecState *exec)
     2490{
     2491  if (cl)
     2492    cl->processVarDecls(exec);
     2493  if (nx)
     2494    nx->processVarDecls(exec);
     2495}
     2496
     2497// ------------------------------ CaseBlockNode --------------------------------
     2498
     2499CaseBlockNode::~CaseBlockNode()
     2500{
     2501}
     2502
     2503void CaseBlockNode::ref()
     2504{
     2505  Node::ref();
     2506  if ( def )
     2507    def->ref();
     2508  if ( list1 )
     2509    list1->ref();
     2510  if ( list2 )
     2511    list2->ref();
     2512}
     2513
     2514bool CaseBlockNode::deref()
     2515{
     2516  if ( def && def->deref() )
     2517    delete def;
     2518  if ( list1 && list1->deref() )
     2519    delete list1;
     2520  if ( list2 && list2->deref() )
     2521    delete list2;
     2522  return Node::deref();
     2523}
     2524
     2525Value CaseBlockNode::evaluate(ExecState */*exec*/)
     2526{
     2527  /* should never be called */
     2528  assert(false);
     2529  return Value();
     2530}
     2531
    11692532// ECMA 12.11
    1170 Completion SwitchNode::execute()
    1171 {
    1172   KJS_BREAKPOINT;
    1173 
    1174   KJSO e = expr->evaluate();
    1175   KJSO v = e.getValue();
    1176   Completion res = block->evalBlock(v);
    1177 
    1178   if ((res.complType() == Break) && ls.contains(res.target()))
    1179     return Completion(Normal, res.value());
    1180   else
    1181     return res;
    1182 }
    1183 
    1184 // ECMA 12.11
    1185 Completion CaseBlockNode::evalBlock(const KJSO& input)
    1186 {
    1187   KJSO v;
     2533Completion CaseBlockNode::evalBlock(ExecState *exec, const Value& input)
     2534{
     2535  Value v;
    11882536  Completion res;
    11892537  ClauseListNode *a = list1, *b = list2;
     
    11942542      clause = a->clause();
    11952543      a = a->next();
    1196       v = clause->evaluate();
    1197       if (strictEqual(input, v)) {
    1198         res = clause->evalStatements();
     2544      v = clause->evaluate(exec);
     2545      KJS_CHECKEXCEPTION
     2546      if (strictEqual(exec, input, v)) {
     2547        res = clause->evalStatements(exec);
    11992548        if (res.complType() != Normal)
    12002549          return res;
    12012550        while (a) {
    1202           res = a->clause()->evalStatements();
     2551          res = a->clause()->evalStatements(exec);
    12032552          if (res.complType() != Normal)
    12042553            return res;
     
    12132562    clause = b->clause();
    12142563    b = b->next();
    1215     v = clause->evaluate();
    1216     if (strictEqual(input, v)) {
    1217       res = clause->evalStatements();
     2564    v = clause->evaluate(exec);
     2565    KJS_CHECKEXCEPTION
     2566    if (strictEqual(exec, input, v)) {
     2567      res = clause->evalStatements(exec);
    12182568      if (res.complType() != Normal)
    12192569        return res;
     
    12242574  // default clause
    12252575  if (def) {
    1226     res = def->evalStatements();
     2576    res = def->evalStatements(exec);
    12272577    if (res.complType() != Normal)
    12282578      return res;
     
    12322582  while (b) {
    12332583    clause = b->clause();
    1234     res = clause->evalStatements();
     2584    res = clause->evalStatements(exec);
    12352585    if (res.complType() != Normal)
    12362586      return res;
     
    12382588  }
    12392589
     2590  // bail out on error
     2591  KJS_CHECKEXCEPTION
     2592
    12402593  return Completion(Normal);
    12412594}
    12422595
     2596void CaseBlockNode::processVarDecls(ExecState *exec)
     2597{
     2598  if (list1)
     2599    list1->processVarDecls(exec);
     2600  if (def)
     2601    def->processVarDecls(exec);
     2602  if (list2)
     2603    list2->processVarDecls(exec);
     2604}
     2605
     2606// ------------------------------ SwitchNode -----------------------------------
     2607
     2608SwitchNode::~SwitchNode()
     2609{
     2610}
     2611
     2612void SwitchNode::ref()
     2613{
     2614  Node::ref();
     2615  if ( expr )
     2616    expr->ref();
     2617  if ( block )
     2618    block->ref();
     2619}
     2620
     2621bool SwitchNode::deref()
     2622{
     2623  if ( expr && expr->deref() )
     2624    delete expr;
     2625  if ( block && block->deref() )
     2626    delete block;
     2627  return Node::deref();
     2628}
     2629
    12432630// ECMA 12.11
    1244 KJSO CaseClauseNode::evaluate()
    1245 {
    1246   KJSO e = expr->evaluate();
    1247   KJSO v = e.getValue();
    1248 
    1249   return v;
    1250 }
    1251 
    1252 // ECMA 12.11
    1253 Completion CaseClauseNode::evalStatements()
    1254 {
    1255   if (list)
    1256     return list->execute();
     2631Completion SwitchNode::execute(ExecState *exec)
     2632{
     2633  KJS_BREAKPOINT;
     2634
     2635  Value e = expr->evaluate(exec);
     2636  KJS_CHECKEXCEPTION
     2637  Value v = e.getValue(exec);
     2638  Completion res = block->evalBlock(exec,v);
     2639
     2640  if ((res.complType() == Break) && ls.contains(res.target()))
     2641    return Completion(Normal, res.value());
    12572642  else
    1258     return Completion(Normal, Undefined());
     2643    return res;
     2644}
     2645
     2646void SwitchNode::processVarDecls(ExecState *exec)
     2647{
     2648  block->processVarDecls(exec);
     2649}
     2650
     2651// ------------------------------ LabelNode ------------------------------------
     2652
     2653LabelNode::~LabelNode()
     2654{
     2655}
     2656
     2657void LabelNode::ref()
     2658{
     2659  Node::ref();
     2660  if ( statement )
     2661    statement->ref();
     2662}
     2663
     2664bool LabelNode::deref()
     2665{
     2666  if ( statement && statement->deref() )
     2667    delete statement;
     2668  return Node::deref();
    12592669}
    12602670
    12612671// ECMA 12.12
    1262 Completion LabelNode::execute()
     2672Completion LabelNode::execute(ExecState *exec)
    12632673{
    12642674  Completion e;
    12652675
    1266   if (!Context::current()->seenLabels()->push(label)) {
     2676  if (!exec->context().imp()->seenLabels()->push(label)) {
    12672677    return Completion( Throw,
    1268                        throwError(SyntaxError, "Duplicated label found" ));
     2678                       throwError(exec, SyntaxError, "Duplicated label found" ));
    12692679  };
    1270   e = stat->execute();
    1271   Context::current()->seenLabels()->pop();
     2680  e = statement->execute(exec);
     2681  exec->context().imp()->seenLabels()->pop();
    12722682
    12732683  if ((e.complType() == Break) && (e.target() == label))
     
    12772687}
    12782688
     2689void LabelNode::processVarDecls(ExecState *exec)
     2690{
     2691  statement->processVarDecls(exec);
     2692}
     2693
     2694// ------------------------------ ThrowNode ------------------------------------
     2695
     2696ThrowNode::~ThrowNode()
     2697{
     2698}
     2699
     2700void ThrowNode::ref()
     2701{
     2702  Node::ref();
     2703  if ( expr )
     2704    expr->ref();
     2705}
     2706
     2707bool ThrowNode::deref()
     2708{
     2709  if ( expr && expr->deref() )
     2710    delete expr;
     2711  return Node::deref();
     2712}
     2713
    12792714// ECMA 12.13
    1280 Completion ThrowNode::execute()
     2715Completion ThrowNode::execute(ExecState *exec)
    12812716{
    12822717  KJS_BREAKPOINT;
    12832718
    1284   KJSO v = expr->evaluate().getValue();
     2719  Value e = expr->evaluate(exec);
     2720  KJS_CHECKEXCEPTION
     2721  Value v = e.getValue(exec);
     2722
     2723  // bail out on error
     2724  KJS_CHECKEXCEPTION
    12852725
    12862726  return Completion(Throw, v);
    12872727}
    12882728
     2729// ------------------------------ CatchNode ------------------------------------
     2730
     2731CatchNode::~CatchNode()
     2732{
     2733}
     2734
     2735void CatchNode::ref()
     2736{
     2737  Node::ref();
     2738  if ( block )
     2739    block->ref();
     2740}
     2741
     2742bool CatchNode::deref()
     2743{
     2744  if ( block && block->deref() )
     2745    delete block;
     2746  return Node::deref();
     2747}
     2748
     2749Completion CatchNode::execute(ExecState */*exec*/)
     2750{
     2751  // should never be reached. execute(exec, arg) is used instead
     2752  assert(0L);
     2753  return Completion();
     2754}
     2755
    12892756// ECMA 12.14
    1290 Completion TryNode::execute()
     2757Completion CatchNode::execute(ExecState *exec, const Value &arg)
     2758{
     2759  /* TODO: correct ? Not part of the spec */
     2760
     2761  exec->clearException();
     2762
     2763  Object obj(new ObjectImp());
     2764  obj.put(exec, ident, arg, DontDelete);
     2765  exec->context().imp()->pushScope(obj);
     2766  Completion c = block->execute(exec);
     2767  exec->context().imp()->popScope();
     2768
     2769  return c;
     2770}
     2771
     2772void CatchNode::processVarDecls(ExecState *exec)
     2773{
     2774  block->processVarDecls(exec);
     2775}
     2776
     2777// ------------------------------ FinallyNode ----------------------------------
     2778
     2779FinallyNode::~FinallyNode()
     2780{
     2781}
     2782
     2783void FinallyNode::ref()
     2784{
     2785  Node::ref();
     2786  if ( block )
     2787    block->ref();
     2788}
     2789
     2790bool FinallyNode::deref()
     2791{
     2792  if ( block && block->deref() )
     2793    delete block;
     2794  return Node::deref();
     2795}
     2796
     2797// ECMA 12.14
     2798Completion FinallyNode::execute(ExecState *exec)
     2799{
     2800  return block->execute(exec);
     2801}
     2802
     2803void FinallyNode::processVarDecls(ExecState *exec)
     2804{
     2805  block->processVarDecls(exec);
     2806}
     2807
     2808// ------------------------------ TryNode --------------------------------------
     2809
     2810TryNode::~TryNode()
     2811{
     2812}
     2813
     2814void TryNode::ref()
     2815{
     2816  Node::ref();
     2817  if ( block )
     2818    block->ref();
     2819  if ( _final )
     2820    _final->ref();
     2821  if ( _catch )
     2822    _catch->ref();
     2823}
     2824
     2825bool TryNode::deref()
     2826{
     2827  if ( block && block->deref() )
     2828    delete block;
     2829  if ( _final && _final->deref() )
     2830    delete _final;
     2831  if ( _catch && _catch->deref() )
     2832    delete _catch;
     2833  return Node::deref();
     2834}
     2835
     2836// ECMA 12.14
     2837Completion TryNode::execute(ExecState *exec)
    12912838{
    12922839  KJS_BREAKPOINT;
     
    12942841  Completion c, c2;
    12952842
    1296   c = block->execute();
     2843  c = block->execute(exec);
    12972844
    12982845  if (!_final) {
    12992846    if (c.complType() != Throw)
    13002847      return c;
    1301     return _catch->execute(c.value());
     2848    return _catch->execute(exec,c.value());
    13022849  }
    13032850
    13042851  if (!_catch) {
    1305     c2 = _final->execute();
     2852    c2 = _final->execute(exec);
    13062853    return (c2.complType() == Normal) ? c : c2;
    13072854  }
    13082855
    13092856  if (c.complType() == Throw)
    1310     c = _catch->execute(c.value());
    1311 
    1312   c2 = _final->execute();
     2857    c = _catch->execute(exec,c.value());
     2858
     2859  c2 = _final->execute(exec);
    13132860  return (c2.complType() == Normal) ? c : c2;
    13142861}
    13152862
    1316 Completion CatchNode::execute()
    1317 {
    1318   // should never be reached. execute(const KJS &arg) is used instead
    1319   assert(0L);
    1320   return Completion();
    1321 }
    1322 
    1323 // ECMA 12.14
    1324 Completion CatchNode::execute(const KJSO &arg)
    1325 {
    1326   /* TODO: correct ? Not part of the spec */
    1327   KJScriptImp::clearException();
    1328 
    1329   Object obj;
    1330   obj.put(ident, arg, DontDelete);
    1331   Context::current()->pushScope(obj);
    1332   Completion c = block->execute();
    1333   Context::current()->popScope();
    1334 
    1335   return c;
    1336 }
    1337 
    1338 // ECMA 12.14
    1339 Completion FinallyNode::execute()
    1340 {
    1341   return block->execute();
    1342 }
     2863void TryNode::processVarDecls(ExecState *exec)
     2864{
     2865  block->processVarDecls(exec);
     2866  if (_final)
     2867    _final->processVarDecls(exec);
     2868  if (_catch)
     2869    _catch->processVarDecls(exec);
     2870}
     2871
     2872// ------------------------------ ParameterNode --------------------------------
     2873
     2874ParameterNode::~ParameterNode()
     2875{
     2876}
     2877
     2878void ParameterNode::ref()
     2879{
     2880  Node::ref();
     2881  if ( next )
     2882    next->ref();
     2883}
     2884
     2885bool ParameterNode::deref()
     2886{
     2887  if ( next && next->deref() )
     2888    delete next;
     2889  return Node::deref();
     2890}
     2891
     2892ParameterNode* ParameterNode::append(const UString *i)
     2893{
     2894  ParameterNode *p = this;
     2895  while (p->next)
     2896    p = p->next;
     2897
     2898  p->next = new ParameterNode(i);
     2899
     2900  return this;
     2901}
     2902
     2903// ECMA 13
     2904Value ParameterNode::evaluate(ExecState */*exec*/)
     2905{
     2906  return Undefined();
     2907}
     2908
     2909// ------------------------------ FunctionBodyNode -----------------------------
     2910
    13432911
    13442912FunctionBodyNode::FunctionBodyNode(SourceElementsNode *s)
    13452913  : source(s)
    13462914{
    1347 #ifdef KJS_DEBUGGER
    1348   setLoc(-1, -1);
    1349 #endif
     2915  setLoc(-1, -1, -1);
     2916  //fprintf(stderr,"FunctionBodyNode::FunctionBodyNode %p\n",this);
     2917}
     2918
     2919FunctionBodyNode::~FunctionBodyNode()
     2920{
     2921  //fprintf(stderr,"FunctionBodyNode::~FunctionBodyNode %p\n",this);
     2922}
     2923
     2924void FunctionBodyNode::ref()
     2925{
     2926  Node::ref();
     2927  if ( source )
     2928    source->ref();
     2929  //fprintf( stderr, "FunctionBodyNode::ref() %p. Refcount now %d\n", (void*)this, refcount);
     2930}
     2931
     2932bool FunctionBodyNode::deref()
     2933{
     2934  if ( source && source->deref() )
     2935    delete source;
     2936  //fprintf( stderr, "FunctionBodyNode::deref() %p. Refcount now %d\n", (void*)this, refcount-1);
     2937  return Node::deref();
    13502938}
    13512939
    13522940// ECMA 13 + 14 for ProgramNode
    1353 Completion FunctionBodyNode::execute()
     2941Completion FunctionBodyNode::execute(ExecState *exec)
    13542942{
    13552943  /* TODO: workaround for empty body which I don't see covered by the spec */
     
    13572945    return Completion(ReturnValue, Undefined());
    13582946
    1359   source->processFuncDecl();
    1360 
    1361   return source->execute();
     2947  source->processFuncDecl(exec);
     2948
     2949  return source->execute(exec);
     2950}
     2951
     2952void FunctionBodyNode::processFuncDecl(ExecState *exec)
     2953{
     2954  if (source)
     2955    source->processFuncDecl(exec);
     2956}
     2957
     2958void FunctionBodyNode::processVarDecls(ExecState *exec)
     2959{
     2960  if (source)
     2961    source->processVarDecls(exec);
     2962}
     2963
     2964// ------------------------------ FuncDeclNode ---------------------------------
     2965
     2966FuncDeclNode::~FuncDeclNode()
     2967{
     2968}
     2969
     2970void FuncDeclNode::ref()
     2971{
     2972  Node::ref();
     2973  if ( param )
     2974    param->ref();
     2975  if ( body )
     2976    body->ref();
     2977}
     2978
     2979bool FuncDeclNode::deref()
     2980{
     2981  if ( param && param->deref() )
     2982    delete param;
     2983  if ( body && body->deref() )
     2984    delete body;
     2985  return Node::deref();
    13622986}
    13632987
    13642988// ECMA 13
    1365 void FuncDeclNode::processFuncDecl()
    1366 {
    1367   const List *sc = Context::current()->pScopeChain();
    1368   /* TODO: let this be an object with [[Class]] property "Function" */
    1369   FunctionImp *fimp = new DeclaredFunctionImp(ident, body, sc);
    1370   Function func(fimp); // protect from GC
    1371   fimp->put("prototype", Object::create(ObjectClass), DontDelete);
     2989void FuncDeclNode::processFuncDecl(ExecState *exec)
     2990{
     2991  const List sc = exec->context().imp()->scopeChain();
     2992
     2993  // TODO: let this be an object with [[Class]] property "Function"
     2994  FunctionImp *fimp = new DeclaredFunctionImp(exec, ident, body, sc);
     2995  Object func(fimp); // protect from GC
     2996
     2997  //  Value proto = exec->interpreter()->builtinObject().construct(exec,List::empty());
     2998  List empty;
     2999  Value proto = exec->interpreter()->builtinObject().construct(exec,empty);
     3000  func.put(exec, "prototype", proto, Internal|DontDelete);
    13723001
    13733002  int plen = 0;
     
    13753004    fimp->addParameter(p->ident());
    13763005
    1377   fimp->setLength(plen);
    1378 
    1379   Context::current()->variableObject().put(ident, func);
    1380 }
     3006  func.put(exec, "length", Number(plen), ReadOnly|DontDelete|DontEnum);
     3007
     3008  exec->context().imp()->variableObject().put(exec,ident,func);
     3009
     3010  if (body) {
     3011    // hack the scope so that the function gets put as a property of func, and it's scope
     3012    // contains the func as well as our current scope
     3013    Object oldVar = exec->context().imp()->variableObject();
     3014    exec->context().imp()->setVariableObject(func);
     3015    exec->context().imp()->pushScope(func);
     3016    body->processFuncDecl(exec);
     3017    exec->context().imp()->popScope();
     3018    exec->context().imp()->setVariableObject(oldVar);
     3019  }
     3020}
     3021
     3022// ------------------------------ FuncExprNode ---------------------------------
     3023
     3024FuncExprNode::~FuncExprNode()
     3025{
     3026}
     3027
     3028void FuncExprNode::ref()
     3029{
     3030  Node::ref();
     3031  if ( param )
     3032    param->ref();
     3033  if ( body )
     3034    body->ref();
     3035}
     3036
     3037bool FuncExprNode::deref()
     3038{
     3039  if ( param && param->deref() )
     3040    delete param;
     3041  if ( body && body->deref() )
     3042    delete body;
     3043  return Node::deref();
     3044}
     3045
    13813046
    13823047// ECMA 13
    1383 KJSO FuncExprNode::evaluate()
    1384 {
    1385   const List *sc = Context::current()->pScopeChain();
    1386   FunctionImp *fimp = new DeclaredFunctionImp(UString::null, body, sc->copy());
    1387   Function ret(fimp);
     3048Value FuncExprNode::evaluate(ExecState *exec)
     3049{
     3050  const List sc = exec->context().scopeChain();
     3051  FunctionImp *fimp = new DeclaredFunctionImp(exec, UString::null, body, sc);
     3052  Value ret(fimp);
     3053  List empty;
     3054  Value proto = exec->interpreter()->builtinObject().construct(exec,empty);
     3055  fimp->put(exec, "prototype", proto, Internal|DontDelete);
    13883056
    13893057  int plen = 0;
    13903058  for(ParameterNode *p = param; p != 0L; p = p->nextParam(), plen++)
    13913059    fimp->addParameter(p->ident());
    1392   fimp->setLength(plen);
     3060  fimp->put(exec,"length", Number(plen), ReadOnly|DontDelete|DontEnum);
    13933061
    13943062  return ret;
    13953063}
    13963064
    1397 ParameterNode* ParameterNode::append(const UString *i)
    1398 {
    1399   ParameterNode *p = this;
    1400   while (p->next)
    1401     p = p->next;
    1402 
    1403   p->next = new ParameterNode(i);
    1404 
    1405   return this;
    1406 }
    1407 
    1408 // ECMA 13
    1409 KJSO ParameterNode::evaluate()
    1410 {
    1411   return Undefined();
    1412 }
    1413 
    1414 void ProgramNode::deleteGlobalStatements()
    1415 {
    1416   source->deleteStatements();
     3065// ------------------------------ SourceElementNode ----------------------------
     3066
     3067SourceElementNode::~SourceElementNode()
     3068{
     3069}
     3070
     3071void SourceElementNode::ref()
     3072{
     3073  Node::ref();
     3074  if ( statement )
     3075    statement->ref();
     3076  if ( function )
     3077    function->ref();
     3078}
     3079
     3080bool SourceElementNode::deref()
     3081{
     3082  if ( statement && statement->deref() )
     3083    delete statement;
     3084  if ( function && function->deref() )
     3085    delete function;
     3086  return Node::deref();
    14173087}
    14183088
    14193089// ECMA 14
    1420 Completion SourceElementsNode::execute()
    1421 {
    1422   if (KJScriptImp::hadException())
    1423     return Completion(Throw, KJScriptImp::exception());
     3090Completion SourceElementNode::execute(ExecState *exec)
     3091{
     3092  if (statement)
     3093    return statement->execute(exec);
     3094
     3095  return Completion(Normal);
     3096}
     3097
     3098// ECMA 14
     3099void SourceElementNode::processFuncDecl(ExecState *exec)
     3100{
     3101  if (function)
     3102    function->processFuncDecl(exec);
     3103}
     3104
     3105void SourceElementNode::processVarDecls(ExecState *exec)
     3106{
     3107  if (statement)
     3108    statement->processVarDecls(exec);
     3109}
     3110
     3111// ------------------------------ SourceElementsNode ---------------------------
     3112
     3113SourceElementsNode::~SourceElementsNode()
     3114{
     3115}
     3116
     3117void SourceElementsNode::ref()
     3118{
     3119  Node::ref();
     3120  if ( element )
     3121    element->ref();
     3122  if ( elements )
     3123    elements->ref();
     3124}
     3125
     3126bool SourceElementsNode::deref()
     3127{
     3128  if ( element && element->deref() )
     3129    delete element;
     3130  if ( elements && elements->deref() )
     3131    delete elements;
     3132  return Node::deref();
     3133}
     3134
     3135// ECMA 14
     3136Completion SourceElementsNode::execute(ExecState *exec)
     3137{
     3138  KJS_CHECKEXCEPTION
    14243139
    14253140  if (!elements)
    1426     return element->execute();
    1427 
    1428   Completion c1 = elements->execute();
    1429   if (KJScriptImp::hadException())
    1430     return Completion(Throw, KJScriptImp::exception());
     3141    return element->execute(exec);
     3142
     3143  Completion c1 = elements->execute(exec);
     3144  KJS_CHECKEXCEPTION
    14313145  if (c1.complType() != Normal)
    14323146    return c1;
    14333147
    1434   Completion c2 = element->execute();
    1435   if (KJScriptImp::hadException())
    1436     return Completion(Throw, KJScriptImp::exception());
    1437 
    1438   return c2;
     3148  Completion c2 = element->execute(exec);
     3149  KJS_CHECKEXCEPTION
     3150
     3151  // The spec says to return c2 here, but it seems that mozilla returns c1 if
     3152  // c2 doesn't have a value
     3153  if (c2.complType() == Normal && c2.value().isNull())
     3154    return c1;
     3155  else
     3156    return c2;
    14393157}
    14403158
    14413159// ECMA 14
    1442 void SourceElementsNode::processFuncDecl()
     3160void SourceElementsNode::processFuncDecl(ExecState *exec)
    14433161{
    14443162  if (elements)
    1445     elements->processFuncDecl();
    1446 
    1447   element->processFuncDecl();
    1448 }
    1449 
    1450 void SourceElementsNode::deleteStatements()
    1451 {
    1452   element->deleteStatements();
    1453 
     3163    elements->processFuncDecl(exec);
     3164
     3165  element->processFuncDecl(exec);
     3166}
     3167
     3168void SourceElementsNode::processVarDecls(ExecState *exec)
     3169{
    14543170  if (elements)
    1455     elements->deleteStatements();
    1456 }
    1457 
    1458 // ECMA 14
    1459 Completion SourceElementNode::execute()
    1460 {
    1461   if (statement)
    1462     return statement->execute();
    1463 
    1464   return Completion(Normal);
    1465 }
    1466 
    1467 // ECMA 14
    1468 void SourceElementNode::processFuncDecl()
    1469 {
    1470   if (function)
    1471     function->processFuncDecl();
    1472 }
    1473 
    1474 void SourceElementNode::deleteStatements()
    1475 {
    1476   delete statement;
    1477 }
    1478 
    1479 ArgumentListNode::ArgumentListNode(Node *e) : list(0L), expr(e) {}
    1480 
    1481 VarDeclNode::VarDeclNode(const UString *id, AssignExprNode *in)
    1482     : ident(*id), init(in) { }
    1483 
    1484 ArgumentListNode::ArgumentListNode(ArgumentListNode *l, Node *e) :
    1485     list(l), expr(e) {}
    1486 
    1487 ArgumentsNode::ArgumentsNode(ArgumentListNode *l) : list(l) {}
     3171    elements->processVarDecls(exec);
     3172
     3173  element->processVarDecls(exec);
     3174}
     3175
     3176ProgramNode::ProgramNode(SourceElementsNode *s): FunctionBodyNode(s) {
     3177    //fprintf(stderr,"ProgramNode::ProgramNode %p\n",this);
     3178}
     3179
     3180ProgramNode::~ProgramNode() {
     3181    //fprintf(stderr,"ProgramNode::~ProgramNode %p\n",this);
     3182}
  • trunk/JavaScriptCore/kjs/nodes.h

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    34 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1719 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1820 *  Boston, MA 02111-1307, USA.
     21 *
     22 *  $Id$
    1923 */
    2024
     
    2327
    2428#include "internal.h"
    25 #include "ustring.h"
    26 #include "object.h"
    27 #include "types.h"
    28 #include "debugger.h"
     29//#include "debugger.h"
     30#ifndef NDEBUG
     31#ifndef __osf__
     32#include <list>
     33#endif
     34#endif
    2935
    3036namespace KJS {
    3137
    32   class KJSO;
    3338  class RegExp;
    3439  class SourceElementsNode;
     
    7075    Node();
    7176    virtual ~Node();
    72     virtual KJSO evaluate() = 0;
     77    virtual Value evaluate(ExecState *exec) = 0;
     78    virtual void processVarDecls(ExecState */*exec*/) {}
    7379    int lineNo() const { return line; }
    74     static Node *firstNode() { return first; }
    75     static void setFirstNode(Node *n) { first = n; }
    76     static void deleteAllNodes();
    77 #ifdef KJS_DEBUGGER
    78     static bool setBreakpoint(Node *firstNode, int id, int line, bool set);
    79     virtual bool setBreakpoint(int, int, bool) { return false; }
     80
     81  public:
     82    // reference counting mechanism
     83    virtual void ref() { refcount++; }
     84#ifdef KJS_DEBUG_MEM
     85    virtual bool deref() { assert( refcount > 0 ); return (!--refcount); }
     86#else
     87    virtual bool deref() { return (!--refcount); }
     88#endif
     89
     90
     91#ifdef KJS_DEBUG_MEM
     92    static void finalCheck();
    8093#endif
    8194  protected:
    82     KJSO throwError(ErrorType e, const char *msg);
    83   private:
    84     // disallow assignment and copy-construction
    85     Node(const Node &);
     95    Value throwError(ExecState *exec, ErrorType e, const char *msg);
     96    int line;
     97    unsigned int refcount;
     98    virtual int sourceId() const { return -1; }
     99  private:
     100#ifdef KJS_DEBUG_MEM
     101    // List of all nodes, for debugging purposes. Don't remove!
     102    static std::list<Node *> s_nodes;
     103#endif
     104    // disallow assignment
    86105    Node& operator=(const Node&);
    87     int line;
    88     static  int nodeCount;
    89     static Node *first;
    90     Node *next, *prev;
     106    Node(const Node &other);
    91107  };
    92108
    93109  class StatementNode : public Node {
    94110  public:
    95 #ifdef KJS_DEBUGGER
    96     StatementNode() : l0(-1), l1(-1), sid(-1), breakPoint(false) { }
    97     void setLoc(int line0, int line1);
     111    StatementNode();
     112    ~StatementNode();
     113    void setLoc(int line0, int line1, int sourceId);
    98114    int firstLine() const { return l0; }
    99115    int lastLine() const { return l1; }
    100116    int sourceId() const { return sid; }
    101     bool hitStatement();
    102     bool abortStatement();
    103     virtual bool setBreakpoint(int id, int line, bool set);
    104 #endif
    105     virtual Completion execute() = 0;
     117    bool hitStatement(ExecState *exec);
     118    bool abortStatement(ExecState *exec);
     119    virtual Completion execute(ExecState *exec) = 0;
    106120    void pushLabel(const UString *id) {
    107121      if (id) ls.push(*id);
     
    110124    LabelStack ls;
    111125  private:
    112     KJSO evaluate() { return Undefined(); }
    113 #ifdef KJS_DEBUGGER
     126    Value evaluate(ExecState */*exec*/) { return Undefined(); }
    114127    int l0, l1;
    115128    int sid;
    116129    bool breakPoint;
    117 #endif
    118130  };
    119131
    120132  class NullNode : public Node {
    121133  public:
    122     KJSO evaluate();
     134    NullNode() {}
     135    Value evaluate(ExecState *exec);
    123136  };
    124137
     
    126139  public:
    127140    BooleanNode(bool v) : value(v) {}
    128     KJSO evaluate();
     141    Value evaluate(ExecState *exec);
    129142  private:
    130143    bool value;
     
    134147  public:
    135148    NumberNode(double v) : value(v) { }
    136     KJSO evaluate();
     149    Value evaluate(ExecState *exec);
    137150  private:
    138151    double value;
     
    142155  public:
    143156    StringNode(const UString *v) { value = *v; }
    144     KJSO evaluate();
     157    Value evaluate(ExecState *exec);
    145158  private:
    146159    UString value;
     
    151164    RegExpNode(const UString &p, const UString &f)
    152165      : pattern(p), flags(f) { }
    153     KJSO evaluate();
     166    Value evaluate(ExecState *exec);
    154167  private:
    155168    UString pattern, flags;
     
    158171  class ThisNode : public Node {
    159172  public:
    160     KJSO evaluate();
     173    ThisNode() {}
     174    Value evaluate(ExecState *exec);
    161175  };
    162176
     
    164178  public:
    165179    ResolveNode(const UString *s) : ident(*s) { }
    166     KJSO evaluate();
     180    Value evaluate(ExecState *exec);
    167181  private:
    168182    UString ident;
     
    172186  public:
    173187    GroupNode(Node *g) : group(g) { }
    174     KJSO evaluate();
     188    virtual void ref();
     189    virtual bool deref();
     190    virtual ~GroupNode();
     191    Value evaluate(ExecState *exec);
    175192  private:
    176193    Node *group;
     
    180197  public:
    181198    ElisionNode(ElisionNode *e) : elision(e) { }
    182     KJSO evaluate();
     199    virtual void ref();
     200    virtual bool deref();
     201    virtual ~ElisionNode();
     202    Value evaluate(ExecState *exec);
    183203  private:
    184204    ElisionNode *elision;
     
    190210    ElementNode(ElementNode *l, ElisionNode *e, Node *n)
    191211      : list(l), elision(e), node(n) { }
    192     KJSO evaluate();
     212    virtual void ref();
     213    virtual bool deref();
     214    virtual ~ElementNode();
     215    Value evaluate(ExecState *exec);
    193216  private:
    194217    ElementNode *list;
     
    204227    ArrayNode(ElisionNode *eli, ElementNode *ele)
    205228      : element(ele), elision(eli), opt(true) { }
    206     KJSO evaluate();
     229    virtual void ref();
     230    virtual bool deref();
     231    virtual ~ArrayNode();
     232    Value evaluate(ExecState *exec);
    207233  private:
    208234    ElementNode *element;
     
    214240  public:
    215241    ObjectLiteralNode(Node *l) : list(l) { }
    216     KJSO evaluate();
     242    virtual void ref();
     243    virtual bool deref();
     244    virtual ~ObjectLiteralNode();
     245    Value evaluate(ExecState *exec);
    217246  private:
    218247    Node *list;
     
    223252    PropertyValueNode(Node *n, Node *a, Node *l = 0L)
    224253      : name(n), assign(a), list(l) { }
    225     KJSO evaluate();
     254    virtual void ref();
     255    virtual bool deref();
     256    virtual ~PropertyValueNode();
     257    Value evaluate(ExecState *exec);
    226258  private:
    227259    Node *name, *assign, *list;
     
    232264    PropertyNode(double d) : numeric(d) { }
    233265    PropertyNode(const UString *s) : str(*s) { }
    234     KJSO evaluate();
     266    Value evaluate(ExecState *exec);
    235267  private:
    236268    double numeric;
     
    241273  public:
    242274    AccessorNode1(Node *e1, Node *e2) : expr1(e1), expr2(e2) {}
    243     KJSO evaluate();
     275    virtual void ref();
     276    virtual bool deref();
     277    virtual ~AccessorNode1();
     278    Value evaluate(ExecState *exec);
    244279  private:
    245280    Node *expr1;
     
    250285  public:
    251286    AccessorNode2(Node *e, const UString *s) : expr(e), ident(*s) { }
    252     KJSO evaluate();
     287    virtual void ref();
     288    virtual bool deref();
     289    virtual ~AccessorNode2();
     290    Value evaluate(ExecState *exec);
    253291  private:
    254292    Node *expr;
     
    260298    ArgumentListNode(Node *e);
    261299    ArgumentListNode(ArgumentListNode *l, Node *e);
    262     KJSO evaluate();
    263     List *evaluateList();
     300    virtual void ref();
     301    virtual bool deref();
     302    virtual ~ArgumentListNode();
     303    Value evaluate(ExecState *exec);
     304    List evaluateList(ExecState *exec);
    264305  private:
    265306    ArgumentListNode *list;
     
    270311  public:
    271312    ArgumentsNode(ArgumentListNode *l);
    272     KJSO evaluate();
    273     List *evaluateList();
     313    virtual void ref();
     314    virtual bool deref();
     315    virtual ~ArgumentsNode();
     316    Value evaluate(ExecState *exec);
     317    List evaluateList(ExecState *exec);
    274318  private:
    275319    ArgumentListNode *list;
     
    280324    NewExprNode(Node *e) : expr(e), args(0L) {}
    281325    NewExprNode(Node *e, ArgumentsNode *a) : expr(e), args(a) {}
    282     KJSO evaluate();
     326    virtual void ref();
     327    virtual bool deref();
     328    virtual ~NewExprNode();
     329    Value evaluate(ExecState *exec);
    283330  private:
    284331    Node *expr;
     
    289336  public:
    290337    FunctionCallNode(Node *e, ArgumentsNode *a) : expr(e), args(a) {}
    291     KJSO evaluate();
    292 #ifdef KJS_DEBUGGER
    293     void steppingInto(bool in);
    294     Debugger::Mode previousMode;
    295 #endif
     338    virtual void ref();
     339    virtual bool deref();
     340    virtual ~FunctionCallNode();
     341    Value evaluate(ExecState *exec);
    296342  private:
    297343    Node *expr;
     
    302348  public:
    303349    PostfixNode(Node *e, Operator o) : expr(e), oper(o) {}
    304     KJSO evaluate();
     350    virtual void ref();
     351    virtual bool deref();
     352    virtual ~PostfixNode();
     353    Value evaluate(ExecState *exec);
    305354  private:
    306355    Node *expr;
     
    311360  public:
    312361    DeleteNode(Node *e) : expr(e) {}
    313     KJSO evaluate();
     362    virtual void ref();
     363    virtual bool deref();
     364    virtual ~DeleteNode();
     365    Value evaluate(ExecState *exec);
    314366  private:
    315367    Node *expr;
     
    319371  public:
    320372    VoidNode(Node *e) : expr(e) {}
    321     KJSO evaluate();
     373    virtual void ref();
     374    virtual bool deref();
     375    virtual ~VoidNode();
     376    Value evaluate(ExecState *exec);
    322377  private:
    323378    Node *expr;
     
    327382  public:
    328383    TypeOfNode(Node *e) : expr(e) {}
    329     KJSO evaluate();
     384    virtual void ref();
     385    virtual bool deref();
     386    virtual ~TypeOfNode();
     387    Value evaluate(ExecState *exec);
    330388  private:
    331389    Node *expr;
     
    335393  public:
    336394    PrefixNode(Operator o, Node *e) : oper(o), expr(e) {}
    337     KJSO evaluate();
     395    virtual void ref();
     396    virtual bool deref();
     397    virtual ~PrefixNode();
     398    Value evaluate(ExecState *exec);
    338399  private:
    339400    Operator oper;
     
    344405  public:
    345406    UnaryPlusNode(Node *e) : expr(e) {}
    346     KJSO evaluate();
     407    virtual void ref();
     408    virtual bool deref();
     409    virtual ~UnaryPlusNode();
     410    Value evaluate(ExecState *exec);
    347411  private:
    348412    Node *expr;
     
    352416  public:
    353417    NegateNode(Node *e) : expr(e) {}
    354     KJSO evaluate();
     418    virtual void ref();
     419    virtual bool deref();
     420    virtual ~NegateNode();
     421    Value evaluate(ExecState *exec);
    355422  private:
    356423    Node *expr;
     
    360427  public:
    361428    BitwiseNotNode(Node *e) : expr(e) {}
    362     KJSO evaluate();
     429    virtual void ref();
     430    virtual bool deref();
     431    virtual ~BitwiseNotNode();
     432    Value evaluate(ExecState *exec);
    363433  private:
    364434    Node *expr;
     
    368438  public:
    369439    LogicalNotNode(Node *e) : expr(e) {}
    370     KJSO evaluate();
     440    virtual void ref();
     441    virtual bool deref();
     442    virtual ~LogicalNotNode();
     443    Value evaluate(ExecState *exec);
    371444  private:
    372445    Node *expr;
     
    376449  public:
    377450    MultNode(Node *t1, Node *t2, char op) : term1(t1), term2(t2), oper(op) {}
    378     KJSO evaluate();
     451    virtual void ref();
     452    virtual bool deref();
     453    virtual ~MultNode();
     454    Value evaluate(ExecState *exec);
    379455  private:
    380456    Node *term1, *term2;
     
    385461  public:
    386462    AddNode(Node *t1, Node *t2, char op) : term1(t1), term2(t2), oper(op) {}
    387     KJSO evaluate();
     463    virtual void ref();
     464    virtual bool deref();
     465    virtual ~AddNode();
     466    Value evaluate(ExecState *exec);
    388467  private:
    389468    Node *term1, *term2;
     
    395474    ShiftNode(Node *t1, Operator o, Node *t2)
    396475      : term1(t1), term2(t2), oper(o) {}
    397     KJSO evaluate();
     476    virtual void ref();
     477    virtual bool deref();
     478    virtual ~ShiftNode();
     479    Value evaluate(ExecState *exec);
    398480  private:
    399481    Node *term1, *term2;
     
    405487    RelationalNode(Node *e1, Operator o, Node *e2) :
    406488      expr1(e1), expr2(e2), oper(o) {}
    407     KJSO evaluate();
     489    virtual void ref();
     490    virtual bool deref();
     491    virtual ~RelationalNode();
     492    Value evaluate(ExecState *exec);
    408493  private:
    409494    Node *expr1, *expr2;
     
    415500    EqualNode(Node *e1, Operator o, Node *e2)
    416501      : expr1(e1), expr2(e2), oper(o) {}
    417     KJSO evaluate();
     502    virtual void ref();
     503    virtual bool deref();
     504    virtual ~EqualNode();
     505    Value evaluate(ExecState *exec);
    418506  private:
    419507    Node *expr1, *expr2;
     
    425513    BitOperNode(Node *e1, Operator o, Node *e2) :
    426514      expr1(e1), expr2(e2), oper(o) {}
    427     KJSO evaluate();
     515    virtual void ref();
     516    virtual bool deref();
     517    virtual ~BitOperNode();
     518    Value evaluate(ExecState *exec);
    428519  private:
    429520    Node *expr1, *expr2;
     
    431522  };
    432523
     524  /** expr1 && expr2, expr1 || expr2 */
    433525  class BinaryLogicalNode : public Node {
    434526  public:
    435527    BinaryLogicalNode(Node *e1, Operator o, Node *e2) :
    436528      expr1(e1), expr2(e2), oper(o) {}
    437     KJSO evaluate();
     529    virtual void ref();
     530    virtual bool deref();
     531    virtual ~BinaryLogicalNode();
     532    Value evaluate(ExecState *exec);
    438533  private:
    439534    Node *expr1, *expr2;
     
    441536  };
    442537
     538  /** The ternary operator, "logical ? expr1 : expr2" */
    443539  class ConditionalNode : public Node {
    444540  public:
    445541    ConditionalNode(Node *l, Node *e1, Node *e2) :
    446542      logical(l), expr1(e1), expr2(e2) {}
    447     KJSO evaluate();
     543    virtual void ref();
     544    virtual bool deref();
     545    virtual ~ConditionalNode();
     546    Value evaluate(ExecState *exec);
    448547  private:
    449548    Node *logical, *expr1, *expr2;
     
    453552  public:
    454553    AssignNode(Node *l, Operator o, Node *e) : left(l), oper(o), expr(e) {}
    455     KJSO evaluate();
     554    virtual void ref();
     555    virtual bool deref();
     556    virtual ~AssignNode();
     557    Value evaluate(ExecState *exec);
    456558  private:
    457559    Node *left;
     
    463565  public:
    464566    CommaNode(Node *e1, Node *e2) : expr1(e1), expr2(e2) {}
    465     KJSO evaluate();
     567    virtual void ref();
     568    virtual bool deref();
     569    virtual ~CommaNode();
     570    Value evaluate(ExecState *exec);
    466571  private:
    467572    Node *expr1, *expr2;
     
    472577    StatListNode(StatementNode *s) : statement(s), list(0L) { }
    473578    StatListNode(StatListNode *l, StatementNode *s) : statement(s), list(l) { }
    474     Completion execute();
     579    virtual void ref();
     580    virtual bool deref();
     581    virtual ~StatListNode();
     582    virtual Completion execute(ExecState *exec);
     583    virtual void processVarDecls(ExecState *exec);
    475584  private:
    476585    StatementNode *statement;
     
    481590  public:
    482591    AssignExprNode(Node *e) : expr(e) {}
    483     KJSO evaluate();
     592    virtual void ref();
     593    virtual bool deref();
     594    virtual ~AssignExprNode();
     595    Value evaluate(ExecState *exec);
    484596  private:
    485597    Node *expr;
     
    489601  public:
    490602    VarDeclNode(const UString *id, AssignExprNode *in);
    491     KJSO evaluate();
     603    virtual void ref();
     604    virtual bool deref();
     605    virtual ~VarDeclNode();
     606    Value evaluate(ExecState *exec);
     607    virtual void processVarDecls(ExecState *exec);
    492608  private:
    493609    UString ident;
     
    499615    VarDeclListNode(VarDeclNode *v) : list(0L), var(v) {}
    500616    VarDeclListNode(Node *l, VarDeclNode *v) : list(l), var(v) {}
    501     KJSO evaluate();
     617    virtual void ref();
     618    virtual bool deref();
     619    virtual ~VarDeclListNode();
     620    Value evaluate(ExecState *exec);
     621    virtual void processVarDecls(ExecState *exec);
    502622  private:
    503623    Node *list;
     
    508628  public:
    509629    VarStatementNode(VarDeclListNode *l) : list(l) {}
    510     Completion execute();
     630    virtual void ref();
     631    virtual bool deref();
     632    virtual ~VarStatementNode();
     633    virtual Completion execute(ExecState *exec);
     634    virtual void processVarDecls(ExecState *exec);
    511635  private:
    512636    VarDeclListNode *list;
     
    515639  class BlockNode : public StatementNode {
    516640  public:
    517     BlockNode(StatListNode *s) : statlist(s) {}
    518     Completion execute();
    519   private:
    520     StatListNode *statlist;
     641    BlockNode(SourceElementsNode *s) : source(s) {}
     642    virtual void ref();
     643    virtual bool deref();
     644    virtual ~BlockNode();
     645    virtual Completion execute(ExecState *exec);
     646    virtual void processVarDecls(ExecState *exec);
     647  private:
     648    SourceElementsNode *source;
    521649  };
    522650
     
    524652  public:
    525653    EmptyStatementNode() { } // debug
    526     Completion execute();
     654    virtual Completion execute(ExecState *exec);
    527655  };
    528656
     
    530658  public:
    531659    ExprStatementNode(Node *e) : expr(e) { }
    532     Completion execute();
     660    virtual void ref();
     661    virtual bool deref();
     662    virtual ~ExprStatementNode();
     663    virtual Completion execute(ExecState *exec);
    533664  private:
    534665    Node *expr;
     
    539670    IfNode(Node *e, StatementNode *s1, StatementNode *s2)
    540671      : expr(e), statement1(s1), statement2(s2) {}
    541     Completion execute();
     672    virtual void ref();
     673    virtual bool deref();
     674    virtual ~IfNode();
     675    virtual Completion execute(ExecState *exec);
     676    virtual void processVarDecls(ExecState *exec);
    542677  private:
    543678    Node *expr;
     
    548683  public:
    549684    DoWhileNode(StatementNode *s, Node *e) : statement(s), expr(e) {}
    550     Completion execute();
     685    virtual void ref();
     686    virtual bool deref();
     687    virtual ~DoWhileNode();
     688    virtual Completion execute(ExecState *exec);
     689    virtual void processVarDecls(ExecState *exec);
    551690  private:
    552691    StatementNode *statement;
     
    557696  public:
    558697    WhileNode(Node *e, StatementNode *s) : expr(e), statement(s) {}
    559     Completion execute();
     698    virtual void ref();
     699    virtual bool deref();
     700    virtual ~WhileNode();
     701    virtual Completion execute(ExecState *exec);
     702    virtual void processVarDecls(ExecState *exec);
    560703  private:
    561704    Node *expr;
     
    566709  public:
    567710    ForNode(Node *e1, Node *e2, Node *e3, StatementNode *s) :
    568       expr1(e1), expr2(e2), expr3(e3), stat(s) {}
    569     Completion execute();
     711      expr1(e1), expr2(e2), expr3(e3), statement(s) {}
     712    virtual void ref();
     713    virtual bool deref();
     714    virtual ~ForNode();
     715    virtual Completion execute(ExecState *exec);
     716    virtual void processVarDecls(ExecState *exec);
    570717  private:
    571718    Node *expr1, *expr2, *expr3;
    572     StatementNode *stat;
     719    StatementNode *statement;
    573720  };
    574721
    575722  class ForInNode : public StatementNode {
    576723  public:
    577     ForInNode(Node *l, Node *e, StatementNode *s) :
    578       init(0L), lexpr(l), expr(e), stat(s) {}
    579     ForInNode(const UString *i, AssignExprNode *in, Node *e, StatementNode *s)
    580       : ident(*i), init(in), lexpr(0L), expr(e), stat(s) {}
    581     Completion execute();
     724    ForInNode(Node *l, Node *e, StatementNode *s);
     725    ForInNode(const UString *i, AssignExprNode *in, Node *e, StatementNode *s);
     726    virtual void ref();
     727    virtual bool deref();
     728    virtual ~ForInNode();
     729    virtual Completion execute(ExecState *exec);
     730    virtual void processVarDecls(ExecState *exec);
    582731  private:
    583732    UString ident;
    584733    AssignExprNode *init;
    585734    Node *lexpr, *expr;
    586     StatementNode *stat;
     735    VarDeclNode *varDecl;
     736    StatementNode *statement;
    587737  };
    588738
     
    591741    ContinueNode() { }
    592742    ContinueNode(const UString *i) : ident(*i) { }
    593     Completion execute();
     743    virtual Completion execute(ExecState *exec);
    594744  private:
    595745    UString ident;
     
    600750    BreakNode() { }
    601751    BreakNode(const UString *i) : ident(*i) { }
    602     Completion execute();
     752    virtual Completion execute(ExecState *exec);
    603753  private:
    604754    UString ident;
     
    608758  public:
    609759    ReturnNode(Node *v) : value(v) {}
    610     Completion execute();
     760    virtual void ref();
     761    virtual bool deref();
     762    virtual ~ReturnNode();
     763    virtual Completion execute(ExecState *exec);
    611764  private:
    612765    Node *value;
     
    615768  class WithNode : public StatementNode {
    616769  public:
    617     WithNode(Node *e, StatementNode *s) : expr(e), stat(s) {}
    618     Completion execute();
    619   private:
    620     Node *expr;
    621     StatementNode *stat;
     770    WithNode(Node *e, StatementNode *s) : expr(e), statement(s) {}
     771    virtual void ref();
     772    virtual bool deref();
     773    virtual ~WithNode();
     774    virtual Completion execute(ExecState *exec);
     775    virtual void processVarDecls(ExecState *exec);
     776  private:
     777    Node *expr;
     778    StatementNode *statement;
    622779  };
    623780
     
    625782  public:
    626783    CaseClauseNode(Node *e, StatListNode *l) : expr(e), list(l) { }
    627     KJSO evaluate();
    628     Completion evalStatements();
     784    virtual void ref();
     785    virtual bool deref();
     786    virtual ~CaseClauseNode();
     787    Value evaluate(ExecState *exec);
     788    Completion evalStatements(ExecState *exec);
     789    virtual void processVarDecls(ExecState *exec);
    629790  private:
    630791    Node *expr;
     
    635796  public:
    636797    ClauseListNode(CaseClauseNode *c) : cl(c), nx(0L) { }
     798    virtual void ref();
     799    virtual bool deref();
     800    virtual ~ClauseListNode();
    637801    ClauseListNode* append(CaseClauseNode *c);
    638     KJSO evaluate() { /* should never be called */ return KJSO(); }
     802    Value evaluate(ExecState *exec);
    639803    CaseClauseNode *clause() const { return cl; }
    640804    ClauseListNode *next() const { return nx; }
     805    virtual void processVarDecls(ExecState *exec);
    641806  private:
    642807    CaseClauseNode *cl;
     
    648813    CaseBlockNode(ClauseListNode *l1, CaseClauseNode *d, ClauseListNode *l2)
    649814      : list1(l1), def(d), list2(l2) { }
    650     KJSO evaluate() { /* should never be called */ return KJSO(); }
    651     Completion evalBlock(const KJSO& input);
     815    virtual void ref();
     816    virtual bool deref();
     817    virtual ~CaseBlockNode();
     818    Value evaluate(ExecState *exec);
     819    Completion evalBlock(ExecState *exec, const Value& input);
     820    virtual void processVarDecls(ExecState *exec);
    652821  private:
    653822    ClauseListNode *list1;
     
    659828  public:
    660829    SwitchNode(Node *e, CaseBlockNode *b) : expr(e), block(b) { }
    661     Completion execute();
     830    virtual void ref();
     831    virtual bool deref();
     832    virtual ~SwitchNode();
     833    virtual Completion execute(ExecState *exec);
     834    virtual void processVarDecls(ExecState *exec);
    662835  private:
    663836    Node *expr;
     
    667840  class LabelNode : public StatementNode {
    668841  public:
    669     LabelNode(const UString *l, StatementNode *s) : label(*l), stat(s) { }
    670     Completion execute();
     842    LabelNode(const UString *l, StatementNode *s) : label(*l), statement(s) { }
     843    virtual void ref();
     844    virtual bool deref();
     845    virtual ~LabelNode();
     846    virtual Completion execute(ExecState *exec);
     847    virtual void processVarDecls(ExecState *exec);
    671848  private:
    672849    UString label;
    673     StatementNode *stat;
     850    StatementNode *statement;
    674851  };
    675852
     
    677854  public:
    678855    ThrowNode(Node *e) : expr(e) {}
    679     Completion execute();
     856    virtual void ref();
     857    virtual bool deref();
     858    virtual ~ThrowNode();
     859    virtual Completion execute(ExecState *exec);
    680860  private:
    681861    Node *expr;
     
    684864  class CatchNode : public StatementNode {
    685865  public:
    686     CatchNode(UString *i, StatementNode *b) : ident(*i), block(b) {}
    687     Completion execute();
    688     Completion execute(const KJSO &arg);
     866    CatchNode(const UString *i, StatementNode *b) : ident(*i), block(b) {}
     867    virtual void ref();
     868    virtual bool deref();
     869    virtual ~CatchNode();
     870    virtual Completion execute(ExecState *exec);
     871    Completion execute(ExecState *exec, const Value &arg);
     872    virtual void processVarDecls(ExecState *exec);
    689873  private:
    690874    UString ident;
     
    695879  public:
    696880    FinallyNode(StatementNode *b) : block(b) {}
    697     Completion execute();
     881    virtual void ref();
     882    virtual bool deref();
     883    virtual ~FinallyNode();
     884    virtual Completion execute(ExecState *exec);
     885    virtual void processVarDecls(ExecState *exec);
    698886  private:
    699887    StatementNode *block;
     
    704892    TryNode(StatementNode *b, Node *c = 0L, Node *f = 0L)
    705893      : block(b), _catch((CatchNode*)c), _final((FinallyNode*)f) {}
    706     Completion execute();
     894    virtual void ref();
     895    virtual bool deref();
     896    virtual ~TryNode();
     897    virtual Completion execute(ExecState *exec);
     898    virtual void processVarDecls(ExecState *exec);
    707899  private:
    708900    StatementNode *block;
     
    715907    ParameterNode(const UString *i) : id(*i), next(0L) { }
    716908    ParameterNode *append(const UString *i);
    717     KJSO evaluate();
     909    virtual void ref();
     910    virtual bool deref();
     911    virtual ~ParameterNode();
     912    Value evaluate(ExecState *exec);
    718913    UString ident() { return id; }
    719914    ParameterNode *nextParam() { return next; }
     
    726921  class FunctionBodyNode : public StatementNode {
    727922  public:
    728       FunctionBodyNode(SourceElementsNode *s);
    729       Completion execute();
     923    FunctionBodyNode(SourceElementsNode *s);
     924    virtual void ref();
     925    virtual bool deref();
     926    virtual ~FunctionBodyNode();
     927    Completion execute(ExecState *exec);
     928    virtual void processFuncDecl(ExecState *exec);
     929    virtual void processVarDecls(ExecState *exec);
    730930  protected:
    731       SourceElementsNode *source;
     931    SourceElementsNode *source;
    732932  };
    733933
     
    736936    FuncDeclNode(const UString *i, ParameterNode *p, FunctionBodyNode *b)
    737937      : ident(*i), param(p), body(b) { }
    738     Completion execute() { /* empty */ return Completion(); }
    739     void processFuncDecl();
     938    virtual void ref();
     939    virtual bool deref();
     940    virtual ~FuncDeclNode();
     941    Completion execute(ExecState */*exec*/)
     942      { /* empty */ return Completion(); }
     943    void processFuncDecl(ExecState *exec);
    740944  private:
    741945    UString ident;
     
    748952    FuncExprNode(ParameterNode *p, FunctionBodyNode *b)
    749953        : param(p), body(b) { }
    750     KJSO evaluate();
     954    virtual void ref();
     955    virtual bool deref();
     956    virtual ~FuncExprNode();
     957    Value evaluate(ExecState *exec);
    751958  private:
    752959    ParameterNode *param;
     
    758965    SourceElementNode(StatementNode *s) { statement = s; function = 0L; }
    759966    SourceElementNode(FuncDeclNode *f) { function = f; statement = 0L;}
    760     Completion execute();
    761     virtual void processFuncDecl();
    762     void deleteStatements();
     967    virtual void ref();
     968    virtual bool deref();
     969    virtual ~SourceElementNode();
     970    Completion execute(ExecState *exec);
     971    virtual void processFuncDecl(ExecState *exec);
     972    virtual void processVarDecls(ExecState *exec);
    763973  private:
    764974    StatementNode *statement;
     
    766976  };
    767977
     978  // A linked list of source element nodes
    768979  class SourceElementsNode : public StatementNode {
    769980  public:
     
    771982    SourceElementsNode(SourceElementsNode *s1, SourceElementNode *s2)
    772983      { elements = s1; element = s2; }
    773     Completion execute();
    774     virtual void processFuncDecl();
    775     void deleteStatements();
    776   private:
    777     SourceElementNode *element;
    778     SourceElementsNode *elements;
     984    virtual void ref();
     985    virtual bool deref();
     986    virtual ~SourceElementsNode();
     987    Completion execute(ExecState *exec);
     988    virtual void processFuncDecl(ExecState *exec);
     989    virtual void processVarDecls(ExecState *exec);
     990  private:
     991    SourceElementNode *element; // 'this' element
     992    SourceElementsNode *elements; // pointer to next
    779993  };
    780994
    781995  class ProgramNode : public FunctionBodyNode {
    782996  public:
    783     ProgramNode(SourceElementsNode *s) : FunctionBodyNode(s) { }
    784     void deleteGlobalStatements();
     997    ProgramNode(SourceElementsNode *s);
     998    ~ProgramNode();
     999  private:
     1000    // Disallow copy
     1001    ProgramNode(const ProgramNode &other);
    7851002  };
    7861003
  • trunk/JavaScriptCore/kjs/number_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 *
     20 *  $Id$
    1821 */
    1922
    20 #include "kjs.h"
     23#include "value.h"
     24#include "object.h"
     25#include "types.h"
     26#include "interpreter.h"
    2127#include "operations.h"
    2228#include "number_object.h"
     29#include "error_object.h"
     30
     31#include "number_object.lut.h"
    2332
    2433using namespace KJS;
    2534
    26 NumberObject::NumberObject(const Object& funcProto, const Object &numProto)
    27   : ConstructorImp(funcProto, 1)
     35
     36// ------------------------------ NumberInstanceImp ----------------------------
     37
     38const ClassInfo NumberInstanceImp::info = {"Number", 0, 0, 0};
     39
     40NumberInstanceImp::NumberInstanceImp(const Object &proto)
     41  : ObjectImp(proto)
    2842{
    29   // Number.Prototype
    30   setPrototypeProperty(numProto);
     43}
     44// ------------------------------ NumberPrototypeImp ---------------------------
     45
     46// ECMA 15.7.4
     47
     48NumberPrototypeImp::NumberPrototypeImp(ExecState *exec,
     49                                       ObjectPrototypeImp *objProto,
     50                                       FunctionPrototypeImp *funcProto)
     51  : NumberInstanceImp(Object(objProto))
     52{
     53  Value protect(this);
     54  setInternalValue(Number(0));
     55
     56  // The constructor will be added later, after NumberObjectImp has been constructed
     57
     58  put(exec,"toString",       Object(new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToString,       1)), DontEnum);
     59  put(exec,"toLocaleString", Object(new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToLocaleString, 0)), DontEnum);
     60  put(exec,"valueOf",        Object(new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ValueOf,        0)), DontEnum);
    3161}
    3262
    33 // ECMA 15.7.3
    34 KJSO NumberObject::get(const UString &p) const
     63
     64// ------------------------------ NumberProtoFuncImp ---------------------------
     65
     66NumberProtoFuncImp::NumberProtoFuncImp(ExecState *exec,
     67                                       FunctionPrototypeImp *funcProto, int i, int len)
     68  : InternalFunctionImp(funcProto), id(i)
    3569{
    36   double d;
    37 
    38   if (p == "NaN")
    39     d = NaN;
    40   else if (p == "NEGATIVE_INFINITY")
    41     d = -Inf;
    42   else if (p == "POSITIVE_INFINITY")
    43     d = Inf;
    44   else
    45     return Imp::get(p);
    46 
    47   return Number(d);
     70  Value protect(this);
     71  put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
    4872}
    4973
     74
     75bool NumberProtoFuncImp::implementsCall() const
     76{
     77  return true;
     78}
     79
     80// ECMA 15.7.4.2 - 15.7.4.7
     81Value NumberProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &/*args*/)
     82{
     83  Value result;
     84
     85  // no generic function. "this" has to be a Number object
     86  if (!thisObj.inherits(&NumberInstanceImp::info)) {
     87    Object err = Error::create(exec,TypeError);
     88    exec->setException(err);
     89    return err;
     90  }
     91
     92  // execute "toString()" or "valueOf()", respectively
     93  Value v = thisObj.internalValue();
     94  switch (id) {
     95  case ToString:
     96  case ToLocaleString: /* TODO */
     97    result = String(v.toString(exec));
     98    break;
     99  case ValueOf:
     100    result = Number(v.toNumber(exec));
     101    break;
     102  }
     103
     104  return result;
     105}
     106
     107// ------------------------------ NumberObjectImp ------------------------------
     108
     109const ClassInfo NumberObjectImp::info = {"Number", &InternalFunctionImp::info, &numberTable, 0};
     110//const ClassInfo NumberObjectImp::info = {"Number", 0, &numberTable, 0};
     111
     112/* Source for number_object.lut.h
     113@begin numberTable 5
     114  NaN                   NumberObjectImp::NaNValue       DontEnum
     115  NEGATIVE_INFINITY     NumberObjectImp::NegInfinity    DontEnum
     116  POSITIVE_INFINITY     NumberObjectImp::PosInfinity    DontEnum
     117  MAX_VALUE             NumberObjectImp::MaxValue       DontEnum
     118  MIN_VALUE             NumberObjectImp::MinValue       DontEnum
     119@end
     120*/
     121NumberObjectImp::NumberObjectImp(ExecState *exec,
     122                                 FunctionPrototypeImp *funcProto,
     123                                 NumberPrototypeImp *numberProto)
     124  : InternalFunctionImp(funcProto)
     125{
     126  Value protect(this);
     127  // Number.Prototype
     128  put(exec,"prototype", Value(numberProto),DontEnum|DontDelete|ReadOnly);
     129
     130  // no. of arguments for constructor
     131  put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum);
     132}
     133
     134Value NumberObjectImp::get(ExecState *exec, const UString &propertyName) const
     135{
     136  return lookupGetValue<NumberObjectImp, InternalFunctionImp>( exec, propertyName, &numberTable, this );
     137}
     138
     139Value NumberObjectImp::getValueProperty(ExecState *, int token) const
     140{
     141  // ECMA 15.7.3
     142  switch(token) {
     143  case NaNValue:
     144    return Number(NaN);
     145  case NegInfinity:
     146    return Number(-Inf);
     147  case PosInfinity:
     148    return Number(Inf);
     149  case MaxValue:
     150    return Number(1.7976931348623157E+308);
     151  case MinValue:
     152    return Number(5E-324);
     153  }
     154  return Null();
     155}
     156
     157bool NumberObjectImp::implementsConstruct() const
     158{
     159  return true;
     160}
     161
     162
    50163// ECMA 15.7.1
    51 Completion NumberObject::execute(const List &args)
     164Object NumberObjectImp::construct(ExecState *exec, const List &args)
    52165{
     166  Object proto = exec->interpreter()->builtinNumberPrototype();
     167  Object obj(new NumberInstanceImp(proto));
     168
    53169  Number n;
    54170  if (args.isEmpty())
    55171    n = Number(0);
    56172  else
    57     n = args[0].toNumber();
     173    n = args[0].toNumber(exec);
    58174
    59   return Completion(ReturnValue, n);
     175  obj.setInternalValue(n);
     176
     177  return obj;
     178}
     179
     180bool NumberObjectImp::implementsCall() const
     181{
     182  return true;
    60183}
    61184
    62185// ECMA 15.7.2
    63 Object NumberObject::construct(const List &args)
     186Value NumberObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
    64187{
    65   Number n;
    66188  if (args.isEmpty())
    67     n = Number(0);
     189    return Number(0);
    68190  else
    69     n = args[0].toNumber();
    70 
    71   return Object::create(NumberClass, n);
     191    return Number(args[0].toNumber(exec));
    72192}
    73 
    74 class NumberProtoFunc : public InternalFunctionImp {
    75 public:
    76   NumberProtoFunc(int i) : id (i) { }
    77   Completion execute(const List &);
    78   enum { ToString, ToLocaleString, ValueOf };
    79 private:
    80   int id;
    81 };
    82 
    83 // ECMA 15.7.4.2 - 15.7.4.7
    84 Completion NumberProtoFunc::execute(const List &)
    85 {
    86   KJSO result;
    87 
    88   Object thisObj = Object::dynamicCast(thisValue());
    89 
    90   // no generic function. "this" has to be a Number object
    91   if (thisObj.isNull() || thisObj.getClass() != NumberClass) {
    92     result = Error::create(TypeError);
    93     return Completion(ReturnValue, result);
    94   }
    95 
    96   // execute "toString()" or "valueOf()", respectively
    97   KJSO v = thisObj.internalValue();
    98   switch (id) {
    99   case ToString:
    100   case ToLocaleString: /* TODO */
    101     result = v.toString();
    102     break;
    103   case ValueOf:
    104     result = v.toNumber();
    105     break;
    106   }
    107 
    108   return Completion(ReturnValue, result);
    109 }
    110 
    111 // ECMA 15.7.4
    112 NumberPrototype::NumberPrototype(const Object& proto)
    113   : ObjectImp(NumberClass, Number(0), proto)
    114 {
    115   // The constructor will be added later in NumberObject's constructor
    116 }
    117 
    118 KJSO NumberPrototype::get(const UString &p) const
    119 {
    120   int t;
    121   if (p == "toString")
    122     t = NumberProtoFunc::ToString;
    123   else if (p == "toLocaleString")
    124     t = NumberProtoFunc::ToLocaleString;
    125   else if (p == "valueOf")
    126     t = NumberProtoFunc::ValueOf;
    127   else
    128     return Imp::get(p);
    129 
    130   return Function(new NumberProtoFunc(t));
    131 }
  • trunk/JavaScriptCore/kjs/number_object.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2124#define _NUMBER_OBJECT_H_
    2225
    23 #include "object.h"
    24 #include "function.h"
     26#include "internal.h"
     27#include "function_object.h"
    2528
    2629namespace KJS {
    2730
    28   class NumberObject : public ConstructorImp {
     31  class NumberInstanceImp : public ObjectImp {
    2932  public:
    30     NumberObject(const Object& funcProto, const Object &numProto);
    31     virtual KJSO get(const UString &p) const;
     33    NumberInstanceImp(const Object &proto);
     34
     35    virtual const ClassInfo *classInfo() const { return &info; }
     36    static const ClassInfo info;
     37  };
     38
     39  /**
     40   * @internal
     41   *
     42   * The initial value of Number.prototype (and thus all objects created
     43   * with the Number constructor
     44   */
     45  class NumberPrototypeImp : public NumberInstanceImp {
     46  public:
     47    NumberPrototypeImp(ExecState *exec,
     48                       ObjectPrototypeImp *objProto,
     49                       FunctionPrototypeImp *funcProto);
     50  };
     51
     52  /**
     53   * @internal
     54   *
     55   * Class to implement all methods that are properties of the
     56   * Number.prototype object
     57   */
     58  class NumberProtoFuncImp : public InternalFunctionImp {
     59  public:
     60    NumberProtoFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto,
     61                       int i, int len);
     62
     63    virtual bool implementsCall() const;
     64    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     65
     66    enum { ToString, ToLocaleString, ValueOf };
     67  private:
     68    int id;
     69  };
     70
     71  /**
     72   * @internal
     73   *
     74   * The initial value of the the global variable's "Number" property
     75   */
     76  class NumberObjectImp : public InternalFunctionImp {
     77  public:
     78    NumberObjectImp(ExecState *exec,
     79                    FunctionPrototypeImp *funcProto,
     80                    NumberPrototypeImp *numberProto);
     81
     82    virtual bool implementsConstruct() const;
     83    virtual Object construct(ExecState *exec, const List &args);
     84
     85    virtual bool implementsCall() const;
     86    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     87
     88    Value get(ExecState *exec, const UString &p) const;
     89    Value getValueProperty(ExecState *exec, int token) const;
     90    virtual const ClassInfo *classInfo() const { return &info; }
     91    static const ClassInfo info;
     92    enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue };
     93
    3294    Completion execute(const List &);
    3395    Object construct(const List &);
    34   };
    35 
    36   class NumberPrototype : public ObjectImp {
    37   public:
    38     NumberPrototype(const Object& proto);
    39     virtual KJSO get(const UString &p) const;
    4096  };
    4197
  • trunk/JavaScriptCore/kjs/object.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    3  *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     4 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1719 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1820 *  Boston, MA 02111-1307, USA.
     21 *
     22 *  $Id$
    1923 */
    2024
     25#include "value.h"
    2126#include "object.h"
    22 
    23 #ifdef HAVE_CONFIG_H
    24 #include <config.h>
    25 #endif
     27#include "types.h"
     28#include "interpreter.h"
     29#include "lookup.h"
     30
     31#include <assert.h>
     32#include <math.h>
    2633#include <stdio.h>
    27 #include <string.h>
    28 #include <math.h>
    29 
    30 #include "kjs.h"
    31 #include "types.h"
     34
    3235#include "internal.h"
     36#include "collector.h"
    3337#include "operations.h"
    34 #include "collector.h"
    3538#include "error_object.h"
    36 
    37 namespace KJS {
    38 
    39 #ifdef WORDS_BIGENDIAN
    40   unsigned char NaN_Bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
    41   unsigned char Inf_Bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
    42 #elif defined(arm)
    43   unsigned char NaN_Bytes[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 };
    44   unsigned char Inf_Bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 };
    45 #else
    46   unsigned char NaN_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
    47   unsigned char Inf_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
    48 #endif
    49 
    50   const double NaN = *(const double*) NaN_Bytes;
    51   const double Inf = *(const double*) Inf_Bytes;
    52   const double D16 = 65536.0;
    53   const double D31 = 2147483648.0;      /* TODO: remove in next version */
    54   const double D32 = 4294967296.0;
    55 
    56   // TODO: -0
    57 };
     39#include "nodes.h"
     40#include "property_map.h"
    5841
    5942using namespace KJS;
    6043
    61 const TypeInfo Imp::info = { "Imp", AbstractType, 0, 0, 0 };
    62 
    63 namespace KJS {
    64   struct Property {
    65     UString name;
    66     Imp *object;
    67     int attribute;
    68     Property *next;
    69   };
    70 }
    71 
    72 KJSO::KJSO()
    73   : rep(0)
    74 {
    75 #ifdef KJS_DEBUG_MEM
    76   count++;
    77 #endif
    78 }
    79 
    80 KJSO::KJSO(Imp *d)
    81   : rep(d)
    82 {
    83 #ifdef KJS_DEBUG_MEM
    84   count++;
    85 #endif
    86 
    87   if (rep) {
    88     rep->ref();
    89     rep->setGcAllowed(true);
    90   }
    91 }
    92 
    93 KJSO::KJSO(const KJSO &o)
    94 {
    95 #ifdef KJS_DEBUG_MEM
    96   count++;
    97 #endif
    98 
    99   rep = o.rep;
    100   if (rep) {
    101     rep->ref();
    102     rep->setGcAllowed(true);
    103   }
    104 }
    105 
    106 KJSO& KJSO::operator=(const KJSO &o)
    107 {
    108   if (rep)
    109     rep->deref();
    110   rep = o.rep;
    111   if (rep) {
    112     rep->ref();
    113     rep->setGcAllowed(true);
    114   }
    115 
     44// ------------------------------ Object ---------------------------------------
     45
     46Object::Object() : Value()
     47{
     48}
     49
     50Object::Object(ObjectImp *v) : Value(v)
     51{
     52}
     53
     54Object::Object(const Object &v) : Value(v)
     55{
     56}
     57
     58Object::~Object()
     59{
     60}
     61
     62Object& Object::operator=(const Object &v)
     63{
     64  Value::operator=(v);
    11665  return *this;
    11766}
    11867
    119 KJSO::~KJSO()
    120 {
    121 #ifdef KJS_DEBUG_MEM
    122   count--;
    123 #endif
    124 
    125   if (rep)
    126     rep->deref();
    127 }
    128 
    129 bool KJSO::isDefined() const
    130 {
    131   return !isA(UndefinedType);
    132 }
    133 
    134 bool KJSO::isNull() const
    135 {
    136   return !rep;
    137 }
    138 
    139 Type KJSO::type() const
    140 {
    141 #ifdef KJS_VERBOSE
    142   if (!rep)
    143     fprintf(stderr, "requesting type of null object\n");
    144 #endif
    145 
    146   return rep ? rep->typeInfo()->type : UndefinedType;
    147 }
    148 
    149 bool KJSO::isObject() const
    150 {
    151   return (type() >= ObjectType);
    152 }
    153 
    154 bool KJSO::isA(const char *s) const
    155 {
    156   assert(rep);
    157   const TypeInfo *info = rep->typeInfo();
    158 
    159   if (!s || !info || !info->name)
     68const ClassInfo *Object::classInfo() const
     69{
     70  return static_cast<ObjectImp*>(rep)->classInfo();
     71}
     72
     73bool Object::inherits(const ClassInfo *cinfo) const
     74{
     75  return static_cast<ObjectImp*>(rep)->inherits(cinfo);
     76}
     77
     78Object Object::dynamicCast(const Value &v)
     79{
     80  if (v.isNull() || v.type() != ObjectType)
     81    return Object(0);
     82
     83  return Object(static_cast<ObjectImp*>(v.imp()));
     84}
     85
     86Value Object::prototype() const
     87{
     88  return Value(static_cast<ObjectImp*>(rep)->prototype());
     89}
     90
     91UString Object::className() const
     92{
     93  return static_cast<ObjectImp*>(rep)->className();
     94}
     95
     96Value Object::get(ExecState *exec, const UString &propertyName) const
     97{
     98  return static_cast<ObjectImp*>(rep)->get(exec,propertyName);
     99}
     100
     101void Object::put(ExecState *exec, const UString &propertyName, const Value &value, int attr)
     102{
     103  static_cast<ObjectImp*>(rep)->put(exec,propertyName,value,attr);
     104}
     105
     106bool Object::canPut(ExecState *exec, const UString &propertyName) const
     107{
     108  return static_cast<ObjectImp*>(rep)->canPut(exec,propertyName);
     109}
     110
     111bool Object::hasProperty(ExecState *exec, const UString &propertyName, bool recursive) const
     112{
     113  return static_cast<ObjectImp*>(rep)->hasProperty(exec,propertyName,recursive);
     114}
     115
     116bool Object::deleteProperty(ExecState *exec, const UString &propertyName)
     117{
     118  return static_cast<ObjectImp*>(rep)->deleteProperty(exec,propertyName);
     119}
     120
     121Value Object::defaultValue(ExecState *exec, Type hint) const
     122{
     123  return static_cast<ObjectImp*>(rep)->defaultValue(exec,hint);
     124}
     125
     126bool Object::implementsConstruct() const
     127{
     128  return static_cast<ObjectImp*>(rep)->implementsConstruct();
     129}
     130
     131Object Object::construct(ExecState *exec, const List &args)
     132{
     133  return static_cast<ObjectImp*>(rep)->construct(exec,args);
     134}
     135
     136bool Object::implementsCall() const
     137{
     138  return static_cast<ObjectImp*>(rep)->implementsCall();
     139}
     140
     141Value Object::call(ExecState *exec, Object &thisObj, const List &args)
     142{
     143  return static_cast<ObjectImp*>(rep)->call(exec,thisObj,args);
     144}
     145
     146bool Object::implementsHasInstance() const
     147{
     148  return static_cast<ObjectImp*>(rep)->implementsHasInstance();
     149}
     150
     151Boolean Object::hasInstance(ExecState *exec, const Value &value)
     152{
     153  return static_cast<ObjectImp*>(rep)->hasInstance(exec,value);
     154}
     155
     156const List Object::scope() const
     157{
     158  return static_cast<ObjectImp*>(rep)->scope();
     159}
     160
     161void Object::setScope(const List &s)
     162{
     163  static_cast<ObjectImp*>(rep)->setScope(s);
     164}
     165
     166List Object::propList(ExecState *exec, bool recursive)
     167{
     168  return static_cast<ObjectImp*>(rep)->propList(exec,recursive);
     169}
     170
     171Value Object::internalValue() const
     172{
     173  return static_cast<ObjectImp*>(rep)->internalValue();
     174}
     175
     176void Object::setInternalValue(const Value &v)
     177{
     178  static_cast<ObjectImp*>(rep)->setInternalValue(v);
     179}
     180
     181// ------------------------------ ObjectImp ------------------------------------
     182
     183ObjectImp::ObjectImp(const Object &proto)
     184  : _prop(0), _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L), _scope(0)
     185{
     186  //fprintf(stderr,"ObjectImp::ObjectImp %p %s\n",(void*)this);
     187  _scope = ListImp::empty();
     188  _prop = new PropertyMap();
     189}
     190
     191ObjectImp::ObjectImp()
     192{
     193  //fprintf(stderr,"ObjectImp::ObjectImp %p %s\n",(void*)this);
     194  _prop = 0;
     195  _proto = NullImp::staticNull;
     196  _internalValue = 0L;
     197  _scope = ListImp::empty();
     198  _prop = new PropertyMap();
     199}
     200
     201ObjectImp::~ObjectImp()
     202{
     203  //fprintf(stderr,"ObjectImp::~ObjectImp %p\n",(void*)this);
     204  if (_proto)
     205    _proto->setGcAllowed();
     206  if (_internalValue)
     207    _internalValue->setGcAllowed();
     208  if (_scope)
     209    _scope->setGcAllowed();
     210  delete _prop;
     211}
     212
     213void ObjectImp::mark()
     214{
     215  //fprintf(stderr,"ObjectImp::mark() %p\n",(void*)this);
     216  ValueImp::mark();
     217
     218  if (_proto && !_proto->marked())
     219    _proto->mark();
     220
     221  PropertyMapNode *node = _prop->first();
     222  while (node) {
     223    if (!node->value->marked())
     224      node->value->mark();
     225    node = node->next();
     226  }
     227
     228  if (_internalValue && !_internalValue->marked())
     229    _internalValue->mark();
     230  if (_scope && !_scope->marked())
     231    _scope->mark();
     232}
     233
     234const ClassInfo *ObjectImp::classInfo() const
     235{
     236  return 0;
     237}
     238
     239bool ObjectImp::inherits(const ClassInfo *info) const
     240{
     241  if (!info)
    160242    return false;
    161243
    162   if (info->type == HostType && strcmp(s, "HostObject") == 0)
    163     return true;
    164 
    165   return (strcmp(s, info->name) == 0);
    166 }
    167 
    168 bool KJSO::derivedFrom(const char *s) const
    169 {
    170   if (!s)
     244  const ClassInfo *ci = classInfo();
     245  if (!ci)
    171246    return false;
    172247
    173   assert(rep);
    174   const TypeInfo *info = rep->typeInfo();
    175   while (info) {
    176     if (info->name && strcmp(s, info->name) == 0)
    177       return true;
    178     info = info->base;
    179   }
    180 
    181   return false;
    182 }
    183 
    184 KJSO KJSO::toPrimitive(Type preferred) const
    185 {
    186   assert(rep);
    187   return rep->toPrimitive(preferred);
    188 }
    189 
    190 Boolean KJSO::toBoolean() const
    191 {
    192   assert(rep);
    193   return rep->toBoolean();
    194 }
    195 
    196 Number KJSO::toNumber() const
    197 {
    198   assert(rep);
    199   return rep->toNumber();
    200 }
    201 
    202 // helper function for toInteger, toInt32, toUInt32 and toUInt16
    203 double KJSO::round() const
    204 {
    205   if (isA(UndefinedType)) /* TODO: see below */
    206     return 0.0;
    207   Number n = toNumber();
    208   if (n.value() == 0.0)   /* TODO: -0, NaN, Inf */
    209     return 0.0;
    210   double d = floor(fabs(n.value()));
    211   if (n.value() < 0)
    212     d *= -1;
    213 
    214   return d;
    215 }
    216 
    217 // ECMA 9.4
    218 Number KJSO::toInteger() const
    219 {
    220   return Number(round());
    221 }
    222 
    223 // ECMA 9.5
    224 int KJSO::toInt32() const
    225 {
    226   double d = round();
    227   double d32 = fmod(d, D32);
    228 
    229   if (d32 >= D32 / 2.0)
    230     d32 -= D32;
    231 
    232   return static_cast<int>(d32);
    233 }
    234 
    235 // ECMA 9.6
    236 unsigned int KJSO::toUInt32() const
    237 {
    238   double d = round();
    239   double d32 = fmod(d, D32);
    240 
    241   return static_cast<unsigned int>(d32);
    242 }
    243 
    244 // ECMA 9.7
    245 unsigned short KJSO::toUInt16() const
    246 {
    247   double d = round();
    248   double d16 = fmod(d, D16);
    249 
    250   return static_cast<unsigned short>(d16);
    251 }
    252 
    253 String KJSO::toString() const
    254 {
    255   assert(rep);
    256   return rep->toString();
    257 }
    258 
    259 Object KJSO::toObject() const
    260 {
    261   assert(rep);
    262   if (isObject())
    263     return Object(rep);
    264 
    265   return rep->toObject();
    266 }
    267 
    268 bool KJSO::implementsCall() const
    269 {
    270   return (type() == FunctionType ||
    271           type() == InternalFunctionType ||
    272           type() == ConstructorType ||
    273           type() == DeclaredFunctionType ||
    274           type() == AnonymousFunctionType);
    275 }
    276 
    277 // [[call]]
    278 KJSO KJSO::executeCall(const KJSO &thisV, const List *args)
    279 {
    280   assert(rep);
    281   assert(implementsCall());
    282   return (static_cast<FunctionImp*>(rep))->executeCall(thisV.imp(), args);
    283 }
    284 
    285 KJSO KJSO::executeCall(const KJSO &thisV, const List *args, const List *extraScope) const
    286 {
    287   assert(rep);
    288   assert(implementsCall());
    289   return (static_cast<FunctionImp*>(rep))->executeCall(thisV.imp(), args, extraScope);
    290 }
    291 
    292 void KJSO::setConstructor(KJSO c)
    293 {
    294   put("constructor", c, DontEnum | DontDelete | ReadOnly);
    295 }
    296 
    297 // ECMA 8.7.1
    298 KJSO KJSO::getBase() const
    299 {
    300   if (!isA(ReferenceType))
    301     return Error::create(ReferenceError, I18N_NOOP("Invalid reference base"));
    302 
    303   return ((ReferenceImp*)rep)->getBase();
    304 }
    305 
    306 // ECMA 8.7.2
    307 UString KJSO::getPropertyName() const
    308 {
    309   if (!isA(ReferenceType))
    310     // the spec wants a runtime error here. But getValue() and putValue()
    311     // will catch this case on their own earlier. When returning a Null
    312     // string we should be on the safe side.
    313     return UString();
    314 
    315   return ((ReferenceImp*)rep)->getPropertyName();
    316 }
    317 
    318 // ECMA 8.7.1
    319 KJSO KJSO::getValue() const
    320 {
    321   if (!isA(ReferenceType)) {
    322     return *this;
    323   }
    324   KJSO o = getBase();
    325   if (o.isNull() || o.isA(NullType)) {
    326     UString m = I18N_NOOP("Can't find variable: ") + getPropertyName();
    327     return Error::create(ReferenceError, m.ascii());
    328   }
    329 
    330   return o.get(getPropertyName());
    331 }
    332 
    333 /* TODO: remove in next version */
    334 KJSO KJSO::getValue()
    335 {
    336     return const_cast<const KJSO*>(this)->getValue();
    337 }
    338 
    339 // ECMA 8.7.2
    340 ErrorType KJSO::putValue(const KJSO& v)
    341 {
    342   if (!isA(ReferenceType))
    343     return ReferenceError;
    344 
    345   KJSO o = getBase();
    346   if (o.isA(NullType))
    347     Global::current().put(getPropertyName(), v);
    348   else {
    349     // are we writing into an array ?
    350     if (o.isA(ObjectType) && (o.toObject().getClass() == ArrayClass))
    351       o.putArrayElement(getPropertyName(), v);
     248  while (ci && ci != info)
     249    ci = ci->parentClass;
     250
     251  return (ci == info);
     252}
     253
     254Type ObjectImp::type() const
     255{
     256  return ObjectType;
     257}
     258
     259Value ObjectImp::prototype() const
     260{
     261  return Value(_proto);
     262}
     263
     264void ObjectImp::setPrototype(const Value &proto)
     265{
     266  _proto = proto.imp();
     267}
     268
     269UString ObjectImp::className() const
     270{
     271  const ClassInfo *ci = classInfo();
     272  if ( ci )
     273    return ci->className;
     274  return "Object";
     275}
     276
     277Value ObjectImp::get(ExecState *exec, const UString &propertyName) const
     278{
     279  if (propertyName == "__proto__") {
     280    Object proto = Object::dynamicCast(prototype());
     281    // non-standard netscape extension
     282    if (proto.isNull())
     283      return Null();
    352284    else
    353       o.put(getPropertyName(), v);
    354   }
    355 
    356   return NoError;
    357 }
    358 
    359 void KJSO::setPrototype(const KJSO& p)
    360 {
    361   assert(rep);
    362   rep->setPrototype(p);
    363 }
    364 
    365 void KJSO::setPrototypeProperty(const KJSO& p)
    366 {
    367   assert(rep);
    368   put("prototype", p, DontEnum | DontDelete | ReadOnly);
    369 }
    370 
    371 KJSO KJSO::prototype() const
    372 {
    373   if (rep)
    374     return KJSO(rep->proto);
    375   else
    376     return KJSO();
    377 }
    378 
    379 // ECMA 8.6.2.1
    380 KJSO KJSO::get(const UString &p) const
    381 {
    382   assert(rep);
    383   return rep->get(p);
     285      return proto;
     286  }
     287
     288  ValueImp *imp = getDirect(propertyName);
     289  if ( imp )
     290    return Value(imp);
     291
     292  Object proto = Object::dynamicCast(prototype());
     293  if (proto.isNull())
     294    return Undefined();
     295
     296  return proto.get(exec,propertyName);
     297}
     298
     299// This get method only looks at the property map.
     300// A bit like hasProperty(recursive=false), this doesn't go to the prototype.
     301// This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
     302// to look up in the prototype, it might already exist there)
     303ValueImp* ObjectImp::getDirect(const UString& propertyName) const
     304{
     305  return _prop->get(propertyName);
    384306}
    385307
    386308// ECMA 8.6.2.2
    387 void KJSO::put(const UString &p, const KJSO& v)
    388 {
    389   assert(rep);
    390   rep->put(p, v);
    391 }
    392 
    393 // ECMA 8.6.2.2
    394 void KJSO::put(const UString &p, const KJSO& v, int attr)
    395 {
    396   static_cast<Imp*>(rep)->put(p, v, attr);
    397 }
    398 
    399 // provided for convenience.
    400 void KJSO::put(const UString &p, double d, int attr)
    401 {
    402   put(p, Number(d), attr);
    403 }
    404 
    405 // provided for convenience.
    406 void KJSO::put(const UString &p, int i, int attr)
    407 {
    408   put(p, Number(i), attr);
    409 }
    410 
    411 // provided for convenience.
    412 void KJSO::put(const UString &p, unsigned int u, int attr)
    413 {
    414   put(p, Number(u), attr);
    415 }
    416 
    417 // ECMA 15.4.5.1
    418 void KJSO::putArrayElement(const UString &p, const KJSO& v)
    419 {
    420   assert(rep);
    421   rep->putArrayElement(p, v);
    422 }
    423 
    424 // ECMA 8.6.2.3
    425 bool KJSO::canPut(const UString &p) const
    426 {
    427   assert(rep);
    428   return rep->canPut(p);
    429 }
    430 
    431 // ECMA 8.6.2.4
    432 bool KJSO::hasProperty(const UString &p, bool recursive) const
    433 {
    434   assert(rep);
    435   return rep->hasProperty(p, recursive);
    436 }
    437 
    438 // ECMA 8.6.2.5
    439 bool KJSO::deleteProperty(const UString &p)
    440 {
    441   assert(rep);
    442   return rep->deleteProperty(p);
    443 }
    444 
    445 Object::Object(Imp *d) : KJSO(d) { }
    446 
    447 Object::Object(Class c) : KJSO(new ObjectImp(c)) { }
    448 
    449 Object::Object(Class c, const KJSO& v) : KJSO(new ObjectImp(c, v)) { }
    450 
    451 Object::Object(Class c, const KJSO& v, const Object& p)
    452   : KJSO(new ObjectImp(c, v))
    453 {
    454   setPrototype(p);
    455 }
    456 
    457 Object::~Object() { }
    458 
    459 void Object::setClass(Class c)
    460 {
    461   static_cast<ObjectImp*>(rep)->cl = c;
    462 }
    463 
    464 Class Object::getClass() const
    465 {
    466   assert(rep);
    467   return static_cast<ObjectImp*>(rep)->cl;
    468 }
    469 
    470 void Object::setInternalValue(const KJSO& v)
    471 {
    472   assert(rep);
    473   static_cast<ObjectImp*>(rep)->val = v.imp();
    474 }
    475 
    476 KJSO Object::internalValue()
    477 {
    478   assert(rep);
    479   return KJSO(static_cast<ObjectImp*>(rep)->val);
    480 }
    481 
    482 Object Object::create(Class c)
    483 {
    484   return Object::create(c, KJSO());
    485 }
    486 
    487 // factory
    488 Object Object::create(Class c, const KJSO& val)
    489 {
    490   Global global(Global::current());
    491   Object obj = Object();
    492   obj.setClass(c);
    493   obj.setInternalValue(val);
    494 
    495   UString p = "[[";
    496   switch (c) {
    497   case UndefClass:
    498   case ObjectClass:
    499     p += "Object";
    500     break;
    501   case FunctionClass:
    502     p += "Function";
    503     break;
    504   case ArrayClass:
    505     p += "Array";
    506     obj.put("length", Number(0), DontEnum | DontDelete);
    507     break;
    508   case StringClass:
    509     p += "String";
    510     obj.put("length", val.toString().value().size());
    511     break;
    512   case BooleanClass:
    513     p += "Boolean";
    514     break;
    515   case NumberClass:
    516     p += "Number";
    517     break;
    518   case DateClass:
    519     p += "Date";
    520     break;
    521   case RegExpClass:
    522     p += "RegExp";
    523     break;
    524   case ErrorClass:
    525     p += "Error";
    526     break;
    527   }
    528   p += ".prototype]]";
    529 
    530   //  KJSO prot = global.get(p).get("prototype");
    531   KJSO prot = global.get(p);
    532   assert(prot.isDefined());
    533 
    534   obj.setPrototype(prot);
    535   return obj;
    536 }
    537 
    538 Object Object::create(Class c, const KJSO& val, const Object& p)
    539 {
    540   Global global(Global::current());
    541   Object obj = Object();
    542   Object prot;
    543   obj.setClass(c);
    544   obj.setInternalValue(val);
    545 
    546   prot = p;
    547   obj.setPrototype(prot);
    548   return obj;
    549 }
    550 
    551 Object Object::dynamicCast(const KJSO &obj)
    552 {
    553   // return null object on type mismatch
    554   if (!obj.isA(ObjectType))
    555     return Object(0L);
    556 
    557   return Object(obj.imp());
    558 
    559 }
    560 
    561 #ifdef KJS_DEBUG_MEM
    562 int KJSO::count = 0;
    563 int Imp::count = 0;
    564 int List::count = 0;
    565 #endif
    566 
    567 Imp::Imp()
    568   : refcount(0), prop(0), proto(0)
    569 {
    570   setCreated(true);
    571 #ifdef KJS_DEBUG_MEM
    572   count++;
    573 #endif
    574 }
    575 
    576 Imp::~Imp()
    577 {
    578 #ifdef KJS_DEBUG_MEM
    579   assert(Collector::collecting);
    580   count--;
    581 #endif
    582 
    583 // dangling pointer during garbage collection !
    584 //   if (proto)
    585 //     proto->deref();
    586 
    587   // delete attached properties
    588   Property *tmp, *p = prop;
    589   while (p) {
    590     tmp = p;
    591     p = p->next;
    592     delete tmp;
    593   }
    594 }
    595 
    596 KJSO Imp::toPrimitive(Type preferred) const
    597 {
    598   return defaultValue(preferred);
    599   /* TODO: is there still any need to throw a runtime error _here_ ? */
    600 }
    601 
    602 Boolean Imp::toBoolean() const
    603 {
    604   return Boolean();
    605 }
    606 
    607 Number Imp::toNumber() const
    608 {
    609   return Number();
    610 }
    611 
    612 String Imp::toString() const
    613 {
    614   return String();
    615 }
    616 
    617 Object Imp::toObject() const
    618 {
    619   return Object(Error::create(TypeError).imp());
    620 }
    621 
    622 
    623 PropList* Imp::propList(PropList *first, PropList *last, bool recursive) const
    624 {
    625   Property *pr = prop;
    626   while(pr) {
    627     if (!(pr->attribute & DontEnum) && !first->contains(pr->name)) {
    628       if(last) {
    629         last->next = new PropList();
    630         last = last->next;
    631       } else {
    632         first = new PropList();
    633         last = first;
    634       }
    635       last->name = pr->name;
    636     }
    637     pr = pr->next;
    638   }
    639   if (proto && recursive)
    640     proto->propList(first, last);
    641 
    642   return first;
    643 }
    644 
    645 KJSO Imp::get(const UString &p) const
    646 {
    647   Property *pr = prop;
    648   while (pr) {
    649     if (pr->name == p) {
    650       return pr->object;
    651     }
    652     pr = pr->next;
    653   }
    654 
    655   if (!proto)
    656     return Undefined();
    657 
    658   return proto->get(p);
    659 }
    660 
    661 // may be overriden
    662 void Imp::put(const UString &p, const KJSO& v)
    663 {
    664   put(p, v, None);
    665 }
    666 
    667 // ECMA 8.6.2.2
    668 void Imp::put(const UString &p, const KJSO& v, int attr)
    669 {
     309void ObjectImp::put(ExecState *exec, const UString &propertyName,
     310                     const Value &value, int attr)
     311{
     312  assert(!value.isNull());
     313  assert(value.type() != ReferenceType);
     314  assert(value.type() != CompletionType);
     315  assert(value.type() != ListType);
     316
    670317  /* TODO: check for write permissions directly w/o this call */
     318  /* Doesn't look very easy with the PropertyMap API - David */
    671319  // putValue() is used for JS assignemnts. It passes no attribute.
    672320  // Assume that a C++ implementation knows what it is doing
    673321  // and let it override the canPut() check.
    674   if (attr == None && !canPut(p))
     322  if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) {
     323#ifdef KJS_VERBOSE
     324    fprintf( stderr, "WARNING: canPut %s said NO\n", propertyName.ascii() );
     325#endif
    675326    return;
    676 
    677   Property *pr;
    678 
    679   if (prop) {
    680     pr = prop;
    681     while (pr) {
    682       if (pr->name == p) {
    683         // replace old value
    684         pr->object = v.imp();
    685         pr->attribute = attr;
    686         return;
     327  }
     328
     329  if (propertyName == "__proto__") {
     330    // non-standard netscape extension
     331    setPrototype(value);
     332    return;
     333  }
     334
     335  _prop->put(propertyName,value.imp(),attr);
     336}
     337
     338// ECMA 8.6.2.3
     339bool ObjectImp::canPut(ExecState *, const UString &propertyName) const
     340{
     341  PropertyMapNode *node = _prop->getNode(propertyName);
     342  if (node)
     343    return!(node->attr & ReadOnly);
     344
     345  // Look in the static hashtable of properties
     346  const HashEntry* e = findPropertyHashEntry(propertyName);
     347  if (e)
     348    return !(e->attr & ReadOnly);
     349
     350  // Don't look in the prototype here. We can always put an override
     351  // in the object, even if the prototype has a ReadOnly property.
     352  return true;
     353}
     354
     355// ECMA 8.6.2.4
     356bool ObjectImp::hasProperty(ExecState *exec, const UString &propertyName, bool recursive) const
     357{
     358  if (propertyName == "__proto__")
     359    return true;
     360  if (_prop->get(propertyName))
     361    return true;
     362
     363  // Look in the static hashtable of properties
     364  if (findPropertyHashEntry(propertyName))
     365      return true;
     366
     367  // Look in the prototype
     368  Object proto = Object::dynamicCast(prototype());
     369  if (proto.isNull() || !recursive)
     370    return false;
     371
     372  return proto.hasProperty(exec,propertyName);
     373}
     374
     375// ECMA 8.6.2.5
     376bool ObjectImp::deleteProperty(ExecState */*exec*/, const UString &propertyName)
     377{
     378  PropertyMapNode *node = _prop->getNode(propertyName);
     379  if (node) {
     380    if ((node->attr & DontDelete))
     381      return false;
     382    _prop->remove(propertyName);
     383    return true;
     384  }
     385
     386  // Look in the static hashtable of properties
     387  if (findPropertyHashEntry(propertyName))
     388    return false; // No builtin property can be deleted
     389  return true;
     390}
     391
     392void ObjectImp::deleteAllProperties( ExecState * )
     393{
     394  _prop->clear();
     395}
     396
     397// ECMA 8.6.2.6
     398Value ObjectImp::defaultValue(ExecState *exec, Type hint) const
     399{
     400  if (hint != StringType && hint != NumberType) {
     401    /* Prefer String for Date objects */
     402    if (_proto == exec->interpreter()->builtinDatePrototype().imp())
     403      hint = StringType;
     404    else
     405      hint = NumberType;
     406  }
     407
     408  Value v;
     409  if (hint == StringType)
     410    v = get(exec,"toString");
     411  else
     412    v = get(exec,"valueOf");
     413
     414  if (v.type() == ObjectType) {
     415    Object o = Object(static_cast<ObjectImp*>(v.imp()));
     416    if (o.implementsCall()) { // spec says "not primitive type" but ...
     417      Object thisObj = Object(const_cast<ObjectImp*>(this));
     418      Value def = o.call(exec,thisObj,List::empty());
     419      Type defType = def.type();
     420      if (defType == UnspecifiedType || defType == UndefinedType ||
     421          defType == NullType || defType == BooleanType ||
     422          defType == StringType || defType == NumberType) {
     423        return def;
    687424      }
    688       pr = pr->next;
    689425    }
    690426  }
    691427
    692   // add new property
    693   pr = new Property;
    694   pr->name = p;
    695   pr->object = v.imp();
    696   pr->attribute = attr;
    697   pr->next = prop;
    698   prop = pr;
    699 }
    700 
    701 // ECMA 8.6.2.3
    702 bool Imp::canPut(const UString &p) const
    703 {
    704   if (prop) {
    705     const Property *pr = prop;
    706     while (pr) {
    707       if (pr->name == p)
    708         return !(pr->attribute & ReadOnly);
    709       pr = pr->next;
     428  if (hint == StringType)
     429    v = get(exec,"valueOf");
     430  else
     431    v = get(exec,"toString");
     432
     433  if (v.type() == ObjectType) {
     434    Object o = Object(static_cast<ObjectImp*>(v.imp()));
     435    if (o.implementsCall()) { // spec says "not primitive type" but ...
     436      Object thisObj = Object(const_cast<ObjectImp*>(this));
     437      Value def = o.call(exec,thisObj,List::empty());
     438      Type defType = def.type();
     439      if (defType == UnspecifiedType || defType == UndefinedType ||
     440          defType == NullType || defType == BooleanType ||
     441          defType == StringType || defType == NumberType) {
     442        return def;
     443      }
    710444    }
    711445  }
    712   if (!proto)
    713     return true;
    714 
    715   return proto->canPut(p);
    716 }
    717 
    718 // ECMA 8.6.2.4
    719 bool Imp::hasProperty(const UString &p, bool recursive) const
    720 {
    721   const Property *pr = prop;
    722   while (pr) {
    723     if (pr->name == p)
    724       return true;
    725     pr = pr->next;
    726   }
    727 
    728   if (!proto || !recursive)
    729     return false;
    730 
    731   return proto->hasProperty(p);
    732 }
    733 
    734 // ECMA 8.6.2.5
    735 bool Imp::deleteProperty(const UString &p)
    736 {
    737   Property *pr = prop;
    738   Property **prev = &prop;
    739   while (pr) {
    740     if (pr->name == p) {
    741       if ((pr->attribute & DontDelete))
    742         return false;
    743       *prev = pr->next;
    744       delete pr;
    745       return true;
     446
     447  Object err = Error::create(exec, TypeError, I18N_NOOP("No default value"));
     448  exec->setException(err);
     449  return err;
     450}
     451
     452const HashEntry* ObjectImp::findPropertyHashEntry( const UString& propertyName ) const
     453{
     454  const ClassInfo *info = classInfo();
     455  while (info) {
     456    if (info->propHashTable) {
     457      const HashEntry *e = Lookup::findEntry(info->propHashTable, propertyName);
     458      if (e)
     459        return e;
    746460    }
    747     prev = &(pr->next);
    748     pr = pr->next;
    749   }
     461    info = info->parentClass;
     462  }
     463  return 0L;
     464}
     465
     466bool ObjectImp::implementsConstruct() const
     467{
     468  return false;
     469}
     470
     471Object ObjectImp::construct(ExecState */*exec*/, const List &/*args*/)
     472{
     473  assert(false);
     474  return Object(0);
     475}
     476
     477bool ObjectImp::implementsCall() const
     478{
     479  return false;
     480}
     481
     482Value ObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/)
     483{
     484  assert(false);
     485  return Object(0);
     486}
     487
     488bool ObjectImp::implementsHasInstance() const
     489{
     490  return false;
     491}
     492
     493Boolean ObjectImp::hasInstance(ExecState */*exec*/, const Value &/*value*/)
     494{
     495  assert(false);
     496  return Boolean(false);
     497}
     498
     499const List ObjectImp::scope() const
     500{
     501  return _scope;
     502}
     503
     504void ObjectImp::setScope(const List &s)
     505{
     506  if (_scope) _scope->setGcAllowed();
     507  _scope = static_cast<ListImp*>(s.imp());
     508}
     509
     510List ObjectImp::propList(ExecState *exec, bool recursive)
     511{
     512  List list;
     513  if (_proto && _proto->type() == ObjectType && recursive)
     514    list = static_cast<ObjectImp*>(_proto)->propList(exec,recursive);
     515
     516
     517  PropertyMapNode *node = _prop->first();
     518  while (node) {
     519    if (!(node->attr & DontEnum))
     520      list.append(Reference(Object(this), node->name));
     521    node = node->next();
     522  }
     523
     524  // Add properties from the static hashtable of properties
     525  const ClassInfo *info = classInfo();
     526  while (info) {
     527    if (info->propHashTable) {
     528      int size = info->propHashTable->size;
     529      const HashEntry *e = info->propHashTable->entries;
     530      for (int i = 0; i < size; ++i, ++e) {
     531        if ( e->s && !(e->attr & DontEnum) )
     532          list.append(Reference(Object(this), e->s)); /// ######### check for duplicates with the propertymap
     533      }
     534    }
     535    info = info->parentClass;
     536  }
     537
     538  return list;
     539}
     540
     541Value ObjectImp::internalValue() const
     542{
     543  return Value(_internalValue);
     544}
     545
     546void ObjectImp::setInternalValue(const Value &v)
     547{
     548  _internalValue = v.imp();
     549}
     550
     551// The following functions simply call the corresponding functions in ValueImp
     552// but are overridden in case of future needs
     553
     554Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const
     555{
     556  return defaultValue(exec,preferredType);
     557}
     558
     559bool ObjectImp::toBoolean(ExecState */*exec*/) const
     560{
    750561  return true;
    751562}
    752563
    753 // ECMA 15.4.5.1
    754 void Imp::putArrayElement(const UString &p, const KJSO& v)
    755 {
    756   if (!canPut(p))
    757     return;
    758 
    759   if (hasProperty(p)) {
    760     if (p == "length") {
    761       KJSO len = get("length");
    762       unsigned int oldLen = len.toUInt32();
    763       unsigned int newLen = v.toUInt32();
    764       // shrink array
    765       for (unsigned int u = newLen; u < oldLen; u++) {
    766         UString p = UString::from(u);
    767         if (hasProperty(p, false))
    768           deleteProperty(p);
    769       }
    770       put("length", Number(newLen), DontEnum | DontDelete);
    771       return;
    772     }
    773     //    put(p, v);
    774     } //  } else
    775     put(p, v);
    776 
    777   // array index ?
    778   unsigned int idx;
    779   if (!sscanf(p.cstring().c_str(), "%u", &idx)) /* TODO */
    780     return;
    781 
    782   // do we need to update/create the length property ?
    783   if (hasProperty("length", false)) {
    784     KJSO len = get("length");
    785     if (idx < len.toUInt32())
    786       return;
    787   }
    788 
    789   put("length", Number(idx+1), DontDelete | DontEnum);
    790 }
    791 
    792 bool Imp::implementsCall() const
    793 {
    794   return (type() == FunctionType ||
    795           type() == InternalFunctionType ||
    796           type() == ConstructorType ||
    797           type() == DeclaredFunctionType ||
    798           type() == AnonymousFunctionType);
    799 }
    800 
    801 // ECMA 8.6.2.6 (new draft)
    802 KJSO Imp::defaultValue(Type hint) const
    803 {
    804   KJSO o;
    805 
    806   /* TODO String on Date object */
    807   if (hint != StringType && hint != NumberType)
    808     hint = NumberType;
    809 
    810   if (hint == StringType)
    811     o = get("toString");
    812   else
    813     o = get("valueOf");
    814 
    815   Imp *that = const_cast<Imp*>(this);
    816   if (o.implementsCall()) { // spec says "not primitive type" but ...
    817     FunctionImp *f = static_cast<FunctionImp*>(o.imp());
    818     KJSO s = f->executeCall(that, 0L);
    819     if (!s.isObject())
    820       return s;
    821   }
    822 
    823   if (hint == StringType)
    824     o = get("valueOf");
    825   else
    826     o = get("toString");
    827 
    828   if (o.implementsCall()) {
    829     FunctionImp *f = static_cast<FunctionImp*>(o.imp());
    830     KJSO s = f->executeCall(that, 0L);
    831     if (!s.isObject())
    832       return s;
    833   }
    834 
    835   return Error::create(TypeError, I18N_NOOP("No default value"));
    836 }
    837 
    838 void Imp::mark(Imp*)
    839 {
    840   setMarked(true);
    841 
    842   if (proto && !proto->marked())
    843     proto->mark();
    844 
    845   struct Property *p = prop;
    846   while (p) {
    847     if (p->object && !p->object->marked())
    848       p->object->mark();
    849     p = p->next;
    850   }
    851 }
    852 
    853 bool Imp::marked() const
    854 {
    855   return prev;
    856 }
    857 
    858 void Imp::setPrototype(const KJSO& p)
    859 {
    860   if (proto)
    861     proto->deref();
    862   proto = p.imp();
    863   if (proto)
    864     proto->ref();
    865 }
    866 
    867 void Imp::setPrototypeProperty(const KJSO &p)
    868 {
    869   put("prototype", p, DontEnum | DontDelete | ReadOnly);
    870 }
    871 
    872 void Imp::setConstructor(const KJSO& c)
    873 {
    874   put("constructor", c, DontEnum | DontDelete | ReadOnly);
    875 }
    876 
    877 void* Imp::operator new(size_t s)
    878 {
    879   return Collector::allocate(s);
    880 }
    881 
    882 void Imp::operator delete(void*, size_t)
    883 {
    884   // deprecated. a mistake.
    885 }
    886 
    887 void Imp::operator delete(void*)
    888 {
    889   // Do nothing. So far.
    890 }
    891 
    892 void Imp::setMarked(bool m)
    893 {
    894   prev = m ? this : 0L;
    895 }
    896 
    897 void Imp::setGcAllowed(bool a)
    898 {
    899   next = this;
    900   if (a)
    901     next++;
    902 }
    903 
    904 bool Imp::gcAllowed() const
    905 {
    906   return (next && next != this);
    907 }
    908 
    909 void Imp::setCreated(bool c)
    910 {
    911   next = c ? this : 0L;
    912 }
    913 
    914 bool Imp::created() const
    915 {
    916   return next;
    917 }
    918 
    919 ObjectImp::ObjectImp(Class c) : cl(c), val(0L) { }
    920 
    921 ObjectImp::ObjectImp(Class c, const KJSO &v) : cl(c), val(v.imp()) { }
    922 
    923 ObjectImp::ObjectImp(Class c, const KJSO &v, const KJSO &p)
    924   : cl(c), val(v.imp())
    925 {
    926   setPrototype(p);
    927 }
    928 
    929 ObjectImp::~ObjectImp() { }
    930 
    931 Boolean ObjectImp::toBoolean() const
    932 {
    933   return Boolean(true);
    934 }
    935 
    936 Number ObjectImp::toNumber() const
    937 {
    938   return toPrimitive(NumberType).toNumber();
    939 }
    940 
    941 String ObjectImp::toString() const
    942 {
    943   KJSO tmp;
    944   String res;
    945 
    946   if (hasProperty("toString") && (tmp = get("toString")).implementsCall()) {
    947     // TODO live w/o hack
    948     res = tmp.executeCall(KJSO(const_cast<ObjectImp*>(this)), 0L).toString();
    949   } else {
    950     tmp = toPrimitive(StringType);
    951     res = tmp.toString();
    952   }
    953 
    954   return res;
    955 }
    956 
    957 const TypeInfo ObjectImp::info = { "Object", ObjectType, 0, 0, 0 };
    958 
    959 Object ObjectImp::toObject() const
     564double ObjectImp::toNumber(ExecState *exec) const
     565{
     566  Value prim = toPrimitive(exec,NumberType);
     567  if (exec->hadException()) // should be picked up soon in nodes.cpp
     568    return 0.0;
     569  return prim.toNumber(exec);
     570}
     571
     572int ObjectImp::toInteger(ExecState *exec) const
     573{
     574  return ValueImp::toInteger(exec);
     575}
     576
     577int ObjectImp::toInt32(ExecState *exec) const
     578{
     579  return ValueImp::toInt32(exec);
     580}
     581
     582unsigned int ObjectImp::toUInt32(ExecState *exec) const
     583{
     584  return ValueImp::toUInt32(exec);
     585}
     586
     587unsigned short ObjectImp::toUInt16(ExecState *exec) const
     588{
     589  return ValueImp::toUInt16(exec);
     590}
     591
     592UString ObjectImp::toString(ExecState *exec) const
     593{
     594  Value prim = toPrimitive(exec,StringType);
     595  if (exec->hadException()) // should be picked up soon in nodes.cpp
     596    return "";
     597  return prim.toString(exec);
     598}
     599
     600Object ObjectImp::toObject(ExecState */*exec*/) const
    960601{
    961602  return Object(const_cast<ObjectImp*>(this));
    962603}
    963604
    964 KJSO ObjectImp::toPrimitive(Type preferred) const
    965 {
    966   // ### Imp already does that now. Remove in KDE 3.0.
    967   return defaultValue(preferred);
    968   /* TODO: is there still any need to throw a runtime error _here_ ? */
    969 }
    970 
    971 void ObjectImp::mark(Imp*)
    972 {
    973   // mark objects from the base
    974   Imp::mark();
    975 
    976   // mark internal value, if any and it has not been visited yet
    977   if (val && !val->marked())
    978     val->mark();
    979 }
    980 
    981 HostImp::HostImp()
    982 {
    983     setPrototype(Global::current().objectPrototype());
    984     //printf("HostImp::HostImp() %p\n",this);
    985 }
    986 
    987 HostImp::~HostImp() { }
    988 
    989 Boolean HostImp::toBoolean() const
    990 {
    991   return Boolean(true);
    992 }
    993 
    994 String HostImp::toString() const
    995 {
    996   // Exact copy of ObjectImp::toString....
    997   KJSO tmp;
    998   String res;
    999 
    1000   if (hasProperty("toString") && (tmp = get("toString")).implementsCall()) {
    1001     // TODO live w/o hack
    1002     res = tmp.executeCall(KJSO(const_cast<HostImp*>(this)), 0L).toString();
    1003   } else {
    1004     tmp = toPrimitive(StringType);
    1005     res = tmp.toString();
    1006   }
    1007 
    1008   return res;
    1009 }
    1010 
    1011 const TypeInfo HostImp::info = { "HostObject", HostType, 0, 0, 0 };
    1012 
    1013 Object Error::createObject(ErrorType e, const char *m, int l)
    1014 {
    1015   Context *context = Context::current();
    1016   if (!context)
    1017     return Object();
    1018 
    1019   Object err = ErrorObject::create(e, m, l);
    1020 
    1021   if (!KJScriptImp::hadException())
    1022     KJScriptImp::setException(err.imp());
    1023 
    1024   const struct ErrorStruct {
    1025       ErrorType e;
    1026       const char *s;
    1027   } errtab[] = {
    1028       { GeneralError, I18N_NOOP("General error") },
    1029       { EvalError, I18N_NOOP("Evaluation error") },
    1030       { RangeError, I18N_NOOP("Range error") },
    1031       { ReferenceError, I18N_NOOP("Reference error") },
    1032       { SyntaxError, I18N_NOOP("Syntax error") },
    1033       { TypeError, I18N_NOOP("Type error") },
    1034       { URIError, I18N_NOOP("URI error") },
    1035       { (ErrorType)0, 0 }
    1036   };
    1037 
    1038   const char *estr = I18N_NOOP("Unknown error");
    1039   const ErrorStruct *estruct = errtab;
    1040   while (estruct->e) {
    1041       if (estruct->e == e) {
    1042           estr = estruct->s;
    1043           break;
    1044       }
    1045       estruct++;
    1046   }
    1047 
     605
     606// ------------------------------ Error ----------------------------------------
     607
     608const char * const errorNamesArr[] = {
     609  I18N_NOOP("Error"), // GeneralError
     610  I18N_NOOP("Evaluation error"), // EvalError
     611  I18N_NOOP("Range error"), // RangeError
     612  I18N_NOOP("Reference error"), // ReferenceError
     613  I18N_NOOP("Syntax error"), // SyntaxError
     614  I18N_NOOP("Type error"), // TypeError
     615  I18N_NOOP("URI error"), // URIError
     616};
     617
     618const char * const * const Error::errorNames = errorNamesArr;
     619
     620Object Error::create(ExecState *exec, ErrorType errtype, const char *message,
     621                     int lineno, int sourceId)
     622{
     623  Object cons;
     624
     625  switch (errtype) {
     626  case EvalError:
     627    cons = exec->interpreter()->builtinEvalError();
     628    break;
     629  case RangeError:
     630    cons = exec->interpreter()->builtinRangeError();
     631    break;
     632  case ReferenceError:
     633    cons = exec->interpreter()->builtinReferenceError();
     634    break;
     635  case SyntaxError:
     636    cons = exec->interpreter()->builtinSyntaxError();
     637    break;
     638  case TypeError:
     639    cons = exec->interpreter()->builtinTypeError();
     640    break;
     641  case URIError:
     642    cons = exec->interpreter()->builtinURIError();
     643    break;
     644  default:
     645    cons = exec->interpreter()->builtinError();
     646    break;
     647  }
     648
     649  if (!message)
     650    message = errorNames[errtype];
     651  List args;
     652  args.append(String(message));
     653  Object err = Object::dynamicCast(cons.construct(exec,args));
     654
     655  if (lineno != -1)
     656    err.put(exec, "line", Number(lineno));
     657  if (sourceId != -1)
     658    err.put(exec, "sourceId", Number(sourceId));
     659
     660  return err;
     661
     662/*
    1048663#ifndef NDEBUG
    1049664  const char *msg = err.get("message").toString().value().ascii();
    1050665  if (l >= 0)
    1051       fprintf(stderr, "JS: %s at line %d. %s\n", estr, l, msg);
     666      fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg);
    1052667  else
    1053       fprintf(stderr, "JS: %s. %s\n", estr, msg);
     668      fprintf(stderr, "KJS: %s. %s\n", estr, msg);
    1054669#endif
    1055670
    1056671  return err;
    1057 }
    1058 
    1059 KJSO Error::create(ErrorType e, const char *m, int l)
    1060 {
    1061   return KJSO(createObject(e, m, l).imp());
    1062 }
     672*/
     673}
     674
  • trunk/JavaScriptCore/kjs/object.h

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    34 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1719 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1820 *  Boston, MA 02111-1307, USA.
     21 *
    1922 */
     23
    2024
    2125#ifndef _KJS_OBJECT_H_
    2226#define _KJS_OBJECT_H_
    2327
    24 #include <stdlib.h>
    25 
    26 #include "ustring.h"
    27 
    28 /**
    29  * @short Main namespace
    30  */
     28// Objects
     29
     30#include "value.h"
     31#include "types.h"
     32
    3133namespace KJS {
    3234
     35  class ObjectImpPrivate;
     36  class PropertyMap;
     37  class HashTable;
     38  class HashEntry;
     39  class ListImp;
     40
     41  // ECMA 262-3 8.6.1
     42  // Attributes (only applicable to the Object type)
     43  enum Attribute { None       = 0,
     44                   ReadOnly   = 1 << 1, // property can be only read, not written
     45                   DontEnum   = 1 << 2, // property doesn't appear in (for .. in ..)
     46                   DontDelete = 1 << 3, // property can't be deleted
     47                   Internal   = 1 << 4, // an internal property, set to by pass checks
     48                   Function   = 1 << 5 }; // property is a function - only used by static hashtables
     49
    3350  /**
    34    * Types of classes derived from KJSO
     51   * Class Information
    3552   */
    36   enum Type { // main types
    37               AbstractType = 1,
    38               UndefinedType,
    39               NullType,
    40               BooleanType,
    41               NumberType,
    42               StringType,
    43               ObjectType,
    44               HostType,
    45               ReferenceType,
    46               CompletionType,
    47               // extended types
    48               FunctionType,
    49               InternalFunctionType,
    50               DeclaredFunctionType,
    51               AnonymousFunctionType,
    52               ConstructorType,
    53               ActivationType
    54   };
    55 
    56   /**
    57    * Property attributes.
    58    */
    59   enum Attribute { None       = 0,
    60                    ReadOnly   = 1 << 1,
    61                    DontEnum   = 1 << 2,
    62                    DontDelete = 1 << 3,
    63                    Internal   = 1 << 4 };
    64 
    65   /**
    66    * Types of classes derived from @ref Object.
    67    */
    68   enum Class { UndefClass,
    69                ArrayClass,
    70                StringClass,
    71                BooleanClass,
    72                NumberClass,
    73                ObjectClass,
    74                DateClass,
    75                RegExpClass,
    76                ErrorClass,
    77                FunctionClass };
    78 
    79   /**
    80    * Completion types.
    81    */
    82   enum Compl { Normal, Break, Continue, ReturnValue, Throw };
    83 
    84   /**
    85    * Error codes.
    86    */
    87   enum ErrorType { NoError = 0,
    88                    GeneralError,
    89                    EvalError,
    90                    RangeError,
    91                    ReferenceError,
    92                    SyntaxError,
    93                    TypeError,
    94                    URIError };
    95 
    96   extern const double NaN;
    97   extern const double Inf;
    98 
    99   // forward declarations
    100   class Imp;
    101   class Boolean;
    102   class Number;
    103   class String;
    104   class Object;
    105   struct Property;
    106   class PropList;
    107   class List;
    108 
    109   /**
    110    * @short Type information.
    111    */
    112   struct TypeInfo {
    113     /**
    114      * A string denoting the type name. Example: "Number".
    115      */
    116     const char *name;
    117     /**
    118      * One of the @ref KJS::Type enums.
    119      */
    120     Type type;
    121     /**
    122      * Pointer to the type information of the base class.
    123      * NULL if there is none.
    124      */
    125     const TypeInfo *base;
    126     /**
    127      * Additional specifier for your own use.
    128      */
    129     int extra;
    130     /**
    131      * Reserved for future extensions (internal).
     53  struct ClassInfo {
     54    /**
     55     * A string denoting the class name. Example: "Window".
     56     */
     57    const char* className;
     58    /**
     59     * Pointer to the class information of the base class.
     60     * 0L if there is none.
     61     */
     62    const ClassInfo *parentClass;
     63    /**
     64     * Static hash-table of properties.
     65     */
     66    const HashTable *propHashTable;
     67    /**
     68     * Reserved for future extension.
    13269     */
    13370    void *dummy;
     
    13572
    13673  /**
    137    * @short Main base class for every KJS object.
     74   * Represents an Object. This is a wrapper for ObjectImp
    13875   */
    139   class KJSO {
    140     friend class ElementNode;
     76  class Object : public Value {
    14177  public:
    142     /**
    143      * Constructor.
    144      */
    145     KJSO();
    146     /**
    147      * @internal
    148      */
    149     KJSO(Imp *d);
    150     /**
    151      * Copy constructor.
    152      */
    153     KJSO(const KJSO &);
    154     /*
    155      * Assignment operator
    156      */
    157     KJSO& operator=(const KJSO &);
    158     /**
    159      * Destructor.
    160      */
    161     virtual ~KJSO();
    162     /**
    163      * @return True if this object is null, i.e. if there is no data attached
    164      * to this object. Don't confuse this with the Null object.
    165      */
    166     bool isNull() const;
    167     /**
    168      * @return True if this objects is of any other value than Undefined.
    169      */
    170     bool isDefined() const;
    171     /**
    172      * @return the type of the object. One of the @ref KJS::Type enums.
    173      */
     78    Object();
     79    explicit Object(ObjectImp *v);
     80    Object(const Object &v);
     81    virtual ~Object();
     82
     83    Object& operator=(const Object &v);
     84
     85    virtual const ClassInfo *classInfo() const;
     86    bool inherits(const ClassInfo *cinfo) const;
     87
     88    /**
     89     * Converts a Value into an Object. If the value's type is not ObjectType,
     90     * a null object will be returned (i.e. one with it's internal pointer set
     91     * to 0). If you do not know for sure whether the value is of type
     92     * ObjectType, you should check the @ref isNull() methods afterwards before
     93     * calling any methods on the Object.
     94     *
     95     * @return The value converted to an object
     96     */
     97    static Object dynamicCast(const Value &v);
     98
     99    /**
     100     * Returns the prototype of this object. Note that this is not the same as
     101     * the "prototype" property.
     102     *
     103     * See ECMA 8.6.2
     104     *
     105     * @return The object's prototype
     106     */
     107    Value prototype() const;
     108
     109    /**
     110     * Returns the class name of the object
     111     *
     112     * See ECMA 8.6.2
     113     *
     114     * @return The object's class name
     115     */
     116    UString className() const;
     117
     118    /**
     119     * Retrieves the specified property from the object. If neither the object
     120     * or any other object in it's prototype chain have the property, this
     121     * function will return Undefined.
     122     *
     123     * See ECMA 8.6.2.1
     124     *
     125     * @param exec The current execution state
     126     * @param propertyName The name of the property to retrieve
     127     *
     128     * @return The specified property, or Undefined
     129     */
     130    Value get(ExecState *exec, const UString &propertyName) const;
     131
     132    /**
     133     * Sets the specified property.
     134     *
     135     * See ECMA 8.6.2.2
     136     *
     137     * @param exec The current execution state
     138     * @param propertyName The name of the property to set
     139     * @param propertyValue The value to set
     140     */
     141    void put(ExecState *exec, const UString &propertyName,
     142             const Value &value, int attr = None);
     143
     144    /**
     145     * Used to check whether or not a particular property is allowed to be set
     146     * on an object
     147     *
     148     * See ECMA 8.6.2.3
     149     *
     150     * @param exec The current execution state
     151     * @param propertyName The name of the property
     152     * @return true if the property can be set, otherwise false
     153     */
     154    bool canPut(ExecState *exec, const UString &propertyName) const;
     155
     156    /**
     157     * Checks to see whether the object (or any object in it's prototype chain)
     158     * has a property with the specified name.
     159     *
     160     * See ECMA 8.6.2.4
     161     *
     162     * @param exec The current execution state
     163     * @param propertyName The name of the property to check for
     164     * @return true if the object has the property, otherwise false
     165     */
     166    bool hasProperty(ExecState *exec, const UString &propertyName,
     167                     bool recursive = true) const;
     168
     169    /**
     170     * Removes the specified property from the object.
     171     *
     172     * See ECMA 8.6.2.5
     173     *
     174     * @param exec The current execution state
     175     * @param propertyName The name of the property to delete
     176     * @return true if the property was successfully deleted or did not
     177     * exist on the object. false if deleting the specified property is not
     178     * allowed.
     179     */
     180    bool deleteProperty(ExecState *exec, const UString &propertyName);
     181
     182    /**
     183     * Converts the object into a primitive value. The value return may differ
     184     * depending on the supplied hint
     185     *
     186     * See ECMA 8.6.2.6
     187     *
     188     * @param exec The current execution state
     189     * @param hint The desired primitive type to convert to
     190     * @return A primitive value converted from the objetc. Note that the
     191     * type of primitive value returned may not be the same as the requested
     192     * hint.
     193     */
     194    Value defaultValue(ExecState *exec, Type hint) const;
     195
     196    /**
     197     * Whether or not the object implements the construct() method. If this
     198     * returns false you should not call the construct() method on this
     199     * object (typically, an assertion will fail to indicate this).
     200     *
     201     * @return true if this object implements the construct() method, otherwise
     202     * false
     203     */
     204    bool implementsConstruct() const;
     205
     206    /**
     207     * Creates a new object based on this object. Typically this means the
     208     * following:
     209     * 1. A new object is created
     210     * 2. The prototype of the new object is set to the value of this object's
     211     *    "prototype" property
     212     * 3. The call() method of this object is called, with the new object
     213     *    passed as the this value
     214     * 4. The new object is returned
     215     *
     216     * In some cases, Host objects may differ from these semantics, although
     217     * this is discouraged.
     218     *
     219     * If an error occurs during construction, the execution state's exception
     220     * will be set. This can be tested for with @ref ExecState::hadException().
     221     * Under some circumstances, the exception object may also be returned.
     222     *
     223     * Note: This function should not be called if implementsConstruct() returns
     224     * false, in which case it will result in an assertion failure.
     225     *
     226     * @param exec The current execution state
     227     * @param args The arguments to be passed to call() once the new object has
     228     * been created
     229     * @return The newly created &amp; initialized object
     230     */
     231    Object construct(ExecState *exec, const List &args);
     232
     233    /**
     234     * Whether or not the object implements the call() method. If this returns
     235     * false you should not call the call() method on this object (typically,
     236     * an assertion will fail to indicate this).
     237     *
     238     * @return true if this object implements the call() method, otherwise
     239     * false
     240     */
     241    bool implementsCall() const;
     242
     243
     244    /**
     245     * Calls this object as if it is a function.
     246     *
     247     * Note: This function should not be called if implementsCall() returns
     248     * false, in which case it will result in an assertion failure.
     249     *
     250     * See ECMA 8.6.2.3
     251     *
     252     * @param exec The current execution state
     253     * @param thisObj The obj to be used as "this" within function execution.
     254     * Note that in most cases this will be different from the C++ "this"
     255     * object. For example, if the ECMAScript code "window.location.toString()"
     256     * is executed, call() will be invoked on the C++ object which implements
     257     * the toString method, with the thisObj being window.location
     258     * @param args List of arguments to be passed to the function
     259     * @return The return value from the function
     260     */
     261    Value call(ExecState *exec, Object &thisObj, const List &args);
     262
     263    /**
     264     * Whether or not the object implements the hasInstance() method. If this
     265     * returns false you should not call the hasInstance() method on this
     266     * object (typically, an assertion will fail to indicate this).
     267     *
     268     * @return true if this object implements the hasInstance() method,
     269     * otherwise false
     270     */
     271    bool implementsHasInstance() const;
     272
     273    /**
     274     * Checks whether value delegates behaviour to this object. Used by the
     275     * instanceof operator.
     276     *
     277     * @param exec The current execution state
     278     * @param value The value to check
     279     * @return true if value delegates behaviour to this object, otherwise
     280     * false
     281     */
     282    Boolean hasInstance(ExecState *exec, const Value &value);
     283
     284    /**
     285     * Returns the scope of this object. This is used when execution declared
     286     * functions - the execution context for the function is initialized with
     287     * extra object in it's scope. An example of this is functions declared
     288     * inside other functions:
     289     *
     290     * function f() {
     291     *
     292     *   function b() {
     293     *     return prototype;
     294     *   }
     295     *
     296     *   var x = 4;
     297     *   // do some stuff
     298     * }
     299     * f.prototype = new String();
     300     *
     301     * When the function f.b is executed, its scope will include properties of
     302     * f. So in the example above the return value of f.b() would be the new
     303     * String object that was assigned to f.prototype.
     304     *
     305     * @param exec The current execution state
     306     * @return The function's scope
     307     */
     308    const List scope() const;
     309    void setScope(const List &s);
     310
     311    /**
     312     * Returns a List of References to all the properties of the object. Used
     313     * in "for x in y" statements. The list is created new, so it can be freely
     314     * modified without affecting the object's properties. It should be deleted
     315     * by the caller.
     316     *
     317     * Subclasses can override this method in ObjectImpl to provide the
     318     * appearance of
     319     * having extra properties other than those set specifically with put().
     320     *
     321     * @param exec The current execution state
     322     * @param recursive Whether or not properties in the object's prototype
     323     * chain should be
     324     * included in the list.
     325     * @return A List of References to properties of the object.
     326     **/
     327    List propList(ExecState *exec, bool recursive = true);
     328
     329    /**
     330     * Returns the internal value of the object. This is used for objects such
     331     * as String and Boolean which are wrappers for native types. The interal
     332     * value is the actual value represented by the wrapper objects.
     333     *
     334     * @see ECMA 8.6.2
     335     * @return The internal value of the object
     336     */
     337    Value internalValue() const;
     338
     339    /**
     340     * Sets the internal value of the object
     341     *
     342     * @see internalValue()
     343     *
     344     * @param v The new internal value
     345     */
     346    void setInternalValue(const Value &v);
     347  };
     348
     349  class ObjectImp : public ValueImp {
     350  public:
     351    /**
     352     * Creates a new ObjectImp with the specified prototype
     353     *
     354     * @param proto The prototype
     355     */
     356    ObjectImp(const Object &proto);
     357
     358    /**
     359     * Creates a new ObjectImp with a prototype of Null()
     360     * (that is, the ECMAScript "null" value, not a null Object).
     361     *
     362     */
     363    ObjectImp();
     364
     365    virtual ~ObjectImp();
     366
     367    virtual void mark();
     368
    174369    Type type() const;
    175     /**
    176      * Check whether object is of a certain type
    177      * @param t type to check for
    178      */
    179     bool isA(Type t) const { return (type() == t); }
    180     /**
    181      * Check whether object is of a certain type. Allows checking of
    182      * host objects, too.
    183      * @param type name (Number, Boolean etc.)
    184      */
    185     bool isA(const char *s) const;
    186     /**
    187      * Use this method when checking for objects. It's safer than checking
    188      * for a single object type with @ref isA().
    189      */
    190     bool isObject() const;
    191     /**
    192      * Examine the inheritance structure of this object.
    193      * @param t Name of the base class.
    194      * @return True if object is of type t or a derived from such a type.
    195      */
    196     bool derivedFrom(const char *s) const;
    197 
    198     /**
    199      * @return Conversion to primitive type (Undefined, Boolean, Number
    200      * or String)
    201      * @param preferred Optional hint. Either StringType or NumberType.
    202      */
    203     KJSO toPrimitive(Type preferred = UndefinedType) const; // ECMA 9.1
    204     /**
    205      * @return Conversion to Boolean type.
    206      */
    207     Boolean toBoolean() const; // ECMA 9.2
    208     /**
    209      * @return Conversion to Number type.
    210      */
    211     Number toNumber() const; // ECMA 9.3
    212     /**
    213      * @return Conversion to double. 0.0 if conversion failed.
    214      */
    215     double round() const;
    216     /**
    217      * @return Conversion to Number type containing an integer value.
    218      */
    219     Number toInteger() const; // ECMA 9.4
    220     /**
    221      * @return Conversion to signed integer value.
    222      */
    223     int toInt32() const; // ECMA 9.5
    224     /**
    225      * @return Conversion to unsigned integer value.
    226      */
    227     unsigned int toUInt32() const; // ECMA 9.6
    228     /**
    229      * @return Conversion to unsigned short value.
    230      */
    231     unsigned short toUInt16() const; // ECMA 9.7
    232     /**
    233      * @return Conversion to String type.
    234      */
    235     String toString() const; // ECMA 9.8
    236     /**
    237      * @return Conversion to Object type.
    238      */
    239     Object toObject() const; // ECMA 9.9
    240 
    241     // Properties
    242     /**
    243      * Set the internal [[Prototype]] property of this object.
    244      * @param p A prototype object.
    245      */
    246     void setPrototype(const KJSO &p);
    247     /**
    248      * Set the "prototype" property of this object. Different from
    249      * the internal [[Prototype]] property.
    250      * @param p A prototype object.
    251      */
    252     void setPrototypeProperty(const KJSO &p);
    253     /**
    254      * @return The internal [[prototype]] property.
    255      */
    256     KJSO prototype() const;
    257     /**
    258      * The internal [[Get]] method.
    259      * @return The value of property p.
    260      */
    261     KJSO get(const UString &p) const;
    262     /**
    263      * The internal [[HasProperty]] method.
    264      * @param p Property name.
    265      * @param recursive Indicates whether prototypes are searched as well.
    266      * @return Boolean value indicating whether the object already has a
    267      * member with the given name p.
    268      */
    269     bool hasProperty(const UString &p, bool recursive = true) const;
    270     /**
    271      * The internal [[Put]] method. Sets the specified property to the value v.
    272      * @param p Property name.
    273      * @param v Value.
    274      */
    275     void put(const UString &p, const KJSO& v);
    276     /**
    277      * The internal [[CanPut]] method.
    278      * @param p Property name.
    279      * @return A boolean value indicating whether a [[Put]] operation with
    280      * p succeed.
    281      */
    282     bool canPut(const UString &p) const;
    283     /**
    284      * The internal [[Delete]] method. Removes the specified property from
    285      * the object.
    286      * @param p Property name.
    287      * @return True if the property was deleted successfully or didn't exist
    288      * in the first place. False if the DontDelete attribute was set.
    289      */
    290     bool deleteProperty(const UString &p);
    291     /**
    292      * Same as above put() method except the additional attribute. Right now,
    293      * this only works with native types as Host Objects don't reimplement
    294      * this method.
    295      * @param attr One of @ref KJS::Attribute.
    296      */
    297     void put(const UString &p, const KJSO& v, int attr);
    298     /**
    299      * Convenience function for adding a Number property constructed from
    300      * a double value.
    301      */
    302     void put(const UString &p, double d, int attr = None);
    303     /**
    304      * Convenience function for adding a Number property constructed from
    305      * an integer value.
    306      */
    307     void put(const UString &p, int i, int attr = None);
    308     /**
    309      * Convenience function for adding a Number property constructed from
    310      * an unsigned integer value.
    311      */
    312     void put(const UString &p, unsigned int u, int attr = None);
    313 
    314     /**
    315      * Reference method.
    316      * @return Reference base if object is a reference. Throws
    317      * a ReferenceError otherwise.
    318      */
    319     KJSO getBase() const;
    320     /**
    321      * Reference method.
    322      * @return Property name of a reference. Null string if object is not
    323      * a reference.
    324      */
    325     UString getPropertyName() const;
    326     /**
    327      * Reference method.
    328      * @return Referenced value. This object if no reference.
    329      */
    330     KJSO getValue() const;
    331     KJSO getValue();    /* TODO: remove in next version */
    332     /**
    333      * Reference method. Set referenced value to v.
    334      */
    335     ErrorType putValue(const KJSO& v);
    336 
    337     /**
    338      * @return True if object supports @ref executeCall() method. That's the
    339      * case for all objects derived from FunctionType.
    340      */
    341     bool implementsCall() const;
    342     /**
    343      * Execute function implemented via the @ref Function::execute() method.
    344      *
    345      * Note: check availability via @ref implementsCall() beforehand.
    346      * @param thisV Object serving as the 'this' value.
    347      * @param args Pointer to the list of arguments or null.
    348      * @return Result of the function call.
    349      */
    350     KJSO executeCall(const KJSO &thisV, const List *args);
    351     KJSO executeCall(const KJSO &thisV, const List *args, const List *extraScope) const;
    352 
    353     /**
    354      * Set this object's constructor.
    355      */
    356     void setConstructor(KJSO c);
    357 
    358     /**
    359      * @return A Pointer to the internal implementation.
    360      */
    361     Imp *imp() const { return rep; }
    362 
    363 #ifdef KJS_DEBUG_MEM
    364     /**
    365      * @internal
    366      */
    367     static int count;
    368 #endif
    369   protected:
    370     /**
    371      * Pointer to the internal implementation.
    372      */
    373     Imp *rep;
    374 
     370
     371    /**
     372     * A pointer to a ClassInfo struct for this class. This provides a basic
     373     * facility for run-time type information, and can be used to check an
     374     * object's class an inheritance (see @ref inherits()). This should
     375     * always return a statically declared pointer, or 0 to indicate that
     376     * there is no class information.
     377     *
     378     * This is primarily useful if you have application-defined classes that you
     379     * wish to check against for casting purposes.
     380     *
     381     * For example, to specify the class info for classes FooImp and BarImp,
     382     * where FooImp inherits from BarImp, you would add the following in your
     383     * class declarations:
     384     *
     385     *   class BarImp : public ObjectImp {
     386     *     virtual const ClassInfo *classInfo() const { return &info; }
     387     *     static const ClassInfo info;
     388     *     // ...
     389     *   };
     390     *
     391     *   class FooImp : public ObjectImp {
     392     *     virtual const ClassInfo *classInfo() const { return &info; }
     393     *     static const ClassInfo info;
     394     *     // ...
     395     *   };
     396     *
     397     * And in your source file:
     398     *
     399     *   const ClassInfo BarImp::info = {0, 0, 0}; // no parent class
     400     *   const ClassInfo FooImp::info = {&BarImp::info, 0, 0};
     401     *
     402     * @see inherits()
     403     */
     404    virtual const ClassInfo *classInfo() const;
     405
     406    /**
     407     * Checks whether this object inherits from the class with the specified
     408     * classInfo() pointer. This requires that both this class and the other
     409     * class return a non-NULL pointer for their classInfo() methods (otherwise
     410     * it will return false).
     411     *
     412     * For example, for two ObjectImp pointers obj1 and obj2, you can check
     413     * if obj1's class inherits from obj2's class using the following:
     414     *
     415     *   if (obj1->inherits(obj2->classInfo())) {
     416     *     // ...
     417     *   }
     418     *
     419     * If you have a handle to a statically declared ClassInfo, such as in the
     420     * @ref classInfo() example, you can check for inheritance without needing
     421     * an instance of the other class:
     422     *
     423     *   if (obj1->inherits(FooImp::info)) {
     424     *     // ...
     425     *   }
     426     *
     427     * @param cinfo The ClassInfo pointer for the class you want to check
     428     * inheritance against.
     429     * @return true if this object's class inherits from class with the
     430     * ClassInfo pointer specified in cinfo
     431     */
     432    bool inherits(const ClassInfo *cinfo) const;
     433
     434    // internal properties (ECMA 262-3 8.6.2)
     435
     436    /**
     437     * Implementation of the [[Prototype]] internal property (implemented by
     438     * all Objects)
     439     *
     440     * @see Object::prototype()
     441     */
     442    Value prototype() const;
     443    void setPrototype(const Value &proto);
     444
     445    /**
     446     * Implementation of the [[Class]] internal property (implemented by all
     447     * Objects)
     448     *
     449     * The default implementation uses classInfo().
     450     * You should either implement @ref classInfo(), or
     451     * if you simply need a classname, you can reimplement @ref className()
     452     * instead.
     453     *
     454     * @see Object::className()
     455     */
     456    virtual UString className() const;
     457
     458    /**
     459     * Implementation of the [[Get]] internal property (implemented by all
     460     * Objects)
     461     *
     462     * @see Object::get()
     463     */
     464    // [[Get]] - must be implemented by all Objects
     465    virtual Value get(ExecState *exec, const UString &propertyName) const;
     466
     467    /**
     468     * Implementation of the [[Put]] internal property (implemented by all
     469     * Objects)
     470     *
     471     * @see Object::put()
     472     */
     473    virtual void put(ExecState *exec, const UString &propertyName,
     474                     const Value &value, int attr = None);
     475
     476    /**
     477     * Implementation of the [[CanPut]] internal property (implemented by all
     478     * Objects)
     479     *
     480     * @see Object::canPut()
     481     */
     482    virtual bool canPut(ExecState *exec, const UString &propertyName) const;
     483
     484    /**
     485     * Implementation of the [[HasProperty]] internal property (implemented by
     486     * all Objects)
     487     *
     488     * @see Object::hasProperty()
     489     */
     490    virtual bool hasProperty(ExecState *exec, const UString &propertyName,
     491                             bool recursive = true) const;
     492
     493    /**
     494     * Implementation of the [[Delete]] internal property (implemented by all
     495     * Objects)
     496     *
     497     * @see Object::deleteProperty()
     498     */
     499    virtual bool deleteProperty(ExecState *exec,
     500                                const UString &propertyName);
     501
     502    /**
     503     * Remove all properties from this object.
     504     * This doesn't take DontDelete into account, and isn't in the ECMA spec.
     505     * It's simply a quick way to remove everything before destroying.
     506     */
     507    void deleteAllProperties( ExecState * );
     508
     509    /**
     510     * Implementation of the [[DefaultValue]] internal property (implemented by
     511     * all Objects)
     512     *
     513     * @see Object::defaultValue()
     514     */
     515    virtual Value defaultValue(ExecState *exec, Type hint) const;
     516
     517    virtual bool implementsConstruct() const;
     518    /**
     519     * Implementation of the [[Construct]] internal property
     520     *
     521     * @see Object::construct()
     522     */
     523    virtual Object construct(ExecState *exec, const List &args);
     524
     525    virtual bool implementsCall() const;
     526    /**
     527     * Implementation of the [[Call]] internal property
     528     *
     529     * @see Object::call()
     530     */
     531    virtual Value call(ExecState *exec, Object &thisObj,
     532                       const List &args);
     533
     534    virtual bool implementsHasInstance() const;
     535    /**
     536     * Implementation of the [[HasInstance]] internal property
     537     *
     538     * @see Object::hasInstance()
     539     */
     540    virtual Boolean hasInstance(ExecState *exec, const Value &value);
     541
     542    /**
     543     * Implementation of the [[Scope]] internal property
     544     *
     545     * @see Object::scope()
     546     */
     547    const List scope() const;
     548    void setScope(const List &s);
     549
     550    List propList(ExecState *exec, bool recursive = true);
     551
     552    Value internalValue() const;
     553    void setInternalValue(const Value &v);
     554
     555    Value toPrimitive(ExecState *exec,
     556                      Type preferredType = UnspecifiedType) const;
     557    bool toBoolean(ExecState *exec) const;
     558    double toNumber(ExecState *exec) const;
     559    int toInteger(ExecState *exec) const;
     560    int toInt32(ExecState *exec) const;
     561    unsigned int toUInt32(ExecState *exec) const;
     562    unsigned short toUInt16(ExecState *exec) const;
     563    UString toString(ExecState *exec) const;
     564    Object toObject(ExecState *exec) const;
     565
     566    ValueImp* getDirect(const UString& propertyName) const;
    375567  private:
    376     void putArrayElement(const UString &p, const KJSO &v);
    377   }; // end of KJSO
     568    const HashEntry* findPropertyHashEntry( const UString& propertyName ) const;
     569    ObjectImpPrivate *_od;
     570    PropertyMap *_prop;
     571    ValueImp *_proto;
     572    ValueImp *_internalValue;
     573    ListImp *_scope;
     574  };
    378575
    379576  /**
    380    * @short Base for all implementation classes.
     577   * Types of Native Errors available. For custom errors, GeneralError
     578   * should be used.
    381579   */
    382   class Imp {
    383     friend class KJSO;
    384     friend class Collector;
    385     friend class ForInNode;
    386     friend class Debugger;
    387   public:
    388     Imp();
    389   public:
    390     virtual KJSO toPrimitive(Type preferred = UndefinedType) const; // ECMA 9.1
    391     virtual Boolean toBoolean() const; // ECMA 9.2
    392     virtual Number toNumber() const; // ECMA 9.3
    393     virtual String toString() const; // ECMA 9.8
    394     virtual Object toObject() const; // ECMA 9.9
    395 
    396     // properties
    397     virtual KJSO get(const UString &p) const;
    398     virtual bool hasProperty(const UString &p, bool recursive = true) const;
    399     virtual void put(const UString &p, const KJSO& v);
    400     void put(const UString &p, const KJSO& v, int attr);
    401     virtual bool canPut(const UString &p) const;
    402     virtual bool deleteProperty(const UString &p);
    403     virtual KJSO defaultValue(Type hint) const;
    404 
    405     bool implementsCall() const;
    406 
    407     /**
    408      * @internal Reserved for mark & sweep garbage collection
    409      */
    410     virtual void mark(Imp *imp = 0L);
    411     bool marked() const;
    412 
    413     Type type() const { return typeInfo()->type; }
    414     /**
    415      * @return The TypeInfo struct describing this object.
    416      */
    417     virtual const TypeInfo* typeInfo() const { return &info; }
    418 
    419     void setPrototype(const KJSO& p);
    420     Imp* prototype() const { return proto; }
    421     void setPrototypeProperty(const KJSO &p);
    422     void setConstructor(const KJSO& c);
    423 
    424     void* operator new(size_t);
    425     void operator delete(void*);
    426     /**
    427      * @deprecated
    428      */
    429     void operator delete(void*, size_t);
    430 
    431 #ifdef KJS_DEBUG_MEM
    432     /**
    433      * @internal
    434      */
    435     static int count;
    436 #endif
    437   protected:
    438     virtual ~Imp();
    439   private:
    440     Imp(const Imp&);
    441     Imp& operator=(const Imp&);
    442     void putArrayElement(const UString &p, const KJSO& v);
    443 
    444     /**
    445      * Get the property names for this object. To be used by for .. in loops
    446      * @return The (pointer to the) first element of a PropList, to be deleted
    447      * by the caller, or 0 if there are no enumerable properties
    448      */
    449     PropList *propList(PropList *first = 0L, PropList *last = 0L,
    450                        bool recursive = true) const;
    451 
    452   public:
    453     // reference counting mechanism
    454     inline Imp* ref() { refcount++; return this; }
    455     inline bool deref() { return (!--refcount); }
    456     unsigned int refcount;
    457 
    458   private:
    459     Property *prop;
    460     Imp *proto;
    461     static const TypeInfo info;
    462 
    463     // reserved for memory managment - currently used as flags for garbage collection
    464     // (prev != 0) = marked, (next != 0) = created, (next != this) = created and gc allowed
    465     Imp *prev, *next;
    466     // for future extensions
    467     class ImpInternal;
    468     ImpInternal *internal;
    469 
    470     void setMarked(bool m);
    471     void setGcAllowed(bool a);
    472     bool gcAllowed() const;
    473     void setCreated(bool c);
    474     bool created() const;
    475   };
    476 
    477   /**
    478    * @short General implementation class for Objects
    479    */
    480   class ObjectImp : public Imp {
    481     friend class Object;
    482   public:
    483     ObjectImp(Class c);
    484     ObjectImp(Class c, const KJSO &v);
    485     ObjectImp(Class c, const KJSO &v, const KJSO &p);
    486     virtual ~ObjectImp();
    487     virtual KJSO toPrimitive(Type preferred = UndefinedType) const;
    488     virtual Boolean toBoolean() const;
    489     virtual Number toNumber() const;
    490     virtual String toString() const;
    491     virtual Object toObject() const;
    492 
    493     virtual const TypeInfo* typeInfo() const { return &info; }
    494     static const TypeInfo info;
    495     /**
    496      * @internal Reimplemenation of @ref Imp::mark().
    497      */
    498     virtual void mark(Imp *imp = 0L);
    499   private:
    500     Class cl;
    501     Imp *val;
    502   };
    503 
    504   /**
    505    * @short Object class encapsulating an internal value.
    506    */
    507   class Object : public KJSO {
    508   public:
    509     Object(Imp *d);
    510     Object(Class c = UndefClass);
    511     Object(Class c, const KJSO& v);
    512     Object(Class c, const KJSO& v, const Object& p);
    513     virtual ~Object();
    514     void setClass(Class c);
    515     Class getClass() const;
    516     void setInternalValue(const KJSO& v);
    517     KJSO internalValue();
    518     static Object create(Class c);
    519     static Object create(Class c, const KJSO& val);
    520     static Object create(Class c, const KJSO& val, const Object &p);
    521     static Object dynamicCast(const KJSO &obj);
    522   };
    523 
    524   /**
    525    * @short Implementation base class for Host Objects.
    526    */
    527   class HostImp : public Imp {
    528   public:
    529     HostImp();
    530     virtual ~HostImp();
    531     virtual const TypeInfo* typeInfo() const { return &info; }
    532 
    533     virtual Boolean toBoolean() const;
    534     virtual String toString() const;
    535 
    536     static const TypeInfo info;
    537   };
    538 
    539   class KJScriptImp;
    540   /**
    541    * The Global object represents the global namespace. It holds the native
    542    * objects like String and functions like eval().
    543    *
    544    * It also serves as a container for variables created by the user, i.e.
    545    * the statement
    546    * <pre>
    547    *   var i = 2;
    548    * </pre>
    549    * will basically perform a Global::current().put("i", Number(2)); operation.
    550    *
    551    * @short Unique global object containing initial native properties.
    552    */
    553   class Global : public Object {
    554     friend class KJScriptImp;
    555   public:
    556     /**
    557      * Constructs a Global object. This is done by the interpreter once and
    558      * there should be no need to create an instance on your own. Usually,
    559      * you'll just want to access the current instance.
    560      * For example like this:
    561      * <pre>
    562      * Global global(Global::current());
    563      * KJSO proto = global.objectPrototype();
    564      * </pre>
    565      */
    566     Global();
    567     /**
    568      * Destruct the Global object.
    569      */
    570     virtual ~Global();
    571     /**
    572      * @return A reference to the Global object belonging to the current
    573      * interpreter instance.
    574      */
    575     static Global current();
    576     /**
    577      * @return A handle to Object.prototype.
    578      */
    579     KJSO objectPrototype() const;
    580     /**
    581      * @return A handle to Function.prototype.
    582      */
    583     KJSO functionPrototype() const;
    584     /**
    585      * Set a filter object that will intercept all put() and get() calls
    586      * to the global object. If this object returns Undefined on get() the
    587      * request will be passed on the global object.
    588      * @deprecated
    589      */
    590     void setFilter(const KJSO &f);
    591     /**
    592      * Return a handle to the filter object (see @ref setFilter()).
    593      * Null if no filter has been installed.
    594      * @deprecated
    595      */
    596     KJSO filter() const;
    597     /**
    598      * Returns the extra user data set for this global object. Null by default.
    599      * Typical usage if you need to query any info related to the currently
    600      * running interpreter:
    601      *
    602      *    MyMainWindow *m = (MyMainWindow*)Global::current().extra();
    603      */
    604     void *extra() const;
    605     /**
    606      * Set the extra user data for this global object. It's not used by the
    607      * interpreter itself and can therefore be used to bind arbitrary data
    608      * to each interpreter instance.
    609      */
    610     void setExtra(void *e);
    611   private:
    612     Global(void *);
    613     void init();
    614     void clear();
    615   };
     580  enum ErrorType { GeneralError   = 0,
     581                   EvalError      = 1,
     582                   RangeError     = 2,
     583                   ReferenceError = 3,
     584                   SyntaxError    = 4,
     585                   TypeError      = 5,
     586                   URIError       = 6};
    616587
    617588  /**
     
    621592  public:
    622593    /**
    623      * Factory method for error objects. The error will be registered globally
    624      * and the execution will continue as if a "throw" statement was
    625      * encountered.
    626      * @param e Type of error.
    627      * @param m Optional error message.
    628      * @param l Optional line number.
    629      */
    630     static KJSO create(ErrorType e, const char *m = 0, int l = -1);
    631     /**
    632      * Same as above except the different return type (which is not casted
    633      * here).
    634      */
    635     static Object createObject(ErrorType e, const char *m = 0, int l = -1);
     594     * Factory method for error objects.
     595     *
     596     * @param exec The current execution state
     597     * @param errtype Type of error.
     598     * @param message Optional error message.
     599     * @param lineno Optional line number.
     600     * @param lineno Optional source id.
     601     */
     602    static Object create(ExecState *exec, ErrorType errtype = GeneralError,
     603                         const char *message = 0, int lineno = -1,
     604                         int sourceId = -1);
     605
     606    /**
     607     * Array of error names corresponding to @ref ErrorType
     608     */
     609    static const char * const * const errorNames;
    636610  };
    637611
    638612}; // namespace
    639613
    640 #endif
     614#endif // _KJS_OBJECT_H_
  • trunk/JavaScriptCore/kjs/object_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 *
     20 *  $Id$
    1821 */
    1922
    20 #include "kjs.h"
     23#include "value.h"
     24#include "object.h"
     25#include "types.h"
     26#include "interpreter.h"
    2127#include "operations.h"
    2228#include "object_object.h"
    23 #include "types.h"
     29#include "function_object.h"
    2430#include <stdio.h>
     31#include <assert.h>
    2532
    2633using namespace KJS;
    2734
    28 ObjectObject::ObjectObject(const Object &funcProto, const Object &objProto)
    29     : ConstructorImp(funcProto, 1)
     35// ------------------------------ ObjectPrototypeImp --------------------------------
     36
     37ObjectPrototypeImp::ObjectPrototypeImp(ExecState *exec,
     38                                       FunctionPrototypeImp *funcProto)
     39  : ObjectImp() // [[Prototype]] is Null()
    3040{
    31   // ECMA 15.2.3.1
    32   setPrototypeProperty(objProto);
     41  Value protect(this);
     42  put(exec,"toString", Object(new ObjectProtoFuncImp(exec,funcProto,ObjectProtoFuncImp::ToString, 0)), DontEnum);
     43  put(exec,"valueOf",  Object(new ObjectProtoFuncImp(exec,funcProto,ObjectProtoFuncImp::ValueOf,  0)), DontEnum);
    3344}
    3445
    35 Completion ObjectObject::execute(const List &args)
     46
     47// ------------------------------ ObjectProtoFuncImp --------------------------------
     48
     49ObjectProtoFuncImp::ObjectProtoFuncImp(ExecState *exec,
     50                                       FunctionPrototypeImp *funcProto,
     51                                       int i, int len)
     52  : InternalFunctionImp(funcProto), id(i)
    3653{
    37   KJSO result;
     54  Value protect(this);
     55  put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
     56}
    3857
    39   List argList;
    40   if (args.isEmpty()) {
    41     result = construct(argList);
    42   } else {
    43     KJSO arg = args[0];
    44     if (arg.isA(NullType) || arg.isA(UndefinedType)) {
    45       argList.append(arg);
    46       result = construct(argList);
    47     } else
    48       result = arg.toObject();
    49   }
    50   return Completion(ReturnValue, result);
     58
     59bool ObjectProtoFuncImp::implementsCall() const
     60{
     61  return true;
     62}
     63
     64// ECMA 15.2.4.2 + 15.2.4.3
     65
     66Value ObjectProtoFuncImp::call(ExecState */*exec*/, Object &thisObj, const List &/*args*/)
     67{
     68  if (id == ValueOf)
     69    return thisObj;
     70  else /* ToString */
     71    return String("[object "+thisObj.className()+"]");
     72}
     73
     74// ------------------------------ ObjectObjectImp --------------------------------
     75
     76ObjectObjectImp::ObjectObjectImp(ExecState *exec,
     77                                 ObjectPrototypeImp *objProto,
     78                                 FunctionPrototypeImp *funcProto)
     79  : InternalFunctionImp(funcProto)
     80{
     81  Value protect(this);
     82  // ECMA 15.2.3.1
     83  put(exec,"prototype", Object(objProto), DontEnum|DontDelete|ReadOnly);
     84
     85  // no. of arguments for constructor
     86  put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum);
     87}
     88
     89
     90bool ObjectObjectImp::implementsConstruct() const
     91{
     92  return true;
    5193}
    5294
    5395// ECMA 15.2.2
    54 Object ObjectObject::construct(const List &args)
     96Object ObjectObjectImp::construct(ExecState *exec, const List &args)
    5597{
    5698  // if no arguments have been passed ...
    57   if (args.isEmpty())
    58     return Object::create(ObjectClass);
     99  if (args.isEmpty()) {
     100    Object proto = exec->interpreter()->builtinObjectPrototype();
     101    Object result(new ObjectImp(proto));
     102    return result;
     103  }
    59104
    60   KJSO arg = *args.begin();
     105  Value arg = *(args.begin());
    61106  Object obj = Object::dynamicCast(arg);
    62107  if (!obj.isNull()) {
    63     /* TODO: handle host objects */
    64108    return obj;
    65109  }
     
    69113  case BooleanType:
    70114  case NumberType:
    71     return arg.toObject();
     115    return arg.toObject(exec);
    72116  default:
    73117    assert(!"unhandled switch case in ObjectConstructor");
    74118  case NullType:
    75119  case UndefinedType:
    76     return Object::create(ObjectClass);
     120    Object proto = exec->interpreter()->builtinObjectPrototype();
     121    return Object(new ObjectImp(proto));
    77122  }
    78123}
    79124
    80 ObjectPrototype::ObjectPrototype()
    81   : ObjectImp(ObjectClass)
     125bool ObjectObjectImp::implementsCall() const
    82126{
    83   // the spec says that [[Property]] should be `null'.
    84   // Not sure if Null or C's NULL is needed.
     127  return true;
    85128}
    86129
    87 bool ObjectPrototype::hasProperty(const UString &p, bool recursive) const
     130Value ObjectObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
    88131{
    89     if ( p == "toString" || p == "valueOf" )
    90         return true;
    91     return /*recursive &&*/ ObjectImp::hasProperty(p, recursive);
     132  Value result;
     133
     134  List argList;
     135  // Construct a new Object
     136  if (args.isEmpty()) {
     137    result = construct(exec,argList);
     138  } else {
     139    Value arg = args[0];
     140    if (arg.type() == NullType || arg.type() == UndefinedType) {
     141      argList.append(arg);
     142      result = construct(exec,argList);
     143    } else
     144      result = arg.toObject(exec);
     145  }
     146  return result;
    92147}
    93148
    94 KJSO ObjectPrototype::get(const UString &p) const
    95 {
    96   if (p == "toString")
    97     return Function(new ObjectProtoFunc(ToString));
    98   else if (p == "valueOf")
    99     return Function(new ObjectProtoFunc(ValueOf));
    100   else
    101     return Imp::get(p);
    102 }
    103 
    104 ObjectProtoFunc::ObjectProtoFunc(int i)
    105   : id(i)
    106 {
    107 }
    108 
    109 // ECMA 15.2.4.2 + 15.2.4.3
    110 Completion ObjectProtoFunc::execute(const List &)
    111 {
    112   Object thisObj = Object::dynamicCast(thisValue());
    113 
    114   /* TODO: what to do with non-objects. Is this possible at all ? */
    115   // Yes, this happens with Host Object at least (David)
    116   if (thisObj.isNull()) {
    117     UString str = "[object ";
    118     str += thisValue().isNull() ? "null" : thisValue().imp()->typeInfo()->name;
    119     str += "]";
    120     return Completion(ReturnValue, String(str));
    121   }
    122 
    123   // valueOf()
    124   if (id == ObjectPrototype::ValueOf)
    125     /* TODO: host objects*/
    126     return Completion(ReturnValue, thisObj);
    127 
    128   // toString()
    129   UString str;
    130   switch(thisObj.getClass()) {
    131   case StringClass:
    132     str = "[object String]";
    133     break;
    134   case BooleanClass:
    135     str = "[object Boolean]";
    136     break;
    137   case NumberClass:
    138     str = "[object Number]";
    139     break;
    140   case ObjectClass:
    141   {
    142     str = "[object ";
    143     str += thisValue().isNull() ? "Object" : thisValue().imp()->typeInfo()->name;
    144     str += "]";
    145     break;
    146   }
    147   default:
    148     str = "[undefined object]";
    149   }
    150 
    151   return Completion(ReturnValue, String(str));
    152 }
  • trunk/JavaScriptCore/kjs/object_object.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2124#define _OBJECT_OBJECT_H_
    2225
    23 #include "object.h"
    24 #include "function.h"
     26#include "internal.h"
    2527
    2628namespace KJS {
    2729
    28   class ObjectObject : public ConstructorImp {
     30  class FunctionPrototypeImp;
     31
     32  /**
     33   * @internal
     34   *
     35   * The initial value of Object.prototype (and thus all objects created
     36   * with the Object constructor
     37   */
     38  class ObjectPrototypeImp : public ObjectImp {
    2939  public:
    30     ObjectObject(const Object &funcProto, const Object &objProto);
    31     Completion execute(const List &);
    32     Object construct(const List &);
     40    ObjectPrototypeImp(ExecState *exec, FunctionPrototypeImp *funcProto);
    3341  };
    3442
    35   class ObjectPrototype : public ObjectImp {
     43  /**
     44   * @internal
     45   *
     46   * Class to implement all methods that are properties of the
     47   * Object.prototype object
     48   */
     49  class ObjectProtoFuncImp : public InternalFunctionImp {
    3650  public:
    37     ObjectPrototype();
    38     bool hasProperty(const UString &p, bool recursive) const;
    39     KJSO get(const UString &p) const;
     51    ObjectProtoFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto,
     52                       int i, int len);
     53
     54    virtual bool implementsCall() const;
     55    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     56
    4057    enum { ToString, ValueOf };
     58  private:
     59    int id;
    4160  };
    4261
    43   class ObjectProtoFunc : public InternalFunctionImp {
     62  /**
     63   * @internal
     64   *
     65   * The initial value of the the global variable's "Object" property
     66   */
     67  class ObjectObjectImp : public InternalFunctionImp {
    4468  public:
    45     ObjectProtoFunc(int i);
    46     Completion execute(const List &);
    47   private:
    48     int id;
     69
     70    ObjectObjectImp(ExecState *exec,
     71                    ObjectPrototypeImp *objProto,
     72                    FunctionPrototypeImp *funcProto);
     73
     74    virtual bool implementsConstruct() const;
     75    virtual Object construct(ExecState *exec, const List &args);
     76    virtual bool implementsCall() const;
     77    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
    4978  };
    5079
  • trunk/JavaScriptCore/kjs/operations.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
     
    1718 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1819 *  Boston, MA 02111-1307, USA.
     20 *
    1921 */
    2022
     
    4244#endif
    4345
     46#include "operations.h"
    4447#include "object.h"
    45 #include "types.h"
    46 #include "operations.h"
    4748
    4849using namespace KJS;
     
    7273}
    7374
     75bool KJS::isPosInf(double d)
     76{
     77#if defined(HAVE_FUNC_ISINF)
     78  return (isinf(d) == 1);
     79#elif HAVE_FUNC_FINITE
     80  return finite(d) == 0 && d == d; // ### can we distinguish between + and - ?
     81#elif HAVE_FUNC__FINITE
     82  return _finite(d) == 0 && d == d; // ###
     83#else
     84  return false;
     85#endif
     86}
     87
     88bool KJS::isNegInf(double d)
     89{
     90#if defined(HAVE_FUNC_ISINF)
     91  return (isinf(d) == -1);
     92#elif HAVE_FUNC_FINITE
     93  return finite(d) == 0 && d == d; // ###
     94#elif HAVE_FUNC__FINITE
     95  return _finite(d) == 0 && d == d; // ###
     96#else
     97  return false;
     98#endif
     99}
     100
    74101// ECMA 11.9.3
    75 bool KJS::equal(const KJSO& v1, const KJSO& v2)
     102bool KJS::equal(ExecState *exec, const Value& v1, const Value& v2)
    76103{
    77104  Type t1 = v1.type();
     
    82109      return true;
    83110    if (t1 == NumberType)
    84       return (v1.toNumber().value() == v2.toNumber().value()); /* TODO: NaN, -0 ? */
     111    {
     112      double d1 = v1.toNumber(exec);
     113      double d2 = v2.toNumber(exec);
     114      if ( isNaN( d1 ) || isNaN( d2 ) )
     115        return false;
     116      return ( d1 == d2 ); /* TODO: +0, -0 ? */
     117    }
    85118    if (t1 == StringType)
    86       return (v1.toString().value() == v2.toString().value());
     119      return (v1.toString(exec) == v2.toString(exec));
    87120    if (t1 == BooleanType)
    88       return (v1.toBoolean().value() == v2.toBoolean().value());
    89     if (t1 == HostType) {
    90         KJSO h1 = v1.get("[[==]]");
    91         KJSO h2 = v2.get("[[==]]");
    92         if (!h1.isA(UndefinedType) && !h2.isA(UndefinedType))
    93             return equal(h1, h2);
    94     }
     121      return (v1.toBoolean(exec) == v2.toBoolean(exec));
     122
     123    // types are Object
    95124    return (v1.imp() == v2.imp());
    96125  }
     
    100129    return true;
    101130  if (t1 == NumberType && t2 == StringType) {
    102     Number n2 = v2.toNumber();
    103     return equal(v1, n2);
     131    Number n2 = v2.toNumber(exec);
     132    return equal(exec,v1, n2);
    104133  }
    105134  if ((t1 == StringType && t2 == NumberType) || t1 == BooleanType) {
    106     Number n1 = v1.toNumber();
    107     return equal(n1, v2);
     135    Number n1 = v1.toNumber(exec);
     136    return equal(exec,n1, v2);
    108137  }
    109138  if (t2 == BooleanType) {
    110     Number n2 = v2.toNumber();
    111     return equal(v1, n2);
     139    Number n2 = v2.toNumber(exec);
     140    return equal(exec,v1, n2);
    112141  }
    113142  if ((t1 == StringType || t1 == NumberType) && t2 >= ObjectType) {
    114     KJSO p2 = v2.toPrimitive();
    115     return equal(v1, p2);
     143    Value p2 = v2.toPrimitive(exec);
     144    return equal(exec,v1, p2);
    116145  }
    117146  if (t1 >= ObjectType && (t2 == StringType || t2 == NumberType)) {
    118     KJSO p1 = v1.toPrimitive();
    119     return equal(p1, v2);
    120   }
    121 
    122   return false;
    123 }
    124 
    125 bool KJS::strictEqual(const KJSO &v1, const KJSO &v2)
     147    Value p1 = v1.toPrimitive(exec);
     148    return equal(exec,p1, v2);
     149  }
     150
     151  return false;
     152}
     153
     154bool KJS::strictEqual(ExecState *exec, const Value &v1, const Value &v2)
    126155{
    127156  Type t1 = v1.type();
     
    133162    return true;
    134163  if (t1 == NumberType) {
    135     double n1 = v1.toNumber().value();
    136     double n2 = v2.toNumber().value();
     164    double n1 = v1.toNumber(exec);
     165    double n2 = v2.toNumber(exec);
    137166    if (isNaN(n1) || isNaN(n2))
    138167      return false;
     
    142171    return false;
    143172  } else if (t1 == StringType) {
    144     return v1.toString().value() == v2.toString().value();
     173    return v1.toString(exec) == v2.toString(exec);
    145174  } else if (t2 == BooleanType) {
    146     return v1.toBoolean().value() == v2.toBoolean().value();
     175    return v1.toBoolean(exec) == v2.toBoolean(exec);
    147176  }
    148177  if (v1.imp() == v2.imp())
     
    153182}
    154183
    155 int KJS::relation(const KJSO& v1, const KJSO& v2)
    156 {
    157   KJSO p1 = v1.toPrimitive(NumberType);
    158   KJSO p2 = v2.toPrimitive(NumberType);
    159 
    160   if (p1.isA(StringType) && p2.isA(StringType))
    161     return p1.toString().value() < p2.toString().value() ? 1 : 0;
    162 
    163   Number n1 = p1.toNumber();
    164   Number n2 = p2.toNumber();
    165   /* TODO: check for NaN */
    166   if (n1.value() == n2.value())
     184int KJS::relation(ExecState *exec, const Value& v1, const Value& v2)
     185{
     186  Value p1 = v1.toPrimitive(exec,NumberType);
     187  Value p2 = v2.toPrimitive(exec,NumberType);
     188
     189  if (p1.type() == StringType && p2.type() == StringType)
     190    return p1.toString(exec) < p2.toString(exec) ? 1 : 0;
     191
     192  double n1 = p1.toNumber(exec);
     193  double n2 = p2.toNumber(exec);
     194  if ( isNaN( n1 ) || isNaN( n2 ) )
     195    return -1; // means undefined
     196  if (n1 == n2)
    167197    return 0;
    168   /* TODO: +0, -0 and Infinity */
    169   return (n1.value() < n2.value());
    170 }
    171 
    172 double KJS::max(double d1, double d2)
    173 {
    174   /* TODO: check for NaN */
     198  /* TODO: +0, -0 */
     199  if ( isPosInf( n1 ) )
     200    return 0;
     201  if ( isPosInf( n2 ) )
     202    return 1;
     203  if ( isNegInf( n2 ) )
     204    return 0;
     205  if ( isNegInf( n1 ) )
     206    return 1;
     207  return (n1 < n2) ? 1 : 0;
     208}
     209
     210int KJS::maxInt(int d1, int d2)
     211{
    175212  return (d1 > d2) ? d1 : d2;
    176213}
    177214
    178 double KJS::min(double d1, double d2)
    179 {
    180   /* TODO: check for NaN */
     215int KJS::minInt(int d1, int d2)
     216{
    181217  return (d1 < d2) ? d1 : d2;
    182218}
    183219
    184220// ECMA 11.6
    185 KJSO KJS::add(const KJSO &v1, const KJSO &v2, char oper)
    186 {
    187   KJSO p1 = v1.toPrimitive();
    188   KJSO p2 = v2.toPrimitive();
    189 
    190   if ((p1.isA(StringType) || p2.isA(StringType)) && oper == '+') {
    191     String s1 = p1.toString();
    192     String s2 = p2.toString();
    193 
    194     UString s = s1.value() + s2.value();
    195 
    196     return String(s);
    197   }
    198 
    199   Number n1 = p1.toNumber();
    200   Number n2 = p2.toNumber();
     221Value KJS::add(ExecState *exec, const Value &v1, const Value &v2, char oper)
     222{
     223  Value p1 = v1.toPrimitive(exec);
     224  Value p2 = v2.toPrimitive(exec);
     225
     226  if ((p1.type() == StringType || p2.type() == StringType) && oper == '+') {
     227    UString s1 = p1.toString(exec);
     228    UString s2 = p2.toString(exec);
     229
     230    return String(s1 + s2);
     231  }
     232
     233  double n1 = p1.toNumber(exec);
     234  double n2 = p2.toNumber(exec);
    201235
    202236  if (oper == '+')
    203     return Number(n1.value() + n2.value());
     237    return Number(n1 + n2);
    204238  else
    205     return Number(n1.value() - n2.value());
     239    return Number(n1 - n2);
    206240}
    207241
    208242// ECMA 11.5
    209 KJSO KJS::mult(const KJSO &v1, const KJSO &v2, char oper)
    210 {
    211   Number n1 = v1.toNumber();
    212   Number n2 = v2.toNumber();
     243Value KJS::mult(ExecState *exec, const Value &v1, const Value &v2, char oper)
     244{
     245  Number n1 = v1.toNumber(exec);
     246  Number n2 = v2.toNumber(exec);
    213247
    214248  double result;
  • trunk/JavaScriptCore/kjs/operations.h

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
     
    1718 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1819 *  Boston, MA 02111-1307, USA.
     20 *
     21 *  $Id$
    1922 */
    2023
     
    2225#define _KJS_OPERATIONS_H_
    2326
    24 #include "object.h"
     27#include "value.h"
    2528
    2629namespace KJS {
     30
     31  class ExecState;
    2732
    2833  /**
     
    3439   */
    3540  bool isInf(double d);
    36   bool equal(const KJSO& v1, const KJSO& v2);
    37   bool strictEqual(const KJSO &v1, const KJSO &v2);
     41  bool isPosInf(double d);
     42  bool isNegInf(double d);
     43  bool equal(ExecState *exec, const Value& v1, const Value& v2);
     44  bool strictEqual(ExecState *exec, const Value &v1, const Value &v2);
    3845  /**
    3946   * This operator performs an abstract relational comparision of the two
     
    4451   * equal". -1 if the result is undefined.
    4552   */
    46   int relation(const KJSO& v1, const KJSO& v2);
    47   double max(double d1, double d2);
    48   double min(double d1, double d2);
     53  int relation(ExecState *exec, const Value& v1, const Value& v2);
     54  int maxInt(int d1, int d2);
     55  int minInt(int d1, int d2);
    4956  /**
    5057   * Additive operator. Either performs an addition or substraction of v1
     
    5360   * @return The result of the operation.
    5461   */
    55   KJSO add(const KJSO &v1, const KJSO &v2, char oper);
     62  Value add(ExecState *exec, const Value &v1, const Value &v2, char oper);
    5663  /**
    5764   * Multiplicative operator. Either multiplies/divides v1 and v2 or
     
    6168   * @return The result of the operation.
    6269   */
    63   KJSO mult(const KJSO &v1, const KJSO &v2, char oper);
     70  Value mult(ExecState *exec, const Value &v1, const Value &v2, char oper);
    6471
    6572};
  • trunk/JavaScriptCore/kjs/regexp.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 *
     20 *  $Id$
    1821 */
    1922
    2023#include <stdio.h>
     24#include <stdlib.h>
     25#include <string.h>
    2126
    22 #include "object.h"
    2327#include "regexp.h"
    2428
     
    2630
    2731RegExp::RegExp(const UString &p, int f)
    28  : pattern(p), flags(f)
     32  : pattern(p), flags(f)
    2933{
    30 #ifdef REG_EXTENDED   
    31   regcomp(&preg, p.ascii(), REG_EXTENDED);
    32 #else
    33   regcomp(&preg, p.ascii(), 0); 
    34 #endif 
    35   /* TODO use flags, check for errors */
     34
     35#ifdef HAVE_PCREPOSIX
     36  int pcreflags = 0;
     37  const char *perrormsg;
     38  int errorOffset;
     39
     40  if (flags & IgnoreCase)
     41    pcreflags |= PCRE_CASELESS;
     42
     43  if (flags & Multiline)
     44    pcreflags |= PCRE_MULTILINE;
     45
     46  pcregex = pcre_compile(p.ascii(), pcreflags,
     47                         &perrormsg, &errorOffset, NULL);
     48
     49#ifdef PCRE_INFO_CAPTURECOUNT
     50  // Get number of subpatterns that will be returned
     51  int rc = pcre_fullinfo( pcregex, NULL, PCRE_INFO_CAPTURECOUNT, &nrSubPatterns);
     52  if (rc != 0)
     53#endif
     54    nrSubPatterns = 0; // fallback. We always need the first pair of offsets.
     55
     56#else /* HAVE_PCREPOSIX */
     57
     58  nrSubPatterns = 0; // not implemented with POSIX regex.
     59  int regflags = 0;
     60#ifdef REG_EXTENDED
     61  regflags |= REG_EXTENDED;
     62#endif
     63#ifdef REG_ICASE
     64  if ( f & IgnoreCase )
     65    regflags |= REG_ICASE;
     66#endif
     67
     68  //NOTE: Multiline is not feasible with POSIX regex.
     69  //if ( f & Multiline )
     70  //    ;
     71  // Note: the Global flag is already handled by RegExpProtoFunc::execute
     72
     73  regcomp(&preg, p.ascii(), regflags);
     74  /* TODO check for errors */
     75#endif
     76
    3677}
    3778
    3879RegExp::~RegExp()
    3980{
     81#ifdef HAVE_PCREPOSIX
     82  pcre_free(pcregex);
     83
     84#else
    4085  /* TODO: is this really okay after an error ? */
    4186  regfree(&preg);
     87#endif
    4288}
    4389
    44 UString RegExp::match(const UString &s, int i, int *pos)
     90UString RegExp::match(const UString &s, int i, int *pos, int **ovector)
    4591{
     92
     93#ifdef HAVE_PCREPOSIX
     94  CString buffer(s.cstring());
     95  int ovecsize = (nrSubPatterns+1)*3; // see pcre docu
     96  if (ovector) *ovector = new int[ovecsize];
     97
     98  if (i < 0)
     99    i = 0;
     100
     101  if (i > s.size() || s.isNull() ||
     102      pcre_exec(pcregex, NULL, buffer.c_str(), buffer.size(), i,
     103                0, ovector ? *ovector : 0L, ovecsize) == PCRE_ERROR_NOMATCH) {
     104
     105    if (pos)
     106       *pos = -1;
     107    return UString::null;
     108  }
     109
     110  if (!ovector)
     111    return UString::null; // don't rely on the return value if you pass ovector==0
     112  if (pos)
     113     *pos = (*ovector)[0];
     114  return s.substr((*ovector)[0], (*ovector)[1] - (*ovector)[0]);
     115
     116#else
    46117  regmatch_t rmatch[10];
    47118
     
    49120    i = 0;
    50121
     122  char *str = strdup(s.ascii());
    51123  if (i > s.size() || s.isNull() ||
    52       regexec(&preg, s.ascii() + i, 10, rmatch, 0)) {
     124      regexec(&preg, str + i, 10, rmatch, 0)) {
    53125    if (pos)
    54       *pos = -1;
     126       *pos = -1;
    55127    return UString::null;
    56128  }
     129  free(str);
    57130
    58131  if (pos)
    59     *pos = rmatch[0].rm_so + i;
     132     *pos = rmatch[0].rm_so + i;
     133  // TODO copy from rmatch to ovector
    60134  return s.substr(rmatch[0].rm_so + i, rmatch[0].rm_eo - rmatch[0].rm_so);
     135#endif
    61136}
    62137
     138#if 0 // unused
    63139bool RegExp::test(const UString &s, int)
    64140{
    65   int r = regexec(&preg, s.ascii(), 0, 0, 0);
     141#ifdef HAVE_PCREPOSIX
     142  int ovector[300];
     143  CString buffer(s.cstring());
     144
     145  if (s.isNull() ||
     146      pcre_exec(pcregex, NULL, buffer.c_str(), buffer.size(), 0,
     147                0, ovector, 300) == PCRE_ERROR_NOMATCH)
     148    return false;
     149  else
     150    return true;
     151
     152#else
     153
     154  char *str = strdup(s.ascii());
     155  int r = regexec(&preg, str, 0, 0, 0);
     156  free(str);
    66157
    67158  return r == 0;
     159#endif
    68160}
     161#endif
  • trunk/JavaScriptCore/kjs/regexp.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2730#ifdef HAVE_PCREPOSIX
    2831#include <pcreposix.h>
     32#include <pcre.h>
    2933#else  // POSIX regex - not so good...
    3034extern "C" { // bug with some libc5 distributions
     
    3943  class RegExp {
    4044  public:
    41     enum { None, Global, IgnoreCase, Multiline };
     45    enum { None = 0, Global = 1, IgnoreCase = 2, Multiline = 4 };
    4246    RegExp(const UString &p, int f = None);
    4347    ~RegExp();
    44     UString match(const UString &s, int i = -1, int *pos = 0L);
    45     bool test(const UString &s, int i = -1);
     48    UString match(const UString &s, int i = -1, int *pos = 0L, int **ovector = 0L);
     49    // test is unused. The JS spec says that RegExp.test should use
     50    // RegExp.exec, so it has to store $1 etc.
     51    // bool test(const UString &s, int i = -1);
     52    uint subPatterns() const { return nrSubPatterns; }
    4653  private:
    4754    const UString &pattern;
    4855    int flags;
     56
     57#ifndef HAVE_PCREPOSIX
    4958    regex_t preg;
     59#else
     60    pcre *pcregex;
     61#endif
     62    uint nrSubPatterns;
    5063
    5164    RegExp();
  • trunk/JavaScriptCore/kjs/regexp_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 *
     20 *  $Id$
    1821 */
    1922
    2023#include <stdio.h>
    2124
    22 #include "kjs.h"
     25#include "value.h"
     26#include "object.h"
     27#include "types.h"
     28#include "interpreter.h"
    2329#include "operations.h"
    24 #include "types.h"
    2530#include "internal.h"
    2631#include "regexp.h"
    2732#include "regexp_object.h"
     33#include "error_object.h"
    2834
    2935using namespace KJS;
    3036
    31 RegExpObject::RegExpObject(const Object& funcProto, const Object &regProto)
    32     : ConstructorImp(funcProto, 2)
    33 {
     37// ------------------------------ RegExpPrototypeImp ---------------------------
     38
     39// ECMA 15.9.4
     40
     41RegExpPrototypeImp::RegExpPrototypeImp(ExecState *exec,
     42                                       ObjectPrototypeImp *objProto,
     43                                       FunctionPrototypeImp *funcProto)
     44  : ObjectImp(Object(objProto))
     45{
     46  Value protect(this);
     47  setInternalValue(String(""));
     48
     49  // The constructor will be added later in RegExpObject's constructor (?)
     50
     51  put(exec, "exec",     Object(new RegExpProtoFuncImp(exec,funcProto,RegExpProtoFuncImp::Exec,     0)), DontEnum);
     52  put(exec, "test",     Object(new RegExpProtoFuncImp(exec,funcProto,RegExpProtoFuncImp::Test,     0)), DontEnum);
     53  put(exec, "toString", Object(new RegExpProtoFuncImp(exec,funcProto,RegExpProtoFuncImp::ToString, 0)), DontEnum);
     54}
     55
     56// ------------------------------ RegExpProtoFuncImp ---------------------------
     57
     58RegExpProtoFuncImp::RegExpProtoFuncImp(ExecState *exec,
     59                                       FunctionPrototypeImp *funcProto, int i, int len)
     60  : InternalFunctionImp(funcProto), id(i)
     61{
     62  Value protect(this);
     63  put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
     64}
     65
     66bool RegExpProtoFuncImp::implementsCall() const
     67{
     68  return true;
     69}
     70
     71Value RegExpProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
     72{
     73  if (!thisObj.inherits(&RegExpImp::info)) {
     74    Object err = Error::create(exec,TypeError);
     75    exec->setException(err);
     76    return err;
     77  }
     78
     79  RegExpImp *reimp = static_cast<RegExpImp*>(thisObj.imp());
     80  RegExp *re = reimp->regExp();
     81  String s;
     82  UString str;
     83  switch (id) {
     84  case Exec:      // 15.10.6.2
     85  case Test:
     86  {
     87    s = args[0].toString(exec);
     88    int length = s.value().size();
     89    Value lastIndex = thisObj.get(exec,"lastIndex");
     90    int i = lastIndex.isNull() ? 0 : lastIndex.toInt32(exec);
     91    bool globalFlag = thisObj.get(exec,"global").toBoolean(exec);
     92    if (!globalFlag)
     93      i = 0;
     94    if (i < 0 || i > length) {
     95      thisObj.put(exec,"lastIndex", Number(0), DontDelete | DontEnum);
     96      return Null();
     97    }
     98    RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp());
     99    int **ovector = regExpObj->registerRegexp( re, s.value() );
     100
     101    str = re->match(s.value(), i, 0L, ovector);
     102
     103    if (id == Test)
     104      return Boolean(!str.isNull());
     105
     106    if (str.isNull()) // no match
     107    {
     108      if (globalFlag)
     109        thisObj.put(exec,"lastIndex",Number(0), DontDelete | DontEnum);
     110      return Null();
     111    }
     112    else // success
     113    {
     114      if (globalFlag)
     115        thisObj.put(exec,"lastIndex",Number( (*ovector)[1] ), DontDelete | DontEnum);
     116      return regExpObj->arrayOfMatches(exec,str);
     117    }
     118  }
     119  break;
     120  case ToString:
     121    s = thisObj.get(exec,"source").toString(exec);
     122    str = "/";
     123    str += s.value();
     124    str += "/";
     125    // TODO append the flags
     126    return String(str);
     127  }
     128
     129  return Undefined();
     130}
     131
     132// ------------------------------ RegExpImp ------------------------------------
     133
     134const ClassInfo RegExpImp::info = {"RegExp", 0, 0, 0};
     135
     136RegExpImp::RegExpImp(RegExpPrototypeImp *regexpProto)
     137  : ObjectImp(Object(regexpProto)), reg(0L)
     138{
     139}
     140
     141RegExpImp::~RegExpImp()
     142{
     143  delete reg;
     144}
     145
     146// ------------------------------ RegExpObjectImp ------------------------------
     147
     148RegExpObjectImp::RegExpObjectImp(ExecState *exec,
     149                                 RegExpPrototypeImp *regProto,
     150                                 FunctionPrototypeImp *funcProto)
     151  : InternalFunctionImp(funcProto), lastOvector(0L), lastNrSubPatterns(0)
     152{
     153  Value protect(this);
    34154  // ECMA 15.10.5.1 RegExp.prototype
    35   setPrototypeProperty(regProto);
    36 }
    37 
    38 // ECMA 15.9.2
    39 Completion RegExpObject::execute(const List &)
    40 {
    41   return Completion(ReturnValue, Undefined());
    42 }
    43 
    44 // ECMA 15.9.3
    45 Object RegExpObject::construct(const List &args)
    46 {
    47   /* TODO: regexp arguments */
    48   String p = args[0].toString();
    49   String f = args[1].toString();
     155  put(exec,"prototype", Object(regProto), DontEnum|DontDelete|ReadOnly);
     156
     157  // no. of arguments for constructor
     158  put(exec,"length", Number(2), ReadOnly|DontDelete|DontEnum);
     159}
     160
     161RegExpObjectImp::~RegExpObjectImp()
     162{
     163  if (lastOvector)
     164    delete [] lastOvector;
     165}
     166
     167int **RegExpObjectImp::registerRegexp( const RegExp* re, const UString& s )
     168{
     169  lastString = s;
     170  if (lastOvector)
     171    delete [] lastOvector;
     172  lastOvector = 0;
     173  lastNrSubPatterns = re->subPatterns();
     174  return &lastOvector;
     175}
     176
     177Value RegExpObjectImp::arrayOfMatches(ExecState *exec, const UString &result) const
     178{
     179  List list;
     180  // The returned array contains 'result' as first item, followed by the list of matches
     181  list.append(String(result));
     182  if ( lastOvector )
     183    for ( uint i = 1 ; i < lastNrSubPatterns + 1 ; ++i )
     184    {
     185      UString substring = lastString.substr( lastOvector[2*i], lastOvector[2*i+1] - lastOvector[2*i] );
     186      list.append(String(substring));
     187    }
     188  return exec->interpreter()->builtinArray().construct(exec, list);
     189}
     190
     191Value RegExpObjectImp::get(ExecState *, const UString &p) const
     192{
     193  if (p[0] == '$' && lastOvector)
     194  {
     195    bool ok;
     196    unsigned long i = p.substr(1).toULong(&ok);
     197    if (ok)
     198    {
     199      if (i < lastNrSubPatterns + 1)
     200      {
     201        UString substring = lastString.substr( lastOvector[2*i], lastOvector[2*i+1] - lastOvector[2*i] );
     202        return String(substring);
     203      }
     204      return String("");
     205    }
     206  }
     207  return Undefined();
     208}
     209
     210bool RegExpObjectImp::implementsConstruct() const
     211{
     212  return true;
     213}
     214
     215// ECMA 15.10.4
     216Object RegExpObjectImp::construct(ExecState *exec, const List &args)
     217{
     218  String p = args[0].toString(exec);
     219  String f = args[1].toString(exec);
    50220  UString flags = f.value();
    51221
    52   RegExpImp *dat = new RegExpImp();
     222  RegExpPrototypeImp *proto = static_cast<RegExpPrototypeImp*>(exec->interpreter()->builtinRegExpPrototype().imp());
     223  RegExpImp *dat = new RegExpImp(proto);
    53224  Object obj(dat); // protect from GC
    54225
     
    56227  bool ignoreCase = (flags.find("i") >= 0);
    57228  bool multiline = (flags.find("m") >= 0);
    58   /* TODO: throw an error on invalid flags */
    59 
    60   dat->put("global", Boolean(global));
    61   dat->put("ignoreCase", Boolean(ignoreCase));
    62   dat->put("multiline", Boolean(multiline));
    63 
    64   dat->put("source", String(p.value()));
    65   dat->put("lastIndex", 0, DontDelete | DontEnum);
    66 
    67   dat->setRegExp(new RegExp(p.value() /* TODO flags */));
    68   obj.setClass(RegExpClass);
    69   obj.setPrototype(Global::current().get("[[RegExp.prototype]]"));
     229  // TODO: throw a syntax error on invalid flags
     230
     231  dat->put(exec, "global", Boolean(global));
     232  dat->put(exec, "ignoreCase", Boolean(ignoreCase));
     233  dat->put(exec, "multiline", Boolean(multiline));
     234
     235  dat->put(exec, "source", String(p.value()));
     236  dat->put(exec, "lastIndex", Number(0), DontDelete | DontEnum);
     237
     238  int reflags = RegExp::None;
     239  if (global)
     240      reflags |= RegExp::Global;
     241  if (ignoreCase)
     242      reflags |= RegExp::IgnoreCase;
     243  if (multiline)
     244      reflags |= RegExp::Multiline;
     245  dat->setRegExp(new RegExp(p.value(), reflags));
    70246
    71247  return obj;
    72248}
    73249
    74 // ECMA 15.9.4
    75 RegExpPrototype::RegExpPrototype(const Object& proto)
    76   : ObjectImp(RegExpClass, String(""), proto)
    77 {
    78   // The constructor will be added later in RegExpObject's constructor
    79 }
    80 
    81 KJSO RegExpPrototype::get(const UString &p) const
    82 {
    83   int id = -1;
    84   if (p == "exec")
    85     id = RegExpProtoFunc::Exec;
    86   else if (p == "test")
    87     id = RegExpProtoFunc::Test;
    88   else if (p == "toString")
    89     id = RegExpProtoFunc::ToString;
    90 
    91   if (id >= 0)
    92     return Function(new RegExpProtoFunc(id));
    93   else
    94     return Imp::get(p);
    95 }
    96 
    97 Completion RegExpProtoFunc::execute(const List &args)
    98 {
    99   KJSO result;
    100 
    101   Object thisObj = Object::dynamicCast(thisValue());
    102 
    103   if (thisObj.getClass() != RegExpClass) {
    104     result = Error::create(TypeError);
    105     return Completion(ReturnValue, result);
    106   }
    107 
    108   RegExp *re = static_cast<RegExpImp*>(thisObj.imp())->regExp();
    109   String s;
    110   KJSO lastIndex, tmp;
    111   UString str;
    112   int length, i;
    113   switch (id) {
    114   case Exec:
    115   case Test:
    116     s = args[0].toString();
    117     length = s.value().size();
    118     lastIndex = thisObj.get("lastIndex");
    119     i = lastIndex.toInt32();
    120     tmp = thisObj.get("global");
    121     if (tmp.toBoolean().value() == false)
    122       i = 0;
    123     if (i < 0 || i > length) {
    124       thisObj.put("lastIndex", 0);
    125       result = Null();
    126       break;
    127     }
    128     str = re->match(s.value(), i);
    129     if (id == Test) {
    130       result = Boolean(str.size() != 0);
    131       break;
    132     }
    133     /* TODO complete */
    134     result = String(str);
    135     break;
    136   case ToString:
    137     s = thisObj.get("source").toString();
    138     str = "/";
    139     str += s.value();
    140     str += "/";
    141     result = String(str);
    142     break;
    143   }
    144 
    145   return Completion(ReturnValue, result);
    146 }
     250bool RegExpObjectImp::implementsCall() const
     251{
     252  return true;
     253}
     254
     255// ECMA 15.10.3
     256Value RegExpObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/)
     257{
     258  // TODO: implement constructor
     259  return Undefined();
     260}
  • trunk/JavaScriptCore/kjs/regexp_object.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2124#define _REGEXP_OBJECT_H_
    2225
    23 #include "object.h"
    24 #include "function.h"
     26#include "internal.h"
     27#include "function_object.h"
     28#include "regexp.h"
    2529
    2630namespace KJS {
    27 
    28   class RegExpObject : public ConstructorImp {
     31  class ExecState;
     32  class RegExpPrototypeImp : public ObjectImp {
    2933  public:
    30     RegExpObject(const Object& funcProto, const Object &regProto);
    31     Completion execute(const List &);
    32     Object construct(const List &);
     34    RegExpPrototypeImp(ExecState *exec,
     35                       ObjectPrototypeImp *objProto,
     36                       FunctionPrototypeImp *funcProto);
    3337  };
    3438
    35   class RegExpPrototype : public ObjectImp {
     39  class RegExpProtoFuncImp : public InternalFunctionImp {
    3640  public:
    37     RegExpPrototype(const Object& proto);
    38     KJSO get(const UString &p) const;
    39   };
     41    RegExpProtoFuncImp(ExecState *exec,
     42                       FunctionPrototypeImp *funcProto, int i, int len);
    4043
    41   class RegExpProtoFunc : public InternalFunctionImp {
    42   public:
    43     RegExpProtoFunc(int i) : id(i) { }
    44     Completion execute(const List &);
     44    virtual bool implementsCall() const;
     45    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     46
    4547    enum { Exec, Test, ToString };
    4648  private:
     
    4850  };
    4951
     52  class RegExpImp : public ObjectImp {
     53  public:
     54    RegExpImp(RegExpPrototypeImp *regexpProto);
     55    ~RegExpImp();
     56    void setRegExp(RegExp *r) { reg = r; }
     57    RegExp* regExp() const { return reg; }
     58
     59    virtual const ClassInfo *classInfo() const { return &info; }
     60    static const ClassInfo info;
     61  private:
     62    RegExp *reg;
     63  };
     64
     65  class RegExpObjectImp : public InternalFunctionImp {
     66  public:
     67    RegExpObjectImp(ExecState *exec,
     68                    RegExpPrototypeImp *regProto,
     69                    FunctionPrototypeImp *funcProto);
     70    virtual ~RegExpObjectImp();
     71    virtual bool implementsConstruct() const;
     72    virtual Object construct(ExecState *exec, const List &args);
     73    virtual bool implementsCall() const;
     74    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     75
     76    Value get(ExecState *exec, const UString &p) const;
     77    int ** registerRegexp( const RegExp* re, const UString& s );
     78    Value arrayOfMatches(ExecState *exec, const UString &result) const;
     79  private:
     80    UString lastString;
     81    int *lastOvector;
     82    uint lastNrSubPatterns;
     83  };
     84
    5085}; // namespace
    5186
  • trunk/JavaScriptCore/kjs/string_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 "regexp.h"
     28#include "regexp_object.h"
    2429#include "string_object.h"
     30#include "error_object.h"
    2531#include <stdio.h>
     32#include "string_object.lut.h"
    2633
    2734using namespace KJS;
    2835
    29 StringObject::StringObject(const Object &funcProto, const Object &stringProto)
    30   : ConstructorImp(funcProto, 1)
    31 {
     36// ------------------------------ StringInstanceImp ----------------------------
     37
     38const ClassInfo StringInstanceImp::info = {"String", 0, 0, 0};
     39
     40StringInstanceImp::StringInstanceImp(const Object &proto)
     41  : ObjectImp(proto)
     42{
     43  setInternalValue(String(""));
     44}
     45
     46// ------------------------------ StringPrototypeImp ---------------------------
     47const ClassInfo StringPrototypeImp::info = {"String", &StringInstanceImp::info, &stringTable, 0};
     48/* Source for string_object.lut.h
     49@begin stringTable 26
     50  toString              StringProtoFuncImp::ToString    DontEnum|Function       0
     51  valueOf               StringProtoFuncImp::ValueOf     DontEnum|Function       0
     52  charAt                StringProtoFuncImp::CharAt      DontEnum|Function       1
     53  charCodeAt            StringProtoFuncImp::CharCodeAt  DontEnum|Function       1
     54  concat                StringProtoFuncImp::Concat      DontEnum|Function       1
     55  indexOf               StringProtoFuncImp::IndexOf     DontEnum|Function       2
     56  lastIndexOf           StringProtoFuncImp::LastIndexOf DontEnum|Function       2
     57  match                 StringProtoFuncImp::Match       DontEnum|Function       1
     58  replace               StringProtoFuncImp::Replace     DontEnum|Function       2
     59  search                StringProtoFuncImp::Search      DontEnum|Function       1
     60  slice                 StringProtoFuncImp::Slice       DontEnum|Function       0
     61  split                 StringProtoFuncImp::Split       DontEnum|Function       1
     62  substr                StringProtoFuncImp::Substr      DontEnum|Function       2
     63  substring             StringProtoFuncImp::Substring   DontEnum|Function       2
     64  toLowerCase           StringProtoFuncImp::ToLowerCase DontEnum|Function       0
     65  toUpperCase           StringProtoFuncImp::ToUpperCase DontEnum|Function       0
     66#
     67# Under here: html extension, should only exist if KJS_PURE_ECMA is not defined
     68# I guess we need to generate two hashtables in the .lut.h file, and use #ifdef
     69# to select the right one... TODO. #####
     70  big                   StringProtoFuncImp::Big         DontEnum|Function       0
     71  small                 StringProtoFuncImp::Small       DontEnum|Function       0
     72  blink                 StringProtoFuncImp::Blink       DontEnum|Function       0
     73  bold                  StringProtoFuncImp::Bold        DontEnum|Function       0
     74  fixed                 StringProtoFuncImp::Fixed       DontEnum|Function       0
     75  italics               StringProtoFuncImp::Italics     DontEnum|Function       0
     76  strike                StringProtoFuncImp::Strike      DontEnum|Function       0
     77  sub                   StringProtoFuncImp::Sub         DontEnum|Function       0
     78  sup                   StringProtoFuncImp::Sup         DontEnum|Function       0
     79  fontcolor             StringProtoFuncImp::Fontcolor   DontEnum|Function       1
     80  fontsize              StringProtoFuncImp::Fontsize    DontEnum|Function       1
     81  anchor                StringProtoFuncImp::Anchor      DontEnum|Function       1
     82  link                  StringProtoFuncImp::Link        DontEnum|Function       1
     83@end
     84*/
     85// ECMA 15.5.4
     86StringPrototypeImp::StringPrototypeImp(ExecState *exec,
     87                                       ObjectPrototypeImp *objProto)
     88  : StringInstanceImp(Object(objProto))
     89{
     90  Value protect(this);
     91  // The constructor will be added later, after StringObjectImp has been built
     92  put(exec,"length",Number(0),DontDelete|ReadOnly|DontEnum);
     93
     94}
     95
     96Value StringPrototypeImp::get(ExecState *exec, const UString &propertyName) const
     97{
     98  return lookupGetFunction<StringProtoFuncImp, StringInstanceImp>( exec, propertyName, &stringTable, this );
     99}
     100
     101// ------------------------------ StringProtoFuncImp ---------------------------
     102
     103StringProtoFuncImp::StringProtoFuncImp(ExecState *exec, int i, int len)
     104  : InternalFunctionImp(
     105    static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
     106    ), id(i)
     107{
     108  Value protect(this);
     109  put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
     110}
     111
     112bool StringProtoFuncImp::implementsCall() const
     113{
     114  return true;
     115}
     116
     117// ECMA 15.5.4.2 - 15.5.4.20
     118Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
     119{
     120  Value result;
     121
     122  // toString and valueOf are no generic function.
     123  if (id == ToString || id == ValueOf) {
     124    if (thisObj.isNull() || !thisObj.inherits(&StringInstanceImp::info)) {
     125      Object err = Error::create(exec,TypeError);
     126      exec->setException(err);
     127      return err;
     128    }
     129
     130    return String(thisObj.internalValue().toString(exec));
     131  }
     132
     133  int n, m;
     134  UString u, u2, u3;
     135  int pos, p0, i;
     136  double d = 0.0;
     137
     138  UString s = thisObj.toString(exec);
     139
     140  int len = s.size();
     141  Value a0 = args[0];
     142  Value a1 = args[1];
     143
     144  switch (id) {
     145  case ToString:
     146  case ValueOf:
     147    // handled above
     148    break;
     149  case CharAt:
     150    pos = a0.toInteger(exec);
     151    if (pos < 0 || pos >= len)
     152      u = "";
     153    else
     154      u = s.substr(pos, 1);
     155    result = String(u);
     156    break;
     157  case CharCodeAt:
     158    pos = a0.toInteger(exec);
     159    if (pos < 0 || pos >= len)
     160      d = NaN;
     161    else {
     162      UChar c = s[pos];
     163      d = (c.high() << 8) + c.low();
     164    }
     165    result = Number(d);
     166    break;
     167  case Concat: {
     168    ListIterator it = args.begin();
     169    for ( ; it != args.end() ; ++it) {
     170        s += it->toString(exec);
     171    }
     172    result = String(s);
     173    break;
     174  }
     175  case IndexOf:
     176    u2 = a0.toString(exec);
     177    if (a1.type() == UndefinedType)
     178      pos = 0;
     179    else
     180      pos = a1.toInteger(exec);
     181    d = s.find(u2, pos);
     182    result = Number(d);
     183    break;
     184  case LastIndexOf:
     185    u2 = a0.toString(exec);
     186    d = a1.toNumber(exec);
     187    if (a1.type() == UndefinedType || KJS::isNaN(d) || KJS::isPosInf(d))
     188      pos = len;
     189    else
     190      pos = a1.toInteger(exec);
     191    if (pos < 0)
     192      pos = 0;
     193    d = s.rfind(u2, pos);
     194    result = Number(d);
     195    break;
     196  case Match:
     197  case Search: {
     198    u = s;
     199    RegExp* reg = 0;
     200    if (a0.isA(ObjectType) && a0.toObject(exec).inherits(&RegExpImp::info))
     201    {
     202      RegExpImp* imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
     203      reg = imp->regExp();
     204    }
     205    else if (a0.isA(StringType))
     206    {
     207      reg = new RegExp(a0.toString(exec), RegExp::None);
     208    }
     209    else
     210    {
     211#ifndef NDEBUG
     212      printf("KJS: Match/Search. Argument is not a RegExp nor a String - returning Undefined\n");
     213#endif
     214      result = Undefined();
     215      break;
     216    }
     217    RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp());
     218    int **ovector = regExpObj->registerRegexp( reg, u );
     219    UString mstr = reg->match(u, -1, &pos, ovector);
     220    if (a0.isA(StringType))
     221      delete reg;
     222    if (id == Search) {
     223      result = Number(pos);
     224      break;
     225    }
     226    if (mstr.isNull())
     227      result = Null();
     228    else
     229      result = regExpObj->arrayOfMatches(exec,mstr);
     230  }
     231    break;
     232  case Replace:
     233    u = s;
     234    if (a0.type() == ObjectType && a0.toObject(exec).inherits(&RegExpImp::info)) {
     235      RegExpImp* imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
     236      RegExp *reg = imp->regExp();
     237      bool global = false;
     238      Value tmp = imp->get(exec,"global");
     239      if (tmp.type() != UndefinedType && tmp.toBoolean(exec) == true)
     240        global = true;
     241
     242      RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp());
     243      int **ovector = regExpObj->registerRegexp( reg, u );
     244      int lastIndex = 0;
     245      u3 = a1.toString(exec); // replacement string
     246      // This is either a loop (if global is set) or a one-way (if not).
     247      do {
     248        UString mstr = reg->match(u, lastIndex, &pos, ovector);
     249        len = mstr.size();
     250        lastIndex = pos + u3.size();
     251        if ( pos != -1 )
     252          u = u.substr(0, pos) + u3 + u.substr(pos + len);
     253        //fprintf(stderr,"pos=%d,len=%d,lastIndex=%d,u=%s\n",pos,len,lastIndex,u.ascii());
     254      } while ( global && pos != -1 );
     255
     256      result = String(u);
     257    } else { // First arg is a string
     258      u2 = a0.toString(exec);
     259      pos = u.find(u2);
     260      len = u2.size();
     261      // Do the replacement
     262      if (pos == -1)
     263        result = String(s);
     264      else {
     265        u3 = u.substr(0, pos) + a1.toString(exec) +
     266             u.substr(pos + len);
     267        result = String(u3);
     268      }
     269    }
     270    break;
     271  case Slice: // http://developer.netscape.com/docs/manuals/js/client/jsref/string.htm#1194366
     272    {
     273        // The arg processing is very much like ArrayProtoFunc::Slice
     274        // We return a new array
     275        result = exec->interpreter()->builtinArray().construct(exec,List::empty());
     276        int begin = args[0].toUInt32(exec);
     277        int end = len;
     278        if (args[1].type() != UndefinedType)
     279        {
     280          end = args[1].toUInt32(exec);
     281          if ( end < 0 )
     282            end += len;
     283        }
     284        // safety tests
     285        if ( begin < 0 || end < 0 || begin >= end ) {
     286            result = String();
     287            break;
     288        }
     289        //printf( "Slicing from %d to %d \n", begin, end );
     290        result = String(s.substr(begin, end-begin));
     291        break;
     292    }
     293    case Split: {
     294    Object constructor = exec->interpreter()->builtinArray();
     295    Object res = Object::dynamicCast(constructor.construct(exec,List::empty()));
     296    result = res;
     297    u = s;
     298    i = p0 = 0;
     299    d = (a1.type() != UndefinedType) ? a1.toInteger(exec) : -1; // optional max number
     300    if (a0.type() == ObjectType && Object::dynamicCast(a0).inherits(&RegExpImp::info)) {
     301      Object obj0 = Object::dynamicCast(a0);
     302      RegExp reg(obj0.get(exec,"source").toString(exec));
     303      if (u.isEmpty() && !reg.match(u, 0).isNull()) {
     304        // empty string matched by regexp -> empty array
     305        res.put(exec,"length", Number(0));
     306        break;
     307      }
     308      int *ovector;
     309      int mpos;
     310      pos = 0;
     311      while (1) {
     312        // TODO: back references
     313        UString mstr = reg.match(u, pos, &mpos, &ovector);
     314        if (mpos < 0)
     315          break;
     316        pos = mpos + (mstr.isEmpty() ? 1 : mstr.size());
     317        if (mpos != p0 || !mstr.isEmpty()) {
     318          res.put(exec,UString::from(i), String(u.substr(p0, mpos-p0)));
     319          p0 = mpos + mstr.size();
     320          i++;
     321        }
     322      }
     323      delete ovector;
     324    } else if (a0.type() != UndefinedType) {
     325      u2 = a0.toString(exec);
     326      if (u2.isEmpty()) {
     327        if (u.isEmpty()) {
     328          // empty separator matches empty string -> empty array
     329          put(exec,"length", Number(0));
     330          break;
     331        } else {
     332          while (i != d && i < u.size()-1)
     333            res.put(exec,UString::from(i++), String(u.substr(p0++, 1)));
     334        }
     335      } else {
     336        while (i != d && (pos = u.find(u2, p0)) >= 0) {
     337          res.put(exec,UString::from(i), String(u.substr(p0, pos-p0)));
     338          p0 = pos + u2.size();
     339          i++;
     340        }
     341      }
     342    }
     343    // add remaining string, if any
     344    if (i != d)
     345      res.put(exec,UString::from(i++), String(u.substr(p0)));
     346    res.put(exec,"length", Number(i));
     347    }
     348    break;
     349  case Substr: {
     350    n = a0.toInteger(exec);
     351    m = a1.toInteger(exec);
     352    int d, d2;
     353    if (n >= 0)
     354      d = n;
     355    else
     356      d = maxInt(len + n, 0);
     357    if (a1.type() == UndefinedType)
     358      d2 = len - d;
     359    else
     360      d2 = minInt(maxInt(m, 0), len - d);
     361    result = String(s.substr(d, d2));
     362    break;
     363  }
     364  case Substring: {
     365    double start = a0.toNumber(exec);
     366    double end = a1.toNumber(exec);
     367    if (KJS::isNaN(start))
     368      start = 0;
     369    if (KJS::isNaN(end))
     370      end = 0;
     371    if (start < 0)
     372      start = 0;
     373    if (end < 0)
     374      end = 0;
     375    if (start > len)
     376      start = len;
     377    if (end > len)
     378      end = len;
     379    if (a1.type() == UndefinedType)
     380      end = len;
     381    if (start > end) {
     382      double temp = end;
     383      end = start;
     384      start = temp;
     385    }
     386    result = String(s.substr((int)start, (int)end-(int)start));
     387    }
     388    break;
     389  case ToLowerCase:
     390    u = s;
     391    for (i = 0; i < len; i++)
     392      u[i] = u[i].toLower();
     393    result = String(u);
     394    break;
     395  case ToUpperCase:
     396    u = s;
     397    for (i = 0; i < len; i++)
     398      u[i] = u[i].toUpper();
     399    result = String(u);
     400    break;
     401#ifndef KJS_PURE_ECMA
     402  case Big:
     403    result = String("<BIG>" + s + "</BIG>");
     404    break;
     405  case Small:
     406    result = String("<SMALL>" + s + "</SMALL>");
     407    break;
     408  case Blink:
     409    result = String("<BLINK>" + s + "</BLINK>");
     410    break;
     411  case Bold:
     412    result = String("<B>" + s + "</B>");
     413    break;
     414  case Fixed:
     415    result = String("<TT>" + s + "</TT>");
     416    break;
     417  case Italics:
     418    result = String("<I>" + s + "</I>");
     419    break;
     420  case Strike:
     421    result = String("<STRIKE>" + s + "</STRIKE>");
     422    break;
     423  case Sub:
     424    result = String("<SUB>" + s + "</SUB>");
     425    break;
     426  case Sup:
     427    result = String("<SUP>" + s + "</SUP>");
     428    break;
     429  case Fontcolor:
     430    result = String("<FONT COLOR=" + a0.toString(exec) + ">"
     431                    + s + "</FONT>");
     432    break;
     433  case Fontsize:
     434    result = String("<FONT SIZE=" + a0.toString(exec) + ">"
     435                    + s + "</FONT>");
     436    break;
     437  case Anchor:
     438    result = String("<a name=" + a0.toString(exec) + ">"
     439                    + s + "</a>");
     440    break;
     441  case Link:
     442    result = String("<a href=" + a0.toString(exec) + ">"
     443                    + s + "</a>");
     444    break;
     445#endif
     446  }
     447
     448  return result;
     449}
     450
     451// ------------------------------ StringObjectImp ------------------------------
     452
     453StringObjectImp::StringObjectImp(ExecState *exec,
     454                                 FunctionPrototypeImp *funcProto,
     455                                 StringPrototypeImp *stringProto)
     456  : InternalFunctionImp(funcProto)
     457{
     458  Value protect(this);
    32459  // ECMA 15.5.3.1 String.prototype
    33   setPrototypeProperty(stringProto);
    34 }
    35 
    36 KJSO StringObject::get(const UString &p) const
    37 {
    38   if (p == "fromCharCode")
    39     return Function(new StringObjectFunc());
     460  put(exec,"prototype", Object(stringProto), DontEnum|DontDelete|ReadOnly);
     461
     462  put(exec,"fromCharCode", Object(new StringObjectFuncImp(exec,funcProto)), DontEnum);
     463
     464  // no. of arguments for constructor
     465  put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum);
     466}
     467
     468
     469bool StringObjectImp::implementsConstruct() const
     470{
     471  return true;
     472}
     473
     474// ECMA 15.5.2
     475Object StringObjectImp::construct(ExecState *exec, const List &args)
     476{
     477  Object proto = exec->interpreter()->builtinStringPrototype();
     478  Object obj(new StringInstanceImp(proto ));
     479
     480  UString s;
     481  if (args.size() > 0)
     482    s = args.begin()->toString(exec);
    40483  else
    41     return Imp::get(p);
     484    s = UString("");
     485
     486  obj.setInternalValue(String(s));
     487  obj.put(exec, "length", Number(s.size()), ReadOnly|DontEnum|DontDelete);
     488
     489  return obj;
     490}
     491
     492bool StringObjectImp::implementsCall() const
     493{
     494  return true;
    42495}
    43496
    44497// ECMA 15.5.1
    45 Completion StringObject::execute(const List &args)
    46 {
    47   KJSO v;
    48   String s;
    49 
     498Value StringObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
     499{
    50500  if (args.isEmpty())
    51     s = String("");
     501    return String("");
    52502  else {
    53     v = args[0];
    54     s = v.toString();
     503    Value v = args[0];
     504    return String(v.toString(exec));
    55505  }
    56 
    57   return Completion(ReturnValue, s);
    58 }
    59 
    60 // ECMA 15.5.2
    61 Object StringObject::construct(const List &args)
    62 {
    63   String s;
    64   if (args.size() > 0)
    65     s = args.begin()->toString();
    66   else
    67     s = String("");
    68 
    69   return Object::create(StringClass, s);
    70 }
     506}
     507
     508// ------------------------------ StringObjectFuncImp --------------------------
    71509
    72510// ECMA 15.5.3.2 fromCharCode()
    73 Completion StringObjectFunc::execute(const List &args)
     511StringObjectFuncImp::StringObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto)
     512  : InternalFunctionImp(funcProto)
     513{
     514  Value protect(this);
     515  put(exec,"length",Number(1),DontDelete|ReadOnly|DontEnum);
     516}
     517
     518bool StringObjectFuncImp::implementsCall() const
     519{
     520  return true;
     521}
     522
     523Value StringObjectFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
    74524{
    75525  UString s;
     
    79529    ListIterator it = args.begin();
    80530    while (it != args.end()) {
    81       unsigned short u = it->toUInt16();
     531      unsigned short u = it->toUInt16(exec);
    82532      *p++ = UChar(u);
    83533      it++;
     
    87537    s = "";
    88538
    89   return Completion(ReturnValue, String(s));
    90 }
    91 
    92 // ECMA 15.5.4
    93 StringPrototype::StringPrototype(const Object& proto)
    94   : ObjectImp(StringClass, String(""), proto)
    95 {
    96   // The constructor will be added later in StringObject's constructor
    97 }
    98 
    99 KJSO StringPrototype::get(const UString &p) const
    100 {
    101   int id;
    102 
    103   if (p == "toString")
    104     id = StringProtoFunc::ToString;
    105   else if (p == "valueOf")
    106     id = StringProtoFunc::ValueOf;
    107   else if (p == "charAt")
    108     id = StringProtoFunc::CharAt;
    109   else if (p == "charCodeAt")
    110     id = StringProtoFunc::CharCodeAt;
    111   else if (p == "indexOf")
    112     id = StringProtoFunc::IndexOf;
    113   else if (p == "lastIndexOf")
    114     id = StringProtoFunc::LastIndexOf;
    115   else if (p == "match")
    116     id = StringProtoFunc::Match;
    117   else if (p == "replace")
    118     id = StringProtoFunc::Replace;
    119   else if (p == "search")
    120     id = StringProtoFunc::Search;
    121   else if (p == "split")
    122     id = StringProtoFunc::Split;
    123   else if (p == "substr")
    124     id = StringProtoFunc::Substr;
    125   else if (p == "substring")
    126     id = StringProtoFunc::Substring;
    127   else if (p == "toLowerCase")
    128     id = StringProtoFunc::ToLowerCase;
    129   else if (p == "toUpperCase")
    130     id = StringProtoFunc::ToUpperCase;
    131 #ifndef KJS_PURE_ECMA
    132   else if (p == "big")
    133     id = StringProtoFunc::Big;
    134   else if (p == "small")
    135     id = StringProtoFunc::Small;
    136   else if (p == "blink")
    137     id = StringProtoFunc::Blink;
    138   else if (p == "bold")
    139     id = StringProtoFunc::Bold;
    140   else if (p == "fixed")
    141     id = StringProtoFunc::Fixed;
    142   else if (p == "italics")
    143     id = StringProtoFunc::Italics;
    144   else if (p == "strike")
    145     id = StringProtoFunc::Strike;
    146   else if (p == "sub")
    147     id = StringProtoFunc::Sub;
    148   else if (p == "sup")
    149     id = StringProtoFunc::Sup;
    150   else if (p == "fontcolor")
    151     id = StringProtoFunc::Fontcolor;
    152   else if (p == "fontsize")
    153     id = StringProtoFunc::Fontsize;
    154   else if (p == "anchor")
    155     id = StringProtoFunc::Anchor;
    156   else if (p == "link")
    157     id = StringProtoFunc::Link;
    158 #endif
    159   else
    160     return Imp::get(p);
    161 
    162   return Function(new StringProtoFunc(id));
    163 }
    164 
    165 StringProtoFunc::StringProtoFunc(int i)
    166   : id(i)
    167 {
    168 }
    169 
    170 // ECMA 15.5.4.2 - 15.5.4.20
    171 Completion StringProtoFunc::execute(const List &args)
    172 {
    173   KJSO result;
    174 
    175   Object thisObj = Object::dynamicCast(thisValue());
    176 
    177   // toString and valueOf are no generic function.
    178   if (id == ToString || id == ValueOf) {
    179     if (thisObj.isNull() || thisObj.getClass() != StringClass) {
    180       result = Error::create(TypeError);
    181       return Completion(ReturnValue, result);
    182     }
    183   }
    184 
    185   String s2;
    186   Number n, m;
    187   UString u, u2, u3;
    188   int pos, p0, i;
    189   double d, d2;
    190   KJSO v = thisObj.internalValue();
    191   String s = v.toString();
    192   int len = s.value().size();
    193   KJSO a0 = args[0];
    194   KJSO a1 = args[1];
    195 
    196   switch (id) {
    197   case ToString:
    198   case ValueOf:
    199     result = v.toString();
    200     break;
    201   case CharAt:
    202     n = a0.toInteger();
    203     pos = (int) n.value();
    204     if (pos < 0 || pos >= len)
    205       u = "";
    206     else
    207       u = s.value().substr(pos, 1);
    208     result = String(u);
    209     break;
    210   case CharCodeAt:
    211     n = a0.toInteger();
    212     pos = (int) n.value();
    213     if (pos < 0 || pos >= len)
    214       d = NaN;
    215     else {
    216       UChar c = s.value()[pos];
    217       d = (c.high() << 8) + c.low();
    218     }
    219     result = Number(d);
    220     break;
    221   case IndexOf:
    222     s2 = a0.toString();
    223     if (a1.isA(UndefinedType))
    224       pos = 0;
    225     else
    226       pos = a1.toInteger().intValue();
    227     d = s.value().find(s2.value(), pos);
    228     result = Number(d);
    229     break;
    230   case LastIndexOf:
    231     s2 = a0.toString();
    232     if (a1.isA(UndefinedType))
    233       pos = len;
    234     else
    235       pos = a1.toInteger().intValue();
    236     d = s.value().rfind(s2.value(), pos);
    237     result = Number(d);
    238     break;
    239   case Match:
    240   case Search:
    241     u = s.value();
    242     if (a0.isA(ObjectType) && a0.toObject().getClass() == RegExpClass) {
    243       s2 = a0.get("source").toString();
    244       RegExp reg(s2.value());
    245       UString mstr = reg.match(u, -1, &pos);
    246       if (id == Search) {
    247         result = Number(pos);
    248         break;
    249       }
    250       if (mstr.isNull()) {
    251         result = Null();
    252         break;
    253       }
    254       /* TODO return an array, with the matches, etc. */
    255       result = String(mstr);
    256     } else
    257     {
    258       printf("Match/Search. Argument is not a RegExp - returning Undefined\n");
    259       result = Undefined(); // No idea what to do here
    260     }
    261     break;
    262   case Replace:
    263     /* TODO: this is just a hack to get the most common cases going */
    264     u = s.value();
    265     if (a0.isA(ObjectType) && a0.toObject().getClass() == RegExpClass) {
    266       s2 = a0.get("source").toString();
    267       RegExp reg(s2.value());
    268       UString mstr = reg.match(u, -1, &pos);
    269       len = mstr.size();
    270     } else {
    271       s2 = a0.toString();
    272       u2 = s2.value();
    273       pos = u.find(u2);
    274       len = u2.size();
    275     }
    276     if (pos == -1)
    277         result = s;
    278     else {
    279         u3 = u.substr(0, pos) + a1.toString().value() +
    280              u.substr(pos + len);
    281         result = String(u3);
    282     }
    283     break;
    284   case Split:
    285     result = Object::create(ArrayClass);
    286     u = s.value();
    287     i = p0 = 0;
    288     d = a1.isDefined() ? a1.toInteger().intValue() : -1; // optional max number
    289     if (a0.isA(ObjectType) && Object(a0.imp()).getClass() == RegExpClass) {
    290       RegExp reg(a0.get("source").toString().value());
    291       if (u.isEmpty() && !reg.match(u, 0).isNull()) {
    292         // empty string matched by regexp -> empty array
    293         result.put("length", 0);
    294         break;
    295       }
    296       int mpos;
    297       pos = 0;
    298       while (1) {
    299         /* TODO: back references */
    300         UString mstr = reg.match(u, pos, &mpos);
    301         if (mpos < 0)
    302           break;
    303         pos = mpos + (mstr.isEmpty() ? 1 : mstr.size());
    304         if (mpos != p0 || !mstr.isEmpty()) {
    305           result.put(UString::from(i), String(u.substr(p0, mpos-p0)));
    306           p0 = mpos + mstr.size();
    307           i++;
    308         }
    309       }
    310     } else if (a0.isDefined()) {
    311       u2 = a0.toString().value();
    312       if (u2.isEmpty()) {
    313         if (u.isEmpty()) {
    314           // empty separator matches empty string -> empty array
    315           put("length", 0);
    316           break;
    317         } else {
    318           while (i != d && i < u.size())
    319             result.put(UString::from(i++), String(u.substr(p0++, 1)));
    320         }
    321       } else {
    322         while (i != d && (pos = u.find(u2, p0)) >= 0) {
    323           result.put(UString::from(i), String(u.substr(p0, pos-p0)));
    324           p0 = pos + u2.size();
    325           i++;
    326         }
    327       }
    328     }
    329     // add remaining string, if any
    330     if (i != d && (p0 < len || i == 0))
    331       result.put(UString::from(i++), String(u.substr(p0)));
    332     result.put("length", i);
    333     break;
    334   case Substr:
    335     n = a0.toInteger();
    336     m = a1.toInteger();
    337     if (n.value() >= 0)
    338       d = n.value();
    339     else
    340       d = max(len + n.value(), 0);
    341     if (a1.isA(UndefinedType))
    342       d2 = len - d;
    343     else
    344       d2 = min(max(m.value(), 0), len - d);
    345     result = String(s.value().substr((int)d, (int)d2));
    346     break;
    347   case Substring:
    348     n = a0.toInteger();
    349     m = a1.toInteger();
    350     d = min(max(n.value(), 0), len);
    351     if (a1.isA(UndefinedType))
    352       d2 = len - d;
    353     else {
    354       d2 = min(max(m.value(), 0), len);
    355       d2 = max(d2-d, 0);
    356     }
    357     result = String(s.value().substr((int)d, (int)d2));
    358     break;
    359   case ToLowerCase:
    360     u = UString(s.value());
    361     for (i = 0; i < len; i++)
    362       u[i] = u[i].toLower();
    363     result = String(u);
    364     break;
    365   case ToUpperCase:
    366     u = UString(s.value());
    367     for (i = 0; i < len; i++)
    368       u[i] = u[i].toUpper();
    369     result = String(u);
    370     break;
    371 #ifndef KJS_PURE_ECMA
    372   case Big:
    373     result = String("<BIG>" + s.value() + "</BIG>");
    374     break;
    375   case Small:
    376     result = String("<SMALL>" + s.value() + "</SMALL>");
    377     break;
    378   case Blink:
    379     result = String("<BLINK>" + s.value() + "</BLINK>");
    380     break;
    381   case Bold:
    382     result = String("<B>" + s.value() + "</B>");
    383     break;
    384   case Fixed:
    385     result = String("<TT>" + s.value() + "</TT>");
    386     break;
    387   case Italics:
    388     result = String("<I>" + s.value() + "</I>");
    389     break;
    390   case Strike:
    391     result = String("<STRIKE>" + s.value() + "</STRIKE>");
    392     break;
    393   case Sub:
    394     result = String("<SUB>" + s.value() + "</SUB>");
    395     break;
    396   case Sup:
    397     result = String("<SUP>" + s.value() + "</SUP>");
    398     break;
    399   case Fontcolor:
    400     result = String("<FONT COLOR=" + a0.toString().value() + ">"
    401                     + s.value() + "</FONT>");
    402     break;
    403   case Fontsize:
    404     result = String("<FONT SIZE=" + a0.toString().value() + ">"
    405                     + s.value() + "</FONT>");
    406     break;
    407   case Anchor:
    408     result = String("<a name=" + a0.toString().value() + ">"
    409                     + s.value() + "</a>");
    410     break;
    411   case Link:
    412     result = String("<a href=" + a0.toString().value() + ">"
    413                     + s.value() + "</a>");
    414     break;
    415 #endif
    416   }
    417 
    418   return Completion(ReturnValue, result);
    419 }
     539  return String(s);
     540}
  • trunk/JavaScriptCore/kjs/string_object.h

    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 *
     20 *  $Id$
    1821 */
    1922
     
    2124#define _STRING_OBJECT_H_
    2225
    23 #include "object.h"
    24 #include "function.h"
     26#include "internal.h"
     27#include "function_object.h"
    2528
    2629namespace KJS {
    2730
    28   class StringObject : public ConstructorImp {
     31  class StringInstanceImp : public ObjectImp {
    2932  public:
    30     StringObject(const Object &funcProto, const Object &stringProto);
    31     KJSO get(const UString &p) const;
    32     Completion execute(const List &);
    33     Object construct(const List &);
     33    StringInstanceImp(const Object &proto);
     34
     35    virtual const ClassInfo *classInfo() const { return &info; }
     36    static const ClassInfo info;
    3437  };
    3538
    36   class StringObjectFunc : public InternalFunctionImp {
     39  /**
     40   * @internal
     41   *
     42   * The initial value of String.prototype (and thus all objects created
     43   * with the String constructor
     44   */
     45  class StringPrototypeImp : public StringInstanceImp {
    3746  public:
    38     Completion execute(const List &);
     47    StringPrototypeImp(ExecState *exec,
     48                       ObjectPrototypeImp *objProto);
     49    Value get(ExecState *exec, const UString &p) const;
     50    virtual const ClassInfo *classInfo() const { return &info; }
     51    static const ClassInfo info;
    3952  };
    4053
    41   class StringPrototype : public ObjectImp {
     54  /**
     55   * @internal
     56   *
     57   * Class to implement all methods that are properties of the
     58   * String.prototype object
     59   */
     60  class StringProtoFuncImp : public InternalFunctionImp {
    4261  public:
    43     StringPrototype(const Object& proto);
    44     KJSO get(const UString &p) const;
    45   };
     62    StringProtoFuncImp(ExecState *exec, int i, int len);
    4663
    47   class StringProtoFunc : public InternalFunctionImp {
    48   public:
    49     StringProtoFunc(int i);
    50     Completion execute(const List &);
     64    virtual bool implementsCall() const;
     65    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
    5166
    52     enum { ToString, ValueOf, CharAt, CharCodeAt, IndexOf, LastIndexOf,
     67    enum { ToString, ValueOf, CharAt, CharCodeAt, Concat, IndexOf, LastIndexOf,
    5368           Match, Replace, Search, Slice, Split,
    5469           Substr, Substring, FromCharCode, ToLowerCase, ToUpperCase
     
    6277  };
    6378
     79  /**
     80   * @internal
     81   *
     82   * The initial value of the the global variable's "String" property
     83   */
     84  class StringObjectImp : public InternalFunctionImp {
     85  public:
     86    StringObjectImp(ExecState *exec,
     87                    FunctionPrototypeImp *funcProto,
     88                    StringPrototypeImp *stringProto);
     89
     90    virtual bool implementsConstruct() const;
     91    virtual Object construct(ExecState *exec, const List &args);
     92    virtual bool implementsCall() const;
     93    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     94  };
     95
     96  /**
     97   * @internal
     98   *
     99   * Class to implement all methods that are properties of the
     100   * String object
     101   */
     102  class StringObjectFuncImp : public InternalFunctionImp {
     103  public:
     104    StringObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto);
     105    virtual bool implementsCall() const;
     106    virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     107  };
     108
    64109}; // namespace
    65110
    66111#endif
     112
  • trunk/JavaScriptCore/kjs/testkjs.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
     
    1718 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1819 *  Boston, MA 02111-1307, USA.
     20 *
     21 *  $Id$
    1922 */
    2023
    2124#include <stdio.h>
     25#include <iostream.h>
    2226
    23 #include "kjs.h"
    24 
     27#include "value.h"
    2528#include "object.h"
    2629#include "types.h"
    27 #include "internal.h"
     30#include "interpreter.h"
     31
     32using namespace KJS;
     33
     34class TestFunctionImp : public ObjectImp {
     35public:
     36  TestFunctionImp() : ObjectImp() {}
     37  virtual bool implementsCall() const { return true; }
     38  virtual Value call(ExecState *exec, Object &thisObj, const List &args);
     39};
     40
     41Value TestFunctionImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
     42{
     43  fprintf(stderr,"--> %s\n",args[0].toString(exec).ascii());
     44  return Undefined();
     45}
     46
     47class GlobalImp : public ObjectImp {
     48public:
     49  virtual UString className() const { return "global"; }
     50};
    2851
    2952int main(int argc, char **argv)
     
    3558  }
    3659
    37   // create interpreter
    38   KJScript *kjs = new KJScript();
     60  bool ret = true;
     61  {
     62    Object global(new GlobalImp());
    3963
    40   // add debug() function
    41   kjs->enableDebug();
     64    // create interpreter
     65    Interpreter interp(global);
     66    global.put(interp.globalExec(),"debug", Object(new TestFunctionImp()));
     67    // add "print" for compatibility with the mozilla js shell
     68    global.put(interp.globalExec(),"print", Object(new TestFunctionImp()));
    4269
    43   const int BufferSize = 100000;
    44   char code[BufferSize];
     70    // add debug() function
     71    //  kjs->enableDebug();
    4572
    46   bool ret = true;
    47   for (int i = 1; i < argc; i++) {
    48     const char *file = argv[i];
    49     FILE *f = fopen(file, "r");
    50     if (!f) {
    51       fprintf(stderr, "Error opening %s.\n", file);
    52       return -1;
     73    const int BufferSize = 200000;
     74    char code[BufferSize];
     75
     76    for (int i = 1; i < argc; i++) {
     77      const char *file = argv[i];
     78      FILE *f = fopen(file, "r");
     79      if (!f) {
     80        fprintf(stderr, "Error opening %s.\n", file);
     81        return -1;
     82      }
     83      int num = fread(code, 1, BufferSize, f);
     84      code[num] = '\0';
     85      if(num >= BufferSize)
     86        fprintf(stderr, "Warning: File may have been too long.\n");
     87
     88      // run
     89      Completion comp(interp.evaluate(code));
     90
     91      fclose(f);
     92
     93      if (comp.complType() == Throw) {
     94        ExecState *exec = interp.globalExec();
     95        Value exVal = comp.value();
     96        char *msg = exVal.toString(exec).ascii();
     97        int lineno = -1;
     98        if (exVal.type() == ObjectType) {
     99          Value lineVal = Object::dynamicCast(exVal).get(exec,"line");
     100          if (lineVal.type() == NumberType)
     101            lineno = int(lineVal.toNumber(exec));
     102        }
     103        if (lineno != -1)
     104          fprintf(stderr,"Exception, line %d: %s\n",lineno,msg);
     105        else
     106          fprintf(stderr,"Exception: %s\n",msg);
     107        ret = false;
     108      }
     109      else if (comp.complType() == ReturnValue) {
     110        char *msg = comp.value().toString(interp.globalExec()).ascii();
     111        fprintf(stderr,"Return value: %s\n",msg);
     112      }
    53113    }
    54     int num = fread(code, 1, BufferSize, f);
    55     code[num] = '\0';
    56     if(num >= BufferSize)
    57       fprintf(stderr, "Warning: File may have been too long.\n");
    58114
    59     // run
    60     ret = ret && kjs->evaluate(code);
    61     if (kjs->errorType() != 0)
    62       printf("%s returned: %s\n", file, kjs->errorMsg());
    63     else if (kjs->returnValue())
    64       printf("returned a value\n");
     115    //  delete kjs;
     116  } // end block, so that Interpreter and global get deleted
    65117
    66     fclose(f);
    67   }
    68 
    69   delete kjs;
     118  if (ret)
     119    fprintf(stderr, "OK.\n");
    70120
    71121#ifdef KJS_DEBUG_MEM
    72   printf("List::count = %d\n", KJS::List::count);
    73   assert(KJS::List::count == 0);
    74   printf("Imp::count = %d\n", KJS::Imp::count);
    75   assert(KJS::Imp::count == 0);
     122  Interpreter::finalCheck();
    76123#endif
    77 
    78   fprintf(stderr, "OK.\n");
    79124  return ret;
    80125}
  • trunk/JavaScriptCore/kjs/types.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    3  *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     4 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1719 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1820 *  Boston, MA 02111-1307, USA.
     21 *
     22 *  $Id$
    1923 */
    2024
    21 #include <stdio.h>
    22 
    23 #include "kjs.h"
     25#include "value.h"
    2426#include "object.h"
    2527#include "types.h"
     28#include "interpreter.h"
     29
     30#include <assert.h>
     31#include <math.h>
     32#include <stdio.h>
     33
    2634#include "internal.h"
     35#include "collector.h"
    2736#include "operations.h"
     37#include "error_object.h"
    2838#include "nodes.h"
    2939
    3040using namespace KJS;
    3141
    32 Undefined::Undefined() : KJSO(UndefinedImp::staticUndefined) { }
    33 
    34 Undefined::~Undefined() { }
    35 
    36 Null::Null() : KJSO(NullImp::staticNull) { }
    37 
    38 Null::~Null() { }
    39 
    40 Boolean::Boolean(bool b)
    41   : KJSO(b ? BooleanImp::staticTrue : BooleanImp::staticFalse)
    42 {
    43 }
    44 
    45 Boolean::Boolean(BooleanImp *i) : KJSO(i) { }
    46 
    47 Boolean::~Boolean() { }
    48 
    49 bool Boolean::value() const
    50 {
    51   assert(rep);
    52   return ((BooleanImp*)rep)->value();
    53 }
    54 
    55 Number::Number(int i)
    56   : KJSO(new NumberImp(static_cast<double>(i))) { }
    57 
    58 Number::Number(unsigned int u)
    59   : KJSO(new NumberImp(static_cast<double>(u))) { }
    60 
    61 Number::Number(double d)
    62   : KJSO(new NumberImp(d)) { }
    63 
    64 Number::Number(long int l)
    65   : KJSO(new NumberImp(static_cast<double>(l))) { }
    66 
    67 Number::Number(long unsigned int l)
    68   : KJSO(new NumberImp(static_cast<double>(l))) { }
    69 
    70 Number::Number(NumberImp *i)
    71   : KJSO(i) { }
    72 
    73 Number::~Number() { }
    74 
    75 double Number::value() const
    76 {
    77   assert(rep);
    78   return ((NumberImp*)rep)->value();
    79 }
    80 
    81 int Number::intValue() const
    82 {
    83   assert(rep);
    84   return (int)((NumberImp*)rep)->value();
    85 }
    86 
    87 bool Number::isNaN() const
    88 {
    89   return KJS::isNaN(((NumberImp*)rep)->value());
    90 }
    91 
    92 bool Number::isInf() const
    93 {
    94   return KJS::isInf(((NumberImp*)rep)->value());
    95 }
    96 
    97 String::String(const UString &s) : KJSO(new StringImp(UString(s))) { }
    98 
    99 String::String(StringImp *i) : KJSO(i) { }
    100 
    101 String::~String() { }
    102 
    103 UString String::value() const
    104 {
    105   assert(rep);
    106   return ((StringImp*)rep)->value();
    107 }
    108 
    109 Reference::Reference(const KJSO& b, const UString &p)
    110   : KJSO(new ReferenceImp(b, p))
     42// ------------------------------ Reference ------------------------------------
     43
     44Reference::Reference(const Object& b, const UString& p)
     45  : Value(new ReferenceImp(b,p))
     46{
     47}
     48
     49Reference::Reference(const Null& b, const UString& p)
     50  : Value(new ReferenceImp(b,p))
     51{
     52}
     53
     54Reference::Reference(ReferenceImp *v) : Value(v)
     55{
     56}
     57
     58Reference::Reference(const Reference &v) : Value(v)
    11159{
    11260}
     
    11664}
    11765
    118 Completion::Completion(Imp *d) : KJSO(d) { }
    119 
    120 Completion::Completion(Compl c)
    121   : KJSO(new CompletionImp(c, KJSO(), UString::null))
    122 {
    123   if (c == Throw)
    124     KJScriptImp::setException(new UndefinedImp());
    125 }
    126 
    127 Completion::Completion(Compl c, const KJSO& v, const UString &t)
    128   : KJSO(new CompletionImp(c, v, t))
    129 {
    130   if (c == Throw)
    131     KJScriptImp::setException(v.imp());
    132 }
    133 
    134 Completion::~Completion() { }
    135 
    136 Compl Completion::complType() const
    137 {
    138   assert(rep);
    139   return ((CompletionImp*)rep)->completion();
     66Reference& Reference::operator=(const Reference &v)
     67{
     68  Value::operator=(v);
     69  return *this;
     70}
     71
     72Reference Reference::dynamicCast(const Value &v)
     73{
     74  if (v.isNull() || v.type() != ReferenceType)
     75    return 0;
     76
     77  return static_cast<ReferenceImp*>(v.imp());
     78}
     79
     80// ------------------------------ ListIterator ---------------------------------
     81
     82//d  dont add   ListIterator();
     83
     84ListIterator::ListIterator(ListNode *n) : node(n)
     85{
     86}
     87
     88ListIterator::ListIterator(const List &l)
     89  : node(static_cast<ListImp*>(l.imp())->hook->next)
     90{
     91}
     92
     93ListIterator& ListIterator::operator=(const ListIterator &iterator)
     94{
     95  node=iterator.node;
     96  return *this;
     97}
     98
     99ListIterator::ListIterator(const ListIterator &i) : node(i.node)
     100{
     101}
     102
     103ListIterator::~ListIterator()
     104{
     105}
     106
     107ValueImp* ListIterator::operator->() const
     108{
     109  return node->member;
     110}
     111
     112    //    operator Value* () const { return node->member; }
     113Value ListIterator::operator*() const
     114{
     115  return Value(node->member);
     116}
     117
     118    //    operator Value*() const { return node->member; }
     119Value ListIterator::operator++()
     120{
     121  node = node->next;
     122  return Value(node->member);
     123}
     124
     125Value ListIterator::operator++(int)
     126{
     127  const ListNode *n = node;
     128  ++*this;
     129  return Value(n->member);
     130}
     131
     132Value ListIterator::operator--()
     133{
     134  node = node->prev;
     135  return Value(node->member);
     136}
     137
     138Value ListIterator::operator--(int)
     139{
     140  const ListNode *n = node;
     141  --*this;
     142  return Value(n->member);
     143}
     144
     145bool ListIterator::operator==(const ListIterator &it) const
     146{
     147  return (node==it.node);
     148}
     149
     150bool ListIterator::operator!=(const ListIterator &it) const
     151{
     152  return (node!=it.node);
     153}
     154
     155// ------------------------------ List -----------------------------------------
     156
     157List::List()
     158  : Value(new ListImp())
     159{
     160  //fprintf(stderr,"List::List() this=%p imp=%p refcount=%d\n",this,rep,rep->refcount);
     161}
     162
     163List::List(ListImp *v) : Value(v)
     164{
     165  //fprintf(stderr,"List::List(imp) this=%p imp=%p refcount=%d\n",this,v,v?v->refcount:0);
     166}
     167
     168List::List(const List &v) : Value(v)
     169{
     170  //fprintf(stderr,"List::List(List) this=%p imp=%p refcount=%d\n",this,rep,rep?rep->refcount:0);
     171}
     172
     173List::~List()
     174{
     175  //fprintf(stderr,"List::~List() this=%p imp=%p refcount=%d\n",this,rep,rep->refcount-1);
     176}
     177
     178List& List::operator=(const List &v)
     179{
     180  //fprintf(stderr,"List::operator=() this=%p\n",this);
     181  Value::operator=(v);
     182  return *this;
     183}
     184
     185List List::dynamicCast(const Value &v)
     186{
     187  if (v.isNull() || v.type() != ListType)
     188    return 0;
     189
     190  return static_cast<ListImp*>(v.imp());
     191}
     192
     193void List::append(const Value& val)
     194{
     195  static_cast<ListImp*>(rep)->append(val);
     196}
     197
     198void List::prepend(const Value& val)
     199{
     200  static_cast<ListImp*>(rep)->prepend(val);
     201}
     202
     203void List::appendList(const List& lst)
     204{
     205  static_cast<ListImp*>(rep)->appendList(lst);
     206}
     207
     208void List::prependList(const List& lst)
     209{
     210  static_cast<ListImp*>(rep)->prependList(lst);
     211}
     212
     213void List::removeFirst()
     214{
     215  static_cast<ListImp*>(rep)->removeFirst();
     216}
     217
     218void List::removeLast()
     219{
     220  static_cast<ListImp*>(rep)->removeLast();
     221}
     222
     223void List::remove(const Value &val)
     224{
     225  static_cast<ListImp*>(rep)->remove(val);
     226}
     227
     228void List::clear()
     229{
     230  static_cast<ListImp*>(rep)->clear();
     231}
     232
     233List List::copy() const
     234{
     235  return static_cast<ListImp*>(rep)->copy();
     236}
     237
     238ListIterator List::begin() const
     239{
     240  return static_cast<ListImp*>(rep)->begin();
     241}
     242
     243ListIterator List::end() const
     244{
     245  return static_cast<ListImp*>(rep)->end();
     246}
     247
     248bool List::isEmpty() const
     249{
     250  return static_cast<ListImp*>(rep)->isEmpty();
     251}
     252
     253int List::size() const
     254{
     255  return static_cast<ListImp*>(rep)->size();
     256}
     257
     258Value List::at(int i) const
     259{
     260  return static_cast<ListImp*>(rep)->at(i);
     261}
     262
     263Value List::operator[](int i) const
     264{
     265  return static_cast<ListImp*>(rep)->at(i);
     266}
     267
     268const List List::empty()
     269{
     270  return ListImp::empty();
     271}
     272
     273// ------------------------------ Completion -----------------------------------
     274
     275Completion::Completion(ComplType c, const Value& v, const UString &t)
     276  : Value(new CompletionImp(c,v,t))
     277{
     278}
     279
     280Completion::Completion(CompletionImp *v) : Value(v)
     281{
     282}
     283
     284Completion::Completion(const Completion &v) : Value(v)
     285{
     286}
     287
     288Completion::~Completion()
     289{
     290}
     291
     292Completion& Completion::operator=(const Completion &v)
     293{
     294  Value::operator=(v);
     295  return *this;
     296}
     297
     298Completion Completion::dynamicCast(const Value &v)
     299{
     300  if (v.isNull() || v.type() != CompletionType)
     301    return 0;
     302
     303  return static_cast<CompletionImp*>(v.imp());
     304}
     305
     306ComplType Completion::complType() const
     307{
     308  return static_cast<CompletionImp*>(rep)->complType();
     309}
     310
     311Value Completion::value() const
     312{
     313  return static_cast<CompletionImp*>(rep)->value();
     314}
     315
     316UString Completion::target() const
     317{
     318  return static_cast<CompletionImp*>(rep)->target();
    140319}
    141320
    142321bool Completion::isValueCompletion() const
    143322{
    144   assert(rep);
    145   return !((CompletionImp*)rep)->value().isNull();
    146 }
    147 
    148 KJSO Completion::value() const
    149 {
    150   assert(isA(CompletionType));
    151   return ((CompletionImp*)rep)->value();
    152 }
    153 
    154 UString Completion::target() const
    155 {
    156   assert(rep);
    157   return ((CompletionImp*)rep)->target();
    158 }
    159 
    160 ListIterator::ListIterator(const List &l)
    161   : node(l.hook->next)
    162 {
    163 }
    164 
    165 List::List()
    166 {
    167 #ifdef KJS_DEBUG_MEM
    168   count++;
    169 #endif
    170 
    171   static KJSO *null = 0;
    172   if (!null)
    173      null = new KJSO();
    174 
    175   hook = new ListNode(*null, 0L, 0L);
    176   hook->next = hook;
    177   hook->prev = hook;
    178 }
    179 
    180 List::~List()
    181 {
    182 #ifdef KJS_DEBUG_MEM
    183   count--;
    184 #endif
    185 
    186   clear();
    187   delete hook;
    188 }
    189 
    190 void List::append(const KJSO& obj)
    191 {
    192   ListNode *n = new ListNode(obj, hook->prev, hook);
    193   hook->prev->next = n;
    194   hook->prev = n;
    195 }
    196 
    197 void List::prepend(const KJSO& obj)
    198 {
    199   ListNode *n = new ListNode(obj, hook, hook->next);
    200   hook->next->prev = n;
    201   hook->next = n;
    202 }
    203 
    204 void List::removeFirst()
    205 {
    206   erase(hook->next);
    207 }
    208 
    209 void List::removeLast()
    210 {
    211   erase(hook->prev);
    212 }
    213 
    214 void List::remove(const KJSO &obj)
    215 {
    216   if (obj.isNull())
    217     return;
    218   ListNode *n = hook->next;
    219   while (n != hook) {
    220     if (n->member.imp() == obj.imp()) {
    221       erase(n);
    222       return;
    223     }
    224     n = n->next;
    225   }
    226 }
    227 
    228 void List::clear()
    229 {
    230   ListNode *n = hook->next;
    231   while (n != hook) {
    232     n = n->next;
    233     delete n->prev;
    234   }
    235 
    236   hook->next = hook;
    237   hook->prev = hook;
    238 }
    239 
    240 List *List::copy() const
    241 {
    242   List *newList = new List();
    243   ListIterator e = end();
    244   ListIterator it = begin();
    245 
    246   while(it != e) {
    247     newList->append(*it);
    248     ++it;
    249   }
    250 
    251   return newList;
    252 }
    253 
    254 void List::erase(ListNode *n)
    255 {
    256   if (n != hook) {
    257     n->next->prev = n->prev;
    258     n->prev->next = n->next;
    259     delete n;
    260   }
    261 }
    262 
    263 int List::size() const
    264 {
    265   int s = 0;
    266   ListNode *node = hook;
    267   while ((node = node->next) != hook)
    268     s++;
    269 
    270   return s;
    271 }
    272 
    273 KJSO List::at(int i) const
    274 {
    275   if (i < 0 || i >= size())
    276     return Undefined();
    277 
    278   ListIterator it = begin();
    279   int j = 0;
    280   while ((j++ < i))
    281     it++;
    282 
    283   return *it;
    284 }
    285 
    286 List *List::emptyList = 0L;
    287 
    288 const List *List::empty()
    289 {
    290   if (!emptyList)
    291     emptyList = new List;
    292 #ifdef KJS_DEBUG_MEM
    293   else
    294     count++;
    295 #endif
    296 
    297 
    298   return emptyList;
    299 }
     323  return !value().isNull();
     324}
  • trunk/JavaScriptCore/kjs/types.h

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    3  *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     4 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1719 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1820 *  Boston, MA 02111-1307, USA.
     21 *
     22 *  $Id$
    1923 */
    2024
    21 #ifndef _TYPES_H_
    22 #define _TYPES_H_
    23 
    24 #include "object.h"
     25#ifndef _KJS_TYPES_H_
     26#define _KJS_TYPES_H_
     27
     28// internal data types
     29
     30#include "value.h"
    2531
    2632namespace KJS {
    2733
    28   /**
    29    * @short Handle for an Undefined type.
    30    */
    31   class Undefined : public KJSO {
    32   public:
    33     Undefined();
    34     virtual ~Undefined();
    35   };
    36 
    37   /**
    38    * @short Handle for a Null type.
    39    */
    40   class Null : public KJSO {
    41   public:
    42     Null();
    43     virtual ~Null();
    44   };
    45 
    46   class BooleanImp;
    47   class NumberImp;
    48   class StringImp;
    49 
    50   /**
    51    * @short Handle for a Boolean type.
    52    */
    53   class Boolean : public KJSO {
    54     friend class BooleanImp;
    55   public:
    56     Boolean(bool b = false);
    57     virtual ~Boolean();
    58     bool value() const;
    59   private:
    60     Boolean(BooleanImp *i);
    61   };
    62 
    63   /**
    64    * @short Handle for a Number type.
    65    *
    66    * Number is a handle for a number value. @ref KJSO::toPrimitive(),
    67    * @ref KJSO::toBoolean(), @ref KJSO::toNumber(), @ref KJSO::toString() and
    68    * @ref KJSO::toString() are re-implemented internally according to the
    69    * specification.
    70    *
    71    * Example usage:
    72    * <pre>
    73    * Number a(2), b(3.0), c; // c defaults to 0.0
    74    *
    75    * c = a.value() * b.value(); // c will be 6.0 now
    76    *
    77    * String s = c.toString(); // s holds "6"
    78    * </pre>
    79    *
    80    * Note the following implementation detail: Internally, the value is stored
    81    * as a double and will be casted from and to other types when needed.
    82    * This won't be noticable within a certain range of values but might produce
    83    * unpredictable results when crossing these limits. In case this turns out
    84    * to be a real problem for an application we might have to extend this class
    85    * to behave more intelligently.
    86    */
    87   class Number : public KJSO {
    88     friend class NumberImp;
    89   public:
    90     /**
    91      * Construct a Number type from an integer.
    92      */
    93     Number(int i);
    94     /**
    95      * Construct a Number type from an unsigned integer.
    96      */
    97     Number(unsigned int u);
    98     /**
    99      * Construct a Number type from a double.
    100      */
    101     Number(double d = 0.0);
    102     /**
    103      * Construct a Number type from a long int.
    104      */
    105     Number(long int l);
    106     /**
    107      * Construct a Number type from a long unsigned int.
    108      */
    109     Number(long unsigned int l);
    110     /**
    111      * Destructor.
    112      */
    113     virtual ~Number();
    114     /**
    115      * @return The internally stored value.
    116      */
    117     double value() const;
    118     /**
    119      * Convenience function.
    120      * @return The internally stored value converted to an int.
    121      */
    122     int intValue() const;
    123     /**
    124      * @return True is this is not a number (NaN).
    125      */
    126     bool isNaN() const;
    127     /**
    128      * @return True if Number is either +Infinity or -Infinity.
    129      */
    130     bool isInf() const;
    131   private:
    132     Number(NumberImp *i);
    133   };
    134 
    135   /**
    136    * @short Handle for a String type.
    137    */
    138   class String : public KJSO {
    139     friend class StringImp;
    140   public:
    141     String(const UString &s = "");
    142     virtual ~String();
    143     UString value() const;
    144   private:
    145     String(StringImp *i);
    146   };
    147 
    148   /**
    149    * Completion objects are used to convey the return status and value
    150    * from functions.
    151    *
    152    * See @ref FunctionImp::execute()
    153    *
    154    * @see FunctionImp
    155    *
    156    * @short Handle for a Completion type.
    157    */
    158   class Completion : public KJSO {
    159   public:
    160     Completion(Imp *d = 0L);
    161     Completion(Compl c);
    162     Completion(Compl c, const KJSO& v, const UString &t = UString::null);
    163     virtual ~Completion();
    164     Compl complType() const;
    165     bool isValueCompletion() const;
    166     KJSO value() const;
    167     UString target() const;
     34  class Reference : public Value {
     35  public:
     36    Reference(const Object& b, const UString& p);
     37    Reference(const Null& b, const UString& p);
     38    Reference(ReferenceImp *v);
     39    Reference(const Reference &v);
     40    virtual ~Reference();
     41
     42    Reference& operator=(const Reference &v);
     43
     44    /**
     45     * Converts a Value into an Reference. If the value's type is not
     46     * ReferenceType, a null object will be returned (i.e. one with it's
     47     * internal pointer set to 0). If you do not know for sure whether the
     48     * value is of type ReferenceType, you should check the @ref isNull()
     49     * methods afterwards before calling any methods on the returned value.
     50     *
     51     * @return The value converted to an Reference
     52     */
     53    static Reference dynamicCast(const Value &v);
    16854  };
    16955
    17056  class List;
    17157  class ListIterator;
    172 
    173   /**
    174    * @internal
    175    */
    176   class ListNode {
    177     friend class List;
    178     friend class ListIterator;
    179     ListNode(KJSO obj, ListNode *p, ListNode *n)
    180       : member(obj), prev(p), next(n) {};
    181     KJSO member;
    182     ListNode *prev, *next;
    183   };
     58  class ListNode;
    18459
    18560  /**
     
    18863  class ListIterator {
    18964    friend class List;
     65    friend class ListImp;
    19066    ListIterator();
    191     ListIterator(ListNode *n) : node(n) { }
     67    ListIterator(ListNode *n);
    19268  public:
    19369    /**
     
    19571     * @param l The list the iterator will operate on.
    19672     */
    197     ListIterator(const List &list);
     73    ListIterator(const List &l);
    19874    /**
    19975     * Assignment constructor.
    20076     */
    201     ListIterator& operator=(const ListIterator &iterator)
    202       { node=iterator.node; return *this; }
     77    ListIterator& operator=(const ListIterator &iterator);
    20378    /**
    20479     * Copy constructor.
    20580     */
    206     ListIterator(const ListIterator &i) : node(i.node) { }
     81    ListIterator(const ListIterator &i);
     82    ~ListIterator();
    20783    /**
    20884     * Dereference the iterator.
    20985     * @return A pointer to the element the iterator operates on.
    21086     */
    211     KJSO* operator->() const { return &node->member; }
    212     //    operator KJSO* () const { return node->member; }
    213     KJSO operator*() const { return node->member; }
    214     /**
    215      * Conversion to @ref KJS::KJSO*
     87    ValueImp* operator->() const;
     88    //    operator Value* () const { return node->member; }
     89    Value operator*() const;
     90    /**
     91     * Conversion to @ref KJS::Value*
    21692     * @return A pointer to the element the iterator operates on.
    21793     */
    218     //    operator KJSO*() const { return node->member; }
     94    //    operator Value*() const { return node->member; }
    21995    /**
    22096     * Postfix increment operator.
    22197     * @return The element after the increment.
    22298     */
    223     KJSO operator++() { node = node->next; return node->member; }
     99    Value operator++();
    224100    /**
    225101     * Prefix increment operator.
    226102     */
    227     KJSO operator++(int) { const ListNode *n = node; ++*this; return n->member; }
     103    Value operator++(int);
    228104    /**
    229105     * Postfix decrement operator.
    230106     */
    231     KJSO operator--() { node = node->prev; return node->member; }
     107    Value operator--();
    232108    /**
    233109     * Prefix decrement operator.
    234110     */
    235     KJSO operator--(int) { const ListNode *n = node; --*this; return n->member; }
     111    Value operator--(int);
    236112    /**
    237113     * Compare the iterator with another one.
     
    239115     * False otherwise.
    240116     */
    241     bool operator==(const ListIterator &it) const { return (node==it.node); }
     117    bool operator==(const ListIterator &it) const;
    242118    /**
    243119     * Check for inequality with another iterator.
    244120     * @return True if the two iterators operate on different list elements.
    245121     */
    246     bool operator!=(const ListIterator &it) const { return (node!=it.node); }
     122    bool operator!=(const ListIterator &it) const;
    247123  private:
    248124    ListNode *node;
     
    259135   * copy of the list the referenced objects are still shared.
    260136   */
    261   class List {
     137  class List : public Value {
    262138    friend class ListIterator;
    263139  public:
    264     /**
    265      * Constructor.
    266      */
    267140    List();
    268     /**
    269      * Destructor.
    270      */
    271     ~List();
     141    List(ListImp *v);
     142    List(const List &v);
     143    virtual ~List();
     144
     145    List& operator=(const List &v);
     146
     147    /**
     148     * Converts a Value into an List. If the value's type is not
     149     * ListType, a null object will be returned (i.e. one with it's
     150     * internal pointer set to 0). If you do not know for sure whether the
     151     * value is of type List, you should check the @ref isNull()
     152     * methods afterwards before calling any methods on the returned value.
     153     *
     154     * @return The value converted to an List
     155     */
     156    static List dynamicCast(const Value &v);
    272157    /**
    273158     * Append an object to the end of the list.
    274159     *
    275      * @param obj Pointer to object.
    276      */
    277     void append(const KJSO& obj);
     160     * @param val Pointer to object.
     161     */
     162    void append(const Value& val);
    278163    /**
    279164     * Insert an object at the beginning of the list.
    280165     *
    281      * @param obj Pointer to object.
    282      */
    283     void prepend(const KJSO& obj);
     166     * @param val Pointer to object.
     167     */
     168    void prepend(const Value& val);
     169    /**
     170     * Appends the items of another list at the end of this one.
     171     */
     172    void appendList(const List& lst);
     173    /**
     174     * Prepend the items of another list to this one.
     175     * The first item of @p lst will become the first item of the list.
     176     */
     177    void prependList(const List& lst);
    284178    /**
    285179     * Remove the element at the beginning of the list.
     
    291185    void removeLast();
    292186    /*
    293      * Remove obj from list.
    294      */
    295     void remove(const KJSO &obj);
     187     * Remove val from list.
     188     */
     189    void remove(const Value &val);
    296190    /**
    297191     * Remove all elements from the list.
     
    302196     * who is responsible for deleting the list then.
    303197     */
    304     List *copy() const;
     198    List copy() const;
    305199    /**
    306200     * @return A @ref KJS::ListIterator pointing to the first element.
    307201     */
    308     ListIterator begin() const { return ListIterator(hook->next); }
     202    ListIterator begin() const;
    309203    /**
    310204     * @return A @ref KJS::ListIterator pointing to the last element.
    311205     */
    312     ListIterator end() const { return ListIterator(hook); }
     206    ListIterator end() const;
    313207    /**
    314208     * @return true if the list is empty. false otherwise.
    315209     */
    316     bool isEmpty() const { return (hook->prev == hook); }
     210    bool isEmpty() const;
    317211    /**
    318212     * @return the current size of the list.
     
    327221     * index is out of range.
    328222     */
    329     KJSO at(int i) const;
     223    Value at(int i) const;
    330224    /**
    331225     * Equivalent to @ref at.
    332226     */
    333     KJSO operator[](int i) const { return at(i); }
     227    Value operator[](int i) const;
    334228    /**
    335229     * Returns a pointer to a static instance of an empty list. Useful if a
    336230     * function has a @ref KJS::List parameter.
    337231     */
    338     static const List *empty();
    339 
    340 #ifdef KJS_DEBUG_MEM
    341     /**
    342      * @internal
    343      */
    344     static int count;
    345 #endif
    346   private:
    347     void erase(ListNode *n);
    348     ListNode *hook;
    349     static List *emptyList;
     232    static const List empty();
     233  };
     234
     235  /**
     236   * Completion types.
     237   */
     238  enum ComplType { Normal, Break, Continue, ReturnValue, Throw };
     239
     240  /**
     241   * Completion objects are used to convey the return status and value
     242   * from functions.
     243   *
     244   * See @ref FunctionImp::execute()
     245   *
     246   * @see FunctionImp
     247   *
     248   * @short Handle for a Completion type.
     249   */
     250  class Completion : public Value {
     251  public:
     252    Completion(ComplType c = Normal, const Value& v = Value(),
     253               const UString &t = UString::null);
     254    Completion(CompletionImp *v);
     255    Completion(const Completion &v);
     256    virtual ~Completion();
     257
     258    Completion& operator=(const Completion &v);
     259
     260    /**
     261     * Converts a Value into an Completion. If the value's type is not
     262     * CompletionType, a null object will be returned (i.e. one with it's
     263     * internal pointer set to 0). If you do not know for sure whether the
     264     * value is of type CompletionType, you should check the @ref isNull()
     265     * methods afterwards before calling any methods on the returned value.
     266     *
     267     * @return The value converted to an Completion
     268     */
     269    static Completion dynamicCast(const Value &v);
     270
     271    ComplType complType() const;
     272    Value value() const;
     273    UString target() const;
     274    bool isValueCompletion() const;
    350275  };
    351276
    352277}; // namespace
    353278
    354 
    355 #endif
     279#endif // _KJS_TYPES_H_
  • trunk/JavaScriptCore/kjs/ustring.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
     
    1718 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1819 *  Boston, MA 02111-1307, USA.
     20 *
     21 *  $Id$
    1922 */
    2023
     
    3538#include "ustring.h"
    3639#include "operations.h"
     40#include <math.h>
    3741
    3842namespace KJS {
     
    122126
    123127UChar::UChar(const UCharReference &c)
    124 #ifdef KJS_SWAPPED_CHAR
    125   : lo(c.low()), hi(c.high())
    126 #else
    127   : hi(c.high()), lo(c.low())
    128 #endif
     128    : uc( c.unicode() )
    129129{
    130130}
     
    132132UChar UChar::toLower() const
    133133{
    134   if (islower(lo) && hi == 0)
     134  // ### properly supprot unicode tolower
     135  if (uc >= 256 || islower(uc))
    135136    return *this;
    136137
    137   return UChar(0, tolower(lo));
     138  return UChar(tolower(uc));
    138139}
    139140
    140141UChar UChar::toUpper() const
    141142{
    142   if (isupper(lo) && hi == 0)
     143  if (uc >= 256 || isupper(uc))
    143144    return *this;
    144145
    145   return UChar(0, toupper(lo));
     146  return UChar(toupper(uc));
    146147}
    147148
     
    237238{
    238239  char buf[40];
    239   sprintf(buf, "%.16g", d);     // does the right thing
     240
     241  if (d == -0)
     242    strcpy(buf,"0");
     243  else if (KJS::isNaN(d))
     244    strcpy(buf,"NaN");
     245  else if (KJS::isPosInf(d))
     246    strcpy(buf,"Infinity");
     247  else if (KJS::isNegInf(d))
     248    strcpy(buf,"-Infinity");
     249  else
     250    sprintf(buf, "%.16g", d);   // does the right thing
     251
     252  // ECMA 3rd ed. 9.8.1 9 e: "with no leading zeros"
     253  int buflen = strlen(buf);
     254  if (buflen >= 4 && buf[buflen-4] == 'e' && buf[buflen-2] == '0') {
     255    buf[buflen-2] = buf[buflen-1];
     256    buf[buflen-1] = 0;
     257  }
     258
    240259  return UString(buf);
    241260}
     
    265284  statBuffer = new char[size()+1];
    266285  for(int i = 0; i < size(); i++)
    267     statBuffer[i] = data()[i].lo;
     286    statBuffer[i] = data()[i].low();
    268287  statBuffer[size()] = '\0';
    269288
     
    277296  UChar *d = new UChar[l];
    278297  for (int i = 0; i < l; i++)
    279     d[i].lo = c[i];
     298    d[i].uc = c[i];
    280299  rep = Rep::create(d, l);
    281300
     
    287306  str.rep->ref();
    288307  release();
    289   rep = str.rep; 
     308  rep = str.rep;
    290309
    291310  return *this;
     
    301320  const UChar *u = data();
    302321  for(int i = 0; i < size(); i++, u++)
    303     if (u->hi)
     322    if (u->uc > 0xFF)
    304323      return false;
    305324
     
    321340}
    322341
    323 double UString::toDouble() const
     342double UString::toDouble( bool tolerant ) const
    324343{
    325344  double d;
     
    355374    char *end;
    356375    d = strtod(c, &end);
    357     if (d != 0.0 || end != c) {
     376    if ((d != 0.0 || end != c) && d != HUGE_VAL && d != -HUGE_VAL) {
    358377      c = end;
    359378    } else {
     
    376395  while (isspace(*c))
    377396    c++;
    378   if (*c != '\0')
     397  // don't allow anything after - unless tolerant=true
     398  if ( !tolerant && *c != '\0')
    379399    d = NaN;
    380400
     
    474494}
    475495
    476 bool KJS::operator==(const UChar &c1, const UChar &c2)
    477 {
    478   return ((c1.lo == c2.lo) & (c1.hi == c2.hi));
    479 }
    480 
    481496bool KJS::operator==(const UString& s1, const UString& s2)
    482497{
     
    498513  const UChar *u = s1.data();
    499514  while (*s2) {
    500     if (u->lo != *s2 || u->hi != 0)
     515    if (u->uc != *s2 )
    501516      return false;
    502517    s2++;
     
    505520
    506521  return true;
    507 }
    508 
    509 bool KJS::operator==(const char *s1, const UString& s2)
    510 {
    511   return operator==(s2, s1);
    512522}
    513523
  • trunk/JavaScriptCore/kjs/ustring.h

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
     
    1718 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1819 *  Boston, MA 02111-1307, USA.
     20 *
     21 *  $Id$
    1922 */
    2023
    21 #ifndef _KJS_STRING_H_
    22 #define _KJS_STRING_H_
     24#ifndef _KJS_USTRING_H_
     25#define _KJS_USTRING_H_
    2326
    2427#ifdef HAVE_CONFIG_H
    2528#include <config.h>
     29#endif
     30
     31#ifdef APPLE_CHANGES
     32#include <KWQDef.h>
    2633#endif
    2734
     
    3643class QConstString;
    3744
    38 #if defined(__GNUC__)
    39 #define KJS_PACKED __attribute__((__packed__))
    40 #else
    41 #define KJS_PACKED
    42 #endif
    43 
    4445namespace KJS {
    4546
     
    7475     * @return The higher byte of the character.
    7576     */
    76     unsigned char high() const { return hi; }
     77    unsigned char high() const { return uc >> 8; }
    7778    /**
    7879     * @return The lower byte of the character.
    7980     */
    80     unsigned char low() const { return lo; }
     81    unsigned char low() const { return uc & 0xFF; }
    8182    /**
    8283     * @return the 16 bit Unicode value of the character
    8384     */
    84     unsigned short unicode() const { return hi << 8 | lo; }
     85    unsigned short unicode() const { return uc; }
    8586  public:
    8687    /**
     
    102103    friend bool operator==(const UString& s1, const char *s2);
    103104    friend bool operator<(const UString& s1, const UString& s2);
    104 #ifdef KJS_SWAPPED_CHAR
    105     unsigned char lo;
    106     unsigned char hi;
    107 #else
    108     unsigned char hi;
    109     unsigned char lo;
    110 #endif
    111   } KJS_PACKED;
    112 
    113 
    114 #ifdef KJS_SWAPPED_CHAR // to avoid reorder warnings
    115   inline UChar::UChar() : lo(0), hi(0) { }
    116   inline UChar::UChar(unsigned char h , unsigned char l) : lo(l), hi(h) { }
    117   inline UChar::UChar(unsigned short u) : lo(u & 0x00ff), hi(u >> 8) { }
    118 #else
    119   inline UChar::UChar() : hi(0), lo(0) { }
    120   inline UChar::UChar(unsigned char h , unsigned char l) : hi(h), lo(l) { }
    121   inline UChar::UChar(unsigned short u) : hi(u >> 8), lo(u & 0x00ff) { }
    122 #endif
     105
     106    ushort uc;
     107  };
     108
     109  inline UChar::UChar() : uc(0) { }
     110  inline UChar::UChar(unsigned char h , unsigned char l) : uc(h << 8 | l) { }
     111  inline UChar::UChar(unsigned short u) : uc(u) { }
    123112
    124113  /**
     
    155144     * @return Lower byte.
    156145     */
    157     unsigned char& low() const { return ref().lo; }
     146    unsigned char low() const { return ref().uc & 0xFF; }
    158147    /**
    159148     * @return Higher byte.
    160149     */
    161     unsigned char& high() const { return ref().hi; }
     150    unsigned char high() const { return ref().uc >> 8; }
    162151    /**
    163152     * @return Character converted to lower case.
     
    365354     * indicated by a 0x or 0X prefix) and +/- Infinity.
    366355     * Returns NaN if the conversion failed.
    367      */
    368     double toDouble() const;
     356     * @param tolerant if true, toDouble can tolerate garbage after the number.
     357     */
     358    double toDouble(bool tolerant=false) const;
    369359    /**
    370360     * Attempts an conversion to an unsigned long integer. ok will be set
     
    398388  };
    399389
    400   bool operator==(const UChar &c1, const UChar &c2);
     390  inline bool operator==(const UChar &c1, const UChar &c2) {
     391    return (c1.uc == c2.uc);
     392  }
    401393  bool operator==(const UString& s1, const UString& s2);
    402394  inline bool operator!=(const UString& s1, const UString& s2) {
     
    408400    return !KJS::operator==(s1, s2);
    409401  }
    410   bool operator==(const char *s1, const UString& s2);
     402  inline bool operator==(const char *s1, const UString& s2) {
     403    return operator==(s2, s1);
     404  }
    411405  inline bool operator!=(const char *s1, const UString& s2) {
    412406    return !KJS::operator==(s1, s2);
Note: See TracChangeset for help on using the changeset viewer.