//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   15 Sep 05  Brian Frank  Creation
//   26 Aug 06  Brian Frank  Ported from Java to Fan
//

**
** Vistor is used to walk the abstract syntax tree and visit key nodes.
** The walk for each node type entails:
**   1. enter
**   2. children
**   3. exit
**   4. visit
**
mixin Visitor
{

//////////////////////////////////////////////////////////////////////////
// Visit
//////////////////////////////////////////////////////////////////////////

  **
  ** Peform a walk of the abstract syntax tree down
  ** to the specified depth.
  **
  Void walk(Compiler c, VisitDepth depth)
  {
    c.types.each |TypeDef def| { def.walk(this, depth) }
  }

//////////////////////////////////////////////////////////////////////////
// CompilationUnit Callbacks
//////////////////////////////////////////////////////////////////////////

  **
  ** Callback when entering a compilation unit.
  **
  virtual Void enterUnit(CompilationUnit unit) {}

  **
  ** Callback when existing a compilation unit.
  **
  virtual Void exitUnit(CompilationUnit unit) {}

//////////////////////////////////////////////////////////////////////////
// TypeDef Callbacks
//////////////////////////////////////////////////////////////////////////

  **
  ** Callback when entering a type definition.
  **
  virtual Void enterTypeDef(TypeDef def) {}

  **
  ** Callback when exiting a type definition.
  **
  virtual Void exitTypeDef(TypeDef def) {}

  **
  ** Callback when visiting a type definition.
  **
  virtual Void visitTypeDef(TypeDef def) {}

//////////////////////////////////////////////////////////////////////////
// FieldDef Callbacks
//////////////////////////////////////////////////////////////////////////

  **
  ** Callback when entering a field definition.
  **
  virtual Void enterFieldDef(FieldDef def) {}

  **
  ** Callback when exiting a field definition.
  **
  virtual Void exitFieldDef(FieldDef def) {}

  **
  ** Callback when visiting a field definition.
  **
  virtual Void visitFieldDef(FieldDef def) {}

//////////////////////////////////////////////////////////////////////////
// MethodDef Callbacks
//////////////////////////////////////////////////////////////////////////

  **
  ** Callback when entering a method.
  **
  virtual Void enterMethodDef(MethodDef def) {}

  **
  ** Callback when exiting a method.
  **
  virtual Void exitMethodDef(MethodDef def) {}

  **
  ** Callback when visiting a method.
  **
  virtual Void visitMethodDef(MethodDef def) {}

//////////////////////////////////////////////////////////////////////////
// Block Callbacks
//////////////////////////////////////////////////////////////////////////

  **
  ** Callback when entering a block.
  **
  virtual Void enterBlock(Block block) {}

  **
  ** Callback when exiting a block.
  **
  virtual Void exitBlock(Block block) {}

  **
  ** Callback when visiting a block.
  **
  virtual Void visitBlock(Block block) {}

//////////////////////////////////////////////////////////////////////////
// Stmt Callbacks
//////////////////////////////////////////////////////////////////////////

  **
  ** Callback when entering a stmt.
  **
  virtual Void enterStmt(Stmt stmt) {}

  **
  ** Callback when exiting a stmt.
  **
  virtual Void exitStmt(Stmt stmt) {}

  **
  ** Callback when visiting a stmt.  Return a list to replace
  ** the statement with new statements, or return null to
  ** keep existing statement.
  **
  virtual Stmt[]? visitStmt(Stmt stmt) { null }

  **
  ** Callback when entering a finally block
  **
  virtual Void enterFinally(TryStmt stmt) {}

  **
  ** Callback when exiting a finally block
  **
  virtual Void exitFinally(TryStmt stmt) {}

//////////////////////////////////////////////////////////////////////////
// Expr Callbacks
//////////////////////////////////////////////////////////////////////////

  **
  ** Call to visit an expression.  Return expr or a new
  ** expression if doing a replacement for the expression in
  ** the abstract syntax tree.
  **
  virtual Expr visitExpr(Expr expr) { expr }
}

**************************************************************************
** VisitDepth
**************************************************************************

**
** VisitDepth enumerates how deep to traverse the AST
**
enum class VisitDepth { typeDef, slotDef, stmt, expr }

**************************************************************************
** ExprVisitor
**************************************************************************

**
** ExprVisitor implements a Visitor which visits
** each expr using a closure.
**
internal class ExprVisitor : Visitor
{
  new make(|Expr expr->Expr| func)
  {
    this.func = func
  }

  override Expr visitExpr(Expr expr)
  {
    return (Expr)func.call(expr)
  }

  |Expr expr->Expr| func
}

**************************************************************************
** TreeWriter
**************************************************************************

/*
class TreeWriter : AstWriter mixin Visitor
{
  new make(OutStream out := Env.cur.out) : super(out) {}
  override Void enterTypeDef(TypeDef def) { w(def.qname).nl; indent }
  override Void exitTypeDef(TypeDef def) { unindent }

  override Void enterFieldDef(FieldDef def) { w(def).nl; indent }
  override Void exitFieldDef(FieldDef def) { unindent }

  override Void enterMethodDef(MethodDef def) { w(def).nl; indent }
  override Void exitMethodDef(MethodDef def) { unindent }

  override Void enterBlock(Block b) { w("{").nl; indent }
  override Void exitBlock(Block b) { unindent; w("}").nl }

  override Void enterStmt(Stmt s) { w(s.id).nl; indent }
  override Void exitStmt(Stmt s) { unindent }

  override Void enterExpr(Expr expr) { w(expr).nl; indent }
  override Void exitExpr(Expr expr) { unindent  }
  override Expr visitExpr(Expr expr) {  return expr }
}
*/