Commit 9355457b authored by caitpotter88's avatar caitpotter88 Committed by Commit bot

Implement parsing of ES6 Rest Parameters

BUG=v8:2159
LOG=N
R=marja@chromium.org, arv@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#26362}
parent 3df0a9ae
...@@ -1599,6 +1599,7 @@ EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_templates) ...@@ -1599,6 +1599,7 @@ EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_templates)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_sloppy) EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_sloppy)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_unicode) EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_unicode)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_computed_property_names) EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_computed_property_names)
EMPTY_NATIVE_FUNCTIONS_FOR_FEATURE(harmony_rest_parameters)
void Genesis::InstallNativeFunctions_harmony_proxies() { void Genesis::InstallNativeFunctions_harmony_proxies() {
...@@ -1629,6 +1630,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_proxies) ...@@ -1629,6 +1630,7 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_proxies)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_templates) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_templates)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_sloppy) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_sloppy)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_computed_property_names) EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_computed_property_names)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_rest_parameters)
void Genesis::InitializeGlobal_harmony_regexps() { void Genesis::InitializeGlobal_harmony_regexps() {
Handle<JSObject> builtins(native_context()->builtins()); Handle<JSObject> builtins(native_context()->builtins());
...@@ -2208,6 +2210,7 @@ bool Genesis::InstallExperimentalNatives() { ...@@ -2208,6 +2210,7 @@ bool Genesis::InstallExperimentalNatives() {
static const char* harmony_sloppy_natives[] = {NULL}; static const char* harmony_sloppy_natives[] = {NULL};
static const char* harmony_unicode_natives[] = {NULL}; static const char* harmony_unicode_natives[] = {NULL};
static const char* harmony_computed_property_names_natives[] = {NULL}; static const char* harmony_computed_property_names_natives[] = {NULL};
static const char* harmony_rest_parameters_natives[] = {NULL};
for (int i = ExperimentalNatives::GetDebuggerCount(); for (int i = ExperimentalNatives::GetDebuggerCount();
i < ExperimentalNatives::GetBuiltinsCount(); i++) { i < ExperimentalNatives::GetBuiltinsCount(); i++) {
......
...@@ -186,7 +186,8 @@ DEFINE_IMPLICATION(es_staging, harmony) ...@@ -186,7 +186,8 @@ DEFINE_IMPLICATION(es_staging, harmony)
V(harmony_proxies, "harmony proxies") \ V(harmony_proxies, "harmony proxies") \
V(harmony_sloppy, "harmony features in sloppy mode") \ V(harmony_sloppy, "harmony features in sloppy mode") \
V(harmony_unicode, "harmony unicode escapes") \ V(harmony_unicode, "harmony unicode escapes") \
V(harmony_computed_property_names, "harmony computed property names") V(harmony_computed_property_names, "harmony computed property names") \
V(harmony_rest_parameters, "harmony rest parameters")
// Features that are complete (but still behind --harmony/es-staging flag). // Features that are complete (but still behind --harmony/es-staging flag).
#define HARMONY_STAGED(V) \ #define HARMONY_STAGED(V) \
......
...@@ -816,6 +816,7 @@ Parser::Parser(CompilationInfo* info, ParseInfo* parse_info) ...@@ -816,6 +816,7 @@ Parser::Parser(CompilationInfo* info, ParseInfo* parse_info)
set_allow_harmony_unicode(FLAG_harmony_unicode); set_allow_harmony_unicode(FLAG_harmony_unicode);
set_allow_harmony_computed_property_names( set_allow_harmony_computed_property_names(
FLAG_harmony_computed_property_names); FLAG_harmony_computed_property_names);
set_allow_harmony_rest_params(FLAG_harmony_rest_parameters);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) { ++feature) {
use_counts_[feature] = 0; use_counts_[feature] = 0;
...@@ -3675,11 +3676,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -3675,11 +3676,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
Scanner::Location dupe_error_loc = Scanner::Location::invalid(); Scanner::Location dupe_error_loc = Scanner::Location::invalid();
Scanner::Location reserved_loc = Scanner::Location::invalid(); Scanner::Location reserved_loc = Scanner::Location::invalid();
bool is_rest = false;
bool done = arity_restriction == FunctionLiteral::GETTER_ARITY || bool done = arity_restriction == FunctionLiteral::GETTER_ARITY ||
(peek() == Token::RPAREN && (peek() == Token::RPAREN &&
arity_restriction != FunctionLiteral::SETTER_ARITY); arity_restriction != FunctionLiteral::SETTER_ARITY);
while (!done) { while (!done) {
bool is_strict_reserved = false; bool is_strict_reserved = false;
is_rest = peek() == Token::ELLIPSIS && allow_harmony_rest_params();
if (is_rest) {
Consume(Token::ELLIPSIS);
}
const AstRawString* param_name = const AstRawString* param_name =
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
...@@ -3695,7 +3702,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -3695,7 +3702,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
dupe_error_loc = scanner()->location(); dupe_error_loc = scanner()->location();
} }
Variable* var = scope_->DeclareParameter(param_name, VAR); Variable* var = scope_->DeclareParameter(param_name, VAR, is_rest);
if (scope->strict_mode() == SLOPPY) { if (scope->strict_mode() == SLOPPY) {
// TODO(sigurds) Mark every parameter as maybe assigned. This is a // TODO(sigurds) Mark every parameter as maybe assigned. This is a
// conservative approximation necessary to account for parameters // conservative approximation necessary to account for parameters
...@@ -3711,7 +3718,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -3711,7 +3718,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
} }
if (arity_restriction == FunctionLiteral::SETTER_ARITY) break; if (arity_restriction == FunctionLiteral::SETTER_ARITY) break;
done = (peek() == Token::RPAREN); done = (peek() == Token::RPAREN);
if (!done) Expect(Token::COMMA, CHECK_OK); if (!done) {
if (is_rest) {
ReportMessageAt(scanner()->peek_location(), "param_after_rest");
*ok = false;
return NULL;
}
Expect(Token::COMMA, CHECK_OK);
}
} }
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
...@@ -3794,7 +3808,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral( ...@@ -3794,7 +3808,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// Validate strict mode. // Validate strict mode.
// Concise methods use StrictFormalParameters. // Concise methods use StrictFormalParameters.
if (strict_mode() == STRICT || IsConciseMethod(kind)) { // Functions for which IsSimpleParameterList() returns false use
// StrictFormalParameters.
if (strict_mode() == STRICT || IsConciseMethod(kind) || is_rest) {
CheckStrictFunctionNameAndParameters(function_name, CheckStrictFunctionNameAndParameters(function_name,
name_is_strict_reserved, name_is_strict_reserved,
function_name_location, function_name_location,
...@@ -3979,6 +3995,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( ...@@ -3979,6 +3995,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
reusable_preparser_->set_allow_harmony_unicode(allow_harmony_unicode()); reusable_preparser_->set_allow_harmony_unicode(allow_harmony_unicode());
reusable_preparser_->set_allow_harmony_computed_property_names( reusable_preparser_->set_allow_harmony_computed_property_names(
allow_harmony_computed_property_names()); allow_harmony_computed_property_names());
reusable_preparser_->set_allow_harmony_rest_params(
allow_harmony_rest_params());
} }
PreParser::PreParseResult result = PreParser::PreParseResult result =
reusable_preparser_->PreParseLazyFunction(strict_mode(), reusable_preparser_->PreParseLazyFunction(strict_mode(),
......
...@@ -878,11 +878,17 @@ PreParser::Expression PreParser::ParseFunctionLiteral( ...@@ -878,11 +878,17 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
Scanner::Location dupe_error_loc = Scanner::Location::invalid(); Scanner::Location dupe_error_loc = Scanner::Location::invalid();
Scanner::Location reserved_error_loc = Scanner::Location::invalid(); Scanner::Location reserved_error_loc = Scanner::Location::invalid();
bool is_rest = false;
bool done = arity_restriction == FunctionLiteral::GETTER_ARITY || bool done = arity_restriction == FunctionLiteral::GETTER_ARITY ||
(peek() == Token::RPAREN && (peek() == Token::RPAREN &&
arity_restriction != FunctionLiteral::SETTER_ARITY); arity_restriction != FunctionLiteral::SETTER_ARITY);
while (!done) { while (!done) {
bool is_strict_reserved = false; bool is_strict_reserved = false;
is_rest = peek() == Token::ELLIPSIS && allow_harmony_rest_params();
if (is_rest) {
Consume(Token::ELLIPSIS);
}
Identifier param_name = Identifier param_name =
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
if (!eval_args_error_loc.IsValid() && param_name.IsEvalOrArguments()) { if (!eval_args_error_loc.IsValid() && param_name.IsEvalOrArguments()) {
...@@ -900,7 +906,14 @@ PreParser::Expression PreParser::ParseFunctionLiteral( ...@@ -900,7 +906,14 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
if (arity_restriction == FunctionLiteral::SETTER_ARITY) break; if (arity_restriction == FunctionLiteral::SETTER_ARITY) break;
done = (peek() == Token::RPAREN); done = (peek() == Token::RPAREN);
if (!done) Expect(Token::COMMA, CHECK_OK); if (!done) {
if (is_rest) {
ReportMessageAt(scanner()->peek_location(), "param_after_rest");
*ok = false;
return Expression::Default();
}
Expect(Token::COMMA, CHECK_OK);
}
} }
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
...@@ -921,7 +934,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral( ...@@ -921,7 +934,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
// Validate strict mode. We can do this only after parsing the function, // Validate strict mode. We can do this only after parsing the function,
// since the function can declare itself strict. // since the function can declare itself strict.
// Concise methods use StrictFormalParameters. // Concise methods use StrictFormalParameters.
if (strict_mode() == STRICT || IsConciseMethod(kind)) { if (strict_mode() == STRICT || IsConciseMethod(kind) || is_rest) {
if (function_name.IsEvalOrArguments()) { if (function_name.IsEvalOrArguments()) {
ReportMessageAt(function_name_location, "strict_eval_arguments"); ReportMessageAt(function_name_location, "strict_eval_arguments");
*ok = false; *ok = false;
......
...@@ -89,7 +89,8 @@ class ParserBase : public Traits { ...@@ -89,7 +89,8 @@ class ParserBase : public Traits {
allow_harmony_arrow_functions_(false), allow_harmony_arrow_functions_(false),
allow_harmony_object_literals_(false), allow_harmony_object_literals_(false),
allow_harmony_sloppy_(false), allow_harmony_sloppy_(false),
allow_harmony_computed_property_names_(false) {} allow_harmony_computed_property_names_(false),
allow_harmony_rest_params_(false) {}
// Getters that indicate whether certain syntactical constructs are // Getters that indicate whether certain syntactical constructs are
// allowed to be parsed by this instance of the parser. // allowed to be parsed by this instance of the parser.
...@@ -113,6 +114,9 @@ class ParserBase : public Traits { ...@@ -113,6 +114,9 @@ class ParserBase : public Traits {
bool allow_harmony_computed_property_names() const { bool allow_harmony_computed_property_names() const {
return allow_harmony_computed_property_names_; return allow_harmony_computed_property_names_;
} }
bool allow_harmony_rest_params() const {
return allow_harmony_rest_params_;
}
// Setters that determine whether certain syntactical constructs are // Setters that determine whether certain syntactical constructs are
// allowed to be parsed by this instance of the parser. // allowed to be parsed by this instance of the parser.
...@@ -148,6 +152,9 @@ class ParserBase : public Traits { ...@@ -148,6 +152,9 @@ class ParserBase : public Traits {
void set_allow_harmony_computed_property_names(bool allow) { void set_allow_harmony_computed_property_names(bool allow) {
allow_harmony_computed_property_names_ = allow; allow_harmony_computed_property_names_ = allow;
} }
void set_allow_harmony_rest_params(bool allow) {
allow_harmony_rest_params_ = allow;
}
protected: protected:
enum AllowEvalOrArgumentsAsIdentifier { enum AllowEvalOrArgumentsAsIdentifier {
...@@ -625,6 +632,7 @@ class ParserBase : public Traits { ...@@ -625,6 +632,7 @@ class ParserBase : public Traits {
bool allow_harmony_object_literals_; bool allow_harmony_object_literals_;
bool allow_harmony_sloppy_; bool allow_harmony_sloppy_;
bool allow_harmony_computed_property_names_; bool allow_harmony_computed_property_names_;
bool allow_harmony_rest_params_;
}; };
......
...@@ -599,6 +599,15 @@ void Scanner::Scan() { ...@@ -599,6 +599,15 @@ void Scanner::Scan() {
token = ScanNumber(true); token = ScanNumber(true);
} else { } else {
token = Token::PERIOD; token = Token::PERIOD;
if (c0_ == '.') {
Advance();
if (c0_ == '.') {
Advance();
token = Token::ELLIPSIS;
} else {
PushBack('.');
}
}
} }
break; break;
......
...@@ -180,6 +180,8 @@ void Scope::SetDefaults(ScopeType scope_type, ...@@ -180,6 +180,8 @@ void Scope::SetDefaults(ScopeType scope_type,
num_heap_slots_ = 0; num_heap_slots_ = 0;
num_modules_ = 0; num_modules_ = 0;
module_var_ = NULL, module_var_ = NULL,
rest_parameter_ = NULL;
rest_index_ = -1;
scope_info_ = scope_info; scope_info_ = scope_info;
start_position_ = RelocInfo::kNoPosition; start_position_ = RelocInfo::kNoPosition;
end_position_ = RelocInfo::kNoPosition; end_position_ = RelocInfo::kNoPosition;
...@@ -450,11 +452,17 @@ Variable* Scope::Lookup(const AstRawString* name) { ...@@ -450,11 +452,17 @@ Variable* Scope::Lookup(const AstRawString* name) {
} }
Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode) { Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode,
bool is_rest) {
DCHECK(!already_resolved()); DCHECK(!already_resolved());
DCHECK(is_function_scope()); DCHECK(is_function_scope());
Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL, Variable* var = variables_.Declare(this, name, mode, true, Variable::NORMAL,
kCreatedInitialized); kCreatedInitialized);
if (is_rest) {
DCHECK_NULL(rest_parameter_);
rest_parameter_ = var;
rest_index_ = num_parameters();
}
params_.Add(var, zone()); params_.Add(var, zone());
return var; return var;
} }
...@@ -1286,12 +1294,18 @@ void Scope::AllocateParameterLocals() { ...@@ -1286,12 +1294,18 @@ void Scope::AllocateParameterLocals() {
uses_sloppy_arguments = strict_mode() == SLOPPY; uses_sloppy_arguments = strict_mode() == SLOPPY;
} }
if (rest_parameter_ && !MustAllocate(rest_parameter_)) {
rest_parameter_ = NULL;
}
// The same parameter may occur multiple times in the parameters_ list. // The same parameter may occur multiple times in the parameters_ list.
// If it does, and if it is not copied into the context object, it must // If it does, and if it is not copied into the context object, it must
// receive the highest parameter index for that parameter; thus iteration // receive the highest parameter index for that parameter; thus iteration
// order is relevant! // order is relevant!
for (int i = params_.length() - 1; i >= 0; --i) { for (int i = params_.length() - 1; i >= 0; --i) {
Variable* var = params_[i]; Variable* var = params_[i];
if (var == rest_parameter_) continue;
DCHECK(var->scope() == this); DCHECK(var->scope() == this);
if (uses_sloppy_arguments || has_forced_context_allocation()) { if (uses_sloppy_arguments || has_forced_context_allocation()) {
// Force context allocation of the parameter. // Force context allocation of the parameter.
...@@ -1359,6 +1373,10 @@ void Scope::AllocateNonParameterLocals() { ...@@ -1359,6 +1373,10 @@ void Scope::AllocateNonParameterLocals() {
if (function_ != NULL) { if (function_ != NULL) {
AllocateNonParameterLocal(function_->proxy()->var()); AllocateNonParameterLocal(function_->proxy()->var());
} }
if (rest_parameter_) {
AllocateNonParameterLocal(rest_parameter_);
}
} }
......
...@@ -126,7 +126,8 @@ class Scope: public ZoneObject { ...@@ -126,7 +126,8 @@ class Scope: public ZoneObject {
// Declare a parameter in this scope. When there are duplicated // Declare a parameter in this scope. When there are duplicated
// parameters the rightmost one 'wins'. However, the implementation // parameters the rightmost one 'wins'. However, the implementation
// expects all parameters to be declared and from left to right. // expects all parameters to be declared and from left to right.
Variable* DeclareParameter(const AstRawString* name, VariableMode mode); Variable* DeclareParameter(const AstRawString* name, VariableMode mode,
bool is_rest = false);
// Declare a local variable in this scope. If the variable has been // Declare a local variable in this scope. If the variable has been
// declared before, the previously declared variable is returned. // declared before, the previously declared variable is returned.
...@@ -358,8 +359,32 @@ class Scope: public ZoneObject { ...@@ -358,8 +359,32 @@ class Scope: public ZoneObject {
return params_[index]; return params_[index];
} }
// Returns the default function arity --- does not include rest parameters.
int default_function_length() const {
int count = params_.length();
if (rest_index_ >= 0) {
DCHECK(count > 0);
DCHECK(is_function_scope());
--count;
}
return count;
}
int num_parameters() const { return params_.length(); } int num_parameters() const { return params_.length(); }
// A function can have at most one rest parameter. Returns Variable* or NULL.
Variable* rest_parameter(int* index) const {
*index = rest_index_;
if (rest_index_ < 0) return NULL;
return rest_parameter_;
}
bool is_simple_parameter_list() const {
DCHECK(is_function_scope());
if (rest_index_ >= 0) return false;
return true;
}
// The local variable 'arguments' if we need to allocate it; NULL otherwise. // The local variable 'arguments' if we need to allocate it; NULL otherwise.
Variable* arguments() const { return arguments_; } Variable* arguments() const { return arguments_; }
...@@ -555,6 +580,10 @@ class Scope: public ZoneObject { ...@@ -555,6 +580,10 @@ class Scope: public ZoneObject {
// For module scopes, the host scope's internal variable binding this module. // For module scopes, the host scope's internal variable binding this module.
Variable* module_var_; Variable* module_var_;
// Rest parameter
Variable* rest_parameter_;
int rest_index_;
// Serialized scope info support. // Serialized scope info support.
Handle<ScopeInfo> scope_info_; Handle<ScopeInfo> scope_info_;
bool already_resolved() { return already_resolved_; } bool already_resolved() { return already_resolved_; }
......
...@@ -40,6 +40,7 @@ namespace internal { ...@@ -40,6 +40,7 @@ namespace internal {
T(COLON, ":", 0) \ T(COLON, ":", 0) \
T(SEMICOLON, ";", 0) \ T(SEMICOLON, ";", 0) \
T(PERIOD, ".", 0) \ T(PERIOD, ".", 0) \
T(ELLIPSIS, "...", 0) \
T(CONDITIONAL, "?", 3) \ T(CONDITIONAL, "?", 3) \
T(INC, "++", 0) \ T(INC, "++", 0) \
T(DEC, "--", 0) \ T(DEC, "--", 0) \
......
...@@ -1356,6 +1356,7 @@ enum ParserFlag { ...@@ -1356,6 +1356,7 @@ enum ParserFlag {
kAllowHarmonyArrowFunctions, kAllowHarmonyArrowFunctions,
kAllowHarmonyClasses, kAllowHarmonyClasses,
kAllowHarmonyObjectLiterals, kAllowHarmonyObjectLiterals,
kAllowHarmonyRestParameters,
kAllowHarmonyTemplates, kAllowHarmonyTemplates,
kAllowHarmonySloppy, kAllowHarmonySloppy,
kAllowHarmonyUnicode, kAllowHarmonyUnicode,
...@@ -1384,6 +1385,8 @@ void SetParserFlags(i::ParserBase<Traits>* parser, ...@@ -1384,6 +1385,8 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
flags.Contains(kAllowHarmonyArrowFunctions)); flags.Contains(kAllowHarmonyArrowFunctions));
parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses)); parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses));
parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates)); parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates));
parser->set_allow_harmony_rest_params(
flags.Contains(kAllowHarmonyRestParameters));
parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy)); parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode)); parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
parser->set_allow_harmony_computed_property_names( parser->set_allow_harmony_computed_property_names(
...@@ -4569,6 +4572,66 @@ TEST(TemplateLiteralsIllegalTokens) { ...@@ -4569,6 +4572,66 @@ TEST(TemplateLiteralsIllegalTokens) {
} }
TEST(ParseRestParameters) {
const char* context_data[][2] = {{"'use strict';(function(",
"){ return args;})(1, [], /regexp/, 'str',"
"function(){});"},
{"(function(", "){ return args;})(1, [],"
"/regexp/, 'str', function(){});"},
{NULL, NULL}};
const char* data[] = {
"...args",
"a, ...args",
"... args",
"a, ... args",
"...\targs",
"a, ...\targs",
"...\r\nargs",
"a, ...\r\nargs",
"...\rargs",
"a, ...\rargs",
"...\t\n\t\t\n args",
"a, ... \n \n args",
NULL};
static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
arraysize(always_flags));
}
TEST(ParseRestParametersErrors) {
const char* context_data[][2] = {{"'use strict';(function(",
"){ return args;}(1, [], /regexp/, 'str',"
"function(){});"},
{"(function(", "){ return args;}(1, [],"
"/regexp/, 'str', function(){});"},
{NULL, NULL}};
const char* data[] = {
"...args, b",
"a, ...args, b",
"...args, b",
"a, ...args, b",
"...args,\tb",
"a,...args\t,b",
"...args\r\n, b",
"a, ... args,\r\nb",
"...args\r,b",
"a, ... args,\rb",
"...args\t\n\t\t\n, b",
"a, ... args, \n \n b",
"a, a, ...args",
"a,\ta, ...args",
"a,\ra, ...args",
"a,\na, ...args",
NULL};
static const ParserFlag always_flags[] = {kAllowHarmonyRestParameters};
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
TEST(LexicalScopingSloppyMode) { TEST(LexicalScopingSloppyMode) {
const char* context_data[][2] = { const char* context_data[][2] = {
{"", ""}, {"", ""},
......
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