OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 (function(global, utils) { | 5 (function(global, utils) { |
6 | 6 |
7 %CheckIsBootstrapping(); | 7 %CheckIsBootstrapping(); |
8 | 8 |
9 // ------------------------------------------------------------------- | 9 // ------------------------------------------------------------------- |
10 // Imports | 10 // Imports |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 | 155 |
156 // Successful match. | 156 // Successful match. |
157 if (updateLastIndex) { | 157 if (updateLastIndex) { |
158 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; | 158 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; |
159 } | 159 } |
160 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string); | 160 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string); |
161 } | 161 } |
162 %FunctionRemovePrototype(RegExpSubclassExecJS); | 162 %FunctionRemovePrototype(RegExpSubclassExecJS); |
163 | 163 |
164 | 164 |
165 // Legacy implementation of RegExp.prototype.exec | |
166 function RegExpExecJS(string) { | |
167 if (!IS_REGEXP(this)) { | |
168 throw %make_type_error(kIncompatibleMethodReceiver, | |
169 'RegExp.prototype.exec', this); | |
170 } | |
171 | |
172 string = TO_STRING(string); | |
173 var lastIndex = this.lastIndex; | |
174 | |
175 // Conversion is required by the ES2015 specification (RegExpBuiltinExec | |
176 // algorithm, step 4) even if the value is discarded for non-global RegExps. | |
177 var i = TO_LENGTH(lastIndex); | |
178 | |
179 var updateLastIndex = REGEXP_GLOBAL(this) || REGEXP_STICKY(this); | |
180 if (updateLastIndex) { | |
181 if (i < 0 || i > string.length) { | |
182 this.lastIndex = 0; | |
183 return null; | |
184 } | |
185 } else { | |
186 i = 0; | |
187 } | |
188 | |
189 // matchIndices is either null or the RegExpLastMatchInfo array. | |
190 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo); | |
191 | |
192 if (IS_NULL(matchIndices)) { | |
193 this.lastIndex = 0; | |
194 return null; | |
195 } | |
196 | |
197 // Successful match. | |
198 if (updateLastIndex) { | |
199 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; | |
200 } | |
201 RETURN_NEW_RESULT_FROM_MATCH_INFO(matchIndices, string); | |
202 } | |
203 | |
204 | |
205 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) | 165 // ES#sec-regexpexec Runtime Semantics: RegExpExec ( R, S ) |
206 // Also takes an optional exec method in case our caller | 166 // Also takes an optional exec method in case our caller |
207 // has already fetched exec. | 167 // has already fetched exec. |
208 function RegExpSubclassExec(regexp, string, exec) { | 168 function RegExpSubclassExec(regexp, string, exec) { |
209 if (IS_UNDEFINED(exec)) { | 169 if (IS_UNDEFINED(exec)) { |
210 exec = regexp.exec; | 170 exec = regexp.exec; |
211 } | 171 } |
212 if (IS_CALLABLE(exec)) { | 172 if (IS_CALLABLE(exec)) { |
213 var result = %_Call(exec, regexp, string); | 173 var result = %_Call(exec, regexp, string); |
214 if (!IS_RECEIVER(result) && !IS_NULL(result)) { | 174 if (!IS_RECEIVER(result) && !IS_NULL(result)) { |
215 throw %make_type_error(kInvalidRegExpExecResult); | 175 throw %make_type_error(kInvalidRegExpExecResult); |
216 } | 176 } |
217 return result; | 177 return result; |
218 } | 178 } |
219 return %_Call(RegExpExecJS, regexp, string); | 179 return %_Call(RegExpSubclassExecJS, regexp, string); |
220 } | 180 } |
221 %SetForceInlineFlag(RegExpSubclassExec); | 181 %SetForceInlineFlag(RegExpSubclassExec); |
222 | 182 |
223 | 183 |
224 // One-element cache for the simplified test regexp. | |
225 var regexp_key; | |
226 var regexp_val; | |
227 | |
228 // Legacy implementation of RegExp.prototype.test | |
229 // Section 15.10.6.3 doesn't actually make sense, but the intention seems to be | |
230 // that test is defined in terms of String.prototype.exec. However, it probably | |
231 // means the original value of String.prototype.exec, which is what everybody | |
232 // else implements. | |
233 function RegExpTest(string) { | |
234 if (!IS_REGEXP(this)) { | |
235 throw %make_type_error(kIncompatibleMethodReceiver, | |
236 'RegExp.prototype.test', this); | |
237 } | |
238 string = TO_STRING(string); | |
239 | |
240 var lastIndex = this.lastIndex; | |
241 | |
242 // Conversion is required by the ES2015 specification (RegExpBuiltinExec | |
243 // algorithm, step 4) even if the value is discarded for non-global RegExps. | |
244 var i = TO_LENGTH(lastIndex); | |
245 | |
246 if (REGEXP_GLOBAL(this) || REGEXP_STICKY(this)) { | |
247 if (i < 0 || i > string.length) { | |
248 this.lastIndex = 0; | |
249 return false; | |
250 } | |
251 // matchIndices is either null or the RegExpLastMatchInfo array. | |
252 var matchIndices = %_RegExpExec(this, string, i, RegExpLastMatchInfo); | |
253 if (IS_NULL(matchIndices)) { | |
254 this.lastIndex = 0; | |
255 return false; | |
256 } | |
257 this.lastIndex = RegExpLastMatchInfo[CAPTURE1]; | |
258 return true; | |
259 } else { | |
260 // Non-global, non-sticky regexp. | |
261 // Remove irrelevant preceeding '.*' in a test regexp. The expression | |
262 // checks whether this.source starts with '.*' and that the third char is | |
263 // not a '?'. But see https://code.google.com/p/v8/issues/detail?id=3560 | |
264 var regexp = this; | |
265 var source = REGEXP_SOURCE(regexp); | |
266 if (source.length >= 3 && | |
267 %_StringCharCodeAt(source, 0) == 46 && // '.' | |
268 %_StringCharCodeAt(source, 1) == 42 && // '*' | |
269 %_StringCharCodeAt(source, 2) != 63) { // '?' | |
270 regexp = TrimRegExp(regexp); | |
271 } | |
272 // matchIndices is either null or the RegExpLastMatchInfo array. | |
273 var matchIndices = %_RegExpExec(regexp, string, 0, RegExpLastMatchInfo); | |
274 if (IS_NULL(matchIndices)) { | |
275 this.lastIndex = 0; | |
276 return false; | |
277 } | |
278 return true; | |
279 } | |
280 } | |
281 | |
282 | |
283 // ES#sec-regexp.prototype.test RegExp.prototype.test ( S ) | 184 // ES#sec-regexp.prototype.test RegExp.prototype.test ( S ) |
284 function RegExpSubclassTest(string) { | 185 function RegExpSubclassTest(string) { |
285 if (!IS_RECEIVER(this)) { | 186 if (!IS_RECEIVER(this)) { |
286 throw %make_type_error(kIncompatibleMethodReceiver, | 187 throw %make_type_error(kIncompatibleMethodReceiver, |
287 'RegExp.prototype.test', this); | 188 'RegExp.prototype.test', this); |
288 } | 189 } |
289 string = TO_STRING(string); | 190 string = TO_STRING(string); |
290 var match = RegExpSubclassExec(this, string); | 191 var match = RegExpSubclassExec(this, string); |
291 return !IS_NULL(match); | 192 return !IS_NULL(match); |
292 } | 193 } |
293 %FunctionRemovePrototype(RegExpSubclassTest); | 194 %FunctionRemovePrototype(RegExpSubclassTest); |
294 | 195 |
295 function TrimRegExp(regexp) { | |
296 if (regexp_key !== regexp) { | |
297 regexp_key = regexp; | |
298 regexp_val = | |
299 new GlobalRegExp( | |
300 %_SubString(REGEXP_SOURCE(regexp), 2, REGEXP_SOURCE(regexp).length), | |
301 (REGEXP_IGNORE_CASE(regexp) ? REGEXP_MULTILINE(regexp) ? "im" : "i" | |
302 : REGEXP_MULTILINE(regexp) ? "m" : "")); | |
303 } | |
304 return regexp_val; | |
305 } | |
306 | |
307 | 196 |
308 function AtSurrogatePair(subject, index) { | 197 function AtSurrogatePair(subject, index) { |
309 if (index + 1 >= subject.length) return false; | 198 if (index + 1 >= subject.length) return false; |
310 var first = %_StringCharCodeAt(subject, index); | 199 var first = %_StringCharCodeAt(subject, index); |
311 if (first < 0xD800 || first > 0xDBFF) return false; | 200 if (first < 0xD800 || first > 0xDBFF) return false; |
312 var second = %_StringCharCodeAt(subject, index + 1); | 201 var second = %_StringCharCodeAt(subject, index + 1); |
313 return second >= 0xDC00 || second <= 0xDFFF; | 202 return second >= 0xDC00 || second <= 0xDFFF; |
314 } | 203 } |
315 | 204 |
316 | 205 |
(...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
920 subject, regexp, replacement, InternalRegExpMatchInfo); | 809 subject, regexp, replacement, InternalRegExpMatchInfo); |
921 } | 810 } |
922 | 811 |
923 // ------------------------------------------------------------------- | 812 // ------------------------------------------------------------------- |
924 // Exports | 813 // Exports |
925 | 814 |
926 utils.Export(function(to) { | 815 utils.Export(function(to) { |
927 to.InternalRegExpMatch = InternalRegExpMatch; | 816 to.InternalRegExpMatch = InternalRegExpMatch; |
928 to.InternalRegExpReplace = InternalRegExpReplace; | 817 to.InternalRegExpReplace = InternalRegExpReplace; |
929 to.IsRegExp = IsRegExp; | 818 to.IsRegExp = IsRegExp; |
930 to.RegExpExec = DoRegExpExec; | |
931 to.RegExpInitialize = RegExpInitialize; | 819 to.RegExpInitialize = RegExpInitialize; |
932 to.RegExpLastMatchInfo = RegExpLastMatchInfo; | |
933 to.RegExpTest = RegExpTest; | |
934 }); | 820 }); |
935 | 821 |
936 }) | 822 }) |
OLD | NEW |