Ignore:
Timestamp:
Jun 28, 2008, 5:09:26 PM (17 years ago)
Author:
[email protected]
Message:

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

Rubber-stamped by Darin Adler.

Splits RegExpConstructor and RegExpPrototype out of RegExpObject.h/cpp

  • DerivedSources.make:
  • GNUmakefile.am:
  • JavaScriptCore.pri:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • JavaScriptCoreSources.bkl:
  • VM/Machine.cpp:
  • kjs/AllInOneFile.cpp:
  • kjs/JSGlobalObject.cpp:
  • kjs/RegExpConstructor.cpp: Copied from kjs/RegExpObject.cpp.
  • kjs/RegExpConstructor.h: Copied from kjs/RegExpObject.h.
  • kjs/RegExpObject.cpp:
  • kjs/RegExpObject.h:
  • kjs/RegExpPrototype.cpp: Copied from kjs/RegExpObject.cpp.
  • kjs/RegExpPrototype.h: Copied from kjs/RegExpObject.h.
  • kjs/StringPrototype.cpp:
  • kjs/internal.cpp:
File:
1 edited

Legend:

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

    r34857 r34863  
    2323#include "RegExpObject.lut.h"
    2424
    25 #include "ArrayPrototype.h"
    2625#include "JSArray.h"
    27 #include "JSObject.h"
     26#include "JSGlobalObject.h"
    2827#include "JSString.h"
    29 #include "JSValue.h"
    30 #include "ObjectPrototype.h"
    31 #include "UnusedParam.h"
     28#include "RegExpConstructor.h"
     29#include "RegExpPrototype.h"
    3230#include "error_object.h"
    33 #include "operations.h"
    34 #include "regexp.h"
    35 
    36 #include <stdio.h>
    3731
    3832namespace KJS {
    39 
    40 // ------------------------------ RegExpPrototype ---------------------------
    41 
    42 static JSValue* regExpProtoFuncTest(ExecState*, JSObject*, JSValue*, const ArgList&);
    43 static JSValue* regExpProtoFuncExec(ExecState*, JSObject*, JSValue*, const ArgList&);
    44 static JSValue* regExpProtoFuncCompile(ExecState*, JSObject*, JSValue*, const ArgList&);
    45 static JSValue* regExpProtoFuncToString(ExecState*, JSObject*, JSValue*, const ArgList&);
    46 
    47 // ECMA 15.10.5
    48 
    49 const ClassInfo RegExpPrototype::info = { "RegExpPrototype", 0, 0, 0 };
    50 
    51 RegExpPrototype::RegExpPrototype(ExecState* exec, ObjectPrototype* objectPrototype, FunctionPrototype* functionPrototype)
    52     : JSObject(objectPrototype)
    53 {
    54     putDirectFunction(new (exec) PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum);
    55     putDirectFunction(new (exec) PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().exec, regExpProtoFuncExec), DontEnum);
    56     putDirectFunction(new (exec) PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().test, regExpProtoFuncTest), DontEnum);
    57     putDirectFunction(new (exec) PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toString, regExpProtoFuncToString), DontEnum);
    58 }
    59 
    60 // ------------------------------ Functions ---------------------------
    61    
    62 JSValue* regExpProtoFuncTest(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    63 {
    64     if (!thisValue->isObject(&RegExpObject::info))
    65         return throwError(exec, TypeError);
    66     return static_cast<RegExpObject*>(thisValue)->test(exec, args);
    67 }
    68 
    69 JSValue* regExpProtoFuncExec(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    70 {
    71     if (!thisValue->isObject(&RegExpObject::info))
    72         return throwError(exec, TypeError);
    73     return static_cast<RegExpObject*>(thisValue)->exec(exec, args);
    74 }
    75 
    76 JSValue* regExpProtoFuncCompile(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
    77 {
    78     if (!thisValue->isObject(&RegExpObject::info))
    79         return throwError(exec, TypeError);
    80 
    81     RefPtr<RegExp> regExp;
    82     JSValue* arg0 = args[0];
    83     JSValue* arg1 = args[1];
    84    
    85     if (arg0->isObject(&RegExpObject::info)) {
    86         if (!arg1->isUndefined())
    87             return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another.");
    88         regExp = static_cast<RegExpObject*>(arg0)->regExp();
    89     } else {
    90         UString pattern = args.isEmpty() ? UString("") : arg0->toString(exec);
    91         UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec);
    92         regExp = RegExp::create(pattern, flags);
    93     }
    94 
    95     if (!regExp->isValid())
    96         return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
    97 
    98     static_cast<RegExpObject*>(thisValue)->setRegExp(regExp.release());
    99     static_cast<RegExpObject*>(thisValue)->setLastIndex(0);
    100     return jsUndefined();
    101 }
    102 
    103 JSValue* regExpProtoFuncToString(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList&)
    104 {
    105     if (!thisValue->isObject(&RegExpObject::info)) {
    106         if (thisValue->isObject(&RegExpPrototype::info))
    107             return jsString(exec, "//");
    108         return throwError(exec, TypeError);
    109     }
    110 
    111     UString result = "/" + static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().source)->toString(exec) + "/";
    112     if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().global)->toBoolean(exec))
    113         result += "g";
    114     if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().ignoreCase)->toBoolean(exec))
    115         result += "i";
    116     if (static_cast<RegExpObject*>(thisValue)->get(exec, exec->propertyNames().multiline)->toBoolean(exec))
    117         result += "m";
    118     return jsString(exec, result);
    119 }
    120 
    121 // ------------------------------ RegExpObject ------------------------------------
    12233
    12334const ClassInfo RegExpObject::info = { "RegExp", 0, 0, ExecState::regExpTable };
     
    240151}
    241152
    242 // ------------------------------ RegExpConstructor ------------------------------
    243 
    244 const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, 0, ExecState::regExpConstructorTable };
    245 
    246 /* Source for RegExpObject.lut.h
    247 @begin regExpConstructorTable
    248   input           RegExpConstructor::Input          None
    249   $_              RegExpConstructor::Input          DontEnum
    250   multiline       RegExpConstructor::Multiline      None
    251   $*              RegExpConstructor::Multiline      DontEnum
    252   lastMatch       RegExpConstructor::LastMatch      DontDelete|ReadOnly
    253   $&              RegExpConstructor::LastMatch      DontDelete|ReadOnly|DontEnum
    254   lastParen       RegExpConstructor::LastParen      DontDelete|ReadOnly
    255   $+              RegExpConstructor::LastParen      DontDelete|ReadOnly|DontEnum
    256   leftContext     RegExpConstructor::LeftContext    DontDelete|ReadOnly
    257   $`              RegExpConstructor::LeftContext    DontDelete|ReadOnly|DontEnum
    258   rightContext    RegExpConstructor::RightContext   DontDelete|ReadOnly
    259   $'              RegExpConstructor::RightContext   DontDelete|ReadOnly|DontEnum
    260   $1              RegExpConstructor::Dollar1        DontDelete|ReadOnly
    261   $2              RegExpConstructor::Dollar2        DontDelete|ReadOnly
    262   $3              RegExpConstructor::Dollar3        DontDelete|ReadOnly
    263   $4              RegExpConstructor::Dollar4        DontDelete|ReadOnly
    264   $5              RegExpConstructor::Dollar5        DontDelete|ReadOnly
    265   $6              RegExpConstructor::Dollar6        DontDelete|ReadOnly
    266   $7              RegExpConstructor::Dollar7        DontDelete|ReadOnly
    267   $8              RegExpConstructor::Dollar8        DontDelete|ReadOnly
    268   $9              RegExpConstructor::Dollar9        DontDelete|ReadOnly
    269 @end
    270 */
    271 
    272 struct RegExpConstructorPrivate {
    273   // Global search cache / settings
    274   RegExpConstructorPrivate() : lastNumSubPatterns(0), multiline(false) { }
    275   UString lastInput;
    276   OwnArrayPtr<int> lastOvector;
    277   unsigned lastNumSubPatterns : 31;
    278   bool multiline              : 1;
    279 };
    280 
    281 RegExpConstructor::RegExpConstructor(ExecState* exec, FunctionPrototype* funcProto, RegExpPrototype* regProto)
    282   : InternalFunction(funcProto, Identifier(exec, "RegExp"))
    283   , d(new RegExpConstructorPrivate)
    284 {
    285   // ECMA 15.10.5.1 RegExp.prototype
    286   putDirect(exec->propertyNames().prototype, regProto, DontEnum | DontDelete | ReadOnly);
    287 
    288   // no. of arguments for constructor
    289   putDirect(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly | DontDelete | DontEnum);
    290 }
    291 
    292 /*
    293   To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular
    294   expression matching through the performMatch function. We use cached results to calculate,
    295   e.g., RegExp.lastMatch and RegExp.leftParen.
    296 */
    297 void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
    298 {
    299   OwnArrayPtr<int> tmpOvector;
    300   position = r->match(s, startOffset, &tmpOvector);
    301 
    302   if (ovector)
    303     *ovector = tmpOvector.get();
    304  
    305   if (position != -1) {
    306     ASSERT(tmpOvector);
    307 
    308     length = tmpOvector[1] - tmpOvector[0];
    309 
    310     d->lastInput = s;
    311     d->lastOvector.set(tmpOvector.release());
    312     d->lastNumSubPatterns = r->numSubpatterns();
    313   }
    314 }
    315 
    316 class RegExpMatchesArray : public JSArray {
    317 public:
    318     RegExpMatchesArray(ExecState*, RegExpConstructorPrivate*);
    319     virtual ~RegExpMatchesArray();
    320 
    321 private:
    322     virtual bool getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { if (lazyCreationData()) fillArrayInstance(exec); return JSArray::getOwnPropertySlot(exec, propertyName, slot); }
    323     virtual bool getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) { if (lazyCreationData()) fillArrayInstance(exec); return JSArray::getOwnPropertySlot(exec, propertyName, slot); }
    324     virtual void put(ExecState* exec, const Identifier& propertyName, JSValue* v) { if (lazyCreationData()) fillArrayInstance(exec); JSArray::put(exec, propertyName, v); }
    325     virtual void put(ExecState* exec, unsigned propertyName, JSValue* v) { if (lazyCreationData()) fillArrayInstance(exec); JSArray::put(exec, propertyName, v); }
    326     virtual bool deleteProperty(ExecState* exec, const Identifier& propertyName) { if (lazyCreationData()) fillArrayInstance(exec); return JSArray::deleteProperty(exec, propertyName); }
    327     virtual bool deleteProperty(ExecState* exec, unsigned propertyName) { if (lazyCreationData()) fillArrayInstance(exec); return JSArray::deleteProperty(exec, propertyName); }
    328     virtual void getPropertyNames(ExecState* exec, PropertyNameArray& arr) { if (lazyCreationData()) fillArrayInstance(exec); JSArray::getPropertyNames(exec, arr); }
    329 
    330     void fillArrayInstance(ExecState*);
    331 };
    332 
    333 RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data)
    334     : JSArray(exec->lexicalGlobalObject()->arrayPrototype(), data->lastNumSubPatterns + 1)
    335 {
    336     RegExpConstructorPrivate* d = new RegExpConstructorPrivate;
    337     d->lastInput = data->lastInput;
    338     d->lastNumSubPatterns = data->lastNumSubPatterns;
    339     unsigned offsetVectorSize = (data->lastNumSubPatterns + 1) * 2; // only copying the result part of the vector
    340     d->lastOvector.set(new int[offsetVectorSize]);
    341     memcpy(d->lastOvector.get(), data->lastOvector.get(), offsetVectorSize * sizeof(int));
    342     // d->multiline is not needed, and remains uninitialized
    343 
    344     setLazyCreationData(d);
    345 }
    346 
    347 RegExpMatchesArray::~RegExpMatchesArray()
    348 {
    349     delete static_cast<RegExpConstructorPrivate*>(lazyCreationData());
    350 }
    351 
    352 void RegExpMatchesArray::fillArrayInstance(ExecState* exec)
    353 {
    354     RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(lazyCreationData());
    355     ASSERT(d);
    356 
    357     unsigned lastNumSubpatterns = d->lastNumSubPatterns;
    358 
    359     for (unsigned i = 0; i <= lastNumSubpatterns; ++i) {
    360         int start = d->lastOvector[2 * i];
    361         if (start >= 0)
    362             JSArray::put(exec, i, jsString(exec, d->lastInput.substr(start, d->lastOvector[2 * i + 1] - start)));
    363     }
    364     JSArray::put(exec, exec->propertyNames().index, jsNumber(exec, d->lastOvector[0]));
    365     JSArray::put(exec, exec->propertyNames().input, jsString(exec, d->lastInput));
    366 
    367     delete d;
    368     setLazyCreationData(0);
    369 }
    370 
    371 JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const
    372 {
    373     return new (exec) RegExpMatchesArray(exec, d.get());
    374 }
    375 
    376 JSValue* RegExpConstructor::getBackref(ExecState* exec, unsigned i) const
    377 {
    378   if (d->lastOvector && i <= d->lastNumSubPatterns)
    379     return jsString(exec, d->lastInput.substr(d->lastOvector[2 * i], d->lastOvector[2 * i + 1] - d->lastOvector[2 * i]));
    380   return jsString(exec, "");
    381 }
    382 
    383 JSValue* RegExpConstructor::getLastParen(ExecState* exec) const
    384 {
    385   unsigned i = d->lastNumSubPatterns;
    386   if (i > 0) {
    387     ASSERT(d->lastOvector);
    388     return jsString(exec, d->lastInput.substr(d->lastOvector[2 * i], d->lastOvector[2 * i + 1] - d->lastOvector[2 * i]));
    389   }
    390   return jsString(exec, "");
    391 }
    392 
    393 JSValue* RegExpConstructor::getLeftContext(ExecState* exec) const
    394 {
    395   if (d->lastOvector)
    396     return jsString(exec, d->lastInput.substr(0, d->lastOvector[0]));
    397   return jsString(exec, "");
    398 }
    399 
    400 JSValue* RegExpConstructor::getRightContext(ExecState* exec) const
    401 {
    402   if (d->lastOvector) {
    403     UString s = d->lastInput;
    404     return jsString(exec, s.substr(d->lastOvector[1], s.size() - d->lastOvector[1]));
    405   }
    406   return jsString(exec, "");
    407 }
    408 
    409 bool RegExpConstructor::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
    410 {
    411   return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, slot);
    412 }
    413 
    414 JSValue *RegExpConstructor::getValueProperty(ExecState* exec, int token) const
    415 {
    416   switch (token) {
    417     case Dollar1:
    418       return getBackref(exec, 1);
    419     case Dollar2:
    420       return getBackref(exec, 2);
    421     case Dollar3:
    422       return getBackref(exec, 3);
    423     case Dollar4:
    424       return getBackref(exec, 4);
    425     case Dollar5:
    426       return getBackref(exec, 5);
    427     case Dollar6:
    428       return getBackref(exec, 6);
    429     case Dollar7:
    430       return getBackref(exec, 7);
    431     case Dollar8:
    432       return getBackref(exec, 8);
    433     case Dollar9:
    434       return getBackref(exec, 9);
    435     case Input:
    436       return jsString(exec, d->lastInput);
    437     case Multiline:
    438       return jsBoolean(d->multiline);
    439     case LastMatch:
    440       return getBackref(exec, 0);
    441     case LastParen:
    442       return getLastParen(exec);
    443     case LeftContext:
    444       return getLeftContext(exec);
    445     case RightContext:
    446       return getRightContext(exec);
    447     default:
    448       ASSERT_NOT_REACHED();
    449   }
    450 
    451   return jsString(exec, "");
    452 }
    453 
    454 void RegExpConstructor::put(ExecState *exec, const Identifier &propertyName, JSValue *value)
    455 {
    456     lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, ExecState::regExpConstructorTable(exec), this);
    457 }
    458 
    459 void RegExpConstructor::putValueProperty(ExecState *exec, int token, JSValue *value)
    460 {
    461   switch (token) {
    462     case Input:
    463       d->lastInput = value->toString(exec);
    464       break;
    465     case Multiline:
    466       d->multiline = value->toBoolean(exec);
    467       break;
    468     default:
    469       ASSERT(0);
    470   }
    471 }
    472  
    473 // ECMA 15.10.4
    474 static JSObject* constructRegExp(ExecState* exec, const ArgList& args)
    475 {
    476   JSValue* arg0 = args[0];
    477   JSValue* arg1 = args[1];
    478  
    479   if (arg0->isObject(&RegExpObject::info)) {
    480     if (!arg1->isUndefined())
    481       return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another.");
    482     return static_cast<JSObject*>(arg0);
    483   }
    484  
    485   UString pattern = arg0->isUndefined() ? UString("") : arg0->toString(exec);
    486   UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec);
    487  
    488   RefPtr<RegExp> regExp = RegExp::create(pattern, flags);
    489   return regExp->isValid()
    490     ? new (exec) RegExpObject(exec->lexicalGlobalObject()->regExpPrototype(), regExp.release())
    491     : throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
    492 }
    493 
    494 static JSObject* constructWithRegExpConstructor(ExecState* exec, JSObject*, const ArgList& args)
    495 {
    496     return constructRegExp(exec, args);
    497 }
    498 
    499 ConstructType RegExpConstructor::getConstructData(ConstructData& constructData)
    500 {
    501     constructData.native.function = constructWithRegExpConstructor;
    502     return ConstructTypeNative;
    503 }
    504 
    505 // ECMA 15.10.3
    506 static JSValue* callRegExpConstructor(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
    507 {
    508     return constructRegExp(exec, args);
    509 }
    510 
    511 CallType RegExpConstructor::getCallData(CallData& callData)
    512 {
    513     callData.native.function = callRegExpConstructor;
    514     return CallTypeNative;
    515 }
    516 
    517 const UString& RegExpConstructor::input() const
    518 {
    519     // Can detect a distinct initial state that is invisible to JavaScript, by checking for null
    520     // state (since jsString turns null strings to empty strings).
    521     return d->lastInput;
    522 }
    523 
    524 }
     153} // namespace KJS
Note: See TracChangeset for help on using the changeset viewer.