Index: src/preparser.h |
diff --git a/src/preparser.h b/src/preparser.h |
index 1ade9a7e6ff77becf07be9fb2f7b57a49cb224f4..2b61853b0c35db347cb8d4c970d422a1ed576240 100644 |
--- a/src/preparser.h |
+++ b/src/preparser.h |
@@ -90,6 +90,7 @@ class ParserBase : public Traits { |
allow_harmony_sloppy_(false), |
allow_harmony_computed_property_names_(false), |
allow_harmony_rest_params_(false), |
+ allow_harmony_spreadcalls_(false), |
allow_strong_mode_(false) {} |
// Getters that indicate whether certain syntactical constructs are |
@@ -112,6 +113,7 @@ class ParserBase : public Traits { |
bool allow_harmony_rest_params() const { |
return allow_harmony_rest_params_; |
} |
+ bool allow_harmony_spreadcalls() const { return allow_harmony_spreadcalls_; } |
bool allow_strong_mode() const { return allow_strong_mode_; } |
@@ -143,6 +145,9 @@ class ParserBase : public Traits { |
void set_allow_harmony_rest_params(bool allow) { |
allow_harmony_rest_params_ = allow; |
} |
+ void set_allow_harmony_spreadcalls(bool allow) { |
+ allow_harmony_spreadcalls_ = allow; |
+ } |
void set_allow_strong_mode(bool allow) { allow_strong_mode_ = allow; } |
protected: |
@@ -574,7 +579,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); |
@@ -686,6 +692,7 @@ class ParserBase : public Traits { |
bool allow_harmony_sloppy_; |
bool allow_harmony_computed_property_names_; |
bool allow_harmony_rest_params_; |
+ bool allow_harmony_spreadcalls_; |
bool allow_strong_mode_; |
}; |
@@ -778,6 +785,10 @@ class PreParserExpression { |
return PreParserExpression(TypeField::encode(kExpression)); |
} |
+ static PreParserExpression Spread(PreParserExpression expression) { |
+ return PreParserExpression(TypeField::encode(kSpreadExpression)); |
+ } |
+ |
static PreParserExpression FromIdentifier(PreParserIdentifier id) { |
return PreParserExpression(TypeField::encode(kIdentifierExpression) | |
IdentifierTypeField::encode(id.type_)); |
@@ -906,6 +917,10 @@ class PreParserExpression { |
ExpressionTypeField::decode(code_) == kNoTemplateTagExpression; |
} |
+ bool IsSpreadExpression() const { |
+ return TypeField::decode(code_) == kSpreadExpression; |
+ } |
+ |
PreParserExpression AsFunctionLiteral() { return *this; } |
bool IsBinaryOperation() const { |
@@ -938,7 +953,8 @@ class PreParserExpression { |
kExpression, |
kIdentifierExpression, |
kStringLiteralExpression, |
- kBinaryOperationExpression |
+ kBinaryOperationExpression, |
+ kSpreadExpression |
}; |
enum Parenthesization { |
@@ -964,8 +980,8 @@ class PreParserExpression { |
: (IsIdentifier() && AsIdentifier().IsValidArrowParam()); |
} |
- // The first four bits are for the Type and Parenthesization. |
- typedef BitField<Type, 0, 2> TypeField; |
+ // The first five bits are for the Type and Parenthesization. |
+ typedef BitField<Type, 0, 3> TypeField; |
typedef BitField<Parenthesization, TypeField::kNext, 2> ParenthesizationField; |
// The rest of the bits are interpreted depending on the value |
@@ -1166,6 +1182,12 @@ class PreParserFactory { |
int pos) { |
return PreParserExpression::Default(); |
} |
+ PreParserExpression NewCallRuntime(const AstRawString* name, |
+ const Runtime::Function* function, |
+ PreParserExpressionList arguments, |
+ int pos) { |
+ return PreParserExpression::Default(); |
+ } |
PreParserStatement NewReturnStatement(PreParserExpression expression, |
int pos) { |
return PreParserStatement::Default(); |
@@ -1182,6 +1204,10 @@ class PreParserFactory { |
return PreParserExpression::Default(); |
} |
+ PreParserExpression NewSpread(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; } |
@@ -1494,6 +1520,19 @@ class PreParserTraits { |
bool name_is_strict_reserved, int pos, |
bool* ok); |
+ PreParserExpressionList PrepareSpreadArguments(PreParserExpressionList list) { |
+ return list; |
+ } |
+ |
+ inline void MaterializeUnspreadArgumentsLiterals(int count); |
+ |
+ inline PreParserExpression SpreadCall(PreParserExpression function, |
+ PreParserExpressionList args, int pos); |
+ |
+ inline PreParserExpression SpreadCallNew(PreParserExpression function, |
+ PreParserExpressionList args, |
+ int pos); |
+ |
private: |
PreParser* pre_parser_; |
}; |
@@ -1634,6 +1673,26 @@ void PreParserTraits::MaterializeTemplateCallsiteLiterals() { |
} |
+void PreParserTraits::MaterializeUnspreadArgumentsLiterals(int count) { |
+ for (int i = 0; i < count; ++i) { |
+ pre_parser_->function_state_->NextMaterializedLiteralIndex(); |
+ } |
+} |
+ |
+ |
+PreParserExpression PreParserTraits::SpreadCall(PreParserExpression function, |
+ PreParserExpressionList args, |
+ int pos) { |
+ return pre_parser_->factory()->NewCall(function, args, pos); |
+} |
+ |
+PreParserExpression PreParserTraits::SpreadCallNew(PreParserExpression function, |
+ PreParserExpressionList args, |
+ int pos) { |
+ return pre_parser_->factory()->NewCallNew(function, args, pos); |
+} |
+ |
+ |
PreParserStatementList PreParser::ParseEagerFunctionBody( |
PreParserIdentifier function_name, int pos, Variable* fvar, |
Token::Value fvar_init_op, FunctionKind kind, bool* ok) { |
@@ -2303,18 +2362,42 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseObjectLiteral( |
template <class Traits> |
typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments( |
- bool* ok) { |
+ Scanner::Location* first_spread_arg_loc, bool* ok) { |
// Arguments :: |
// '(' (AssignmentExpression)*[','] ')' |
+ Scanner::Location spread_arg = Scanner::Location::invalid(); |
typename Traits::Type::ExpressionList result = |
this->NewExpressionList(4, zone_); |
Expect(Token::LPAREN, CHECK_OK_CUSTOM(NullExpressionList)); |
bool done = (peek() == Token::RPAREN); |
+ bool was_unspread = false; |
+ int unspread_sequences_count = 0; |
while (!done) { |
+ bool is_spread = allow_harmony_spreadcalls() && (peek() == Token::ELLIPSIS); |
+ int start_pos = peek_position(); |
+ if (is_spread) Consume(Token::ELLIPSIS); |
+ |
ExpressionT argument = this->ParseAssignmentExpression( |
true, CHECK_OK_CUSTOM(NullExpressionList)); |
+ if (is_spread) { |
+ if (!spread_arg.IsValid()) { |
+ spread_arg.beg_pos = start_pos; |
+ spread_arg.end_pos = peek_position(); |
+ } |
+ argument = factory()->NewSpread(argument, start_pos); |
+ } |
result->Add(argument, zone_); |
+ |
+ // unspread_sequences_count is the number of sequences of parameters which |
+ // are not prefixed with a spread '...' operator. |
+ if (is_spread) { |
+ was_unspread = false; |
+ } else if (!was_unspread) { |
+ was_unspread = true; |
+ unspread_sequences_count++; |
+ } |
+ |
if (result->length() > Code::kMaxArguments) { |
ReportMessage("too_many_arguments"); |
*ok = false; |
@@ -2331,6 +2414,15 @@ typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments( |
*ok = false; |
return this->NullExpressionList(); |
} |
+ *first_spread_arg_loc = spread_arg; |
+ |
+ if (spread_arg.IsValid()) { |
+ // Unspread parameter sequences are translated into array literals in the |
+ // parser. Ensure that the number of materialized literals matches between |
+ // the parser and preparser |
+ Traits::MaterializeUnspreadArgumentsLiterals(unspread_sequences_count); |
+ } |
+ |
return result; |
} |
@@ -2645,7 +2737,9 @@ 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. |
@@ -2655,7 +2749,13 @@ ParserBase<Traits>::ParseLeftHandSideExpression(bool* ok) { |
// These calls are marked as potentially direct eval calls. Whether |
// 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()) { |
+ args = Traits::PrepareSpreadArguments(args); |
+ result = Traits::SpreadCall(result, args, pos); |
+ } else { |
+ result = factory()->NewCall(result, args, pos); |
+ } |
if (fni_ != NULL) fni_->RemoveLastFunction(); |
break; |
} |
@@ -2709,9 +2809,16 @@ 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); |
- result = factory()->NewCallNew(result, args, new_pos); |
+ this->ParseArguments(&spread_pos, CHECK_OK); |
+ |
+ if (spread_pos.IsValid()) { |
+ args = Traits::PrepareSpreadArguments(args); |
+ result = Traits::SpreadCallNew(result, args, new_pos); |
+ } else { |
+ result = factory()->NewCallNew(result, args, new_pos); |
+ } |
// The expression can still continue with . or [ after the arguments. |
result = this->ParseMemberExpressionContinuation(result, CHECK_OK); |
return result; |