[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}
This commit is contained in:
parent
483d8b9bd8
commit
9a569ec2c8
@ -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,95 +555,38 @@ 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 [];
|
||||
|
||||
// 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;
|
||||
}
|
||||
var separator_string = TO_STRING(separator);
|
||||
|
||||
if (limit === 0) return [];
|
||||
|
||||
// Separator is a regular expression.
|
||||
return StringSplitOnRegExp(subject, separator, limit, length);
|
||||
}
|
||||
// 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;
|
||||
|
||||
function StringSplitOnRegExp(subject, separator, limit, length) {
|
||||
if (length === 0) {
|
||||
if (RegExpExec(separator, subject, 0, 0) != null) {
|
||||
return [];
|
||||
}
|
||||
return [subject];
|
||||
}
|
||||
// If the separator string is empty then return the elements in the subject.
|
||||
if (separator_length === 0) return %StringToArray(subject, limit);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
21
test/mjsunit/harmony/string-split.js
Normal file
21
test/mjsunit/harmony/string-split.js
Normal file
@ -0,0 +1,21 @@
|
||||
// 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);
|
Loading…
Reference in New Issue
Block a user