Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(290)

Unified Diff: src/parser.cc

Issue 1094653002: Revert "Factor formal argument parsing into ParserBase" (Closed) Base URL: https://chromium.googlesource.com/v8/v8@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/parser.h ('k') | src/preparser.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/parser.cc
diff --git a/src/parser.cc b/src/parser.cc
index 5f794c23c999a740ad1e0f0c9bb2c60286bf8a6e..53aa2ee2462ba2b55f4d150df5118d3a711097cf 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -787,7 +787,16 @@ Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name,
Scope* scope,
AstNodeFactory* factory) {
if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name);
- return scope->NewUnresolved(factory, name, start_position, end_position);
+
+ // Arrow function parameters are parsed as an expression. When
+ // parsing lazily, it is enough to create a VariableProxy in order
+ // for Traits::DeclareArrowParametersFromExpression() to be able to
+ // pick the names of the parameters.
+ return parser_->parsing_lazy_arrow_parameters_
+ ? factory->NewVariableProxy(name, Variable::NORMAL, start_position,
+ end_position)
+ : scope->NewUnresolved(factory, name, start_position,
+ end_position);
}
@@ -852,6 +861,7 @@ Parser::Parser(ParseInfo* info)
target_stack_(NULL),
compile_options_(info->compile_options()),
cached_parse_data_(NULL),
+ parsing_lazy_arrow_parameters_(false),
total_preparse_skipped_(0),
pre_parse_timer_(NULL),
parsing_on_main_thread_(true) {
@@ -1132,40 +1142,27 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
bool ok = true;
if (shared_info->is_arrow()) {
- FormalParameterErrorLocations error_locs;
- bool has_rest = false;
- ZoneList<const AstRawString*>* params;
- if (Check(Token::LPAREN)) {
- // '(' StrictFormalParameters ')'
- params = ParseFormalParameterList(&error_locs, &has_rest, &ok);
- if (ok) ok = Check(Token::RPAREN);
- } else {
- // BindingIdentifier
- params = NewFormalParameterList(1, zone());
- DuplicateFinder* null_duplicate_finder = nullptr;
- const AstRawString* single_param =
- ParseFormalParameter(null_duplicate_finder, &error_locs, &ok);
- if (ok) params->Add(single_param, zone());
- }
-
+ // The first expression being parsed is the parameter list of the arrow
+ // function. Setting this avoids prevents ExpressionFromIdentifier()
+ // from creating unresolved variables in already-resolved scopes.
+ parsing_lazy_arrow_parameters_ = true;
+ Expression* expression = ParseExpression(false, &ok);
if (ok) {
- Expression* expression = ParseArrowFunctionLiteral(
- shared_info->start_position(), params, error_locs, has_rest, &ok);
- if (ok) {
- // Scanning must end at the same position that was recorded
- // previously. If not, parsing has been interrupted due to a stack
- // overflow, at which point the partially parsed arrow function
- // concise body happens to be a valid expression. This is a problem
- // only for arrow functions with single expression bodies, since there
- // is no end token such as "}" for normal functions.
- if (scanner()->location().end_pos == shared_info->end_position()) {
- // The pre-parser saw an arrow function here, so the full parser
- // must produce a FunctionLiteral.
- DCHECK(expression->IsFunctionLiteral());
- result = expression->AsFunctionLiteral();
- } else {
- ok = false;
- }
+ // Scanning must end at the same position that was recorded
+ // previously. If not, parsing has been interrupted due to a
+ // stack overflow, at which point the partially parsed arrow
+ // function concise body happens to be a valid expression. This
+ // is a problem only for arrow functions with single statement
+ // bodies, since there is no end token such as "}" for normal
+ // functions.
+ if (scanner()->location().end_pos == shared_info->end_position()) {
+ // The pre-parser saw an arrow function here, so the full parser
+ // must produce a FunctionLiteral.
+ DCHECK(expression->IsFunctionLiteral());
+ result = expression->AsFunctionLiteral();
+ } else {
+ result = NULL;
+ ok = false;
}
}
} else if (shared_info->is_default_constructor()) {
@@ -3737,141 +3734,77 @@ Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
}
-void ParserTraits::RecordArrowFunctionParameter(
- ZoneList<const AstRawString*>* params, VariableProxy* proxy,
- FormalParameterErrorLocations* error_locs, bool* ok) {
- const AstRawString* raw_name = proxy->raw_name();
- Scanner::Location param_location(proxy->position(),
- proxy->position() + raw_name->length());
-
- if (proxy->is_this()) {
- ReportMessageAt(param_location, "this_formal_parameter");
- *ok = false;
- return;
- }
-
- if (!error_locs->eval_or_arguments.IsValid() && IsEvalOrArguments(raw_name))
- error_locs->eval_or_arguments = param_location;
- if (!error_locs->reserved.IsValid() && IsFutureStrictReserved(raw_name))
- error_locs->reserved = param_location;
- if (!error_locs->undefined.IsValid() && IsUndefined(raw_name))
- error_locs->undefined = param_location;
-
- // TODO(wingo): Fix quadratic check. (Scope::IsDeclaredParameter has the same
- // issue.)
- for (int i = 0; i < params->length(); i++) {
- // Eagerly report the error here; duplicate formal parameter names are never
- // allowed in arrow functions.
- if (raw_name == params->at(i)) {
- ReportMessageAt(param_location,
- "duplicate_arrow_function_formal_parameter");
- *ok = false;
- return;
- }
- }
-
- // When the formal parameter was originally seen, it was parsed as a
- // VariableProxy and recorded as unresolved in the scope. Here we undo that
- // parse-time side-effect.
- parser_->scope_->RemoveUnresolved(proxy);
-
- params->Add(raw_name, parser_->zone());
-}
-
-
-// Arrow function parameter lists are parsed as StrictFormalParameters, which
-// means that they cannot have duplicates. Note that this is a subset of the
-// restrictions placed on parameters to functions whose body is strict.
-ZoneList<const AstRawString*>*
-ParserTraits::ParseArrowFunctionFormalParameterList(
- Expression* params, const Scanner::Location& params_loc,
- FormalParameterErrorLocations* error_locs, bool* is_rest, bool* ok) {
- ZoneList<const AstRawString*>* result =
- NewFormalParameterList(4, parser_->zone());
-
- DCHECK_NOT_NULL(params);
+bool CheckAndDeclareArrowParameter(ParserTraits* traits, Expression* expression,
+ Scope* scope, int* num_params,
+ Scanner::Location* undefined_loc,
+ Scanner::Location* dupe_loc) {
+ // Case for empty parameter lists:
+ // () => ...
+ if (expression == NULL) return true;
// Too many parentheses around expression:
// (( ... )) => ...
- if (params->is_multi_parenthesized()) {
- // TODO(wingo): Make a better message.
- ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
- *ok = false;
- return NULL;
- }
+ if (expression->is_multi_parenthesized()) return false;
- // ArrowFunctionFormals ::
- // VariableProxy
- // Binary(Token::COMMA, ArrowFunctionFormals, VariableProxy)
- //
- // To stay iterative we'll process arguments in right-to-left order, then
- // reverse the list in place.
- //
- // Sadly, for the various malformed_arrow_function_parameter_list errors, we
- // can't be more specific on the error message or on the location because we
- // need to match the pre-parser's behavior.
- while (params->IsBinaryOperation()) {
- BinaryOperation* binop = params->AsBinaryOperation();
- Expression* left = binop->left();
- Expression* right = binop->right();
- if (binop->op() != Token::COMMA) {
- ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
- *ok = false;
- return NULL;
- }
- // RHS of comma expression should be an unparenthesized variable proxy.
- if (right->is_parenthesized() || !right->IsVariableProxy()) {
- ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
- *ok = false;
- return NULL;
+ // Case for a single parameter:
+ // (foo) => ...
+ // foo => ...
+ if (expression->IsVariableProxy()) {
+ if (expression->AsVariableProxy()->is_this()) return false;
+
+ const AstRawString* raw_name = expression->AsVariableProxy()->raw_name();
+ if (traits->IsEvalOrArguments(raw_name) ||
+ traits->IsFutureStrictReserved(raw_name))
+ return false;
+ if (traits->IsUndefined(raw_name) && !undefined_loc->IsValid()) {
+ *undefined_loc = Scanner::Location(
+ expression->position(), expression->position() + raw_name->length());
}
- RecordArrowFunctionParameter(result, right->AsVariableProxy(), error_locs,
- CHECK_OK);
- // LHS of comma expression should be unparenthesized.
- params = left;
- if (params->is_parenthesized()) {
- ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
- *ok = false;
- return NULL;
+ if (scope->IsDeclared(raw_name)) {
+ *dupe_loc = Scanner::Location(
+ expression->position(), expression->position() + raw_name->length());
+ return false;
}
- if (result->length() > Code::kMaxArguments) {
- ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
- *ok = false;
- return NULL;
- }
- }
+ // When the variable was seen, it was recorded as unresolved in the outer
+ // scope. But it's really not unresolved.
+ scope->outer_scope()->RemoveUnresolved(expression->AsVariableProxy());
- if (params->IsVariableProxy()) {
- RecordArrowFunctionParameter(result, params->AsVariableProxy(), error_locs,
- CHECK_OK);
- } else {
- ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
- *ok = false;
- return NULL;
+ scope->DeclareParameter(raw_name, VAR);
+ ++(*num_params);
+ return true;
}
- // Reverse in place.
- std::reverse(result->begin(), result->end());
+ // Case for more than one parameter:
+ // (foo, bar [, ...]) => ...
+ if (expression->IsBinaryOperation()) {
+ BinaryOperation* binop = expression->AsBinaryOperation();
+ if (binop->op() != Token::COMMA || binop->left()->is_parenthesized() ||
+ binop->right()->is_parenthesized())
+ return false;
- return result;
+ return CheckAndDeclareArrowParameter(traits, binop->left(), scope,
+ num_params, undefined_loc, dupe_loc) &&
+ CheckAndDeclareArrowParameter(traits, binop->right(), scope,
+ num_params, undefined_loc, dupe_loc);
+ }
+
+ // Any other kind of expression is not a valid parameter list.
+ return false;
}
-int ParserTraits::DeclareFormalParameters(ZoneList<const AstRawString*>* params,
- Scope* scope, bool has_rest) {
- for (int i = 0; i < params->length(); i++) {
- const AstRawString* param_name = params->at(i);
- int is_rest = has_rest && i == params->length() - 1;
- Variable* var = scope->DeclareParameter(param_name, VAR, is_rest);
- if (is_sloppy(scope->language_mode())) {
- // TODO(sigurds) Mark every parameter as maybe assigned. This is a
- // conservative approximation necessary to account for parameters
- // that are assigned via the arguments array.
- var->set_maybe_assigned();
- }
- }
- return params->length();
+int ParserTraits::DeclareArrowParametersFromExpression(
+ Expression* expression, Scope* scope, Scanner::Location* undefined_loc,
+ Scanner::Location* dupe_loc, bool* ok) {
+ int num_params = 0;
+ // Always reset the flag: It only needs to be set for the first expression
+ // parsed as arrow function parameter list, because only top-level functions
+ // are parsed lazily.
+ parser_->parsing_lazy_arrow_parameters_ = false;
+ *ok = CheckAndDeclareArrowParameter(this, expression, scope, &num_params,
+ undefined_loc, dupe_loc);
+ return num_params;
}
@@ -3970,25 +3903,77 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
function_state.set_generator_object_variable(temp);
}
- FormalParameterErrorLocations error_locs;
- bool has_rest = false;
+ // FormalParameterList ::
+ // '(' (Identifier)*[','] ')'
Expect(Token::LPAREN, CHECK_OK);
- int start_position = scanner()->location().beg_pos;
- ZoneList<const AstRawString*>* params =
- ParseFormalParameterList(&error_locs, &has_rest, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
- int formals_end_position = scanner()->location().end_pos;
+ scope->set_start_position(scanner()->location().beg_pos);
+
+ // We don't yet know if the function will be strict, so we cannot yet
+ // produce errors for parameter names or duplicates. However, we remember
+ // the locations of these errors if they occur and produce the errors later.
+ Scanner::Location eval_args_loc = Scanner::Location::invalid();
+ Scanner::Location dupe_loc = Scanner::Location::invalid();
+ Scanner::Location reserved_loc = Scanner::Location::invalid();
+
+ // Similarly for strong mode.
+ Scanner::Location undefined_loc = Scanner::Location::invalid();
+
+ bool is_rest = false;
+ bool done = arity_restriction == FunctionLiteral::GETTER_ARITY ||
+ (peek() == Token::RPAREN &&
+ arity_restriction != FunctionLiteral::SETTER_ARITY);
+ while (!done) {
+ bool is_strict_reserved = false;
+ is_rest = peek() == Token::ELLIPSIS && allow_harmony_rest_params();
+ if (is_rest) {
+ Consume(Token::ELLIPSIS);
+ }
- CheckArityRestrictions(params->length(), arity_restriction, start_position,
- formals_end_position, CHECK_OK);
+ const AstRawString* param_name =
+ ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
- scope->set_start_position(start_position);
+ // Store locations for possible future error reports.
+ if (!eval_args_loc.IsValid() && IsEvalOrArguments(param_name)) {
+ eval_args_loc = scanner()->location();
+ }
+ if (!undefined_loc.IsValid() && IsUndefined(param_name)) {
+ undefined_loc = scanner()->location();
+ }
+ if (!reserved_loc.IsValid() && is_strict_reserved) {
+ reserved_loc = scanner()->location();
+ }
+ if (!dupe_loc.IsValid() &&
+ scope_->IsDeclaredParameter(param_name)) {
+ duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
+ dupe_loc = scanner()->location();
+ }
- num_parameters = DeclareFormalParameters(params, scope_, has_rest);
- if (error_locs.duplicate.IsValid()) {
- duplicate_parameters = FunctionLiteral::kHasDuplicateParameters;
- }
+ Variable* var = scope_->DeclareParameter(param_name, VAR, is_rest);
+ if (is_sloppy(scope->language_mode())) {
+ // TODO(sigurds) Mark every parameter as maybe assigned. This is a
+ // conservative approximation necessary to account for parameters
+ // that are assigned via the arguments array.
+ var->set_maybe_assigned();
+ }
+ num_parameters++;
+ if (num_parameters > Code::kMaxArguments) {
+ ReportMessage("too_many_parameters");
+ *ok = false;
+ return NULL;
+ }
+ if (arity_restriction == FunctionLiteral::SETTER_ARITY) break;
+ done = (peek() == Token::RPAREN);
+ 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::LBRACE, CHECK_OK);
@@ -4070,9 +4055,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
CheckFunctionName(language_mode(), kind, function_name,
name_is_strict_reserved, function_name_location,
CHECK_OK);
- const bool use_strict_params = has_rest || IsConciseMethod(kind);
- CheckFunctionParameterNames(language_mode(), use_strict_params, error_locs,
- CHECK_OK);
+ const bool use_strict_params = is_rest || IsConciseMethod(kind);
+ CheckFunctionParameterNames(language_mode(), use_strict_params,
+ eval_args_loc, undefined_loc, dupe_loc,
+ reserved_loc, CHECK_OK);
if (is_strict(language_mode())) {
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
« no previous file with comments | « src/parser.h ('k') | src/preparser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698