treebrowsers.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 694 行 · 第 1/2 页

SCALA
694
字号
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * @author  Martin Odersky */// $Id: TreeBrowsers.scala 14477 2008-04-02 10:07:21Z rytz $package scala.tools.nsc.astimport java.awt.{List => awtList, _}import java.awt.event._import java.io.StringWriterimport javax.swing._import javax.swing.event.TreeModelListenerimport javax.swing.tree._import scala.concurrent.Lockimport scala.text._import symtab.Flags._import symtab.SymbolTable/** * Tree browsers can show the AST in a graphical and interactive * way, useful for debugging and understanding. * * @author Iulian Dragos * @version 1.0 */abstract class TreeBrowsers {  val global: Global  import global._  import nme.EMPTY  def create(): SwingBrowser = new SwingBrowser();  /** Pseudo tree class, so that all JTree nodes are treated uniformly */  case class ProgramTree(units: List[UnitTree]) extends Tree {    override def toString(): String = "Program"  }  /** Pseudo tree class, so that all JTree nodes are treated uniformly */  case class UnitTree(unit: CompilationUnit) extends Tree {    override def toString(): String = unit.toString()  }  /**   * Java Swing pretty printer for Scala abstract syntax trees.   */  class SwingBrowser {    def browse(t: Tree): Unit = {      val tm = new ASTTreeModel(t)      val frame = new BrowserFrame()      frame.setTreeModel(tm)      val lock = new Lock()      frame.createFrame(lock)      // wait for the frame to be closed      lock.acquire    }    def browse(units: Iterator[CompilationUnit]): Unit =      browse(units.toList)    /** print the whole program */    def browse(units: List[CompilationUnit]): Unit = {      var unitList: List[UnitTree] = Nil      for (i <- units)        unitList = UnitTree(i) :: unitList      val tm = new ASTTreeModel(ProgramTree(unitList))      val frame = new BrowserFrame()      frame.setTreeModel(tm)      val lock = new Lock()      frame.createFrame(lock)      // wait for the frame to be closed      lock.acquire    }  }  /** Tree model for abstract syntax trees */  class ASTTreeModel(val program: Tree) extends TreeModel {    var listeners: List[TreeModelListener] = Nil    /** Add a listener to this tree */    def addTreeModelListener(l: TreeModelListener): Unit =      listeners = l :: listeners    /** Return the index'th child of parent */    def getChild(parent: Any, index: Int): AnyRef =      packChildren(parent).drop(index).head    /** Return the number of children this 'parent' has */    def getChildCount(parent: Any): Int =      packChildren(parent).length    /** Return the index of the given child */    def getIndexOfChild(parent: Any, child: Any): Int =      packChildren(parent).dropWhile(c => c != child).length    /** Return the root node */    def getRoot(): AnyRef = program    /** Test whether the given node is a leaf */    def isLeaf(node: Any): Boolean = packChildren(node).length == 0    def removeTreeModelListener(l: TreeModelListener): Unit =      listeners remove (x => x == l)    /** we ignore this message for now */    def valueForPathChanged(path: TreePath, newValue: Any) = ()    /**     * Return a list of children for the given node.     */    def packChildren(t: Any): List[AnyRef] =        TreeInfo.children(t.asInstanceOf[Tree])  }  /**   * A window that can host the Tree widget and provide methods for    * displaying information    *   * @author Iulian Dragos   * @version 1.0   */  class BrowserFrame {    val frame = new JFrame("Scala AST")    val topLeftPane = new JPanel(new BorderLayout())    val topRightPane = new JPanel(new BorderLayout())    val bottomPane = new JPanel(new BorderLayout())    var splitPane: JSplitPane = _    var treeModel: TreeModel = _    val textArea: JTextArea = new JTextArea(20, 50)    val infoPanel = new TextInfoPanel()    /** Create a frame that displays the AST.     *     * @param lock The lock is used in order to stop the compilation thread     * until the user is done with the tree inspection. Swing creates its     * own threads when the frame is packed, and therefore execution      * would continue. However, this is not what we want, as the tree and     * especially symbols/types would change while the window is visible.     */    def createFrame(lock: Lock): Unit = {      lock.acquire // keep the lock until the user closes the window      frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)      frame.addWindowListener(new WindowAdapter() {        /** Release the lock, so compilation may resume after the window is closed. */        override def windowClosed(e: WindowEvent): Unit = lock.release      });      val tree = new JTree(treeModel) {        /** Return the string for a tree node. */        override def convertValueToText(value: Any, sel: Boolean,                                        exp: Boolean, leaf: Boolean,                                        row: Int, hasFocus: Boolean) = {            val (cls, name) = TreeInfo.treeName(value.asInstanceOf[Tree])            if (name != EMPTY)              cls + "[" + name.toString() + "]"            else              cls        }      }      tree.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {        def valueChanged(e: javax.swing.event.TreeSelectionEvent): Unit = {          textArea.setText(e.getPath().getLastPathComponent().toString())          infoPanel.update(e.getPath().getLastPathComponent())        }      })      val topSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, topLeftPane, topRightPane)      topSplitPane.setResizeWeight(0.5)      topLeftPane.add(new JScrollPane(tree), BorderLayout.CENTER)      topRightPane.add(new JScrollPane(infoPanel), BorderLayout.CENTER)      bottomPane.add(new JScrollPane(textArea), BorderLayout.CENTER)      textArea.setFont(new Font("monospaced", Font.PLAIN, 14))      textArea.setEditable(false)      splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topSplitPane, bottomPane)      frame.getContentPane().add(splitPane)      frame.pack()      frame.setVisible(true)    }    def setTreeModel(tm: TreeModel): Unit = treeModel = tm  }  /**   * Present detailed information about the selected tree node.   */  class TextInfoPanel extends JTextArea(30, 40) {    setFont(new Font("monospaced", Font.PLAIN, 12))    def update(v: AnyRef): Unit = {      val t: Tree = v.asInstanceOf[Tree]      val str = new StringBuilder()      var buf = new StringWriter()      t match {        case ProgramTree(_) => ()        case UnitTree(_)    => ()        case _ =>          str.append("tree.pos: ").append(t.pos)          str.append("\nSymbol: ").append(TreeInfo.symbolText(t))          str.append("\nSymbol info: \n")          TreeInfo.symbolTypeDoc(t).format(getWidth() / getColumnWidth(), buf)          str.append(buf.toString())          str.append("\nSymbol tpe: ")          if (t.symbol ne null) {            str.append(t.symbol.tpe).append("\n")            buf = new StringWriter()            TypePrinter.toDocument(t.symbol.tpe).format(getWidth() / getColumnWidth(), buf)            str.append(buf.toString())          }          str.append("\nSymbol Attributes: \n").append(TreeInfo.symbolAttributes(t))          str.append("\ntree.tpe: ")          if (t.tpe ne null) {            str.append(t.tpe.toString()).append("\n")            buf = new StringWriter()            TypePrinter.toDocument(t.tpe).format(getWidth() / getColumnWidth(), buf)            str.append(buf.toString())          }      }      setText(str.toString())    }  }  /** Computes different information about a tree node. It   *  is used as central place to do all pattern matching against   *  Tree.   */  object TreeInfo {    /** Return the case class name and the Name, if the node defines one */    def treeName(t: Tree): (String, Name) = t match {      case ProgramTree(units) =>        ("Program", EMPTY)      case UnitTree(unit) =>        ("CompilationUnit", unit.toString())      case DocDef(comment, definition) =>        ("DocDef", EMPTY)      case ClassDef(mods, name, tparams, impl) =>        ("ClassDef", name)      case PackageDef(packaged, impl) =>        ("PackageDef", EMPTY)      case ModuleDef(mods, name, impl) =>        ("ModuleDef", name)      case ValDef(mods, name, tpe, rhs) =>        ("ValDef", name)      case DefDef(mods, name, tparams, vparams, tpe, rhs) =>        ("DefDef", name)      case TypeDef(mods, name, tparams, rhs) =>        ("TypeDef", name)      case Import(expr, selectors) =>        ("Import", EMPTY)      case CaseDef(pat, guard, body) =>        ("CaseDef", EMPTY)      case Template(parents, self, body) =>        ("Template", EMPTY)      case LabelDef(name, params, rhs) =>        ("LabelDef", name)      case Block(stats, expr) =>        ("Block", EMPTY)      case Sequence(trees) =>        ("Sequence", EMPTY)      case Alternative(trees) =>        ("Alternative", EMPTY)      case Bind(name, rhs) =>        ("Bind", name)            case UnApply(fun, args) =>        ("UnApply", EMPTY)              case Match(selector, cases) =>        ("Visitor", EMPTY)      case Function(vparams, body) =>        ("Function", EMPTY)      case Assign(lhs, rhs) =>        ("Assign", EMPTY)      case If(cond, thenp, elsep) =>        ("If", EMPTY)      case Return(expr) =>        ("Return", EMPTY)      case Throw(expr) =>        ("Throw", EMPTY)      case New(init) =>        ("New", EMPTY)      case Typed(expr, tpe) =>        ("Typed", EMPTY)      case TypeApply(fun, args) =>        ("TypeApply", EMPTY)      case Apply(fun, args) =>        ("Apply", EMPTY)      case ApplyDynamic(qual, args) =>        ("Apply", EMPTY)      case Super(qualif, mix) =>        ("Super", qualif.toString() + ", mix: " + mix.toString())      case This(qualifier) =>        ("This", qualifier)      case Select(qualifier, selector) =>        ("Select", selector)      case Ident(name) =>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?