Index: src/parsing/parser-base.h |
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h |
index d273910ced7493d818e2ddd9e9498d776a69b30a..26a947a1e23ab070aaff47b1e057c26bb756cbff 100644 |
--- a/src/parsing/parser-base.h |
+++ b/src/parsing/parser-base.h |
@@ -190,19 +190,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, |
}; |
@@ -264,12 +293,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); |
} |
} |
@@ -332,7 +367,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_; |
@@ -358,7 +393,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_); |
@@ -374,17 +415,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 |
@@ -642,23 +683,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, |
@@ -759,6 +783,15 @@ class ParserBase : public Traits { |
} |
} |
+ void ValidateTailCallExpression(const ExpressionClassifier* classifier, |
+ bool* ok) { |
+ if (FLAG_harmony_explicit_tailcalls && |
+ classifier->has_tail_call_expression()) { |
rossberg
2016/05/02 10:59:40
I'm confused, why is it an error if it _has_ a tai
Igor Sheludko
2016/05/04 10:28:55
Updated confusing function name.
|
+ ReportClassifierError(classifier->tail_call_expression_error()); |
+ *ok = false; |
+ } |
+ } |
+ |
void ExpressionUnexpectedToken(ExpressionClassifier* classifier) { |
MessageTemplate::Template message = MessageTemplate::kUnexpectedToken; |
const char* arg; |
@@ -792,6 +825,8 @@ class ParserBase : public Traits { |
classifier->RecordFormalParameterInitializerError(location, message, arg); |
} |
+ enum AcceptTailCallExpression { kDontAcceptTCE, kAcceptTCE }; |
+ |
// Recursive descent functions: |
// Parses an identifier that is valid for the current scope, in particular it |
@@ -845,6 +880,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); |
@@ -853,7 +890,8 @@ class ParserBase : public Traits { |
ExpressionT ParseUnaryExpression(ExpressionClassifier* classifier, bool* ok); |
ExpressionT ParsePostfixExpression(ExpressionClassifier* classifier, |
bool* ok); |
- ExpressionT ParseLeftHandSideExpression(ExpressionClassifier* classifier, |
+ ExpressionT ParseLeftHandSideExpression(AcceptTailCallExpression accept_TCE, |
+ ExpressionClassifier* classifier, |
bool* ok); |
ExpressionT ParseMemberWithNewPrefixesExpression( |
ExpressionClassifier* classifier, bool* ok); |
@@ -1016,7 +1054,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), |
@@ -1456,7 +1495,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) { |
@@ -1472,6 +1510,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression( |
bool is_simple_parameter_list = this->IsIdentifier(result); |
bool seen_rest = false; |
while (peek() == Token::COMMA) { |
+ ValidateTailCallExpression(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. |
@@ -1963,7 +2002,6 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, |
// ArrowFunction |
// YieldExpression |
// LeftHandSideExpression AssignmentOperator AssignmentExpression |
- // TailCallExpression |
bool is_destructuring_assignment = false; |
int lhs_beg_pos = peek_position(); |
@@ -2164,6 +2202,54 @@ 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(kDontAcceptTCE, classifier, 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> |
@@ -2208,6 +2294,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) { |
+ ValidateTailCallExpression(classifier, CHECK_OK); |
rossberg
2016/05/02 10:59:40
Ah, okay, think I get it now: this is validating t
Igor Sheludko
2016/05/04 10:28:55
Done.
|
Traits::RewriteNonPattern(classifier, CHECK_OK); |
BindingPatternUnexpectedToken(classifier); |
ArrowFormalParametersUnexpectedToken(classifier); |
@@ -2218,6 +2305,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) { |
+ ValidateTailCallExpression(classifier, CHECK_OK); |
+ } |
Traits::RewriteNonPattern(classifier, CHECK_OK); |
if (this->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos, |
@@ -2333,7 +2423,7 @@ ParserBase<Traits>::ParsePostfixExpression(ExpressionClassifier* classifier, |
int lhs_beg_pos = peek_position(); |
ExpressionT expression = |
- this->ParseLeftHandSideExpression(classifier, CHECK_OK); |
+ this->ParseLeftHandSideExpression(kAcceptTCE, classifier, CHECK_OK); |
if (!scanner()->HasAnyLineTerminatorBeforeNext() && |
Token::IsCountOp(peek())) { |
BindingPatternUnexpectedToken(classifier); |
@@ -2355,20 +2445,26 @@ ParserBase<Traits>::ParsePostfixExpression(ExpressionClassifier* classifier, |
return expression; |
} |
- |
template <class Traits> |
typename ParserBase<Traits>::ExpressionT |
ParserBase<Traits>::ParseLeftHandSideExpression( |
- ExpressionClassifier* classifier, bool* ok) { |
+ AcceptTailCallExpression accept_TCE, ExpressionClassifier* classifier, |
+ bool* ok) { |
// LeftHandSideExpression :: |
// (NewExpression | MemberExpression) ... |
+ if (FLAG_harmony_explicit_tailcalls && accept_TCE == kAcceptTCE && |
+ peek() == Token::CONTINUE) { |
+ return this->ParseTailCallExpression(classifier, ok); |
+ } |
+ |
ExpressionT result = |
this->ParseMemberWithNewPrefixesExpression(classifier, CHECK_OK); |
while (true) { |
switch (peek()) { |
case Token::LBRACK: { |
+ ValidateTailCallExpression(classifier, CHECK_OK); |
Traits::RewriteNonPattern(classifier, CHECK_OK); |
BindingPatternUnexpectedToken(classifier); |
ArrowFormalParametersUnexpectedToken(classifier); |
@@ -2382,6 +2478,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression( |
} |
case Token::LPAREN: { |
+ ValidateTailCallExpression(classifier, CHECK_OK); |
Traits::RewriteNonPattern(classifier, CHECK_OK); |
BindingPatternUnexpectedToken(classifier); |
ArrowFormalParametersUnexpectedToken(classifier); |
@@ -2440,6 +2537,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression( |
} |
case Token::PERIOD: { |
+ ValidateTailCallExpression(classifier, CHECK_OK); |
Traits::RewriteNonPattern(classifier, CHECK_OK); |
BindingPatternUnexpectedToken(classifier); |
ArrowFormalParametersUnexpectedToken(classifier); |
@@ -2454,6 +2552,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression( |
case Token::TEMPLATE_SPAN: |
case Token::TEMPLATE_TAIL: { |
+ ValidateTailCallExpression(classifier, CHECK_OK); |
Traits::RewriteNonPattern(classifier, CHECK_OK); |
BindingPatternUnexpectedToken(classifier); |
ArrowFormalParametersUnexpectedToken(classifier); |
@@ -2931,22 +3030,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); |
@@ -2955,9 +3042,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(); |