Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(849)

Unified Diff: src/parsing/parser-base.h

Issue 1928203002: [es8] More spec compliant syntactic tail calls implementation. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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();

Powered by Google App Engine
This is Rietveld 408576698