Changeset 34863 in webkit for trunk/JavaScriptCore/kjs/RegExpObject.cpp
- Timestamp:
- Jun 28, 2008, 5:09:26 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/RegExpObject.cpp
r34857 r34863 23 23 #include "RegExpObject.lut.h" 24 24 25 #include "ArrayPrototype.h"26 25 #include "JSArray.h" 27 #include "JS Object.h"26 #include "JSGlobalObject.h" 28 27 #include "JSString.h" 29 #include "JSValue.h" 30 #include "ObjectPrototype.h" 31 #include "UnusedParam.h" 28 #include "RegExpConstructor.h" 29 #include "RegExpPrototype.h" 32 30 #include "error_object.h" 33 #include "operations.h"34 #include "regexp.h"35 36 #include <stdio.h>37 31 38 32 namespace 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.548 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 ------------------------------------122 33 123 34 const ClassInfo RegExpObject::info = { "RegExp", 0, 0, ExecState::regExpTable }; … … 240 151 } 241 152 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.