Commit 9c00c889 authored by adamk's avatar adamk Committed by Commit bot

Remove duplicated code from comma-separated Expression parsing

This removes two bits of duplication:
  - Parsing of each AssignmentExpression, which previously was called
    first outside the loop and then inside the loop.
  - Parsing of arrow rest parameters, which previously was handled
    separately for the one-arg and N-arg cases.

The only change in behavior is in a few error messages.

Review-Url: https://codereview.chromium.org/2279363002
Cr-Commit-Position: refs/heads/master@{#39030}
parent b9810ba0
...@@ -550,8 +550,6 @@ class ErrorUtils : public AllStatic { ...@@ -550,8 +550,6 @@ class ErrorUtils : public AllStatic {
T(NoCatchOrFinally, "Missing catch or finally after try") \ T(NoCatchOrFinally, "Missing catch or finally after try") \
T(NotIsvar, "builtin %%IS_VAR: not a variable") \ T(NotIsvar, "builtin %%IS_VAR: not a variable") \
T(ParamAfterRest, "Rest parameter must be last formal parameter") \ T(ParamAfterRest, "Rest parameter must be last formal parameter") \
T(InvalidRestParameter, \
"Rest parameter must be an identifier or destructuring pattern") \
T(PushPastSafeLength, \ T(PushPastSafeLength, \
"Pushing % elements on an array-like of length % " \ "Pushing % elements on an array-like of length % " \
"is disallowed, as the total surpasses 2**53-1") \ "is disallowed, as the total surpasses 2**53-1") \
......
...@@ -1616,39 +1616,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression( ...@@ -1616,39 +1616,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePrimaryExpression(
MessageTemplate::kUnexpectedToken, MessageTemplate::kUnexpectedToken,
Token::String(Token::RPAREN)); Token::String(Token::RPAREN));
return factory()->NewEmptyParentheses(beg_pos); return factory()->NewEmptyParentheses(beg_pos);
} else if (Check(Token::ELLIPSIS)) {
// (...x)=>x. The continuation that looks for the => is in
// ParseAssignmentExpression.
int ellipsis_pos = position();
int expr_pos = peek_position();
classifier->RecordExpressionError(scanner()->location(),
MessageTemplate::kUnexpectedToken,
Token::String(Token::ELLIPSIS));
classifier->RecordNonSimpleParameter();
ExpressionClassifier binding_classifier(this);
// TODO(adamk): The grammar for this is
// BindingIdentifier | BindingPattern, so
// ParseAssignmentExpression is overkill.
ExpressionT expr =
ParseAssignmentExpression(true, &binding_classifier, CHECK_OK);
// This already couldn't be an expression or a pattern, so the
// only remaining possibility is an arrow formal parameter list.
classifier->Accumulate(
&binding_classifier,
ExpressionClassifier::ArrowFormalParametersProduction);
if (!impl()->IsIdentifier(expr) && !IsValidPattern(expr)) {
classifier->RecordArrowFormalParametersError(
Scanner::Location(ellipsis_pos, scanner()->location().end_pos),
MessageTemplate::kInvalidRestParameter);
}
if (peek() == Token::COMMA) {
impl()->ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kParamAfterRest);
*ok = false;
return impl()->EmptyExpression();
}
Expect(Token::RPAREN, CHECK_OK);
return factory()->NewSpread(expr, ellipsis_pos, expr_pos);
} }
// Heuristically try to detect immediately called functions before // Heuristically try to detect immediately called functions before
// seeing the call parentheses. // seeing the call parentheses.
...@@ -1721,66 +1688,57 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression( ...@@ -1721,66 +1688,57 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseExpression(
// AssignmentExpression // AssignmentExpression
// Expression ',' AssignmentExpression // Expression ',' AssignmentExpression
ExpressionT result; ExpressionT result = impl()->EmptyExpression();
while (true) {
// No need to accumulate binding pattern-related errors, since
// an Expression can't be a binding pattern anyway.
static const unsigned kExpressionProductions =
ExpressionClassifier::AllProductions &
~(ExpressionClassifier::BindingPatternProduction |
ExpressionClassifier::LetPatternProduction);
{
ExpressionClassifier binding_classifier(this);
result =
ParseAssignmentExpression(accept_IN, &binding_classifier, CHECK_OK);
classifier->Accumulate(&binding_classifier, kExpressionProductions);
}
bool is_simple_parameter_list = impl()->IsIdentifier(result);
bool seen_rest = false;
while (peek() == Token::COMMA) {
CheckNoTailCallExpressions(classifier, CHECK_OK); CheckNoTailCallExpressions(classifier, CHECK_OK);
if (seen_rest) { int comma_pos = position();
// At this point the production can't possibly be valid, but we don't know ExpressionClassifier binding_classifier(this);
// which error to signal. ExpressionT right;
if (Check(Token::ELLIPSIS)) {
// 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only
// as the formal parameters of'(x, y, ...z) => foo', and is not itself a
// valid expression.
binding_classifier.RecordExpressionError(
scanner()->location(), MessageTemplate::kUnexpectedToken,
Token::String(Token::ELLIPSIS));
int ellipsis_pos = position();
int pattern_pos = peek_position();
ExpressionT pattern =
ParsePrimaryExpression(&binding_classifier, CHECK_OK);
ValidateBindingPattern(&binding_classifier, CHECK_OK);
right = factory()->NewSpread(pattern, ellipsis_pos, pattern_pos);
} else {
right =
ParseAssignmentExpression(accept_IN, &binding_classifier, CHECK_OK);
}
// No need to accumulate binding pattern-related errors, since
// an Expression can't be a binding pattern anyway.
classifier->Accumulate(
&binding_classifier,
ExpressionClassifier::AllProductions &
~(ExpressionClassifier::BindingPatternProduction |
ExpressionClassifier::LetPatternProduction));
if (!impl()->IsIdentifier(right)) classifier->RecordNonSimpleParameter();
if (impl()->IsEmptyExpression(result)) {
// First time through the loop.
result = right;
} else {
result =
factory()->NewBinaryOperation(Token::COMMA, result, right, comma_pos);
}
if (!Check(Token::COMMA)) break;
if (right->IsSpread()) {
classifier->RecordArrowFormalParametersError( classifier->RecordArrowFormalParametersError(
scanner()->peek_location(), MessageTemplate::kParamAfterRest); scanner()->location(), MessageTemplate::kParamAfterRest);
} }
Consume(Token::COMMA);
bool is_rest = false;
if (allow_harmony_trailing_commas() && peek() == Token::RPAREN && if (allow_harmony_trailing_commas() && peek() == Token::RPAREN &&
PeekAhead() == Token::ARROW) { PeekAhead() == Token::ARROW) {
// a trailing comma is allowed at the end of an arrow parameter list // a trailing comma is allowed at the end of an arrow parameter list
break; break;
} else if (peek() == Token::ELLIPSIS) {
// 'x, y, ...z' in CoverParenthesizedExpressionAndArrowParameterList only
// as the formal parameters of'(x, y, ...z) => foo', and is not itself a
// valid expression or binding pattern.
ExpressionUnexpectedToken(classifier);
BindingPatternUnexpectedToken(classifier);
Consume(Token::ELLIPSIS);
// TODO(adamk): If is_rest is true we don't need to parse an assignment
// expression, the grammar is BindingIdentifier | BindingPattern.
seen_rest = is_rest = true;
} }
int pos = position(), expr_pos = peek_position();
ExpressionClassifier binding_classifier(this);
ExpressionT right =
ParseAssignmentExpression(accept_IN, &binding_classifier, CHECK_OK);
classifier->Accumulate(&binding_classifier, kExpressionProductions);
if (is_rest) {
if (!impl()->IsIdentifier(right) && !IsValidPattern(right)) {
classifier->RecordArrowFormalParametersError(
Scanner::Location(pos, scanner()->location().end_pos),
MessageTemplate::kInvalidRestParameter);
}
right = factory()->NewSpread(right, pos, expr_pos);
}
is_simple_parameter_list =
is_simple_parameter_list && impl()->IsIdentifier(right);
result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
}
if (!is_simple_parameter_list || seen_rest) {
classifier->RecordNonSimpleParameter();
} }
return result; return result;
......
...@@ -881,6 +881,10 @@ class Parser : public ParserBase<Parser> { ...@@ -881,6 +881,10 @@ class Parser : public ParserBase<Parser> {
} }
V8_INLINE static FunctionLiteral* EmptyFunctionLiteral() { return nullptr; } V8_INLINE static FunctionLiteral* EmptyFunctionLiteral() { return nullptr; }
V8_INLINE static bool IsEmptyExpression(Expression* expr) {
return expr == nullptr;
}
// Used in error return values. // Used in error return values.
V8_INLINE static ZoneList<Expression*>* NullExpressionList() { V8_INLINE static ZoneList<Expression*>* NullExpressionList() {
return nullptr; return nullptr;
......
...@@ -123,10 +123,12 @@ class PreParserIdentifier { ...@@ -123,10 +123,12 @@ class PreParserIdentifier {
class PreParserExpression { class PreParserExpression {
public: public:
PreParserExpression() : code_(TypeField::encode(kExpression)) {} PreParserExpression() : code_(TypeField::encode(kEmpty)) {}
static PreParserExpression Empty() { return PreParserExpression(); }
static PreParserExpression Default() { static PreParserExpression Default() {
return PreParserExpression(); return PreParserExpression(TypeField::encode(kExpression));
} }
static PreParserExpression Spread(PreParserExpression expression) { static PreParserExpression Spread(PreParserExpression expression) {
...@@ -206,6 +208,8 @@ class PreParserExpression { ...@@ -206,6 +208,8 @@ class PreParserExpression {
ExpressionTypeField::encode(kNoTemplateTagExpression)); ExpressionTypeField::encode(kNoTemplateTagExpression));
} }
bool IsEmpty() const { return TypeField::decode(code_) == kEmpty; }
bool IsIdentifier() const { bool IsIdentifier() const {
return TypeField::decode(code_) == kIdentifierExpression; return TypeField::decode(code_) == kIdentifierExpression;
} }
...@@ -282,7 +286,7 @@ class PreParserExpression { ...@@ -282,7 +286,7 @@ class PreParserExpression {
ExpressionTypeField::decode(code_) == kNoTemplateTagExpression; ExpressionTypeField::decode(code_) == kNoTemplateTagExpression;
} }
bool IsSpreadExpression() const { bool IsSpread() const {
return TypeField::decode(code_) == kSpreadExpression; return TypeField::decode(code_) == kSpreadExpression;
} }
...@@ -305,6 +309,7 @@ class PreParserExpression { ...@@ -305,6 +309,7 @@ class PreParserExpression {
private: private:
enum Type { enum Type {
kEmpty,
kExpression, kExpression,
kIdentifierExpression, kIdentifierExpression,
kStringLiteralExpression, kStringLiteralExpression,
...@@ -999,7 +1004,7 @@ class PreParser : public ParserBase<PreParser> { ...@@ -999,7 +1004,7 @@ class PreParser : public ParserBase<PreParser> {
return PreParserIdentifier::Default(); return PreParserIdentifier::Default();
} }
V8_INLINE static PreParserExpression EmptyExpression() { V8_INLINE static PreParserExpression EmptyExpression() {
return PreParserExpression::Default(); return PreParserExpression::Empty();
} }
V8_INLINE static PreParserExpression EmptyLiteral() { V8_INLINE static PreParserExpression EmptyLiteral() {
return PreParserExpression::Default(); return PreParserExpression::Default();
...@@ -1011,6 +1016,10 @@ class PreParser : public ParserBase<PreParser> { ...@@ -1011,6 +1016,10 @@ class PreParser : public ParserBase<PreParser> {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
V8_INLINE static bool IsEmptyExpression(PreParserExpression expr) {
return expr.IsEmpty();
}
V8_INLINE static PreParserExpressionList NullExpressionList() { V8_INLINE static PreParserExpressionList NullExpressionList() {
return PreParserExpressionList(); return PreParserExpressionList();
} }
......
*%(basename)s:7: SyntaxError: Rest parameter must be an identifier or destructuring pattern *%(basename)s:7: SyntaxError: Unexpected token =
var f = (a, ...x = 10) => x; var f = (a, ...x = 10) => x;
^^^^^^^^^ ^
SyntaxError: Rest parameter must be an identifier or destructuring pattern SyntaxError: Unexpected token =
*%(basename)s:7: SyntaxError: Rest parameter must be an identifier or destructuring pattern *%(basename)s:7: SyntaxError: Unexpected token =
var f = (...x = 10) => x; var f = (...x = 10) => x;
^^^^^^^^^ ^
SyntaxError: Rest parameter must be an identifier or destructuring pattern SyntaxError: Unexpected token =
...@@ -142,12 +142,6 @@ var SyntaxErrorTests = [ ...@@ -142,12 +142,6 @@ var SyntaxErrorTests = [
{ src: `()=>{ (1, 2, 3, continue f() ) => {} }`, { src: `()=>{ (1, 2, 3, continue f() ) => {} }`,
err: ` ^^^^^^^^^^^^`, err: ` ^^^^^^^^^^^^`,
}, },
{ src: `()=>{ (... continue f()) => {} }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ (a, b, c, ... continue f() ) => {} }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a <= continue f(); }`, { src: `()=>{ return a <= continue f(); }`,
err: ` ^^^^^^^^^^^^`, err: ` ^^^^^^^^^^^^`,
}, },
...@@ -333,6 +327,16 @@ var SyntaxErrorTests = [ ...@@ -333,6 +327,16 @@ var SyntaxErrorTests = [
}, },
], ],
}, },
{ msg: "Unexpected token continue",
tests: [
{ src: `()=>{ (... continue f()) => {} }`,
err: ` ^^^^^^^^`,
},
{ src: `()=>{ (a, b, c, ... continue f() ) => {} }`,
err: ` ^^^^^^^^`,
},
],
},
{ msg: "Undefined label 'foo'", { msg: "Undefined label 'foo'",
tests: [ tests: [
{ src: `()=>{ continue foo () ; }`, { src: `()=>{ continue foo () ; }`,
......
...@@ -136,12 +136,6 @@ var SyntaxErrorTests = [ ...@@ -136,12 +136,6 @@ var SyntaxErrorTests = [
{ src: `()=>{ (1, 2, 3, continue f() ) => {} }`, { src: `()=>{ (1, 2, 3, continue f() ) => {} }`,
err: ` ^^^^^^^^^^^^`, err: ` ^^^^^^^^^^^^`,
}, },
{ src: `()=>{ (... continue f()) => {} }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ (a, b, c, ... continue f() ) => {} }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a <= continue f(); }`, { src: `()=>{ return a <= continue f(); }`,
err: ` ^^^^^^^^^^^^`, err: ` ^^^^^^^^^^^^`,
}, },
...@@ -295,6 +289,16 @@ var SyntaxErrorTests = [ ...@@ -295,6 +289,16 @@ var SyntaxErrorTests = [
}, },
], ],
}, },
{ msg: "Unexpected token continue",
tests: [
{ src: `()=>{ (... continue f()) => {} }`,
err: ` ^^^^^^^^`,
},
{ src: `()=>{ (a, b, c, ... continue f() ) => {} }`,
err: ` ^^^^^^^^`,
},
],
},
{ msg: "Undefined label 'foo'", { msg: "Undefined label 'foo'",
tests: [ tests: [
{ src: `()=>{ continue foo () ; }`, { src: `()=>{ continue foo () ; }`,
......
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