summaryrefslogtreecommitdiff
path: root/sources
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2004-11-19 14:47:39 +0000
committerIulian Dragos <jaguarul@gmail.com>2004-11-19 14:47:39 +0000
commit02dc24e06886d3ecc2180f4ac53c2c48a643de1b (patch)
tree5280b24457744443212aa6c8553729e9c7d7c4ad /sources
parentd2b9c55e12acbab3694ae9c8fcb0d69d46c643ea (diff)
downloadscala-02dc24e06886d3ecc2180f4ac53c2c48a643de1b.tar.gz
scala-02dc24e06886d3ecc2180f4ac53c2c48a643de1b.tar.bz2
scala-02dc24e06886d3ecc2180f4ac53c2c48a643de1b.zip
Added swing printer.
Diffstat (limited to 'sources')
-rw-r--r--sources/scala/tools/scalac/Global.scala2
-rw-r--r--sources/scala/tools/scalac/ast/printer/SwingPrinter.scala253
-rw-r--r--sources/scala/tools/scalac/ast/printer/TreeInfo.scala333
-rw-r--r--sources/scalac/Global.java7
4 files changed, 594 insertions, 1 deletions
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);