Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index b7bead792f3db8df128955cc896997d4b5a88520..c73b6d841cdb41a5d8d0fcf1db725d9997db0c5d 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,37 @@ 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 |
+ ParseFormalParameter(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 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,79 +3732,103 @@ Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) { |
} |
-bool CheckAndDeclareArrowParameter(ParserTraits* traits, Expression* expression, |
- Scope* scope, int* num_params, |
- FormalParameterErrorLocations* locs) { |
- // 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) && !locs->undefined.IsValid()) { |
- locs->undefined = 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; |
} |
- |
- // 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()); |
- |
- bool is_rest = false; |
- bool is_duplicate = false; |
- scope->DeclareParameter(raw_name, VAR, is_rest, &is_duplicate); |
- if (is_duplicate) { |
- locs->duplicate = 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; |
+ } |
- ++(*num_params); |
- return true; |
+ // TODO(wingo): Support rest parameters. |
+ if (!expr->IsVariableProxy()) { |
+ ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list"); |
+ *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; |
+ const AstRawString* raw_name = expr->AsVariableProxy()->raw_name(); |
+ Scanner::Location param_location(expr->position(), |
+ expr->position() + raw_name->length()); |
- return CheckAndDeclareArrowParameter(traits, binop->left(), scope, |
- num_params, locs) && |
- CheckAndDeclareArrowParameter(traits, binop->right(), scope, |
- num_params, locs); |
+ if (expr->AsVariableProxy()->is_this()) { |
+ ReportMessageAt(param_location, "this_formal_parameter"); |
+ *ok = false; |
+ return; |
} |
- // Any other kind of expression is not a valid parameter list. |
- 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; |
+ |
+ // 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; |
+ bool is_duplicate = DeclareFormalParameter(scope, raw_name, is_rest); |
+ |
+ if (is_duplicate) { |
+ // 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. |
+ ReportMessageAt(param_location, |
+ "duplicate_arrow_function_formal_parameter"); |
+ *ok = false; |
+ return; |
+ } |
} |
-int ParserTraits::DeclareArrowParametersFromExpression( |
- Expression* expression, Scope* scope, FormalParameterErrorLocations* locs, |
- 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, locs); |
- 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); |
} |