~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/script/qscriptecmaregexp.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/****************************************************************************
2
 
**
3
 
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
 
** Contact: Nokia Corporation (qt-info@nokia.com)
5
 
**
6
 
** This file is part of the QtScript module of the Qt Toolkit.
7
 
**
8
 
** $QT_BEGIN_LICENSE:LGPL$
9
 
** Commercial Usage
10
 
** Licensees holding valid Qt Commercial licenses may use this file in
11
 
** accordance with the Qt Commercial License Agreement provided with the
12
 
** Software or, alternatively, in accordance with the terms contained in
13
 
** a written agreement between you and Nokia.
14
 
**
15
 
** GNU Lesser General Public License Usage
16
 
** Alternatively, this file may be used under the terms of the GNU Lesser
17
 
** General Public License version 2.1 as published by the Free Software
18
 
** Foundation and appearing in the file LICENSE.LGPL included in the
19
 
** packaging of this file.  Please review the following information to
20
 
** ensure the GNU Lesser General Public License version 2.1 requirements
21
 
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22
 
**
23
 
** In addition, as a special exception, Nokia gives you certain
24
 
** additional rights. These rights are described in the Nokia Qt LGPL
25
 
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26
 
** package.
27
 
**
28
 
** GNU General Public License Usage
29
 
** Alternatively, this file may be used under the terms of the GNU
30
 
** General Public License version 3.0 as published by the Free Software
31
 
** Foundation and appearing in the file LICENSE.GPL included in the
32
 
** packaging of this file.  Please review the following information to
33
 
** ensure the GNU General Public License version 3.0 requirements will be
34
 
** met: http://www.gnu.org/copyleft/gpl.html.
35
 
**
36
 
** If you are unsure which license is appropriate for your use, please
37
 
** contact the sales department at http://www.qtsoftware.com/contact.
38
 
** $QT_END_LICENSE$
39
 
**
40
 
****************************************************************************/
41
 
 
42
 
#include "qscriptecmaregexp_p.h"
43
 
 
44
 
#ifndef QT_NO_SCRIPT
45
 
 
46
 
#include "qscriptengine_p.h"
47
 
#include "qscriptvalueimpl_p.h"
48
 
#include "qscriptcontext_p.h"
49
 
#include "qscriptmember_p.h"
50
 
#include "qscriptobject_p.h"
51
 
 
52
 
#include <QtCore/QStringList>
53
 
#include <QtCore/QRegExp>
54
 
#include <QtCore/QtDebug>
55
 
 
56
 
QT_BEGIN_NAMESPACE
57
 
 
58
 
namespace QScript { namespace Ecma {
59
 
 
60
 
RegExp::RegExp(QScriptEnginePrivate *eng):
61
 
    Core(eng, QLatin1String("RegExp"), QScriptClassInfo::RegExpType)
62
 
{
63
 
    newRegExp(&publicPrototype, QString(), /*flags=*/0);
64
 
 
65
 
    eng->newConstructor(&ctor, this, publicPrototype);
66
 
 
67
 
    addPrototypeFunction(QLatin1String("exec"), method_exec, 1);
68
 
    addPrototypeFunction(QLatin1String("test"), method_test, 1);
69
 
    addPrototypeFunction(QLatin1String("toString"), method_toString, 1);
70
 
}
71
 
 
72
 
RegExp::~RegExp()
73
 
{
74
 
}
75
 
 
76
 
RegExp::Instance *RegExp::Instance::get(const QScriptValueImpl &object, QScriptClassInfo *klass)
77
 
{
78
 
    if (! klass || klass == object.classInfo())
79
 
        return static_cast<Instance*> (object.objectData());
80
 
 
81
 
    return 0;
82
 
}
83
 
 
84
 
void RegExp::execute(QScriptContextPrivate *context)
85
 
{
86
 
#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
87
 
    engine()->notifyFunctionEntry(context);
88
 
#endif
89
 
    QString P;
90
 
    int F;
91
 
    QScriptValueImpl pattern = context->argument(0);
92
 
    QScriptValueImpl flags = context->argument(1);
93
 
    if (!context->isCalledAsConstructor()) {
94
 
        if ((pattern.classInfo() == classInfo()) && flags.isUndefined()) {
95
 
            context->m_result = pattern;
96
 
            goto Lout;
97
 
        }
98
 
    }
99
 
    if (pattern.classInfo() == classInfo()) {
100
 
        if (!flags.isUndefined()) {
101
 
            context->throwTypeError(QString::fromLatin1("cannot specify flags when creating a copy of a RegExp"));
102
 
            goto Lout;
103
 
        }
104
 
        Instance *data = Instance::get(pattern, classInfo());
105
 
#ifndef QT_NO_REGEXP
106
 
        P = data->value.pattern();
107
 
#else
108
 
        P = data->pattern;
109
 
#endif
110
 
        F = data->flags;
111
 
    } else {
112
 
        if (!pattern.isUndefined())
113
 
            P = pattern.toString();
114
 
        F = 0;
115
 
        if (!flags.isUndefined()) {
116
 
            QString flagsStr = flags.toString();
117
 
            for (int i = 0; i < flagsStr.length(); ++i) {
118
 
                int bitflag = flagFromChar(flagsStr.at(i));
119
 
                if (bitflag == 0) {
120
 
                    context->throwError(
121
 
                        QScriptContext::SyntaxError,
122
 
                        QString::fromUtf8("invalid regular expression flag '%0'")
123
 
                        .arg(flagsStr.at(i)));
124
 
                    goto Lout;
125
 
                }
126
 
                F |= bitflag;
127
 
            }
128
 
        }
129
 
    }
130
 
    if (context->isCalledAsConstructor()) {
131
 
        QScriptValueImpl &object = context->m_thisObject;
132
 
        object.setClassInfo(classInfo());
133
 
        object.setPrototype(publicPrototype);
134
 
#ifndef QT_NO_REGEXP
135
 
        initRegExp(&object, toRegExp(P, F), F);
136
 
#else
137
 
        initRegExp(&object, P, F);
138
 
#endif
139
 
    } else {
140
 
        newRegExp(&context->m_result, P, F);
141
 
    }
142
 
 Lout: ;
143
 
#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
144
 
    engine()->notifyFunctionExit(context);
145
 
#endif
146
 
}
147
 
 
148
 
void RegExp::newRegExp(QScriptValueImpl *result, const QString &pattern, int flags)
149
 
{
150
 
#ifndef QT_NO_REGEXP
151
 
    QRegExp rx = toRegExp(pattern, flags);
152
 
    newRegExp_helper(result, rx, flags);
153
 
#else
154
 
    engine()->newObject(result, publicPrototype, classInfo());
155
 
    initRegExp(result, pattern, flags);
156
 
#endif // QT_NO_REGEXP
157
 
}
158
 
 
159
 
#ifndef QT_NO_REGEXP
160
 
void RegExp::newRegExp(QScriptValueImpl *result, const QRegExp &rx, int flags)
161
 
{
162
 
    Q_ASSERT(!(flags & IgnoreCase) || (rx.caseSensitivity() == Qt::CaseInsensitive));
163
 
    newRegExp_helper(result, rx, flags);
164
 
}
165
 
 
166
 
void RegExp::newRegExp_helper(QScriptValueImpl *result, const QRegExp &rx,
167
 
                              int flags)
168
 
{
169
 
    engine()->newObject(result, publicPrototype, classInfo());
170
 
    initRegExp(result, rx, flags);
171
 
}
172
 
 
173
 
QRegExp RegExp::toRegExp(const QScriptValueImpl &value) const
174
 
{
175
 
    Instance *rx_data = Instance::get(value, classInfo());
176
 
    Q_ASSERT(rx_data != 0);
177
 
    return rx_data->value;
178
 
}
179
 
 
180
 
QRegExp RegExp::toRegExp(const QString &pattern, int flags)
181
 
{
182
 
    bool ignoreCase = (flags & IgnoreCase) != 0;
183
 
    return QRegExp(pattern,
184
 
                   (ignoreCase ? Qt::CaseInsensitive: Qt::CaseSensitive),
185
 
                   QRegExp::RegExp2);
186
 
}
187
 
 
188
 
#endif // QT_NO_REGEXP
189
 
 
190
 
void RegExp::initRegExp(QScriptValueImpl *result,
191
 
#ifndef QT_NO_REGEXP
192
 
                        const QRegExp &rx,
193
 
#else
194
 
                        const QString &pattern,
195
 
#endif
196
 
                        int flags)
197
 
{
198
 
    Instance *instance = new Instance();
199
 
#ifndef QT_NO_REGEXP
200
 
    instance->value = rx;
201
 
#else
202
 
    instance->pattern = pattern;
203
 
#endif
204
 
    instance->flags = flags;
205
 
    result->setObjectData(instance);
206
 
 
207
 
    bool global = (flags & Global) != 0;
208
 
    bool ignoreCase = (flags & IgnoreCase) != 0;
209
 
    bool multiline = (flags & Multiline) != 0;
210
 
 
211
 
    QScriptValue::PropertyFlags propertyFlags = QScriptValue::SkipInEnumeration
212
 
                                                | QScriptValue::Undeletable
213
 
                                                | QScriptValue::ReadOnly;
214
 
 
215
 
    result->setProperty(QLatin1String("global"), QScriptValueImpl(global),
216
 
                        propertyFlags);
217
 
    result->setProperty(QLatin1String("ignoreCase"), QScriptValueImpl(ignoreCase),
218
 
                        propertyFlags);
219
 
    result->setProperty(QLatin1String("multiline"), QScriptValueImpl(multiline),
220
 
                        propertyFlags);
221
 
#ifndef QT_NO_REGEXP
222
 
    const QString &pattern = rx.pattern();
223
 
#endif
224
 
    result->setProperty(QLatin1String("source"), QScriptValueImpl(engine(), pattern),
225
 
                        propertyFlags);
226
 
    result->setProperty(QLatin1String("lastIndex"), QScriptValueImpl(0),
227
 
                        propertyFlags & ~QScriptValue::ReadOnly);
228
 
}
229
 
 
230
 
int RegExp::flagFromChar(const QChar &ch)
231
 
{
232
 
    static QHash<QChar, int> flagsHash;
233
 
    if (flagsHash.isEmpty()) {
234
 
        flagsHash[QLatin1Char('g')] = Global;
235
 
        flagsHash[QLatin1Char('i')] = IgnoreCase;
236
 
        flagsHash[QLatin1Char('m')] = Multiline;
237
 
    }
238
 
    QHash<QChar, int>::const_iterator it;
239
 
    it = flagsHash.constFind(ch);
240
 
    if (it == flagsHash.constEnd())
241
 
        return 0;
242
 
    return it.value();
243
 
}
244
 
 
245
 
QString RegExp::flagsToString(int flags)
246
 
{
247
 
    QString result;
248
 
    if (flags & Global)
249
 
        result += QLatin1Char('g');
250
 
    if (flags & IgnoreCase)
251
 
        result += QLatin1Char('i');
252
 
    if (flags & Multiline)
253
 
        result += QLatin1Char('m');
254
 
    return result;
255
 
}
256
 
 
257
 
QScriptValueImpl RegExp::method_exec(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
258
 
{
259
 
    QScriptValueImpl self = context->thisObject();
260
 
    if (self.classInfo() != classInfo) {
261
 
        return throwThisObjectTypeError(
262
 
            context, QLatin1String("RegExp.prototype.exec"));
263
 
    }
264
 
    Instance *rx_data = Instance::get(self, classInfo);
265
 
    Q_ASSERT(rx_data != 0);
266
 
 
267
 
    QString S = context->argument(0).toString();
268
 
    int length = S.length();
269
 
    QScriptValueImpl lastIndex = self.property(QLatin1String("lastIndex"));
270
 
 
271
 
    int i = lastIndex.isValid() ? int (lastIndex.toInteger()) : 0;
272
 
    bool global = self.property(QLatin1String("global")).toBoolean();
273
 
 
274
 
    if (! global)
275
 
        i = 0;
276
 
 
277
 
    if (i < 0 || i >= length)
278
 
        return (eng->nullValue());
279
 
 
280
 
#ifndef QT_NO_REGEXP
281
 
    int index = rx_data->value.indexIn(S, i);
282
 
    if (index == -1)
283
 
#endif // QT_NO_REGEXP
284
 
        return eng->nullValue();
285
 
 
286
 
#ifndef QT_NO_REGEXP
287
 
    int e = index + rx_data->value.matchedLength();
288
 
 
289
 
    if (global)
290
 
        self.setProperty(QLatin1String("lastIndex"), QScriptValueImpl(e));
291
 
 
292
 
    QScript::Array elts(eng);
293
 
    QStringList capturedTexts = rx_data->value.capturedTexts();
294
 
    for (int i = 0; i < capturedTexts.count(); ++i)
295
 
        elts.assign(i, QScriptValueImpl(eng, capturedTexts.at(i)));
296
 
 
297
 
    QScriptValueImpl r = eng->newArray(elts);
298
 
 
299
 
    r.setProperty(QLatin1String("index"), QScriptValueImpl(index));
300
 
    r.setProperty(QLatin1String("input"), QScriptValueImpl(eng, S));
301
 
 
302
 
    return r;
303
 
#endif // QT_NO_REGEXP
304
 
}
305
 
 
306
 
QScriptValueImpl RegExp::method_test(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
307
 
{
308
 
    QScriptValueImpl r = method_exec(context, eng, classInfo);
309
 
    return QScriptValueImpl(!r.isNull());
310
 
}
311
 
 
312
 
QScriptValueImpl RegExp::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
313
 
{
314
 
    if (Instance *instance = Instance::get(context->thisObject(), classInfo)) {
315
 
        QString result;
316
 
        result += QLatin1Char('/');
317
 
#ifndef QT_NO_REGEXP
318
 
        const QString &pattern = instance->value.pattern();
319
 
#else
320
 
        const QString &pattern = instance->pattern;
321
 
#endif
322
 
        if (pattern.isEmpty())
323
 
            result += QLatin1String("(?:)");
324
 
        else
325
 
            result += pattern; // ### quote
326
 
        result += QLatin1Char('/');
327
 
        result += flagsToString(instance->flags);
328
 
        return (QScriptValueImpl(eng, result));
329
 
    }
330
 
 
331
 
    return throwThisObjectTypeError(
332
 
        context, QLatin1String("RegExp.prototype.toString"));
333
 
}
334
 
 
335
 
} } // namespace QScript::Ecma
336
 
 
337
 
QT_END_NAMESPACE
338
 
 
339
 
#endif // QT_NO_SCRIPT