/* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "config.h" #include "RegExpPrototype.h" #include "ArrayPrototype.h" #include "Error.h" #include "JSArray.h" #include "JSFunction.h" #include "JSObject.h" #include "JSString.h" #include "JSStringBuilder.h" #include "JSValue.h" #include "ObjectPrototype.h" #include "RegExpObject.h" #include "RegExp.h" #include "RegExpCache.h" #include "StringRecursionChecker.h" #include "UStringConcatenate.h" namespace JSC { ASSERT_CLASS_FITS_IN_CELL(RegExpPrototype); static EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState*); static EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*); static EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*); static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*); // ECMA 15.10.5 RegExpPrototype::RegExpPrototype(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, Structure* functionStructure) : RegExpObject(globalObject, structure, RegExp::create(&exec->globalData(), "", NoFlags)) { putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 2, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum); putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().exec, regExpProtoFuncExec), DontEnum); putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 1, exec->propertyNames().test, regExpProtoFuncTest), DontEnum); putDirectFunctionWithoutTransition(exec, new (exec) JSFunction(exec, globalObject, functionStructure, 0, exec->propertyNames().toString, regExpProtoFuncToString), DontEnum); } // ------------------------------ Functions --------------------------- EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&RegExpObject::s_info)) return throwVMTypeError(exec); return JSValue::encode(asRegExpObject(thisValue)->test(exec)); } EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&RegExpObject::s_info)) return throwVMTypeError(exec); return JSValue::encode(asRegExpObject(thisValue)->exec(exec)); } EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&RegExpObject::s_info)) return throwVMTypeError(exec); RefPtr regExp; JSValue arg0 = exec->argument(0); JSValue arg1 = exec->argument(1); if (arg0.inherits(&RegExpObject::s_info)) { if (!arg1.isUndefined()) return throwVMError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another.")); regExp = asRegExpObject(arg0)->regExp(); } else { UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); RegExpFlags flags = NoFlags; if (!arg1.isUndefined()) { flags = regExpFlags(arg1.toString(exec)); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (flags == InvalidFlags) return throwVMError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); } regExp = exec->globalData().regExpCache()->lookupOrCreate(pattern, flags); } if (!regExp->isValid()) return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage())); asRegExpObject(thisValue)->setRegExp(regExp.release()); asRegExpObject(thisValue)->setLastIndex(0); return JSValue::encode(jsUndefined()); } EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec) { JSValue thisValue = exec->hostThisValue(); if (!thisValue.inherits(&RegExpObject::s_info)) { if (thisValue.inherits(&RegExpPrototype::s_info)) return JSValue::encode(jsNontrivialString(exec, "//")); return throwVMTypeError(exec); } RegExpObject* thisObject = asRegExpObject(thisValue); StringRecursionChecker checker(exec, thisObject); if (EncodedJSValue earlyReturnValue = checker.earlyReturnValue()) return earlyReturnValue; char postfix[5] = { '/', 0, 0, 0, 0 }; int index = 1; if (thisObject->get(exec, exec->propertyNames().global).toBoolean(exec)) postfix[index++] = 'g'; if (thisObject->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec)) postfix[index++] = 'i'; if (thisObject->get(exec, exec->propertyNames().multiline).toBoolean(exec)) postfix[index] = 'm'; UString source = thisObject->get(exec, exec->propertyNames().source).toString(exec); // If source is empty, use "/(?:)/" to avoid colliding with comment syntax return JSValue::encode(jsMakeNontrivialString(exec, "/", source.length() ? source : UString("(?:)"), postfix)); } } // namespace JSC