string_object.cpp

00001 // -*- c-basic-offset: 2 -*-
00002 /*
00003  *  This file is part of the KDE libraries
00004  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
00005  *  Copyright (C) 2003 Apple Computer, Inc.
00006  *
00007  *  This library is free software; you can redistribute it and/or
00008  *  modify it under the terms of the GNU Lesser General Public
00009  *  License as published by the Free Software Foundation; either
00010  *  version 2 of the License, or (at your option) any later version.
00011  *
00012  *  This library is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  *  Lesser General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU Lesser General Public
00018  *  License along with this library; if not, write to the Free Software
00019  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020  *
00021  */
00022 
00023 #include "value.h"
00024 #include "object.h"
00025 #include "types.h"
00026 #include "interpreter.h"
00027 #include "operations.h"
00028 #include "regexp.h"
00029 #include "regexp_object.h"
00030 #include "string_object.h"
00031 #include "error_object.h"
00032 #include <stdio.h>
00033 #include "string_object.lut.h"
00034 
00035 #ifdef HAVE_STDINT_H
00036 #include <stdint.h>
00037 #endif
00038 #ifdef HAVE_SYS_TYPES_H
00039 #include <sys/types.h>
00040 #endif
00041 #ifdef HAVE_SYS_BITYPES_H
00042 #include <sys/bitypes.h> /* For uintXX_t on Tru64 */
00043 #endif
00044 
00045 using namespace KJS;
00046 
00047 // ------------------------------ StringInstanceImp ----------------------------
00048 
00049 const ClassInfo StringInstanceImp::info = {"String", 0, 0, 0};
00050 
00051 StringInstanceImp::StringInstanceImp(ObjectImp *proto)
00052   : ObjectImp(proto)
00053 {
00054   setInternalValue(String(""));
00055 }
00056 
00057 StringInstanceImp::StringInstanceImp(ObjectImp *proto, const UString &string)
00058   : ObjectImp(proto)
00059 {
00060   setInternalValue(String(string));
00061 }
00062 
00063 Value StringInstanceImp::get(ExecState *exec, const Identifier &propertyName) const
00064 {
00065   if (propertyName == lengthPropertyName)
00066     return Number(internalValue().toString(exec).size());
00067 
00068   bool ok;
00069   const unsigned index = propertyName.toArrayIndex(&ok);
00070   if (ok) {
00071     const UString s = internalValue().toString(exec);
00072     const unsigned length = s.size();
00073     if (index < length) {
00074       const UChar c = s[index];
00075       return String(UString(&c, 1));
00076     }
00077   }
00078 
00079   return ObjectImp::get(exec, propertyName);
00080 }
00081 
00082 void StringInstanceImp::put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr)
00083 {
00084   if (propertyName == lengthPropertyName)
00085     return;
00086   ObjectImp::put(exec, propertyName, value, attr);
00087 }
00088 
00089 bool StringInstanceImp::hasProperty(ExecState *exec, const Identifier &propertyName) const
00090 {
00091   if (propertyName == lengthPropertyName)
00092     return true;
00093 
00094   bool ok;
00095   unsigned index = propertyName.toULong(&ok);
00096   if (ok && index < (unsigned)internalValue().toString(exec).size())
00097     return true;
00098 
00099   return ObjectImp::hasProperty(exec, propertyName);
00100 }
00101 
00102 bool StringInstanceImp::deleteProperty(ExecState *exec, const Identifier &propertyName)
00103 {
00104   if (propertyName == lengthPropertyName)
00105     return false;
00106 
00107   bool ok;
00108   unsigned index = propertyName.toULong(&ok);
00109   if (ok && index < (unsigned)internalValue().toString(exec).size())
00110     return false;
00111 
00112   return ObjectImp::deleteProperty(exec, propertyName);
00113 }
00114 
00115 ReferenceList StringInstanceImp::propList(ExecState *exec, bool recursive)
00116 {
00117   ReferenceList properties = ObjectImp::propList(exec,recursive);
00118 
00119   UString str = internalValue().toString(exec);
00120   for (int i = 0; i < str.size(); i++)
00121     if (!ObjectImp::hasProperty(exec,Identifier::from(i)))
00122       properties.append(Reference(this, i));
00123 
00124   return properties;
00125 }
00126 
00127 // ------------------------------ StringPrototypeImp ---------------------------
00128 const ClassInfo StringPrototypeImp::info = {"String", &StringInstanceImp::info, &stringTable, 0};
00129 /* Source for string_object.lut.h
00130 @begin stringTable 28
00131   toString      StringProtoFuncImp::ToString    DontEnum|Function   0
00132   valueOf       StringProtoFuncImp::ValueOf DontEnum|Function   0
00133   charAt        StringProtoFuncImp::CharAt  DontEnum|Function   1
00134   charCodeAt        StringProtoFuncImp::CharCodeAt  DontEnum|Function   1
00135   concat        StringProtoFuncImp::Concat  DontEnum|Function   1
00136   indexOf       StringProtoFuncImp::IndexOf DontEnum|Function   1
00137   lastIndexOf       StringProtoFuncImp::LastIndexOf DontEnum|Function   1
00138   match         StringProtoFuncImp::Match   DontEnum|Function   1
00139   replace       StringProtoFuncImp::Replace DontEnum|Function   2
00140   search        StringProtoFuncImp::Search  DontEnum|Function   1
00141   slice         StringProtoFuncImp::Slice   DontEnum|Function   2
00142   split         StringProtoFuncImp::Split   DontEnum|Function   2
00143   substr        StringProtoFuncImp::Substr  DontEnum|Function   2
00144   substring     StringProtoFuncImp::Substring   DontEnum|Function   2
00145   toLowerCase       StringProtoFuncImp::ToLowerCase DontEnum|Function   0
00146   toUpperCase       StringProtoFuncImp::ToUpperCase DontEnum|Function   0
00147   toLocaleLowerCase StringProtoFuncImp::ToLocaleLowerCase DontEnum|Function 0
00148   toLocaleUpperCase     StringProtoFuncImp::ToLocaleUpperCase DontEnum|Function 0
00149 #
00150 # Under here: html extension, should only exist if KJS_PURE_ECMA is not defined
00151 # I guess we need to generate two hashtables in the .lut.h file, and use #ifdef
00152 # to select the right one... TODO. #####
00153   big           StringProtoFuncImp::Big     DontEnum|Function   0
00154   small         StringProtoFuncImp::Small   DontEnum|Function   0
00155   blink         StringProtoFuncImp::Blink   DontEnum|Function   0
00156   bold          StringProtoFuncImp::Bold    DontEnum|Function   0
00157   fixed         StringProtoFuncImp::Fixed   DontEnum|Function   0
00158   italics       StringProtoFuncImp::Italics DontEnum|Function   0
00159   strike        StringProtoFuncImp::Strike  DontEnum|Function   0
00160   sub           StringProtoFuncImp::Sub     DontEnum|Function   0
00161   sup           StringProtoFuncImp::Sup     DontEnum|Function   0
00162   fontcolor     StringProtoFuncImp::Fontcolor   DontEnum|Function   1
00163   fontsize      StringProtoFuncImp::Fontsize    DontEnum|Function   1
00164   anchor        StringProtoFuncImp::Anchor  DontEnum|Function   1
00165   link          StringProtoFuncImp::Link    DontEnum|Function   1
00166 @end
00167 */
00168 // ECMA 15.5.4
00169 StringPrototypeImp::StringPrototypeImp(ExecState * /*exec*/,
00170                                        ObjectPrototypeImp *objProto)
00171   : StringInstanceImp(objProto)
00172 {
00173   Value protect(this);
00174   // The constructor will be added later, after StringObjectImp has been built
00175   putDirect(lengthPropertyName, NumberImp::zero(), DontDelete|ReadOnly|DontEnum);
00176 
00177 }
00178 
00179 Value StringPrototypeImp::get(ExecState *exec, const Identifier &propertyName) const
00180 {
00181   return lookupGetFunction<StringProtoFuncImp, StringInstanceImp>( exec, propertyName, &stringTable, this );
00182 }
00183 
00184 // ------------------------------ StringProtoFuncImp ---------------------------
00185 
00186 StringProtoFuncImp::StringProtoFuncImp(ExecState *exec, int i, int len)
00187   : InternalFunctionImp(
00188     static_cast<FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype().imp())
00189     ), id(i)
00190 {
00191   Value protect(this);
00192   putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
00193 }
00194 
00195 bool StringProtoFuncImp::implementsCall() const
00196 {
00197   return true;
00198 }
00199 
00200 // ECMA 15.5.4.2 - 15.5.4.20
00201 Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
00202 {
00203   Value result;
00204 
00205   // toString and valueOf are no generic functions.
00206   if (id == ToString || id == ValueOf) {
00207     KJS_CHECK_THIS( StringInstanceImp, thisObj );
00208 
00209     return String(thisObj.internalValue().toString(exec));
00210   }
00211 
00212   int n, m;
00213   UString u2, u3;
00214   double dpos;
00215   int pos, p0, i;
00216   double d = 0.0;
00217 
00218   UString s = thisObj.toString(exec);
00219 
00220   int len = s.size();
00221   Value a0 = args[0];
00222   Value a1 = args[1];
00223 
00224   switch (id) {
00225   case ToString:
00226   case ValueOf:
00227     // handled above
00228     break;
00229   case CharAt:
00230     pos = a0.type() == UndefinedType ? 0 : a0.toInteger(exec);
00231     if (pos < 0 || pos >= len)
00232       s = "";
00233     else
00234       s = s.substr(pos, 1);
00235     result = String(s);
00236     break;
00237   case CharCodeAt:
00238     pos = a0.type() == UndefinedType ? 0 : a0.toInteger(exec);
00239     if (pos < 0 || pos >= len)
00240       d = NaN;
00241     else {
00242       UChar c = s[pos];
00243       d = (c.high() << 8) + c.low();
00244     }
00245     result = Number(d);
00246     break;
00247   case Concat: {
00248     ListIterator it = args.begin();
00249     for ( ; it != args.end() ; ++it) {
00250         s += it->dispatchToString(exec);
00251     }
00252     result = String(s);
00253     break;
00254   }
00255   case IndexOf:
00256     u2 = a0.toString(exec);
00257     if (a1.type() == UndefinedType)
00258       pos = 0;
00259     else
00260       pos = a1.toInteger(exec);
00261     d = s.find(u2, pos);
00262     result = Number(d);
00263     break;
00264   case LastIndexOf:
00265     u2 = a0.toString(exec);
00266     d = a1.toNumber(exec);
00267     if (a1.type() == UndefinedType || KJS::isNaN(d))
00268       dpos = len;
00269     else {
00270       dpos = d;
00271       if (dpos < 0)
00272         dpos = 0;
00273       else if (dpos > len)
00274         dpos = len;
00275     }
00276     result = Number(s.rfind(u2, int(dpos)));
00277     break;
00278   case Match:
00279   case Search: {
00280     RegExp *reg, *tmpReg = 0;
00281     RegExpImp *imp = 0;
00282     if (a0.isA(ObjectType) && a0.toObject(exec).inherits(&RegExpImp::info))
00283     {
00284       imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
00285       reg = imp->regExp();
00286     }
00287     else
00288     { /*
00289        *  ECMA 15.5.4.12 String.prototype.search (regexp)
00290        *  If regexp is not an object whose [[Class]] property is "RegExp", it is
00291        *  replaced with the result of the expression new RegExp(regexp).
00292        */
00293       reg = tmpReg = new RegExp(a0.toString(exec), RegExp::None);
00294     }
00295     RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp());
00296     int **ovector = regExpObj->registerRegexp(reg, s);
00297     UString mstr = reg->match(s, -1, &pos, ovector);
00298     if (id == Search) {
00299       result = Number(pos);
00300     } else { // Match
00301       if (mstr.isNull()) {
00302         result = Null(); // no match
00303       } else if ((reg->flags() & RegExp::Global) == 0) {
00304     // case without 'g' flag is handled like RegExp.prototype.exec
00305     regExpObj->setSubPatterns(reg->subPatterns());
00306     result = regExpObj->arrayOfMatches(exec,mstr);
00307       } else {
00308     // return array of matches
00309     List list;
00310     while (pos >= 0) {
00311       list.append(String(mstr));
00312       pos += mstr.isEmpty() ? 1 : mstr.size();
00313       delete [] *ovector;
00314       mstr = reg->match(s, pos, &pos, ovector);
00315     }
00316     result = exec->lexicalInterpreter()->builtinArray().construct(exec, list);
00317       }
00318     }
00319     delete tmpReg;
00320     break;
00321   }
00322   case Replace:
00323     if (a0.type() == ObjectType && a0.toObject(exec).inherits(&RegExpImp::info)) {
00324       RegExpImp* imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
00325       RegExp *reg = imp->regExp();
00326       bool global = false;
00327       Value tmp = imp->get(exec,"global");
00328       if (tmp.type() != UndefinedType && tmp.toBoolean(exec) == true)
00329         global = true;
00330 
00331       RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalInterpreter()->builtinRegExp().imp());
00332       int lastIndex = 0;
00333       Object o1;
00334       // Test if 2nd arg is a function (new in JS 1.3)
00335       if ( a1.type() == ObjectType && a1.toObject(exec).implementsCall() )
00336         o1 = a1.toObject(exec);
00337       else
00338         u3 = a1.toString(exec); // 2nd arg is the replacement string
00339 
00340       // This is either a loop (if global is set) or a one-way (if not).
00341       do {
00342         int **ovector = regExpObj->registerRegexp( reg, s );
00343         UString mstr = reg->match(s, lastIndex, &pos, ovector);
00344         regExpObj->setSubPatterns(reg->subPatterns());
00345         if (pos == -1)
00346           break;
00347         len = mstr.size();
00348 
00349         UString rstr;
00350         // Prepare replacement
00351         if (!o1.isValid())
00352         {
00353           rstr = u3;
00354           bool ok;
00355           // check if u3 matches $1 or $2 etc
00356           for (int i = 0; (i = rstr.find(UString("$"), i)) != -1; i++) {
00357             if (i+1<rstr.size() && rstr[i+1] == '$') {  // "$$" -> "$"
00358               rstr = rstr.substr(0,i) + "$" + rstr.substr(i+2);
00359               continue;
00360             }
00361             // Assume number part is one char exactly
00362             unsigned long pos = rstr.substr(i+1,1).toULong(&ok, false /* tolerate empty string */);
00363             if (ok && pos <= (unsigned)reg->subPatterns()) {
00364               rstr = rstr.substr(0,i)
00365                      + s.substr((*ovector)[2*pos],
00366                                 (*ovector)[2*pos+1]-(*ovector)[2*pos])
00367                      + rstr.substr(i+2);
00368               i += (*ovector)[2*pos+1]-(*ovector)[2*pos] - 1; // -1 offsets i++
00369             }
00370           }
00371         } else // 2nd arg is a function call. Spec from http://devedge.netscape.com/library/manuals/2000/javascript/1.5/reference/string.html#1194258
00372         {
00373           List l;
00374           l.append(String(mstr)); // First arg: complete matched substring
00375           // Then the submatch strings
00376           for ( unsigned int sub = 1; sub <= reg->subPatterns() ; ++sub )
00377             l.append( String( s.substr((*ovector)[2*sub],
00378                                (*ovector)[2*sub+1]-(*ovector)[2*sub]) ) );
00379           l.append(Number(pos)); // The offset within the string where the match occurred
00380           l.append(String(s)); // Last arg: the string itself. Can't see the difference with the 1st arg!
00381           Object thisObj = exec->interpreter()->globalObject();
00382           rstr = o1.call( exec, thisObj, l ).toString(exec);
00383         }
00384         lastIndex = pos + rstr.size();
00385         s = s.substr(0, pos) + rstr + s.substr(pos + len);
00386         //fprintf(stderr,"pos=%d,len=%d,lastIndex=%d,s=%s\n",pos,len,lastIndex,s.ascii());
00387       } while (global);
00388 
00389       result = String(s);
00390     } else { // First arg is a string
00391       u2 = a0.toString(exec);
00392       pos = s.find(u2);
00393       len = u2.size();
00394       // Do the replacement
00395       if (pos == -1)
00396         result = String(s);
00397       else {
00398         u3 = s.substr(0, pos) + a1.toString(exec) +
00399              s.substr(pos + len);
00400         result = String(u3);
00401       }
00402     }
00403     break;
00404   case Slice: // http://developer.netscape.com/docs/manuals/js/client/jsref/string.htm#1194366 or 15.5.4.13
00405     {
00406         // The arg processing is very much like ArrayProtoFunc::Slice
00407         int begin = args[0].toUInt32(exec);
00408         int end = len;
00409         if (args[1].type() != UndefinedType) {
00410           end = args[1].toInteger(exec);
00411         }
00412         int from = begin < 0 ? len + begin : begin;
00413         int to = end < 0 ? len + end : end;
00414         if (to > from && to > 0 && from < len) {
00415           if (from < 0) {
00416             from = 0;
00417           }
00418           if (to > len) {
00419             to = len;
00420           }
00421           result = String(s.substr(from, to - from));
00422         } else {
00423           result = String("");
00424         }
00425         break;
00426     }
00427     case Split: {
00428     Object constructor = exec->lexicalInterpreter()->builtinArray();
00429     Object res = Object::dynamicCast(constructor.construct(exec,List::empty()));
00430     result = res;
00431     i = p0 = 0;
00432     uint32_t limit = (a1.type() != UndefinedType) ? a1.toUInt32(exec) : 0xFFFFFFFFU;
00433     if (a0.type() == ObjectType && Object::dynamicCast(a0).inherits(&RegExpImp::info)) {
00434       Object obj0 = Object::dynamicCast(a0);
00435       RegExp reg(obj0.get(exec,"source").toString(exec));
00436       if (s.isEmpty() && !reg.match(s, 0).isNull()) {
00437     // empty string matched by regexp -> empty array
00438     res.put(exec, lengthPropertyName, Number(0), DontDelete|ReadOnly|DontEnum);
00439     break;
00440       }
00441       pos = 0;
00442       while (static_cast<uint32_t>(i) != limit && pos < s.size()) {
00443     // TODO: back references
00444         int mpos;
00445         int *ovector = 0L;
00446     UString mstr = reg.match(s, pos, &mpos, &ovector);
00447         delete [] ovector; ovector = 0L;
00448     if (mpos < 0)
00449       break;
00450     pos = mpos + (mstr.isEmpty() ? 1 : mstr.size());
00451     if (mpos != p0 || !mstr.isEmpty()) {
00452       res.put(exec,i, String(s.substr(p0, mpos-p0)));
00453       p0 = mpos + mstr.size();
00454       i++;
00455     }
00456       }
00457     } else {
00458       u2 = a0.toString(exec);
00459       if (u2.isEmpty()) {
00460     if (s.isEmpty()) {
00461       // empty separator matches empty string -> empty array
00462       put(exec,lengthPropertyName, Number(0));
00463       break;
00464     } else {
00465       while (static_cast<uint32_t>(i) != limit && i < s.size()-1)
00466         res.put(exec,i++, String(s.substr(p0++, 1)));
00467     }
00468       } else {
00469     while (static_cast<uint32_t>(i) != limit && (pos = s.find(u2, p0)) >= 0) {
00470       res.put(exec,i, String(s.substr(p0, pos-p0)));
00471       p0 = pos + u2.size();
00472       i++;
00473     }
00474       }
00475     }
00476     // add remaining string, if any
00477     if (static_cast<uint32_t>(i) != limit)
00478       res.put(exec,i++, String(s.substr(p0)));
00479     res.put(exec,lengthPropertyName, Number(i));
00480     }
00481     break;
00482   case Substr: {
00483     n = a0.toInteger(exec);
00484     m = a1.toInteger(exec);
00485     int d, d2;
00486     if (n >= 0)
00487       d = n;
00488     else
00489       d = maxInt(len + n, 0);
00490     if (a1.type() == UndefinedType)
00491       d2 = len - d;
00492     else
00493       d2 = minInt(maxInt(m, 0), len - d);
00494     result = String(s.substr(d, d2));
00495     break;
00496   }
00497   case Substring: {
00498     double start = a0.toNumber(exec);
00499     double end = a1.toNumber(exec);
00500     if (KJS::isNaN(start))
00501       start = 0;
00502     if (KJS::isNaN(end))
00503       end = 0;
00504     if (start < 0)
00505       start = 0;
00506     if (end < 0)
00507       end = 0;
00508     if (start > len)
00509       start = len;
00510     if (end > len)
00511       end = len;
00512     if (a1.type() == UndefinedType)
00513       end = len;
00514     if (start > end) {
00515       double temp = end;
00516       end = start;
00517       start = temp;
00518     }
00519     result = String(s.substr((int)start, (int)end-(int)start));
00520     }
00521     break;
00522   case ToLowerCase:
00523   case ToLocaleLowerCase: // FIXME: To get this 100% right we need to detect Turkish and change I to lowercase i without a dot.
00524     for (i = 0; i < len; i++)
00525       s[i] = s[i].toLower();
00526     result = String(s);
00527     break;
00528   case ToUpperCase:
00529   case ToLocaleUpperCase: // FIXME: To get this 100% right we need to detect Turkish and change i to uppercase I with a dot.
00530     for (i = 0; i < len; i++)
00531       s[i] = s[i].toUpper();
00532     result = String(s);
00533     break;
00534 #ifndef KJS_PURE_ECMA
00535   case Big:
00536     result = String("<big>" + s + "</big>");
00537     break;
00538   case Small:
00539     result = String("<small>" + s + "</small>");
00540     break;
00541   case Blink:
00542     result = String("<blink>" + s + "</blink>");
00543     break;
00544   case Bold:
00545     result = String("<b>" + s + "</b>");
00546     break;
00547   case Fixed:
00548     result = String("<tt>" + s + "</tt>");
00549     break;
00550   case Italics:
00551     result = String("<i>" + s + "</i>");
00552     break;
00553   case Strike:
00554     result = String("<strike>" + s + "</strike>");
00555     break;
00556   case Sub:
00557     result = String("<sub>" + s + "</sub>");
00558     break;
00559   case Sup:
00560     result = String("<sup>" + s + "</sup>");
00561     break;
00562   case Fontcolor:
00563     result = String("<font color=\"" + a0.toString(exec) + "\">" + s + "</font>");
00564     break;
00565   case Fontsize:
00566     result = String("<font size=\"" + a0.toString(exec) + "\">" + s + "</font>");
00567     break;
00568   case Anchor:
00569     result = String("<a name=\"" + a0.toString(exec) + "\">" + s + "</a>");
00570     break;
00571   case Link:
00572     result = String("<a href=\"" + a0.toString(exec) + "\">" + s + "</a>");
00573     break;
00574 #endif
00575   }
00576 
00577   return result;
00578 }
00579 
00580 // ------------------------------ StringObjectImp ------------------------------
00581 
00582 StringObjectImp::StringObjectImp(ExecState *exec,
00583                                  FunctionPrototypeImp *funcProto,
00584                                  StringPrototypeImp *stringProto)
00585   : InternalFunctionImp(funcProto)
00586 {
00587   Value protect(this);
00588   // ECMA 15.5.3.1 String.prototype
00589   putDirect(prototypePropertyName, stringProto, DontEnum|DontDelete|ReadOnly);
00590 
00591   putDirect("fromCharCode", new StringObjectFuncImp(exec,funcProto), DontEnum);
00592 
00593   // no. of arguments for constructor
00594   putDirect(lengthPropertyName, NumberImp::one(), ReadOnly|DontDelete|DontEnum);
00595 }
00596 
00597 
00598 bool StringObjectImp::implementsConstruct() const
00599 {
00600   return true;
00601 }
00602 
00603 // ECMA 15.5.2
00604 Object StringObjectImp::construct(ExecState *exec, const List &args)
00605 {
00606   ObjectImp *proto = exec->lexicalInterpreter()->builtinStringPrototype().imp();
00607   if (args.size() == 0)
00608     return Object(new StringInstanceImp(proto));
00609   return Object(new StringInstanceImp(proto, args.begin()->dispatchToString(exec)));
00610 }
00611 
00612 bool StringObjectImp::implementsCall() const
00613 {
00614   return true;
00615 }
00616 
00617 // ECMA 15.5.1
00618 Value StringObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
00619 {
00620   if (args.isEmpty())
00621     return String("");
00622   else {
00623     Value v = args[0];
00624     return String(v.toString(exec));
00625   }
00626 }
00627 
00628 // ------------------------------ StringObjectFuncImp --------------------------
00629 
00630 // ECMA 15.5.3.2 fromCharCode()
00631 StringObjectFuncImp::StringObjectFuncImp(ExecState* /*exec*/, FunctionPrototypeImp *funcProto)
00632   : InternalFunctionImp(funcProto)
00633 {
00634   Value protect(this);
00635   putDirect(lengthPropertyName, NumberImp::one(), DontDelete|ReadOnly|DontEnum);
00636 }
00637 
00638 bool StringObjectFuncImp::implementsCall() const
00639 {
00640   return true;
00641 }
00642 
00643 Value StringObjectFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
00644 {
00645   UString s;
00646   if (args.size()) {
00647     UChar *buf = new UChar[args.size()];
00648     UChar *p = buf;
00649     ListIterator it = args.begin();
00650     while (it != args.end()) {
00651       unsigned short u = it->toUInt16(exec);
00652       *p++ = UChar(u);
00653       it++;
00654     }
00655     s = UString(buf, args.size(), false);
00656   } else
00657     s = "";
00658 
00659   return String(s);
00660 }
KDE Home | KDE Accessibility Home | Description of Access Keys