diff options
author | Iulian Dragos <jaguarul@gmail.com> | 2004-11-19 14:47:39 +0000 |
---|---|---|
committer | Iulian Dragos <jaguarul@gmail.com> | 2004-11-19 14:47:39 +0000 |
commit | 02dc24e06886d3ecc2180f4ac53c2c48a643de1b (patch) | |
tree | 5280b24457744443212aa6c8553729e9c7d7c4ad | |
parent | d2b9c55e12acbab3694ae9c8fcb0d69d46c643ea (diff) | |
download | scala-02dc24e06886d3ecc2180f4ac53c2c48a643de1b.tar.gz scala-02dc24e06886d3ecc2180f4ac53c2c48a643de1b.tar.bz2 scala-02dc24e06886d3ecc2180f4ac53c2c48a643de1b.zip |
Added swing printer.
-rw-r--r-- | config/list/scalac.lst | 2 | ||||
-rw-r--r-- | sources/scala/tools/scalac/Global.scala | 2 | ||||
-rw-r--r-- | sources/scala/tools/scalac/ast/printer/SwingPrinter.scala | 253 | ||||
-rw-r--r-- | sources/scala/tools/scalac/ast/printer/TreeInfo.scala | 333 | ||||
-rw-r--r-- | sources/scalac/Global.java | 7 |
5 files changed, 596 insertions, 1 deletions
diff --git a/config/list/scalac.lst b/config/list/scalac.lst index 186dcb5db3..767f33571d 100644 --- a/config/list/scalac.lst +++ b/config/list/scalac.lst @@ -184,6 +184,8 @@ ast/parser/Tokens.scala ast/printer/HTMLPrinter.scala ast/printer/TextTreePrinter.scala +ast/printer/SwingPrinter.scala +ast/printer/TreeInfo.scala transformer/TransMatch.scala transformer/TransMatchPhase.scala diff --git a/sources/scala/tools/scalac/Global.scala b/sources/scala/tools/scalac/Global.scala index 6d3ec6a9fd..fb5028ed17 100644 --- a/sources/scala/tools/scalac/Global.scala +++ b/sources/scala/tools/scalac/Global.scala @@ -28,6 +28,8 @@ class Global(args: CompilerCommand, interpret: boolean) extends scalac_Global(ar new TextTreePrinter(writer); override def newHTMLTreePrinter(writer: PrintWriter): TreePrinter = new HTMLTreePrinter(writer); + override def newSwingTreePrinter(writer: PrintWriter): TreePrinter = + new SwingTreePrinter; } } diff --git a/sources/scala/tools/scalac/ast/printer/SwingPrinter.scala b/sources/scala/tools/scalac/ast/printer/SwingPrinter.scala new file mode 100644 index 0000000000..b8c7d98969 --- /dev/null +++ b/sources/scala/tools/scalac/ast/printer/SwingPrinter.scala @@ -0,0 +1,253 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ + + +import scalac.CompilationUnit; +import scalac.symtab._; +import scalac.ast.Tree; +import scalac.ast.printer._; + +import scalac.{Global => scalac_Global, Phase}; +import scalac.CompilationUnit; +import scalac.util.Name; +import scalac.util.TypeNames; + +import scala.concurrent._; + +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.HashMap; + +import javax.swing.tree._; +import javax.swing.event.TreeModelListener; +import javax.swing._; + +import java.awt.{List => awtList, _}; +import java.awt.event._; + +package scala.tools.scalac.ast.printer { + +/** + * Java Swing pretty printer for Scala abstract syntax trees. + * + * @author Iulian Dragos + * @version 0.2 + */ +class SwingTreePrinter extends TreePrinter { + def begin() = (); + def end() = (); + def flush() = (); + + + /** print the whole program */ + def print(global: scalac_Global): Unit = { + val phase: Phase = global.currentPhase; + + val tm = new ASTTreeModel(); + + for (val i <- Iterator.range(0, global.units.length)) + tm.addUnit(global.units(i)); + + val frame = new WindowFrame(); + frame.setTreeModel(tm); + + val lock = new Lock(); + frame.createFrame(lock); + + // wait for the frame to be closed + lock.acquire; + } + + /** print one compilation unit*/ + def print(unit: CompilationUnit): Unit = { + } + + def print(tree: Tree) = this; + + def print(str: String) = this; + def println() = this; + + +} + +/** Tree model for abstract syntax trees */ +class ASTTreeModel extends TreeModel { + var listeners: List[TreeModelListener] = Nil; + var units: List[CompilationUnit] = Nil; + + def addUnit(c: CompilationUnit): Unit = units = c :: units; + + /** 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 = units; + + /** 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 objects for the current node. We have to + * take care of the "top" of the tree, which is not made of case + * classes of Tree. Therefore, instanceOf is used to differentatiate + * between "true" tree nodes, and "logical" ones (CompilationUnit and + * Program). + * + * @todo A type-safe version of this. However, new case classes of Tree + * cannot be derived in Scala because of "final" method getType of + * Tree, which overlaps with scala runtime types. + */ + def packChildren(t: Any): List[AnyRef] = + if (t.isInstanceOf[CompilationUnit]) { + val cu = t.asInstanceOf[CompilationUnit]; + List.fromArray(cu.body) + } else if (t.isInstanceOf[Tree]) + TreeInfo.packTreeChildren(t.asInstanceOf[Tree]); + else if (t.isInstanceOf[List[CompilationUnit]]) + t.asInstanceOf[List[CompilationUnit]]; + else + Nil; + +} + + +/** a window that can host the Tree widget and provide methods for + * displaying information */ +class WindowFrame { + val frame = new JFrame("Scala AST"); + val topPane = new JPanel(new BorderLayout()); + val topRightPane = new JPanel(); + val bottomPane = new JPanel(new BorderLayout()); + var splitPane: JSplitPane = _; + var treeModel: TreeModel = _; + + val textArea: JTextArea = new JTextArea(20, 50); + + + /** 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; + }); + + topPane.setMinimumSize(new java.awt.Dimension(150, 200)); + bottomPane.setMinimumSize(new java.awt.Dimension(150, 200)); + + splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topPane, bottomPane); + + 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) = { + if (value.isInstanceOf[List[CompilationUnit]]) + "Program" + else if (value.isInstanceOf[CompilationUnit]) + "CompilationUnit" + else { + val Pair(cls, name) = TreeInfo.treeName(value.asInstanceOf[Tree]); + if (name != TreeInfo.NO_NAME) + 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()); + } + }); + + topPane.add(new JScrollPane(tree), BorderLayout.CENTER); + topPane.add(topRightPane, BorderLayout.EAST); + + topRightPane.add(new InfoPanel()); + + bottomPane.add(new JScrollPane(textArea), BorderLayout.CENTER); + textArea.setFont(new Font("monospaced", Font.PLAIN, 14)); + textArea.setEditable(false); + + frame.getContentPane().add(splitPane); + frame.pack(); + frame.setVisible(true); + } + + def setTreeModel(tm: TreeModel): Unit = treeModel = tm; +} + + +class InfoPanel extends JPanel() { + val symbolLine = Box.createHorizontalBox(); + val symbolAttLine = Box.createHorizontalBox(); + val symbolTypeLine = Box.createHorizontalBox(); + val treeTypeLine = Box.createHorizontalBox(); + + val symLabel = new JLabel("some"); + val attLabel = new JLabel("[private, final, synthetic]"); + val stypeLabel = new JLabel("..."); + val ttypeLabel = new JLabel("......."); + + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + symbolLine.add(new JLabel("Symbol: ")); + symbolLine.add(symLabel); + symbolLine.add(Box.createHorizontalGlue()); + + symbolAttLine.add(new JLabel("Symbol attributes: ")); + symbolAttLine.add(attLabel); + symbolAttLine.add(Box.createHorizontalGlue()); + + symbolTypeLine.add(new JLabel("Symbol type: ")); + symbolTypeLine.add(stypeLabel); + symbolTypeLine.add(Box.createHorizontalGlue()); + + treeTypeLine.add(new JLabel("Tree type: ")); + treeTypeLine.add(ttypeLabel); + treeTypeLine.add(Box.createHorizontalGlue()); + + add(symbolLine); + add(symbolAttLine); + add(symbolTypeLine); + add(treeTypeLine); +} + +} // package + diff --git a/sources/scala/tools/scalac/ast/printer/TreeInfo.scala b/sources/scala/tools/scalac/ast/printer/TreeInfo.scala new file mode 100644 index 0000000000..d84e164c87 --- /dev/null +++ b/sources/scala/tools/scalac/ast/printer/TreeInfo.scala @@ -0,0 +1,333 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ +import scalac.CompilationUnit; +import scalac.symtab._; +import scalac.ast.Tree; +import scalac.ast.printer._; + +import scalac.{Global => scalac_Global, Phase}; +import scalac.CompilationUnit; +import scalac.util.Name; +import scalac.util.TypeNames; + +import java.io.OutputStream; +import java.io.PrintWriter; +import java.lang.Math; +import java.util.HashMap; + +import javax.swing.tree._; +import javax.swing.event.TreeModelListener; +import javax.swing._; + +import java.awt.BorderLayout; + +package scala.tools.scalac.ast.printer { + + +/** Computes different information about a tree node. It + is used as central place to do all pattern matching against + Tree. +*/ +object TreeInfo { + val NO_NAME = Name.fromString(""); + + /** Return the case class name and the Name, if the node defines one */ + def treeName(t: Tree): Pair[String, Name] = t match { + case Tree.Attributed(attribute, definition) => + Pair("Attributed", NO_NAME); + + case Tree.DocDef(comment, definition) => + Pair("DocDef", NO_NAME); + + case Tree.ClassDef(mods, name, tparams, vparams, tpe, impl) => + Pair("ClassDef", name); + + case Tree.PackageDef(packaged, impl) => + Pair("PackageDef", NO_NAME); + + case Tree.ModuleDef(mods, name, tpe, impl) => + Pair("ModuleDef", name); + + case Tree.ValDef(mods, name, tpe, rhs) => + Pair("ValDef", name); + + case Tree.PatDef(mods, pat, rhs) => + Pair("PatDef", NO_NAME); + + case Tree.DefDef(mods, name, tparams, vparams, tpe, rhs) => + Pair("DefDef", name); + + case Tree.AbsTypeDef(mods, name, rhs, lobound) => + Pair("AbsTypeDef", name); + + case Tree.AliasTypeDef(mods, name, tparams, rhs) => + Pair("AliasTypeDef", name); + + case Tree.Import(expr, selectors) => + Pair("Import", Name.fromString(selectors.toString())); + + case Tree.CaseDef(pat, guard, body) => + Pair("CaseDef", NO_NAME); + + case Tree.Template(parents, body) => + Pair("Template", NO_NAME); + + case Tree.LabelDef(name, params, rhs) => + Pair("LabelDef", name); + + case Tree.Block(stats, expr) => + Pair("Block", NO_NAME); + + case Tree.Sequence(trees) => + Pair("Sequence", NO_NAME); + + case Tree.Alternative(trees) => + Pair("Alternative", NO_NAME); + + case Tree.Bind(name, rhs) => + Pair("Bind", name); + + case Tree.Visitor(cases) => + Pair("Visitor", NO_NAME); + + case Tree.Function(vparams, body) => + Pair("Function", NO_NAME); + + case Tree.Assign(lhs, rhs) => + Pair("Assign", NO_NAME); + + case Tree.If(cond, thenp, elsep) => + Pair("If", NO_NAME); + + case Tree.Switch(test, tags, bodies, otherwise) => + Pair("Switch", NO_NAME); + + case Tree.Return(expr) => + Pair("Return", NO_NAME); + + case Tree.Throw(expr) => + Pair("Throw", NO_NAME); + + case Tree.New(init) => + Pair("New", NO_NAME); + + case Tree.Create(qualifier, targs) => + Pair("Create", NO_NAME); + + case Tree.Typed(expr, tpe) => + Pair("Typed", NO_NAME); + + case Tree.TypeApply(fun, args) => + Pair("TypeApply", NO_NAME); + + case Tree.Apply(fun, args) => + Pair("Apply", NO_NAME); + + case Tree.Super(qualif, mixin) => + Pair("Super", Name.fromString(qualif.toString() + ", mixin: " + mixin.toString())); + + case Tree.This(qualifier) => + Pair("This", qualifier); + + case Tree.Select(qualifier, selector) => + Pair("Select", selector); + + case Tree.Ident(name) => + Pair("Ident", name); + + case Tree.Literal(value) => + Pair("Literal", NO_NAME); + + case Tree.TypeTerm() => + Pair("TypeTerm", NO_NAME); + + case Tree.SingletonType(ref) => + Pair("SingletonType", NO_NAME); + + case Tree.SelectFromType(qualifier, selector) => + Pair("SelectFromType", selector); + + case Tree.FunType(argtpes, restpe) => + Pair("FunType", NO_NAME); + + case Tree.CompoundType(parents, refinements) => + Pair("CompoundType", NO_NAME); + + case Tree.AppliedType(tpe, args) => + Pair("AppliedType", NO_NAME); + + case Tree.Try(block, catcher, finalizer) => + Pair("Try", NO_NAME); + + case Tree.Empty => + Pair("Empty", NO_NAME); + } + + /** Generate a list that contains all the elements of an Array of Array */ + def flattenArrays[a <: AnyRef](as: Array[Array[a]]): List[a] = { + def flattenArrays0[a <: AnyRef](as: Array[Array[a]], i: Int): List[a] = + if (as.length - i == 0) + Nil; + else if (as.length - i == 1) + List.fromArray(as(i)); + else + List.fromArray(as(i)) ::: flattenArrays0(as, i + 1); + + flattenArrays0(as, 0); + } + + /** Return a list of children for the given tree node */ + def packTreeChildren(t: Tree): List[Tree] = t match { + case Tree.Attributed(attribute, definition) => + List(attribute, definition); + + case Tree.DocDef(comment, definition) => + List(definition); + + case Tree.ClassDef(mods, name, tparams, vparams, tpe, impl) => { + var children: List[Tree] = List(); + children = List.fromArray(tparams) ::: children; + children = flattenArrays(vparams) ::: children; + tpe :: impl :: children + } + + case Tree.PackageDef(packaged, impl) => + List(packaged, impl); + + case Tree.ModuleDef(mods, name, tpe, impl) => + List(tpe, impl); + + case Tree.ValDef(mods, name, tpe, rhs) => + List(tpe, rhs); + + case Tree.PatDef(mods, pat, rhs) => + List(pat, rhs); + + case Tree.DefDef(mods, name, tparams, vparams, tpe, rhs) => { + var children: List[Tree] = List(); + children = List.fromArray(tparams) ::: children; + children = flattenArrays(vparams) ::: children; + tpe :: rhs :: children + } + + case Tree.AbsTypeDef(mods, name, rhs, lobound) => + List(rhs, lobound); + + case Tree.AliasTypeDef(mods, name, tparams, rhs) => { + var children: List[Tree] = List(); + children = List.fromArray(tparams) ::: children; + rhs :: children + } + + case Tree.Import(expr, selectors) => { + var children: List[Tree] = List(expr); + children + } + + case Tree.CaseDef(pat, guard, body) => + List(pat, guard, body); + + case Tree.Template(parents, body) => + List.fromArray(parents) ::: List.fromArray(body); + + case Tree.LabelDef(name, params, rhs) => + List.fromArray(params) ::: List(rhs); + + case Tree.Block(stats, expr) => + List.fromArray(stats) ::: List(expr); + + case Tree.Sequence(trees) => + List.fromArray(trees); + + case Tree.Alternative(trees) => + List.fromArray(trees); + + case Tree.Bind(name, rhs) => + List(rhs); + + case Tree.Visitor(cases) => + List.fromArray(cases); + + case Tree.Function(vparams, body) => + List.fromArray(vparams) ::: List(body); + + case Tree.Assign(lhs, rhs) => + List(lhs, rhs); + + case Tree.If(cond, thenp, elsep) => + List(cond, thenp, elsep); + + case Tree.Switch(test, tags, bodies, otherwise) => + test :: List.fromArray(bodies) ::: List(otherwise); + + case Tree.Return(expr) => + List(expr); + + case Tree.Throw(expr) => + List(expr); + + case Tree.New(init) => + List(init); + + case Tree.Create(qualif, targs) => + List(qualif) ::: List.fromArray(targs); + + case Tree.Typed(expr, tpe) => + List(expr, tpe); + + case Tree.TypeApply(fun, args) => + List(fun) ::: List.fromArray(args); + + case Tree.Apply(fun, args) => + List(fun) ::: List.fromArray(args); + + case Tree.Super(qualif, mixin) => + Nil; + + case Tree.This(qualif) => + Nil + + case Tree.Select(qualif, selector) => + List(qualif); + + case Tree.Ident(name) => + Nil; + + case Tree.Literal(value) => + Nil; + + case Tree.TypeTerm() => + Nil; + + case Tree.SingletonType(ref) => + List(ref); + + case Tree.SelectFromType(qualif, selector) => + List(qualif); + + case Tree.FunType(argtpes, restpe) => + List.fromArray(argtpes) ::: List(restpe); + + case Tree.CompoundType(parents, refinements) => + List.fromArray(parents) ::: List.fromArray(refinements); + + case Tree.AppliedType(tpe, args) => + tpe :: List.fromArray(args); + + case Tree.Try(block, catcher, finalizer) => + List(block, catcher, finalizer); + + case Tree.Empty => + Nil; + } + + +} + +} // package diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java index 93a19ff47e..091eefe2c5 100644 --- a/sources/scalac/Global.java +++ b/sources/scalac/Global.java @@ -181,10 +181,12 @@ public abstract class Global { */ public static final String PRINTER_TEXT; public static final String PRINTER_HTML; + public static final String PRINTER_SWING; public static final String[] PRINTERS = new String[] { PRINTER_TEXT = "text", PRINTER_HTML = "html", + PRINTER_SWING = "swing", }; /** @@ -201,6 +203,7 @@ public abstract class Global { public abstract Infer newInfer(); public abstract TreePrinter newTextTreePrinter(PrintWriter writer); public abstract TreePrinter newHTMLTreePrinter(PrintWriter writer); + public abstract TreePrinter newSwingTreePrinter(PrintWriter writer); /** * Creates an instance variable. @@ -264,7 +267,9 @@ public abstract class Global { this.writer = new PrintWriter(stream, debug); if (args.printer.value.equals(PRINTER_HTML)) { this.treePrinter = newHTMLTreePrinter(writer); - } else { + } else if (args.printer.value.equals(PRINTER_SWING)) { + this.treePrinter = newSwingTreePrinter(writer); + } else { if (!args.printer.value.equals(PRINTER_TEXT)) error("unknown printer kind: " + args.printer.value); this.treePrinter = newTextTreePrinter(writer); |