| Index: src/parsing/parser-base.h
|
| diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
|
| index da3816f4b9cede5eba9f8a0487826932ffac458b..484d4b977e04c66bd26d3b42d860e00195fd6802 100644
|
| --- a/src/parsing/parser-base.h
|
| +++ b/src/parsing/parser-base.h
|
| @@ -191,19 +191,48 @@ class ParserBase : public Traits {
|
| Scope* scope;
|
| };
|
|
|
| - struct TailCallExpression {
|
| - TailCallExpression(ExpressionT expression, int pos)
|
| - : expression(expression), pos(pos) {}
|
| + class TailCallExpressionList {
|
| + public:
|
| + explicit TailCallExpressionList(Zone* zone)
|
| + : zone_(zone), expressions_(0, zone) {}
|
| +
|
| + const ZoneList<ExpressionT>& expressions() const { return expressions_; }
|
| + const Scanner::Location& location() const { return loc_; }
|
| +
|
| + bool is_empty() const { return expressions_.is_empty(); }
|
| +
|
| + void Swap(TailCallExpressionList& other) {
|
| + expressions_.Swap(&other.expressions_);
|
| + std::swap(loc_, other.loc_);
|
| + }
|
| +
|
| + void Add(ExpressionT expr, const Scanner::Location& loc) {
|
| + if (expressions_.is_empty()) loc_ = loc;
|
| + expressions_.Add(expr, zone_);
|
| + }
|
| +
|
| + void Append(const TailCallExpressionList& other) {
|
| + if (expressions_.is_empty()) loc_ = other.loc_;
|
| + expressions_.AddAll(other.expressions_, zone_);
|
| + }
|
|
|
| - ExpressionT expression;
|
| - int pos;
|
| + private:
|
| + Zone* zone_;
|
| + ZoneList<ExpressionT> expressions_;
|
| + Scanner::Location loc_;
|
| };
|
|
|
| // Defines whether tail call expressions are allowed or not.
|
| enum class ReturnExprContext {
|
| - // Tail call expressions are allowed.
|
| - kNormal,
|
| - // Tail call expressions are not allowed.
|
| + // We are inside return statement which is allowed to contain tail call
|
| + // expressions. Tail call expressions are allowed.
|
| + kInsideValidReturnStatement,
|
| +
|
| + // We are inside a block in which tail call expressions are allowed but
|
| + // not yet inside a return statement.
|
| + kInsideValidBlock,
|
| +
|
| + // Tail call expressions are not allowed in the following blocks.
|
| kInsideTryBlock,
|
| kInsideForInOfBody,
|
| };
|
| @@ -265,12 +294,18 @@ class ParserBase : public Traits {
|
| return destructuring_assignments_to_rewrite_;
|
| }
|
|
|
| - List<TailCallExpression>& expressions_in_tail_position() {
|
| - return expressions_in_tail_position_;
|
| + TailCallExpressionList& tail_call_expressions() {
|
| + return tail_call_expressions_;
|
| }
|
| - void AddExpressionInTailPosition(ExpressionT expression, int pos) {
|
| - if (return_expr_context() == ReturnExprContext::kNormal) {
|
| - expressions_in_tail_position_.Add(TailCallExpression(expression, pos));
|
| + void AddExpressionInTailPosition(ExpressionT expression,
|
| + const Scanner::Location& loc) {
|
| + // If only FLAG_harmony_explicit_tailcalls is enabled then expression
|
| + // must be a Call expression.
|
| + DCHECK(FLAG_harmony_tailcalls || !FLAG_harmony_explicit_tailcalls ||
|
| + expression->IsCall());
|
| + if (return_expr_context() ==
|
| + ReturnExprContext::kInsideValidReturnStatement) {
|
| + tail_call_expressions_.Add(expression, loc);
|
| }
|
| }
|
|
|
| @@ -333,7 +368,7 @@ class ParserBase : public Traits {
|
| Scope* outer_scope_;
|
|
|
| List<DestructuringAssignment> destructuring_assignments_to_rewrite_;
|
| - List<TailCallExpression> expressions_in_tail_position_;
|
| + TailCallExpressionList tail_call_expressions_;
|
| ReturnExprContext return_expr_context_;
|
| ZoneList<ExpressionT> non_patterns_to_rewrite_;
|
|
|
| @@ -359,7 +394,13 @@ class ParserBase : public Traits {
|
| ReturnExprContext return_expr_context)
|
| : function_state_(function_state),
|
| sav_return_expr_context_(function_state->return_expr_context()) {
|
| - function_state->set_return_expr_context(return_expr_context);
|
| + // Don't update context if we are requested to enable tail call
|
| + // expressions but current block does not allow them.
|
| + if (return_expr_context !=
|
| + ReturnExprContext::kInsideValidReturnStatement ||
|
| + sav_return_expr_context_ == ReturnExprContext::kInsideValidBlock) {
|
| + function_state->set_return_expr_context(return_expr_context);
|
| + }
|
| }
|
| ~ReturnExprScope() {
|
| function_state_->set_return_expr_context(sav_return_expr_context_);
|
| @@ -375,17 +416,17 @@ class ParserBase : public Traits {
|
| class CollectExpressionsInTailPositionToListScope {
|
| public:
|
| CollectExpressionsInTailPositionToListScope(FunctionState* function_state,
|
| - List<TailCallExpression>* list)
|
| + TailCallExpressionList* list)
|
| : function_state_(function_state), list_(list) {
|
| - function_state->expressions_in_tail_position().Swap(list_);
|
| + function_state->tail_call_expressions().Swap(*list_);
|
| }
|
| ~CollectExpressionsInTailPositionToListScope() {
|
| - function_state_->expressions_in_tail_position().Swap(list_);
|
| + function_state_->tail_call_expressions().Swap(*list_);
|
| }
|
|
|
| private:
|
| FunctionState* function_state_;
|
| - List<TailCallExpression>* list_;
|
| + TailCallExpressionList* list_;
|
| };
|
|
|
| // Annoyingly, arrow functions first parse as comma expressions, then when we
|
| @@ -643,23 +684,6 @@ class ParserBase : public Traits {
|
| error_type);
|
| }
|
|
|
| - void ReportIllegalTailCallAt(int pos, ReturnExprContext return_expr_context) {
|
| - Scanner::Location loc(pos, pos + 1);
|
| - MessageTemplate::Template msg = MessageTemplate::kNone;
|
| - switch (return_expr_context) {
|
| - case ReturnExprContext::kNormal:
|
| - UNREACHABLE();
|
| - return;
|
| - case ReturnExprContext::kInsideTryBlock:
|
| - msg = MessageTemplate::kTailCallInTryBlock;
|
| - break;
|
| - case ReturnExprContext::kInsideForInOfBody:
|
| - msg = MessageTemplate::kTailCallInForInOf;
|
| - break;
|
| - }
|
| - ReportMessageAt(loc, msg);
|
| - }
|
| -
|
| void GetUnexpectedTokenMessage(
|
| Token::Value token, MessageTemplate::Template* message,
|
| Scanner::Location* location, const char** arg,
|
| @@ -760,6 +784,15 @@ class ParserBase : public Traits {
|
| }
|
| }
|
|
|
| + void CheckNoTailCallExpressions(const ExpressionClassifier* classifier,
|
| + bool* ok) {
|
| + if (FLAG_harmony_explicit_tailcalls &&
|
| + classifier->has_tail_call_expression()) {
|
| + ReportClassifierError(classifier->tail_call_expression_error());
|
| + *ok = false;
|
| + }
|
| + }
|
| +
|
| void ExpressionUnexpectedToken(ExpressionClassifier* classifier) {
|
| MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
|
| const char* arg;
|
| @@ -837,6 +870,8 @@ class ParserBase : public Traits {
|
| bool* ok);
|
| ExpressionT ParseYieldExpression(bool accept_IN,
|
| ExpressionClassifier* classifier, bool* ok);
|
| + ExpressionT ParseTailCallExpression(ExpressionClassifier* classifier,
|
| + bool* ok);
|
| ExpressionT ParseConditionalExpression(bool accept_IN,
|
| ExpressionClassifier* classifier,
|
| bool* ok);
|
| @@ -1013,7 +1048,8 @@ ParserBase<Traits>::FunctionState::FunctionState(
|
| outer_function_state_(*function_state_stack),
|
| scope_stack_(scope_stack),
|
| outer_scope_(*scope_stack),
|
| - return_expr_context_(ReturnExprContext::kNormal),
|
| + tail_call_expressions_(scope->zone()),
|
| + return_expr_context_(ReturnExprContext::kInsideValidBlock),
|
| non_patterns_to_rewrite_(0, scope->zone()),
|
| factory_(factory),
|
| next_function_is_parenthesized_(false),
|
| @@ -1454,7 +1490,6 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
|
| return result;
|
| }
|
|
|
| -
|
| template <class Traits>
|
| typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
|
| bool accept_IN, ExpressionClassifier* classifier, bool* ok) {
|
| @@ -1470,6 +1505,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
|
| bool is_simple_parameter_list = this->IsIdentifier(result);
|
| bool seen_rest = false;
|
| while (peek() == Token::COMMA) {
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| if (seen_rest) {
|
| // At this point the production can't possibly be valid, but we don't know
|
| // which error to signal.
|
| @@ -1533,6 +1569,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
|
| int expr_pos = peek_position();
|
| ExpressionT argument =
|
| this->ParseAssignmentExpression(true, classifier, CHECK_OK);
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| elem = factory()->NewSpread(argument, start_pos, expr_pos);
|
|
|
| if (first_spread_index < 0) {
|
| @@ -1556,6 +1593,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
|
| } else {
|
| int beg_pos = peek_position();
|
| elem = this->ParseAssignmentExpression(true, classifier, CHECK_OK);
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| CheckDestructuringElement(elem, classifier, beg_pos,
|
| scanner()->location().end_pos);
|
| }
|
| @@ -1903,6 +1941,7 @@ typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
|
|
|
| ExpressionT argument = this->ParseAssignmentExpression(
|
| true, classifier, CHECK_OK_CUSTOM(NullExpressionList));
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK_CUSTOM(NullExpressionList));
|
| Traits::RewriteNonPattern(classifier, CHECK_OK_CUSTOM(NullExpressionList));
|
| if (is_spread) {
|
| if (!spread_arg.IsValid()) {
|
| @@ -1961,7 +2000,6 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
| // ArrowFunction
|
| // YieldExpression
|
| // LeftHandSideExpression AssignmentOperator AssignmentExpression
|
| - // TailCallExpression
|
| bool is_destructuring_assignment = false;
|
| int lhs_beg_pos = peek_position();
|
|
|
| @@ -2047,6 +2085,8 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
| // Now pending non-pattern expressions must be discarded.
|
| arrow_formals_classifier.Discard();
|
|
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| +
|
| if (IsValidPattern(expression) && peek() == Token::ASSIGN) {
|
| classifier->ForgiveCoverInitializedNameError();
|
| ValidateAssignmentPattern(classifier, CHECK_OK);
|
| @@ -2071,6 +2111,7 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
|
|
| ExpressionT right =
|
| this->ParseAssignmentExpression(accept_IN, &rhs_classifier, CHECK_OK);
|
| + CheckNoTailCallExpressions(&rhs_classifier, CHECK_OK);
|
| Traits::RewriteNonPattern(&rhs_classifier, CHECK_OK);
|
| classifier->Accumulate(
|
| &rhs_classifier, ExpressionClassifier::ExpressionProductions |
|
| @@ -2170,6 +2211,56 @@ ParserBase<Traits>::ParseYieldExpression(bool accept_IN,
|
| return yield;
|
| }
|
|
|
| +template <class Traits>
|
| +typename ParserBase<Traits>::ExpressionT
|
| +ParserBase<Traits>::ParseTailCallExpression(ExpressionClassifier* classifier,
|
| + bool* ok) {
|
| + // TailCallExpression::
|
| + // 'continue' MemberExpression Arguments
|
| + // 'continue' CallExpression Arguments
|
| + // 'continue' MemberExpression TemplateLiteral
|
| + // 'continue' CallExpression TemplateLiteral
|
| + Expect(Token::CONTINUE, CHECK_OK);
|
| + int pos = position();
|
| + int sub_expression_pos = peek_position();
|
| + ExpressionT expression =
|
| + this->ParseLeftHandSideExpression(classifier, CHECK_OK);
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| +
|
| + Scanner::Location loc(pos, scanner()->location().end_pos);
|
| + ReturnExprContext return_expr_context =
|
| + function_state_->return_expr_context();
|
| + if (return_expr_context != ReturnExprContext::kInsideValidReturnStatement) {
|
| + MessageTemplate::Template msg = MessageTemplate::kNone;
|
| + switch (return_expr_context) {
|
| + case ReturnExprContext::kInsideValidReturnStatement:
|
| + UNREACHABLE();
|
| + return Traits::EmptyExpression();
|
| + case ReturnExprContext::kInsideValidBlock:
|
| + msg = MessageTemplate::kUnexpectedTailCall;
|
| + break;
|
| + case ReturnExprContext::kInsideTryBlock:
|
| + msg = MessageTemplate::kUnexpectedTailCallInTryBlock;
|
| + break;
|
| + case ReturnExprContext::kInsideForInOfBody:
|
| + msg = MessageTemplate::kUnexpectedTailCallInForInOf;
|
| + break;
|
| + }
|
| + ReportMessageAt(loc, msg);
|
| + *ok = false;
|
| + return Traits::EmptyExpression();
|
| + }
|
| + if (!expression->IsCall()) {
|
| + Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
|
| + ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedInsideTailCall);
|
| + *ok = false;
|
| + return Traits::EmptyExpression();
|
| + }
|
| + classifier->RecordTailCallExpressionError(
|
| + loc, MessageTemplate::kUnexpectedTailCall);
|
| + function_state_->AddExpressionInTailPosition(expression, loc);
|
| + return expression;
|
| +}
|
|
|
| // Precedence = 3
|
| template <class Traits>
|
| @@ -2186,6 +2277,7 @@ ParserBase<Traits>::ParseConditionalExpression(bool accept_IN,
|
| ExpressionT expression =
|
| this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK);
|
| if (peek() != Token::CONDITIONAL) return expression;
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| Traits::RewriteNonPattern(classifier, CHECK_OK);
|
| ArrowFormalParametersUnexpectedToken(classifier);
|
| BindingPatternUnexpectedToken(classifier);
|
| @@ -2214,6 +2306,7 @@ ParserBase<Traits>::ParseBinaryExpression(int prec, bool accept_IN,
|
| for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
|
| // prec1 >= 4
|
| while (Precedence(peek(), accept_IN) == prec1) {
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| Traits::RewriteNonPattern(classifier, CHECK_OK);
|
| BindingPatternUnexpectedToken(classifier);
|
| ArrowFormalParametersUnexpectedToken(classifier);
|
| @@ -2224,6 +2317,9 @@ ParserBase<Traits>::ParseBinaryExpression(int prec, bool accept_IN,
|
| const int next_prec = is_right_associative ? prec1 : prec1 + 1;
|
| ExpressionT y =
|
| ParseBinaryExpression(next_prec, accept_IN, classifier, CHECK_OK);
|
| + if (op != Token::OR && op != Token::AND) {
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| + }
|
| Traits::RewriteNonPattern(classifier, CHECK_OK);
|
|
|
| if (this->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos,
|
| @@ -2288,6 +2384,7 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
|
| op = Next();
|
| int pos = position();
|
| ExpressionT expression = ParseUnaryExpression(classifier, CHECK_OK);
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| Traits::RewriteNonPattern(classifier, CHECK_OK);
|
|
|
| if (op == Token::DELETE && is_strict(language_mode())) {
|
| @@ -2313,6 +2410,7 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
|
| op = Next();
|
| int beg_pos = peek_position();
|
| ExpressionT expression = this->ParseUnaryExpression(classifier, CHECK_OK);
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| expression = this->CheckAndRewriteReferenceExpression(
|
| expression, beg_pos, scanner()->location().end_pos,
|
| MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
|
| @@ -2342,6 +2440,7 @@ ParserBase<Traits>::ParsePostfixExpression(ExpressionClassifier* classifier,
|
| this->ParseLeftHandSideExpression(classifier, CHECK_OK);
|
| if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
|
| Token::IsCountOp(peek())) {
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| BindingPatternUnexpectedToken(classifier);
|
| ArrowFormalParametersUnexpectedToken(classifier);
|
|
|
| @@ -2361,7 +2460,6 @@ ParserBase<Traits>::ParsePostfixExpression(ExpressionClassifier* classifier,
|
| return expression;
|
| }
|
|
|
| -
|
| template <class Traits>
|
| typename ParserBase<Traits>::ExpressionT
|
| ParserBase<Traits>::ParseLeftHandSideExpression(
|
| @@ -2369,12 +2467,17 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
| // LeftHandSideExpression ::
|
| // (NewExpression | MemberExpression) ...
|
|
|
| + if (FLAG_harmony_explicit_tailcalls && peek() == Token::CONTINUE) {
|
| + return this->ParseTailCallExpression(classifier, ok);
|
| + }
|
| +
|
| ExpressionT result =
|
| this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK);
|
|
|
| while (true) {
|
| switch (peek()) {
|
| case Token::LBRACK: {
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| Traits::RewriteNonPattern(classifier, CHECK_OK);
|
| BindingPatternUnexpectedToken(classifier);
|
| ArrowFormalParametersUnexpectedToken(classifier);
|
| @@ -2388,6 +2491,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
| }
|
|
|
| case Token::LPAREN: {
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| Traits::RewriteNonPattern(classifier, CHECK_OK);
|
| BindingPatternUnexpectedToken(classifier);
|
| ArrowFormalParametersUnexpectedToken(classifier);
|
| @@ -2446,6 +2550,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
| }
|
|
|
| case Token::PERIOD: {
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| Traits::RewriteNonPattern(classifier, CHECK_OK);
|
| BindingPatternUnexpectedToken(classifier);
|
| ArrowFormalParametersUnexpectedToken(classifier);
|
| @@ -2460,6 +2565,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
|
|
|
| case Token::TEMPLATE_SPAN:
|
| case Token::TEMPLATE_TAIL: {
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| Traits::RewriteNonPattern(classifier, CHECK_OK);
|
| BindingPatternUnexpectedToken(classifier);
|
| ArrowFormalParametersUnexpectedToken(classifier);
|
| @@ -2938,22 +3044,10 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
| // Single-expression body
|
| int pos = position();
|
| ExpressionClassifier classifier(this);
|
| - bool is_tail_call_expression;
|
| - if (FLAG_harmony_explicit_tailcalls) {
|
| - // TODO(ishell): update chapter number.
|
| - // ES8 XX.YY.ZZ
|
| - if (peek() == Token::CONTINUE) {
|
| - Consume(Token::CONTINUE);
|
| - pos = position();
|
| - is_tail_call_expression = true;
|
| - } else {
|
| - is_tail_call_expression = false;
|
| - }
|
| - } else {
|
| - // ES6 14.6.1 Static Semantics: IsInTailPosition
|
| - is_tail_call_expression =
|
| - allow_tailcalls() && !is_sloppy(language_mode());
|
| - }
|
| + DCHECK(ReturnExprContext::kInsideValidBlock ==
|
| + function_state_->return_expr_context());
|
| + ReturnExprScope allow_tail_calls(
|
| + function_state_, ReturnExprContext::kInsideValidReturnStatement);
|
| ExpressionT expression =
|
| ParseAssignmentExpression(accept_IN, &classifier, CHECK_OK);
|
| Traits::RewriteNonPattern(&classifier, CHECK_OK);
|
| @@ -2962,9 +3056,11 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
| body->Add(factory()->NewReturnStatement(expression, pos), zone());
|
| materialized_literal_count = function_state.materialized_literal_count();
|
| expected_property_count = function_state.expected_property_count();
|
| - if (is_tail_call_expression) {
|
| + if (allow_tailcalls() && !is_sloppy(language_mode())) {
|
| + // ES6 14.6.1 Static Semantics: IsInTailPosition
|
| this->MarkTailPosition(expression);
|
| }
|
| + this->MarkCollectedTailCallExpressions();
|
| }
|
| super_loc = function_state.super_location();
|
|
|
| @@ -3063,6 +3159,7 @@ ParserBase<Traits>::ParseTemplateLiteral(ExpressionT tag, int start,
|
|
|
| int expr_pos = peek_position();
|
| ExpressionT expression = this->ParseExpression(true, classifier, CHECK_OK);
|
| + CheckNoTailCallExpressions(classifier, CHECK_OK);
|
| Traits::RewriteNonPattern(classifier, CHECK_OK);
|
| Traits::AddTemplateExpression(&ts, expression);
|
|
|
|
|