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