Chromium Code Reviews| Index: src/parser.cc |
| diff --git a/src/parser.cc b/src/parser.cc |
| index fb52eef56382155d70889fa53efcc74ba8f5a700..fdd6d991d6a303fb7c8ff90182dfa762b364a4d1 100644 |
| --- a/src/parser.cc |
| +++ b/src/parser.cc |
| @@ -787,16 +787,7 @@ Expression* ParserTraits::ExpressionFromIdentifier(const AstRawString* name, |
| Scope* scope, |
| AstNodeFactory* factory) { |
| if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name); |
| - |
| - // 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); |
| + return scope->NewUnresolved(factory, name, start_position, end_position); |
| } |
| @@ -861,7 +852,6 @@ 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) { |
| @@ -1142,27 +1132,40 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info, |
| bool ok = true; |
| if (shared_info->is_arrow()) { |
| - // 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); |
| + Scope* scope = NewScope(scope_, ARROW_SCOPE); |
| + scope->set_start_position(shared_info->start_position()); |
| + FormalParameterErrorLocations error_locs; |
| + bool has_rest = false; |
| + if (Check(Token::LPAREN)) { |
| + // '(' StrictFormalParameters ')' |
| + ParseFormalParameterList(scope, &error_locs, &has_rest, &ok); |
| + if (ok) ok = Check(Token::RPAREN); |
| + } else { |
| + // BindingIdentifier |
| + DuplicateFinder* null_duplicate_finder = nullptr; |
| + const AstRawString* single_param = |
| + ParseFormalParameter(null_duplicate_finder, &error_locs, &ok); |
| + ParserTraits::DeclareFormalParameter(scope, single_param, has_rest); |
| + } |
| + |
| 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 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; |
| + Expression* expression = |
| + ParseArrowFunctionLiteral(scope, 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; |
| + } |
| } |
| } |
| } else if (shared_info->is_default_constructor()) { |
| @@ -3732,77 +3735,102 @@ Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) { |
| } |
| -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 (expression->is_multi_parenthesized()) return false; |
| - |
| - // Case for a single parameter: |
| - // (foo) => ... |
| - // foo => ... |
| - if (expression->IsVariableProxy()) { |
| - if (expression->AsVariableProxy()->is_this()) return false; |
| +void ParserTraits::DeclareArrowFunctionParameters( |
| + Scope* scope, Expression* expr, const Scanner::Location& params_loc, |
| + FormalParameterErrorLocations* error_locs, bool* ok) { |
| + if (scope->num_parameters() >= Code::kMaxArguments) { |
| + ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list"); |
| + *ok = false; |
| + return; |
| + } |
| - 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()); |
| + // ArrowFunctionFormals :: |
| + // Binary(Token::COMMA, ArrowFunctionFormals, VariableProxy) |
| + // VariableProxy |
| + // |
| + // As we need to visit the parameters in left-to-right order, we recurse on |
| + // the left-hand side of comma expressions. |
| + // |
| + // 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. |
| + if (expr->IsBinaryOperation()) { |
| + BinaryOperation* binop = expr->AsBinaryOperation(); |
| + if (binop->op() != Token::COMMA) { |
| + ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list"); |
| + *ok = false; |
| + return; |
| } |
| - if (scope->IsDeclared(raw_name)) { |
| - *dupe_loc = Scanner::Location( |
| - expression->position(), expression->position() + raw_name->length()); |
| - return false; |
| + Expression* left = binop->left(); |
| + Expression* right = binop->right(); |
| + if (left->is_parenthesized() || right->is_parenthesized()) { |
| + ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list"); |
| + *ok = false; |
| + return; |
| } |
| + DeclareArrowFunctionParameters(scope, left, params_loc, error_locs, ok); |
| + if (!*ok) return; |
| + // LHS of comma expression should be unparenthesized. |
| + expr = right; |
| + } |
| - // 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()); |
| + // TODO(wingo): Support rest parameters. |
| + if (!expr->IsVariableProxy()) { |
| + ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list"); |
| + *ok = false; |
| + return; |
| + } |
| - scope->DeclareParameter(raw_name, VAR); |
| - ++(*num_params); |
| - return true; |
| + const AstRawString* raw_name = expr->AsVariableProxy()->raw_name(); |
| + Scanner::Location param_location(expr->position(), |
| + expr->position() + raw_name->length()); |
| + |
| + if (expr->AsVariableProxy()->is_this()) { |
| + ReportMessageAt(param_location, "this_formal_parameter"); |
| + *ok = false; |
| + return; |
| } |
| - // 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; |
| + 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; |
| - return CheckAndDeclareArrowParameter(traits, binop->left(), scope, |
| - num_params, undefined_loc, dupe_loc) && |
| - CheckAndDeclareArrowParameter(traits, binop->right(), scope, |
| - num_params, undefined_loc, dupe_loc); |
| + // 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. |
| + if (scope->IsDeclared(raw_name)) { |
| + ReportMessageAt(param_location, |
| + "duplicate_arrow_function_formal_parameter"); |
| + *ok = false; |
| + return; |
| } |
| - // Any other kind of expression is not a valid parameter list. |
| - return false; |
| + // 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(expr->AsVariableProxy()); |
| + |
| + bool is_rest = false; |
| + scope->DeclareParameter(raw_name, VAR, is_rest); |
| } |
| -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; |
| +void ParserTraits::ParseArrowFunctionFormalParameters( |
| + Scope* scope, Expression* params, const Scanner::Location& params_loc, |
| + FormalParameterErrorLocations* error_locs, bool* is_rest, bool* ok) { |
| + // 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; |
| + } |
| + |
| + DeclareArrowFunctionParameters(scope, params, params_loc, error_locs, ok); |
| } |
| @@ -3901,77 +3929,22 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| function_state.set_generator_object_variable(temp); |
| } |
| - // FormalParameterList :: |
| - // '(' (Identifier)*[','] ')' |
| + FormalParameterErrorLocations error_locs; |
| + bool has_rest = false; |
| Expect(Token::LPAREN, CHECK_OK); |
| - 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); |
| - } |
| - |
| - const AstRawString* param_name = |
| - ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK); |
| - |
| - // 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(); |
| - } |
| + int start_position = scanner()->location().beg_pos; |
| + scope_->set_start_position(start_position); |
| + num_parameters = ParseFormalParameterList(scope, &error_locs, &has_rest, |
| + CHECK_OK); |
| + Expect(Token::RPAREN, CHECK_OK); |
| + int formals_end_position = scanner()->location().end_pos; |
| - 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(); |
| - } |
| + CheckArityRestrictions(num_parameters, arity_restriction, start_position, |
| + formals_end_position, CHECK_OK); |
| - 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); |
| - } |
| + if (error_locs.duplicate.IsValid()) { |
|
marja
2015/04/20 12:31:02
Nit: duplicate_parameters is really far from its u
wingo
2015/04/20 13:26:54
I did so, though I had to move the error_locs decl
|
| + duplicate_parameters = FunctionLiteral::kHasDuplicateParameters; |
| } |
| - Expect(Token::RPAREN, CHECK_OK); |
| Expect(Token::LBRACE, CHECK_OK); |
| @@ -4053,10 +4026,9 @@ FunctionLiteral* Parser::ParseFunctionLiteral( |
| CheckFunctionName(language_mode(), kind, function_name, |
| name_is_strict_reserved, function_name_location, |
| 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); |
| + const bool use_strict_params = has_rest || IsConciseMethod(kind); |
| + CheckFunctionParameterNames(language_mode(), use_strict_params, error_locs, |
| + CHECK_OK); |
| if (is_strict(language_mode())) { |
| CheckStrictOctalLiteral(scope->start_position(), scope->end_position(), |