// $Id: Block.java,v 1.8 2000/06/12 06:50:45 msato Exp $
// $RWC_Release: Omni-1.6 $
// $RWC_Copyright:
//  Omni Compiler Software Version 1.5-1.6
//  Copyright (C) 2002 PC Cluster Consortium
//  
//  This software is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License version
//  2.1 published by the Free Software Foundation.
//  
//  Omni Compiler Software Version 1.0-1.4
//  Copyright (C) 1999, 2000, 2001.
//   Tsukuba Research Center, Real World Computing Partnership, Japan.
//  
//  Please check the Copyright and License information in the files named
//  COPYRIGHT and LICENSE under the top  directory of the Omni Compiler
//  Software release kit.
//  
//  
//  $
package exc.block;
import exc.object.*;

/**
 * abstract class of statement block
 */
public class Block extends PropObject {
  protected static int BlockCounter = 0;
  int id;
  int code;
  BasicBlock bblock;	// for expression

  Block prev,next;	// double linked list in BlockList
  BlockList parent;

  LineNo lineno;	// lineno information

  public Block(int code,BasicBlock bblock){
    this.code = code;
    this.bblock = bblock;
    if(bblock != null) bblock.parent = this;
    id = BlockCounter++;
  }

  public Block(Block b){
    this.code = b.code;
    this.lineno = b.lineno;
    if(b.bblock != null){
      this.bblock = b.bblock.copy();
      this.bblock.parent = this;
    }
    id = BlockCounter++;
  }

  public Block copy() { return new Block(this); }

  public int Opcode() { return code; }
  public int Id() { return id; }
  public BasicBlock getBasicBlock() { return bblock; }
  public Block getNext() { return next; }
  public Block getPrev() { return prev; }
  public BlockList getParent() { return parent; }
  public Block getParentBlock() { 
    return parent == null? null:parent.getParent(); 
  }

  public void setLineNo(LineNo ln){ lineno = ln; }
  public LineNo getLineNo() { return lineno; }

  public String toString(){
    if(code >= Xcode.MAX_CODE) 
      return "Block.<"+code+">#"+id;
    return "Block."+Xcode.getName(code)+"#"+id;
  }

  public void visitBasicBlock(BasicBlockVisitor v){ v.visit(bblock); }
  public void visitBody(BasicBlockVisitor v){ v.visit(getBody()); }

  //
  // abstract member function
  //
  public Xobject toXobject() { fatal("toXobject",this); return null; }
  public BlockList getBody(){ return null; }
  public void setBody(BlockList s) {  fatal("setBody",this); }
  public BasicBlock getCondBBlock() 
  { fatal("getCondBBlock",this); return null; }
  public BlockList getThenBody(){ fatal("getThenBody",this); return null; }
  public BlockList getElseBody(){ fatal("getElseBody",this); return null; }
  public void setThenBody(BlockList s){ fatal("setThenBody",this); }
  public void setElseBody(BlockList s){ fatal("setElseBody",this); }
  public BasicBlock getInitBBlock()
  { fatal("getInitBBlock",this); return null;}
  public BasicBlock getIterBBlock()
  { fatal("getIterBBlock",this); return null; }
  public void setInitBBlock(BasicBlock s){ fatal("setInitBBlock",this); }
  public void setIterBBlock(BasicBlock s){ fatal("setIterBBlock",this); }
  public Xobject getLabel() { fatal("getLabel",this); return null; }
  public void setLabel(Xobject x) { fatal("setLabel",this); }

  public Xobject getInfoExpr() { return null; }
  public void setInfoExpr() { fatal("no InfoExpr"); }

  // add Block
  public Block add(Block s) { 
    s.parent = parent;
    s.next = next;
    next = s;
    s.prev = this;
    if(s.next == null){ // tail of list
      parent.tail = s;
    } else {
      s.next.prev = s;
    }
    return s;
  }
  public Block add(BasicBlock bb){ 
    return add(Bcons.BasicBlock(bb));
  }
  public Block add(Xobject s){
    if(code == Xcode.LIST){
      bblock.add(s);
      return this;
    }
    return add(Bcons.Statement(s));
  }

  public Block insert(Block s){
    s.parent = parent;
    s.prev = prev;
    prev = s;
    s.next = this;
    if(s.prev == null){ // head of list
      parent.head = s;
    } else {
      s.prev.next = s;
    }
    return s;
  }
  public Block insert(BasicBlock bb) { 
    return insert(Bcons.BasicBlock(bb));
  }
  public Block insert(Xobject s){
    if(code == Xcode.LIST){
      bblock.insert(s);
      return this;
    }
    return insert(Bcons.Statement(s));
  }

  public void replace(Block b){
    b.parent = parent;
    b.prev = prev;
    b.next = next;
    if(prev != null) prev.next = b;
    else parent.head = b;
    if(next != null) next.prev = b;
    else parent.tail = b;
  }
    
  // remove block from list
  public Block remove(){
    if(prev != null) prev.next = next;
    else  parent.head = next;
    if(next != null) next.prev = prev;
    else parent.tail = prev;
    parent = null;
    next = null;
    prev = null;
    return this;
  }

  // find Id in this context
  public Ident findIdent(String name){
    BlockList b_list;
    Ident id;
    for(b_list = parent; b_list != null; b_list = b_list.getParentList()){
      if((id = b_list.findLocalIdent(name)) != null) return id;
      if(b_list.getParent() instanceof FunctionBlock){
	return ((FunctionBlock)b_list.getParent()).
	  getFile().findIdent(name);
      }
    }
    return null;	// not found
  }

  static void fatal(String msg,Block b){
    fatal(msg+" at "+b);
  }

  static void fatal(String msg){
    System.err.println("Fatal Block:"+msg);
    Thread.dumpStack();
    System.exit(1);
  }

  public static int numberOfBlock(){
    return Block.BlockCounter;
  }

  public static int numberOfBasicBlock(){
    return BasicBlock.BasicBlockCounter;
  }
}


