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  *  Copyright (C) 2009 Torch Mobile, Inc.
      5  *
      6  *  This library is free software; you can redistribute it and/or
      7  *  modify it under the terms of the GNU Lesser General Public
      8  *  License as published by the Free Software Foundation; either
      9  *  version 2 of the License, or (at your option) any later version.
     10  *
     11  *  This library is distributed in the hope that it will be useful,
     12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  *  Lesser General Public License for more details.
     15  *
     16  *  You should have received a copy of the GNU Lesser General Public
     17  *  License along with this library; if not, write to the Free Software
     18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     19  *
     20  */
     21 
     22 #include "config.h"
     23 #include "RegExpConstructor.h"
     24 
     25 #include "ArrayPrototype.h"
     26 #include "Error.h"
     27 #include "JSArray.h"
     28 #include "JSFunction.h"
     29 #include "JSString.h"
     30 #include "ObjectPrototype.h"
     31 #include "RegExpMatchesArray.h"
     32 #include "RegExpObject.h"
     33 #include "RegExpPrototype.h"
     34 #include "RegExp.h"
     35 
     36 namespace JSC {
     37 
     38 static JSValue regExpConstructorInput(ExecState*, const Identifier&, const PropertySlot&);
     39 static JSValue regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot&);
     40 static JSValue regExpConstructorLastMatch(ExecState*, const Identifier&, const PropertySlot&);
     41 static JSValue regExpConstructorLastParen(ExecState*, const Identifier&, const PropertySlot&);
     42 static JSValue regExpConstructorLeftContext(ExecState*, const Identifier&, const PropertySlot&);
     43 static JSValue regExpConstructorRightContext(ExecState*, const Identifier&, const PropertySlot&);
     44 static JSValue regExpConstructorDollar1(ExecState*, const Identifier&, const PropertySlot&);
     45 static JSValue regExpConstructorDollar2(ExecState*, const Identifier&, const PropertySlot&);
     46 static JSValue regExpConstructorDollar3(ExecState*, const Identifier&, const PropertySlot&);
     47 static JSValue regExpConstructorDollar4(ExecState*, const Identifier&, const PropertySlot&);
     48 static JSValue regExpConstructorDollar5(ExecState*, const Identifier&, const PropertySlot&);
     49 static JSValue regExpConstructorDollar6(ExecState*, const Identifier&, const PropertySlot&);
     50 static JSValue regExpConstructorDollar7(ExecState*, const Identifier&, const PropertySlot&);
     51 static JSValue regExpConstructorDollar8(ExecState*, const Identifier&, const PropertySlot&);
     52 static JSValue regExpConstructorDollar9(ExecState*, const Identifier&, const PropertySlot&);
     53 
     54 static void setRegExpConstructorInput(ExecState*, JSObject*, JSValue);
     55 static void setRegExpConstructorMultiline(ExecState*, JSObject*, JSValue);
     56 
     57 } // namespace JSC
     58 
     59 #include "RegExpConstructor.lut.h"
     60 
     61 namespace JSC {
     62 
     63 ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor);
     64 
     65 const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::regExpConstructorTable };
     66 
     67 /* Source for RegExpConstructor.lut.h
     68 @begin regExpConstructorTable
     69     input           regExpConstructorInput          None
     70     $_              regExpConstructorInput          DontEnum
     71     multiline       regExpConstructorMultiline      None
     72     $*              regExpConstructorMultiline      DontEnum
     73     lastMatch       regExpConstructorLastMatch      DontDelete|ReadOnly
     74     $&              regExpConstructorLastMatch      DontDelete|ReadOnly|DontEnum
     75     lastParen       regExpConstructorLastParen      DontDelete|ReadOnly
     76     $+              regExpConstructorLastParen      DontDelete|ReadOnly|DontEnum
     77     leftContext     regExpConstructorLeftContext    DontDelete|ReadOnly
     78     $`              regExpConstructorLeftContext    DontDelete|ReadOnly|DontEnum
     79     rightContext    regExpConstructorRightContext   DontDelete|ReadOnly
     80     $'              regExpConstructorRightContext   DontDelete|ReadOnly|DontEnum
     81     $1              regExpConstructorDollar1        DontDelete|ReadOnly
     82     $2              regExpConstructorDollar2        DontDelete|ReadOnly
     83     $3              regExpConstructorDollar3        DontDelete|ReadOnly
     84     $4              regExpConstructorDollar4        DontDelete|ReadOnly
     85     $5              regExpConstructorDollar5        DontDelete|ReadOnly
     86     $6              regExpConstructorDollar6        DontDelete|ReadOnly
     87     $7              regExpConstructorDollar7        DontDelete|ReadOnly
     88     $8              regExpConstructorDollar8        DontDelete|ReadOnly
     89     $9              regExpConstructorDollar9        DontDelete|ReadOnly
     90 @end
     91 */
     92 
     93 RegExpConstructor::RegExpConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype)
     94     : InternalFunction(&exec->globalData(), structure, Identifier(exec, "RegExp"))
     95     , d(new RegExpConstructorPrivate)
     96 {
     97     // ECMA 15.10.5.1 RegExp.prototype
     98     putDirectWithoutTransition(exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly);
     99 
    100     // no. of arguments for constructor
    101     putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly | DontDelete | DontEnum);
    102 }
    103 
    104 RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data)
    105     : JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1)
    106 {
    107     RegExpConstructorPrivate* d = new RegExpConstructorPrivate;
    108     d->input = data->lastInput;
    109     d->lastInput = data->lastInput;
    110     d->lastNumSubPatterns = data->lastNumSubPatterns;
    111     unsigned offsetVectorSize = (data->lastNumSubPatterns + 1) * 2; // only copying the result part of the vector
    112     d->lastOvector().resize(offsetVectorSize);
    113     memcpy(d->lastOvector().data(), data->lastOvector().data(), offsetVectorSize * sizeof(int));
    114     // d->multiline is not needed, and remains uninitialized
    115 
    116     setLazyCreationData(d);
    117 }
    118 
    119 RegExpMatchesArray::~RegExpMatchesArray()
    120 {
    121     delete static_cast<RegExpConstructorPrivate*>(lazyCreationData());
    122 }
    123 
    124 void RegExpMatchesArray::fillArrayInstance(ExecState* exec)
    125 {
    126     RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(lazyCreationData());
    127     ASSERT(d);
    128 
    129     unsigned lastNumSubpatterns = d->lastNumSubPatterns;
    130 
    131     for (unsigned i = 0; i <= lastNumSubpatterns; ++i) {
    132         int start = d->lastOvector()[2 * i];
    133         if (start >= 0)
    134             JSArray::put(exec, i, jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start));
    135         else
    136             JSArray::put(exec, i, jsUndefined());
    137     }
    138 
    139     PutPropertySlot slot;
    140     JSArray::put(exec, exec->propertyNames().index, jsNumber(exec, d->lastOvector()[0]), slot);
    141     JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->input), slot);
    142 
    143     delete d;
    144     setLazyCreationData(0);
    145 }
    146 
    147 JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const
    148 {
    149     return new (exec) RegExpMatchesArray(exec, d.get());
    150 }
    151 
    152 JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) const
    153 {
    154     if (!d->lastOvector().isEmpty() && i <= d->lastNumSubPatterns) {
    155         int start = d->lastOvector()[2 * i];
    156         if (start >= 0)
    157             return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start);
    158     }
    159     return jsEmptyString(exec);
    160 }
    161 
    162 JSValue RegExpConstructor::getLastParen(ExecState* exec) const
    163 {
    164     unsigned i = d->lastNumSubPatterns;
    165     if (i > 0) {
    166         ASSERT(!d->lastOvector().isEmpty());
    167         int start = d->lastOvector()[2 * i];
    168         if (start >= 0)
    169             return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start);
    170     }
    171     return jsEmptyString(exec);
    172 }
    173 
    174 JSValue RegExpConstructor::getLeftContext(ExecState* exec) const
    175 {
    176     if (!d->lastOvector().isEmpty())
    177         return jsSubstring(exec, d->lastInput, 0, d->lastOvector()[0]);
    178     return jsEmptyString(exec);
    179 }
    180 
    181 JSValue RegExpConstructor::getRightContext(ExecState* exec) const
    182 {
    183     if (!d->lastOvector().isEmpty())
    184         return jsSubstring(exec, d->lastInput, d->lastOvector()[1], d->lastInput.size() - d->lastOvector()[1]);
    185     return jsEmptyString(exec);
    186 }
    187 
    188 bool RegExpConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
    189 {
    190     return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, slot);
    191 }
    192 
    193 bool RegExpConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
    194 {
    195     return getStaticValueDescriptor<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, descriptor);
    196 }
    197 
    198 JSValue regExpConstructorDollar1(ExecState* exec, const Identifier&, const PropertySlot& slot)
    199 {
    200     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 1);
    201 }
    202 
    203 JSValue regExpConstructorDollar2(ExecState* exec, const Identifier&, const PropertySlot& slot)
    204 {
    205     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 2);
    206 }
    207 
    208 JSValue regExpConstructorDollar3(ExecState* exec, const Identifier&, const PropertySlot& slot)
    209 {
    210     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 3);
    211 }
    212 
    213 JSValue regExpConstructorDollar4(ExecState* exec, const Identifier&, const PropertySlot& slot)
    214 {
    215     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 4);
    216 }
    217 
    218 JSValue regExpConstructorDollar5(ExecState* exec, const Identifier&, const PropertySlot& slot)
    219 {
    220     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 5);
    221 }
    222 
    223 JSValue regExpConstructorDollar6(ExecState* exec, const Identifier&, const PropertySlot& slot)
    224 {
    225     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 6);
    226 }
    227 
    228 JSValue regExpConstructorDollar7(ExecState* exec, const Identifier&, const PropertySlot& slot)
    229 {
    230     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 7);
    231 }
    232 
    233 JSValue regExpConstructorDollar8(ExecState* exec, const Identifier&, const PropertySlot& slot)
    234 {
    235     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 8);
    236 }
    237 
    238 JSValue regExpConstructorDollar9(ExecState* exec, const Identifier&, const PropertySlot& slot)
    239 {
    240     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 9);
    241 }
    242 
    243 JSValue regExpConstructorInput(ExecState* exec, const Identifier&, const PropertySlot& slot)
    244 {
    245     return jsString(exec, asRegExpConstructor(slot.slotBase())->input());
    246 }
    247 
    248 JSValue regExpConstructorMultiline(ExecState*, const Identifier&, const PropertySlot& slot)
    249 {
    250     return jsBoolean(asRegExpConstructor(slot.slotBase())->multiline());
    251 }
    252 
    253 JSValue regExpConstructorLastMatch(ExecState* exec, const Identifier&, const PropertySlot& slot)
    254 {
    255     return asRegExpConstructor(slot.slotBase())->getBackref(exec, 0);
    256 }
    257 
    258 JSValue regExpConstructorLastParen(ExecState* exec, const Identifier&, const PropertySlot& slot)
    259 {
    260     return asRegExpConstructor(slot.slotBase())->getLastParen(exec);
    261 }
    262 
    263 JSValue regExpConstructorLeftContext(ExecState* exec, const Identifier&, const PropertySlot& slot)
    264 {
    265     return asRegExpConstructor(slot.slotBase())->getLeftContext(exec);
    266 }
    267 
    268 JSValue regExpConstructorRightContext(ExecState* exec, const Identifier&, const PropertySlot& slot)
    269 {
    270     return asRegExpConstructor(slot.slotBase())->getRightContext(exec);
    271 }
    272 
    273 void RegExpConstructor::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
    274 {
    275     lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, ExecState::regExpConstructorTable(exec), this, slot);
    276 }
    277 
    278 void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValue value)
    279 {
    280     asRegExpConstructor(baseObject)->setInput(value.toString(exec));
    281 }
    282 
    283 void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValue value)
    284 {
    285     asRegExpConstructor(baseObject)->setMultiline(value.toBoolean(exec));
    286 }
    287 
    288 // ECMA 15.10.4
    289 JSObject* constructRegExp(ExecState* exec, const ArgList& args)
    290 {
    291     JSValue arg0 = args.at(0);
    292     JSValue arg1 = args.at(1);
    293 
    294     if (arg0.inherits(&RegExpObject::info)) {
    295         if (!arg1.isUndefined())
    296             return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another.");
    297         return asObject(arg0);
    298     }
    299 
    300     UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec);
    301     UString flags = arg1.isUndefined() ? UString("") : arg1.toString(exec);
    302 
    303     RefPtr<RegExp> regExp = RegExp::create(&exec->globalData(), pattern, flags);
    304     if (!regExp->isValid())
    305         return throwError(exec, SyntaxError, makeString("Invalid regular expression: ", regExp->errorMessage()));
    306     return new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
    307 }
    308 
    309 static JSObject* constructWithRegExpConstructor(ExecState* exec, JSObject*, const ArgList& args)
    310 {
    311     return constructRegExp(exec, args);
    312 }
    313 
    314 ConstructType RegExpConstructor::getConstructData(ConstructData& constructData)
    315 {
    316     constructData.native.function = constructWithRegExpConstructor;
    317     return ConstructTypeHost;
    318 }
    319 
    320 // ECMA 15.10.3
    321 static JSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec, JSObject*, JSValue, const ArgList& args)
    322 {
    323     return constructRegExp(exec, args);
    324 }
    325 
    326 CallType RegExpConstructor::getCallData(CallData& callData)
    327 {
    328     callData.native.function = callRegExpConstructor;
    329     return CallTypeHost;
    330 }
    331 
    332 void RegExpConstructor::setInput(const UString& input)
    333 {
    334     d->input = input;
    335 }
    336 
    337 const UString& RegExpConstructor::input() const
    338 {
    339     // Can detect a distinct initial state that is invisible to JavaScript, by checking for null
    340     // state (since jsString turns null strings to empty strings).
    341     return d->input;
    342 }
    343 
    344 void RegExpConstructor::setMultiline(bool multiline)
    345 {
    346     d->multiline = multiline;
    347 }
    348 
    349 bool RegExpConstructor::multiline() const
    350 {
    351     return d->multiline;
    352 }
    353 
    354 } // namespace JSC
    355