| 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 |