//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   19 Jul 06  Brian Frank  Creation
//

**
** Block is a list of zero or more Stmts
**
class Block : Node
{

//////////////////////////////////////////////////////////////////////////
// Construction
//////////////////////////////////////////////////////////////////////////

  new make(Loc loc)
    : super(loc)
  {
    stmts = Stmt[,]
  }

//////////////////////////////////////////////////////////////////////////
// Stmts
//////////////////////////////////////////////////////////////////////////

  **
  ** Return is there are no statements
  **
  Bool isEmpty() { stmts.isEmpty }

  **
  ** Return number of statements
  **
  Int size() { stmts.size }

  **
  ** Does this block always cause us to exit the method (does the
  ** last statement return true for Stmt.isExit)
  **
  Bool isExit()
  {
    if (stmts.isEmpty) return false
    return stmts.last.isExit
  }

  **
  ** Return if any of the statements perform definite assignment.
  **
  Bool isDefiniteAssign(|Expr lhs->Bool| f)
  {
    return stmts.any |Stmt s->Bool| { s.isDefiniteAssign(f) }
  }

  **
  ** Append a statement
  **
  Void add(Stmt stmt)
  {
    stmts.add(stmt)
  }

  **
  ** Append a list of statements
  **
  Void addAll(Stmt[] stmts)
  {
    this.stmts.addAll(stmts)
  }

//////////////////////////////////////////////////////////////////////////
// Tree
//////////////////////////////////////////////////////////////////////////

  Void walkExpr(|Expr expr->Expr| closure)
  {
    walk(ExprVisitor(closure), VisitDepth.expr)
  }

  Void walk(Visitor v, VisitDepth depth)
  {
    v.enterBlock(this)
    copy := Stmt[,]
    copy.capacity = stmts.size
    stmts.each |Stmt stmt|
    {
      r := stmt.walk(v, depth)
      if (r == null) copy.add(stmt)
      else copy.addAll(r)
    }
    stmts = copy
    v.visitBlock(this)
    v.exitBlock(this)
  }

//////////////////////////////////////////////////////////////////////////
// Debug
//////////////////////////////////////////////////////////////////////////

  override Void print(AstWriter out) { printOpt(out) }

  Void printOpt(AstWriter out, Bool braces := true)
  {
    if (braces) out.w("{").nl
    out.indent
    stmts.each |Stmt stmt| { stmt.print(out) }
    out.unindent
    if (braces) out.w("}").nl
  }

//////////////////////////////////////////////////////////////////////////
// Fields
//////////////////////////////////////////////////////////////////////////

  Stmt[] stmts
}