Chromium Code Reviews| Index: src/preparser.h |
| diff --git a/src/preparser.h b/src/preparser.h |
| index a17296349b362df6afefbb5b8538d7c030915270..78f58d60072626a608a9cca31f16133ad2fa8815 100644 |
| --- a/src/preparser.h |
| +++ b/src/preparser.h |
| @@ -563,7 +563,7 @@ class ParserBase : public Traits { |
| ExpressionT ParseRegExpLiteral(bool seen_equal, bool* ok); |
| - ExpressionT ParsePrimaryExpression(bool* ok); |
| + ExpressionT ParsePrimaryExpression(bool maybeArrow, bool* ok); |
| ExpressionT ParseExpression(bool accept_IN, bool* ok); |
| ExpressionT ParseArrayLiteral(bool* ok); |
| ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set, |
| @@ -577,13 +577,15 @@ class ParserBase : public Traits { |
| typename Traits::Type::ExpressionList ParseArguments(bool* ok); |
| ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok); |
| ExpressionT ParseYieldExpression(bool* ok); |
| - ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok); |
| - ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool* ok); |
| - ExpressionT ParseUnaryExpression(bool* ok); |
| - ExpressionT ParsePostfixExpression(bool* ok); |
| - ExpressionT ParseLeftHandSideExpression(bool* ok); |
| - ExpressionT ParseMemberWithNewPrefixesExpression(bool* ok); |
| - ExpressionT ParseMemberExpression(bool* ok); |
| + ExpressionT ParseConditionalExpression(bool accept_IN, bool maybeArrow, |
| + bool* ok); |
| + ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool maybeArrow, |
| + bool* ok); |
| + ExpressionT ParseUnaryExpression(bool maybeArrow, bool* ok); |
| + ExpressionT ParsePostfixExpression(bool maybeArrow, bool* ok); |
| + ExpressionT ParseLeftHandSideExpression(bool maybeArrow, bool* ok); |
| + ExpressionT ParseMemberWithNewPrefixesExpression(bool maybeArrow, bool* ok); |
| + ExpressionT ParseMemberExpression(bool maybeArrow, bool* ok); |
| ExpressionT ParseMemberExpressionContinuation(ExpressionT expression, |
| bool* ok); |
| ExpressionT ParseArrowFunctionLiteral(int start_pos, ExpressionT params_ast, |
| @@ -778,6 +780,11 @@ class PreParserExpression { |
| return PreParserExpression(TypeField::encode(kExpression)); |
| } |
| + static PreParserExpression Spread(PreParserExpression expression) { |
| + return PreParserExpression( |
| + expression.code_ | TypeField::encode(kSpreadExpression)); |
| + } |
| + |
| static PreParserExpression FromIdentifier(PreParserIdentifier id) { |
| return PreParserExpression(TypeField::encode(kIdentifierExpression) | |
| IdentifierTypeField::encode(id.type_)); |
| @@ -789,7 +796,7 @@ class PreParserExpression { |
| bool valid_arrow_param_list = |
| op == Token::COMMA && !left.is_parenthesized() && |
| !right.is_parenthesized() && left.IsValidArrowParams() && |
| - right.IsValidArrowParams(); |
| + right.IsValidArrowParams() && !left.IsSpread(); |
| return PreParserExpression( |
| TypeField::encode(kBinaryOperationExpression) | |
| IsValidArrowParamListField::encode(valid_arrow_param_list)); |
| @@ -922,6 +929,15 @@ class PreParserExpression { |
| : kParanthesizedExpression); |
| } |
| + bool IsSpread() const { |
| + // Is<NodeType> queries other than IsSpread() should always fail |
| + return TypeField::decode(code_) & kSpreadExpression; |
| + } |
| + |
| + PreParserExpression SpreadExpression() const { |
| + return PreParserExpression(code_ & ~TypeField::encode(kSpreadExpression)); |
| + } |
| + |
| // Dummy implementation for making expression->somefunc() work in both Parser |
| // and PreParser. |
| PreParserExpression* operator->() { return this; } |
| @@ -938,7 +954,8 @@ class PreParserExpression { |
| kExpression, |
| kIdentifierExpression, |
| kStringLiteralExpression, |
| - kBinaryOperationExpression |
| + kBinaryOperationExpression, |
| + kSpreadExpression |
| }; |
| enum Parenthesization { |
| @@ -959,13 +976,14 @@ class PreParserExpression { |
| : code_(expression_code) {} |
| V8_INLINE bool IsValidArrowParams() const { |
| - return IsBinaryOperation() |
| - ? IsValidArrowParamListField::decode(code_) |
| - : (IsIdentifier() && AsIdentifier().IsValidArrowParam()); |
| + PreParserExpression e = IsSpread() ? SpreadExpression() : *this; |
| + return e.IsBinaryOperation() |
| + ? IsValidArrowParamListField::decode(e.code_) |
| + : (e.IsIdentifier() && e.AsIdentifier().IsValidArrowParam()); |
| } |
| // The first four bits are for the Type and Parenthesization. |
| - typedef BitField<Type, 0, 2> TypeField; |
| + typedef BitField<Type, 0, 3> TypeField; |
| typedef BitField<Parenthesization, TypeField::kNext, 2> ParenthesizationField; |
| // The rest of the bits are interpreted depending on the value |
| @@ -1150,6 +1168,9 @@ class PreParserFactory { |
| int pos) { |
| return PreParserExpression::Default(); |
| } |
| + PreParserExpression NewSpread(PreParserExpression expression, int pos) { |
| + return PreParserExpression::Spread(expression); |
| + } |
| PreParserExpression NewCountOperation(Token::Value op, |
| bool is_prefix, |
| PreParserExpression expression, |
| @@ -1494,6 +1515,10 @@ class PreParserTraits { |
| bool name_is_strict_reserved, int pos, |
| bool* ok); |
| + PreParserExpression SpreadExpression(PreParserExpression spread) const { |
| + return spread.SpreadExpression(); |
| + } |
| + |
| private: |
| PreParser* pre_parser_; |
| }; |
| @@ -1601,7 +1626,8 @@ class PreParser : public ParserBase<PreParserTraits> { |
| Statement ParseThrowStatement(bool* ok); |
| Statement ParseTryStatement(bool* ok); |
| Statement ParseDebuggerStatement(bool* ok); |
| - Expression ParseConditionalExpression(bool accept_IN, bool* ok); |
| + Expression ParseConditionalExpression(bool accept_IN, bool maybeArrow, |
| + bool* ok); |
| Expression ParseObjectLiteral(bool* ok); |
| Expression ParseV8Intrinsic(bool* ok); |
| @@ -1850,7 +1876,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseRegExpLiteral( |
| template <class Traits> |
| typename ParserBase<Traits>::ExpressionT |
| -ParserBase<Traits>::ParsePrimaryExpression(bool* ok) { |
| +ParserBase<Traits>::ParsePrimaryExpression(bool maybeArrow, bool* ok) { |
| // PrimaryExpression :: |
| // 'this' |
| // 'null' |
| @@ -1976,6 +2002,30 @@ ParserBase<Traits>::ParsePrimaryExpression(bool* ok) { |
| // If we're not allowing special syntax we fall-through to the |
| // default case. |
| + case Token::ELLIPSIS: |
|
arv (Not doing code reviews)
2015/03/11 18:59:13
Beware of fall through here.
|
| + if (maybeArrow && allow_harmony_arrow_functions() && |
| + allow_harmony_rest_params()) { |
| + Consume(Token::ELLIPSIS); |
| + if (!peek_any_identifier()) { |
| + ReportUnexpectedToken(token); |
| + *ok = false; |
| + break; |
| + } |
| + bool is_strict_reserved_name = false; |
| + IdentifierT name = ParseIdentifierOrStrictReservedWord( |
| + &is_strict_reserved_name, CHECK_OK); |
| + if (peek() != Token::RPAREN) { |
| + ReportUnexpectedTokenAt(Scanner::Location(beg_pos, beg_pos + 3), |
| + Token::ELLIPSIS); |
| + *ok = false; |
| + break; |
| + } |
| + result = this->ExpressionFromIdentifier(name, position(), |
| + peek_position(), scope_, |
| + factory()); |
| + return factory()->NewSpread(result, beg_pos); |
| + } |
| + |
| default: { |
| Next(); |
| ReportUnexpectedToken(token); |
| @@ -2345,14 +2395,25 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, bool* ok) { |
| if (fni_ != NULL) fni_->Enter(); |
| ParserBase<Traits>::Checkpoint checkpoint(this); |
| + const bool maybeArrow = |
| + allow_harmony_arrow_functions() && allow_harmony_rest_params(); |
| ExpressionT expression = |
| - this->ParseConditionalExpression(accept_IN, CHECK_OK); |
| + this->ParseConditionalExpression(accept_IN, maybeArrow, CHECK_OK); |
| if (allow_harmony_arrow_functions() && peek() == Token::ARROW) { |
| checkpoint.Restore(); |
| + if (expression->IsSpread() && !expression->is_parenthesized()) { |
| + // TODO(caitp): the error is an unexpected `...`, it would be nice if we |
|
arv (Not doing code reviews)
2015/03/11 18:59:12
Can you store the position before calling ParseCon
|
| + // knew where the `...` occurred. |
| + ReportUnexpectedToken(peek()); |
| + *ok = false; |
| + return this->EmptyExpression(); |
| + } |
| expression = this->ParseArrowFunctionLiteral(lhs_location.beg_pos, |
| expression, CHECK_OK); |
| return expression; |
| + } else if (maybeArrow) { |
| + // TODO(caitp): report an error if an unexpected `...` occurred. |
|
arv (Not doing code reviews)
2015/03/11 18:59:13
Here it would be good to have an ast ;-)
I'm not
|
| } |
| if (!Token::IsAssignmentOp(peek())) { |
| @@ -2448,14 +2509,16 @@ ParserBase<Traits>::ParseYieldExpression(bool* ok) { |
| // Precedence = 3 |
| template <class Traits> |
| typename ParserBase<Traits>::ExpressionT |
| -ParserBase<Traits>::ParseConditionalExpression(bool accept_IN, bool* ok) { |
| +ParserBase<Traits>::ParseConditionalExpression(bool accept_IN, bool maybeArrow, |
| + bool* ok) { |
| // ConditionalExpression :: |
| // LogicalOrExpression |
| // LogicalOrExpression '?' AssignmentExpression ':' AssignmentExpression |
| int pos = peek_position(); |
| // We start using the binary expression parser for prec >= 4 only! |
| - ExpressionT expression = this->ParseBinaryExpression(4, accept_IN, CHECK_OK); |
| + ExpressionT expression = this->ParseBinaryExpression(4, accept_IN, maybeArrow, |
| + CHECK_OK); |
| if (peek() != Token::CONDITIONAL) return expression; |
| Consume(Token::CONDITIONAL); |
| // In parsing the first assignment expression in conditional |
| @@ -2471,16 +2534,20 @@ ParserBase<Traits>::ParseConditionalExpression(bool accept_IN, bool* ok) { |
| // Precedence >= 4 |
| template <class Traits> |
| typename ParserBase<Traits>::ExpressionT |
| -ParserBase<Traits>::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) { |
| +ParserBase<Traits>::ParseBinaryExpression(int prec, bool accept_IN, |
| + bool maybeArrow, bool* ok) { |
| DCHECK(prec >= 4); |
| - ExpressionT x = this->ParseUnaryExpression(CHECK_OK); |
| + ExpressionT x = this->ParseUnaryExpression(maybeArrow, CHECK_OK); |
| for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) { |
| // prec1 >= 4 |
| while (Precedence(peek(), accept_IN) == prec1) { |
| Token::Value op = Next(); |
| Scanner::Location op_location = scanner()->location(); |
| int pos = position(); |
| - ExpressionT y = ParseBinaryExpression(prec1 + 1, accept_IN, CHECK_OK); |
| + // Only allow arrow extensions in binary expressions if op is comma |
| + ExpressionT y = ParseBinaryExpression(prec1 + 1, accept_IN, |
| + maybeArrow && op == Token::COMMA, |
| + CHECK_OK); |
| if (this->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos, |
| factory())) { |
| @@ -2521,7 +2588,7 @@ ParserBase<Traits>::ParseBinaryExpression(int prec, bool accept_IN, bool* ok) { |
| template <class Traits> |
| typename ParserBase<Traits>::ExpressionT |
| -ParserBase<Traits>::ParseUnaryExpression(bool* ok) { |
| +ParserBase<Traits>::ParseUnaryExpression(bool maybeArrow, bool* ok) { |
| // UnaryExpression :: |
| // PostfixExpression |
| // 'delete' UnaryExpression |
| @@ -2538,7 +2605,7 @@ ParserBase<Traits>::ParseUnaryExpression(bool* ok) { |
| if (Token::IsUnaryOp(op)) { |
| op = Next(); |
| int pos = position(); |
| - ExpressionT expression = ParseUnaryExpression(CHECK_OK); |
| + ExpressionT expression = ParseUnaryExpression(false, CHECK_OK); |
| if (op == Token::DELETE && is_strict(language_mode())) { |
| if (is_strong(language_mode())) { |
| @@ -2558,7 +2625,7 @@ ParserBase<Traits>::ParseUnaryExpression(bool* ok) { |
| } else if (Token::IsCountOp(op)) { |
| op = Next(); |
| Scanner::Location lhs_location = scanner()->peek_location(); |
| - ExpressionT expression = this->ParseUnaryExpression(CHECK_OK); |
| + ExpressionT expression = this->ParseUnaryExpression(false, CHECK_OK); |
| expression = this->CheckAndRewriteReferenceExpression( |
| expression, lhs_location, "invalid_lhs_in_prefix_op", CHECK_OK); |
| this->MarkExpressionAsAssigned(expression); |
| @@ -2569,19 +2636,20 @@ ParserBase<Traits>::ParseUnaryExpression(bool* ok) { |
| position()); |
| } else { |
| - return this->ParsePostfixExpression(ok); |
| + return this->ParsePostfixExpression(maybeArrow, ok); |
| } |
| } |
| template <class Traits> |
| typename ParserBase<Traits>::ExpressionT |
| -ParserBase<Traits>::ParsePostfixExpression(bool* ok) { |
| +ParserBase<Traits>::ParsePostfixExpression(bool maybeArrow, bool* ok) { |
| // PostfixExpression :: |
| // LeftHandSideExpression ('++' | '--')? |
| Scanner::Location lhs_location = scanner()->peek_location(); |
| - ExpressionT expression = this->ParseLeftHandSideExpression(CHECK_OK); |
| + ExpressionT expression = this->ParseLeftHandSideExpression(maybeArrow, |
| + CHECK_OK); |
| if (!scanner()->HasAnyLineTerminatorBeforeNext() && |
| Token::IsCountOp(peek())) { |
| expression = this->CheckAndRewriteReferenceExpression( |
| @@ -2601,11 +2669,12 @@ ParserBase<Traits>::ParsePostfixExpression(bool* ok) { |
| template <class Traits> |
| typename ParserBase<Traits>::ExpressionT |
| -ParserBase<Traits>::ParseLeftHandSideExpression(bool* ok) { |
| +ParserBase<Traits>::ParseLeftHandSideExpression(bool maybeArrow, bool* ok) { |
| // LeftHandSideExpression :: |
| // (NewExpression | MemberExpression) ... |
| - ExpressionT result = this->ParseMemberWithNewPrefixesExpression(CHECK_OK); |
| + ExpressionT result = this->ParseMemberWithNewPrefixesExpression( |
| + maybeArrow, CHECK_OK); |
| while (true) { |
| switch (peek()) { |
| @@ -2689,7 +2758,8 @@ ParserBase<Traits>::ParseLeftHandSideExpression(bool* ok) { |
| template <class Traits> |
| typename ParserBase<Traits>::ExpressionT |
| -ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(bool* ok) { |
| +ParserBase<Traits>::ParseMemberWithNewPrefixesExpression( |
| + bool maybeArrow, bool* ok) { |
| // NewExpression :: |
| // ('new')+ MemberExpression |
| @@ -2715,7 +2785,7 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(bool* ok) { |
| const bool is_new = true; |
| result = ParseSuperExpression(is_new, CHECK_OK); |
| } else { |
| - result = this->ParseMemberWithNewPrefixesExpression(CHECK_OK); |
| + result = this->ParseMemberWithNewPrefixesExpression(maybeArrow, CHECK_OK); |
| } |
| if (peek() == Token::LPAREN) { |
| // NewExpression with arguments. |
| @@ -2731,13 +2801,13 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(bool* ok) { |
| new_pos); |
| } |
| // No 'new' or 'super' keyword. |
| - return this->ParseMemberExpression(ok); |
| + return this->ParseMemberExpression(maybeArrow, ok); |
| } |
| template <class Traits> |
| typename ParserBase<Traits>::ExpressionT |
| -ParserBase<Traits>::ParseMemberExpression(bool* ok) { |
| +ParserBase<Traits>::ParseMemberExpression(bool maybeArrow, bool* ok) { |
| // MemberExpression :: |
| // (PrimaryExpression | FunctionLiteral | ClassLiteral) |
| // ('[' Expression ']' | '.' Identifier | Arguments)* |
| @@ -2773,7 +2843,7 @@ ParserBase<Traits>::ParseMemberExpression(bool* ok) { |
| const bool is_new = false; |
| result = ParseSuperExpression(is_new, CHECK_OK); |
| } else { |
| - result = ParsePrimaryExpression(CHECK_OK); |
| + result = ParsePrimaryExpression(maybeArrow, CHECK_OK); |
| } |
| result = ParseMemberExpressionContinuation(result, CHECK_OK); |