Commit 9271b0cc authored by wingo's avatar wingo Committed by Commit bot

Parse arrow functions at proper precedence level

BUG=v8:4211
LOG=Y
R=rossberg@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#30298}
parent 6c404625
...@@ -174,6 +174,9 @@ void AstLiteralReindexer::VisitSpread(Spread* node) { ...@@ -174,6 +174,9 @@ void AstLiteralReindexer::VisitSpread(Spread* node) {
} }
void AstLiteralReindexer::VisitEmptyParentheses(EmptyParentheses* node) {}
void AstLiteralReindexer::VisitForInStatement(ForInStatement* node) { void AstLiteralReindexer::VisitForInStatement(ForInStatement* node) {
Visit(node->each()); Visit(node->each());
Visit(node->enumerable()); Visit(node->enumerable());
......
...@@ -371,6 +371,11 @@ void AstNumberingVisitor::VisitSpread(Spread* node) { ...@@ -371,6 +371,11 @@ void AstNumberingVisitor::VisitSpread(Spread* node) {
} }
void AstNumberingVisitor::VisitEmptyParentheses(EmptyParentheses* node) {
UNREACHABLE();
}
void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) { void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) {
IncrementNodeCount(); IncrementNodeCount();
DisableSelfOptimization(); DisableSelfOptimization();
......
...@@ -88,7 +88,8 @@ namespace internal { ...@@ -88,7 +88,8 @@ namespace internal {
V(ThisFunction) \ V(ThisFunction) \
V(SuperPropertyReference) \ V(SuperPropertyReference) \
V(SuperCallReference) \ V(SuperCallReference) \
V(CaseClause) V(CaseClause) \
V(EmptyParentheses)
#define AST_NODE_LIST(V) \ #define AST_NODE_LIST(V) \
DECLARATION_NODE_LIST(V) \ DECLARATION_NODE_LIST(V) \
...@@ -2848,6 +2849,17 @@ class SuperCallReference final : public Expression { ...@@ -2848,6 +2849,17 @@ class SuperCallReference final : public Expression {
}; };
// This class is produced when parsing the () in arrow functions without any
// arguments and is not actually a valid expression.
class EmptyParentheses final : public Expression {
public:
DECLARE_NODE_TYPE(EmptyParentheses)
private:
EmptyParentheses(Zone* zone, int pos) : Expression(zone, pos) {}
};
#undef DECLARE_NODE_TYPE #undef DECLARE_NODE_TYPE
...@@ -3633,6 +3645,10 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3633,6 +3645,10 @@ class AstNodeFactory final BASE_EMBEDDED {
this_function_var, pos); this_function_var, pos);
} }
EmptyParentheses* NewEmptyParentheses(int pos) {
return new (zone_) EmptyParentheses(zone_, pos);
}
private: private:
Zone* zone_; Zone* zone_;
AstValueFactory* ast_value_factory_; AstValueFactory* ast_value_factory_;
......
...@@ -2867,6 +2867,12 @@ void AstGraphBuilder::VisitSpread(Spread* expr) { ...@@ -2867,6 +2867,12 @@ void AstGraphBuilder::VisitSpread(Spread* expr) {
} }
void AstGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) {
// Handled entirely by the parser itself.
UNREACHABLE();
}
void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) { void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) {
Node* value = GetFunctionClosure(); Node* value = GetFunctionClosure();
ast_context()->ProduceValue(value); ast_context()->ProduceValue(value);
......
...@@ -193,6 +193,9 @@ void ALAA::VisitCompareOperation(CompareOperation* e) { ...@@ -193,6 +193,9 @@ void ALAA::VisitCompareOperation(CompareOperation* e) {
void ALAA::VisitSpread(Spread* e) { Visit(e->expression()); } void ALAA::VisitSpread(Spread* e) { Visit(e->expression()); }
void ALAA::VisitEmptyParentheses(EmptyParentheses* e) { UNREACHABLE(); }
void ALAA::VisitCaseClause(CaseClause* cc) { void ALAA::VisitCaseClause(CaseClause* cc) {
if (!cc->is_default()) Visit(cc->label()); if (!cc->is_default()) Visit(cc->label());
VisitStatements(cc->statements()); VisitStatements(cc->statements());
......
...@@ -1400,6 +1400,11 @@ void FullCodeGenerator::ExitTryBlock(int handler_index) { ...@@ -1400,6 +1400,11 @@ void FullCodeGenerator::ExitTryBlock(int handler_index) {
void FullCodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } void FullCodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); }
void FullCodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
UNREACHABLE();
}
FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit( FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
int* stack_depth, int* context_length) { int* stack_depth, int* context_length) {
// The macros used here must preserve the result register. // The macros used here must preserve the result register.
......
...@@ -11525,6 +11525,11 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, ...@@ -11525,6 +11525,11 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
void HOptimizedGraphBuilder::VisitSpread(Spread* expr) { UNREACHABLE(); } void HOptimizedGraphBuilder::VisitSpread(Spread* expr) { UNREACHABLE(); }
void HOptimizedGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) {
UNREACHABLE();
}
HInstruction* HOptimizedGraphBuilder::BuildThisFunction() { HInstruction* HOptimizedGraphBuilder::BuildThisFunction() {
// If we share optimized code between different closures, the // If we share optimized code between different closures, the
// this-function is not a constant, except inside an inlined body. // this-function is not a constant, except inside an inlined body.
......
...@@ -335,6 +335,11 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* node) { ...@@ -335,6 +335,11 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* node) {
void BytecodeGenerator::VisitSpread(Spread* node) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitSpread(Spread* node) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* node) {
UNIMPLEMENTED();
}
void BytecodeGenerator::VisitThisFunction(ThisFunction* node) { void BytecodeGenerator::VisitThisFunction(ThisFunction* node) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
......
...@@ -308,8 +308,6 @@ class CallSite { ...@@ -308,8 +308,6 @@ class CallSite {
T(MalformedArrowFunParamList, "Malformed arrow function parameter list") \ T(MalformedArrowFunParamList, "Malformed arrow function parameter list") \
T(MalformedRegExp, "Invalid regular expression: /%/: %") \ T(MalformedRegExp, "Invalid regular expression: /%/: %") \
T(MalformedRegExpFlags, "Invalid regular expression flags") \ T(MalformedRegExpFlags, "Invalid regular expression flags") \
T(MissingArrow, \
"Expected () to start arrow function, but got '%' instead of '=>'") \
T(ModuleExportUndefined, "Export '%' is not defined in module") \ T(ModuleExportUndefined, "Export '%' is not defined in module") \
T(MultipleDefaultsInSwitch, \ T(MultipleDefaultsInSwitch, \
"More than one default clause in switch statement") \ "More than one default clause in switch statement") \
......
...@@ -3934,6 +3934,8 @@ void ParserTraits::ParseArrowFunctionFormalParameterList( ...@@ -3934,6 +3934,8 @@ void ParserTraits::ParseArrowFunctionFormalParameterList(
ParserFormalParameters* parameters, Expression* expr, ParserFormalParameters* parameters, Expression* expr,
const Scanner::Location& params_loc, const Scanner::Location& params_loc,
Scanner::Location* duplicate_loc, bool* ok) { Scanner::Location* duplicate_loc, bool* ok) {
if (expr->IsEmptyParentheses()) return;
ParseArrowFunctionFormalParameters(parameters, expr, params_loc, ParseArrowFunctionFormalParameters(parameters, expr, params_loc,
duplicate_loc, ok); duplicate_loc, ok);
if (!*ok) return; if (!*ok) return;
......
...@@ -368,6 +368,11 @@ void Parser::PatternRewriter::VisitSpread(Spread* node) { ...@@ -368,6 +368,11 @@ void Parser::PatternRewriter::VisitSpread(Spread* node) {
} }
void Parser::PatternRewriter::VisitEmptyParentheses(EmptyParentheses* node) {
UNREACHABLE();
}
// =============== UNREACHABLE ============================= // =============== UNREACHABLE =============================
void Parser::PatternRewriter::Visit(AstNode* node) { UNREACHABLE(); } void Parser::PatternRewriter::Visit(AstNode* node) { UNREACHABLE(); }
......
...@@ -1308,6 +1308,10 @@ class PreParserFactory { ...@@ -1308,6 +1308,10 @@ class PreParserFactory {
return PreParserExpression::Spread(expression); return PreParserExpression::Spread(expression);
} }
PreParserExpression NewEmptyParentheses(int pos) {
return PreParserExpression::Default();
}
// Return the object itself as AstVisitor and implement the needed // Return the object itself as AstVisitor and implement the needed
// dummy method right in this class. // dummy method right in this class.
PreParserFactory* visitor() { return this; } PreParserFactory* visitor() { return this; }
...@@ -2262,38 +2266,35 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, ...@@ -2262,38 +2266,35 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
} }
BindingPatternUnexpectedToken(classifier); BindingPatternUnexpectedToken(classifier);
Consume(Token::LPAREN); Consume(Token::LPAREN);
if (allow_harmony_arrow_functions() && Check(Token::RPAREN)) { if (Check(Token::RPAREN)) {
// As a primary expression, the only thing that can follow "()" is "=>". // ()=>x. The continuation that looks for the => is in
// ParseAssignmentExpression.
classifier->RecordExpressionError(scanner()->location(),
MessageTemplate::kUnexpectedToken,
Token::String(Token::RPAREN));
classifier->RecordBindingPatternError(scanner()->location(), classifier->RecordBindingPatternError(scanner()->location(),
MessageTemplate::kUnexpectedToken, MessageTemplate::kUnexpectedToken,
Token::String(Token::RPAREN)); Token::String(Token::RPAREN));
// Give a good error to the user who might have typed e.g. "return();". result = factory()->NewEmptyParentheses(beg_pos);
if (peek() != Token::ARROW) { } else if (allow_harmony_rest_parameters() && Check(Token::ELLIPSIS)) {
ReportUnexpectedTokenAt(scanner_->peek_location(), peek(), // (...x)=>x. The continuation that looks for the => is in
MessageTemplate::kMissingArrow); // ParseAssignmentExpression.
int ellipsis_pos = scanner()->location().beg_pos;
classifier->RecordExpressionError(scanner()->location(),
MessageTemplate::kUnexpectedToken,
Token::String(Token::ELLIPSIS));
Scanner::Location expr_loc = scanner()->peek_location();
Token::Value tok = peek();
result = this->ParseAssignmentExpression(true, classifier, CHECK_OK);
// Patterns are not allowed as rest parameters. There is no way we can
// succeed so go ahead and use the convenient ReportUnexpectedToken
// interface.
if (!Traits::IsIdentifier(result)) {
ReportUnexpectedTokenAt(expr_loc, tok);
*ok = false; *ok = false;
return this->EmptyExpression(); return this->EmptyExpression();
} }
Scope* scope = result = factory()->NewSpread(result, ellipsis_pos);
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
FormalParametersT parameters(scope);
scope->set_start_position(beg_pos);
ExpressionClassifier args_classifier;
result = this->ParseArrowFunctionLiteral(parameters, args_classifier,
CHECK_OK);
} else if (allow_harmony_arrow_functions() &&
allow_harmony_rest_parameters() && Check(Token::ELLIPSIS)) {
// (...x) => y
Scope* scope =
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
FormalParametersT formals(scope);
scope->set_start_position(beg_pos);
ExpressionClassifier formals_classifier;
formals.has_rest = true;
this->ParseFormalParameter(&formals, &formals_classifier, CHECK_OK);
Traits::DeclareFormalParameter(
formals.scope, formals.at(0), formals.is_simple,
&formals_classifier);
if (peek() == Token::COMMA) { if (peek() == Token::COMMA) {
ReportMessageAt(scanner()->peek_location(), ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kParamAfterRest); MessageTemplate::kParamAfterRest);
...@@ -2301,8 +2302,6 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, ...@@ -2301,8 +2302,6 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
return this->EmptyExpression(); return this->EmptyExpression();
} }
Expect(Token::RPAREN, CHECK_OK); Expect(Token::RPAREN, CHECK_OK);
result = this->ParseArrowFunctionLiteral(formals, formals_classifier,
CHECK_OK);
} else { } else {
// Heuristically try to detect immediately called functions before // Heuristically try to detect immediately called functions before
// seeing the call parentheses. // seeing the call parentheses.
......
...@@ -360,6 +360,11 @@ void CallPrinter::VisitSpread(Spread* node) { ...@@ -360,6 +360,11 @@ void CallPrinter::VisitSpread(Spread* node) {
} }
void CallPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
UNREACHABLE();
}
void CallPrinter::VisitThisFunction(ThisFunction* node) {} void CallPrinter::VisitThisFunction(ThisFunction* node) {}
...@@ -845,6 +850,11 @@ void PrettyPrinter::VisitSpread(Spread* node) { ...@@ -845,6 +850,11 @@ void PrettyPrinter::VisitSpread(Spread* node) {
} }
void PrettyPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
Print("<empty-parentheses>");
}
void PrettyPrinter::VisitThisFunction(ThisFunction* node) { void PrettyPrinter::VisitThisFunction(ThisFunction* node) {
Print("<this-function>"); Print("<this-function>");
} }
...@@ -1565,6 +1575,11 @@ void AstPrinter::VisitSpread(Spread* node) { ...@@ -1565,6 +1575,11 @@ void AstPrinter::VisitSpread(Spread* node) {
} }
void AstPrinter::VisitEmptyParentheses(EmptyParentheses* node) {
IndentedScope indent(this, "()");
}
void AstPrinter::VisitThisFunction(ThisFunction* node) { void AstPrinter::VisitThisFunction(ThisFunction* node) {
IndentedScope indent(this, "THIS-FUNCTION"); IndentedScope indent(this, "THIS-FUNCTION");
} }
......
...@@ -753,6 +753,11 @@ void AstTyper::VisitCompareOperation(CompareOperation* expr) { ...@@ -753,6 +753,11 @@ void AstTyper::VisitCompareOperation(CompareOperation* expr) {
void AstTyper::VisitSpread(Spread* expr) { RECURSE(Visit(expr->expression())); } void AstTyper::VisitSpread(Spread* expr) { RECURSE(Visit(expr->expression())); }
void AstTyper::VisitEmptyParentheses(EmptyParentheses* expr) {
UNREACHABLE();
}
void AstTyper::VisitThisFunction(ThisFunction* expr) { void AstTyper::VisitThisFunction(ThisFunction* expr) {
} }
......
*%(basename)s:7: SyntaxError: Expected () to start arrow function, but got ';' instead of '=>' *%(basename)s:7: SyntaxError: Unexpected token )
function foo() { return(); } function foo() { return(); }
^ ^
SyntaxError: Expected () to start arrow function, but got ';' instead of '=>' SyntaxError: Unexpected token )
// 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-arrow-functions --harmony-rest-parameters
assertThrows("()=>{}()", SyntaxError);
assertThrows("x=>{}()", SyntaxError);
assertThrows("(...x)=>{}()", SyntaxError);
assertThrows("(x)=>{}()", SyntaxError);
assertThrows("(x,y)=>{}()", SyntaxError);
assertThrows("(x,y,...z)=>{}()", SyntaxError);
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