/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- 
 * $Id: OPlist.java,v 1.2 2000/09/09 19:51:48 metlov Exp $
 *
 * This file is part of the Java Expressions Library (JEL).
 *   For more information about JEL visit :
 *    http://galaxy.fzu.cz/JEL/
 *
 * (c) 1998 by Konstantin Metlov(metlov@fzu.cz);
 *
 * JEL is Distributed under the terms of GNU General Public License.
 *    This code comes with ABSOLUTELY NO WARRANTY.
 *  For license details see COPYING file in this directory.
 */

package gnu.jel;

import gnu.jel.debug.Debug;
import java.util.Stack;

public class OPlist extends OP {
  
  protected int size=0;
  
  public int size() {return size;}; 
  
  public OP getFirst() {
    if (Debug.enabled)
      Debug.assert(size>0,"First in empty list.");
    return next;
  };

  public OP getLast()  {
    if (Debug.enabled)
      Debug.assert(size>0,"Last in empty list.");
    return prev;
  };

  public void addFirst(OP o) {
    o.prev=null; o.next=null;
    if (next!=null) { o.next=next; next.prev=o; };
    next=o;
    if (prev==null) prev=o; // if only, its the last
    size++;
  };
  
  public void addLast(OP o) {
    o.prev=null; o.next=null;
    if (prev!=null) { o.prev=prev; prev.next=o; };
    prev=o;
    if (next==null) next=o;  // if first
    size++;
  };
  
  public void addBefore(OP e, OP ne) {
    if (e==next) {
      addFirst(ne);
      return;
    };
    ne.prev=e.prev;
    ne.next=e;
    e.prev.next=ne;
    e.prev=ne;
    size++;
  };

  public void addAfter(OP e, OP ne) {
    if (e.next!=null)
      addBefore(e.next,ne);
    else
      addLast(ne);
  };
  
  public void remove(OP o) {
    if (o.prev!=null) o.prev.next=o.next; else this.next=o.next;
    if (o.next!=null) o.next.prev=o.prev; else this.prev=o.prev;
    o.next=null; o.prev=null; // help GC
    size--;
  };

  
  public void performCF() {
    OP curr=next;
    while(curr!=null) {
      OP ncurr=curr.next;
      if (curr instanceof OPfunction)
        ((OPfunction)curr).eval(this); 
      curr=ncurr;
    };
  };

  private static OP skip(OP op) {
    if (op instanceof OPfunction) {
      OP cop=op.prev;
      int nparams=((OPfunction) op).getNParams();
      for(int i=0;i<nparams;i++) cop=skip(cop);
      return cop;
    } else return op.prev;
  };

  private static void compileFunc(ClassFile cf, OPfunction opf) {
    opf.compile_pre(cf);
    compileParams(cf,opf,opf.prev,opf.getNParams());
    opf.compile(cf);
  };

  private static void compileParams(ClassFile cf, OPfunction opf,
                                    OP op,int nparams) {
    if (nparams==0) return;
    
    compileParams(cf,opf,skip(op),nparams-1);
    
    if (op instanceof OPfunction)
      compileFunc(cf,(OPfunction) op);
    else 
      op.compile(cf);
    
    opf.compile_par(cf, nparams);
  };  

  public void compile(ClassFile cf) {
    if (prev instanceof OPfunction)
      compileFunc(cf,(OPfunction) prev);
    else {
      if (Debug.enabled)
        Debug.assert(size()==1);
      prev.compile(cf);
    };
  };
  
  public String toString() {
    OP curr=next;
    StringBuffer res=new StringBuffer();
    while (curr!=null) {
      res.append(curr.toString());
      curr=curr.next;
      if (curr!=null) res.append(' ');
    };
    return res.toString();
  };
};
