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 @@
var FLAG_harmony_tolength;
var GlobalObject = global.Object;
var GlobalRegExp = global.RegExp;
var InternalArray = utils.InternalArray;
var InternalPackedArray = utils.InternalPackedArray;
var MakeTypeError;
var splitSymbol = utils.ImportNow("split_symbol");
utils.ImportFromExperimental(function(from) {
FLAG_harmony_tolength = from.FLAG_harmony_tolength;
......@@ -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
// rightContext of the RegExp constructor. The properties are computed based
// on the captures array of the last successful match and the subject string
......@@ -384,7 +456,8 @@ utils.InstallFunctions(GlobalRegExp.prototype, DONT_ENUM, [
"exec", RegExpExecJS,
"test", RegExpTest,
"toString", RegExpToString,
"compile", RegExpCompileJS
"compile", RegExpCompileJS,
splitSymbol, RegExpSplit,
]);
utils.InstallGetter(GlobalRegExp.prototype, 'global', RegExpGetGlobal);
......
......@@ -20,6 +20,7 @@ var MakeTypeError;
var RegExpExec;
var RegExpExecNoTests;
var RegExpLastMatchInfo;
var splitSymbol = utils.ImportNow("split_symbol");
utils.Import(function(from) {
ArrayIndexOf = from.ArrayIndexOf;
......@@ -554,15 +555,24 @@ function StringSlice(start, end) {
}
// ECMA-262 section 15.5.4.14
// ES6 21.1.3.17.
function StringSplitJS(separator, limit) {
CHECK_OBJECT_COERCIBLE(this, "String.prototype.split");
if (!IS_NULL_OR_UNDEFINED(separator)) {
var splitter = separator[splitSymbol];
if (!IS_UNDEFINED(splitter)) {
if (!IS_CALLABLE(splitter)) {
throw MakeTypeError(kCalledNonCallable, splitter);
}
return %_Call(splitter, separator, this, limit);
}
}
var subject = TO_STRING(this);
limit = (IS_UNDEFINED(limit)) ? 0xffffffff : TO_UINT32(limit);
limit = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit);
var length = subject.length;
if (!IS_REGEXP(separator)) {
var separator_string = TO_STRING(separator);
if (limit === 0) return [];
......@@ -576,73 +586,7 @@ function StringSplitJS(separator, limit) {
// 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 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 = RegExpExec(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;
return %StringSplit(subject, separator_string, limit);
}
......
// 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