void AddSeriesVar(Block*, Declaration*);
void AddSeriesInit(Block*, Expression*);

class SeriesBlock : public Block {
    SeriesLabel* start_label();
    SeriesLabel* end_label();
    SeriesBlock(Declaration* output_value);
    void add_var(Declaration*);
    void add_var(Declaration* decl, Expression* init_val)
	{ add_var(decl); add_init_var(decl, init_val); }
    void add_init(Expression*); // Add statement to be done initially.
    void add_init_var(Declaration*decl, Expression init) {
	add_init(?new UnifyExpr(Decl2Ident(decl), init_val)); }
};

// reduce function identity reducee

ReduceExpr::traverse(data)
{
    Declaration* accumulate_decl = Symbol2Declaration(?"accumulator");
    SeriesBlock* bl = new SeriesBlock(accumulate_decl);
//    AddSeriesVar(bl, accumulate_decl); // should be automatic?
    bl->add_init(bl, new UnifyExpr(? accumulate_decl, identity));
    Declaration* val = reducee->expand_series(bl, data);
    st = [[accumulate_decl := accumulare_decl function val]];
    AddSeriesBody(bl, val);
    return bl;
}

// An expression guaranteed to evaluate to a Vector.

Declaration* VectorExpr::expand_series(SeriesBlock*bl, TraverseData* data)
{
    Declaration* index_decl = Symbol2Declaration(?"i");
    bl->add_var(index_decl, DoQuote(Zero));
    Declaration* vector_decl = Symbol2Declaration(?"v");
    bl->add_var(vector_decl, [[this]]); // Maybe do a traverse first.
    bl->add_var(length_decl, [[size vector_decl]]);
    bl->add_body([[if index_decl >= vector_decl => goto bl->end_label()]]);
    Declaration* element_decl = Symbol2Declaration(?"x");
    bl->add_var(element_decl);
    bl->add_body([[element_decl := vector_decl[index_decl++]]]);
    return element_decl;
}

Declaration* ListConsExpr::expand_series(SeriesBlock*bl, TraverseData* data)
{
    Declaration* index0_decl = Symbol2Declaration(?"i0");
    Declaration* index1_decl = Symbol2Declaration(?"i1");
    Declaration* old_decl = Symbol2Declaration(?"i1");
    bl->add_var(index0_decl, DoQuote(Zero));
    bl->add_var(index1_decl, DoQuote(Zero));
    bl->add_var(old_decl, DoQuote(NullSequence));
  body: [[
	L:
	  if index1 < size old
	      val = old[index1++];
	  else {
	      if (index0 >= length)
		  goto bl->end_label();
	      switch (index0) {
		case 0: val := eval exp10; break;
			...
			}
	      index0++;
	      if (val is a Tuple) {
		  old@ = val;
		  index1 = 0;
		  goto L;
	      }
	  }
     ]]
}
