Commit 9a569ec2 authored by yangguo's avatar yangguo Committed by Commit bot

[es6] Implement @@split subclassing.

RegExp.prototye[@@split] is not yet implement to spec regarding creating
new RegExp object with the SpeciesConstructor.

R=littledan@chromium.org
BUG=v8:4345
LOG=N

Review URL: https://codereview.chromium.org/1427573005

Cr-Commit-Position: refs/heads/master@{#31911}
parent 483d8b9b
...@@ -12,8 +12,10 @@ ...@@ -12,8 +12,10 @@
var FLAG_harmony_tolength; var FLAG_harmony_tolength;
var GlobalObject = global.Object; var GlobalObject = global.Object;
var GlobalRegExp = global.RegExp; var GlobalRegExp = global.RegExp;
var InternalArray = utils.InternalArray;
var InternalPackedArray = utils.InternalPackedArray; var InternalPackedArray = utils.InternalPackedArray;
var MakeTypeError; var MakeTypeError;
var splitSymbol = utils.ImportNow("split_symbol");
utils.ImportFromExperimental(function(from) { utils.ImportFromExperimental(function(from) {
FLAG_harmony_tolength = from.FLAG_harmony_tolength; FLAG_harmony_tolength = from.FLAG_harmony_tolength;
...@@ -268,6 +270,76 @@ function RegExpToString() { ...@@ -268,6 +270,76 @@ function RegExpToString() {
} }
// ES6 21.2.5.11.
function RegExpSplit(string, limit) {
// TODO(yangguo): allow non-regexp receivers.
if (!IS_REGEXP(this)) {
throw MakeTypeError(kIncompatibleMethodReceiver,
"RegExp.prototype.@@split", this);
}
var separator = this;
var subject = TO_STRING(string);
limit = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit);
var length = subject.length;
if (limit === 0) return [];
if (length === 0) {
if (DoRegExpExec(separator, subject, 0, 0) !== null) return [];
return [subject];
}
var currentIndex = 0;
var startIndex = 0;
var startMatch = 0;
var result = new InternalArray();
outer_loop:
while (true) {
if (startIndex === length) {
result[result.length] = %_SubString(subject, currentIndex, length);
break;
}
var matchInfo = DoRegExpExec(separator, subject, startIndex);
if (matchInfo === null || length === (startMatch = matchInfo[CAPTURE0])) {
result[result.length] = %_SubString(subject, currentIndex, length);
break;
}
var endIndex = matchInfo[CAPTURE1];
// We ignore a zero-length match at the currentIndex.
if (startIndex === endIndex && endIndex === currentIndex) {
startIndex++;
continue;
}
result[result.length] = %_SubString(subject, currentIndex, startMatch);
if (result.length === limit) break;
var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE;
for (var i = REGEXP_FIRST_CAPTURE + 2; i < matchinfo_len; ) {
var start = matchInfo[i++];
var end = matchInfo[i++];
if (end != -1) {
result[result.length] = %_SubString(subject, start, end);
} else {
result[result.length] = UNDEFINED;
}
if (result.length === limit) break outer_loop;
}
startIndex = currentIndex = endIndex;
}
var array_result = [];
%MoveArrayContents(result, array_result);
return array_result;
}
// Getters for the static properties lastMatch, lastParen, leftContext, and // Getters for the static properties lastMatch, lastParen, leftContext, and
// rightContext of the RegExp constructor. The properties are computed based // rightContext of the RegExp constructor. The properties are computed based
// on the captures array of the last successful match and the subject string // on the captures array of the last successful match and the subject string
...@@ -384,7 +456,8 @@ utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [ ...@@ -384,7 +456,8 @@ utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [
"exec", RegExpExecJS, "exec", RegExpExecJS,
"test", RegExpTest, "test", RegExpTest,
"toString", RegExpToString, "toString", RegExpToString,
"compile", RegExpCompileJS "compile", RegExpCompileJS,
splitSymbol, RegExpSplit,
]); ]);
utils.InstallGetter(GlobalRegExp.prototype, 'global', RegExpGetGlobal); utils.InstallGetter(GlobalRegExp.prototype, 'global', RegExpGetGlobal);
......
...@@ -20,6 +20,7 @@ var MakeTypeError; ...@@ -20,6 +20,7 @@ var MakeTypeError;
var RegExpExec; var RegExpExec;
var RegExpExecNoTests; var RegExpExecNoTests;
var RegExpLastMatchInfo; var RegExpLastMatchInfo;
var splitSymbol = utils.ImportNow("split_symbol");
utils.Import(function(from) { utils.Import(function(from) {
ArrayIndexOf = from.ArrayIndexOf; ArrayIndexOf = from.ArrayIndexOf;
...@@ -554,95 +555,38 @@ function StringSlice(start, end) { ...@@ -554,95 +555,38 @@ function StringSlice(start, end) {
} }
// ECMA-262 section 15.5.4.14 // ES6 21.1.3.17.
function StringSplitJS(separator, limit) { function StringSplitJS(separator, limit) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.split"); CHECK_OBJECT_COERCIBLE(this, "String.prototype.split");
var subject = TO_STRING(this); if (!IS_NULL_OR_UNDEFINED(separator)) {
limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit); var splitter = separator[splitSymbol];
if (!IS_UNDEFINED(splitter)) {
var length = subject.length; if (!IS_CALLABLE(splitter)) {
if (!IS_REGEXP(separator)) { throw MakeTypeError(kCalledNonCallable, splitter);
var separator_string = TO_STRING(separator); }
return %_Call(splitter, separator, this, limit);
if (limit === 0) return [];
// ECMA-262 says that if separator is undefined, the result should
// be an array of size 1 containing the entire string.
if (IS_UNDEFINED(separator)) return [subject];
var separator_length = separator_string.length;
// If the separator string is empty then return the elements in the subject.
if (separator_length === 0) return %StringToArray(subject, limit);
var result = %StringSplit(subject, separator_string, limit);
return result;
}
if (limit === 0) return [];
// Separator is a regular expression.
return StringSplitOnRegExp(subject, separator, limit, length);
}
function StringSplitOnRegExp(subject, separator, limit, length) {
if (length === 0) {
if (RegExpExec(separator, subject, 0, 0) != null) {
return [];
} }
return [subject];
} }
var currentIndex = 0; var subject = TO_STRING(this);
var startIndex = 0; limit = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit);
var startMatch = 0;
var result = new InternalArray();
outer_loop:
while (true) {
if (startIndex === length) {
result[result.length] = %_SubString(subject, currentIndex, length);
break;
}
var matchInfo = RegExpExec(separator, subject, startIndex); var length = subject.length;
if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) { var separator_string = TO_STRING(separator);
result[result.length] = %_SubString(subject, currentIndex, length);
break;
}
var endIndex = matchInfo[CAPTURE1];
// We ignore a zero-length match at the currentIndex. if (limit === 0) return [];
if (startIndex === endIndex && endIndex === currentIndex) {
startIndex++;
continue;
}
result[result.length] = %_SubString(subject, currentIndex, startMatch); // ECMA-262 says that if separator is undefined, the result should
// be an array of size 1 containing the entire string.
if (IS_UNDEFINED(separator)) return [subject];
if (result.length === limit) break; var separator_length = separator_string.length;
var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE; // If the separator string is empty then return the elements in the subject.
for (var i = REGEXP_FIRST_CAPTURE + 2; i < matchinfo_len; ) { if (separator_length === 0) return %StringToArray(subject, limit);
var start = matchInfo[i++];
var end = matchInfo[i++];
if (end != -1) {
result[result.length] = %_SubString(subject, start, end);
} else {
result[result.length] = UNDEFINED;
}
if (result.length === limit) break outer_loop;
}
startIndex = currentIndex = endIndex; return %StringSplit(subject, separator_string, limit);
}
var array_result = [];
%MoveArrayContents(result, array_result);
return array_result;
} }
......
// 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 = {};
var limit = { value: 3 };
pattern[Symbol.split] = function(string, limit) {
return string.length * limit.value;
};
// Check object coercible fails.
assertThrows(() => String.prototype.split.call(null, pattern, limit),
TypeError);
// Override is called.
assertEquals(15, "abcde".split(pattern, limit));
// Non-callable override.
pattern[Symbol.split] = "dumdidum";
assertThrows(() => "abcde".split(pattern, limit), TypeError);
assertEquals("[Symbol.split]", RegExp.prototype[Symbol.split].name);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment