Home | History | Annotate | Download | only in runtime
      1 /*
      2  *  Copyright (C) 1999-2000 Harri Porten (porten (at) kde.org)
      3  *  Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved.
      4  *
      5  *  This library is free software; you can redistribute it and/or
      6  *  modify it under the terms of the GNU Lesser General Public
      7  *  License as published by the Free Software Foundation; either
      8  *  version 2 of the License, or (at your option) any later version.
      9  *
     10  *  This library is distributed in the hope that it will be useful,
     11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  *  Lesser General Public License for more details.
     14  *
     15  *  You should have received a copy of the GNU Lesser General Public
     16  *  License along with this library; if not, write to the Free Software
     17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     18  *
     19  */
     20 
     21 #include "config.h"
     22 #include "RegExpObject.h"
     23 
     24 #include "Error.h"
     25 #include "ExceptionHelpers.h"
     26 #include "JSArray.h"
     27 #include "JSGlobalObject.h"
     28 #include "JSString.h"
     29 #include "Lookup.h"
     30 #include "RegExpConstructor.h"
     31 #include "RegExpPrototype.h"
     32 #include "UStringConcatenate.h"
     33 #include <wtf/PassOwnPtr.h>
     34 
     35 namespace JSC {
     36 
     37 static JSValue regExpObjectGlobal(ExecState*, JSValue, const Identifier&);
     38 static JSValue regExpObjectIgnoreCase(ExecState*, JSValue, const Identifier&);
     39 static JSValue regExpObjectMultiline(ExecState*, JSValue, const Identifier&);
     40 static JSValue regExpObjectSource(ExecState*, JSValue, const Identifier&);
     41 static JSValue regExpObjectLastIndex(ExecState*, JSValue, const Identifier&);
     42 static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue);
     43 
     44 } // namespace JSC
     45 
     46 #include "RegExpObject.lut.h"
     47 
     48 namespace JSC {
     49 
     50 ASSERT_CLASS_FITS_IN_CELL(RegExpObject);
     51 
     52 const ClassInfo RegExpObject::s_info = { "RegExp", &JSObjectWithGlobalObject::s_info, 0, ExecState::regExpTable };
     53 
     54 /* Source for RegExpObject.lut.h
     55 @begin regExpTable
     56     global        regExpObjectGlobal       DontDelete|ReadOnly|DontEnum
     57     ignoreCase    regExpObjectIgnoreCase   DontDelete|ReadOnly|DontEnum
     58     multiline     regExpObjectMultiline    DontDelete|ReadOnly|DontEnum
     59     source        regExpObjectSource       DontDelete|ReadOnly|DontEnum
     60     lastIndex     regExpObjectLastIndex    DontDelete|DontEnum
     61 @end
     62 */
     63 
     64 RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, NonNullPassRefPtr<RegExp> regExp)
     65     : JSObjectWithGlobalObject(globalObject, structure)
     66     , d(adoptPtr(new RegExpObjectData(regExp)))
     67 {
     68     ASSERT(inherits(&s_info));
     69 }
     70 
     71 RegExpObject::~RegExpObject()
     72 {
     73 }
     74 
     75 void RegExpObject::markChildren(MarkStack& markStack)
     76 {
     77     Base::markChildren(markStack);
     78     if (UNLIKELY(!d->lastIndex.get().isInt32()))
     79         markStack.append(&d->lastIndex);
     80 }
     81 
     82 bool RegExpObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
     83 {
     84     return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, slot);
     85 }
     86 
     87 bool RegExpObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
     88 {
     89     return getStaticValueDescriptor<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, descriptor);
     90 }
     91 
     92 JSValue regExpObjectGlobal(ExecState*, JSValue slotBase, const Identifier&)
     93 {
     94     return jsBoolean(asRegExpObject(slotBase)->regExp()->global());
     95 }
     96 
     97 JSValue regExpObjectIgnoreCase(ExecState*, JSValue slotBase, const Identifier&)
     98 {
     99     return jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase());
    100 }
    101 
    102 JSValue regExpObjectMultiline(ExecState*, JSValue slotBase, const Identifier&)
    103 {
    104     return jsBoolean(asRegExpObject(slotBase)->regExp()->multiline());
    105 }
    106 
    107 JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&)
    108 {
    109     return jsString(exec, asRegExpObject(slotBase)->regExp()->pattern());
    110 }
    111 
    112 JSValue regExpObjectLastIndex(ExecState*, JSValue slotBase, const Identifier&)
    113 {
    114     return asRegExpObject(slotBase)->getLastIndex();
    115 }
    116 
    117 void RegExpObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
    118 {
    119     lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), this, slot);
    120 }
    121 
    122 void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value)
    123 {
    124     asRegExpObject(baseObject)->setLastIndex(exec->globalData(), value);
    125 }
    126 
    127 JSValue RegExpObject::test(ExecState* exec)
    128 {
    129     return jsBoolean(match(exec));
    130 }
    131 
    132 JSValue RegExpObject::exec(ExecState* exec)
    133 {
    134     if (match(exec))
    135         return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec);
    136     return jsNull();
    137 }
    138 
    139 // Shared implementation used by test and exec.
    140 bool RegExpObject::match(ExecState* exec)
    141 {
    142     RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
    143     UString input = exec->argument(0).toString(exec);
    144 
    145     if (!regExp()->global()) {
    146         int position;
    147         int length;
    148         regExpConstructor->performMatch(d->regExp.get(), input, 0, position, length);
    149         return position >= 0;
    150     }
    151 
    152     JSValue jsLastIndex = getLastIndex();
    153     unsigned lastIndex;
    154     if (LIKELY(jsLastIndex.isUInt32())) {
    155         lastIndex = jsLastIndex.asUInt32();
    156         if (lastIndex > input.length()) {
    157             setLastIndex(0);
    158             return false;
    159         }
    160     } else {
    161         double doubleLastIndex = jsLastIndex.toInteger(exec);
    162         if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
    163             setLastIndex(0);
    164             return false;
    165         }
    166         lastIndex = static_cast<unsigned>(doubleLastIndex);
    167     }
    168 
    169     int position;
    170     int length = 0;
    171     regExpConstructor->performMatch(d->regExp.get(), input, lastIndex, position, length);
    172     if (position < 0) {
    173         setLastIndex(0);
    174         return false;
    175     }
    176 
    177     setLastIndex(position + length);
    178     return true;
    179 }
    180 
    181 } // namespace JSC
    182