Ignore:
Timestamp:
Jun 28, 2008, 4:30:55 PM (17 years ago)
Author:
[email protected]
Message:

JavaScriptCore:

2008-06-28 Sam Weinig <[email protected]>

Rubber-stamped by Darin Adler.

Rename string_object.h/cpp to StringObject.h/cpp and split out StringObjectThatMasqueradesAsUndefined,
StringConstructor and StringPrototype.

  • DerivedSources.make:
  • GNUmakefile.am:
  • JavaScriptCore.pri:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • JavaScriptCoreSources.bkl:
  • kjs/AllInOneFile.cpp:
  • kjs/JSGlobalObject.cpp:
  • kjs/StringConstructor.cpp: Copied from JavaScriptCore/kjs/string_object.cpp.
  • kjs/StringConstructor.h: Copied from JavaScriptCore/kjs/string_object.h.
  • kjs/StringObject.cpp: Copied from JavaScriptCore/kjs/string_object.cpp.
  • kjs/StringObject.h: Copied from JavaScriptCore/kjs/string_object.h.
  • kjs/StringObjectThatMasqueradesAsUndefined.h: Copied from JavaScriptCore/kjs/string_object.h.
  • kjs/StringPrototype.cpp: Copied from JavaScriptCore/kjs/string_object.cpp.
  • kjs/StringPrototype.h: Copied from JavaScriptCore/kjs/string_object.h.
  • kjs/internal.cpp:
  • kjs/string_object.cpp: Removed.
  • kjs/string_object.h: Removed.

WebCore:

2008-06-28 Sam Weinig <[email protected]>

Rubber-stamped by Darin Adler.

Update includes after remaming string_object.h to StringObject.h and
splitting out StringObjectThatMasqueradesAsUndefined, StringConstructor
and StringPrototype.

  • ForwardingHeaders/kjs/StringObject.h: Copied from WebCore/ForwardingHeaders/kjs/string_object.h.
  • ForwardingHeaders/kjs/StringObjectThatMasqueradesAsUndefined.h: Added.
  • ForwardingHeaders/kjs/StringPrototype.h: Added.
  • ForwardingHeaders/kjs/string_object.h: Removed.
  • bindings/js/JSCSSStyleDeclarationCustom.cpp:
File:
1 copied

Legend:

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

    r34860 r34861  
    1 // -*- c-basic-offset: 2 -*-
    21/*
    32 *  Copyright (C) 1999-2001 Harri Porten ([email protected])
     
    2120
    2221#include "config.h"
    23 #include "string_object.h"
     22#include "StringObject.h"
    2423
    25 #include "JSArray.h"
    26 #include "JSWrapperObject.h"
    27 #include "ObjectPrototype.h"
    2824#include "PropertyNameArray.h"
    29 #include "RegExpObject.h"
    30 #include "error_object.h"
    31 #include "operations.h"
    32 #include <wtf/MathExtras.h>
    33 #include <wtf/unicode/Collator.h>
    34 
    35 using namespace WTF;
    3625
    3726namespace KJS {
    38 
    39 static JSValue* stringProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&);
    40 static JSValue* stringProtoFuncCharAt(ExecState*, JSObject*, JSValue*, const ArgList&);
    41 static JSValue* stringProtoFuncCharCodeAt(ExecState*, JSObject*, JSValue*, const ArgList&);
    42 static JSValue* stringProtoFuncConcat(ExecState*, JSObject*, JSValue*, const ArgList&);
    43 static JSValue* stringProtoFuncIndexOf(ExecState*, JSObject*, JSValue*, const ArgList&);
    44 static JSValue* stringProtoFuncLastIndexOf(ExecState*, JSObject*, JSValue*, const ArgList&);
    45 static JSValue* stringProtoFuncMatch(ExecState*, JSObject*, JSValue*, const ArgList&);
    46 static JSValue* stringProtoFuncReplace(ExecState*, JSObject*, JSValue*, const ArgList&);
    47 static JSValue* stringProtoFuncSearch(ExecState*, JSObject*, JSValue*, const ArgList&);
    48 static JSValue* stringProtoFuncSlice(ExecState*, JSObject*, JSValue*, const ArgList&);
    49 static JSValue* stringProtoFuncSplit(ExecState*, JSObject*, JSValue*, const ArgList&);
    50 static JSValue* stringProtoFuncSubstr(ExecState*, JSObject*, JSValue*, const ArgList&);
    51 static JSValue* stringProtoFuncSubstring(ExecState*, JSObject*, JSValue*, const ArgList&);
    52 static JSValue* stringProtoFuncToLowerCase(ExecState*, JSObject*, JSValue*, const ArgList&);
    53 static JSValue* stringProtoFuncToUpperCase(ExecState*, JSObject*, JSValue*, const ArgList&);
    54 static JSValue* stringProtoFuncToLocaleLowerCase(ExecState*, JSObject*, JSValue*, const ArgList&);
    55 static JSValue* stringProtoFuncToLocaleUpperCase(ExecState*, JSObject*, JSValue*, const ArgList&);
    56 static JSValue* stringProtoFuncLocaleCompare(ExecState*, JSObject*, JSValue*, const ArgList&);
    57 
    58 static JSValue* stringProtoFuncBig(ExecState*, JSObject*, JSValue*, const ArgList&);
    59 static JSValue* stringProtoFuncSmall(ExecState*, JSObject*, JSValue*, const ArgList&);
    60 static JSValue* stringProtoFuncBlink(ExecState*, JSObject*, JSValue*, const ArgList&);
    61 static JSValue* stringProtoFuncBold(ExecState*, JSObject*, JSValue*, const ArgList&);
    62 static JSValue* stringProtoFuncFixed(ExecState*, JSObject*, JSValue*, const ArgList&);
    63 static JSValue* stringProtoFuncItalics(ExecState*, JSObject*, JSValue*, const ArgList&);
    64 static JSValue* stringProtoFuncStrike(ExecState*, JSObject*, JSValue*, const ArgList&);
    65 static JSValue* stringProtoFuncSub(ExecState*, JSObject*, JSValue*, const ArgList&);
    66 static JSValue* stringProtoFuncSup(ExecState*, JSObject*, JSValue*, const ArgList&);
    67 static JSValue* stringProtoFuncFontcolor(ExecState*, JSObject*, JSValue*, const ArgList&);
    68 static JSValue* stringProtoFuncFontsize(ExecState*, JSObject*, JSValue*, const ArgList&);
    69 static JSValue* stringProtoFuncAnchor(ExecState*, JSObject*, JSValue*, const ArgList&);
    70 static JSValue* stringProtoFuncLink(ExecState*, JSObject*, JSValue*, const ArgList&);
    71 
    72 }
    73 
    74 #include "string_object.lut.h"
    75 
    76 namespace KJS {
    77 
    78 // ------------------------------ StringObject ----------------------------
    7927
    8028const ClassInfo StringObject::info = { "String", 0, 0, 0 };
     
    14997}
    15098
    151 // ------------------------------ StringPrototype ---------------------------
    152 const ClassInfo StringPrototype::info = { "String", &StringObject::info, 0, ExecState::stringTable };
    153 /* Source for string_object.lut.h
    154 @begin stringTable 26
    155   toString              stringProtoFuncToString          DontEnum|Function       0
    156   valueOf               stringProtoFuncToString          DontEnum|Function       0
    157   charAt                stringProtoFuncCharAt            DontEnum|Function       1
    158   charCodeAt            stringProtoFuncCharCodeAt        DontEnum|Function       1
    159   concat                stringProtoFuncConcat            DontEnum|Function       1
    160   indexOf               stringProtoFuncIndexOf           DontEnum|Function       1
    161   lastIndexOf           stringProtoFuncLastIndexOf       DontEnum|Function       1
    162   match                 stringProtoFuncMatch             DontEnum|Function       1
    163   replace               stringProtoFuncReplace           DontEnum|Function       2
    164   search                stringProtoFuncSearch            DontEnum|Function       1
    165   slice                 stringProtoFuncSlice             DontEnum|Function       2
    166   split                 stringProtoFuncSplit             DontEnum|Function       2
    167   substr                stringProtoFuncSubstr            DontEnum|Function       2
    168   substring             stringProtoFuncSubstring         DontEnum|Function       2
    169   toLowerCase           stringProtoFuncToLowerCase       DontEnum|Function       0
    170   toUpperCase           stringProtoFuncToUpperCase       DontEnum|Function       0
    171   toLocaleLowerCase     stringProtoFuncToLocaleLowerCase DontEnum|Function       0
    172   toLocaleUpperCase     stringProtoFuncToLocaleUpperCase DontEnum|Function       0
    173   localeCompare         stringProtoFuncLocaleCompare     DontEnum|Function       1
    174 
    175   big                   stringProtoFuncBig               DontEnum|Function       0
    176   small                 stringProtoFuncSmall             DontEnum|Function       0
    177   blink                 stringProtoFuncBlink             DontEnum|Function       0
    178   bold                  stringProtoFuncBold              DontEnum|Function       0
    179   fixed                 stringProtoFuncFixed             DontEnum|Function       0
    180   italics               stringProtoFuncItalics           DontEnum|Function       0
    181   strike                stringProtoFuncStrike            DontEnum|Function       0
    182   sub                   stringProtoFuncSub               DontEnum|Function       0
    183   sup                   stringProtoFuncSup               DontEnum|Function       0
    184   fontcolor             stringProtoFuncFontcolor         DontEnum|Function       1
    185   fontsize              stringProtoFuncFontsize          DontEnum|Function       1
    186   anchor                stringProtoFuncAnchor            DontEnum|Function       1
    187   link                  stringProtoFuncLink              DontEnum|Function       1
    188 @end
    189 */
    190 // ECMA 15.5.4
    191 StringPrototype::StringPrototype(ExecState* exec, ObjectPrototype* objProto)
    192   : StringObject(exec, objProto)
    193 {
    194   // The constructor will be added later, after StringConstructor has been built
    195   putDirect(exec->propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum);
    196 }
    197 
    198 bool StringPrototype::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot &slot)
    199 {
    200   return getStaticFunctionSlot<StringObject>(exec, ExecState::stringTable(exec), this, propertyName, slot);
    201 }
    202 
    203 // ------------------------------ Functions --------------------------
    204 
    205 static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg)
    206 {
    207   UString substitutedReplacement;
    208   int offset = 0;
    209   int i = -1;
    210   while ((i = replacement.find('$', i + 1)) != -1) {
    211     if (i + 1 == replacement.size())
    212         break;
    213 
    214     unsigned short ref = replacement[i + 1];
    215     if (ref == '$') {
    216         // "$$" -> "$"
    217         ++i;
    218         substitutedReplacement.append(replacement.data() + offset, i - offset);
    219         offset = i + 1;
    220         substitutedReplacement.append('$');
    221         continue;
    222     }
    223 
    224     int backrefStart;
    225     int backrefLength;
    226     int advance = 0;
    227     if (ref == '&') {
    228         backrefStart = ovector[0];
    229         backrefLength = ovector[1] - backrefStart;
    230     } else if (ref == '`') {
    231         backrefStart = 0;
    232         backrefLength = ovector[0];
    233     } else if (ref == '\'') {
    234         backrefStart = ovector[1];
    235         backrefLength = source.size() - backrefStart;
    236     } else if (ref >= '0' && ref <= '9') {
    237         // 1- and 2-digit back references are allowed
    238         unsigned backrefIndex = ref - '0';
    239         if (backrefIndex > reg->numSubpatterns())
    240             continue;
    241         if (replacement.size() > i + 2) {
    242             ref = replacement[i + 2];
    243             if (ref >= '0' && ref <= '9') {
    244                 backrefIndex = 10 * backrefIndex + ref - '0';
    245                 if (backrefIndex > reg->numSubpatterns())
    246                     backrefIndex = backrefIndex / 10;   // Fall back to the 1-digit reference
    247                 else
    248                     advance = 1;
    249             }
    250         }
    251         backrefStart = ovector[2 * backrefIndex];
    252         backrefLength = ovector[2 * backrefIndex + 1] - backrefStart;
    253     } else
    254         continue;
    255 
    256     if (i - offset)
    257         substitutedReplacement.append(replacement.data() + offset, i - offset);
    258     i += 1 + advance;
    259     offset = i + 1;
    260     substitutedReplacement.append(source.data() + backrefStart, backrefLength);
    261   }
    262 
    263   if (!offset)
    264     return replacement;
    265 
    266   if (replacement.size() - offset)
    267     substitutedReplacement.append(replacement.data() + offset, replacement.size() - offset);
    268 
    269   return substitutedReplacement;
    270 }
    271 
    272 static inline int localeCompare(const UString& a, const UString& b)
    273 {
    274     return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.data()), a.size(), reinterpret_cast<const ::UChar*>(b.data()), b.size());
    275 }
    276 
    277 JSValue* stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    278 {
    279   JSString* sourceVal = thisValue->toThisJSString(exec);
    280   const UString& source = sourceVal->value();
    281 
    282   JSValue* pattern = args[0];
    283 
    284   JSValue* replacement = args[1];
    285   UString replacementString;
    286   CallData callData;
    287   CallType callType = replacement->getCallData(callData);
    288   if (callType == CallTypeNone)
    289     replacementString = replacement->toString(exec);
    290 
    291   if (pattern->isObject(&RegExpObject::info)) {
    292     RegExp* reg = static_cast<RegExpObject*>(pattern)->regExp();
    293     bool global = reg->global();
    294 
    295     RegExpConstructor* regExpObj = exec->lexicalGlobalObject()->regExpConstructor();
    296 
    297     int lastIndex = 0;
    298     int startPosition = 0;
    299 
    300     Vector<UString::Range, 16> sourceRanges;
    301     Vector<UString, 16> replacements;
    302 
    303     // This is either a loop (if global is set) or a one-way (if not).
    304     do {
    305       int matchIndex;
    306       int matchLen;
    307       int* ovector;
    308       regExpObj->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector);
    309       if (matchIndex < 0)
    310         break;
    311 
    312       sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex));
    313 
    314       if (callType != CallTypeNone) {
    315           int completeMatchStart = ovector[0];
    316           ArgList args;
    317 
    318           for (unsigned i = 0; i < reg->numSubpatterns() + 1; i++) {
    319               int matchStart = ovector[i * 2];
    320               int matchLen = ovector[i * 2 + 1] - matchStart;
    321 
    322               if (matchStart < 0)
    323                 args.append(jsUndefined());
    324               else
    325                 args.append(jsString(exec, source.substr(matchStart, matchLen)));
    326           }
    327          
    328           args.append(jsNumber(exec, completeMatchStart));
    329           args.append(sourceVal);
    330 
    331           replacements.append(call(exec, replacement, callType, callData, exec->globalThisValue(), args)->toString(exec));
    332       } else
    333           replacements.append(substituteBackreferences(replacementString, source, ovector, reg));
    334 
    335       lastIndex = matchIndex + matchLen;
    336       startPosition = lastIndex;
    337 
    338       // special case of empty match
    339       if (matchLen == 0) {
    340         startPosition++;
    341         if (startPosition > source.size())
    342           break;
    343       }
    344     } while (global);
    345 
    346     if (lastIndex < source.size())
    347       sourceRanges.append(UString::Range(lastIndex, source.size() - lastIndex));
    348 
    349     UString result = source.spliceSubstringsWithSeparators(sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size());
    350 
    351     if (result == source)
    352       return sourceVal;
    353 
    354     return jsString(exec, result);
    355   }
    356  
    357   // First arg is a string
    358   UString patternString = pattern->toString(exec);
    359   int matchPos = source.find(patternString);
    360   int matchLen = patternString.size();
    361   // Do the replacement
    362   if (matchPos == -1)
    363     return sourceVal;
    364  
    365   if (callType != CallTypeNone) {
    366       ArgList args;
    367      
    368       args.append(jsString(exec, source.substr(matchPos, matchLen)));
    369       args.append(jsNumber(exec, matchPos));
    370       args.append(sourceVal);
    371      
    372       replacementString = call(exec, replacement, callType, callData, exec->globalThisValue(), args)->toString(exec);
    373   }
    374 
    375   return jsString(exec, source.substr(0, matchPos) + replacementString + source.substr(matchPos + matchLen));
    376 }
    377 
    378 JSValue* stringProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    379 {
    380     // Also used for valueOf.
    381 
    382     if (thisValue->isString())
    383         return thisValue;
    384 
    385     if (thisValue->isObject(&StringObject::info))
    386         return static_cast<StringObject*>(thisValue)->internalValue();
    387 
    388     return throwError(exec, TypeError);
    389 }
    390 
    391 JSValue* stringProtoFuncCharAt(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    392 {
    393     UString s = thisValue->toThisString(exec);
    394     int len = s.size();
    395 
    396     UString u;
    397     JSValue* a0 = args[0];
    398     double dpos = a0->toInteger(exec);
    399     if (dpos >= 0 && dpos < len)
    400       u = s.substr(static_cast<int>(dpos), 1);
    401     else
    402       u = "";
    403     return jsString(exec, u);
    404 }
    405 
    406 JSValue* stringProtoFuncCharCodeAt(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    407 {
    408     UString s = thisValue->toThisString(exec);
    409     int len = s.size();
    410 
    411     JSValue* result = 0;
    412 
    413     JSValue* a0 = args[0];
    414     double dpos = a0->toInteger(exec);
    415     if (dpos >= 0 && dpos < len)
    416       result = jsNumber(exec, s[static_cast<int>(dpos)]);
    417     else
    418       result = jsNaN(exec);
    419     return result;
    420 }
    421 
    422 JSValue* stringProtoFuncConcat(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    423 {
    424     UString s = thisValue->toThisString(exec);
    425 
    426     ArgList::const_iterator end = args.end();
    427     for (ArgList::const_iterator it = args.begin(); it != end; ++it) {
    428         s += (*it)->toString(exec);
    429     }
    430     return jsString(exec, s);
    431 }
    432 
    433 JSValue* stringProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    434 {
    435     UString s = thisValue->toThisString(exec);
    436     int len = s.size();
    437 
    438     JSValue* a0 = args[0];
    439     JSValue* a1 = args[1];
    440     UString u2 = a0->toString(exec);
    441     double dpos = a1->toInteger(exec);
    442     if (dpos < 0)
    443         dpos = 0;
    444     else if (dpos > len)
    445         dpos = len;
    446     return jsNumber(exec, s.find(u2, static_cast<int>(dpos)));
    447 }
    448 
    449 JSValue* stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    450 {
    451     UString s = thisValue->toThisString(exec);
    452     int len = s.size();
    453 
    454     JSValue* a0 = args[0];
    455     JSValue* a1 = args[1];
    456    
    457     UString u2 = a0->toString(exec);
    458     double dpos = a1->toIntegerPreserveNaN(exec);
    459     if (dpos < 0)
    460         dpos = 0;
    461     else if (!(dpos <= len)) // true for NaN
    462         dpos = len;
    463     return jsNumber(exec, s.rfind(u2, static_cast<int>(dpos)));
    464 }
    465 
    466 JSValue* stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    467 {
    468     UString s = thisValue->toThisString(exec);
    469 
    470     JSValue* a0 = args[0];
    471 
    472     UString u = s;
    473     RefPtr<RegExp> reg;
    474     RegExpObject* imp = 0;
    475     if (a0->isObject() && static_cast<JSObject *>(a0)->inherits(&RegExpObject::info)) {
    476       reg = static_cast<RegExpObject *>(a0)->regExp();
    477     } else {
    478       /*
    479        *  ECMA 15.5.4.12 String.prototype.search (regexp)
    480        *  If regexp is not an object whose [[Class]] property is "RegExp", it is
    481        *  replaced with the result of the expression new RegExp(regexp).
    482        */
    483       reg = RegExp::create(a0->toString(exec));
    484     }
    485     RegExpConstructor* regExpObj = exec->lexicalGlobalObject()->regExpConstructor();
    486     int pos;
    487     int matchLength;
    488     regExpObj->performMatch(reg.get(), u, 0, pos, matchLength);
    489     JSValue* result;
    490     if (!(reg->global())) {
    491       // case without 'g' flag is handled like RegExp.prototype.exec
    492       if (pos < 0)
    493         result = jsNull();
    494       else
    495         result = regExpObj->arrayOfMatches(exec);
    496     } else {
    497       // return array of matches
    498       ArgList list;
    499       int lastIndex = 0;
    500       while (pos >= 0) {
    501         list.append(jsString(exec, u.substr(pos, matchLength)));
    502         lastIndex = pos;
    503         pos += matchLength == 0 ? 1 : matchLength;
    504         regExpObj->performMatch(reg.get(), u, pos, pos, matchLength);
    505       }
    506       if (imp)
    507         imp->setLastIndex(lastIndex);
    508       if (list.isEmpty()) {
    509         // if there are no matches at all, it's important to return
    510         // Null instead of an empty array, because this matches
    511         // other browsers and because Null is a false value.
    512         result = jsNull();
    513       } else {
    514         result = constructArray(exec, list);
    515       }
    516     }
    517     return result;
    518 }
    519 
    520 JSValue* stringProtoFuncSearch(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    521 {
    522     UString s = thisValue->toThisString(exec);
    523 
    524     JSValue* a0 = args[0];
    525 
    526     UString u = s;
    527     RefPtr<RegExp> reg;
    528     if (a0->isObject() && static_cast<JSObject*>(a0)->inherits(&RegExpObject::info)) {
    529       reg = static_cast<RegExpObject*>(a0)->regExp();
    530     } else {
    531       /*
    532        *  ECMA 15.5.4.12 String.prototype.search (regexp)
    533        *  If regexp is not an object whose [[Class]] property is "RegExp", it is
    534        *  replaced with the result of the expression new RegExp(regexp).
    535        */
    536       reg = RegExp::create(a0->toString(exec));
    537     }
    538     RegExpConstructor* regExpObj = exec->lexicalGlobalObject()->regExpConstructor();
    539     int pos;
    540     int matchLength;
    541     regExpObj->performMatch(reg.get(), u, 0, pos, matchLength);
    542     return jsNumber(exec, pos);
    543 }
    544 
    545 JSValue* stringProtoFuncSlice(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    546 {
    547     UString s = thisValue->toThisString(exec);
    548     int len = s.size();
    549 
    550     JSValue* a0 = args[0];
    551     JSValue* a1 = args[1];
    552 
    553     // The arg processing is very much like ArrayProtoFunc::Slice
    554     double start = a0->toInteger(exec);
    555     double end = a1->isUndefined() ? len : a1->toInteger(exec);
    556     double from = start < 0 ? len + start : start;
    557     double to = end < 0 ? len + end : end;
    558     if (to > from && to > 0 && from < len) {
    559         if (from < 0)
    560             from = 0;
    561         if (to > len)
    562             to = len;
    563         return jsString(exec, s.substr(static_cast<int>(from), static_cast<int>(to - from)));
    564     }
    565 
    566     return jsString(exec, "");
    567 }
    568 
    569 JSValue* stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    570 {
    571     UString s = thisValue->toThisString(exec);
    572 
    573     JSValue* a0 = args[0];
    574     JSValue* a1 = args[1];
    575 
    576     JSObject* res = constructEmptyArray(exec);
    577     JSValue* result = res;
    578     UString u = s;
    579     int pos;
    580     int i = 0;
    581     int p0 = 0;
    582     uint32_t limit = a1->isUndefined() ? 0xFFFFFFFFU : a1->toUInt32(exec);
    583     if (a0->isObject() && static_cast<JSObject *>(a0)->inherits(&RegExpObject::info)) {
    584       RegExp *reg = static_cast<RegExpObject *>(a0)->regExp();
    585       if (u.isEmpty() && reg->match(u, 0) >= 0) {
    586         // empty string matched by regexp -> empty array
    587         res->put(exec, exec->propertyNames().length, jsNumber(exec, 0));
    588         return result;
    589       }
    590       pos = 0;
    591       while (static_cast<uint32_t>(i) != limit && pos < u.size()) {
    592         OwnArrayPtr<int> ovector;
    593         int mpos = reg->match(u, pos, &ovector);
    594         if (mpos < 0)
    595           break;
    596         int mlen = ovector[1] - ovector[0];
    597         pos = mpos + (mlen == 0 ? 1 : mlen);
    598         if (mpos != p0 || mlen) {
    599           res->put(exec,i, jsString(exec, u.substr(p0, mpos-p0)));
    600           p0 = mpos + mlen;
    601           i++;
    602         }
    603         for (unsigned si = 1; si <= reg->numSubpatterns(); ++si) {
    604           int spos = ovector[si * 2];
    605           if (spos < 0)
    606             res->put(exec, i++, jsUndefined());
    607           else
    608             res->put(exec, i++, jsString(exec, u.substr(spos, ovector[si * 2 + 1] - spos)));
    609         }
    610       }
    611     } else {
    612       UString u2 = a0->toString(exec);
    613       if (u2.isEmpty()) {
    614         if (u.isEmpty()) {
    615           // empty separator matches empty string -> empty array
    616           res->put(exec, exec->propertyNames().length, jsNumber(exec, 0));
    617           return result;
    618         } else {
    619           while (static_cast<uint32_t>(i) != limit && i < u.size()-1)
    620             res->put(exec, i++, jsString(exec, u.substr(p0++, 1)));
    621         }
    622       } else {
    623         while (static_cast<uint32_t>(i) != limit && (pos = u.find(u2, p0)) >= 0) {
    624           res->put(exec, i, jsString(exec, u.substr(p0, pos - p0)));
    625           p0 = pos + u2.size();
    626           i++;
    627         }
    628       }
    629     }
    630     // add remaining string, if any
    631     if (static_cast<uint32_t>(i) != limit)
    632       res->put(exec, i++, jsString(exec, u.substr(p0)));
    633     res->put(exec, exec->propertyNames().length, jsNumber(exec, i));
    634     return result;
    635 }
    636 
    637 JSValue* stringProtoFuncSubstr(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    638 {
    639     UString s = thisValue->toThisString(exec);
    640     int len = s.size();
    641 
    642     JSValue* a0 = args[0];
    643     JSValue* a1 = args[1];
    644 
    645     double start = a0->toInteger(exec);
    646     double length = a1->isUndefined() ? len : a1->toInteger(exec);
    647     if (start >= len)
    648       return jsString(exec, "");
    649     if (length < 0)
    650       return jsString(exec, "");
    651     if (start < 0) {
    652       start += len;
    653       if (start < 0)
    654         start = 0;
    655     }
    656     if (length > len)
    657       length = len;
    658     return jsString(exec, s.substr(static_cast<int>(start), static_cast<int>(length)));
    659 }
    660 
    661 JSValue* stringProtoFuncSubstring(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    662 {
    663     UString s = thisValue->toThisString(exec);
    664     int len = s.size();
    665 
    666     JSValue* a0 = args[0];
    667     JSValue* a1 = args[1];
    668 
    669     double start = a0->toNumber(exec);
    670     double end = a1->toNumber(exec);
    671     if (isnan(start))
    672       start = 0;
    673     if (isnan(end))
    674       end = 0;
    675     if (start < 0)
    676       start = 0;
    677     if (end < 0)
    678       end = 0;
    679     if (start > len)
    680       start = len;
    681     if (end > len)
    682       end = len;
    683     if (a1->isUndefined())
    684       end = len;
    685     if (start > end) {
    686       double temp = end;
    687       end = start;
    688       start = temp;
    689     }
    690     return jsString(exec, s.substr((int)start, (int)end-(int)start));
    691 }
    692 
    693 JSValue* stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    694 {
    695     JSString* sVal = thisValue->toThisJSString(exec);
    696     const UString& s = sVal->value();
    697    
    698     int ssize = s.size();
    699     if (!ssize)
    700         return sVal;
    701     Vector<UChar> buffer(ssize);
    702     bool error;
    703     int length = Unicode::toLower(buffer.data(), ssize, reinterpret_cast<const UChar*>(s.data()), ssize, &error);
    704     if (error) {
    705         buffer.resize(length);
    706         length = Unicode::toLower(buffer.data(), length, reinterpret_cast<const UChar*>(s.data()), ssize, &error);
    707         if (error)
    708             return sVal;
    709     }
    710     if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
    711         return sVal;
    712     return jsString(exec, UString(buffer.releaseBuffer(), length, false));
    713 }
    714 
    715 JSValue* stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    716 {
    717     JSString* sVal = thisValue->toThisJSString(exec);
    718     const UString& s = sVal->value();
    719    
    720     int ssize = s.size();
    721     if (!ssize)
    722         return sVal;
    723     Vector<UChar> buffer(ssize);
    724     bool error;
    725     int length = Unicode::toUpper(buffer.data(), ssize, reinterpret_cast<const UChar*>(s.data()), ssize, &error);
    726     if (error) {
    727         buffer.resize(length);
    728         length = Unicode::toUpper(buffer.data(), length, reinterpret_cast<const UChar*>(s.data()), ssize, &error);
    729         if (error)
    730             return sVal;
    731     }
    732     if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
    733         return sVal;
    734     return jsString(exec, UString(buffer.releaseBuffer(), length, false));
    735 }
    736 
    737 JSValue* stringProtoFuncToLocaleLowerCase(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    738 {
    739     // FIXME: See http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt for locale-sensitive mappings that aren't implemented.
    740 
    741     JSString* sVal = thisValue->toThisJSString(exec);
    742     const UString& s = sVal->value();
    743    
    744     int ssize = s.size();
    745     if (!ssize)
    746         return sVal;
    747     Vector<UChar> buffer(ssize);
    748     bool error;
    749     int length = Unicode::toLower(buffer.data(), ssize, reinterpret_cast<const UChar*>(s.data()), ssize, &error);
    750     if (error) {
    751         buffer.resize(length);
    752         length = Unicode::toLower(buffer.data(), length, reinterpret_cast<const UChar*>(s.data()), ssize, &error);
    753         if (error)
    754             return sVal;
    755     }
    756     if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
    757         return sVal;
    758     return jsString(exec, UString(buffer.releaseBuffer(), length, false));
    759 }
    760 
    761 JSValue* stringProtoFuncToLocaleUpperCase(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    762 {
    763     JSString* sVal = thisValue->toThisJSString(exec);
    764     const UString& s = sVal->value();
    765    
    766     int ssize = s.size();
    767     if (!ssize)
    768         return sVal;
    769     Vector<UChar> buffer(ssize);
    770     bool error;
    771     int length = Unicode::toUpper(buffer.data(), ssize, reinterpret_cast<const UChar*>(s.data()), ssize, &error);
    772     if (error) {
    773         buffer.resize(length);
    774         length = Unicode::toUpper(buffer.data(), length, reinterpret_cast<const UChar*>(s.data()), ssize, &error);
    775         if (error)
    776             return sVal;
    777     }
    778     if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
    779         return sVal;
    780     return jsString(exec, UString(buffer.releaseBuffer(), length, false));
    781 }
    782 
    783 JSValue* stringProtoFuncLocaleCompare(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    784 {
    785     if (args.size() < 1)
    786       return jsNumber(exec, 0);
    787 
    788     UString s = thisValue->toThisString(exec);
    789     JSValue* a0 = args[0];
    790     return jsNumber(exec, localeCompare(s, a0->toString(exec)));
    791 }
    792 
    793 JSValue* stringProtoFuncBig(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    794 {
    795     UString s = thisValue->toThisString(exec);
    796     return jsString(exec, "<big>" + s + "</big>");
    797 }
    798 
    799 JSValue* stringProtoFuncSmall(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    800 {
    801     UString s = thisValue->toThisString(exec);
    802     return jsString(exec, "<small>" + s + "</small>");
    803 }
    804 
    805 JSValue* stringProtoFuncBlink(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    806 {
    807     UString s = thisValue->toThisString(exec);
    808     return jsString(exec, "<blink>" + s + "</blink>");
    809 }
    810 
    811 JSValue* stringProtoFuncBold(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    812 {
    813     UString s = thisValue->toThisString(exec);
    814     return jsString(exec, "<b>" + s + "</b>");
    815 }
    816 
    817 JSValue* stringProtoFuncFixed(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    818 {
    819     UString s = thisValue->toThisString(exec);
    820     return jsString(exec, "<tt>" + s + "</tt>");
    821 }
    822 
    823 JSValue* stringProtoFuncItalics(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    824 {
    825     UString s = thisValue->toThisString(exec);
    826     return jsString(exec, "<i>" + s + "</i>");
    827 }
    828 
    829 JSValue* stringProtoFuncStrike(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    830 {
    831     UString s = thisValue->toThisString(exec);
    832     return jsString(exec, "<strike>" + s + "</strike>");
    833 }
    834 
    835 JSValue* stringProtoFuncSub(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    836 {
    837     UString s = thisValue->toThisString(exec);
    838     return jsString(exec, "<sub>" + s + "</sub>");
    839 }
    840 
    841 JSValue* stringProtoFuncSup(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    842 {
    843     UString s = thisValue->toThisString(exec);
    844     return jsString(exec, "<sup>" + s + "</sup>");
    845 }
    846 
    847 JSValue* stringProtoFuncFontcolor(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    848 {
    849     UString s = thisValue->toThisString(exec);
    850     JSValue* a0 = args[0];
    851     return jsString(exec, "<font color=\"" + a0->toString(exec) + "\">" + s + "</font>");
    852 }
    853 
    854 JSValue* stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    855 {
    856     UString s = thisValue->toThisString(exec);
    857     JSValue* a0 = args[0];
    858     return jsString(exec, "<font size=\"" + a0->toString(exec) + "\">" + s + "</font>");
    859 }
    860 
    861 JSValue* stringProtoFuncAnchor(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    862 {
    863     UString s = thisValue->toThisString(exec);
    864     JSValue* a0 = args[0];
    865     return jsString(exec, "<a name=\"" + a0->toString(exec) + "\">" + s + "</a>");
    866 }
    867 
    868 JSValue* stringProtoFuncLink(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    869 {
    870     UString s = thisValue->toThisString(exec);
    871     JSValue* a0 = args[0];
    872     return jsString(exec, "<a href=\"" + a0->toString(exec) + "\">" + s + "</a>");
    873 }
    874 
    875 // ------------------------------ StringConstructor ------------------------------
    876 
    877 static JSValue* stringFromCharCode(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
    878 {
    879     UString s;
    880     if (args.size()) {
    881         UChar* buf = static_cast<UChar*>(fastMalloc(args.size() * sizeof(UChar)));
    882         UChar* p = buf;
    883         ArgList::const_iterator end = args.end();
    884         for (ArgList::const_iterator it = args.begin(); it != end; ++it)
    885           *p++ = static_cast<UChar>((*it)->toUInt32(exec));
    886         s = UString(buf, args.size(), false);
    887     } else
    888         s = "";
    889 
    890     return jsString(exec, s);
    891 }
    892 
    893 StringConstructor::StringConstructor(ExecState* exec, FunctionPrototype* funcProto, StringPrototype* stringProto)
    894   : InternalFunction(funcProto, Identifier(exec, stringProto->classInfo()->className))
    895 {
    896   // ECMA 15.5.3.1 String.prototype
    897   putDirect(exec->propertyNames().prototype, stringProto, ReadOnly | DontEnum | DontDelete);
    898 
    899   // ECMA 15.5.3.2 fromCharCode()
    900   putDirectFunction(new (exec) PrototypeFunction(exec, funcProto, 1, exec->propertyNames().fromCharCode, stringFromCharCode), DontEnum);
    901 
    902   // no. of arguments for constructor
    903   putDirect(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete);
    904 }
    905 
    906 // ECMA 15.5.2
    907 static JSObject* constructWithStringConstructor(ExecState* exec, JSObject*, const ArgList& args)
    908 {
    909     JSObject* prototype = exec->lexicalGlobalObject()->stringPrototype();
    910     if (args.isEmpty())
    911         return new (exec) StringObject(exec, prototype);
    912     return new (exec) StringObject(exec, prototype, args[0]->toString(exec));
    913 }
    914 
    915 ConstructType StringConstructor::getConstructData(ConstructData& constructData)
    916 {
    917     constructData.native.function = constructWithStringConstructor;
    918     return ConstructTypeNative;
    919 }
    920 
    921 // ECMA 15.5.1
    922 static JSValue* callStringConstructor(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
    923 {
    924     if (args.isEmpty())
    925         return jsString(exec, "");
    926     return jsString(exec, args[0]->toString(exec));
    927 }
    928 
    929 CallType StringConstructor::getCallData(CallData& callData)
    930 {
    931     callData.native.function = callStringConstructor;
    932     return CallTypeNative;
    933 }
    934 
    93599} // namespace KJS
Note: See TracChangeset for help on using the changeset viewer.