2 * Copyright (C) 1999-2001, 2004 Harri Porten (porten@kde.org)
3 * Copyright (c) 2007, 2008 Apple Inc. All rights reserved.
4 * Copyright (C) 2009 Torch Mobile, Inc.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 #include <wtf/Assertions.h>
29 #include <wtf/OwnArrayPtr.h>
34 #include "yarr/RegexCompiler.h"
36 #include "yarr/RegexJIT.h"
38 #include "yarr/RegexInterpreter.h"
43 #include <pcre/pcre.h>
49 inline RegExp::RegExp(JSGlobalData
* globalData
, const UString
& pattern
)
52 , m_constructionError(0)
54 , m_lastMatchStart(-1)
59 inline RegExp::RegExp(JSGlobalData
* globalData
, const UString
& pattern
, const UString
& flags
)
62 , m_constructionError(0)
64 , m_lastMatchStart(-1)
66 // NOTE: The global flag is handled on a case-by-case basis by functions like
67 // String::match and RegExpObject::match.
68 if (flags
.find('g') != UString::NotFound
)
70 if (flags
.find('i') != UString::NotFound
)
71 m_flagBits
|= IgnoreCase
;
72 if (flags
.find('m') != UString::NotFound
)
73 m_flagBits
|= Multiline
;
81 jsRegExpFree(m_regExp
);
85 PassRefPtr
<RegExp
> RegExp::create(JSGlobalData
* globalData
, const UString
& pattern
)
87 return adoptRef(new RegExp(globalData
, pattern
));
90 PassRefPtr
<RegExp
> RegExp::create(JSGlobalData
* globalData
, const UString
& pattern
, const UString
& flags
)
92 return adoptRef(new RegExp(globalData
, pattern
, flags
));
97 void RegExp::compile(JSGlobalData
* globalData
)
100 Yarr::jitCompileRegex(globalData
, m_regExpJITCode
, m_pattern
, m_numSubpatterns
, m_constructionError
, ignoreCase(), multiline());
102 UNUSED_PARAM(globalData
);
103 m_regExpBytecode
.set(Yarr::byteCompileRegex(m_pattern
, m_numSubpatterns
, m_constructionError
, ignoreCase(), multiline()));
107 int RegExp::match(const UString
& s
, int startOffset
, Vector
<int, 32>* ovector
)
114 if (static_cast<unsigned>(startOffset
) > s
.size() || s
.isNull()) {
115 m_lastMatchString
= UString();
116 m_lastMatchStart
= -1;
117 m_lastOVector
.shrink(0);
121 // Perform check to see if this match call is the same as the last match invocation
122 // and if it is return the prior result.
123 if ((startOffset
== m_lastMatchStart
) && (s
.rep() == m_lastMatchString
.rep())) {
125 *ovector
= m_lastOVector
;
127 if (m_lastOVector
.isEmpty())
130 return m_lastOVector
.at(0);
134 if (!!m_regExpJITCode
) {
136 if (m_regExpBytecode
) {
138 int offsetVectorSize
= (m_numSubpatterns
+ 1) * 3; // FIXME: should be 2 - but adding temporary fallback to pcre.
140 Vector
<int, 32> nonReturnedOvector
;
142 ovector
->resize(offsetVectorSize
);
143 offsetVector
= ovector
->data();
145 nonReturnedOvector
.resize(offsetVectorSize
);
146 offsetVector
= nonReturnedOvector
.data();
149 ASSERT(offsetVector
);
150 for (int j
= 0; j
< offsetVectorSize
; ++j
)
151 offsetVector
[j
] = -1;
155 int result
= Yarr::executeRegex(m_regExpJITCode
, s
.data(), startOffset
, s
.size(), offsetVector
, offsetVectorSize
);
157 int result
= Yarr::interpretRegex(m_regExpBytecode
.get(), s
.data(), startOffset
, s
.size(), offsetVector
);
162 // TODO: define up a symbol, rather than magic -1
164 fprintf(stderr
, "jsRegExpExecute failed with result %d\n", result
);
170 m_lastMatchString
= s
;
171 m_lastMatchStart
= startOffset
;
174 m_lastOVector
= *ovector
;
176 m_lastOVector
= nonReturnedOvector
;
181 m_lastMatchString
= UString();
182 m_lastMatchStart
= -1;
183 m_lastOVector
.shrink(0);
190 void RegExp::compile(JSGlobalData
*)
193 JSRegExpIgnoreCaseOption ignoreCaseOption
= ignoreCase() ? JSRegExpIgnoreCase
: JSRegExpDoNotIgnoreCase
;
194 JSRegExpMultilineOption multilineOption
= multiline() ? JSRegExpMultiline
: JSRegExpSingleLine
;
195 m_regExp
= jsRegExpCompile(reinterpret_cast<const UChar
*>(m_pattern
.data()), m_pattern
.size(), ignoreCaseOption
, multilineOption
, &m_numSubpatterns
, &m_constructionError
);
198 int RegExp::match(const UString
& s
, int startOffset
, Vector
<int, 32>* ovector
)
205 if (static_cast<unsigned>(startOffset
) > s
.size() || s
.isNull())
209 // Set up the offset vector for the result.
210 // First 2/3 used for result, the last third used by PCRE.
212 int offsetVectorSize
;
213 int fixedSizeOffsetVector
[3];
215 offsetVectorSize
= 3;
216 offsetVector
= fixedSizeOffsetVector
;
218 offsetVectorSize
= (m_numSubpatterns
+ 1) * 3;
219 ovector
->resize(offsetVectorSize
);
220 offsetVector
= ovector
->data();
223 int numMatches
= jsRegExpExecute(m_regExp
, reinterpret_cast<const UChar
*>(s
.data()), s
.size(), startOffset
, offsetVector
, offsetVectorSize
);
225 if (numMatches
< 0) {
227 if (numMatches
!= JSRegExpErrorNoMatch
)
228 fprintf(stderr
, "jsRegExpExecute failed with result %d\n", numMatches
);
235 return offsetVector
[0];