// ** This class was generated with DemFGen (vers:09/27/2009)

import gen.*;
import edu.neu.ccs.demeterf.lib.*;
import edu.neu.ccs.demeterf.lib.*;
import edu.neu.ccs.demeterf.*;
import edu.neu.ccs.demeterf.lib.*;

import edu.neu.ccs.demeterf.stackless.Continuation;

public class InlineHeapSimplify{
   private Simplify func;
   public InlineHeapSimplify(Simplify f){ func = f; }

   public Exp traverse(Exp _h){
       Continuation base = new Exp_start(_h, new _Hole());
       while(!base.isValue())
           base = base.step();
       return (Exp)(((_Value)base).val);
   }

   class Var_start extends Continuation{
      final Var _parent;
      Var_start(Var that, Continuation l){ super(l); _parent = that; }
      Var_start(Var_start that){ this(that._parent, that.link); }
      public Continuation step(){ return new Var_id(this, func.combine(_parent.getId())); }
   }
   class Var_id extends Var_start{
      final ident id;
      Var_id(Var_id _p){ this(_p, _p.id); }
      Var_id(Var_start _p, ident v){ super(_p); this.id = v; }
      public Continuation step(){
         return link.apply(func.combine((Var)_parent,(ident)id));
      }
    }
   class Sub_start extends Continuation{
      final Sub _parent;
      Sub_start(Sub that, Continuation l){ super(l); _parent = that; }
      Sub_start(Sub_start that){ this(that._parent, that.link); }
      public Continuation step(){
         return link.apply(func.combine((Sub)_parent));
      }
    }
   class Simplify$Zero_start extends Continuation{
      final Simplify.Zero _parent;
      Simplify$Zero_start(Simplify.Zero that, Continuation l){ super(l); _parent = that; }
      Simplify$Zero_start(Simplify$Zero_start that){ this(that._parent, that.link); }
      public Continuation step(){ return new Simplify$Zero_val(this, func.combine(_parent.getVal())); }
   }
   class Simplify$Zero_val extends Simplify$Zero_start{
      final int val;
      Simplify$Zero_val(Simplify$Zero_val _p){ this(_p, _p.val); }
      Simplify$Zero_val(Simplify$Zero_start _p, int v){ super(_p); this.val = v; }
      public Continuation step(){
         return link.apply(func.combine((Num)_parent,(int)val));
      }
    }
   class Oper_start extends Continuation{
      final Oper _parent;
      Oper_start(Oper that, Continuation l){ super(l); _parent = that; }
      public Continuation step(){
         if(_parent instanceof Sub) return new Sub_start((Sub)_parent,link);
         else throw new RuntimeException("Unknown Oper Variant");
      }
   }
   class Num_start extends Continuation{
      final Num _parent;
      Num_start(Num that, Continuation l){ super(l); _parent = that; }
      public Continuation step(){
         if(_parent instanceof Simplify.Zero) return new Simplify$Zero_start((Simplify.Zero)_parent,link);
         else throw new RuntimeException("Unknown Num Variant");
      }
   }
   class Ifz_start extends Continuation{
      final Ifz _parent;
      Ifz_start(Ifz that, Continuation l){ super(l); _parent = that; }
      Ifz_start(Ifz_start that){ this(that._parent, that.link); }
      public Continuation step(){ return new Exp_start(_parent.getCnd(), this); }
      public Continuation apply(Object v){ return new Ifz_cnd(this, (Exp)v); }
   }
   class Ifz_cnd extends Ifz_start{
      final Exp cnd;
      Ifz_cnd(Ifz_cnd _p){ this(_p, _p.cnd); }
      Ifz_cnd(Ifz_start _p, Exp v){ super(_p); this.cnd = v; }
      public Continuation step(){ return new Exp_start(_parent.getThn(), this); }
      public Continuation apply(Object v){ return new Ifz_thn(this, (Exp)v); }
   }
   class Ifz_thn extends Ifz_cnd{
      final Exp thn;
      Ifz_thn(Ifz_thn _p){ this(_p, _p.thn); }
      Ifz_thn(Ifz_cnd _p, Exp v){ super(_p); this.thn = v; }
      public Continuation step(){ return new Exp_start(_parent.getEls(), this); }
      public Continuation apply(Object v){ return new Ifz_els(this, (Exp)v); }
   }
   class Ifz_els extends Ifz_thn{
      final Exp els;
      Ifz_els(Ifz_els _p){ this(_p, _p.els); }
      Ifz_els(Ifz_thn _p, Exp v){ super(_p); this.els = v; }
      public Continuation step(){
         /*[1..1]*/
         if((cnd instanceof Simplify.Zero)){
            return link.apply(func.combine((Ifz)_parent,(Simplify.Zero)cnd, (Exp)thn, (Exp)els));
         }else
         /*[1..1]*/
         if((cnd instanceof Num)){
            return link.apply(func.combine((Ifz)_parent,(Num)cnd, (Exp)thn, (Exp)els));
         }else{
            return link.apply(func.combine((Ifz)_parent,(Exp)cnd, (Exp)thn, (Exp)els));
         }
      }
    }
   class Exp_start extends Continuation{
      final Exp _parent;
      Exp_start(Exp that, Continuation l){ super(l); _parent = that; }
      public Continuation step(){
         if(_parent instanceof Ifz) return new Ifz_start((Ifz)_parent,link);
         if(_parent instanceof Def) return new Def_start((Def)_parent,link);
         if(_parent instanceof Bin) return new Bin_start((Bin)_parent,link);
         if(_parent instanceof Var) return new Var_start((Var)_parent,link);
         if(_parent instanceof Num) return new Num_start((Num)_parent,link);
         else throw new RuntimeException("Unknown Exp Variant");
      }
   }
   class Def_start extends Continuation{
      final Def _parent;
      Def_start(Def that, Continuation l){ super(l); _parent = that; }
      Def_start(Def_start that){ this(that._parent, that.link); }
      public Continuation step(){ return new Def_id(this, func.combine(_parent.getId())); }
   }
   class Def_id extends Def_start{
      final ident id;
      Def_id(Def_id _p){ this(_p, _p.id); }
      Def_id(Def_start _p, ident v){ super(_p); this.id = v; }
      public Continuation step(){ return new Exp_start(_parent.getE(), this); }
      public Continuation apply(Object v){ return new Def_e(this, (Exp)v); }
   }
   class Def_e extends Def_id{
      final Exp e;
      Def_e(Def_e _p){ this(_p, _p.e); }
      Def_e(Def_id _p, Exp v){ super(_p); this.e = v; }
      public Continuation step(){ return new Exp_start(_parent.getBody(), this); }
      public Continuation apply(Object v){ return new Def_body(this, (Exp)v); }
   }
   class Def_body extends Def_e{
      final Exp body;
      Def_body(Def_body _p){ this(_p, _p.body); }
      Def_body(Def_e _p, Exp v){ super(_p); this.body = v; }
      public Continuation step(){
         /*[3..3]*/
         if((body instanceof Num)){
            return link.apply(func.combine((Def)_parent,(ident)id, (Exp)e, (Num)body));
         }else{
            return link.apply(func.combine((Def)_parent,(ident)id, (Exp)e, (Exp)body));
         }
      }
    }
   class Bin_start extends Continuation{
      final Bin _parent;
      Bin_start(Bin that, Continuation l){ super(l); _parent = that; }
      Bin_start(Bin_start that){ this(that._parent, that.link); }
      public Continuation step(){ return new Oper_start(_parent.getOp(), this); }
      public Continuation apply(Object v){ return new Bin_op(this, (Sub)v); }
   }
   class Bin_op extends Bin_start{
      final Sub op;
      Bin_op(Bin_op _p){ this(_p, _p.op); }
      Bin_op(Bin_start _p, Sub v){ super(_p); this.op = v; }
      public Continuation step(){ return new Exp_start(_parent.getLeft(), this); }
      public Continuation apply(Object v){ return new Bin_left(this, (Exp)v); }
   }
   class Bin_left extends Bin_op{
      final Exp left;
      Bin_left(Bin_left _p){ this(_p, _p.left); }
      Bin_left(Bin_op _p, Exp v){ super(_p); this.left = v; }
      public Continuation step(){ return new Exp_start(_parent.getRight(), this); }
      public Continuation apply(Object v){ return new Bin_right(this, (Exp)v); }
   }
   class Bin_right extends Bin_left{
      final Exp right;
      Bin_right(Bin_right _p){ this(_p, _p.right); }
      Bin_right(Bin_left _p, Exp v){ super(_p); this.right = v; }
      public Continuation step(){
      /*[1..1]*/
      if((op instanceof Sub)){
         /*[2..2]*/
         if((left instanceof Num)){
            /*[3..3]*/
             if((right instanceof Num)){
                 if((right instanceof Simplify.Zero)){
                     return link.apply(func.combine((Bin)_parent,(Sub)op, (Num)left, (Simplify.Zero)right));
                 }else{
                     return link.apply(func.combine((Bin)_parent,(Sub)op, (Num)left, (Num)right));
                 }
             }else{
                 return link.apply(func.combine((Bin)_parent,(Oper)op, (Exp)left, (Exp)right));
             }
         }else{
             if((right instanceof Simplify.Zero)){
                 return link.apply(func.combine((Bin)_parent,(Sub)op, (Exp)left, (Simplify.Zero)right));
             }else{
                 return link.apply(func.combine((Bin)_parent,(Oper)op, (Exp)left, (Exp)right));
             }
         }
      }else{
          return link.apply(func.combine((Bin)_parent,(Oper)op, (Exp)left, (Exp)right));
      }
      }
    }
   class _Hole extends Continuation{
       _Hole(){ super(null); link = this; }
       public Continuation step(){ return this; }
       public Continuation apply(Object v){ return new _Value((Exp)v); }
   }
   class _Value extends Continuation{
       final Object val;
       _Value(Object v){ super(null); val = v; }
       public Continuation step(){ return this; }
       public boolean isValue(){ return true; }
   }
}