std::string common;
     bool rest(false);
 
-    CYForEach (element, array->elements_) {
-        CYString *string(dynamic_cast<CYString *>(element->value_));
+    for (CYElement *element(array->elements_); element != NULL; ) {
+        CYElementValue *value(dynamic_cast<CYElementValue *>(element));
+        _assert(value != NULL);
+        element = value->next_;
+
+        CYString *string(dynamic_cast<CYString *>(value->value_));
         _assert(string != NULL);
 
         std::string completion;
 
 %type <expression_> ArrowFunction
 %type <functionParameter_> ArrowParameters
 %type <expression_> AssignmentExpression
+%type <expression_> AssignmentExpressionOpt
 %type <identifier_> Binding
 %type <identifier_> BindingIdentifier
 %type <expression_> BitwiseANDExpression
 %type <statement_> Declaration_
 %type <statement_> Declaration
 %type <clause_> DefaultClause
-%type <expression_> Element
-%type <expression_> ElementOpt
 %type <element_> ElementList
 %type <element_> ElementListOpt
 %type <statement_> ElseStatementOpt
     : "[" LexPushInOff ElementListOpt "]" LexPopIn { $$ = CYNew CYArray($3); }
     ;
 
-Element
-    : AssignmentExpression { $$ = $1; }
-    ;
-
-ElementOpt
-    : Element { $$ = $1; }
-    | LexSetRegExp { $$ = NULL; }
-    ;
-
 ElementList
-    : ElementOpt "," ElementListOpt { $$ = CYNew CYElement($1, $3); }
-    | Element { $$ = CYNew CYElement($1, NULL); }
+    : AssignmentExpressionOpt "," ElementListOpt { $$ = CYNew CYElementValue($1, $3); }
+    | LexSetRegExp "..." AssignmentExpression { $$ = CYNew CYElementSpread($3); }
+    | AssignmentExpression { $$ = CYNew CYElementValue($1, NULL); }
     ;
 
 ElementListOpt
     | LeftHandSideExpression "^=" AssignmentExpression { $$ = CYNew CYBitwiseXOrAssign($1, $3); }
     | LeftHandSideExpression "|=" AssignmentExpression { $$ = CYNew CYBitwiseOrAssign($1, $3); }
     ;
+
+AssignmentExpressionOpt
+    : AssignmentExpression { $$ = $1; }
+    | LexSetRegExp { $$ = NULL; }
+    ;
 /* }}} */
 /* 12.15 Comma Operator ( , ) {{{ */
 Expression
 
     out << "while" << ' ' << '(' << *test_ << ')';
 }
 
-void CYElement::Output(CYOutput &out) const {
+void CYElementSpread::Output(CYOutput &out) const {
+    out << "..." << value_;
+}
+
+void CYElementValue::Output(CYOutput &out) const {
     if (value_ != NULL)
         value_->Output(out, CYAssign::Precedence_, CYNoFlags);
     if (next_ != NULL || value_ == NULL) {
         out << ',';
-        if (next_ != NULL && next_->value_ != NULL)
+        if (next_ != NULL && !next_->Elision())
             out << ' ';
     }
     if (next_ != NULL)
 
     virtual void PropertyName(CYOutput &out) const;
 };
 
-struct CYElement;
+struct CYElementValue;
 
 struct CYSpan :
     CYNext<CYSpan>
     {
     }
 
-    CYElement *Replace(CYContext &context);
+    CYElementValue *Replace(CYContext &context);
 };
 
 struct CYTemplate :
 };
 
 struct CYElement :
-    CYNext<CYElement>,
     CYThing
+{
+    virtual bool Elision() const = 0;
+
+    virtual void Replace(CYContext &context) = 0;
+};
+
+struct CYElementValue :
+    CYNext<CYElement>,
+    CYElement
 {
     CYExpression *value_;
 
-    CYElement(CYExpression *value, CYElement *next) :
+    CYElementValue(CYExpression *value, CYElement *next) :
         CYNext<CYElement>(next),
         value_(value)
     {
     }
 
-    void Replace(CYContext &context);
-    void Output(CYOutput &out) const;
+    virtual bool Elision() const {
+        return value_ == NULL;
+    }
+
+    virtual void Replace(CYContext &context);
+    virtual void Output(CYOutput &out) const;
+};
+
+struct CYElementSpread :
+    CYElement
+{
+    CYExpression *value_;
+
+    CYElementSpread(CYExpression *value) :
+        value_(value)
+    {
+    }
+
+    virtual bool Elision() const {
+        return false;
+    }
+
+    virtual void Replace(CYContext &context);
+    virtual void Output(CYOutput &out) const;
 };
 
 struct CYArray :
 
 }
 
 CYExpression *CYArray::Replace(CYContext &context) {
-    elements_->Replace(context);
+    if (elements_ != NULL)
+        elements_->Replace(context);
     return this;
 }
 
     return this;
 }
 
-void CYElement::Replace(CYContext &context) { $T()
+void CYElementSpread::Replace(CYContext &context) {
     context.Replace(value_);
-    next_->Replace(context);
+}
+
+void CYElementValue::Replace(CYContext &context) {
+    context.Replace(value_);
+    if (next_ != NULL)
+        next_->Replace(context);
 }
 
 CYStatement *CYEmpty::Replace(CYContext &context) {
         }
 }
 
-CYElement *CYSpan::Replace(CYContext &context) { $T(NULL)
-    return $ CYElement(expression_, $ CYElement(string_, next_->Replace(context)));
+CYElementValue *CYSpan::Replace(CYContext &context) { $T(NULL)
+    return $ CYElementValue(expression_, $ CYElementValue(string_, next_->Replace(context)));
 }
 
 CYStatement *CYStatement::Return() {
 }
 
 CYExpression *CYTemplate::Replace(CYContext &context) {
-    return $C2($M($M($M($V("String"), $S("prototype")), $S("concat")), $S("apply")), $S(""), $ CYArray($ CYElement(string_, spans_->Replace(context))));
+    return $C2($M($M($M($V("String"), $S("prototype")), $S("concat")), $S("apply")), $S(""), $ CYArray($ CYElementValue(string_, spans_->Replace(context))));
 }
 
 CYExpression *CYThis::Replace(CYContext &context) {