1 /* 2 * Copyright (C) 1999-2000 Harri Porten (porten (at) 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 39 namespace JSC { 40 41 ASSERT_CLASS_FITS_IN_CELL(RegExpPrototype); 42 43 static EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState*); 44 static EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*); 45 static EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*); 46 static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*); 47 48 // ECMA 15.10.5 49 50 RegExpPrototype::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 61 EncodedJSValue 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 69 EncodedJSValue 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 77 EncodedJSValue 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 115 EncodedJSValue 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