Index: src/preparser.h |
diff --git a/src/preparser.h b/src/preparser.h |
index 4b526f5f1f3c6f039ae730c70b07eccfa8a20444..214478aeb61bb9342f019b1147a5a877b67ee7a2 100644 |
--- a/src/preparser.h |
+++ b/src/preparser.h |
@@ -553,7 +553,8 @@ class ParserBase : public Traits { |
ObjectLiteralCheckerBase* checker, bool in_class, bool has_extends, |
bool is_static, bool* is_computed_name, bool* has_seen_constructor, |
bool* ok); |
- typename Traits::Type::ExpressionList ParseArguments(bool* ok); |
+ typename Traits::Type::ExpressionList ParseArguments( |
+ Scanner::Location* first_spread_pos, bool* ok); |
ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok); |
ExpressionT ParseYieldExpression(bool* ok); |
ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok); |
@@ -578,6 +579,13 @@ class ParserBase : public Traits { |
ExpressionT expression, |
Scanner::Location location, const char* message, bool* ok); |
+ ExpressionT MaybeSpread(ExpressionT expression, bool is_spread, int pos) { |
+ if (is_spread) { |
+ return factory()->NewSpreadOperation(scope_, expression, pos); |
+ } |
+ return expression; |
+ } |
+ |
// Used to validate property names in object literals and class literals |
enum PropertyKind { |
kAccessorProperty, |
@@ -762,6 +770,11 @@ class PreParserExpression { |
return PreParserExpression(TypeField::encode(kExpression)); |
} |
+ static PreParserExpression Spread(PreParserExpression expression) { |
+ DCHECK(!expression.IsSpreadExpression() || expression.is_parenthesized()); |
+ return PreParserExpression(TypeField::encode(kSpreadExpression)); |
+ } |
+ |
static PreParserExpression FromIdentifier(PreParserIdentifier id) { |
return PreParserExpression(TypeField::encode(kIdentifierExpression) | |
IdentifierTypeField::encode(id.type_)); |
@@ -895,6 +908,10 @@ class PreParserExpression { |
ExpressionTypeField::decode(code_) == kNoTemplateTagExpression; |
} |
+ bool IsSpreadExpression() const { |
+ return TypeField::decode(code_) == kSpreadExpression; |
+ } |
+ |
PreParserExpression AsFunctionLiteral() { return *this; } |
bool IsBinaryOperation() const { |
@@ -927,7 +944,8 @@ class PreParserExpression { |
kExpression, |
kIdentifierExpression, |
kStringLiteralExpression, |
- kBinaryOperationExpression |
+ kBinaryOperationExpression, |
+ kSpreadExpression |
}; |
enum Parenthesization { |
@@ -955,7 +973,7 @@ class PreParserExpression { |
} |
// 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 |
@@ -1172,6 +1190,11 @@ class PreParserFactory { |
return PreParserExpression::Default(); |
} |
+ PreParserExpression NewSpreadOperation( |
+ Scope* scope, PreParserExpression expression, int pos) { |
+ return PreParserExpression::Spread(expression); |
+ } |
+ |
// Return the object itself as AstVisitor and implement the needed |
// dummy method right in this class. |
PreParserFactory* visitor() { return this; } |
@@ -1479,6 +1502,8 @@ class PreParserTraits { |
bool name_is_strict_reserved, int pos, |
bool* ok); |
+ static void MarkSpreadCall(PreParserExpression call) {} |
+ |
private: |
PreParser* pre_parser_; |
}; |
@@ -2267,18 +2292,32 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral( |
template <class Traits> |
typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments( |
- bool* ok) { |
+ Scanner::Location* first_spread, bool* ok) { |
// Arguments :: |
// '(' (AssignmentExpression)*[','] ')' |
- |
+ Scanner::Location spread_loc = Scanner::Location::invalid(); |
typename Traits::Type::ExpressionList result = |
this->NewExpressionList(4, zone_); |
Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList)); |
bool done = (peek() == Token::RPAREN); |
while (!done) { |
+ bool is_spread = peek() == Token::ELLIPSIS; |
+ bool first_spread = false; |
+ int spread_pos = -1; |
+ if (is_spread) { |
+ spread_pos = peek_position(); |
+ first_spread = spread_loc.beg_pos < 0; |
+ if (first_spread) { |
+ spread_loc.beg_pos = spread_pos; |
+ } |
+ Consume(Token::ELLIPSIS); |
+ } |
ExpressionT argument = this->ParseAssignmentExpression( |
true, CHECK_OK_CUSTOM(NullExpressionList)); |
- result->Add(argument, zone_); |
+ if (first_spread) { |
+ spread_loc.end_pos = peek_position(); |
+ } |
+ result->Add(MaybeSpread(argument, is_spread, spread_pos), zone_); |
if (result->length() > Code::kMaxArguments) { |
ReportMessage("too_many_arguments"); |
*ok = false; |
@@ -2291,6 +2330,7 @@ typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments( |
} |
} |
Expect(Token::RPAREN, CHECK_OK_CUSTOM(NullExpressionList)); |
+ *first_spread = spread_loc; |
return result; |
} |
@@ -2594,7 +2634,10 @@ ParserBase<Traits>::ParseLeftHandSideExpression(bool* ok) { |
result->AsFunctionLiteral()->set_parenthesized(); |
} |
} |
- typename Traits::Type::ExpressionList args = ParseArguments(CHECK_OK); |
+ |
+ Scanner::Location spread_pos; |
+ typename Traits::Type::ExpressionList args = |
+ ParseArguments(&spread_pos, CHECK_OK); |
// Keep track of eval() calls since they disable all local variable |
// optimizations. |
@@ -2605,6 +2648,9 @@ ParserBase<Traits>::ParseLeftHandSideExpression(bool* ok) { |
// they are actually direct calls to eval is determined at run time. |
this->CheckPossibleEvalCall(result, scope_); |
result = factory()->NewCall(result, args, pos); |
+ if (spread_pos.IsValid()) { |
+ Traits::MarkSpreadCall(result); |
+ } |
if (fni_ != NULL) fni_->RemoveLastFunction(); |
break; |
} |
@@ -2675,8 +2721,17 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(bool* ok) { |
} |
if (peek() == Token::LPAREN) { |
// NewExpression with arguments. |
+ Scanner::Location spread_pos; |
typename Traits::Type::ExpressionList args = |
- this->ParseArguments(CHECK_OK); |
+ this->ParseArguments(&spread_pos, CHECK_OK); |
+ |
+ // TODO(caitp): support spread-calls in CallNew() |
+ if (spread_pos.IsValid()) { |
+ Traits::ReportMessageAt(spread_pos, "spreadcall_construct"); |
+ *ok = false; |
+ return Traits::EmptyExpression(); |
+ } |
+ |
result = factory()->NewCallNew(result, args, new_pos); |
// The expression can still continue with . or [ after the arguments. |
result = this->ParseMemberExpressionContinuation(result, CHECK_OK); |