1/* 2 * Copyright (C) 1999-2000 Harri Porten (porten@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 "RegExpPrototype.h" 23 24#include "ArrayPrototype.h" 25#include "Error.h" 26#include "JSArray.h" 27#include "JSFunction.h" 28#include "JSObject.h" 29#include "JSString.h" 30#include "JSStringBuilder.h" 31#include "JSValue.h" 32#include "ObjectPrototype.h" 33#include "RegExpObject.h" 34#include "RegExp.h" 35#include "RegExpCache.h" 36#include "StringRecursionChecker.h" 37#include "UStringConcatenate.h" 38 39namespace JSC { 40 41ASSERT_CLASS_FITS_IN_CELL(RegExpPrototype); 42 43static EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState*); 44static EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*); 45static EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*); 46static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*); 47 48// ECMA 15.10.5 49 50RegExpPrototype::RegExpPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, Structure* functionStructure) 51 : RegExpObject(globalObject, structure, RegExp::create(&exec->globalData(), "", NoFlags)) 52{ 53 putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 2, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum); 54 putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().exec, regExpProtoFuncExec), DontEnum); 55 putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().test, regExpProtoFuncTest), DontEnum); 56 putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toString, regExpProtoFuncToString), DontEnum); 57} 58 59// ------------------------------ Functions --------------------------- 60 61EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec) 62{ 63 JSValue thisValue = exec->hostThisValue(); 64 if (!thisValue.inherits(&RegExpObject::s_info)) 65 return throwVMTypeError(exec); 66 return JSValue::encode(asRegExpObject(thisValue)->test(exec)); 67} 68 69EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec) 70{ 71 JSValue thisValue = exec->hostThisValue(); 72 if (!thisValue.inherits(&RegExpObject::s_info)) 73 return throwVMTypeError(exec); 74 return JSValue::encode(asRegExpObject(thisValue)->exec(exec)); 75} 76 77EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) 78{ 79 JSValue thisValue = exec->hostThisValue(); 80 if (!thisValue.inherits(&RegExpObject::s_info)) 81 return throwVMTypeError(exec); 82 83 RefPtr<RegExp> regExp; 84 JSValue arg0 = exec->argument(0); 85 JSValue arg1 = exec->argument(1); 86 87 if (arg0.inherits(&RegExpObject::s_info)) { 88 if (!arg1.isUndefined()) 89 return throwVMError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another.")); 90 regExp = asRegExpObject(arg0)->regExp(); 91 } else { 92 UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec); 93 if (exec->hadException()) 94 return JSValue::encode(jsUndefined()); 95 96 RegExpFlags flags = NoFlags; 97 if (!arg1.isUndefined()) { 98 flags = regExpFlags(arg1.toString(exec)); 99 if (exec->hadException()) 100 return JSValue::encode(jsUndefined()); 101 if (flags == InvalidFlags) 102 return throwVMError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); 103 } 104 regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags); 105 } 106 107 if (!regExp->isValid()) 108 return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage())); 109 110 asRegExpObject(thisValue)->setRegExp(regExp.release()); 111 asRegExpObject(thisValue)->setLastIndex(0); 112 return JSValue::encode(jsUndefined()); 113} 114 115EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec) 116{ 117 JSValue thisValue = exec->hostThisValue(); 118 if (!thisValue.inherits(&RegExpObject::s_info)) { 119 if (thisValue.inherits(&RegExpPrototype::s_info)) 120 return JSValue::encode(jsNontrivialString(exec, "//")); 121 return throwVMTypeError(exec); 122 } 123 124 RegExpObject* thisObject = asRegExpObject(thisValue); 125 126 StringRecursionChecker checker(exec, thisObject); 127 if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue()) 128 return earlyReturnValue; 129 130 char postfix[5] = { '/', 0, 0, 0, 0 }; 131 int index = 1; 132 if (thisObject->get(exec, exec->propertyNames().global).toBoolean(exec)) 133 postfix[index++] = 'g'; 134 if (thisObject->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec)) 135 postfix[index++] = 'i'; 136 if (thisObject->get(exec, exec->propertyNames().multiline).toBoolean(exec)) 137 postfix[index] = 'm'; 138 UString source = thisObject->get(exec, exec->propertyNames().source).toString(exec); 139 // If source is empty, use "/(?:)/" to avoid colliding with comment syntax 140 return JSValue::encode(jsMakeNontrivialString(exec, "/", source.length() ? source : UString("(?:)"), postfix)); 141} 142 143} // namespace JSC 144