From 466da713c3e9e7583586933572d66c6bed1745f3 Mon Sep 17 00:00:00 2001 From: yangguo Date: Mon, 14 Dec 2015 02:22:22 -0800 Subject: [PATCH] [es6] implement RegExp.@@search. BUG=v8:4344 LOG=N R=littledan@chromium.org Review URL: https://codereview.chromium.org/1506353009 Cr-Commit-Position: refs/heads/master@{#32827} --- src/js/regexp.js | 19 +++++++++++++++++-- src/js/string.js | 26 +++++++++++++------------- test/mjsunit/es6/string-search.js | 20 ++++++++++++++++++++ 3 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 test/mjsunit/es6/string-search.js diff --git a/src/js/regexp.js b/src/js/regexp.js index 889c6b0acf..7119fdba01 100644 --- a/src/js/regexp.js +++ b/src/js/regexp.js @@ -16,6 +16,7 @@ var InternalArray = utils.InternalArray; var InternalPackedArray = utils.InternalPackedArray; var MakeTypeError; var matchSymbol = utils.ImportNow("match_symbol"); +var searchSymbol = utils.ImportNow("search_symbol"); var splitSymbol = utils.ImportNow("split_symbol"); utils.ImportFromExperimental(function(from) { @@ -117,8 +118,7 @@ function RegExpCompileJS(pattern, flags) { function DoRegExpExec(regexp, string, index) { - var result = %_RegExpExec(regexp, string, index, RegExpLastMatchInfo); - return result; + return %_RegExpExec(regexp, string, index, RegExpLastMatchInfo); } @@ -357,6 +357,7 @@ function RegExpSplit(string, limit) { // ES6 21.2.5.6. function RegExpMatch(string) { + // TODO(yangguo): allow non-regexp receivers. if (!IS_REGEXP(this)) { throw MakeTypeError(kIncompatibleMethodReceiver, "RegExp.prototype.@@match", this); @@ -370,6 +371,19 @@ function RegExpMatch(string) { } +// ES6 21.2.5.9. +function RegExpSearch(string) { + // TODO(yangguo): allow non-regexp receivers. + if (!IS_REGEXP(this)) { + throw MakeTypeError(kIncompatibleMethodReceiver, + "RegExp.prototype.@@search", this); + } + var match = DoRegExpExec(this, TO_STRING(string), 0); + if (match) return match[CAPTURE0]; + return -1; +} + + // Getters for the static properties lastMatch, lastParen, leftContext, and // rightContext of the RegExp constructor. The properties are computed based // on the captures array of the last successful match and the subject string @@ -488,6 +502,7 @@ utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ "toString", RegExpToString, "compile", RegExpCompileJS, matchSymbol, RegExpMatch, + searchSymbol, RegExpSearch, splitSymbol, RegExpSplit, ]); diff --git a/src/js/string.js b/src/js/string.js index 139bf7a654..b220038b74 100644 --- a/src/js/string.js +++ b/src/js/string.js @@ -23,6 +23,7 @@ var matchSymbol = utils.ImportNow("match_symbol"); var RegExpExec; var RegExpExecNoTests; var RegExpLastMatchInfo; +var searchSymbol = utils.ImportNow("search_symbol"); var splitSymbol = utils.ImportNow("split_symbol"); utils.Import(function(from) { @@ -155,7 +156,7 @@ function StringLocaleCompareJS(other) { } -// ECMA-262 section 15.5.4.10 +// ES6 21.1.3.11. function StringMatchJS(pattern) { CHECK_OBJECT_COERCIBLE(this, "String.prototype.match"); @@ -502,21 +503,20 @@ function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { } -// ECMA-262 section 15.5.4.12 -function StringSearch(re) { +// ES6 21.1.3.15. +function StringSearch(pattern) { CHECK_OBJECT_COERCIBLE(this, "String.prototype.search"); - var regexp; - if (IS_REGEXP(re)) { - regexp = re; - } else { - regexp = new GlobalRegExp(re); + if (!IS_NULL_OR_UNDEFINED(pattern)) { + var searcher = pattern[searchSymbol]; + if (!IS_UNDEFINED(searcher)) { + return %_Call(searcher, pattern, this); + } } - var match = RegExpExec(regexp, TO_STRING(this), 0); - if (match) { - return match[CAPTURE0]; - } - return -1; + + var subject = TO_STRING(this); + var regexp = new GlobalRegExp(pattern); + return %_Call(regexp[searchSymbol], regexp, subject); } diff --git a/test/mjsunit/es6/string-search.js b/test/mjsunit/es6/string-search.js new file mode 100644 index 0000000000..dc029826ad --- /dev/null +++ b/test/mjsunit/es6/string-search.js @@ -0,0 +1,20 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --harmony-regexp-subclass + +var pattern = {}; +pattern[Symbol.search] = function(string) { + return string.length; +}; +// Check object coercible fails. +assertThrows(() => String.prototype.search.call(null, pattern), + TypeError); +// Override is called. +assertEquals(5, "abcde".search(pattern)); +// Non-callable override. +pattern[Symbol.search] = "dumdidum"; +assertThrows(() => "abcde".search(pattern), TypeError); + +assertEquals("[Symbol.search]", RegExp.prototype[Symbol.search].name);