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