summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/ast
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/ast')
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala631
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala158
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeInfo.scala187
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreePrinters.scala303
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala1251
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala583
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Parsers.scala1808
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Scanners.scala908
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala349
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala25
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/Tokens.scala97
-rw-r--r--src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala289
12 files changed, 6589 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
new file mode 100644
index 0000000000..9e4821a734
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/TreeBrowsers.scala
@@ -0,0 +1,631 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.ast;
+
+import scala.concurrent._;
+import symtab.Flags._;
+
+
+import java.lang.Math;
+import java.util.HashMap;
+import java.io.StringWriter;
+
+import javax.swing.tree._;
+import javax.swing.event.TreeModelListener;
+import javax.swing._;
+
+import java.awt.BorderLayout;
+import java.awt.{List => awtList, _};
+import java.awt.event._;
+
+import scala.text._;
+
+/**
+ * Tree browsers can show the AST in a graphical and interactive
+ * way, useful for debugging and understanding.
+ */
+abstract class TreeBrowsers {
+
+ val global: Global;
+ import global._;
+ import nme.EMPTY;
+
+ /** 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();
+ }
+
+ def create(): SwingBrowser = new SwingBrowser();
+
+ /**
+ * Java Swing pretty printer for Scala abstract syntax trees.
+ */
+ class SwingBrowser {
+
+ def browse(units: Iterator[CompilationUnit]): Unit =
+ browse(units.toList);
+
+ /** print the whole program */
+ def browse(units: List[CompilationUnit]): Unit = {
+ val phase: Phase = globalPhase;
+ var unitList: List[UnitTree] = Nil;
+
+
+ for (val 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: ProgramTree) 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
+ */
+ 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 Pair(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 StringBuffer();
+ var buf = new StringWriter();
+
+ t match {
+ case ProgramTree(_) => ();
+ case UnitTree(_) => ();
+ case _ =>
+ str.append("Symbol: ").append(TreeInfo.symbolText(t));
+ str.append("\nSymbol info: \n");
+ TreeInfo.symbolTypeDoc(t).format(getWidth() / getColumnWidth(), buf);
+ str.append(buf.toString());
+ str.append("\nSymbol tpe: \n");
+ if (t.symbol != null) {
+ 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("\nType: \n").append(if (t.tpe ne null) t.tpe.toString() else "");
+ }
+ 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): Pair[String, Name] = t match {
+ case ProgramTree(units) =>
+ Pair("Program", EMPTY);
+
+ case UnitTree(unit) =>
+ Pair("CompilationUnit", unit.toString());
+
+ case Attributed(attribute, definition) =>
+ Pair("Attributed", EMPTY);
+
+ case DocDef(comment, definition) =>
+ Pair("DocDef", EMPTY);
+
+ case ClassDef(mods, name, tparams, tpt, impl) =>
+ Pair("ClassDef", name);
+
+ case PackageDef(packaged, impl) =>
+ Pair("PackageDef", EMPTY);
+
+ case ModuleDef(mods, name, impl) =>
+ Pair("ModuleDef", name);
+
+ case ValDef(mods, name, tpe, rhs) =>
+ Pair("ValDef", name);
+
+ case DefDef(mods, name, tparams, vparams, tpe, rhs) =>
+ Pair("DefDef", name);
+
+ case AbsTypeDef(mods, name, rhs, lobound) =>
+ Pair("AbsTypeDef", name);
+
+ case AliasTypeDef(mods, name, tparams, rhs) =>
+ Pair("AliasTypeDef", name);
+
+ case Import(expr, selectors) =>
+ Pair("Import", EMPTY);
+
+ case CaseDef(pat, guard, body) =>
+ Pair("CaseDef", EMPTY);
+
+ case Template(parents, body) =>
+ Pair("Template", EMPTY);
+
+ case LabelDef(name, params, rhs) =>
+ Pair("LabelDef", name);
+
+ case Block(stats, expr) =>
+ Pair("Block", EMPTY);
+
+ case Sequence(trees) =>
+ Pair("Sequence", EMPTY);
+
+ case Alternative(trees) =>
+ Pair("Alternative", EMPTY);
+
+ case Bind(name, rhs) =>
+ Pair("Bind", name);
+
+ case Match(selector, cases) =>
+ Pair("Visitor", EMPTY);
+
+ case Function(vparams, body) =>
+ Pair("Function", EMPTY);
+
+ case Assign(lhs, rhs) =>
+ Pair("Assign", EMPTY);
+
+ case If(cond, thenp, elsep) =>
+ Pair("If", EMPTY);
+
+ case Return(expr) =>
+ Pair("Return", EMPTY);
+
+ case Throw(expr) =>
+ Pair("Throw", EMPTY);
+
+ case New(init) =>
+ Pair("New", EMPTY);
+
+ case Typed(expr, tpe) =>
+ Pair("Typed", EMPTY);
+
+ case TypeApply(fun, args) =>
+ Pair("TypeApply", EMPTY);
+
+ case Apply(fun, args) =>
+ Pair("Apply", EMPTY);
+
+ case Super(qualif, mixin) =>
+ Pair("Super", qualif.toString() + ", mixin: " + mixin.toString());
+
+ case This(qualifier) =>
+ Pair("This", qualifier);
+
+ case Select(qualifier, selector) =>
+ Pair("Select", selector);
+
+ case Ident(name) =>
+ Pair("Ident", name);
+
+ case Literal(value) =>
+ Pair("Literal", EMPTY);
+
+ case TypeTree() =>
+ Pair("TypeTree", EMPTY);
+
+ case SingletonTypeTree(ref) =>
+ Pair("SingletonType", EMPTY);
+
+ case SelectFromTypeTree(qualifier, selector) =>
+ Pair("SelectFromType", selector);
+
+ case CompoundTypeTree(template) =>
+ Pair("CompoundType", EMPTY);
+
+ case AppliedTypeTree(tpe, args) =>
+ Pair("AppliedType", EMPTY);
+
+ case Try(block, catcher, finalizer) =>
+ Pair("Try", EMPTY);
+
+ case EmptyTree =>
+ Pair("Empty", EMPTY);
+
+ case ArrayValue(elemtpt, trees) =>
+ Pair("ArrayValue", EMPTY);
+ }
+
+ /** Return a list of children for the given tree node */
+ def children(t: Tree): List[Tree] = t match {
+ case ProgramTree(units) =>
+ units;
+
+ case UnitTree(unit) =>
+ List(unit.body);
+
+ case Attributed(attribute, definition) =>
+ List(attribute, definition);
+
+ case DocDef(comment, definition) =>
+ List(definition);
+
+ case ClassDef(mods, name, tparams, tpt, impl) => {
+ var children: List[Tree] = List();
+ children = tparams ::: children;
+ tpt :: impl :: children
+ }
+
+ case PackageDef(name, stats) =>
+ stats;
+
+ case ModuleDef(mods, name, impl) =>
+ List(impl);
+
+ case ValDef(mods, name, tpe, rhs) =>
+ List(tpe, rhs);
+
+ case DefDef(mods, name, tparams, vparams, tpe, rhs) => {
+ var children: List[Tree] = List();
+ children = tparams ::: children;
+ children = List.flatten(vparams) ::: children;
+ tpe :: rhs :: children
+ }
+
+ case AbsTypeDef(mods, name, rhs, lobound) =>
+ List(rhs, lobound);
+
+ case AliasTypeDef(mods, name, tparams, rhs) => {
+ var children: List[Tree] = List();
+ children = tparams ::: children;
+ rhs :: children
+ }
+
+ case Import(expr, selectors) => {
+ var children: List[Tree] = List(expr);
+ children
+ }
+
+ case CaseDef(pat, guard, body) =>
+ List(pat, guard, body);
+
+ case Template(parents, body) =>
+ parents ::: body;
+
+ case LabelDef(name, params, rhs) =>
+ params ::: List(rhs);
+
+ case Block(stats, expr) =>
+ stats ::: List(expr);
+
+ case Sequence(trees) =>
+ trees;
+
+ case Alternative(trees) =>
+ trees;
+
+ case Bind(name, rhs) =>
+ List(rhs);
+
+ case Match(selector, cases) =>
+ selector :: cases;
+
+ case Function(vparams, body) =>
+ vparams ::: List(body);
+
+ case Assign(lhs, rhs) =>
+ List(lhs, rhs);
+
+ case If(cond, thenp, elsep) =>
+ List(cond, thenp, elsep);
+
+ case Return(expr) =>
+ List(expr);
+
+ case Throw(expr) =>
+ List(expr);
+
+ case New(init) =>
+ List(init);
+
+ case Typed(expr, tpe) =>
+ List(expr, tpe);
+
+ case TypeApply(fun, args) =>
+ List(fun) ::: args;
+
+ case Apply(fun, args) =>
+ List(fun) ::: args;
+
+ case Super(qualif, mixin) =>
+ Nil;
+
+ case This(qualif) =>
+ Nil
+
+ case Select(qualif, selector) =>
+ List(qualif);
+
+ case Ident(name) =>
+ Nil;
+
+ case Literal(value) =>
+ Nil;
+
+ case TypeTree() =>
+ Nil;
+
+ case SingletonTypeTree(ref) =>
+ List(ref);
+
+ case SelectFromTypeTree(qualif, selector) =>
+ List(qualif);
+
+ case CompoundTypeTree(templ) =>
+ List(templ);
+
+ case AppliedTypeTree(tpe, args) =>
+ tpe :: args;
+
+ case Try(block, catches, finalizer) =>
+ block :: catches ::: List(finalizer);
+
+ case ArrayValue(elemtpt, elems) =>
+ elemtpt :: elems;
+
+ case EmptyTree =>
+ Nil;
+ }
+
+ /** Return a textual representation of this t's symbol */
+ def symbolText(t: Tree): String = {
+ var prefix = "";
+
+ if (t.hasSymbol)
+ prefix = "[has] ";
+ if (t.isDef)
+ prefix = "[defines] ";
+
+ prefix + t.symbol
+ }
+
+ /** Return t's symbol type */
+ def symbolTypeDoc(t: Tree): Document = {
+ val s = t.symbol;
+ if (s != null)
+ TypePrinter.toDocument(s.info);
+ else
+ DocNil;
+ }
+
+ /** Return a textual representation of (some of) the symbol's
+ * attributes */
+ def symbolAttributes(t: Tree): String = {
+ val s = t.symbol;
+ var att = "";
+
+ if (s != null) {
+ var str = flagsToString(s.flags);
+ if (s.hasFlag(STATIC) || s.hasFlag(STATICMEMBER))
+ str = str + " isStatic ";
+ str
+ }
+ else "";
+ }
+ }
+
+ object TypePrinter {
+
+ ///////////////// Document pretty printer ////////////////
+
+ implicit def view(n: String): Document = DocText(n);
+
+ def toDocument(sym: Symbol): Document =
+ toDocument(sym.info);
+
+ def symsToDocument(syms: List[Symbol]): Document = syms match {
+ case Nil => DocNil;
+ case s :: Nil => Document.group(toDocument(s));
+ case _ =>
+ Document.group(
+ syms.tail.foldLeft (toDocument(syms.head) :: ", ") (
+ (d: Document, s2: Symbol) => toDocument(s2) :: ", " :/: d) );
+ }
+
+ def toDocument(ts: List[Type]): Document = ts match {
+ case Nil => DocNil;
+ case t :: Nil => Document.group(toDocument(t));
+ case _ =>
+ Document.group(
+ ts.tail.foldLeft (toDocument(ts.head) :: ", ") (
+ (d: Document, t2: Type) => toDocument(t2) :: ", " :/: d) );
+ }
+
+ def toDocument(t: Type): Document = t match {
+ case ErrorType => "ErrorType()";
+ case WildcardType => "WildcardType()";
+ case NoType => "NoType()";
+ case NoPrefix => "NoPrefix()";
+ case ThisType(s) => "ThisType(" + s.name + ")";
+
+ case SingleType(pre, sym) =>
+ Document.group(
+ Document.nest(4, "SingleType(" :/:
+ toDocument(pre) :: ", " :/: sym.name.toString() :: ")")
+ );
+
+ case ConstantType(value) =>
+ "ConstantType(" + value + ")";
+
+ case TypeRef(pre, sym, args) =>
+ Document.group(
+ Document.nest(4, "TypeRef(" :/:
+ toDocument(pre) :: ", " :/:
+ sym.name.toString() :: ", " :/:
+ "[ " :: toDocument(args) ::"]" :: ")")
+ );
+
+ case TypeBounds(lo, hi) =>
+ Document.group(
+ Document.nest(4, "TypeBounds(" :/:
+ toDocument(lo) :: ", " :/:
+ toDocument(hi) :: ")")
+ );
+
+ case RefinedType(parents, defs) =>
+ Document.group(
+ Document.nest(4, "RefinedType(" :/:
+ toDocument(parents) :: ")")
+ );
+
+ case ClassInfoType(parents, defs, clazz) =>
+ Document.group(
+ Document.nest(4,"ClassInfoType(" :/:
+ toDocument(parents) :: ", " :/:
+ clazz.name.toString() :: ")")
+ );
+
+ case MethodType(paramtypes, result) =>
+ Document.group(
+ Document.nest(4, "MethodType(" :/:
+ Document.group("(" :/:
+ toDocument(paramtypes) :/:
+ "), ") :/:
+ toDocument(result) :: ")")
+ );
+
+ case PolyType(tparams, result) =>
+ Document.group(
+ Document.nest(4,"PolyType(" :/:
+ Document.group("(" :/:
+ symsToDocument(tparams) :/:
+ "), ") :/:
+ toDocument(result) :: ")")
+ );
+
+ case _ => abort("Unknown case: " + t.toString());
+ }
+ }
+
+}
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
new file mode 100644
index 0000000000..425cf9eac8
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -0,0 +1,158 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.ast;
+
+import scala.tools.nsc.util.Position;
+import symtab.Flags._;
+
+abstract class TreeGen {
+
+ val global: Global;
+
+ import global._;
+ import definitions._;
+ import posAssigner.atPos;
+
+ /** Builds a reference to value whose type is given stable prefix.
+ */
+ def mkQualifier(tpe: Type): Tree = tpe match {
+ case NoPrefix =>
+ EmptyTree
+ case ThisType(clazz) =>
+ if (clazz.isRoot || clazz.isEmptyPackageClass) EmptyTree else This(clazz)
+ case SingleType(pre, sym) =>
+ if (sym.isThisSkolem) {
+ mkQualifier(ThisType(sym.deSkolemize))
+ } else {
+ val qual = mkStableRef(pre, sym);
+ qual.tpe match {
+ case MethodType(List(), restpe) =>
+ Apply(qual, List()) setType restpe
+ case _ =>
+ qual
+ }
+ }
+ case TypeRef(pre, sym, args) =>
+ assert(phase.erasedTypes);
+ if (sym.isModuleClass && !sym.isRoot) {
+ val qual = Select(mkQualifier(sym.owner.tpe), sym.sourceModule);
+ qual.tpe match {
+ case MethodType(List(), restpe) =>
+ Apply(qual, List()) setType restpe
+ case _ =>
+ qual
+ }
+ } else This(sym)
+ }
+
+ /** Builds a reference to given symbol with given stable prefix. */
+ def mkRef(pre: Type, sym: Symbol): Tree = {
+ val qual = mkQualifier(pre);
+ if (qual == EmptyTree) Ident(sym) else Select(qual, sym)
+ }
+
+ /** Builds a reference to given symbol. */
+ def mkRef(sym: Symbol): Tree =
+ if (sym.owner.isClass) mkRef(sym.owner.thisType, sym) else Ident(sym);
+
+ /** Replaces tree type with a stable type if possible */
+ def stabilize(tree: Tree): Tree = tree match {
+ case Ident(_) =>
+ if (tree.symbol.isStable) tree.setType(singleType(tree.symbol.owner.thisType, tree.symbol))
+ else tree
+ case Select(qual, _) =>
+ if (tree.symbol.isStable && qual.tpe.isStable) tree.setType(singleType(qual.tpe, tree.symbol))
+ else tree
+ case _ =>
+ tree
+ }
+
+ /** Cast `tree' to type `pt' */
+ def cast(tree: Tree, pt: Type): Tree = {
+ if (settings.debug.value) log("casting " + tree + ":" + tree.tpe + " to " + pt);
+ assert(!tree.tpe.isInstanceOf[MethodType], tree);
+ typer.typed {
+ atPos(tree.pos) {
+ Apply(TypeApply(Select(tree, Object_asInstanceOf), List(TypeTree(pt))), List())
+ }
+ }
+ }
+
+ /** Builds a reference with stable type to given symbol */
+ def mkStableRef(pre: Type, sym: Symbol): Tree = stabilize(mkRef(pre, sym));
+ def mkStableRef(sym: Symbol): Tree = stabilize(mkRef(sym));
+
+ def This(sym: Symbol): Tree =
+ global.This(sym.name) setSymbol sym setType sym.thisType;
+
+ def Ident(sym: Symbol): Tree = {
+ assert(sym.isTerm);
+ global.Ident(sym.name) setSymbol sym setType sym.tpe;
+ }
+
+ def Select(qual: Tree, sym: Symbol): Tree =
+ if (qual.symbol != null &&
+ (qual.symbol.name.toTermName == nme.ROOT ||
+ qual.symbol.name.toTermName == nme.EMPTY_PACKAGE_NAME)) {
+ this.Ident(sym)
+ } else {
+ assert(sym.isTerm);
+ val result = global.Select(qual, sym.name) setSymbol sym;
+ if (qual.tpe != null) result setType qual.tpe.memberType(sym);
+ result
+ }
+
+ /** Builds an instance test with given value and type. */
+ def mkIsInstanceOf(value: Tree, tpe: Type, erased: Boolean): Tree = {
+ val sym =
+ if(erased)
+ definitions.Any_isInstanceOfErased
+ else
+ definitions.Any_isInstanceOf;
+ Apply(
+ TypeApply(
+ Select(value, sym),
+ List(TypeTree(tpe))),
+ List())
+ }
+
+ def mkIsInstanceOf(value: Tree, tpe: Type): Tree = {
+ mkIsInstanceOf(value, tpe, global.phase.erasedTypes);
+ }
+
+ /** Builds a cast with given value and type. */
+ def mkAsInstanceOf(value: Tree, tpe: Type, erased: Boolean): Tree = {
+ val sym =
+ if(erased)
+ definitions.Any_asInstanceOfErased
+ else
+ definitions.Any_asInstanceOf;
+
+ Apply(
+ TypeApply(
+ Select(value, sym),
+ List(TypeTree(tpe))),
+ List())
+ }
+
+ def mkAsInstanceOf(value: Tree, tpe: Type): Tree = {
+ mkAsInstanceOf(value, tpe, global.phase.erasedTypes);
+ }
+
+
+ /** Builds a list with given head and tail. */
+ def mkNewCons(head: Tree, tail: Tree): Tree =
+ New(Apply(mkRef(definitions.ConsClass), List(head,tail)));
+
+ /** Builds a list with given head and tail. */
+ def mkNil: Tree =
+ mkRef(definitions.NilModule);
+
+ /** Builds a pair */
+ def mkNewPair(left: Tree, right: Tree) =
+ New(Apply(mkRef(definitions.TupleClass(2)), List(left,right)));
+
+}
diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
new file mode 100644
index 0000000000..dedfc6b03a
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala
@@ -0,0 +1,187 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.ast;
+
+import symtab.Flags._;
+
+abstract class TreeInfo {
+
+ val global: Global;
+ import global._;
+
+ def isTerm(tree: Tree): boolean = tree.isTerm;
+ def isType(tree: Tree): boolean = tree.isType;
+
+ def isOwnerDefinition(tree: Tree): boolean = tree match {
+ case PackageDef(_, _)
+ | ClassDef(_, _, _, _, _)
+ | ModuleDef(_, _, _)
+ | DefDef(_, _, _, _, _, _)
+ | Import(_, _) => true
+ case _ => false
+ }
+
+ def isDefinition(tree: Tree): boolean = tree.isDef;
+
+ def isDeclaration(tree: Tree): boolean = tree match {
+ case DefDef(_, _, _, _, _, EmptyTree)
+ | ValDef(_, _, _, EmptyTree)
+ | AbsTypeDef(_, _, _, _)
+ | AliasTypeDef(_, _, _, _) => true
+ case _ => false
+ }
+
+ /** Is tree legal as a member definition of an interface?
+ */
+ def isInterfaceMember(tree: Tree): boolean = tree match {
+ case EmptyTree => true
+ case Import(_, _) => true
+ case AbsTypeDef(_, _, _, _) => true
+ case AliasTypeDef(_, _, _, _) => true
+ case DefDef(mods, _, _, _, _, __) => mods.hasFlag(DEFERRED)
+ case ValDef(mods, _, _, _) => mods.hasFlag(DEFERRED)
+ case DocDef(_, definition) => isInterfaceMember(definition)
+ case Attributed(_, definition) => isInterfaceMember(definition)
+ case _ => false
+ }
+
+
+ /** Is tree a pure definition?
+ */
+ def isPureDef(tree: Tree): boolean = tree match {
+ case EmptyTree
+ | ClassDef(_, _, _, _, _)
+ | ModuleDef(_, _, _)
+ | AbsTypeDef(_, _, _, _)
+ | AliasTypeDef(_, _, _, _)
+ | Import(_, _)
+ | DefDef(_, _, _, _, _, _) =>
+ true
+ case ValDef(mods, _, _, rhs) =>
+ mods.hasFlag(MUTABLE) && isPureExpr(rhs)
+ case DocDef(_, definition) =>
+ isPureDef(definition)
+ case Attributed(_, definition) =>
+ isPureDef(definition)
+ case _ =>
+ false
+ }
+
+ /** Is tree a stable & pure expression?
+ */
+ def isPureExpr(tree: Tree): boolean = tree match {
+ case EmptyTree
+ | This(_)
+ | Super(_, _)
+ | Literal(_) =>
+ true
+ case Ident(_) =>
+ tree.symbol.isStable
+ case Select(qual, _) =>
+ tree.symbol.isStable && isPureExpr(qual)
+ case TypeApply(fn, _) =>
+ isPureExpr(fn)
+ case Apply(fn, List()) =>
+ isPureExpr(fn)
+ case Typed(expr, _) =>
+ isPureExpr(expr)
+ case Block(stats, expr) =>
+ (stats forall isPureDef) && isPureExpr(expr)
+ case _ =>
+ false
+ }
+
+ /** Is tree a self constructor call?
+ */
+ def isSelfConstrCall(tree: Tree): boolean = tree match {
+ case Ident(nme.CONSTRUCTOR) =>
+ true
+ case TypeApply(constr, _) =>
+ isSelfConstrCall(constr)
+ case Apply(constr, _) =>
+ isSelfConstrCall(constr)
+ case _ =>
+ false
+ }
+
+ /** Is tree a variable pattern */
+ def isVarPattern(pat: Tree): boolean = pat match {
+ case Ident(name) => isVariableName(name)
+ case _ => false
+ }
+
+ /** The longest statement suffix that starts with a constructor */
+ def firstConstructor(stats: List[Tree]): Tree = stats.head match {
+ case constr @ DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => constr
+ case _ => firstConstructor(stats.tail)
+ }
+
+ /** Is name a left-associative operator? */
+ def isLeftAssoc(operator: Name): boolean =
+ operator.length > 0 && operator(operator.length - 1) != ':';
+
+ /** Is name a variable name? */
+ def isVariableName(name: Name): boolean = {
+ val first = name(0);
+ ((('a' <= first && first <= 'z') || first == '_')
+ && name != nme.false_
+ && name != nme.true_
+ && name != nme.null_)
+ }
+
+ /** Is tree a this node which belongs to `enclClass'? */
+ def isSelf(tree: Tree, enclClass: Symbol): boolean = tree match {
+ case This(_) => tree.symbol == enclClass
+ case _ => false
+ }
+
+ /** Is this pattern node a catch-all (wildcard or variable) pattern? */
+ def isDefaultCase(cdef: CaseDef) = cdef match {
+ case CaseDef(Ident(nme.WILDCARD), EmptyTree, _) => true
+ case CaseDef(Bind(_, Ident(nme.WILDCARD)), EmptyTree, _) => true
+ case _ => false
+ }
+
+ /** Is this pattern node a catch-all or type-test pattern? */
+ def isCatchCase(cdef: CaseDef) = cdef match {
+ case CaseDef(Typed(Ident(nme.WILDCARD), tpt), EmptyTree, _) => isSimple(tpt.tpe)
+ case CaseDef(Bind(_, Typed(Ident(nme.WILDCARD), tpt)), EmptyTree, _) => isSimple(tpt.tpe)
+ case _ => isDefaultCase(cdef)
+ }
+
+ private def isSimple(tp: Type): boolean = true;
+ /* If we have run-time types, and these are used for pattern matching,
+ we should replace this by something like:
+
+ tp match {
+ case TypeRef(pre, sym, args) =>
+ args.isEmpty && (sym.owner.isPackageClass || isSimple(pre))
+ case NoPrefix =>
+ true
+ case _ =>
+ false
+ }
+*/
+
+ /** Is this pattern node a sequence-valued pattern? */
+ def isSequenceValued(tree: Tree): boolean = tree match {
+ case Bind(_, body) => isSequenceValued(body)
+ case Sequence(_) => true
+ case ArrayValue(_, _) => true
+ case Star(_) => true
+ case Alternative(ts) => ts exists isSequenceValued
+ case _ => false
+ }
+
+ /** The method part of an application node
+ */
+ def methPart(tree: Tree): Tree = tree match {
+ case Apply(fn, _) => methPart(fn)
+ case TypeApply(fn, _) => methPart(fn)
+ case AppliedTypeTree(fn, _) => methPart(fn)
+ case _ => tree
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
new file mode 100644
index 0000000000..206fa58061
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala
@@ -0,0 +1,303 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.ast;
+
+import java.io._;
+import symtab.Flags._;
+
+abstract class TreePrinters {
+
+ val global: Global;
+ import global._;
+
+ class TreePrinter(out: PrintWriter) {
+ protected var indentMargin = 0;
+ protected val indentStep = 2;
+ protected var indentString = " ";
+
+ def flush = out.flush();
+
+ def indent = indentMargin = indentMargin + indentStep;
+ def undent = indentMargin = indentMargin - indentStep;
+
+ def println = {
+ out.println();
+ while (indentMargin > indentString.length())
+ indentString = indentString + indentString;
+ if (indentMargin > 0)
+ out.write(indentString, 0, indentMargin);
+ }
+
+ def printSeq[a](ls: List[a])(printelem: a => unit)(printsep: => unit): unit = ls match {
+ case List() =>
+ case List(x) => printelem(x)
+ case x :: rest => printelem(x); printsep; printSeq(rest)(printelem)(printsep)
+ }
+
+ def printColumn(ts: List[Tree], start: String, sep: String, end: String): unit = {
+ print(start); indent; println;
+ printSeq(ts){print}{print(sep); println}; undent; println; print(end)
+ }
+
+ def printRow(ts: List[Tree], start: String, sep: String, end: String): unit = {
+ print(start); printSeq(ts){print}{print(sep)}; print(end)
+ }
+
+ def printRow(ts: List[Tree], sep: String): unit = printRow(ts, "", sep, "");
+
+ def printTypeParams(ts: List[AbsTypeDef]): unit =
+ if (!ts.isEmpty) {
+ print("["); printSeq(ts){printParam}{print(", ")}; print("]")
+ }
+
+ def printValueParams(ts: List[ValDef]): unit = {
+ print("(");
+ if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, nme.EMPTY.toTypeName);
+ printSeq(ts){printParam}{print(", ")};
+ print(")")
+ }
+
+ def printParam(tree: Tree): unit = tree match {
+ case ValDef(mods, name, tp, rhs) =>
+ print(symName(tree, name)); printOpt(": ", tp);
+ case AbsTypeDef(mods, name, lo, hi) =>
+ print(symName(tree, name));
+ printOpt(" >: ", lo); printOpt(" <: ", hi);
+ }
+
+ def printBlock(tree: Tree): unit = tree match {
+ case Block(_, _) => print(tree)
+ case _ => printColumn(List(tree), "{", ";", "}")
+ }
+
+ def symName(tree: Tree, name: Name): String =
+ if (tree.symbol != NoSymbol) tree.symbol.nameString else name.toString();
+
+ def printOpt(prefix: String, tree: Tree): unit =
+ if (!tree.isEmpty) { print(prefix); print(tree) }
+
+ def printModifiers(tree: Tree, mods: Modifiers): unit = {
+ if (tree.symbol == NoSymbol)
+ printFlags(mods.flags, mods.privateWithin)
+ else if (tree.symbol.privateWithin == null)
+ printFlags(tree.symbol.flags, nme.EMPTY.toTypeName)
+ else
+ printFlags(tree.symbol.flags, tree.symbol.privateWithin.name)
+ }
+
+ def printFlags(flags: long, privateWithin: Name): unit = {
+ val mask = if (settings.debug.value) -1 else PrintableFlags;
+ val suffixes: List[Pair[long, String]] =
+ if (privateWithin.isEmpty) List() else List(Pair(PRIVATE, privateWithin.toString()));
+ val s = flagsToString(flags & mask, suffixes);
+ if (s.length() != 0) print(s + " ")
+ }
+
+ def print(str: String): unit = out.print(str);
+ def print(name: Name): unit = print(name.toString());
+
+ def printRaw(tree: Tree): unit = {
+ tree match {
+ case EmptyTree =>
+ print("<empty>");
+
+ case ClassDef(mods, name, tparams, tp, impl) =>
+ printModifiers(tree, mods);
+ print((if (mods.hasFlag(TRAIT)) "trait " else "class ") + symName(tree, name));
+ printTypeParams(tparams);
+ printOpt(": ", tp); print(" extends "); print(impl);
+
+ case PackageDef(packaged, stats) =>
+ print("package "); print(packaged); printColumn(stats, " {", ";", "}")
+
+ case ModuleDef(mods, name, impl) =>
+ printModifiers(tree, mods); print("object " + symName(tree, name));
+ print(" extends "); print(impl);
+
+ case ValDef(mods, name, tp, rhs) =>
+ printModifiers(tree, mods);
+ print(if (mods.hasFlag(MUTABLE)) "var " else "val ");
+ print(symName(tree, name));
+ printOpt(": ", tp);
+ if (!mods.hasFlag(DEFERRED)) {
+ print(" = ");
+ if (rhs.isEmpty) print("_") else print(rhs)
+ }
+
+ case DefDef(mods, name, tparams, vparamss, tp, rhs) =>
+ printModifiers(tree, mods);
+ print("def " + symName(tree, name));
+ printTypeParams(tparams); vparamss foreach printValueParams;
+ printOpt(": ", tp); printOpt(" = ", rhs);
+
+ case AbsTypeDef(mods, name, lo, hi) =>
+ printModifiers(tree, mods); print("type "); printParam(tree);
+
+ case AliasTypeDef(mods, name, tparams, rhs) =>
+ printModifiers(tree, mods); print("type " + symName(tree, name));
+ printTypeParams(tparams); printOpt(" = ", rhs);
+
+ case LabelDef(name, params, rhs) =>
+ print(symName(tree, name)); printRow(params, "(", ",", ")"); printBlock(rhs);
+
+ case Import(expr, selectors) =>
+ def selectorToString(s: Pair[Name, Name]): String =
+ if (s._1 == nme.WILDCARD || s._1 == s._2) s._1.toString()
+ else s._1.toString() + "=>" + s._2.toString();
+ print("import "); print(expr);
+ print(selectors.map(selectorToString).mkString(".{", ", ", "}"))
+
+ case Attributed(attr, definition) =>
+ print("["); print(attr); print("]"); println; print(definition);
+
+ case DocDef(comment, definition) =>
+ print(comment); println; print(definition);
+
+ case Template(parents, body) =>
+ printRow(parents, " with ");
+ if (!body.isEmpty) printColumn(body, " {", ";", "}")
+
+ case Block(stats, expr) =>
+ printColumn(stats ::: List(expr), "{", ";", "}")
+
+ case Match(selector, cases) =>
+ print(selector); printColumn(cases, " match {", "", "}")
+
+ case CaseDef(pat, guard, body) =>
+ print("case "); print(pat); printOpt(" if ", guard);
+ print(" => "); print(body)
+
+ case Sequence(trees) =>
+ printRow(trees, "[", ", ", "]")
+
+ case Alternative(trees) =>
+ printRow(trees, "(", "| ", ")")
+
+ case Star(elem) =>
+ print("("); print(elem); print(")*");
+
+ case Bind(name, t) =>
+ print("("); print(symName(tree, name)); print(" @ "); print(t); print(")");
+
+ case ArrayValue(elemtpt, trees) =>
+ print("Array["); print(elemtpt); printRow(trees, "]{", ", ", "}")
+
+ case Function(vparams, body) =>
+ print("("); printValueParams(vparams); print(" => "); print(body); print(")")
+
+ case Assign(lhs, rhs) =>
+ print(lhs); print(" = "); print(rhs)
+
+ case If(cond, thenp, elsep) =>
+ print("if ("); print(cond); print(")"); indent; println;
+ print(thenp); undent;
+ if (!elsep.isEmpty) {
+ println; print("else"); indent; println; print(elsep); undent
+ }
+
+ case Return(expr) =>
+ print("return "); print(expr)
+
+ case Try(block, catches, finalizer) =>
+ print("try "); printBlock(block);
+ if (!catches.isEmpty) printColumn(catches, " catch {", "", "}");
+ printOpt(" finally ", finalizer)
+
+ case Throw(expr) =>
+ print("throw "); print(expr)
+
+ case New(tpe) =>
+ print("new "); print(tpe)
+
+ case Typed(expr, tp) =>
+ print("("); print(expr); print(") : "); print(tp);
+
+ case TypeApply(fun, targs) =>
+ print(fun); printRow(targs, "[", ", ", "]");
+
+ case Apply(fun, vargs) =>
+ print(fun); printRow(vargs, "(", ", ", ")");
+
+ case Super(qual, mixin) =>
+ if (!qual.isEmpty || tree.symbol != NoSymbol) print(symName(tree, qual) + ".");
+ print("super");
+ if (!mixin.isEmpty)
+ print("[" + mixin + "]")
+
+ case This(qual) =>
+ if (!qual.isEmpty) print(symName(tree, qual) + ".");
+ print("this");
+
+ case Select(qualifier, name) =>
+ print(qualifier); print("."); print(symName(tree, name))
+
+ case Ident(name) =>
+ print(symName(tree, name))
+
+ case Literal(x) =>
+ print(x.tag match {
+ case NullTag => "null"
+ case StringTag => "\"" + x.stringValue + "\""
+ case CharTag => "\'" + x.charValue + "\'"
+ case LongTag => x.longValue.toString() + "L";
+ case _ => x.value.toString()
+ })
+
+ case TypeTree() =>
+ if (tree.tpe == null) print("<type ?>")
+ else print(tree.tpe.toString());
+
+ case SingletonTypeTree(ref) =>
+ print(ref); print(".type")
+
+ case SelectFromTypeTree(qualifier, selector) =>
+ print(qualifier); print("#"); print(symName(tree, selector))
+
+ case CompoundTypeTree(templ) =>
+ print(templ)
+
+ case AppliedTypeTree(tp, args) =>
+ print(tp); printRow(args, "[", ", ", "]")
+ }
+ if (global.settings.printtypes.value && tree.isTerm && !tree.isEmpty) {
+ print("{"); print(if (tree.tpe == null) "<null>" else tree.tpe.toString()); print("}")
+ }
+ }
+
+ def print(tree: Tree): unit =
+ printRaw(
+ if (tree.isDef && tree.symbol != NoSymbol) {
+ tree match {
+ case ClassDef(_, _, _, _, impl) => ClassDef(tree.symbol, impl)
+ case ModuleDef(_, _, impl) => ModuleDef(tree.symbol, impl)
+// case ValDef(_, _, _, rhs) => ValDef(tree.symbol, rhs)
+ case DefDef(_, _, _, vparamss, _, rhs) => DefDef(tree.symbol, vparamss, rhs)
+ case AbsTypeDef(_, _, _, _) => AbsTypeDef(tree.symbol)
+ case AliasTypeDef(_, _, _, rhs) => AliasTypeDef(tree.symbol, rhs)
+ case _ => tree
+ }
+ } else tree);
+
+ def print(unit: CompilationUnit): unit = {
+ print("// Scala source: " + unit.source + "\n");
+ if (unit.body != null) {
+ print(unit.body); println
+ } else {
+ print("<null>")
+ }
+ println; flush
+ }
+
+ def printAll(): unit = {
+ print("[[syntax trees at end of " + phase + "]]");
+ for (val unit <- global.currentRun.units) print(unit)
+ }
+ }
+
+ def create(writer: PrintWriter): TreePrinter = new TreePrinter(writer);
+ def create(stream: OutputStream): TreePrinter = create(new PrintWriter(stream));
+ def create(): TreePrinter = create(System.out);
+}
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
new file mode 100644
index 0000000000..92b147c947
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -0,0 +1,1251 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.ast;
+
+import scala.tools.nsc.symtab.Flags;
+import java.io.StringWriter;
+import java.io.PrintWriter;
+import scala.tools.nsc.util.{Position,SourceFile};
+import symtab.Flags._;
+
+[_trait_] abstract class Trees: Global {
+
+ //statistics
+ var nodeCount = 0;
+
+ case class Modifiers(flags: int, privateWithin: Name) {
+ def isPrivate = ((flags & PRIVATE ) != 0);
+ def isProtected = ((flags & PROTECTED) != 0);
+ def isVariable = ((flags & MUTABLE) != 0);
+ def isPublic = !isPrivate && !isProtected;
+ def hasFlag(flag: int) = (flags & flag) != 0;
+ def | (flag: int): Modifiers = {
+ val flags1 = flags | flag;
+ if (flags1 == flags) this else Modifiers(flags1, privateWithin)
+ }
+ }
+
+ def Modifiers(flags: int): Modifiers = Modifiers(flags, nme.EMPTY.toTypeName);
+ def Modifiers(flags: long): Modifiers = Modifiers(flags.asInstanceOf[int]);
+
+ val NoMods = Modifiers(0);
+
+ abstract class Tree {
+
+ if (util.Statistics.enabled) nodeCount = nodeCount + 1;
+
+ private var posx: int = Position.NOPOS;
+
+ def pos = posx;
+
+ var tpe: Type = _;
+
+ def setPos(p: int): this.type = { posx = p; this }
+ def setType(tp: Type): this.type = { tpe = tp; this }
+
+ def symbol: Symbol = null;
+ def symbol_=(sym: Symbol): unit =
+ throw new Error("symbol_= inapplicable for " + this);
+ def setSymbol(sym: Symbol): this.type = { symbol = sym; this }
+
+ def hasSymbol = false;
+ def isDef = false;
+ def isTerm = false;
+ def isType = false;
+ def isEmpty = false;
+
+ override def toString(): String = {
+ val buffer = new StringWriter();
+ val printer = treePrinters.create(new PrintWriter(buffer));
+ printer.print(this); printer.flush;
+ buffer.toString()
+ }
+
+ override def hashCode(): int = super.hashCode();
+
+ override def equals(that: Any): boolean = that match {
+ case t: Tree => this eq t
+ case _ => false
+ }
+
+ def duplicate: this.type = (duplicator transform this).asInstanceOf[this.type];
+
+ def copyAttrs(tree: Tree): this.type = {
+ posx = tree.posx;
+ tpe = tree.tpe;
+ if (hasSymbol) symbol = tree.symbol;
+ this
+ }
+ }
+
+ [_trait_] abstract class SymTree extends Tree {
+ override def hasSymbol = true;
+ override var symbol: Symbol = NoSymbol;
+ }
+
+ abstract class DefTree extends SymTree {
+ def name: Name;
+ override def isDef = true;
+ }
+
+ trait TermTree extends Tree {
+ override def isTerm = true
+ }
+
+ trait TypTree extends Tree {
+ override def isType = true
+ }
+
+// ----- auxiliary objects and methods ------------------------------
+
+ private val duplicator = new Transformer {
+ override val copy = new StrictTreeCopier;
+ }
+
+ private def syntheticParams(owner: Symbol, formals: List[Type]): List[Symbol] = {
+ var cnt = 0;
+ def freshName() = { cnt = cnt + 1; newTermName("x$" + cnt) }
+ for (val formal <- formals) yield
+ owner.newValueParameter(owner.pos, freshName()).setInfo(formal);
+ }
+
+ private def syntheticParams(owner: Symbol, mtp: Type): List[List[Symbol]] = mtp match {
+ case PolyType(_, restp) =>
+ syntheticParams(owner, restp)
+ case MethodType(formals, restp) =>
+ syntheticParams(owner, formals) :: syntheticParams(owner, restp)
+ case _ =>
+ List()
+ }
+
+// def nextPhase = if (phase.id > globalPhase.id) phase else phase.next;
+
+// ----- tree node alternatives --------------------------------------
+
+ /** The empty tree */
+ case object EmptyTree extends TermTree {
+ tpe = NoType;
+ override def isEmpty = true;
+ }
+
+ abstract class MemberDef extends DefTree {
+ def mods: Modifiers;
+ def name: Name;
+ def keyword : String;
+ final def hasFlag(mask: long): boolean = (mods.flags & mask) != 0;
+
+ def namePos(source : SourceFile) : Int = if (pos == Position.NOPOS) Position.NOPOS else {
+ assert(keyword != null);
+ if (!source.beginsWith(pos, keyword + " ")) {
+ val p = new Position(source, pos);
+ // System.err.println("SYM=" + symbol + " KW=" + keyword + " LINE=" + p.lineContent + " TEXT=" + source.content(pos) + source.content(pos + 1));
+ if (true) return Position.NOPOS;
+ else throw new Error();
+ }
+ source.skipWhitespace(pos + keyword.length() + 1);
+ }
+ }
+
+ /** Package clause */
+ case class PackageDef(name: Name, stats: List[Tree])
+ extends MemberDef {
+ def mods = NoMods;
+ def keyword = "package";
+ }
+
+ def PackageDef(sym: Symbol, stats: List[Tree]): PackageDef =
+ PackageDef(sym.name, stats) setSymbol sym;
+
+
+ abstract class ImplDef extends MemberDef {
+ def impl: Template
+ }
+
+ /** Class definition */
+ case class ClassDef(mods: Modifiers, name: Name, tparams: List[AbsTypeDef], tpt: Tree, impl: Template)
+ extends ImplDef {
+ def keyword = "class";
+ }
+
+ def ClassDef(sym: Symbol, impl: Template): ClassDef =
+ posAssigner.atPos(sym.pos) {
+ ClassDef(Modifiers(sym.flags),
+ sym.name,
+ sym.typeParams map AbsTypeDef,
+ if (sym.thisSym == sym) EmptyTree else TypeTree(sym.typeOfThis),
+ impl) setSymbol sym
+ }
+
+ /** Construct class definition with given class symbol, value parameters, supercall arguments
+ * and template body.
+ * @param sym the class symbol
+ * @param vparamss the value parameters -- if they have symbols they should be owned by `sym'
+ * @param argss the supercall arguments
+ * @param body the template statements without primary constructor and value parameter fields.
+ */
+ def ClassDef(sym: Symbol, vparamss: List[List[ValDef]], argss: List[List[Tree]], body: List[Tree]): ClassDef =
+ ClassDef(sym, Template(sym.info.parents map TypeTree, vparamss, argss, body));
+
+ /** Singleton object definition */
+ case class ModuleDef(mods: Modifiers, name: Name, impl: Template)
+ extends ImplDef {
+ def keyword = "object";
+ }
+
+ def ModuleDef(sym: Symbol, impl: Template): ModuleDef =
+ posAssigner.atPos(sym.pos) {
+ ModuleDef(Modifiers(sym.flags), sym.name, impl)
+ }
+
+
+ abstract class ValOrDefDef extends MemberDef {
+ def tpt: Tree;
+ def rhs: Tree;
+ }
+
+ /** Value definition */
+ case class ValDef(mods: Modifiers, name: Name, tpt: Tree, rhs: Tree)
+ extends ValOrDefDef {
+ assert(tpt.isType, tpt);
+ assert(rhs.isTerm, rhs);
+ def keyword = if (mods.isVariable) "var" else "val";
+ override def namePos(source : SourceFile) =
+ if (pos == Position.NOPOS) Position.NOPOS;
+ else if (source.beginsWith(pos, "val ") || source.beginsWith(pos, "var ")) source.skipWhitespace(pos + ("val ").length());
+ else if (source.content(pos) == ',') source.skipWhitespace(pos + 1);
+ else pos;
+ }
+
+
+ def ValDef(sym: Symbol, rhs: Tree): ValDef = {
+ posAssigner.atPos(sym.pos) {
+ ValDef(Modifiers(sym.flags), sym.name, TypeTree(sym.tpe), rhs) setSymbol sym
+ }
+ }
+
+ def ValDef(sym: Symbol): ValDef = ValDef(sym, EmptyTree);
+
+ /** Method definition */
+ case class DefDef(mods: Modifiers, name: Name, tparams: List[AbsTypeDef],
+ vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree)
+ extends ValOrDefDef {
+ assert(tpt.isType);
+ assert(rhs.isTerm);
+ def keyword = "def";
+ }
+
+ def DefDef(sym: Symbol, vparamss: List[List[ValDef]], rhs: Tree): DefDef =
+ posAssigner.atPos(sym.pos) {
+ assert(sym != NoSymbol);
+ DefDef(Modifiers(sym.flags),
+ sym.name,
+ sym.typeParams map AbsTypeDef,
+ vparamss,
+ TypeTree(sym.tpe.finalResultType),
+ rhs) setSymbol sym
+ }
+
+ def DefDef(sym: Symbol, rhs: List[List[Symbol]] => Tree): DefDef = {
+ val vparamss = syntheticParams(sym, sym.tpe);
+ DefDef(sym, vparamss map (.map(ValDef)), rhs(vparamss));
+ }
+
+ /** Abstract type or type parameter */
+ case class AbsTypeDef(mods: Modifiers, name: Name, lo: Tree, hi: Tree)
+ extends DefTree {
+ def keyword = "";
+
+ override def setPos(pos : Int) : this.type = {
+ val ret = super.setPos(pos);
+ ret;
+ }
+ def namePos = pos - name.length;
+ }
+
+ def AbsTypeDef(sym: Symbol): AbsTypeDef =
+ posAssigner.atPos(sym.pos) {
+ AbsTypeDef(Modifiers(sym.flags), sym.name,
+ TypeTree(sym.info.bounds.lo), TypeTree(sym.info.bounds.hi))
+ }
+
+ /** Type alias */
+ case class AliasTypeDef(mods: Modifiers, name: Name, tparams: List[AbsTypeDef], rhs: Tree)
+ extends MemberDef {
+ def keyword = "type";
+ }
+
+ def AliasTypeDef(sym: Symbol, rhs: Tree): AliasTypeDef =
+ posAssigner.atPos(sym.pos) {
+ AliasTypeDef(Modifiers(sym.flags), sym.name, sym.typeParams map AbsTypeDef, rhs)
+ }
+
+ /** Labelled expression - the symbols in the array (must be Idents!)
+ * are those the label takes as argument
+ *
+ * The symbol that is given to the labeldef should have a MethodType
+ * (as if it were a nested function)
+ *
+ * jumps are apply nodes attributed with label symbol, the arguements
+ * will get assigned to the idents.
+ *
+ * note: on 2005-06-09 Martin, Iuli, Burak agreed to have forward
+ * jumps within a Block.
+ */
+ case class LabelDef(name: Name, params: List[Ident], rhs: Tree)
+ extends DefTree with TermTree {
+ assert(rhs.isTerm);
+ }
+
+ def LabelDef(sym: Symbol, params: List[Symbol], rhs: Tree): LabelDef =
+ posAssigner.atPos(sym.pos) {
+ LabelDef(sym.name, params map Ident, rhs) setSymbol sym
+ }
+
+ /** Import clause */
+ case class Import(expr: Tree, selectors: List[Pair[Name, Name]])
+ extends SymTree;
+
+ /** Attribuetd definition */
+ case class Attributed(attribute: Tree, definition: Tree)
+ extends Tree {
+ override def symbol: Symbol = definition.symbol;
+ override def symbol_=(sym: Symbol): unit = { definition.symbol = sym }
+ }
+
+ /** Documented definition, eliminated by analyzer */
+ case class DocDef(comment: String, definition: Tree)
+ extends Tree {
+ override def symbol: Symbol = definition.symbol;
+ override def symbol_=(sym: Symbol): unit = { definition.symbol = sym }
+ }
+
+ /** Instantiation template */
+ case class Template(parents: List[Tree], body: List[Tree])
+ extends SymTree {
+ // System.err.println("TEMPLATE: " + parents);
+ }
+
+ def Template(parents: List[Tree], vparamss: List[List[ValDef]], argss: List[List[Tree]], body: List[Tree]): Template = {
+ /** Add constructor to template */
+ var vparamss1 =
+ vparamss map (.map (vd =>
+ ValDef(Modifiers(vd.mods.flags & IMPLICIT | PARAM), vd.name, vd.tpt.duplicate, EmptyTree)));
+ if (vparamss1.isEmpty ||
+ !vparamss1.head.isEmpty && (vparamss1.head.head.mods.flags & IMPLICIT) != 0)
+ vparamss1 = List() :: vparamss1;
+ val superRef: Tree = Select(Super(nme.EMPTY.toTypeName, nme.EMPTY.toTypeName), nme.CONSTRUCTOR);
+ val superCall = (superRef /: argss) (Apply);
+ val constr: Tree = DefDef(NoMods, nme.CONSTRUCTOR, List(), vparamss1, TypeTree(), superCall);
+ Template(parents, List.flatten(vparamss) ::: constr :: body)
+ }
+
+ /** Block of expressions (semicolon separated expressions) */
+ case class Block(stats: List[Tree], expr: Tree)
+ extends TermTree;
+
+ /** Case clause in a pattern match, eliminated by TransMatch
+ * (except for occurences in switch statements)
+ */
+ case class CaseDef(pat: Tree, guard: Tree, body: Tree)
+ extends Tree;
+
+ /** casedef shorthand */
+ def CaseDef(pat: Tree, body: Tree): CaseDef = CaseDef(pat, EmptyTree, body);
+
+ /** Sequence of patterns (comma separated expressions), eliminated by TransMatch */
+ case class Sequence(trees: List[Tree])
+ extends TermTree;
+
+ /** Alternatives of patterns, eliminated by TransMatch, except for
+ * occurences in encoded Switch stmt (=remaining Match(CaseDef(...))
+ */
+ case class Alternative(trees: List[Tree])
+ extends TermTree;
+
+ /** Repetition of pattern, eliminated by TransMatch */
+ case class Star(elem: Tree)
+ extends TermTree;
+
+ /** Bind of a variable to a rhs pattern, eliminated by TransMatch */
+ case class Bind(name: Name, body: Tree)
+ extends DefTree;
+
+ def Bind(sym: Symbol, body: Tree): Bind =
+ Bind(sym.name, body) setSymbol sym;
+
+ /** Array of expressions, needs to be translated in backend,
+ */
+ case class ArrayValue(elemtpt: Tree, elems: List[Tree])
+ extends TermTree;
+
+ /** Anonymous function, eliminated by analyzer */
+ case class Function(vparams: List[ValDef], body: Tree)
+ extends TermTree with SymTree;
+
+ /** Assignment */
+ case class Assign(lhs: Tree, rhs: Tree)
+ extends TermTree;
+
+ /** Conditional expression */
+ case class If(cond: Tree, thenp: Tree, elsep: Tree)
+ extends TermTree;
+
+ /** Pattern matching expression (before TransMatch)
+ * Switch statements (after TransMatch)
+ *
+ * after TM, cases will satisfy the following constraints:
+ * - all guards are EmptyTree,
+ * - all patterns will be either Literal(Constant(x:Int)) or Alternative(lit|...|lit)
+ * - except for an "otherwise" branch, which has pattern Ident(nme.WILDCARD)
+ */
+ case class Match(selector: Tree, cases: List[CaseDef]) extends TermTree;
+
+ /** Return expression */
+ case class Return(expr: Tree)
+ extends TermTree with SymTree;
+
+ case class Try(block: Tree, catches: List[CaseDef], finalizer: Tree)
+ extends TermTree;
+
+ /** Throw expression */
+ case class Throw(expr: Tree)
+ extends TermTree;
+
+ /** Object instantiation
+ * @param tpt a class type
+ * one should always use factory method below to build a user level new.
+ */
+ case class New(tpt: Tree)
+ extends TermTree {
+ assert(tpt.isType)
+ }
+
+ /** Factory method for object creation <new tpt(args_1)...(args_n)> */
+ def New(tpt: Tree, argss: List[List[Tree]]): Tree = {
+ assert(!argss.isEmpty);
+ val superRef: Tree = Select(New(tpt), nme.CONSTRUCTOR);
+ (superRef /: argss) (Apply);
+ }
+
+ /** Type annotation, eliminated by explicit outer */
+ case class Typed(expr: Tree, tpt: Tree)
+ extends TermTree;
+
+ abstract class GenericApply(val fun0: Tree, val args0: List[Tree]) extends TermTree;
+
+
+ /** Type application */
+ case class TypeApply(fun: Tree, args: List[Tree])
+ extends GenericApply(fun, args) {
+ override def symbol: Symbol = fun.symbol;
+ override def symbol_=(sym: Symbol): unit = { fun.symbol = sym }
+ }
+
+ /** Value application */
+ case class Apply(fun: Tree, args: List[Tree])
+ extends GenericApply(fun, args) {
+ override def symbol: Symbol = fun.symbol;
+ override def symbol_=(sym: Symbol): unit = { fun.symbol = sym }
+ }
+
+ /** Super reference */
+ case class Super(qual: Name, mixin: Name)
+ extends TermTree with SymTree;
+
+ def Super(sym: Symbol, mixin: Name): Tree = Super(sym.name, mixin) setSymbol sym;
+
+ /** Self reference */
+ case class This(qual: Name)
+ extends TermTree with SymTree;
+
+ def This(sym: Symbol): Tree = This(sym.name) setSymbol sym;
+
+ /** Designator */
+ case class Select(qualifier: Tree, selector: Name)
+ extends SymTree {
+ override def isTerm = selector.isTermName;
+ override def isType = selector.isTypeName;
+
+ override def setPos(pos : Int) : this.type = {
+ val ret = super.setPos(pos);
+ // System.err.println("SELECT_POS: " + pos + " " + this);
+ // if (pos == 74) Thread.dumpStack();
+ ret;
+ }
+
+
+ }
+
+ def Select(qualifier: Tree, sym: Symbol): Select =
+ Select(qualifier, sym.name) setSymbol sym;
+
+ /** Identifier */
+ case class Ident(name: Name)
+ extends SymTree {
+ override def isTerm = name.isTermName;
+ override def isType = name.isTypeName;
+
+ override def setPos(p : Int) : this.type = {
+ val ret = super.setPos(p);
+ ret;
+ }
+
+ }
+
+ def Ident(sym: Symbol): Ident =
+ Ident(sym.name) setSymbol sym;
+
+ /** Literal */
+ case class Literal(value: Constant)
+ extends TermTree {
+ assert(value != null)
+ }
+
+ def Literal(value: Any): Literal =
+ Literal(Constant(value));
+
+ /** General type term, introduced by RefCheck. */
+ case class TypeTree() extends TypTree {
+ var original : Tree = _;
+
+ def setOriginal(tree : Tree) : this.type = {
+ tree match {
+ case tt : TypeTree =>
+ System.err.println("Illegal: " + this + " to " + tree);
+ Thread.dumpStack();
+ case _ =>
+ }
+
+ original = tree;
+ setPos(tree.pos);
+ }
+ override def setPos(pos : Int) : this.type = {
+ val ret = super.setPos(pos);
+ if (false && pos == 151 && original == null) {
+ System.err.println("TYPE: " + this + " POS=" + pos + " TPE=" + tpe);
+ Thread.dumpStack();
+ }
+ ret;
+ }
+
+
+ override def isEmpty = tpe == null || tpe == NoType;
+ }
+
+ def TypeTree(tp: Type): TypeTree = TypeTree() setType tp;
+ // def TypeTree(tp: Type, tree : Tree): TypeTree = TypeTree(tree) setType tp;
+
+
+ /** Singleton type, eliminated by RefCheck */
+ case class SingletonTypeTree(ref: Tree)
+ extends TypTree;
+
+ /** Type selection, eliminated by RefCheck */
+ case class SelectFromTypeTree(qualifier: Tree, selector: Name)
+ extends TypTree with SymTree;
+
+ /** Intersection type, eliminated by RefCheck */
+ case class CompoundTypeTree(templ: Template)
+ extends TypTree;
+
+ /** Applied type, eliminated by RefCheck */
+ case class AppliedTypeTree(tpt: Tree, args: List[Tree])
+ extends TypTree {
+ override def symbol: Symbol = tpt.symbol;
+ override def symbol_=(sym: Symbol): unit = { tpt.symbol = sym }
+ }
+
+/* A standard pattern match
+ case EmptyTree =>
+ case PackageDef(name, stats) =>
+ case ClassDef(mods, name, tparams, tpt, impl) =>
+ case ModuleDef(mods, name, impl) => (eliminated by refcheck)
+ case ValDef(mods, name, tpt, rhs) =>
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ case AbsTypeDef(mods, name, lo, hi) => (eliminated by erasure)
+ case AliasTypeDef(mods, name, tparams, rhs) => (eliminated by erasure)
+ case LabelDef(name, params, rhs) =>
+ case Import(expr, selectors) => (eliminated by typecheck)
+ case Attributed(attribute, definition) => (eliminated by typecheck)
+ case DocDef(comment, definition) => (eliminated by typecheck)
+ case Template(parents, body) =>
+ case Block(stats, expr) =>
+ case CaseDef(pat, guard, body) => (eliminated by transmatch)
+ case Sequence(trees) => (eliminated by transmatch)
+ case Alternative(trees) => (eliminated by transmatch)
+ case Star(elem) => (eliminated by transmatch)
+ case Bind(name, body) => (eliminated by transmatch)
+ case ArrayValue(elemtpt, trees) => (introduced by uncurry)
+ case Function(vparams, body) => (eliminated by typecheck)
+ case Assign(lhs, rhs) =>
+ case If(cond, thenp, elsep) =>
+ case Match(selector, cases) =>
+ case Return(expr) =>
+ case Try(block, catches, finalizer) =>
+ case Throw(expr) =>
+ case New(tpt) =>
+ case Typed(expr, tpt) => (eliminated by erasure)
+ case TypeApply(fun, args) =>
+ case Apply(fun, args) =>
+ case Super(qual, mixin) =>
+ case This(qual) =>
+ case Select(qualifier, selector) =>
+ case Ident(name) =>
+ case Literal(value) =>
+ case TypeTree() =>
+ case SingletonTypeTree(ref) => (eliminated by typecheck)
+ case SelectFromTypeTree(qualifier, selector) => (eliminated by typecheck)
+ case CompoundTypeTree(templ: Template) => (eliminated by typecheck)
+ case AppliedTypeTree(tpt, args) => (eliminated by typecheck)
+*/
+
+ trait TreeCopier {
+ def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[AbsTypeDef], tpt: Tree, impl: Template): ClassDef;
+ def PackageDef(tree: Tree, name: Name, stats: List[Tree]): PackageDef;
+ def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template): ModuleDef;
+ def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree): ValDef;
+ def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[AbsTypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): DefDef;
+ def AbsTypeDef(tree: Tree, mods: Modifiers, name: Name, lo: Tree, hi: Tree): AbsTypeDef;
+ def AliasTypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[AbsTypeDef], rhs: Tree): AliasTypeDef;
+ def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree): LabelDef;
+ def Import(tree: Tree, expr: Tree, selectors: List[Pair[Name, Name]]): Import;
+ def Attributed(tree: Tree, attribute: Tree, definition: Tree): Attributed;
+ def DocDef(tree: Tree, comment: String, definition: Tree): DocDef;
+ def Template(tree: Tree, parents: List[Tree], body: List[Tree]): Template;
+ def Block(tree: Tree, stats: List[Tree], expr: Tree): Block;
+ def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree): CaseDef;
+ def Sequence(tree: Tree, trees: List[Tree]): Sequence;
+ def Alternative(tree: Tree, trees: List[Tree]): Alternative;
+ def Star(tree: Tree, elem: Tree): Star;
+ def Bind(tree: Tree, name: Name, body: Tree): Bind;
+ def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]): ArrayValue;
+ def Function(tree: Tree, vparams: List[ValDef], body: Tree): Function;
+ def Assign(tree: Tree, lhs: Tree, rhs: Tree): Assign;
+ def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree): If;
+ def Match(tree: Tree, selector: Tree, cases: List[CaseDef]): Match;
+ def Return(tree: Tree, expr: Tree): Return;
+ def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree): Try;
+ def Throw(tree: Tree, expr: Tree): Throw;
+ def New(tree: Tree, tpt: Tree): New;
+ def Typed(tree: Tree, expr: Tree, tpt: Tree): Typed;
+ def TypeApply(tree: Tree, fun: Tree, args: List[Tree]): TypeApply;
+ def Apply(tree: Tree, fun: Tree, args: List[Tree]): Apply;
+ def Super(tree: Tree, qual: Name, mixin: Name): Super;
+ def This(tree: Tree, qual: Name): This;
+ def Select(tree: Tree, qualifier: Tree, selector: Name): Select;
+ def Ident(tree: Tree, name: Name): Ident;
+ def Literal(tree: Tree, value: Constant): Literal;
+ def TypeTree(tree: Tree): TypeTree;
+ def SingletonTypeTree(tree: Tree, ref: Tree): SingletonTypeTree;
+ def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name): SelectFromTypeTree;
+ def CompoundTypeTree(tree: Tree, templ: Template): CompoundTypeTree;
+ def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]): AppliedTypeTree;
+ }
+
+ class StrictTreeCopier extends TreeCopier {
+ def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[AbsTypeDef], tpt: Tree, impl: Template) =
+ new ClassDef(mods, name, tparams, tpt, impl).copyAttrs(tree);
+ def PackageDef(tree: Tree, name: Name, stats: List[Tree]) =
+ new PackageDef(name, stats).copyAttrs(tree);
+ def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template) =
+ new ModuleDef(mods, name, impl).copyAttrs(tree);
+ def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree) =
+ new ValDef(mods, name, tpt, rhs).copyAttrs(tree);
+ def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[AbsTypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) =
+ new DefDef(mods, name, tparams, vparamss, tpt, rhs).copyAttrs(tree);
+ def AbsTypeDef(tree: Tree, mods: Modifiers, name: Name, lo: Tree, hi: Tree) =
+ new AbsTypeDef(mods, name, lo, hi).copyAttrs(tree);
+ def AliasTypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[AbsTypeDef], rhs: Tree) =
+ new AliasTypeDef(mods, name, tparams, rhs).copyAttrs(tree);
+ def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree) =
+ new LabelDef(name, params, rhs).copyAttrs(tree);
+ def Import(tree: Tree, expr: Tree, selectors: List[Pair[Name, Name]]) =
+ new Import(expr, selectors).copyAttrs(tree);
+ def Attributed(tree: Tree, attribute: Tree, definition: Tree) =
+ new Attributed(attribute, definition).copyAttrs(tree);
+ def DocDef(tree: Tree, comment: String, definition: Tree) =
+ new DocDef(comment, definition).copyAttrs(tree);
+ def Template(tree: Tree, parents: List[Tree], body: List[Tree]) =
+ new Template(parents, body).copyAttrs(tree);
+ def Block(tree: Tree, stats: List[Tree], expr: Tree) =
+ new Block(stats, expr).copyAttrs(tree);
+ def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree) =
+ new CaseDef(pat, guard, body).copyAttrs(tree);
+ def Sequence(tree: Tree, trees: List[Tree]) =
+ new Sequence(trees).copyAttrs(tree);
+ def Alternative(tree: Tree, trees: List[Tree]) =
+ new Alternative(trees).copyAttrs(tree);
+ def Star(tree: Tree, elem: Tree) =
+ new Star(elem).copyAttrs(tree);
+ def Bind(tree: Tree, name: Name, body: Tree) =
+ new Bind(name, body).copyAttrs(tree);
+ def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]) =
+ new ArrayValue(elemtpt, trees).copyAttrs(tree);
+ def Function(tree: Tree, vparams: List[ValDef], body: Tree) =
+ new Function(vparams, body).copyAttrs(tree);
+ def Assign(tree: Tree, lhs: Tree, rhs: Tree) =
+ new Assign(lhs, rhs).copyAttrs(tree);
+ def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) =
+ new If(cond, thenp, elsep).copyAttrs(tree);
+ def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) =
+ new Match(selector, cases).copyAttrs(tree);
+ def Return(tree: Tree, expr: Tree) =
+ new Return(expr).copyAttrs(tree);
+ def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree) =
+ new Try(block, catches, finalizer).copyAttrs(tree);
+ def Throw(tree: Tree, expr: Tree) =
+ new Throw(expr).copyAttrs(tree);
+ def New(tree: Tree, tpt: Tree) =
+ new New(tpt).copyAttrs(tree);
+ def Typed(tree: Tree, expr: Tree, tpt: Tree) =
+ new Typed(expr, tpt).copyAttrs(tree);
+ def TypeApply(tree: Tree, fun: Tree, args: List[Tree]) =
+ new TypeApply(fun, args).copyAttrs(tree);
+ def Apply(tree: Tree, fun: Tree, args: List[Tree]) =
+ new Apply(fun, args).copyAttrs(tree);
+ def Super(tree: Tree, qual: Name, mixin: Name) =
+ new Super(qual, mixin).copyAttrs(tree);
+ def This(tree: Tree, qual: Name) =
+ new This(qual).copyAttrs(tree);
+ def Select(tree: Tree, qualifier: Tree, selector: Name) =
+ new Select(qualifier, selector).copyAttrs(tree);
+ def Ident(tree: Tree, name: Name) =
+ new Ident(name).copyAttrs(tree);
+ def Literal(tree: Tree, value: Constant) =
+ new Literal(value).copyAttrs(tree);
+ def TypeTree(tree: Tree) =
+ new TypeTree().copyAttrs(tree);
+ def SingletonTypeTree(tree: Tree, ref: Tree) =
+ new SingletonTypeTree(ref).copyAttrs(tree);
+ def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name) =
+ new SelectFromTypeTree(qualifier, selector).copyAttrs(tree);
+ def CompoundTypeTree(tree: Tree, templ: Template) =
+ new CompoundTypeTree(templ).copyAttrs(tree);
+ def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]) =
+ new AppliedTypeTree(tpt, args).copyAttrs(tree)
+ }
+
+ class LazyTreeCopier(copy: TreeCopier) extends TreeCopier {
+ def this() = this(new StrictTreeCopier);
+ def ClassDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[AbsTypeDef], tpt: Tree, impl: Template) = tree match {
+ case t @ ClassDef(mods0, name0, tparams0, tpt0, impl0)
+ if (mods0 == mods && (name0 == name) && (tparams0 == tparams) && (tpt0 == tpt) && (impl0 == impl)) => t
+ case _ => copy.ClassDef(tree, mods, name, tparams, tpt, impl)
+ }
+ def PackageDef(tree: Tree, name: Name, stats: List[Tree]) = tree match {
+ case t @ PackageDef(name0, stats0)
+ if ((name0 == name) && (stats0 == stats)) => t
+ case _ => copy.PackageDef(tree, name, stats)
+ }
+ def ModuleDef(tree: Tree, mods: Modifiers, name: Name, impl: Template) = tree match {
+ case t @ ModuleDef(mods0, name0, impl0)
+ if (mods0 == mods && (name0 == name) && (impl0 == impl)) => t
+ case _ => copy.ModuleDef(tree, mods, name, impl)
+ }
+ def ValDef(tree: Tree, mods: Modifiers, name: Name, tpt: Tree, rhs: Tree) = tree match {
+ case t @ ValDef(mods0, name0, tpt0, rhs0)
+ if (mods0 == mods && (name0 == name) && (tpt0 == tpt) && (rhs0 == rhs)) => t
+ case _ => copy.ValDef(tree, mods, name, tpt, rhs)
+ }
+ def DefDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[AbsTypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) = tree match {
+ case t @ DefDef(mods0, name0, tparams0, vparamss0, tpt0, rhs0)
+ if (mods0 == mods && (name0 == name) && (tparams0 == tparams) && (vparamss0 == vparamss) && (tpt0 == tpt) && (rhs == rhs0)) => t
+ case _ => copy.DefDef(tree, mods, name, tparams, vparamss, tpt, rhs)
+ }
+ def AbsTypeDef(tree: Tree, mods: Modifiers, name: Name, lo: Tree, hi: Tree) = tree match {
+ case t @ AbsTypeDef(mods0, name0, lo0, hi0)
+ if (mods0 == mods && (name0 == name) && (lo0 == lo) && (hi0 == hi)) => t
+ case _ => copy.AbsTypeDef(tree, mods, name, lo, hi)
+ }
+ def AliasTypeDef(tree: Tree, mods: Modifiers, name: Name, tparams: List[AbsTypeDef], rhs: Tree) = tree match {
+ case t @ AliasTypeDef(mods0, name0, tparams0, rhs0)
+ if (mods0 == mods && (name0 == name) && (tparams0 == tparams) && (rhs0 == rhs)) => t
+ case _ => copy.AliasTypeDef(tree, mods, name, tparams, rhs)
+ }
+ def LabelDef(tree: Tree, name: Name, params: List[Ident], rhs: Tree) = tree match {
+ case t @ LabelDef(name0, params0, rhs0)
+ if ((name0 == name) && (params0 == params) && (rhs0 == rhs)) => t
+ case _ => copy.LabelDef(tree, name, params, rhs)
+ }
+ def Import(tree: Tree, expr: Tree, selectors: List[Pair[Name, Name]]) = tree match {
+ case t @ Import(expr0, selectors0)
+ if ((expr0 == expr) && (selectors0 == selectors)) => t
+ case _ => copy.Import(tree, expr, selectors)
+ }
+ def Attributed(tree: Tree, attribute: Tree, definition: Tree) = tree match {
+ case t @ Attributed(attribute0, definition0)
+ if ((attribute0 == attribute) && (definition0 == definition)) => t
+ case _ => copy.Attributed(tree, attribute, definition)
+ }
+ def DocDef(tree: Tree, comment: String, definition: Tree) = tree match {
+ case t @ DocDef(comment0, definition0)
+ if ((comment0 == comment) && (definition0 == definition)) => t
+ case _ => copy.DocDef(tree, comment, definition)
+ }
+ def Template(tree: Tree, parents: List[Tree], body: List[Tree]) = tree match {
+ case t @ Template(parents0, body0)
+ if ((parents0 == parents) && (body0 == body)) => t
+ case _ => copy.Template(tree, parents, body)
+ }
+ def Block(tree: Tree, stats: List[Tree], expr: Tree) = tree match {
+ case t @ Block(stats0, expr0)
+ if ((stats0 == stats) && (expr0 == expr)) => t
+ case _ => copy.Block(tree, stats, expr)
+ }
+ def CaseDef(tree: Tree, pat: Tree, guard: Tree, body: Tree) = tree match {
+ case t @ CaseDef(pat0, guard0, body0)
+ if ((pat0 == pat) && (guard0 == guard) && (body0 == body)) => t
+ case _ => copy.CaseDef(tree, pat, guard, body)
+ }
+ def Sequence(tree: Tree, trees: List[Tree]) = tree match {
+ case t @ Sequence(trees0)
+ if ((trees0 == trees)) => t
+ case _ => copy.Sequence(tree, trees)
+ }
+ def Alternative(tree: Tree, trees: List[Tree]) = tree match {
+ case t @ Alternative(trees0)
+ if ((trees0 == trees)) => t
+ case _ => copy.Alternative(tree, trees)
+ }
+ def Star(tree: Tree, elem: Tree) = tree match {
+ case t @ Star(elem0)
+ if ((elem0 == elem)) => t
+ case _ => copy.Star(tree, elem)
+ }
+ def Bind(tree: Tree, name: Name, body: Tree) = tree match {
+ case t @ Bind(name0, body0)
+ if ((name0 == name) && (body0 == body)) => t
+ case _ => copy.Bind(tree, name, body)
+ }
+ def ArrayValue(tree: Tree, elemtpt: Tree, trees: List[Tree]) = tree match {
+ case t @ ArrayValue(elemtpt0, trees0)
+ if ((elemtpt0 == elemtpt) && (trees0 == trees)) => t
+ case _ => copy.ArrayValue(tree, elemtpt, trees)
+ }
+ def Function(tree: Tree, vparams: List[ValDef], body: Tree) = tree match {
+ case t @ Function(vparams0, body0)
+ if ((vparams0 == vparams) && (body0 == body)) => t
+ case _ => copy.Function(tree, vparams, body)
+ }
+ def Assign(tree: Tree, lhs: Tree, rhs: Tree) = tree match {
+ case t @ Assign(lhs0, rhs0)
+ if ((lhs0 == lhs) && (rhs0 == rhs)) => t
+ case _ => copy.Assign(tree, lhs, rhs)
+ }
+ def If(tree: Tree, cond: Tree, thenp: Tree, elsep: Tree) = tree match {
+ case t @ If(cond0, thenp0, elsep0)
+ if ((cond0 == cond) && (thenp0 == thenp) && (elsep0 == elsep)) => t
+ case _ => copy.If(tree, cond, thenp, elsep)
+ }
+ def Match(tree: Tree, selector: Tree, cases: List[CaseDef]) = tree match {
+ case t @ Match(selector0, cases0)
+ if ((selector0 == selector) && (cases0 == cases)) => t
+ case _ => copy.Match(tree, selector, cases)
+ }
+ def Return(tree: Tree, expr: Tree) = tree match {
+ case t @ Return(expr0)
+ if ((expr0 == expr)) => t
+ case _ => copy.Return(tree, expr)
+ }
+ def Try(tree: Tree, block: Tree, catches: List[CaseDef], finalizer: Tree) = tree match {
+ case t @ Try(block0, catches0, finalizer0)
+ if ((block0 == block) && (catches0 == catches) && (finalizer0 == finalizer)) => t
+ case _ => copy.Try(tree, block, catches, finalizer)
+ }
+ def Throw(tree: Tree, expr: Tree) = tree match {
+ case t @ Throw(expr0)
+ if ((expr0 == expr)) => t
+ case _ => copy.Throw(tree, expr)
+ }
+ def New(tree: Tree, tpt: Tree) = tree match {
+ case t @ New(tpt0)
+ if ((tpt0 == tpt)) => t
+ case _ => copy.New(tree, tpt)
+ }
+ def Typed(tree: Tree, expr: Tree, tpt: Tree) = tree match {
+ case t @ Typed(expr0, tpt0)
+ if ((expr0 == expr) && (tpt0 == tpt)) => t
+ case _ => copy.Typed(tree, expr, tpt)
+ }
+ def TypeApply(tree: Tree, fun: Tree, args: List[Tree]) = tree match {
+ case t @ TypeApply(fun0, args0)
+ if ((fun0 == fun) && (args0 == args)) => t
+ case _ => copy.TypeApply(tree, fun, args)
+ }
+ def Apply(tree: Tree, fun: Tree, args: List[Tree]) = tree match {
+ case t @ Apply(fun0, args0)
+ if ((fun0 == fun) && (args0 == args)) => t
+ case _ => copy.Apply(tree, fun, args)
+ }
+ def Super(tree: Tree, qual: Name, mixin: Name) = tree match {
+ case t @ Super(qual0, mixin0)
+ if ((qual0 == qual) && (mixin0 == mixin)) => t
+ case _ => copy.Super(tree, qual, mixin)
+ }
+ def This(tree: Tree, qual: Name) = tree match {
+ case t @ This(qual0)
+ if ((qual0 == qual)) => t
+ case _ => copy.This(tree, qual)
+ }
+ def Select(tree: Tree, qualifier: Tree, selector: Name) = tree match {
+ case t @ Select(qualifier0, selector0)
+ if ((qualifier0 == qualifier) && (selector0 == selector)) => t
+ case _ => copy.Select(tree, qualifier, selector)
+ }
+ def Ident(tree: Tree, name: Name) = tree match {
+ case t @ Ident(name0)
+ if ((name0 == name)) => t
+ case _ => copy.Ident(tree, name)
+ }
+ def Literal(tree: Tree, value: Constant) = tree match {
+ case t @ Literal(value0)
+ if (value0 == value) => t
+ case _ => copy.Literal(tree, value)
+ }
+ def TypeTree(tree: Tree) = tree match {
+ case t @ TypeTree() => t
+ case _ => copy.TypeTree(tree)
+ }
+ def SingletonTypeTree(tree: Tree, ref: Tree) = tree match {
+ case t @ SingletonTypeTree(ref0)
+ if ((ref0 == ref)) => t
+ case _ => copy.SingletonTypeTree(tree, ref)
+ }
+ def SelectFromTypeTree(tree: Tree, qualifier: Tree, selector: Name) = tree match {
+ case t @ SelectFromTypeTree(qualifier0, selector0)
+ if ((qualifier0 == qualifier) && (selector0 == selector)) => t
+ case _ => copy.SelectFromTypeTree(tree, qualifier, selector)
+ }
+ def CompoundTypeTree(tree: Tree, templ: Template) = tree match {
+ case t @ CompoundTypeTree(templ0)
+ if (templ0 == templ) => t
+ case _ => copy.CompoundTypeTree(tree, templ)
+ }
+ def AppliedTypeTree(tree: Tree, tpt: Tree, args: List[Tree]) = tree match {
+ case t @ AppliedTypeTree(tpt0, args0)
+ if ((tpt0 == tpt) && (args0 == args)) => t
+ case _ => copy.AppliedTypeTree(tree, tpt, args)
+ }
+ }
+
+ abstract class Transformer {
+ val copy: TreeCopier = new LazyTreeCopier;
+ protected var currentOwner: Symbol = definitions.RootClass;
+ def transform(tree: Tree): Tree = tree match {
+ case EmptyTree =>
+ tree
+ case PackageDef(name, stats) =>
+ atOwner(tree.symbol.moduleClass) {
+ copy.PackageDef(tree, name, transformStats(stats, currentOwner))
+ }
+ case ClassDef(mods, name, tparams, tpt, impl) =>
+ atOwner(tree.symbol) {
+ copy.ClassDef(tree, mods, name, transformAbsTypeDefs(tparams), transform(tpt), transformTemplate(impl))
+ }
+ case ModuleDef(mods, name, impl) =>
+ atOwner(tree.symbol.moduleClass) {
+ copy.ModuleDef(tree, mods, name, transformTemplate(impl))
+ }
+ case ValDef(mods, name, tpt, rhs) =>
+ atOwner(tree.symbol) {
+ copy.ValDef(tree, mods, name, transform(tpt), transform(rhs))
+ }
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ atOwner(tree.symbol) {
+ copy.DefDef(
+ tree, mods, name, transformAbsTypeDefs(tparams), transformValDefss(vparamss), transform(tpt), transform(rhs))
+ }
+ case AbsTypeDef(mods, name, lo, hi) =>
+ atOwner(tree.symbol) {
+ copy.AbsTypeDef(tree, mods, name, transform(lo), transform(hi))
+ }
+ case AliasTypeDef(mods, name, tparams, rhs) =>
+ atOwner(tree.symbol) {
+ copy.AliasTypeDef(tree, mods, name, transformAbsTypeDefs(tparams), transform(rhs))
+ }
+ case LabelDef(name, params, rhs) =>
+ copy.LabelDef(tree, name, transformIdents(params), transform(rhs)) //bq: Martin, once, atOwner(...) works, also change `LamdaLifter.proxy'
+ case Import(expr, selectors) =>
+ copy.Import(tree, transform(expr), selectors)
+ case Attributed(attribute, definition) =>
+ copy.Attributed(tree, transform(attribute), transform(definition))
+ case DocDef(comment, definition) =>
+ copy.DocDef(tree, comment, transform(definition))
+ case Template(parents, body) =>
+ copy.Template(tree, transformTrees(parents), transformStats(body, tree.symbol))
+ case Block(stats, expr) =>
+ copy.Block(tree, transformStats(stats, currentOwner), transform(expr))
+ case CaseDef(pat, guard, body) =>
+ copy.CaseDef(tree, transform(pat), transform(guard), transform(body))
+ case Sequence(trees) =>
+ copy.Sequence(tree, transformTrees(trees))
+ case Alternative(trees) =>
+ copy.Alternative(tree, transformTrees(trees))
+ case Star(elem) =>
+ copy.Star(tree, transform(elem))
+ case Bind(name, body) =>
+ copy.Bind(tree, name, transform(body))
+ case ArrayValue(elemtpt, trees) =>
+ copy.ArrayValue(tree, transform(elemtpt), transformTrees(trees))
+ case Function(vparams, body) =>
+ copy.Function(tree, transformValDefs(vparams), transform(body))
+ case Assign(lhs, rhs) =>
+ copy.Assign(tree, transform(lhs), transform(rhs))
+ case If(cond, thenp, elsep) =>
+ copy.If(tree, transform(cond), transform(thenp), transform(elsep))
+ case Match(selector, cases) =>
+ copy.Match(tree, transform(selector), transformCaseDefs(cases))
+ case Return(expr) =>
+ copy.Return(tree, transform(expr))
+ case Try(block, catches, finalizer) =>
+ copy.Try(tree, transform(block), transformCaseDefs(catches), transform(finalizer))
+ case Throw(expr) =>
+ copy.Throw(tree, transform(expr))
+ case New(tpt) =>
+ copy.New(tree, transform(tpt))
+ case Typed(expr, tpt) =>
+ copy.Typed(tree, transform(expr), transform(tpt))
+ case TypeApply(fun, args) =>
+ copy.TypeApply(tree, transform(fun), transformTrees(args))
+ case Apply(fun, args) =>
+ copy.Apply(tree, transform(fun), transformTrees(args))
+ case Super(qual, mixin) =>
+ copy.Super(tree, qual, mixin)
+ case This(qual) =>
+ copy.This(tree, qual)
+ case Select(qualifier, selector) =>
+ copy.Select(tree, transform(qualifier), selector)
+ case Ident(name) =>
+ copy.Ident(tree, name)
+ case Literal(value) =>
+ copy.Literal(tree, value)
+ case TypeTree() =>
+ copy.TypeTree(tree)
+ case SingletonTypeTree(ref) =>
+ copy.SingletonTypeTree(tree, transform(ref))
+ case SelectFromTypeTree(qualifier, selector) =>
+ copy.SelectFromTypeTree(tree, transform(qualifier), selector)
+ case CompoundTypeTree(templ) =>
+ copy.CompoundTypeTree(tree, transformTemplate(templ))
+ case AppliedTypeTree(tpt, args) =>
+ copy.AppliedTypeTree(tree, transform(tpt), transformTrees(args))
+ }
+
+ def transformTrees(trees: List[Tree]): List[Tree] =
+ List.mapConserve(trees)(transform);
+ def transformTemplate(tree: Template): Template =
+ transform(tree: Tree).asInstanceOf[Template];
+ def transformAbsTypeDefs(trees: List[AbsTypeDef]): List[AbsTypeDef] =
+ List.mapConserve(trees)(tree => transform(tree).asInstanceOf[AbsTypeDef]);
+ def transformValDefs(trees: List[ValDef]): List[ValDef] =
+ List.mapConserve(trees)(tree => transform(tree).asInstanceOf[ValDef]);
+ def transformValDefss(treess: List[List[ValDef]]): List[List[ValDef]] =
+ List.mapConserve(treess)(tree => transformValDefs(tree));
+ def transformCaseDefs(trees: List[CaseDef]): List[CaseDef] =
+ List.mapConserve(trees)(tree => transform(tree).asInstanceOf[CaseDef]);
+ def transformIdents(trees: List[Ident]): List[Ident] =
+ List.mapConserve(trees)(tree => transform(tree).asInstanceOf[Ident]);
+ def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] =
+ List.mapConserve(stats)(stat =>
+ if (exprOwner != currentOwner && stat.isTerm) atOwner(exprOwner)(transform(stat))
+ else transform(stat)) filter (EmptyTree !=);
+ def transformUnit(unit: CompilationUnit): unit = { unit.body = transform(unit.body) }
+
+ def atOwner[A](owner: Symbol)(trans: => A): A = {
+ val prevOwner = currentOwner;
+ currentOwner = owner;
+ val result = trans;
+ currentOwner = prevOwner;
+ result
+ }
+ }
+
+ class Traverser {
+ protected var currentOwner: Symbol = definitions.RootClass;
+ def traverse(tree: Tree): unit = tree match {
+ case EmptyTree =>
+ ;
+ case PackageDef(name, stats) =>
+ atOwner(tree.symbol.moduleClass) {
+ traverseTrees(stats)
+ }
+ case ClassDef(mods, name, tparams, tpt, impl) =>
+ atOwner(tree.symbol) {
+ traverseTrees(tparams); traverse(tpt); traverse(impl)
+ }
+ case ModuleDef(mods, name, impl) =>
+ atOwner(tree.symbol.moduleClass) {
+ traverse(impl)
+ }
+ case ValDef(mods, name, tpt, rhs) =>
+ atOwner(tree.symbol) {
+ traverse(tpt); traverse(rhs)
+ }
+ case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
+ atOwner(tree.symbol) {
+ traverseTrees(tparams); traverseTreess(vparamss); traverse(tpt); traverse(rhs)
+ }
+ case AbsTypeDef(mods, name, lo, hi) =>
+ atOwner(tree.symbol) {
+ traverse(lo); traverse(hi);
+ }
+ case AliasTypeDef(mods, name, tparams, rhs) =>
+ atOwner(tree.symbol) {
+ traverseTrees(tparams); traverse(rhs)
+ }
+ case LabelDef(name, params, rhs) =>
+ traverseTrees(params); traverse(rhs)
+ case Import(expr, selectors) =>
+ traverse(expr)
+ case Attributed(attribute, definition) =>
+ traverse(attribute); traverse(definition)
+ case DocDef(comment, definition) =>
+ traverse(definition)
+ case Template(parents, body) =>
+ traverseTrees(parents); traverseStats(body, tree.symbol)
+ case Block(stats, expr) =>
+ traverseTrees(stats); traverse(expr)
+ case CaseDef(pat, guard, body) =>
+ traverse(pat); traverse(guard); traverse(body)
+ case Sequence(trees) =>
+ traverseTrees(trees)
+ case Alternative(trees) =>
+ traverseTrees(trees)
+ case Star(elem) =>
+ traverse(elem)
+ case Bind(name, body) =>
+ traverse(body)
+ case ArrayValue(elemtpt, trees) =>
+ traverse(elemtpt); traverseTrees(trees)
+ case Function(vparams, body) =>
+ traverseTrees(vparams); traverse(body)
+ case Assign(lhs, rhs) =>
+ traverse(lhs); traverse(rhs)
+ case If(cond, thenp, elsep) =>
+ traverse(cond); traverse(thenp); traverse(elsep)
+ case Match(selector, cases) =>
+ traverse(selector); traverseTrees(cases)
+ case Return(expr) =>
+ traverse(expr)
+ case Try(block, catches, finalizer) =>
+ traverse(block); traverseTrees(catches); traverse(finalizer)
+ case Throw(expr) =>
+ traverse(expr)
+ case New(tpt) =>
+ traverse(tpt)
+ case Typed(expr, tpt) =>
+ traverse(expr); traverse(tpt)
+ case TypeApply(fun, args) =>
+ traverse(fun); traverseTrees(args)
+ case Apply(fun, args) =>
+ traverse(fun); traverseTrees(args)
+ case Super(_, _) =>
+ ;
+ case This(_) =>
+ ;
+ case Select(qualifier, selector) =>
+ traverse(qualifier)
+ case Ident(_) =>
+ ;
+ case Literal(_) =>
+ ;
+ case TypeTree() =>
+ ;
+ case SingletonTypeTree(ref) =>
+ traverse(ref)
+ case SelectFromTypeTree(qualifier, selector) =>
+ traverse(qualifier)
+ case CompoundTypeTree(templ) =>
+ traverse(templ)
+ case AppliedTypeTree(tpt, args) =>
+ traverse(tpt); traverseTrees(args)
+ }
+
+ def traverseTrees(trees: List[Tree]): unit =
+ trees foreach traverse;
+ def traverseTreess(treess: List[List[Tree]]): unit =
+ treess foreach traverseTrees;
+ def traverseStats(stats: List[Tree], exprOwner: Symbol): unit =
+ stats foreach (stat =>
+ if (exprOwner != currentOwner && stat.isTerm) atOwner(exprOwner)(traverse(stat))
+ else traverse(stat));
+ def apply[T <: Tree](tree: T): T = { traverse(tree); tree }
+
+ def atOwner(owner: Symbol)(traverse: => unit): unit = {
+ val prevOwner = currentOwner;
+ currentOwner = owner;
+ traverse;
+ currentOwner = prevOwner;
+ }
+ }
+
+ class TreeSubstituter(from: List[Symbol], to: List[Tree]) extends Transformer {
+ override def transform(tree: Tree): Tree = tree match {
+ case Ident(_) =>
+ def subst(from: List[Symbol], to: List[Tree]): Tree =
+ if (from.isEmpty) tree
+ else if (tree.symbol == from.head) to.head
+ else subst(from.tail, to.tail);
+ subst(from, to)
+ case _ =>
+ super.transform(tree)
+ }
+ }
+
+ class TreeTypeSubstituter(from: List[Symbol], to: List[Type]) extends Traverser {
+ val typeSubst = new SubstTypeMap(from, to);
+ override def traverse(tree: Tree): unit = {
+ if (tree.tpe != null) tree.tpe = typeSubst(tree.tpe);
+ super.traverse(tree)
+ }
+ override def apply[T <: Tree](tree: T): T = super.apply(tree.duplicate)
+ }
+
+ class TreeSymSubstituter(from: List[Symbol], to: List[Symbol]) extends Traverser {
+ val symSubst = new SubstSymMap(from, to);
+ override def traverse(tree: Tree): unit = {
+ def subst(from: List[Symbol], to: List[Symbol]): unit = {
+ if (!from.isEmpty)
+ if (tree.symbol == from.head) tree setSymbol to.head
+ else subst(from.tail, to.tail)
+ }
+ if (tree.tpe != null) tree.tpe = symSubst(tree.tpe);
+ if (tree.hasSymbol) subst(from, to);
+ super.traverse(tree)
+ }
+ override def apply[T <: Tree](tree: T): T = super.apply(tree.duplicate)
+ }
+
+ class ChangeOwnerTraverser(val oldowner: Symbol, val newowner: Symbol) extends Traverser {
+ override def traverse(tree: Tree): unit = {
+ if ((tree.isDef || tree.isInstanceOf[Function]) && tree.symbol != NoSymbol && tree.symbol.owner == oldowner)
+ tree.symbol.owner = newowner;
+ super.traverse(tree)
+ }
+ }
+
+ final class TreeList {
+ private var trees = List[Tree]();
+ def append(t: Tree): TreeList = { trees = t :: trees; this }
+ def append(ts: List[Tree]): TreeList = { trees = ts reverse_::: trees; this }
+ def toList: List[Tree] = trees.reverse;
+ }
+
+ object posAssigner extends Traverser {
+ private var pos: int = _;
+ override def traverse(t: Tree): unit =
+ if (t != EmptyTree && t.pos == Position.NOPOS) {
+ t.setPos(pos);
+ super.traverse(t);
+ }
+ def atPos[T <: Tree](pos: int)(tree: T): T = {
+ this.pos = pos;
+ traverse(tree);
+ tree
+ }
+ }
+}
+
diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
new file mode 100644
index 0000000000..cf4244cb3f
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala
@@ -0,0 +1,583 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author buraq
+ */
+// $Id$
+package scala.tools.nsc.ast.parser;
+
+//import java.lang.{Integer, Long, Float, Double};
+
+//import scalac._;
+//import scalac.ast._;
+//import scalac.atree.AConstant;
+//import scalac.symtab.Modifiers;
+
+import scala.Iterator;
+import scala.collection.immutable.ListMap ;
+import scala.collection.mutable;
+//import scala.tools.scalac.util.NewArray;
+import scala.tools.nsc.util.Position;
+import scala.xml.{Text,TextBuffer};
+
+
+trait MarkupParsers: SyntaxAnalyzer {
+
+ import global._ ;
+ import posAssigner.atPos;
+
+class MarkupParser(unit: CompilationUnit, s: Scanner, p: Parser, presWS: boolean) /*with scala.xml.parsing.MarkupParser[Tree,Tree] */{
+
+ import Tokens.{EMPTY, LBRACE, RBRACE};
+
+ final val preserveWS = presWS;
+
+ import p.{symbXMLBuilder => handle};
+ import s.token;
+
+ /** the XML tree factory */
+ //final val handle: SymbolicXMLBuilder = p.symbXMLBuilder;
+ //new SymbolicXMLBuilder(unit.global.make, unit.global.treeGen, p, presWS);
+
+ /** holds the position in the source file */
+ /*[Duplicate]*/ var pos: Int = _;
+
+ /** holds temporary values of pos */
+ /*[Duplicate]*/ var tmppos: Int = _;
+
+ /** holds the next character */
+ /*[Duplicate]*/ var ch: Char = _;
+
+ /** character buffer, for names */
+ /*[Duplicate]*/ protected val cbuf = new StringBuffer();
+
+ /** append Unicode character to name buffer*/
+ /*[Duplicate]*/ protected def putChar(c: char) = cbuf.append( c );
+
+ /*[Duplicate]*/ var xEmbeddedBlock = false;
+
+ /** munch expected XML token, report syntax error for unexpected */
+ /*[Duplicate]*/ def xToken(that: Char): Unit = {
+ if( ch == that )
+ nextch;
+ else
+ reportSyntaxError("'" + that + "' expected instead of '" + ch + "'");
+ }
+
+ var debugLastStartElement = new mutable.Stack[Pair[Int,String]];
+
+ /** checks whether next character starts a Scala block, if yes, skip it.
+ * @return true if next character starts a scala block
+ */
+ /*[Duplicate]*/ def xCheckEmbeddedBlock:Boolean = {
+ xEmbeddedBlock =
+ enableEmbeddedExpressions && ( ch == '{' ) && { nextch;( ch != '{' ) };
+ return xEmbeddedBlock;
+ }
+
+ /** parse attribute and add it to listmap
+ * [41] Attributes ::= { S Name Eq AttValue }
+ * AttValue ::= `'` { _ } `'`
+ * | `"` { _ } `"`
+ * | `{` scalablock `}`
+ */
+ /*[Duplicate]*/ def xAttributes = {
+ var aMap = new mutable.HashMap[String, Tree]();
+ while (xml.Parsing.isNameStart(ch)) {
+ val key = xName;
+ xEQ;
+ val delim = ch;
+ val pos1 = pos;
+ val value: /* AttribValue[*/Tree/*]*/ = ch match {
+ case '"' | '\'' =>
+ nextch;
+ val tmp = xAttributeValue( delim );
+ nextch;
+ Literal(Constant(tmp));
+ case '{' if enableEmbeddedExpressions =>
+ nextch;
+ xEmbeddedExpr;
+ case _ =>
+ reportSyntaxError( "' or \" delimited attribute value or '{' scala-expr '}' expected" );
+ Literal(Constant("<syntax-error>"))
+ };
+ // well-formedness constraint: unique attribute names
+ if( aMap.contains( key ))
+ reportSyntaxError( "attribute "+key+" may only be defined once" );
+ aMap.update( key, value );
+ if(( ch != '/' )&&( ch != '>' ))
+ xSpace;
+ };
+ aMap
+ }
+
+ /** attribute value, terminated by either ' or ". value may not contain <.
+ * @param endch either ' or "
+ */
+ /*[Duplicate]*/ def xAttributeValue(endCh: char): String = {
+ while (ch != endCh) {
+ putChar(ch);
+ nextch;
+ };
+ val str = cbuf.toString();
+ cbuf.setLength(0);
+ // @todo: normalize attribute value
+ // well-formedness constraint
+ if (str.indexOf('<') != -1) {
+ reportSyntaxError( "'<' not allowed in attrib value" ); ""
+ } else {
+ str
+ }
+ }
+
+ /** parse a start or empty tag.
+ * [40] STag ::= '<' Name { S Attribute } [S]
+ * [44] EmptyElemTag ::= '<' Name { S Attribute } [S]
+ */
+ /*[Duplicate]*/ def xTag: Pair[String, mutable.Map[String, Tree]] = {
+ val elemName = xName;
+ xSpaceOpt;
+ val aMap = if (xml.Parsing.isNameStart(ch)) {
+ xAttributes;
+ } else {
+ new mutable.HashMap[String, Tree]();
+ }
+ Tuple2( elemName, aMap );
+ }
+
+ /* [42] '<' xmlEndTag ::= '<' '/' Name S? '>' */
+ /*[Duplicate]*/ def xEndTag(n: String) = {
+ xToken('/');
+ val m = xName;
+ if(n != m) reportSyntaxError( "expected closing tag of " + n/* +", not "+m*/);
+ xSpaceOpt;
+ xToken('>')
+ }
+
+ /** '<! CharData ::= [CDATA[ ( {char} - {char}"]]>"{char} ) ']]>'
+ *
+ * see [15]
+ */
+ /*[Duplicate]*/ def xCharData: Tree = {
+ xToken('[');
+ xToken('C');
+ xToken('D');
+ xToken('A');
+ xToken('T');
+ xToken('A');
+ xToken('[');
+ val pos1 = pos;
+ val sb:StringBuffer = new StringBuffer();
+ while (true) {
+ if (ch==']' &&
+ { sb.append( ch ); nextch; ch == ']' } &&
+ { sb.append( ch ); nextch; ch == '>' } ) {
+ sb.setLength( sb.length() - 2 );
+ nextch;
+ return handle.charData( pos1, sb.toString() );
+ } else sb.append( ch );
+ nextch;
+ }
+ Predef.error("this cannot happen");
+ };
+
+ /** CharRef ::= "&#" '0'..'9' {'0'..'9'} ";"
+ * | "&#x" '0'..'9'|'A'..'F'|'a'..'f' { hexdigit } ";"
+ *
+ * see [66]
+ */
+ /*[Duplicate]*/ def xCharRef:String = {
+ val hex = ( ch == 'x' ) && { nextch; true };
+ val base = if (hex) 16 else 10;
+ var i = 0;
+ while (ch != ';') {
+ ch match {
+ case '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' =>
+ i = i * base + Character.digit( ch, base );
+ case 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
+ | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' =>
+ if( !hex )
+ reportSyntaxError("hex char not allowed in decimal char ref\n"
+ +"Did you mean to write &#x ?");
+ else
+ i = i * base + Character.digit( ch, base );
+ case _ =>
+ reportSyntaxError("character '"+ch+" not allowed in char ref\n");
+ }
+ nextch;
+ }
+ new String(Predef.Array(i.asInstanceOf[char]))
+ }
+/** Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
+ *
+ * see [15]
+ */
+ /*[Duplicate]*/ def xComment: Tree = {
+ val sb:StringBuffer = new StringBuffer();
+ xToken('-');
+ xToken('-');
+ while (true) {
+ if( ch=='-' && { sb.append( ch ); nextch; ch == '-' } ) {
+ sb.setLength( sb.length() - 1 );
+ nextch;
+ xToken('>');
+ return handle.comment( pos, sb.toString() );
+ } else sb.append( ch );
+ nextch;
+ }
+ Predef.error("this cannot happen");
+ };
+
+ /*[Duplicate]*/ def appendText(pos: int, ts:mutable.Buffer[Tree], txt:String):Unit = {
+ if( !preserveWS )
+ for( val t <- TextBuffer.fromString( txt ).toText ) {
+ ts.append( handle.text( pos, t.text ) );
+ }
+ else
+ ts.append( handle.text( pos, txt ));
+ }
+
+ /*[Duplicate]*/ def content: mutable.Buffer[Tree] = {
+ var ts = new mutable.ArrayBuffer[Tree];
+ var exit = false;
+ while( !exit ) {
+ if( xEmbeddedBlock ) {
+ ts.append( xEmbeddedExpr );
+ } else {
+ tmppos = pos;
+ ch match {
+ case '<' => // another tag
+ nextch;
+ ch match {
+ case '/' =>
+ exit = true; // end tag
+ case '!' =>
+ nextch;
+ if( '[' == ch ) // CDATA
+ ts.append( xCharData );
+ else // comment
+ ts.append( xComment );
+ case '?' => // PI
+ nextch;
+ ts.append( xProcInstr );
+ case _ =>
+ ts.append( element ); // child
+ }
+
+ case '{' =>
+ if( xCheckEmbeddedBlock ) {
+ ts.append(xEmbeddedExpr);
+ } else {
+ val str = new StringBuffer("{");
+ str.append( xText );
+ appendText(tmppos, ts, str.toString());
+ }
+ // postcond: xEmbeddedBlock == false!
+ case '&' => // EntityRef or CharRef
+ nextch;
+ ch match {
+ case '#' => // CharacterRef
+ nextch;
+ val theChar = handle.text( tmppos, xCharRef );
+ xToken(';');
+ ts.append( theChar );
+ case _ => // EntityRef
+ val n = xName ;
+ xToken(';');
+ ts.append( handle.entityRef( tmppos, n ) );
+ }
+ case _ => // text content
+ appendText(tmppos, ts, xText);
+ // here xEmbeddedBlock might be true
+ }
+ }
+ }
+ ts
+ } /* end content */
+
+ /** '<' element ::= xmlTag1 '>' { xmlExpr | '{' simpleExpr '}' } ETag
+ * | xmlTag1 '/' '>'
+ */
+ /*[Duplicate]*/ def element: Tree = {
+ val pos1 = pos;
+ val Tuple2(qname, attrMap) = xTag;
+ //Console.println("MarkupParser::element("+qname+","+attrMap+")");
+ if (ch == '/') { // empty element
+ xToken('/');
+ xToken('>');
+ handle.element( pos1, qname, attrMap, new mutable.ListBuffer[Tree] );
+ }
+ else { // handle content
+ xToken('>');
+ debugLastStartElement.push(Pair(pos1,qname));
+ val ts = content;
+ xEndTag( qname );
+ debugLastStartElement.pop;
+ handle.element( pos1, qname, attrMap, ts );
+ }
+ }
+
+
+ /** Name ::= (Letter | '_' | ':') (NameChar)*
+ *
+ * see [5] of XML 1.0 specification
+ */
+ /*[Duplicate]*/ def xName: String = {
+ if( xml.Parsing.isNameStart( ch ) ) {
+ do {
+ putChar( ch );
+ nextch;
+ } while( xml.Parsing.isNameChar( ch ) );
+ val n = cbuf.toString().intern();
+ cbuf.setLength( 0 );
+ n
+ } else {
+ reportSyntaxError( "name expected, but char '"+ch+"' cannot start a name" );
+ new String();
+ }
+ }
+
+
+ /** scan [S] '=' [S]*/
+ /*[Duplicate]*/ def xEQ = { xSpaceOpt; xToken('='); xSpaceOpt }
+
+ /** skip optional space S? */
+ /*[Duplicate]*/ def xSpaceOpt = { while( xml.Parsing.isSpace( ch ) ) { nextch; }}
+
+ /** scan [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
+ /*[Duplicate]*/ def xSpace = {
+ if (xml.Parsing.isSpace(ch)) {
+ nextch; xSpaceOpt
+ }
+ else {
+ reportSyntaxError("whitespace expected");
+ }
+ }
+
+/** '<?' ProcInstr ::= Name [S ({Char} - ({Char}'>?' {Char})]'?>'
+ *
+ * see [15]
+ */
+ /*[Duplicate]*/ def xProcInstr: Tree = {
+ val sb:StringBuffer = new StringBuffer();
+ val n = xName;
+ if( xml.Parsing.isSpace( ch ) ) {
+ xSpace;
+ while( true ) {
+ if( ch=='?' && { sb.append( ch ); nextch; ch == '>' } ) {
+ sb.setLength( sb.length() - 1 );
+ nextch;
+ return handle.procInstr(tmppos, n.toString(), sb.toString());
+ } else
+ sb.append( ch );
+ nextch;
+ }
+ };
+ xToken('?');
+ xToken('>');
+ return handle.procInstr(tmppos, n.toString(), sb.toString());
+ }
+
+ /** parse character data.
+ * precondition: xEmbeddedBlock == false (we are not in a scala block)
+ */
+ /*[Duplicate]*/ def xText: String = {
+ if( xEmbeddedBlock ) Predef.error("internal error: encountered embedded block"); // assert
+
+ if( xCheckEmbeddedBlock )
+ return ""
+ else {
+ var exit = false;
+ while( !exit ) {
+ putChar( ch );
+ exit = { nextch; xCheckEmbeddedBlock }||( ch == '<' ) || ( ch == '&' );
+ }
+ val str = cbuf.toString();
+ cbuf.setLength( 0 );
+ str
+ }
+ }
+ //override type Tree = handle.Tree;
+ //override type Tree = handle.Tree;
+
+ final val PATTERN = true;
+ final val EXPR = false;
+
+ val enableEmbeddedExpressions: Boolean = true;
+
+ //val cbuf = new StringBuffer();
+
+ /** append Unicode character to name buffer*/
+ //private def putChar(c: char) = cbuf.append( c );
+
+ /** xLiteral = element { element }
+ * @return Scala representation of this xml literal
+ * precondition: s.xStartsXML == true
+ */
+ def xLiteral: Tree = try {
+ init;
+ handle.isPattern = false;
+ val pos = s.currentPos;
+ var tree = element;
+ xSpaceOpt;
+ // parse more XML ?
+ if (ch == '<') {
+ val ts = new mutable.ArrayBuffer[Tree]();
+ ts.append( tree );
+ while( ch == '<' ) {
+ nextch;
+ //Console.println("DEBUG 1: I am getting char '"+ch+"'"); // DEBUG
+ ts.append( element );
+ xSpaceOpt;
+ }
+ tree = handle.makeXMLseq( pos, ts );
+ }
+ //Console.println("out of xLiteral, parsed:"+tree.toString());
+ s.next.token = EMPTY;
+ s.nextToken(); /* s.fetchToken(); */
+ tree
+ }
+ catch {
+ case _:ArrayIndexOutOfBoundsException =>
+ s.syntaxError(debugLastStartElement.top._1,
+ "missing end tag in XML literal for <"
+ +debugLastStartElement.top._2+">");
+ EmptyTree;
+ }
+
+ /** @see xmlPattern. resynchronizes after succesful parse
+ * @return this xml pattern
+ * precondition: s.xStartsXML == true
+ */
+ def xLiteralPattern:Tree = try {
+ init;
+ val oldMode = handle.isPattern;
+ handle.isPattern = true;
+ val pos = s.currentPos;
+ var tree = xPattern; xSpaceOpt;
+ //if (ch == '<') {
+ var ts: List[Tree] = List();
+ ts = tree :: ts;
+
+ s.next.token = EMPTY; s.nextToken(); /* ?????????? */
+ while( token == Tokens.XMLSTART ) {// ???????????????????????????
+ //while (ch == '<' /* && lookahead != '-'*/) {
+ nextch;
+ //Console.println("DEBUG 2: I am getting char '"+ch+"'"); // DEBUG
+ ts = xPattern :: ts;
+ //xSpaceOpt; // ????
+ s.next.token = EMPTY; s.nextToken(); /* ?????????? */
+ //Console.println("DEBUG 3: resync'ed, token = '"+s+"'"); // DEBUG
+ }
+ //Console.println("current token == "+s);
+ tree = handle.makeXMLseqPat( pos, ts.reverse );
+ //}
+ handle.isPattern = oldMode;
+ //Console.println("out of xLiteralPattern, parsed:"+tree.toString());
+ // s.next.token = EMPTY; // ??
+ // s.nextToken(); /* s.fetchToken(); */ // ??
+ tree
+ }catch {
+ case _:ArrayIndexOutOfBoundsException =>
+ s.syntaxError(debugLastStartElement.top._1,
+ "missing end tag in XML literal for <"
+ +debugLastStartElement.top._2+">");
+ EmptyTree;
+ }
+
+ def xEmbeddedExpr:Tree = {
+ sync;
+ val b = p.expr(true,false);
+ if(/*s.*/token != RBRACE)
+ reportSyntaxError(" expected end of Scala block");
+ init;
+ //Console.println("[out of xScalaExpr s.ch = "+s.ch+" ch="+ch+"]");
+ return b
+ }
+
+ /** xScalaPatterns ::= patterns
+ */
+ def xScalaPatterns: List[Tree] = {
+ sync;
+ val b = p.patterns();
+ if (/*s.*/token != RBRACE)
+ reportSyntaxError(" expected end of Scala patterns");
+ init;
+ return b
+ }
+
+ //var ch: Char = _;
+
+ /** this method assign the next character to ch and advances in input */
+ def nextch: Unit = { s.in.next; /*s.xNext;*/ ch = s.in.ch ; pos = s.currentPos; }
+
+ //def lookahead = { s.xLookahead }
+
+ def init: Unit = {
+ ch = s.in.ch;
+ pos = s.currentPos;
+ //Console.println("\ninit! ch = "+ch);
+ }
+
+ def reportSyntaxError(str: String) = {
+ s.syntaxError("in XML literal: " + str);
+ nextch;
+ }
+
+ def sync: Unit = {
+ xEmbeddedBlock = false;
+ s.xSync;
+ }
+
+ /** '<' xPattern ::= Name [S] { xmlPattern | '{' pattern3 '}' } ETag
+ * | Name [S] '/' '>'
+ */
+ def xPattern:Tree = {
+ //Console.println("xPattern");
+ val pos1 = pos;
+ val qname = xName;
+ debugLastStartElement.push(Pair(pos1,qname));
+ xSpaceOpt;
+ if( ch == '/' ) { // empty tag
+ nextch;
+ xToken('>');
+ return handle.makeXMLpat( pos1, qname, new mutable.ArrayBuffer[Tree]() );
+ };
+
+ // else: tag with content
+ xToken('>');
+ var ts = new mutable.ArrayBuffer[Tree];
+ var exit = false;
+ while (! exit) {
+ val pos2 = pos;
+ if( xEmbeddedBlock ) {
+ ts ++ xScalaPatterns;
+ } else
+ ch match {
+ case '<' => { // tag
+ nextch;
+ if( ch != '/' ) { //child
+ ts.append( xPattern );
+ } else {
+ exit = true
+ }
+ }
+ case '{' => // embedded Scala patterns
+ while( ch == '{' ) {
+ s.in.next;
+ ts ++ xScalaPatterns;
+ }
+ // postcond: xEmbeddedBlock = false;
+ if (xEmbeddedBlock) Predef.error("problem with embedded block"); // assert
+ case _ => // teMaxt
+ appendText( pos2, ts, xText );
+ // here xEmbeddedBlock might be true;
+ //if( xEmbeddedBlock ) throw new ApplicationError("after:"+text); // assert
+ }
+ }
+ xEndTag(qname);
+ debugLastStartElement.pop;
+ handle.makeXMLpat(pos1, qname, ts);
+ }
+
+} /* class MarkupParser */
+}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
new file mode 100644
index 0000000000..0634ace4d0
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
@@ -0,0 +1,1808 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.ast.parser;
+
+import scala.tools.nsc.util.Position;
+import util.ListBuffer;
+import symtab.Flags;
+import Tokens._;
+
+/** Performs the following context-free rewritings:
+ * (1) Places all pattern variables in Bind nodes. In a pattern, for identifiers `x':
+ * x => x @ _
+ * x:T => x @ (_ : T)
+ *
+ * (2) Removes pattern definitions (PatDef's) as follows:
+ * If pattern is a simple (typed) identifier:
+ * val x = e ==> val x = e
+ * val x: T = e ==> val x: T = e
+ *
+ * if there are no variables in pattern
+ * val p = e ==> e.match (case p => ())
+ *
+ * if there is exactly one variable in pattern
+ * val x_1 = e.match (case p => (x_1))
+ *
+ * if there is more than one variable in pattern
+ * val p = e ==> private synthetic val t$ = e.match (case p => (x_1, ..., x_N))
+ * val x_1 = t$._1
+ * ...
+ * val x_N = t$._N
+ *
+ * (3) Removes function types as follows:
+ * (argtpes) => restpe ==> scala.Function_n[argtpes, restpe]
+ *
+ * (4) Wraps naked case definitions in a match as follows:
+ * { cases } ==> (x => x.match {cases}), except when already argument to match
+ */
+[_trait_] abstract class Parsers: SyntaxAnalyzer {
+
+ import global._;
+ import posAssigner.atPos;
+
+ class Parser(unit: CompilationUnit) {
+
+ val in = new Scanner(unit);
+
+ /** the markup parser */
+ val xmlp = new MarkupParser(unit, in, Parser.this, true);
+
+ object treeBuilder extends TreeBuilder {
+ val global: Parsers.this.global.type = Parsers.this.global;
+ def freshName(prefix: String): Name = unit.fresh.newName(prefix);
+ }
+ import treeBuilder._;
+
+ object symbXMLBuilder extends SymbolicXMLBuilder(treeBuilder, Parser.this, true) { // DEBUG choices
+ val global: Parsers.this.global.type = Parsers.this.global;
+ def freshName(prefix: String): Name = unit.fresh.newName(prefix);
+ }
+
+ /** this is the general parse method
+ */
+ def parse(): Tree = {
+ val t = compilationUnit();
+ accept(EOF);
+ t
+ }
+
+/////// ERROR HANDLING //////////////////////////////////////////////////////
+
+ private def skip(): unit = {
+ //System.out.println("<skipping> " + in.token2string(in.token));//DEBUG
+ var nparens = 0;
+ var nbraces = 0;
+ while (true) {
+ in.token match {
+ case EOF =>
+ return;
+ case SEMI =>
+ if (nparens == 0 && nbraces == 0) return;
+ case NEWLINE =>
+ if (nparens == 0 && nbraces == 0) return;
+ case RPAREN =>
+ nparens = nparens - 1;
+ case RBRACE =>
+ if (nbraces == 0) return;
+ nbraces = nbraces - 1;
+ case LPAREN =>
+ nparens = nparens + 1;
+ case LBRACE =>
+ nbraces = nbraces + 1;
+ case _ =>
+ }
+ in.nextToken();
+ }
+ }
+
+ def syntaxError(msg: String, skipIt: boolean): unit =
+ syntaxError(in.currentPos, msg, skipIt);
+
+ def syntaxError(pos: int, msg: String, skipIt: boolean): unit = {
+ if (pos != in.errpos) {
+ unit.error(pos, msg);
+ in.errpos = pos;
+ }
+ if (skipIt) skip();
+ }
+
+ def accept(token: int): int = {
+ val pos = in.currentPos;
+ if (in.token != token)
+ syntaxError(
+ if (Position.line(unit.source, in.currentPos) > Position.line(unit.source, in.lastPos)) in.lastPos
+ else in.currentPos,
+ in.token2string(token) + " expected but " +
+ in.token2string(in.token) + " found.", true);
+ if (in.token == token) in.nextToken();
+ pos;
+ }
+
+ /** SEP = NL | `;'
+ * NL = `\n' // where allowed
+ */
+ def acceptStatSep(): unit = if (in.token == NEWLINE) in.nextToken() else accept(SEMI);
+
+ def errorTypeTree = TypeTree().setType(ErrorType).setPos(in.currentPos);
+ def errorTermTree = Literal(Constant(null)).setPos(in.currentPos);
+ def errorPatternTree = Ident(nme.WILDCARD).setPos(in.currentPos);
+
+/////// TOKEN CLASSES //////////////////////////////////////////////////////
+
+ def isModifier: boolean = in.token match {
+ case ABSTRACT | FINAL | SEALED | PRIVATE | PROTECTED | OVERRIDE | IMPLICIT => true
+ case _ => false
+ }
+
+ def isLocalModifier: boolean = in.token match {
+ case ABSTRACT | FINAL | SEALED => true
+ case _ => false
+ }
+
+ def isDefIntro: boolean = in.token match {
+ case VAL | VAR | DEF | TYPE | OBJECT |
+ CASEOBJECT | CLASS | CASECLASS | TRAIT => true
+ case _ => false
+ }
+
+ def isDclIntro: boolean = in.token match {
+ case VAL | VAR | DEF | TYPE => true
+ case _ => false
+ }
+
+ def isExprIntro: boolean = in.token match {
+ case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT |
+ STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL | IDENTIFIER |
+ THIS | SUPER | IF | FOR | NEW | USCORE | TRY | WHILE |
+ DO | RETURN | THROW | LPAREN | LBRACE | XMLSTART => true
+ case _ => false
+ }
+
+/////// COMMENT AND ATTRIBUTE COLLECTION //////////////////////////////////////
+
+ /** Join the comment associated with a definition
+ */
+ def joinComment(trees: => List[Tree]): List[Tree] = {
+ val buf = in.docBuffer;
+ if (buf != null) {
+ in.docBuffer = null;
+ trees map (t => DocDef(buf.toString(), t) setPos t.pos)
+ } else trees
+ }
+
+/////// TREE CONSTRUCTION ////////////////////////////////////////////////////
+
+ def scalaDot(name: Name): Tree =
+ Select(Ident(nme.scala_), name);
+ def scalaAnyRefConstr: Tree =
+ scalaDot(nme.AnyRef.toTypeName);
+ def scalaScalaObjectConstr: Tree =
+ scalaDot(nme.ScalaObject.toTypeName);
+ def caseClassConstr: Tree =
+ scalaDot(nme.CaseClass.toTypeName);
+
+ /** Convert tree to formal parameter list
+ */
+ def convertToParams(t: Tree): List[ValDef] = t match {
+ case Function(params, TypeTree()) =>
+ params
+ case Ident(_) | Typed(Ident(_), _) =>
+ List(convertToParam(t));
+ case Literal(c) if c.tag == UnitTag =>
+ Nil
+ case _ =>
+ syntaxError(t.pos, "malformed formal parameter list", false);
+ Nil
+ }
+
+ /** Convert tree to formal parameter
+ */
+ def convertToParam(tree: Tree): ValDef =
+ atPos(tree.pos) {
+ tree match {
+ case Ident(name) =>
+ ValDef(Modifiers(Flags.PARAM), name, TypeTree(), EmptyTree)
+ case Typed(Ident(name), tpe) =>
+ ValDef(Modifiers(Flags.PARAM), name, tpe, EmptyTree)
+ case _ =>
+ syntaxError(tree.pos, "not a legal formal parameter", false);
+ ValDef(Modifiers(Flags.PARAM), nme.ERROR, errorTypeTree, EmptyTree)
+ }
+ }
+
+ /** Convert (qual)ident to type identifier
+ */
+ def convertToTypeId(tree: Tree): Tree = tree match {
+ case Ident(name) =>
+ Ident(name.toTypeName).setPos(tree.pos)
+ case Select(qual, name) =>
+ Select(qual, name.toTypeName).setPos(tree.pos)
+ case _ =>
+ System.out.println(tree);//debug
+ syntaxError(tree.pos, "identifier expected", false);
+ errorTypeTree
+ }
+
+ /** make closure from tree */
+ def makeClosure(tree: Tree): Tree = {
+ val pname: Name = unit.fresh.newName("x$");
+ def insertParam(tree: Tree): Tree = tree match {
+ case Ident(name) =>
+ Select(Ident(pname), name)
+ case Select(qual, name) =>
+ Select(insertParam(qual), name)
+ case Apply(fn, args) =>
+ Apply(insertParam(fn), args)
+ case TypeApply(fn, args) =>
+ TypeApply(insertParam(fn), args)
+ case _ =>
+ syntaxError(tree.pos, "cannot convert to closure", false);
+ errorTermTree
+ }
+ Function(
+ List(ValDef(Modifiers(Flags.PARAM), pname, TypeTree(), EmptyTree)),
+ insertParam(tree))
+ }
+
+/////// OPERAND/OPERATOR STACK /////////////////////////////////////////////////
+
+ case class OpInfo(operand: Tree, operator: Name, pos: int);
+ var opstack: List[OpInfo] = Nil;
+
+ def precedence(operator: Name): int =
+ if (operator eq nme.ERROR) -1
+ else {
+ val firstCh = operator(0);
+ if (((firstCh >= 'A') && (firstCh <= 'Z')) ||
+ ((firstCh >= 'a') && (firstCh <= 'z')))
+ 1
+ else
+ firstCh match {
+ case '|' => 2
+ case '^' => 3
+ case '&' => 4
+ case '<' | '>' => 5
+ case '=' | '!' => 6
+ case ':' => 7
+ case '+' | '-' => 8;
+ case '*' | '/' | '%' => 9;
+ case _ => 10;
+ }
+ }
+
+ def reduceStack(isExpr: boolean, base: List[OpInfo], top0: Tree, prec: int, leftAssoc: boolean): Tree = {
+ var top = top0;
+ if (opstack != base &&
+ precedence(opstack.head.operator) == prec &&
+ treeInfo.isLeftAssoc(opstack.head.operator) != leftAssoc) {
+ syntaxError(
+ opstack.head.pos,
+ "left- and right-associative operators with same precedence may not be mixed",
+ false);
+ }
+ while (opstack != base &&
+ (prec < precedence(opstack.head.operator) ||
+ (leftAssoc && prec == precedence(opstack.head.operator)))) {
+ top = atPos(opstack.head.pos) {
+ makeBinop(isExpr, opstack.head.operand, opstack.head.operator, top)
+ }
+ opstack = opstack.tail;
+ }
+ top
+ }
+
+/////// IDENTIFIERS AND LITERALS ////////////////////////////////////////////////////////////
+
+ final val MINUS: Name = "-";
+ final val PLUS : Name = "+";
+ final val BANG : Name = "!";
+ final val TILDE: Name = "~";
+ final val STAR : Name = "*";
+ final val BAR : Name = "|";
+ final val OPT : Name = "?";
+ final val LT : Name = "<";
+
+ def ident(): Name =
+ if (in.token == IDENTIFIER) {
+ val name = in.name.encode;
+ in.nextToken();
+ name
+ } else {
+ accept(IDENTIFIER);
+ nme.ERROR
+ }
+
+ /** StableRef ::= StableId
+ * | [Ident `.'] this
+ * SimpleType ::= StableRef [`.' type]
+ */
+ def stableRef(thisOK: boolean, typeOK: boolean): Tree = {
+ var t: Tree = null;
+ if (in.token == THIS) {
+ t = atPos(in.skipToken()) { This(nme.EMPTY.toTypeName) }
+ if (!thisOK || in.token == DOT)
+ t = { selectors(t, typeOK, accept(DOT)) }
+ } else if (in.token == SUPER) {
+ t = atPos(in.skipToken()) {
+ Super(nme.EMPTY.toTypeName, mixinQualifierOpt())
+ }
+ t = atPos(accept(DOT)) { Select(t, ident()) }
+ if (in.token == DOT)
+ t = { selectors(t, typeOK, in.skipToken()) }
+ } else {
+ val i = atPos(in.currentPos) { Ident(ident()) }
+ t = i;
+ if (in.token == DOT) {
+ val pos = in.skipToken();
+ if (in.token == THIS) {
+ in.nextToken();
+ t = atPos(i.pos) { This(i.name.toTypeName) }
+ if (!thisOK || in.token == DOT)
+ t = { selectors(t, typeOK, accept(DOT)) }
+ } else if (in.token == SUPER) {
+ in.nextToken();
+ t = atPos(i.pos) { Super(i.name.toTypeName, mixinQualifierOpt()) }
+ t = atPos(accept(DOT)) { Select(t, ident())}
+ if (in.token == DOT)
+ t = { selectors(t, typeOK, in.skipToken()) }
+ } else {
+ t = { selectors(t, typeOK, pos) }
+ }
+ }
+ }
+ t
+ }
+
+ def selectors(t: Tree, typeOK: boolean, pos : Int): Tree =
+ if (typeOK && in.token == TYPE) {
+ in.nextToken();
+ atPos(pos) { SingletonTypeTree(t) }
+ } else {
+ val t1 = atPos(pos) { Select(t, ident()); }
+ if (in.token == DOT) { selectors(t1, typeOK, in.skipToken()) }
+ else t1
+ }
+
+ /** MixinQualifier ::= `[' Id `]'
+ */
+ def mixinQualifierOpt(): Name =
+ if (in.token == LBRACKET) {
+ in.nextToken();
+ val name = ident().toTypeName;
+ accept(RBRACKET);
+ name
+ } else {
+ nme.EMPTY.toTypeName
+ }
+
+ /** StableId ::= Id
+ * | StableRef `.' Id
+ * | [Id '.'] super [MixinQualifier] ` `.' Id
+ */
+ def stableId(): Tree =
+ stableRef(false, false);
+
+ /** QualId ::= Id {`.' Id}
+ */
+ def qualId(): Tree = {
+ val id = atPos(in.currentPos) { Ident(ident()) }
+ if (in.token == DOT) { selectors(id, false, in.skipToken()) }
+ else id
+ }
+
+ /** SimpleExpr ::= literal
+ * | symbol [ArgumentExprs]
+ * | null
+ */
+ def literal(isPattern: boolean, isNegated: boolean): Tree = {
+ def litToTree() = atPos(in.currentPos) {
+ Literal(
+ in.token match {
+ case CHARLIT =>
+ Constant(in.intVal.asInstanceOf[char])
+ case INTLIT =>
+ Constant(in.intVal(isNegated).asInstanceOf[int])
+ case LONGLIT =>
+ Constant(in.intVal(isNegated))
+ case FLOATLIT =>
+ Constant(in.floatVal(isNegated).asInstanceOf[float])
+ case DOUBLELIT =>
+ Constant(in.floatVal(isNegated))
+ case STRINGLIT | SYMBOLLIT =>
+ Constant(in.name.toString())
+ case TRUE =>
+ Constant(true)
+ case FALSE =>
+ Constant(false)
+ case NULL =>
+ Constant(null)
+ case _ =>
+ syntaxError("illegal literal", true);
+ null
+ })
+ }
+
+ val isSymLit = in.token == SYMBOLLIT;
+ val t = litToTree();
+ val pos = in.skipToken();
+ if (isSymLit) {
+ atPos(pos) {
+ var symid = scalaDot(nme.Symbol);
+ if (isPattern) { symid = convertToTypeId(symid) }
+ Apply(symid, List(t))
+ }
+ } else {
+ t
+ }
+ }
+
+ def newLineOpt(): unit = if (in.token == NEWLINE) in.nextToken();
+
+//////// TYPES ///////////////////////////////////////////////////////////////
+
+ /** TypedOpt ::= [`:' Type]
+ */
+ def typedOpt(): Tree =
+ if (in.token == COLON) { in.nextToken(); typ() }
+ else TypeTree();
+
+ /** RequiresTypedOpt ::= [`:' SimpleType | requires SimpleType]
+ */
+ def requiresTypeOpt(): Tree =
+ if (in.token == COLON | in.token == REQUIRES) { in.nextToken(); simpleType() }
+ else TypeTree();
+
+ /** Types ::= Type {`,' Type}
+ */
+ def types(): List[Tree] = {
+ val ts = new ListBuffer[Tree] + typ();
+ while (in.token == COMMA) {
+ in.nextToken();
+ ts += typ();
+ }
+ ts.toList
+ }
+
+ /** Type ::= Type1 `=>' Type
+ * | `(' [Types] `)' `=>' Type
+ * | Type1
+ */
+ def typ(): Tree = {
+ val t =
+ if (in.token == LPAREN) {
+ in.nextToken();
+ if (in.token == RPAREN) {
+ in.nextToken();
+ atPos(accept(ARROW)) { makeFunctionTypeTree(List(), typ()) }
+ } else {
+ val t0 = typ();
+ if (in.token == COMMA) {
+ in.nextToken();
+ val ts = new ListBuffer[Tree] + t0 ++ types();
+ accept(RPAREN);
+ atPos (accept(ARROW)) { makeFunctionTypeTree(ts.toList, typ()) }
+ } else {
+ accept(RPAREN); t0
+ }
+ }
+ } else {
+ type1()
+ }
+ if (in.token == ARROW) atPos(in.skipToken()) {
+ makeFunctionTypeTree(List(t), typ()) }
+ else t
+ }
+
+ /** Type1 ::= SimpleType {with SimpleType} [Refinement]
+ */
+ def type1(): Tree = {
+ val pos = in.currentPos;
+ var ts = new ListBuffer[Tree] + simpleType();
+ while (in.token == WITH) {
+ in.nextToken(); ts += simpleType()
+ }
+ atPos(pos) {
+ if (in.token == LBRACE) CompoundTypeTree(Template(ts.toList, refinement()))
+ else makeIntersectionTypeTree(ts.toList)
+ }
+ }
+
+ /** SimpleType ::= SimpleType TypeArgs
+ * | SimpleType `#' Id
+ * | StableId
+ * | StableRef `.' type
+ * | `(' Type `)'
+ */
+ def simpleType(): Tree = {
+ val pos = in.currentPos;
+ var t: Tree =
+ if (in.token == LPAREN) {
+ in.nextToken();
+ val t = typ();
+ accept(RPAREN);
+ t
+ } else {
+ val r = stableRef(false, true);
+ val x = r match {
+ case SingletonTypeTree(_) => r
+ case _ => convertToTypeId(r);
+ }
+ // System.err.println("SIMPLE_TYPE: " + r.pos + " " + r + " => " + x.pos + " " + x);
+ x;
+ }
+ while (true) {
+ if (in.token == HASH)
+ t = atPos(in.skipToken()) {
+ SelectFromTypeTree(t, ident().toTypeName);
+ }
+ else if (in.token == LBRACKET)
+ t = atPos(pos) { AppliedTypeTree(t, typeArgs()) }
+ else
+ return t
+ }
+ null; //dummy
+ }
+
+ /** TypeArgs ::= `[' Types `]'
+ */
+ def typeArgs(): List[Tree] = {
+ accept(LBRACKET);
+ val ts = types();
+ accept(RBRACKET);
+ ts
+ }
+
+//////// EXPRESSIONS ////////////////////////////////////////////////////////
+
+ /** EqualsExpr ::= `=' Expr
+ */
+ def equalsExpr(): Tree = {
+ accept(EQUALS);
+ expr()
+ }
+
+ /** Exprs ::= Expr {`,' Expr} [ `:' `_' `*' ]
+ */
+ def exprs(): List[Tree] = {
+ val ts = new ListBuffer[Tree] + expr(true, false);
+ while (in.token == COMMA) {
+ in.nextToken(); ts += expr(true, false)
+ }
+ ts.toList
+ }
+
+ /** Expr ::= Bindings `=>' Expr
+ * | Expr1
+ * ResultExpr ::= Bindings `=>' Block
+ * | Expr1
+ * Expr1 ::= if (' Expr `)' [NL] Expr [[`;'] else Expr]
+ * | try `{' block `}' [catch `{' caseClauses `}'] [finally Expr]
+ * | while `(' Expr `)' [NL] Expr
+ * | do Expr [SEP] while `(' Expr `)'
+ * | for (`(' Enumerators `)' | '{' Enumerators '}') [NL] (yield) Expr
+ * | throw Expr
+ * | return [Expr]
+ * | [SimpleExpr `.'] Id `=' Expr
+ * | SimpleExpr ArgumentExprs `=' Expr
+ * | `.' SimpleExpr
+ * | PostfixExpr [`:' Type1]
+ * | PostfixExpr match `{' caseClauses `}'
+ * Bindings ::= Id [`:' Type1]
+ * | `(' [Binding {`,' Binding}] `)'
+ * Binding ::= Id [`:' Type]
+ */
+ def expr(): Tree =
+ expr(false, false);
+
+ def expr(isArgument: boolean, isInBlock: boolean): Tree = in.token match {
+ case IF =>
+ val pos = in.skipToken();
+ accept(LPAREN);
+ val cond = expr();
+ accept(RPAREN);
+ newLineOpt();
+ val thenp = expr();
+ val elsep =
+ if (in.token == ELSE) { in.nextToken(); expr() }
+ else EmptyTree;
+ atPos(pos) { If(cond, thenp, elsep) }
+ case TRY =>
+ atPos(in.skipToken()) {
+ accept(LBRACE);
+ val body = block();
+ accept(RBRACE);
+ val catches =
+ if (in.token == CATCH) {
+ in.nextToken();
+ accept(LBRACE);
+ val cases = caseClauses();
+ accept(RBRACE);
+ cases
+ } else List();
+ val finalizer =
+ if (in.token == FINALLY) { in.nextToken(); expr() }
+ else EmptyTree;
+ Try(body, catches, finalizer)
+ }
+ case WHILE =>
+ val lname: Name = unit.fresh.newName("label$");
+ val pos = in.skipToken();
+ accept(LPAREN);
+ val cond = expr();
+ accept(RPAREN);
+ newLineOpt();
+ val body = expr();
+ atPos(pos) { makeWhile(lname, cond, body) }
+ case DO =>
+ val lname: Name = unit.fresh.newName("label$");
+ val pos = in.skipToken();
+ val body = expr();
+ if (in.token == SEMI || in.token == NEWLINE) in.nextToken();
+ accept(WHILE);
+ accept(LPAREN);
+ val cond = expr();
+ accept(RPAREN);
+ atPos(pos) { makeDoWhile(lname, body, cond) }
+ case FOR =>
+ atPos(in.skipToken()) {
+ val startToken = in.token;
+ accept(if (startToken == LBRACE) LBRACE else LPAREN);
+ val enums = enumerators();
+ accept(if (startToken == LBRACE) RBRACE else RPAREN);
+ newLineOpt();
+ if (in.token == YIELD) {
+ in.nextToken(); makeForYield(enums, expr())
+ } else makeFor(enums, expr())
+ }
+ case RETURN =>
+ atPos(in.skipToken()) {
+ Return(if (isExprIntro) expr() else Literal(()))
+ }
+ case THROW =>
+ atPos(in.skipToken()) {
+ Throw(expr())
+ }
+ case DOT =>
+ atPos(in.skipToken()) {
+ if (in.token == IDENTIFIER) makeClosure(simpleExpr())
+ else { syntaxError("identifier expected", true); errorTermTree }
+ }
+ case _ =>
+ var t = postfixExpr();
+ if (in.token == EQUALS) {
+ t match {
+ case Ident(_) | Select(_, _) | Apply(_, _) =>
+ t = atPos(in.skipToken()) { makeAssign(t, expr()) }
+ case _ =>
+ }
+ } else if (in.token == COLON) {
+ val pos = in.skipToken();
+ if (isArgument && in.token == USCORE) {
+ val pos1 = in.skipToken();
+ if (in.token == IDENTIFIER && in.name == nme.STAR) {
+ in.nextToken();
+ t = atPos(pos) {
+ Typed(t, atPos(pos1) { Ident(nme.WILDCARD_STAR.toTypeName) })
+ }
+ } else {
+ syntaxError(in.currentPos, "`*' expected", true);
+ }
+ } else {
+ t = atPos(pos) { Typed(t, type1()) }
+ }
+ } else if (in.token == MATCH) {
+ t = atPos(in.skipToken()) {
+ accept(LBRACE);
+ val cases = caseClauses();
+ accept(RBRACE);
+ Match(t, cases): Tree
+ }
+ }
+ if (in.token == ARROW) {
+ t = atPos(in.skipToken()) {
+ Function(convertToParams(t), if (isInBlock) block() else expr())
+ }
+ }
+ t
+ }
+
+ /** PostfixExpr ::= [`.'] InfixExpr [Id]
+ * InfixExpr ::= PrefixExpr
+ * | InfixExpr Id InfixExpr
+ */
+ def postfixExpr(): Tree = {
+ val base = opstack;
+ var top = prefixExpr();
+ while (in.token == IDENTIFIER) {
+ top = reduceStack(
+ true, base, top, precedence(in.name), treeInfo.isLeftAssoc(in.name));
+ opstack = OpInfo(top, in.name, in.currentPos) :: opstack;
+ ident();
+ if (isExprIntro) {
+ top = prefixExpr();
+ } else {
+ val topinfo = opstack.head;
+ opstack = opstack.tail;
+ return Select(
+ reduceStack(true, base, topinfo.operand, 0, true),
+ topinfo.operator.encode).setPos(topinfo.pos);
+ }
+ }
+ reduceStack(true, base, top, 0, true)
+ }
+
+ /** PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr
+ */
+ def prefixExpr(): Tree =
+ if (in.token == IDENTIFIER && in.name == MINUS) {
+ val name = ident();
+ in.token match {
+ case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => literal(false, true)
+ case _ => atPos(in.currentPos) { Select(simpleExpr(), name) }
+ }
+ } else if (in.token == IDENTIFIER && (in.name == PLUS || in.name == TILDE || in.name == BANG)) {
+ val pos = in.currentPos;
+ val name = ident();
+ atPos(pos) { Select(simpleExpr(), name) }
+ } else {
+ simpleExpr()
+ }
+
+ /* SimpleExpr ::= new SimpleType {`(' [Exprs] `)'} {`with' SimpleType} [TemplateBody]
+ * | SimpleExpr1
+ * SimpleExpr1 ::= literal
+ * | xLiteral
+ * | StableRef
+ * | `(' [Expr] `)'
+ * | BlockExpr
+ * | SimpleExpr `.' Id
+ * | SimpleExpr TypeArgs
+ * | SimpleExpr1 ArgumentExprs
+ */
+ def simpleExpr(): Tree = {
+ var t: Tree = null;
+ var isNew = false;
+ in.token match {
+ case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT |
+ SYMBOLLIT | TRUE | FALSE | NULL =>
+ t = literal(false, false);
+ case XMLSTART =>
+ t = xmlp.xLiteral;
+ //Console.println("successfully parsed XML at "+t); // DEBUG
+ case IDENTIFIER | THIS | SUPER =>
+ t = stableRef(true, false);
+ case LPAREN =>
+ val pos = in.skipToken();
+ if (in.token == RPAREN) {
+ in.nextToken();
+ t = Literal(()).setPos(pos);
+ } else {
+ t = expr();
+ if (in.token == COMMA) {
+ val commapos = in.skipToken();
+ val ts = new ListBuffer[Tree] + t ++ exprs();
+ accept(RPAREN);
+ if (in.token == ARROW) {
+ t = atPos(pos) {
+ Function(ts.toList map convertToParam, TypeTree())
+ }
+ } else {
+ syntaxError(commapos, "`)' expected", false);
+ }
+ } else {
+ accept(RPAREN);
+ }
+ }
+ case LBRACE =>
+ t = blockExpr()
+ case NEW =>
+ t = atPos(in.skipToken()) {
+ val parents = new ListBuffer[Tree] + simpleType();
+ val argss = new ListBuffer[List[Tree]];
+ if (in.token == LPAREN)
+ do { argss += argumentExprs() } while (in.token == LPAREN)
+ else argss += List();
+ while (in.token == WITH) {
+ in.nextToken();
+ parents += simpleType()
+ }
+ val stats = if (in.token == LBRACE) templateBody() else List();
+ makeNew(parents.toList, stats, argss.toList)
+ }
+ isNew = true
+ case _ =>
+ syntaxError("illegal start of simple expression", true);
+ t = errorTermTree
+ }
+ while (true) {
+ in.token match {
+ case DOT =>
+ t = atPos(in.skipToken()) { Select(t, ident()) }
+ case LBRACKET =>
+ t match {
+ case Ident(_) | Select(_, _) =>
+ t = atPos(in.currentPos) { TypeApply(t, typeArgs()) }
+ case _ =>
+ return t;
+ }
+ case LPAREN | LBRACE if (!isNew) =>
+ t = atPos(in.currentPos) { Apply(t, argumentExprs()) }
+ case _ =>
+ return t
+ }
+ isNew = false
+ }
+ null;//dummy
+ }
+
+ /** ArgumentExprs ::= `(' [Exprs] `)'
+ * | BlockExpr
+ */
+ def argumentExprs(): List[Tree] = {
+ if (in.token == LBRACE) {
+ List(blockExpr())
+ } else {
+ accept(LPAREN);
+ val ts = if (in.token == RPAREN) List() else exprs();
+ accept(RPAREN);
+ ts
+ }
+ }
+
+ /** BlockExpr ::= `{' CaseClauses | Block `}'
+ */
+ def blockExpr(): Tree = {
+ val res = atPos(accept(LBRACE)) {
+ if (in.token == CASE) makeVisitor(caseClauses())
+ else block()
+ }
+ accept(RBRACE);
+ res
+ }
+
+ /** Block ::= BlockStatSeq
+ */
+ def block(): Tree = makeBlock(blockStatSeq(new ListBuffer[Tree]));
+
+ /** CaseClauses ::= CaseClause {CaseClause}
+ */
+ def caseClauses(): List[CaseDef] = {
+ val ts = new ListBuffer[CaseDef];
+ do { ts += caseClause();
+ } while (in.token == CASE);
+ ts.toList
+ }
+
+ /** caseClause : =>= case Pattern [if PostfixExpr] `=>' Block
+ */
+ def caseClause(): CaseDef =
+ atPos(accept(CASE)) {
+ val pat = pattern();
+ val guard =
+ if (in.token == IF) { in.nextToken(); postfixExpr() }
+ else EmptyTree;
+ makeCaseDef(pat, guard, atPos(accept(ARROW))(block()))
+ }
+
+ /** Enumerators ::= Generator {SEP Enumerator}
+ * Enumerator ::= Generator
+ * | Expr
+ */
+ def enumerators(): List[Tree] = {
+ val enums = new ListBuffer[Tree] + generator();
+ while (in.token == SEMI || in.token == NEWLINE) {
+ in.nextToken();
+ enums += (if (in.token == VAL) generator() else expr())
+ }
+ enums.toList
+ }
+
+ /** Generator ::= val Pattern1 `<-' Expr
+ */
+ def generator(): Tree =
+ atPos(accept(VAL)) {
+ makeGenerator(pattern1(false), { accept(LARROW); expr() })
+ }
+
+//////// PATTERNS ////////////////////////////////////////////////////////////
+
+ /** Patterns ::= SeqPattern { , SeqPattern } */
+ def patterns(): List[Tree] = {
+ val ts = new ListBuffer[Tree];
+ ts += pattern(true);
+ while (in.token == COMMA) {
+ in.nextToken(); ts += pattern(true);
+ }
+ ts.toList
+ }
+
+ /** Pattern ::= Pattern1 { `|' Pattern1 }
+ * SeqPattern ::= SeqPattern1 { `|' SeqPattern1 }
+ */
+ def pattern(seqOK: boolean): Tree = {
+ val pos = in.currentPos;
+ val t = pattern1(seqOK);
+ if (in.token == IDENTIFIER && in.name == BAR) {
+ val ts = new ListBuffer[Tree] + t;
+ while (in.token == IDENTIFIER && in.name == BAR) {
+ in.nextToken(); ts += pattern1(seqOK);
+ }
+ atPos(pos) { makeAlternative(ts.toList) }
+ } else t
+ }
+
+ def pattern(): Tree = pattern(false);
+
+ /** Pattern1 ::= varid `:' Type1
+ * | `_' `:' Type1
+ * | Pattern2
+ * SeqPattern1 ::= varid `:' Type1
+ * | `_' `:' Type1
+ * | [SeqPattern2]
+ */
+ def pattern1(seqOK: boolean): Tree =
+ if (seqOK && !isExprIntro) {
+ atPos(in.currentPos) { Sequence(List()) }
+ } else {
+ val p = pattern2(seqOK);
+ p match {
+ case Ident(name) if (treeInfo.isVariableName(name) && in.token == COLON) =>
+ atPos(in.skipToken()) { Typed(p, type1()) }
+ case _ =>
+ p
+ }
+ }
+
+ /* Pattern2 ::= varid [ @ Pattern3 ]
+ * | Pattern3
+ * SeqPattern2 ::= varid [ @ SeqPattern3 ]
+ * | SeqPattern3
+ */
+ def pattern2(seqOK: boolean): Tree = {
+ val p = pattern3(seqOK);
+ if (in.token == AT) {
+ p match {
+ case Ident(name) =>
+ if (name == nme.WILDCARD) {
+ in.nextToken(); pattern3(seqOK)
+ } else if (treeInfo.isVariableName(name)) {
+ atPos(in.skipToken()) { Bind(name, pattern3(seqOK)) }
+ } else {
+ p
+ }
+ case _ =>
+ p
+ }
+ } else p
+ }
+
+ /* Pattern3 ::= SimplePattern
+ * | SimplePattern {Id SimplePattern}
+ * SeqPattern3 ::= SeqSimplePattern [ '*' | '?' | '+' ]
+ * | SeqSimplePattern {Id SeqSimplePattern}
+ */
+ def pattern3(seqOK: boolean): Tree = {
+ val base = opstack;
+ var top = simplePattern(seqOK);
+ if (seqOK && in.token == IDENTIFIER) {
+ if (in.name == STAR)
+ return atPos(in.skipToken())(Star(top))
+ else if (in.name == PLUS)
+ return atPos(in.skipToken())(makePlus(top))
+ else if (in.name == OPT)
+ return atPos(in.skipToken())(makeOpt(top))
+ }
+ while (in.token == IDENTIFIER && in.name != BAR) {
+ top = reduceStack(
+ false, base, top, precedence(in.name), treeInfo.isLeftAssoc(in.name));
+ opstack = OpInfo(top, in.name, in.currentPos) :: opstack;
+ ident();
+ top = simplePattern(seqOK)
+ }
+ reduceStack(false, base, top, 0, true)
+ }
+
+ /** SimplePattern ::= varid
+ * | `_'
+ * | literal
+ * | `<' xLiteralPattern
+ * | StableId [ `(' Patterns `)' ]
+ * | `(' [Pattern] `)'
+ * SimpleSeqPattern ::= varid
+ * | `_'
+ * | literal
+ * | `<' xLiteralPattern
+ * | StableId [ `(' Patterns `)' ]
+ * | `(' Patterns `)'
+ */
+ def simplePattern(seqOK: boolean): Tree = in.token match {
+ case IDENTIFIER | THIS =>
+ var t = stableId();
+ in.token match {
+ case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT =>
+ t match {
+ case Ident(name) if name == nme.MINUS =>
+ return literal(true, true);
+ case _ =>
+ }
+ case _ =>
+ }
+ if (in.token == LPAREN) {
+ atPos(in.skipToken()) {
+ val ps = if (in.token == RPAREN) List() else patterns();
+ accept(RPAREN);
+ Apply(convertToTypeId(t), ps)
+ }
+ } else t
+ case USCORE =>
+ atPos(in.skipToken()) { Ident(nme.WILDCARD) }
+ case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL =>
+ literal(true, false)
+ case LPAREN =>
+ val pos = in.skipToken();
+ val p =
+ if (seqOK) atPos(pos) { makeSequence(patterns()) }
+ else if (in.token != RPAREN) pattern(false);
+ else Literal(()).setPos(pos);
+ accept(RPAREN);
+ p
+ case XMLSTART =>
+ val r = xmlp.xLiteralPattern;
+ //Console.println("successfully parsed xml pattern "+r); DEBUG
+ r
+ case _ =>
+ syntaxError("illegal start of simple pattern", true);
+ errorPatternTree
+ }
+
+////////// MODIFIERS ////////////////////////////////////////////////////////////
+
+ /** Modifiers ::= {Modifier}
+ * Modifier ::= final
+ * | private [ "[" Id "]" ]
+ * | protected
+ * | override
+ * | abstract
+ */
+ def modifiers(): Modifiers = {
+ def loop(mods: int): int = in.token match {
+ case ABSTRACT =>
+ loop(addMod(mods, Flags.ABSTRACT))
+ case FINAL =>
+ loop(addMod(mods, Flags.FINAL))
+ case SEALED =>
+ loop(addMod(mods, Flags.SEALED))
+ case PRIVATE =>
+ loop(addMod(mods, Flags.PRIVATE))
+ case PROTECTED =>
+ loop(addMod(mods, Flags.PROTECTED))
+ case OVERRIDE =>
+ loop(addMod(mods, Flags.OVERRIDE))
+ case IMPLICIT =>
+ loop(addMod(mods, Flags.IMPLICIT))
+ case _ =>
+ mods
+ }
+ var mods = loop(0);
+ if ((mods & (Flags.ABSTRACT | Flags.OVERRIDE)) == (Flags.ABSTRACT | Flags.OVERRIDE))
+ mods = mods & ~(Flags.ABSTRACT | Flags.OVERRIDE) | Flags.ABSOVERRIDE;
+ Modifiers(mods)
+ }
+
+ /** LocalClassModifiers ::= {LocalClassModifier}
+ * LocalClassModifier ::= final
+ * | private
+ */
+ def localClassModifiers(): Modifiers = {
+ def loop(mods: int): int = in.token match {
+ case ABSTRACT =>
+ loop(addMod(mods, Flags.ABSTRACT))
+ case FINAL =>
+ loop(addMod(mods, Flags.FINAL))
+ case SEALED =>
+ loop(addMod(mods, Flags.SEALED))
+ case _ =>
+ mods
+ }
+ Modifiers(loop(0))
+ }
+
+ private def addMod(mods: int, mod: int): int = {
+ if ((mods & mod) != 0)
+ syntaxError(in.currentPos, "repeated modifier", false);
+ in.nextToken();
+ mods | mod;
+ }
+
+//////// PARAMETERS //////////////////////////////////////////////////////////
+
+ /** ParamClauses ::= {`(' [Param {`,' Param}] ')'}
+ * [`(' implicit Param {`,' Param} `)']
+ * Param ::= Id `:' ParamType
+ * ClassParamClauses ::= {`(' [ClassParam {`' ClassParam}] ')'}
+ * [`(' implicit ClassParam {`,' ClassParam} `)']
+ * ClassParam ::= [[modifiers] (val | var)] Param
+ */
+ def paramClauses(owner: Name, implicitViews: List[Tree], ofCaseClass: boolean): List[List[ValDef]] = {
+ var implicitmod = 0;
+ var caseParam = ofCaseClass;
+ def param(): ValDef = {
+ atPos(in.currentPos) {
+ var mods = Modifiers(Flags.PARAM);
+ if (owner.isTypeName) {
+ mods = modifiers() | Flags.PARAMACCESSOR;
+ if (in.token == VAL) {
+ in.nextToken()
+ } else if (in.token == VAR) {
+ mods = mods | Flags.MUTABLE;
+ in.nextToken()
+ } else {
+ if (mods.flags != Flags.PARAMACCESSOR) accept(VAL);
+ if (!(caseParam)) mods = mods | Flags.PRIVATE | Flags.LOCAL;
+ }
+ if (caseParam) mods = mods | Flags.CASEACCESSOR;
+ }
+ val name = ident();
+ accept(COLON);
+ val bynamemod = if (in.token == ARROW) Flags.BYNAMEPARAM else 0;
+ ValDef(mods | implicitmod | bynamemod, name, paramType(), EmptyTree)
+ }
+ }
+ def paramClause(): List[ValDef] = {
+ val params = new ListBuffer[ValDef];
+ if (in.token != RPAREN) {
+ if (in.token == IMPLICIT) {
+ if (!implicitViews.isEmpty)
+ syntaxError("cannot have both view bounds `<%' and implicit parameters", false);
+ in.nextToken();
+ implicitmod = Flags.IMPLICIT
+ }
+ params += param();
+ while (in.token == COMMA) {
+ in.nextToken(); params += param()
+ }
+ }
+ params.toList
+ }
+ val vds = new ListBuffer[List[ValDef]];
+ val pos = in.currentPos;
+ while (implicitmod == 0 && in.token == LPAREN) {
+ in.nextToken();
+ vds += paramClause();
+ accept(RPAREN);
+ caseParam = false
+ }
+ val result = vds.toList;
+ if (owner == nme.CONSTRUCTOR &&
+ (result.isEmpty ||
+ (!result.head.isEmpty && result.head.head.mods.hasFlag(Flags.IMPLICIT))))
+ if (in.token == LBRACKET)
+ syntaxError(pos, "no type parameters allowed here", false);
+ else
+ syntaxError(pos, "auxiliary constructor needs non-implicit parameter list", false);
+ addImplicitViews(owner, result, implicitViews)
+ }
+
+ /** ParamType ::= Type | `=>' Type | Type `*'
+ */
+ def paramType(): Tree =
+ if (in.token == ARROW)
+ atPos(in.skipToken()) {
+ AppliedTypeTree(
+ scalaDot(nme.BYNAME_PARAM_CLASS_NAME.toTypeName), List(typ()))
+ }
+ else {
+ val t = typ();
+ if (in.token == IDENTIFIER && in.name == STAR) {
+ in.nextToken();
+ atPos(t.pos) {
+ AppliedTypeTree(
+ scalaDot(nme.REPEATED_PARAM_CLASS_NAME.toTypeName), List(t))
+ }
+ } else t
+ }
+
+ /** TypeParamClauseOpt ::= [`[' TypeParam {`,' TypeParam} `]']
+ * TypeParam ::= [`+' | `-'] FunTypeParam
+ * FunTypeParamClauseOpt ::= [`[' FunTypeParam {`,' FunTypeParam} `]']
+ * FunTypeParam ::= Id TypeBounds
+ */
+ def typeParamClauseOpt(owner: Name, implicitViews: ListBuffer[Tree]): List[AbsTypeDef] = {
+ def typeParam(): AbsTypeDef = {
+ var mods = Modifiers(Flags.PARAM);
+ if (owner.isTypeName && in.token == IDENTIFIER) {
+ if (in.name == PLUS) {
+ in.nextToken();
+ mods = mods | Flags.COVARIANT;
+ } else if (in.name == MINUS) {
+ in.nextToken();
+ mods = mods | Flags.CONTRAVARIANT;
+ }
+ }
+ val pname = ident();
+ val param = atPos(in.currentPos) { typeBounds(mods, pname) }
+ if (in.token == VIEWBOUND && (implicitViews != null))
+ implicitViews += atPos(in.skipToken()) {
+ makeFunctionTypeTree(List(Ident(pname.toTypeName)), typ())
+ }
+ param
+ }
+ val params = new ListBuffer[AbsTypeDef];
+ if (in.token == LBRACKET) {
+ in.nextToken();
+ params += typeParam();
+ while (in.token == COMMA) {
+ in.nextToken();
+ params += typeParam();
+ }
+ accept(RBRACKET);
+ }
+ params.toList
+ }
+
+ /** TypeBounds ::= [`>:' Type] [`<:' Type]
+ */
+ def typeBounds(mods: Modifiers, name: Name): AbsTypeDef = {
+ def bound(tok: int, default: Name): Tree =
+ if (in.token == tok) { in.nextToken(); typ() }
+ else scalaDot(default.toTypeName);
+ AbsTypeDef(mods, name.toTypeName,
+ bound(SUPERTYPE, nme.All),
+ bound(SUBTYPE, nme.Any))
+ }
+
+//////// DEFS ////////////////////////////////////////////////////////////////
+
+
+ /** Import ::= import ImportExpr {`,' ImportExpr}
+ */
+ def importClause(): List[Tree] = {
+ accept(IMPORT);
+ val ts = new ListBuffer[Tree] + importExpr();
+ while (in.token == COMMA) {
+ in.nextToken(); ts += importExpr();
+ }
+ ts.toList
+ }
+
+ /** ImportRef ::= StableId `.' (Id | `_' | ImportSelectors)
+ */
+ def importExpr(): Tree =
+ atPos(in.currentPos) {
+ var t: Tree = null;
+ var pos = 0;
+ if (in.token == THIS) {
+ t = atPos(in.currentPos) { This(nme.EMPTY.toTypeName) }
+ t = atPos(accept(DOT)) { Select(t, ident()) }
+ pos = accept(DOT);
+ } else {
+ val i = atPos(in.currentPos) { Ident(ident()) }
+ pos = accept(DOT);
+ if (in.token == THIS) {
+ in.nextToken();
+ t = atPos(i.pos) { This(i.name.toTypeName) }
+ t = atPos(accept(DOT)) { Select(t, ident()) }
+ pos = accept(DOT);
+ } else {
+ t = i;
+ }
+ }
+ def loop: Tree =
+ if (in.token == USCORE) {
+ in.nextToken();
+ Import(t, List(Pair(nme.WILDCARD, null)))
+ } else if (in.token == LBRACE) {
+ Import(t, importSelectors())
+ } else {
+ val name = ident();
+ if (in.token == DOT) {
+ t = atPos(pos) { Select(t, name) }
+ pos = accept(DOT);
+ loop
+ } else {
+ Import(t, List(Pair(name, name)));
+ }
+ }
+ loop
+ }
+
+ /** ImportSelectors ::= `{' {ImportSelector `,'} (ImportSelector | `_') `}'
+ */
+ def importSelectors(): List[Pair[Name, Name]] = {
+ val names = new ListBuffer[Pair[Name, Name]];
+ accept(LBRACE);
+ var isLast = importSelector(names);
+ while (!isLast && in.token == COMMA) {
+ in.nextToken();
+ isLast = importSelector(names);
+ }
+ accept(RBRACE);
+ names.toList
+ }
+
+ /** ImportSelector ::= Id [`=>' Id | `=>' `_']
+ */
+ def importSelector(names: ListBuffer[Pair[Name, Name]]): boolean =
+ if (in.token == USCORE) {
+ in.nextToken(); names += Pair(nme.WILDCARD, null); true
+ } else {
+ val name = ident();
+ names += Pair(
+ name,
+ if (in.token == ARROW) {
+ in.nextToken();
+ if (in.token == USCORE) { in.nextToken(); nme.WILDCARD } else ident()
+ } else {
+ name
+ });
+ false
+ }
+
+ /** Def ::= val PatDef {`,' PatDef}
+ * | var VarDef {`,' VatDef}
+ * | def FunDef {`,' FunDef}
+ * | type TypeDef {`,' TypeDef}
+ * | TmplDef
+ * Dcl ::= val ValDcl {`,' ValDcl}
+ * | var ValDcl {`,' ValDcl}
+ * | def FunDcl {`,' FunDcl}
+ * | type TypeDcl {`,' TypeDcl}
+ */
+ def defOrDcl(mods: Modifiers): List[Tree] = {
+ in.token match {
+ case VAL =>
+ patDefOrDcl(mods);
+ case VAR =>
+ varDefOrDcl(mods);
+ case DEF =>
+ List(funDefOrDcl(mods));
+ case TYPE =>
+ in.nextToken();
+ List(typeDefOrDcl(mods))
+ case _ =>
+ List(tmplDef(mods))
+ }
+ }
+
+ /** PatDef ::= Pattern2 {`,' Pattern2} [`:' Type] `=' Expr
+ * ValDcl ::= Id {`,' Id} `:' Type
+ */
+ def patDefOrDcl(mods: Modifiers): List[Tree] = {
+ var newmods = mods;
+ var lhs = new ListBuffer[Tree];
+ do {
+ in.nextToken();
+ lhs += pattern2(false)
+ } while (in.token == COMMA);
+ val tp = typedOpt();
+ val rhs =
+ if (tp.isEmpty || in.token == EQUALS) equalsExpr()
+ else {
+ newmods = newmods | Flags.DEFERRED;
+ EmptyTree
+ }
+ def mkDefs(p: Tree): List[Tree] = {
+ //Console.println("DEBUG: p = "+p.toString()); // DEBUG
+ val trees =
+ makePatDef(newmods,
+ if (tp.isEmpty)
+ p
+ else
+ Typed(p, tp),
+ rhs.duplicate) map atPos(p.pos);
+ if (rhs == EmptyTree) {
+ trees match {
+ case List(ValDef(_, _, _, EmptyTree)) =>
+ case _ => syntaxError(p.pos, "pattern definition may not be abstract", false);
+ }
+ }
+ trees
+ }
+ for (val p <- lhs.toList; val d <- mkDefs(p)) yield d
+ }
+
+ /** VarDef ::= Id {`,' Id} [`:' Type] `=' Expr
+ * | Id {`,' Id} `:' Type `=' `_'
+ * VarDcl ::= Id {`,' Id} `:' Type
+ */
+ def varDefOrDcl(mods: Modifiers): List[Tree] = {
+ var newmods = mods | Flags.MUTABLE;
+ val lhs = new ListBuffer[Pair[Int, Name]];
+ do {
+ lhs += Pair(in.skipToken(), ident())
+ } while (in.token == COMMA);
+ val tp = typedOpt();
+ val rhs = if (tp.isEmpty || in.token == EQUALS) {
+ accept(EQUALS);
+ if (tp != EmptyTree && in.token == USCORE) {
+ in.nextToken();
+ EmptyTree
+ } else
+ expr();
+ } else {
+ newmods = newmods | Flags.DEFERRED;
+ EmptyTree
+ }
+ for (val Pair(pos, name) <- lhs.toList) yield
+ atPos(pos) { ValDef(newmods, name, tp.duplicate, rhs.duplicate) }
+ }
+
+ /** FunDef ::= FunSig `:' Type `=' Expr
+ * | this ParamClause ParamClauses `=' ConstrExpr
+ * FunDcl ::= FunSig `:' Type
+ * FunSig ::= id [FunTypeParamClause] ParamClauses
+ */
+ def funDefOrDcl(mods: Modifiers): Tree =
+ atPos(in.skipToken()) {
+ if (in.token == THIS) {
+ in.nextToken();
+ val vparamss = paramClauses(nme.CONSTRUCTOR, List(), false);
+ accept(EQUALS);
+ DefDef(mods, nme.CONSTRUCTOR, List(), vparamss, TypeTree(), constrExpr())
+ } else {
+ var newmods = mods;
+ val name = ident();
+ val implicitViews = new ListBuffer[Tree];
+ val tparams = typeParamClauseOpt(name, implicitViews);
+ val vparamss = paramClauses(name, implicitViews.toList, false);
+ val restype = typedOpt();
+ val rhs =
+ if (restype.isEmpty || in.token == EQUALS) equalsExpr();
+ else {
+ newmods = newmods | Flags.DEFERRED;
+ EmptyTree
+ }
+ DefDef(newmods, name, tparams, vparamss, restype, rhs)
+ }
+ }
+
+ /** ConstrExpr ::= SelfInvocation
+ * | `{' SelfInvocation {SEP BlockStat} `}'
+ * SelfInvocation ::= this ArgumentExpr
+ */
+ def constrExpr(): Tree =
+ if (in.token == LBRACE) {
+ atPos(in.skipToken()) {
+ val statlist = new ListBuffer[Tree];
+ statlist += selfInvocation();
+ val stats =
+ if (in.token == SEMI || in.token == NEWLINE) { in.nextToken(); blockStatSeq(statlist) }
+ else statlist.toList;
+ accept(RBRACE);
+ makeBlock(stats)
+ }
+ } else selfInvocation();
+
+ /** SelfInvocation ::= this ArgumentExprs
+ */
+ def selfInvocation(): Tree =
+ atPos(accept(THIS)) { Apply(Ident(nme.CONSTRUCTOR), argumentExprs()) }
+
+ /** TypeDef ::= Id `=' Type
+ * TypeDcl ::= Id TypeBounds
+ */
+ def typeDefOrDcl(mods: Modifiers): Tree =
+ atPos(in.currentPos) {
+ val name = ident().toTypeName;
+ in.token match {
+ case LBRACKET =>
+ val tparams = typeParamClauseOpt(name, null);
+ accept(EQUALS);
+ AliasTypeDef(mods, name, tparams, typ())
+ case EQUALS =>
+ in.nextToken();
+ AliasTypeDef(mods, name, List(), typ())
+ case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | COMMA | RBRACE =>
+ typeBounds(mods | Flags.DEFERRED, name)
+ case _ =>
+ syntaxError("`=', `>:', or `<:' expected", true);
+ EmptyTree
+ }
+ }
+
+ /** TmplDef ::= ([case] class | trait) ClassDef
+ * | [case] object ObjectDef
+ */
+ def tmplDef(mods: Modifiers): Tree = in.token match {
+ case TRAIT =>
+ classDef(mods | Flags.TRAIT | Flags.ABSTRACT);
+ case CLASS =>
+ classDef(mods);
+ case CASECLASS =>
+ classDef(mods | Flags.CASE);
+ case OBJECT =>
+ objectDef(mods);
+ case CASEOBJECT =>
+ objectDef(mods | Flags.CASE);
+ case _ =>
+ syntaxError("illegal start of definition", true);
+ EmptyTree
+ }
+
+ /** ClassDef ::= ClassSig RequiresTypeOpt ClassTemplate
+ * ClassSig ::= Id [TypeParamClause] {ClassParamClause}
+ */
+ def classDef(mods: Modifiers): Tree =
+ atPos(in.skipToken()) {
+ val name = ident().toTypeName;
+ val implicitViews = new ListBuffer[Tree];
+ val tparams = typeParamClauseOpt(name, implicitViews);
+ if (mods.hasFlag(Flags.CASE) && in.token != LPAREN) accept(LPAREN);
+ val vparamss = paramClauses(name, implicitViews.toList, mods.hasFlag(Flags.CASE));
+ val thistpe = requiresTypeOpt();
+ val template = classTemplate(mods, name, vparamss);
+ val mods1 = if (mods.hasFlag(Flags.TRAIT) && (template.body forall treeInfo.isInterfaceMember))
+ mods | Flags.INTERFACE
+ else mods;
+ ClassDef(mods1, name, tparams, thistpe, template)
+ }
+
+ /** ObjectDef ::= Id ClassTemplate
+ */
+ def objectDef(mods: Modifiers): Tree =
+ atPos(in.skipToken()) {
+ val name = ident();
+ val template = classTemplate(mods, name, List());
+ ModuleDef(mods, name, template)
+ }
+
+ /** ClassTemplate ::= [`extends' TemplateParents] [[NL] TemplateBody]
+ * TemplateParents ::= SimpleType {`(' [Exprs] `)'} {`with' SimpleType}
+ */
+ def classTemplate(mods: Modifiers, name: Name, vparamss: List[List[ValDef]]): Template = {
+ val ret = atPos(in.currentPos) {
+ val parents = new ListBuffer[Tree];
+ val argss = new ListBuffer[List[Tree]];
+ if (in.token == EXTENDS) {
+ in.nextToken();
+ val parent = simpleType();
+ // System.err.println("classTempl: " + parent);
+ parents += parent;
+ if (in.token == LPAREN)
+ do { argss += argumentExprs() } while (in.token == LPAREN)
+ else argss += List();
+ while (in.token == WITH) {
+ in.nextToken();
+ parents += simpleType()
+ }
+ } else argss += List();
+ if (name != nme.ScalaObject.toTypeName)
+ parents += scalaScalaObjectConstr;
+ if (mods.hasFlag(Flags.CASE)) parents += caseClassConstr;
+ val ps = parents.toList;
+ if (in.token == NEWLINE && in.next.token == LBRACE) in.nextToken();
+ var body =
+ if (in.token == LBRACE) {
+ templateBody()
+ } else {
+ if (!(in.token == SEMI || in.token == NEWLINE || in.token == COMMA || in.token == RBRACE))
+ syntaxError("`extends' or `{' expected", true);
+ List()
+ }
+ if (!mods.hasFlag(Flags.TRAIT)) Template(ps, vparamss, argss.toList, body)
+ else Template(ps, body)
+ }
+ ret;
+ }
+
+////////// TEMPLATES ////////////////////////////////////////////////////////////
+
+ /** TemplateBody ::= `{' [TemplateStat {SEP TemplateStat}] `}'
+ */
+ def templateBody(): List[Tree] = {
+ accept(LBRACE);
+ var body = templateStatSeq();
+ if (body.isEmpty) body = List(EmptyTree);
+ accept(RBRACE);
+ body
+ }
+
+ /** Refinement ::= `{' [RefineStat {SEP RefineStat}] `}'
+ */
+ def refinement(): List[Tree] = {
+ accept(LBRACE);
+ val body = refineStatSeq();
+ accept(RBRACE);
+ body
+ }
+
+/////// STATSEQS //////////////////////////////////////////////////////////////
+
+ /** Packaging ::= package QualId `{' TopStatSeq `}'
+ */
+ def packaging(): Tree = {
+ atPos(accept(PACKAGE)) {
+ val pkg = qualId();
+ accept(LBRACE);
+ val stats = topStatSeq();
+ accept(RBRACE);
+ makePackaging(pkg, stats)
+ }
+ }
+
+ /** TopStatSeq ::= [TopStat {SEP TopStat}]
+ * TopStat ::= AttributeClauses Modifiers ClsDef
+ * | Packaging
+ * | Import
+ * |
+ */
+ def topStatSeq(): List[Tree] = {
+ val stats = new ListBuffer[Tree];
+ while (in.token != RBRACE && in.token != EOF) {
+ if (in.token == PACKAGE) {
+ stats += packaging()
+ } else if (in.token == IMPORT) {
+ stats ++= importClause()
+ } else if (in.token == CLASS ||
+ in.token == CASECLASS ||
+ in.token == TRAIT ||
+ in.token == OBJECT ||
+ in.token == CASEOBJECT ||
+ in.token == LBRACKET ||
+ isModifier) {
+ val attrs = attributeClauses();
+ (stats ++
+ joinAttributes(attrs, joinComment(List(tmplDef(modifiers() | traitAttribute(attrs))))))
+ } else if (in.token != SEMI && in.token != NEWLINE) {
+ syntaxError("illegal start of class or object definition", true);
+ }
+ if (in.token != RBRACE && in.token != EOF) acceptStatSep();
+ }
+ stats.toList
+ }
+
+ /** TemplateStatSeq ::= TemplateStat {SEP TemplateStat}
+ * TemplateStat ::= Import
+ * | AttributeClauses Modifiers Def
+ * | AttributeClauses Modifiers Dcl
+ * | Expr
+ * |
+ */
+ def templateStatSeq(): List[Tree] = {
+ val stats = new ListBuffer[Tree];
+ while (in.token != RBRACE && in.token != EOF) {
+ if (in.token == IMPORT) {
+ stats ++= importClause()
+ } else if (isExprIntro) {
+ stats += expr()
+ } else if (isDefIntro || isModifier || in.token == LBRACKET) {
+ val attrs = attributeClauses();
+ (stats ++
+ joinAttributes(attrs, joinComment(defOrDcl(modifiers() | traitAttribute(attrs)))))
+ } else if (in.token != SEMI && in.token != NEWLINE) {
+ syntaxError("illegal start of definition", true);
+ }
+ if (in.token != RBRACE) acceptStatSep();
+ }
+ stats.toList
+ }
+
+ /** AttributeClauses ::= {AttributeClause}
+ * AttributeClause ::= `[' Attribute {`,' Attribute} `]' [NL]
+ */
+ def attributeClauses(): List[Tree] = {
+ var attrs = new ListBuffer[Tree];
+ while (in.token == LBRACKET) {
+ in.nextToken();
+ attrs += attribute();
+ while (in.token == COMMA) {
+ in.nextToken();
+ attrs += attribute()
+ }
+ accept(RBRACKET);
+ newLineOpt();
+ }
+ attrs.toList
+ }
+
+ /** Attribute ::= StableId [TypeArgs] [`(' [Exprs] `)']
+ */
+ def attribute(): Tree = {
+ val pos = in.currentPos;
+ var t: Tree = convertToTypeId(stableId());
+ if (in.token == LBRACKET)
+ t = atPos(in.currentPos)(AppliedTypeTree(t, typeArgs()));
+ val args = if (in.token == LPAREN) argumentExprs() else List();
+ atPos(pos) { New(t, List(args)) }
+ }
+
+ def traitAttribute(attrs: List[Tree]) = {
+ def isTraitAttribute(attr: Tree) = attr match {
+ case Apply(Select(New(Ident(name)), constr), List()) if (name.toString() == "_trait_") =>
+ true
+ case _ =>
+ false
+ }
+ if (attrs exists isTraitAttribute) Flags.TRAIT else 0
+ }
+
+ def joinAttributes(attrs: List[Tree], defs: List[Tree]): List[Tree] =
+ defs map (defn =>
+ (attrs :\ defn) ((attr, tree) => Attributed(attr, tree) setPos attr.pos));
+
+ /** RefineStatSeq ::= RefineStat {SEP RefineStat}
+ * RefineStat ::= Dcl
+ * | type TypeDef
+ * |
+ */
+ def refineStatSeq(): List[Tree] = {
+ val stats = new ListBuffer[Tree];
+ while (in.token != RBRACE && in.token != EOF) {
+ if (isDclIntro) {
+ stats ++= joinComment(defOrDcl(NoMods))
+ } else if (in.token != SEMI && in.token != NEWLINE) {
+ syntaxError("illegal start of declaration", true);
+ }
+ if (in.token != RBRACE) acceptStatSep();
+ }
+ stats.toList
+ }
+
+ /** BlockStatSeq ::= { BlockStat SEP } [Expr]
+ * BlockStat ::= Import
+ * | Def
+ * | LocalModifiers TmplDef
+ * | Expr
+ * |
+ */
+ def blockStatSeq(stats: ListBuffer[Tree]): List[Tree] = {
+ while ((in.token != RBRACE) && (in.token != EOF) && (in.token != CASE)) {
+ if (in.token == IMPORT) {
+ stats ++= importClause();
+ acceptStatSep();
+ } else if (isExprIntro) {
+ stats += expr(false, true);
+ if (in.token != RBRACE && in.token != CASE) acceptStatSep();
+ } else if (isDefIntro) {
+ stats ++= defOrDcl(NoMods);
+ acceptStatSep();
+ if (in.token == RBRACE || in.token == CASE) {
+ stats += Literal(()).setPos(in.currentPos)
+ }
+ } else if (isLocalModifier) {
+ stats += tmplDef(localClassModifiers());
+ acceptStatSep();
+ if (in.token == RBRACE || in.token == CASE) {
+ stats += Literal(()).setPos(in.currentPos)
+ }
+ } else if (in.token == SEMI || in.token == NEWLINE) {
+ in.nextToken();
+ } else {
+ syntaxError("illegal start of statement", true);
+ }
+ }
+ stats.toList
+ }
+
+ /** CompilationUnit ::= package QualId SEP TopStatSeq
+ * | package QualId `{' TopStatSeq `}'
+ * | TopStatSeq
+ */
+ def compilationUnit(): Tree =
+ atPos(in.currentPos) {
+ if (in.token == PACKAGE) {
+ in.nextToken();
+ val pkg = qualId();
+ if (in.token == SEMI || in.token == NEWLINE) {
+ in.nextToken();
+ makePackaging(pkg, topStatSeq())
+ } else {
+ accept(LBRACE);
+ val t = makePackaging(pkg, topStatSeq());
+ accept(RBRACE);
+ if (in.token == SEMI || in.token == NEWLINE) in.nextToken();
+ t
+ }
+ } else {
+ makePackaging(Ident(nme.EMPTY_PACKAGE_NAME), topStatSeq())
+ }
+ }
+ }
+}
+
+
+
+// LocalWords: SOcos
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
new file mode 100644
index 0000000000..5fbf54834e
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
@@ -0,0 +1,908 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.ast.parser;
+
+import Tokens._;
+import scala.tools.nsc.util.{Position, SourceFile}
+import SourceFile.{LF, FF, CR, SU}
+import scala.tools.nsc.util.CharArrayReader;
+
+[_trait_] abstract class Scanners: SyntaxAnalyzer {
+
+ import global._;
+
+ /** A class for representing a token's data. */
+ class TokenData {
+
+ /** the next token */
+ var token: int = EMPTY;
+
+ /** the token's position */
+ protected var pos: int = 0;
+
+ /** the first character position after the previous token */
+ var lastPos: int = 0;
+
+ def currentPos = pos - 1;
+
+
+ /** the name of an identifier or token */
+ var name: Name = null;
+
+ /** the base of a number */
+ var base: int = 0;
+
+ def copyFrom(td: TokenData) = {
+ this.token = td.token;
+ this.pos = td.pos;
+ this.lastPos = td.lastPos;
+ this.name = td.name;
+ this.base = td.base;
+ }
+ }
+
+ /** A scanner for the programming language Scala.
+ *
+ * @author Matthias Zenger, Martin Odersky, Burak Emir
+ * @version 1.1
+ */
+ class Scanner(unit: CompilationUnit) extends TokenData {
+
+ import Tokens._;
+ import java.lang.{Integer, Long, Float, Double, Character}
+
+ /** Character input reader
+ */
+ val in = new CharArrayReader(unit.source.getContent(), true, syntaxError);
+
+ /** character buffer for literals
+ */
+ val cbuf = new StringBuffer();
+
+ /** append Unicode character to "lit" buffer
+ */
+ protected def putChar(c: char) = cbuf.append(c);
+
+ /** Clear buffer and set name */
+ private def setName = {
+ name = newTermName(cbuf.toString());
+ cbuf.setLength(0)
+ }
+
+ /** buffer for the documentation comment
+ */
+ var docBuffer: StringBuffer = null;
+
+ /** add the given character to the documentation buffer
+ */
+ protected def putDocChar(c: char): unit =
+ if (docBuffer != null) docBuffer.append(c);
+
+ /** we need one token lookahead
+ */
+ val next = new TokenData();
+ val prev = new TokenData();
+
+ /** the last error position
+ */
+ var errpos = -1;
+
+ /** a stack which indicates whether line-ends can be statement separators
+ */
+ var sepRegions: List[int] = List();
+
+// Get next token ------------------------------------------------------------
+
+ /** read next token and return last position
+ */
+ def skipToken(): int = {
+ val p = pos; nextToken();
+ // XXX: account for off by one error //???
+ p - 1
+ }
+
+ def nextToken(): unit = {
+ if (token == LPAREN) {
+ sepRegions = RPAREN :: sepRegions
+ } else if (token == LBRACKET) {
+ sepRegions = RBRACKET :: sepRegions
+ } else if (token == LBRACE) {
+ sepRegions = RBRACE :: sepRegions
+ } else if (token == CASE) {
+ sepRegions = ARROW :: sepRegions
+ } else if (token == RBRACE) {
+ while (!sepRegions.isEmpty && sepRegions.head != RBRACE)
+ sepRegions = sepRegions.tail;
+ if (!sepRegions.isEmpty)
+ sepRegions = sepRegions.tail
+ } else if (token == RBRACKET || token == RPAREN || token == ARROW) {
+ if (!sepRegions.isEmpty && sepRegions.head == token)
+ sepRegions = sepRegions.tail
+ }
+
+ val lastToken = token;
+ if (next.token == EMPTY) {
+ fetchToken();
+ } else {
+ this.copyFrom(next);
+ next.token = EMPTY
+ }
+
+ if (token == CASE) {
+ prev.copyFrom(this);
+ fetchToken();
+ if (token == CLASS) {
+ token = CASECLASS;
+ lastPos = prev.lastPos;
+ } else if (token == OBJECT) {
+ token = CASEOBJECT;
+ lastPos = prev.lastPos;
+ } else {
+ next.copyFrom(this);
+ this.copyFrom(prev);
+ }
+ } else if (token == SEMI) {
+ prev.copyFrom(this);
+ fetchToken();
+ if (token != ELSE) {
+ next.copyFrom(this);
+ this.copyFrom(prev);
+ }
+ }
+
+ if (afterLineEnd() && inLastOfStat(lastToken) && inFirstOfStat(token) &&
+ (sepRegions.isEmpty || sepRegions.head == RBRACE)) {
+ next.copyFrom(this);
+ pos = in.lineStartPos;
+ token = NEWLINE
+/*
+ } else if (lastToken == RBRACE) {
+ System.out.println("failing to insert NL after RBRACE: " + sepRegions + " " +
+ lastPos + " " + in.lineStartPos + " " + pos);
+*/
+ }
+// System.out.println("token: " + toString());//DEBUG
+ }
+
+ private def afterLineEnd() = (
+ lastPos < in.lineStartPos &&
+ (in.lineStartPos <= pos ||
+ lastPos < in.lastLineStartPos && in.lastLineStartPos <= pos)
+ );
+
+ /** read next token
+ */
+ private def fetchToken(): unit = {
+ if (token == EOF) return;
+ lastPos = in.cpos - 1; // Position.encode(in.cline, in.ccol);
+ //var index = bp;
+ while (true) {
+ in.ch match {
+ case ' ' | '\t' | CR | LF | FF =>
+ in.next;
+ case _ =>
+ pos = in.cpos; // Position.encode(in.cline, in.ccol);
+ in.ch match {
+ case '\u21D2' =>
+ in.next; token = ARROW;
+ return;
+ case 'A' | 'B' | 'C' | 'D' | 'E' |
+ 'F' | 'G' | 'H' | 'I' | 'J' |
+ 'K' | 'L' | 'M' | 'N' | 'O' |
+ 'P' | 'Q' | 'R' | 'S' | 'T' |
+ 'U' | 'V' | 'W' | 'X' | 'Y' |
+ 'Z' | '$' | '_' |
+ 'a' | 'b' | 'c' | 'd' | 'e' |
+ 'f' | 'g' | 'h' | 'i' | 'j' |
+ 'k' | 'l' | 'm' | 'n' | 'o' |
+ 'p' | 'q' | 'r' | 's' | 't' |
+ 'u' | 'v' | 'w' | 'x' | 'y' | // scala-mode: need to understand multi-line case patterns
+ 'z' =>
+ putChar(in.ch);
+ in.next;
+ getIdentRest; // scala-mode: wrong indent for multi-line case blocks
+ return;
+
+ case '<' => // is XMLSTART?
+ val last = in.last;
+ in.next;
+ last match {
+ case ' '|'\t'|'\n'|'{'|'('|'>' if xml.Parsing.isNameStart(in.ch) =>
+ token = XMLSTART;
+ case _ =>
+ // Console.println("found '<', but last is '"+in.last+"'"); // DEBUG
+ putChar('<');
+ getOperatorRest;
+ }
+ return;
+
+ case '~' | '!' | '@' | '#' | '%' |
+ '^' | '*' | '+' | '-' | /*'<' | */
+ '>' | '?' | ':' | '=' | '&' |
+ '|' | '\\' =>
+ putChar(in.ch);
+ in.next;
+ getOperatorRest; // XXX
+ return;
+ case '/' =>
+ in.next;
+ if (!skipComment()) {
+ putChar('/');
+ getOperatorRest;
+ return;
+ }
+
+ case '0' =>
+ putChar(in.ch);
+ in.next;
+ if (in.ch == 'x' || in.ch == 'X') {
+ in.next;
+ base = 16
+ } else {
+ base = 8;
+ }
+ getNumber;
+ return; // scala-mode: return is a keyword
+ case '1' | '2' | '3' | '4' |
+ '5' | '6' | '7' | '8' | '9' =>
+ base = 10;
+ getNumber;
+ return;
+ case '`' => //" scala-mode: need to understand literals
+ getStringLit('`');
+ token = IDENTIFIER;
+ return;
+ case '\"' => //" scala-mode: need to understand literals
+ getStringLit('\"');
+ return;
+ case '\'' =>
+ in.next;
+ in.ch match {
+ case 'A' | 'B' | 'C' | 'D' | 'E' |
+ 'F' | 'G' | 'H' | 'I' | 'J' |
+ 'K' | 'L' | 'M' | 'N' | 'O' |
+ 'P' | 'Q' | 'R' | 'S' | 'T' |
+ 'U' | 'V' | 'W' | 'X' | 'Y' |
+ 'Z' | '$' | '_' |
+ 'a' | 'b' | 'c' | 'd' | 'e' |
+ 'f' | 'g' | 'h' | 'i' | 'j' |
+ 'k' | 'l' | 'm' | 'n' | 'o' |
+ 'p' | 'q' | 'r' | 's' | 't' |
+ 'u' | 'v' | 'w' | 'x' | 'y' |
+ 'z' =>
+ putChar(in.ch);
+ in.next;
+ if (in.ch != '\'') {
+ getIdentRest;
+ token = SYMBOLLIT;
+ return;
+ }
+ case _ =>
+ if (Character.isUnicodeIdentifierStart(in.ch)) {
+ putChar(in.ch);
+ in.next;
+ if (in.ch != '\'') {
+ getIdentRest;
+ token = SYMBOLLIT;
+ return;
+ }
+ } else {
+ getlitch()
+ }
+ }
+ if (in.ch == '\'') {
+ in.next;
+ token = CHARLIT;
+ setName
+ } else {
+ syntaxError("unclosed character literal");
+ }
+ return;
+ case '.' =>
+ in.next;
+ if ('0' <= in.ch && in.ch <= '9') {
+ putChar('.'); getFraction;
+ } else {
+ token = DOT
+ }
+ return;
+ case ';' =>
+ in.next; token = SEMI;
+ return;
+ case ',' =>
+ in.next; token = COMMA;
+ return;
+ case '(' => //scala-mode: need to understand character quotes
+ in.next; token = LPAREN;
+ return;
+ case '{' =>
+ in.next; token = LBRACE;
+ return;
+ case ')' =>
+ in.next; token = RPAREN;
+ return;
+ case '}' =>
+ in.next; token = RBRACE;
+ return;
+ case '[' =>
+ in.next; token = LBRACKET;
+ return;
+ case ']' =>
+ in.next; token = RBRACKET;
+ return;
+ case SU =>
+ if (!in.hasNext) token = EOF;
+ else {
+ syntaxError("illegal character");
+ in.next
+ }
+ return;
+ case _ =>
+ if (Character.isUnicodeIdentifierStart(in.ch)) {
+ putChar(in.ch);
+ in.next;
+ getIdentRest;
+ } else if (isSpecial(in.ch)) {
+ putChar(in.ch);
+ getOperatorRest;
+ } else {
+ syntaxError("illegal character");
+ in.next;
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ private def skipComment(): boolean =
+ if (in.ch == '/') {
+ do {
+ in.next;
+ } while ((in.ch != CR) && (in.ch != LF) && (in.ch != SU));
+ true
+ } else if (in.ch == '*') {
+ docBuffer = null;
+ var openComments = 1;
+ in.next;
+ if (in.ch == '*') docBuffer = new StringBuffer("/**");
+ while (openComments > 0) {
+ do {
+ do {
+ if (in.ch == '/') {
+ in.next; putDocChar(in.ch);
+ if (in.ch == '*') {
+ in.next; putDocChar(in.ch);
+ openComments = openComments + 1;
+ }
+ }
+ in.next; putDocChar(in.ch);
+ } while (in.ch != '*' && in.ch != SU);
+ while (in.ch == '*') {
+ in.next; putDocChar(in.ch);
+ }
+ } while (in.ch != '/' && in.ch != SU);
+ if (in.ch == '/') in.next;
+ else syntaxError("unclosed comment");
+ openComments = openComments - 1;
+ }
+ true
+ } else {
+ false
+ }
+
+ def inFirstOfStat(token: int) = token match {
+ case EOF | ELSE | CASE | EXTENDS | WITH | YIELD | CATCH | FINALLY | MATCH |
+ REQUIRES | COMMA | SEMI | NEWLINE | DOT | USCORE | COLON | EQUALS | ARROW |
+ LARROW | SUBTYPE | VIEWBOUND | SUPERTYPE | HASH | AT |
+ RPAREN | RBRACKET | RBRACE =>
+ false
+ case _ =>
+ true
+ }
+
+ def inLastOfStat(token: int) = token match {
+ case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT |
+ IDENTIFIER | THIS | NULL | TRUE | FALSE | RETURN | USCORE |
+ RPAREN | RBRACKET | RBRACE =>
+ true
+ case _ =>
+ false
+ }
+
+// Identifiers ---------------------------------------------------------------
+
+ def isIdentStart(c: char): boolean = (
+ ('A' <= c && c <= 'Z') ||
+ ('a' <= c && c <= 'a') ||
+ (c == '_') || (c == '$') ||
+ Character.isUnicodeIdentifierStart(c)
+ );
+
+ def isIdentPart(c: char) = (
+ isIdentStart(c) ||
+ ('0' <= c && c <= '9') ||
+ Character.isUnicodeIdentifierPart(c)
+ );
+
+ def isSpecial(c: char) = {
+ val chtp = Character.getType(c);
+ chtp == Character.MATH_SYMBOL || chtp == Character.OTHER_SYMBOL;
+ }
+
+ private def getIdentRest: unit =
+ while (true) {
+ in.ch match {
+ case 'A' | 'B' | 'C' | 'D' | 'E' |
+ 'F' | 'G' | 'H' | 'I' | 'J' |
+ 'K' | 'L' | 'M' | 'N' | 'O' |
+ 'P' | 'Q' | 'R' | 'S' | 'T' |
+ 'U' | 'V' | 'W' | 'X' | 'Y' |
+ 'Z' | '$' |
+ 'a' | 'b' | 'c' | 'd' | 'e' |
+ 'f' | 'g' | 'h' | 'i' | 'j' |
+ 'k' | 'l' | 'm' | 'n' | 'o' |
+ 'p' | 'q' | 'r' | 's' | 't' |
+ 'u' | 'v' | 'w' | 'x' | 'y' |
+ 'z' |
+ '0' | '1' | '2' | '3' | '4' |
+ '5' | '6' | '7' | '8' | '9' =>
+ putChar(in.ch);
+ in.next;
+ case '_' =>
+ putChar(in.ch);
+ in.next;
+ getIdentOrOperatorRest;
+ return;
+ case SU =>
+ setName;
+ token = name2token(name);
+ return;
+ case _ =>
+ if(java.lang.Character.isUnicodeIdentifierPart(in.ch)) {
+ putChar(in.ch);
+ in.next
+ } else {
+ setName;
+ token = name2token(name);
+ return
+ }
+ }
+ }
+
+ private def getOperatorRest: unit =
+ while (true) {
+ in.ch match {
+ case '~' | '!' | '@' | '#' | '%' |
+ '^' | '*' | '+' | '-' | '<' |
+ '>' | '?' | ':' | '=' | '&' |
+ '|' | '\\' =>
+ putChar(in.ch);
+ in.next
+ case '/' =>
+ in.next;
+ if (skipComment()) {
+ setName;
+ token = name2token(name);
+ return;
+ } else {
+ putChar('/');
+ }
+ case _ =>
+ if (isSpecial(in.ch)) {
+ putChar(in.ch);
+ in.next;
+ } else {
+ setName;
+ token = name2token(name);
+ return;
+ }
+ }
+ }
+
+ private def getIdentOrOperatorRest: unit =
+ if (isIdentPart(in.ch))
+ getIdentRest
+ else in.ch match {
+ case '~' | '!' | '@' | '#' | '%' |
+ '^' | '*' | '+' | '-' | '<' |
+ '>' | '?' | ':' | '=' | '&' |
+ '|' | '\\' | '/' =>
+ getOperatorRest;
+ case _ =>
+ if (isSpecial(in.ch)) getOperatorRest
+ else {
+ setName;
+ token = name2token(name)
+ }
+ }
+
+ private def getStringLit(delimiter: char): unit = {
+ in.next;
+ while (in.ch != delimiter && (in.isUnicode || in.ch != CR && in.ch != LF && in.ch != SU)) {
+ getlitch();
+ }
+ if (in.ch == delimiter) {
+ token = STRINGLIT;
+ setName;
+ in.next
+ } else {
+ syntaxError("unclosed string literal");
+ }
+ }
+
+// Literals -----------------------------------------------------------------
+
+ /** read next character in character or string literal:
+ */
+ protected def getlitch() =
+ if (in.ch == '\\') {
+ in.next;
+ if ('0' <= in.ch && in.ch <= '7') {
+ val leadch: char = in.ch;
+ var oct: int = in.digit2int(in.ch, 8);
+ in.next;
+ if ('0' <= in.ch && in.ch <= '7') {
+ oct = oct * 8 + in.digit2int(in.ch, 8);
+ in.next;
+ if (leadch <= '3' && '0' <= in.ch && in.ch <= '7') {
+ oct = oct * 8 + in.digit2int(in.ch, 8);
+ in.next;
+ }
+ }
+ putChar(oct.asInstanceOf[char]);
+ } else {
+ in.ch match {
+ case 'b' => putChar('\b')
+ case 't' => putChar('\t')
+ case 'n' => putChar('\n')
+ case 'f' => putChar('\f')
+ case 'r' => putChar('\r')
+ case '\"' => putChar('\"')
+ case '\'' => putChar('\'')
+ case '\\' => putChar('\\')
+ case _ =>
+ syntaxError(in.cpos - 1, // Position.encode(in.cline, in.ccol - 1),
+ "invalid escape character");
+ putChar(in.ch);
+ }
+ in.next
+ }
+ } else {
+ putChar(in.ch);
+ in.next;
+ }
+
+ /** read fractional part and exponent of floating point number
+ * if one is present.
+ */
+ protected def getFraction = {
+ token = DOUBLELIT;
+ while ('0' <= in.ch && in.ch <= '9') {
+ putChar(in.ch);
+ in.next;
+ }
+ if (in.ch == 'e' || in.ch == 'E') {
+ val lookahead = in.copy;
+ lookahead.next;
+ if (lookahead.ch == '+' || lookahead.ch == '-') {
+ lookahead.next;
+ }
+ if ('0' <= lookahead.ch && lookahead.ch <= '9') {
+ putChar(in.ch);
+ in.next;
+ if (in.ch == '+' || in.ch == '-') {
+ putChar(in.ch);
+ in.next;
+ }
+ while ('0' <= in.ch && in.ch <= '9') {
+ putChar(in.ch);
+ in.next;
+ }
+ }
+ token = DOUBLELIT;
+ }
+ if ((in.ch == 'd') || (in.ch == 'D')) {
+ putChar(in.ch);
+ in.next;
+ token = DOUBLELIT;
+ } else if ((in.ch == 'f') || (in.ch == 'F')) {
+ putChar(in.ch);
+ in.next;
+ token = FLOATLIT;
+ }
+ setName
+ }
+
+ /** convert name to long value
+ */
+ def intVal(negated: boolean): long = {
+ if (token == CHARLIT && !negated) {
+ if (name.length > 0) name(0) else 0
+ } else {
+ var value: long = 0;
+ val divider = if (base == 10) 1 else 2;
+ val limit: long =
+ if (token == LONGLIT) Long.MAX_VALUE else Integer.MAX_VALUE;
+ var i = 0;
+ val len = name.length;
+ while (i < len) {
+ val d = in.digit2int(name(i), base);
+ if (d < 0) {
+ syntaxError("malformed integer number");
+ return 0;
+ }
+ if (value < 0 ||
+ limit / (base / divider) < value ||
+ limit - (d / divider) < value * (base / divider) &&
+ !(negated && limit == value * base - 1 + d)) {
+ syntaxError("integer number too large");
+ return 0;
+ }
+ value = value * base + d;
+ i = i + 1;
+ }
+ if (negated) -value else value
+ }
+ }
+
+ def intVal: long = intVal(false);
+
+ /** convert name, base to double value
+ */
+ def floatVal(negated: boolean): double = {
+ val limit: double =
+ if (token == DOUBLELIT) Double.MAX_VALUE else Float.MAX_VALUE;
+ try {
+ val value = Double.valueOf(name.toString()).doubleValue();
+ if (value > limit)
+ syntaxError("floating point number too large");
+ if (negated) -value else value
+ } catch {
+ case _: NumberFormatException =>
+ syntaxError("malformed floating point number");
+ 0.0
+ }
+ }
+
+ def floatVal: double = floatVal(false);
+
+ /** read a number into name and set base
+ */
+ protected def getNumber:unit = {
+ while (in.digit2int(in.ch, if (base < 10) 10 else base) >= 0) {
+ putChar(in.ch);
+ in.next;
+ }
+ token = INTLIT;
+ if (base <= 10 && in.ch == '.') {
+ val lookahead = in.copy;
+ lookahead.next;
+ lookahead.ch match {
+ case '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
+ '8' | '9' | 'd' | 'D' | 'e' | 'E' | 'f' | 'F' =>
+ putChar(in.ch);
+ in.next;
+ return getFraction
+ case _ =>
+ if (!isIdentStart(lookahead.ch)) {
+ putChar(in.ch);
+ in.next;
+ return getFraction
+ }
+ }
+ }
+ if (base <= 10 &&
+ (in.ch == 'e' || in.ch == 'E' ||
+ in.ch == 'f' || in.ch == 'F' ||
+ in.ch == 'd' || in.ch == 'D')) {
+ return getFraction
+ }
+ setName;
+ if (in.ch == 'l' || in.ch == 'L') {
+ in.next;
+ token = LONGLIT;
+ }
+ }
+
+// XML lexing----------------------------------------------------------------
+ def xSync = {
+ token = NEWLINE; // avoid getting NEWLINE from nextToken if last was RBRACE
+ //in.next;
+ nextToken();
+ }
+
+// Errors -----------------------------------------------------------------
+
+ /** generate an error at the given position
+ */
+ def syntaxError(pos: int, msg: String): unit = {
+ unit.error(pos, msg);
+ token = ERROR;
+ errpos = pos;
+ }
+
+ /** generate an error at the current token position
+ */
+ def syntaxError(msg: String): unit = syntaxError(pos, msg);
+
+// Keywords -----------------------------------------------------------------
+
+ /** Keyword array; maps from name indices to tokens */
+ private var key: Array[byte] = _;
+ private var maxKey = 0;
+ private var tokenName = new Array[Name](128);
+
+ {
+ var tokenCount = 0;
+
+ // Enter keywords
+
+ def enterKeyword(n: Name, tokenId: int): unit = {
+ while (tokenId >= tokenName.length) {
+ val newTokName = new Array[Name](tokenName.length * 2);
+ System.arraycopy(tokenName, 0, newTokName, 0, newTokName.length);
+ tokenName = newTokName;
+ }
+ tokenName(tokenId) = n;
+ if (n.start > maxKey) maxKey = n.start;
+ if (tokenId >= tokenCount) tokenCount = tokenId + 1;
+ }
+
+ enterKeyword(nme.ABSTRACTkw, ABSTRACT);
+ enterKeyword(nme.CASEkw, CASE);
+ enterKeyword(nme.CATCHkw, CATCH);
+ enterKeyword(nme.CLASSkw, CLASS);
+ enterKeyword(nme.DEFkw, DEF);
+ enterKeyword(nme.DOkw, DO);
+ enterKeyword(nme.ELSEkw, ELSE);
+ enterKeyword(nme.EXTENDSkw, EXTENDS);
+ enterKeyword(nme.FALSEkw, FALSE);
+ enterKeyword(nme.FINALkw, FINAL);
+ enterKeyword(nme.FINALLYkw, FINALLY);
+ enterKeyword(nme.FORkw, FOR);
+ enterKeyword(nme.IFkw, IF);
+ enterKeyword(nme.IMPLICITkw, IMPLICIT);
+ enterKeyword(nme.IMPORTkw, IMPORT);
+ enterKeyword(nme.MATCHkw, MATCH);
+ enterKeyword(nme.REQUIRESkw, REQUIRES);
+ enterKeyword(nme.NEWkw, NEW);
+ enterKeyword(nme.NULLkw, NULL);
+ enterKeyword(nme.OBJECTkw, OBJECT);
+ enterKeyword(nme.OVERRIDEkw, OVERRIDE);
+ enterKeyword(nme.PACKAGEkw, PACKAGE);
+ enterKeyword(nme.PRIVATEkw, PRIVATE);
+ enterKeyword(nme.PROTECTEDkw, PROTECTED);
+ enterKeyword(nme.RETURNkw, RETURN);
+ enterKeyword(nme.SEALEDkw, SEALED);
+ enterKeyword(nme.SUPERkw, SUPER);
+ enterKeyword(nme.THISkw, THIS);
+ enterKeyword(nme.THROWkw, THROW);
+ enterKeyword(nme.TRAITkw, TRAIT);
+ enterKeyword(nme.TRUEkw, TRUE);
+ enterKeyword(nme.TRYkw, TRY);
+ enterKeyword(nme.TYPEkw, TYPE);
+ enterKeyword(nme.VALkw, VAL);
+ enterKeyword(nme.VARkw, VAR);
+ enterKeyword(nme.WHILEkw, WHILE);
+ enterKeyword(nme.WITHkw, WITH);
+ enterKeyword(nme.YIELDkw, YIELD);
+ enterKeyword(nme.DOTkw, DOT);
+ enterKeyword(nme.USCOREkw, USCORE);
+ enterKeyword(nme.COLONkw, COLON);
+ enterKeyword(nme.EQUALSkw, EQUALS);
+ enterKeyword(nme.ARROWkw, ARROW);
+ enterKeyword(nme.LARROWkw, LARROW);
+ enterKeyword(nme.SUBTYPEkw, SUBTYPE);
+ enterKeyword(nme.VIEWBOUNDkw, VIEWBOUND);
+ enterKeyword(nme.SUPERTYPEkw, SUPERTYPE);
+ enterKeyword(nme.HASHkw, HASH);
+ enterKeyword(nme.ATkw, AT);
+
+ // Build keyword array
+ key = new Array[byte](maxKey+1);
+ for (val i <- Iterator.range(0, maxKey + 1))
+ key(i) = IDENTIFIER;
+ for (val j <- Iterator.range(0, tokenCount))
+ if (tokenName(j) != null)
+ key(tokenName(j).start) = j.asInstanceOf[byte];
+
+ }
+
+// Token representation -----------------------------------------------------
+
+ /** Convert name to token */
+ def name2token(name: Name): int =
+ if (name.start <= maxKey) key(name.start) else IDENTIFIER;
+
+ /** Returns the string representation of given token. */
+ def token2string(token: int): String = token match {
+ case IDENTIFIER =>
+ "identifier"/* + \""+name+"\""*/
+ case CHARLIT =>
+ "character literal"
+ case INTLIT =>
+ "integer literal"
+ case LONGLIT =>
+ "long literal"
+ case FLOATLIT =>
+ "float literal"
+ case DOUBLELIT =>
+ "double literal"
+ case STRINGLIT =>
+ "string literal"
+ case SYMBOLLIT =>
+ "symbol literal"
+ case LPAREN =>
+ "'('"
+ case RPAREN =>
+ "')'"
+ case LBRACE =>
+ "'{'"
+ case RBRACE =>
+ "'}'"
+ case LBRACKET =>
+ "'['"
+ case RBRACKET =>
+ "']'"
+ case EOF =>
+ "eof"
+ case ERROR =>
+ "something"
+ case SEMI =>
+ "';'"
+ case NEWLINE =>
+ "';'"
+ case COMMA =>
+ "','"
+ case CASECLASS =>
+ "case class"
+ case CASEOBJECT =>
+ "case object"
+ case XMLSTART =>
+ "$XMLSTART$<"
+ case _ =>
+ try {
+ "'" + tokenName(token) + "'"
+ } catch {
+ case _: ArrayIndexOutOfBoundsException =>
+ "'<" + token + ">'"
+ case _: NullPointerException =>
+ "'<(" + token + ")>'"
+ }
+ }
+
+ override def toString() = token match {
+ case IDENTIFIER =>
+ "id(" + name + ")"
+ case CHARLIT =>
+ "char(" + intVal + ")"
+ case INTLIT =>
+ "int(" + intVal + ")"
+ case LONGLIT =>
+ "long(" + intVal + ")"
+ case FLOATLIT =>
+ "float(" + floatVal + ")"
+ case DOUBLELIT =>
+ "double(" + floatVal + ")"
+ case STRINGLIT =>
+ "string(" + name + ")"
+ case SEMI =>
+ ";"
+ case NEWLINE =>
+ ";"
+ case COMMA =>
+ ","
+ case _ =>
+ token2string(token)
+ }
+
+ /** INIT: read lookahead character and token.
+ */
+ in.next;
+ nextToken();
+ }
+}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
new file mode 100644
index 0000000000..4fc234bead
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/parser/SymbolicXMLBuilder.scala
@@ -0,0 +1,349 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author buraq
+ */
+// $Id$
+package scala.tools.nsc.ast.parser;
+
+import scala.tools.nsc.util.Position;
+import scala.Iterator;
+import scala.collection.immutable.{ Map, ListMap };
+import scala.collection.mutable;
+import scala.xml.{Text,TextBuffer};
+
+import symtab.Flags.MUTABLE;
+
+/** this class builds instance of Tree that represent XML */
+abstract class SymbolicXMLBuilder(make: TreeBuilder, p: Parsers # Parser, preserveWS: Boolean ) {
+
+ val global: Global;
+ import global._;
+ import posAssigner.atPos;
+
+ //import scala.tools.scalac.ast.{TreeList => myTreeList}
+
+ var isPattern:Boolean = _;
+
+ import nme.{
+ _Attribute ,
+ _MetaData ,
+ _NamespaceBinding ,
+ _NodeBuffer ,
+
+ _Null ,
+
+ _PrefixedAttribute ,
+ _UnprefixedAttribute ,
+ _Elem ,
+ _Seq ,
+ _immutable ,
+ _mutable ,
+ _append ,
+ _plus ,
+ _collection ,
+ _toList ,
+ _xml ,
+ _Comment ,
+ _CharData ,
+ _Node ,
+ _ProcInstr ,
+ _Text ,
+ _EntityRef ,
+ _md,
+ _scope,
+ _tmpscope};
+
+
+ // convenience methods
+ private def LL[A](x:A*):List[List[A]] = List(List(x:_*));
+
+ private def _scala(name: Name) = Select(Ident(nme.scala_), name);
+
+ private def _scala_Seq = _scala( _Seq );
+ private def _scala_xml(name: Name) = Select( _scala(_xml), name );
+
+ private def _scala_xml_MetaData = _scala_xml( _MetaData );
+ private def _scala_xml_NamespaceBinding = _scala_xml( _NamespaceBinding );
+ private def _scala_xml_Null = _scala_xml( _Null );
+ private def _scala_xml_PrefixedAttribute = _scala_xml(_PrefixedAttribute);
+ private def _scala_xml_UnprefixedAttribute= _scala_xml(_UnprefixedAttribute);
+ private def _scala_xml_Node = _scala_xml( _Node );
+ private def _scala_xml_NodeBuffer = _scala_xml( _NodeBuffer );
+ private def _scala_xml_EntityRef = _scala_xml( _EntityRef );
+ private def _scala_xml_Comment = _scala_xml( _Comment );
+ private def _scala_xml_CharData = _scala_xml( _CharData );
+ private def _scala_xml_ProcInstr = _scala_xml( _ProcInstr );
+ private def _scala_xml_Text = _scala_xml( _Text );
+ private def _scala_xml_Elem = _scala_xml( _Elem );
+ private def _scala_xml_Attribute = _scala_xml( _Attribute );
+
+
+ private def bufferToArray(buf: mutable.Buffer[Tree]): Array[Tree] = {
+ val arr = new Array[Tree]( buf.length );
+ var i = 0;
+ for (val x <- buf.elements) { arr(i) = x; i = i + 1; }
+ arr;
+ }
+
+ // create scala xml tree
+
+ /**
+ * @arg namespace: a Tree of type defs.STRING_TYPE
+ * @arg label: a Tree of type defs.STRING_TYPE
+ * @todo map: a map of attributes !!!
+ */
+
+ protected def mkXML(pos: int, isPattern: boolean, pre: Tree, label: Tree, attrs: /*Array[*/Tree/*]*/ , scope:Tree, children: mutable.Buffer[Tree]): Tree = {
+ if( isPattern ) {
+ //val ts = new mutable.ArrayBuffer[Tree]();
+ convertToTextPat( children );
+ atPos (pos) {
+ Apply( _scala_xml_Elem, List(
+ pre, label, Ident( nme.WILDCARD ) /* attributes? */ , Ident( nme.WILDCARD )) /* scope? */ ::: children.toList )
+ }
+ } else {
+ var ab = List(pre, label, attrs, scope);
+ if(( children.length ) > 0 )
+ ab = ab ::: List(Typed(makeXMLseq(pos, children), Ident(nme.WILDCARD_STAR.toTypeName)));
+ atPos(pos) { New( _scala_xml_Elem, List(ab) )}
+ }
+ }
+
+ final def entityRef( pos:int, n: String ) = {
+ atPos(pos) { New( _scala_xml_EntityRef, LL(Literal(Constant( n )))) };
+
+ };
+ // create scala.xml.Text here <: scala.xml.Node
+ final def text( pos: Int, txt:String ):Tree = {
+ //makeText( isPattern, gen.mkStringLit( txt ));
+ val txt1 = Literal(Constant(txt));
+ atPos(pos) {
+ if( isPattern )
+ makeTextPat( txt1 );
+ else
+ makeText1( txt1 );
+ }
+ }
+
+ // create scala.xml.Text here <: scala.xml.Node
+ def makeTextPat(txt:Tree ) = Apply(_scala_xml_Text, List(txt));
+ def makeText1(txt:Tree ) = New( _scala_xml_Text, LL( txt ));
+
+ // create
+ def comment( pos: int, text: String ):Tree =
+ atPos(pos) { Comment( Literal(Constant(text))) };
+
+ // create
+ def charData( pos: int, txt: String ):Tree =
+ atPos(pos) { CharData( Literal(Constant(txt))) };
+
+ // create scala.xml.Text here <: scala.xml.Node
+ def procInstr( pos: int, target: String, txt: String ) =
+ atPos(pos) { ProcInstr(Literal(Constant(target)), Literal(Constant(txt))) };
+
+ protected def CharData(txt: Tree) = New( _scala_xml_CharData, LL(txt));
+ protected def Comment(txt: Tree) = New( _scala_xml_Comment, LL(txt));
+ protected def ProcInstr(target: Tree, txt: Tree) =
+ New(_scala_xml_ProcInstr, LL( target, txt ));
+
+
+ /** @todo: attributes */
+ def makeXMLpat(pos: int, n: String, args: mutable.Buffer[Tree]): Tree =
+ mkXML(pos,
+ true,
+ Ident( nme.WILDCARD ),
+ Literal(Constant(n)),
+ null, //Predef.Array[Tree](),
+ null,
+ args);
+
+ protected def convertToTextPat(t: Tree): Tree = t match {
+ case _:Literal => makeTextPat(t);
+ case _ => t
+ }
+
+ protected def convertToTextPat(buf: mutable.Buffer[Tree]): Unit = {
+ var i = 0; while( i < buf.length ) {
+ val t1 = buf( i );
+ val t2 = convertToTextPat( t1 );
+ if (!t1.eq(t2)) {
+ buf.remove(i);
+ buf.insert(i,t2);
+ }
+ i = i + 1;
+ }
+ }
+
+ def freshName(prefix:String): Name;
+
+ def isEmptyText(t:Tree) = t match {
+ case Literal(Constant("")) => true;
+ case _ => false;
+ }
+ def makeXMLseq( pos:int, args:mutable.Buffer[Tree] ) = {
+ var _buffer = New( _scala_xml_NodeBuffer, List(Nil));
+ val it = args.elements;
+ while( it.hasNext ) {
+ val t = it.next;
+ if( !isEmptyText( t )) {
+ _buffer = Apply(Select(_buffer, _plus), List( t ));
+ }
+ }
+ atPos(pos) { Select(_buffer, _toList) };
+ }
+
+ def makeXMLseqPat( pos:int, args:List[Tree] ) = atPos(pos) {Apply( _scala_Seq, args )};
+
+
+ /** returns Some(prefix) if pre:name, None otherwise */
+ def getPrefix( name:String ):Option[String] = {
+ val i = name.indexOf(':');
+ if( i != -1 ) Some( name.substring(0, i) ) else None
+ }
+
+ /** splits */
+ protected def qualifiedAttr( pos:Int, namespace:String, name:String ):Pair[String,String] = {
+ getPrefix( name ) match {
+ case Some( pref ) =>
+ val newLabel = name.substring( pref.length()+1, name.length() );
+ // if( newLabel.indexOf(':') != -1 ) syntaxError
+ Pair( "namespace$"+pref, newLabel );
+ case None =>
+ Pair( namespace, name );
+ }
+ }
+ protected def qualified( pos:Int, name:String ):Pair[String,String] =
+ getPrefix( name ) match {
+ case Some( pref ) =>
+ val newLabel = name.substring( pref.length()+1, name.length() );
+ // if( newLabel.indexOf(':') != -1 ) syntaxError
+ Pair( "namespace$"+pref, newLabel );
+ case None =>
+ Pair( "namespace$default", name );
+ }
+
+
+ /** makes an element */
+ def element(pos: int, qname: String, attrMap: mutable.Map[String,Tree], args: mutable.Buffer[Tree]): Tree = {
+ //Console.println("SymbolicXMLBuilder::element("+pos+","+qname+","+attrMap+","+args+")");
+ var setNS = new mutable.HashMap[String, Tree];
+
+ var tlist: List[Tree] = List();
+
+ /* pre can be null */
+ def handleNamespaceBinding(pre:String , uri:Tree): Unit = {
+ val t = Assign(Ident(_tmpscope), New( _scala_xml_NamespaceBinding,
+ LL(Literal(Constant(pre)), uri, Ident( _tmpscope))));
+ tlist = t :: tlist;
+ //Console.println("SymbolicXMLBuilder::handleNamespaceBinding:");
+ //Console.println(t.toString());
+ }
+
+ /* DEBUG */
+ val attrIt = attrMap.keys;
+ while( attrIt.hasNext ) {
+ val z = attrIt.next;
+ if( z.startsWith("xmlns") ) { // handle namespace
+ val i = z.indexOf(':');
+ if( i == -1 )
+ handleNamespaceBinding(null, attrMap( z ));
+ //setNS.update("default", attrMap( z ) );
+ else {
+ val zz = z.substring( i+1, z.length() );
+ //setNS.update( zz, attrMap( z ) );
+ handleNamespaceBinding(zz, attrMap( z ));
+ }
+ attrMap -= z;
+ }
+ }
+
+ val moreNamespaces = (0 < tlist.length);
+
+ /* */
+ val i = qname.indexOf(':');
+
+ var newlabel = qname;
+ val pre = getPrefix(qname) match {
+ case Some(p) =>
+ newlabel = qname.substring(p.length()+1, qname.length());
+ p;
+ case None =>
+ null
+ }
+ var tlist2: List[Tree] = List();
+
+ // make attributes
+
+ def handlePrefixedAttribute(pre:String, key:String, value:Tree): Unit = {
+ val t = atPos(pos) {
+ Assign(Ident(_md), New( _scala_xml_PrefixedAttribute,
+ LL(
+ Literal(Constant(pre)),
+ Literal(Constant(key)),
+ value,
+ Ident(_md)
+ )))};
+ tlist2 = t :: tlist2;
+ // Console.println("SymbolicXMLBuilder::handlePrefixed :");
+ // Console.println(t.toString());
+ }
+
+ def handleUnprefixedAttribute(key:String, value:Tree): Unit = {
+ val t = atPos(pos) {
+ Assign(Ident(_md), New(_scala_xml_UnprefixedAttribute,
+ LL(Literal(Constant(key)),value,Ident(_md))
+ ))};
+ tlist2 = t :: tlist2;
+ }
+
+ var it = attrMap.elements;
+ while (it.hasNext) {
+ val ansk = it.next;
+ getPrefix(ansk._1) match {
+ case Some(pre) =>
+ val key = ansk._1.substring(pre.length()+1, ansk._1.length());
+ handlePrefixedAttribute(pre, key, ansk._2);
+ case None =>
+ handleUnprefixedAttribute(ansk._1, ansk._2);
+ }
+ }
+ // attrs
+
+
+ val moreAttributes = (0 < tlist2.length);
+
+ var ts: List[Tree] = tlist;
+ var ts2: List[Tree] = List();
+
+ if(moreAttributes) {
+ ts2 = atPos(pos) {ValDef(Modifiers(MUTABLE),
+ _md,
+ _scala_xml_MetaData,
+ _scala_xml_Null)} :: tlist2;
+ }
+ if(moreNamespaces) {
+ ts = atPos(pos) {
+ ValDef(Modifiers(MUTABLE),
+ _tmpscope,
+ _scala_xml_NamespaceBinding,
+ Ident(_scope))} :: ts;
+
+ ts2 = ValDef(NoMods, _scope, _scala_xml_NamespaceBinding, Ident(_tmpscope)) :: ts2;
+ }
+
+ val makeSymbolicAttrs = {
+ if (moreAttributes) Ident(_md) else _scala_xml_Null;
+ }
+
+ var t = mkXML(pos,
+ false,
+ Literal(Constant(pre)) /* can be null */ ,
+ Literal(Constant(newlabel)):Tree,
+ makeSymbolicAttrs,
+ Ident(_scope),
+ args);
+
+ atPos(pos) { Block(ts, Block( ts2, t)) }
+ }
+}
+
diff --git a/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
new file mode 100644
index 0000000000..b4a3b507b3
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/parser/SyntaxAnalyzer.scala
@@ -0,0 +1,25 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.ast.parser;
+
+/** An nsc sub-component.
+ */
+abstract class SyntaxAnalyzer extends SubComponent with Parsers with MarkupParsers with Scanners {
+ val phaseName = "parser";
+ def newPhase(prev: Phase): StdPhase = new ParserPhase(prev);
+ class ParserPhase(prev: scala.tools.nsc.Phase) extends StdPhase(prev) {
+ def apply(unit: global.CompilationUnit): unit = {
+ global.informProgress("parsing " + unit);
+ unit.body = new Parser(unit).parse();
+ }
+ }
+ //Moez addition. I wished not to add/modify here, but the fact that Parsers
+ // are NOT accessible (because of Parsers' self type) except in SyntaxAnalyzer
+ // had bitten me, and thus I had to add the following code here.
+ def interpreterParse(unit: global.CompilationUnit): List[global.Tree] =
+ new Parser(unit).templateStatSeq()
+}
+
diff --git a/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala
new file mode 100644
index 0000000000..b99ee08811
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/parser/Tokens.scala
@@ -0,0 +1,97 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.ast.parser;
+
+object Tokens {
+
+ /** special tokens */
+ final val EMPTY = -3;
+ final val UNDEF = -2;
+ final val ERROR = -1;
+ final val EOF = 0;
+
+ /** literals */
+ final val CHARLIT = 1;
+ final val INTLIT = 2;
+ final val LONGLIT = 3;
+ final val FLOATLIT = 4;
+ final val DOUBLELIT = 5;
+ final val STRINGLIT = 6;
+ final val SYMBOLLIT = 7;
+
+ /** identifier */
+ final val IDENTIFIER = 10;
+
+ /** keywords */
+ final val IF = 20;
+ final val FOR = 21;
+ final val ELSE = 22;
+ final val THIS = 23;
+ final val NULL = 24;
+ final val NEW = 25;
+ final val WITH = 26;
+ final val SUPER = 27;
+ final val CASE = 28;
+ final val CASECLASS = 29;
+ final val CASEOBJECT = 30;
+ final val VAL = 31;
+ final val ABSTRACT = 32;
+ final val FINAL = 33;
+ final val PRIVATE = 34;
+ final val PROTECTED = 35;
+ final val OVERRIDE = 36;
+ final val IMPLICIT = 37;
+ final val VAR = 38;
+ final val DEF = 39;
+ final val TYPE = 40;
+ final val EXTENDS = 41;
+ final val TRUE = 42;
+ final val FALSE = 43;
+ final val OBJECT = 44;
+ final val CLASS = 45;
+
+ final val IMPORT = 46;
+ final val PACKAGE = 47;
+ final val YIELD = 48;
+ final val DO = 49;
+ final val TRAIT = 50;
+ final val SEALED = 51;
+ final val THROW = 52;
+ final val TRY = 53;
+ final val CATCH = 54;
+ final val FINALLY = 55;
+ final val WHILE = 56;
+ final val RETURN = 57;
+ final val MATCH = 58;
+ final val REQUIRES = 59;
+
+ /** special symbols */
+ final val COMMA = 61;
+ final val SEMI = 62;
+ final val DOT = 63;
+ final val USCORE = 64;
+ final val COLON = 65;
+ final val EQUALS = 66;
+ final val LARROW = 67;
+ final val ARROW = 68;
+ final val NEWLINE = 69;
+ final val SUBTYPE = 70;
+ final val SUPERTYPE = 71;
+ final val HASH = 72;
+ final val AT = 73;
+ final val VIEWBOUND = 74;
+
+ /** parenthesis */
+ final val LPAREN = 90;
+ final val RPAREN = 91;
+ final val LBRACKET = 92;
+ final val RBRACKET = 93;
+ final val LBRACE = 94;
+ final val RBRACE = 95;
+
+ /** XML mode */
+ final val XMLSTART = 96;
+}
diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
new file mode 100644
index 0000000000..70355350a7
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala
@@ -0,0 +1,289 @@
+/* NSC -- new scala compiler
+ * Copyright 2005 LAMP/EPFL
+ * @author Martin Odersky
+ */
+// $Id$
+package scala.tools.nsc.ast.parser;
+
+import symtab.Flags._;
+import util.ListBuffer;
+
+abstract class TreeBuilder {
+
+ val global: Global;
+ import global._;
+ import posAssigner.atPos;
+
+ def freshName(prefix: String): Name;
+
+ def freshName(): Name = freshName("x$");
+
+ private object patvarTransformer extends Transformer {
+ override def transform(tree: Tree): Tree = tree match {
+ case Ident(name) if (treeInfo.isVariableName(name) && name != nme.WILDCARD) =>
+ atPos(tree.pos)(Bind(name, Ident(nme.WILDCARD)))
+ case Typed(id @ Ident(name), tpt) if (treeInfo.isVariableName(name) && name != nme.WILDCARD) =>
+ Bind(name, atPos(tree.pos)(Typed(Ident(nme.WILDCARD), tpt))) setPos id.pos
+ case Apply(fn @ Apply(_, _), args) =>
+ copy.Apply(tree, transform(fn), transformTrees(args))
+ case Apply(fn, args) =>
+ copy.Apply(tree, fn, transformTrees(args))
+ case Typed(expr, tpt) =>
+ copy.Typed(tree, transform(expr), tpt)
+ case Bind(name, body) =>
+ copy.Bind(tree, name, transform(body))
+ case Sequence(_) | Alternative(_) | Star(_) =>
+ super.transform(tree)
+ case _ =>
+ tree
+ }
+ }
+
+ /** Traverse pattern and collect all variable names in buffer */
+ private object getvarTraverser extends Traverser {
+ val buf = new ListBuffer[Name];
+ def init: Traverser = { buf.clear; this }
+ override def traverse(tree: Tree): unit = tree match {
+ case Bind(name, tpe) =>
+ if ((name != nme.WILDCARD) && (buf.elements forall (name !=))) buf += name;
+ traverse(tpe)
+ case _ => super.traverse(tree)
+ }
+ }
+
+ /** Returns list of all pattern variables without duplicates */
+ private def getVariables(tree: Tree): List[Name] = {
+ getvarTraverser.init.traverse(tree);
+ getvarTraverser.buf.toList
+ }
+
+ private def mkTuple(trees: List[Tree]): Tree = trees match {
+ case List() => Literal(())
+ case List(tree) => tree
+ case _ => Apply(Select(Ident(nme.scala_), newTermName("Tuple" + trees.length)), trees)
+ }
+
+ /** If tree is a variable pattern, return Some("its name and type").
+ * Otherwise return none */
+ private def matchVarPattern(tree: Tree): Option[Pair[Name, Tree]] = tree match {
+ case Ident(name) => Some(Pair(name, TypeTree()))
+ case Bind(name, Ident(nme.WILDCARD)) => Some(Pair(name, TypeTree()))
+ case Typed(Ident(name), tpt) => Some(Pair(name, tpt))
+ case Bind(name, Typed(Ident(nme.WILDCARD), tpt)) => Some(Pair(name, tpt))
+ case _ => None
+ }
+
+ /** Create tree representing (unencoded) binary operation expression or pattern. */
+ def makeBinop(isExpr: boolean, left: Tree, op: Name, right: Tree): Tree = {
+ if (isExpr) {
+ if (treeInfo.isLeftAssoc(op)) {
+ Apply(Select(left, op.encode), List(right))
+ } else {
+ val x = freshName();
+ Block(
+ List(ValDef(Modifiers(SYNTHETIC), x, TypeTree(), left)),
+ Apply(Select(right, op.encode), List(Ident(x))))
+ }
+ } else {
+ Apply(Ident(op.encode.toTypeName), List(left, right))
+ }
+ }
+
+ /** Create tree representing an object creation <new parents { stats }> */
+ def makeNew(parents: List[Tree], stats: List[Tree], argss: List[List[Tree]]): Tree =
+ if (parents.tail.isEmpty && stats.isEmpty)
+ New(parents.head, argss)
+ else {
+ val x = nme.ANON_CLASS_NAME.toTypeName;
+ Block(
+ List(ClassDef(
+ Modifiers(FINAL | SYNTHETIC), x, List(), TypeTree(),
+ Template(parents, List(List()), argss, stats))),
+ New(Ident(x), List(List())))
+ }
+
+ /** Create a tree represeting an assignment <lhs = rhs> */
+ def makeAssign(lhs: Tree, rhs: Tree): Tree = lhs match {
+ case Apply(fn, args) => Apply(Select(fn, nme.update), args ::: List(rhs))
+ case _ => Assign(lhs, rhs)
+ }
+
+ /** A type tree corresponding to (possibly unary) intersection type */
+ def makeIntersectionTypeTree(tps: List[Tree]): Tree = {
+ if (tps.tail.isEmpty) tps.head else CompoundTypeTree(Template(tps, List()))
+ }
+
+ /** Create tree representing a while loop */
+ def makeWhile(lname: Name, cond: Tree, body: Tree): Tree = {
+ val continu = Apply(Ident(lname), List());
+ val rhs = If(cond, Block(List(body), continu), Literal(()));
+ LabelDef(lname, Nil, rhs)
+ }
+
+ /** Create tree representing a do-while loop */
+ def makeDoWhile(lname: Name, body: Tree, cond: Tree): Tree = {
+ val continu = Apply(Ident(lname), List());
+ val rhs = Block(List(body), If(cond, continu, Literal(())));
+ LabelDef(lname, Nil, rhs)
+ }
+
+ /** Create block of statements `stats' */
+ def makeBlock(stats: List[Tree]): Tree = {
+ if (stats.isEmpty) Literal(())
+ else if (!stats.last.isTerm) Block(stats, Literal(()));
+ else if (stats.length == 1) stats(0)
+ else Block(stats.init, stats.last)
+ }
+
+ /** Create tree for for-comprehension generator <val pat0 <- rhs0> */
+ def makeGenerator(pat: Tree, rhs: Tree): Tree = {
+ val pat1 = patvarTransformer.transform(pat);
+ val rhs1 = matchVarPattern(pat1) match {
+ case Some(_) =>
+ rhs
+ case None =>
+ Apply(
+ Select(rhs, nme.filter),
+ List(makeVisitor(List(
+ CaseDef(pat1.duplicate, EmptyTree, Literal(true)),
+ CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(false))))))
+ }
+ CaseDef(pat1, EmptyTree, rhs1)
+ }
+
+ /** Create tree for for-comprehension <for (enums) do body> or
+ * <for (enums) yield body> where mapName and flatMapName are chosen
+ * corresponding to whether this is a for-do or a for-yield.
+ */
+ private def makeFor(mapName: Name, flatMapName: Name, enums: List[Tree], body: Tree): Tree = {
+
+ def makeCont(pat: Tree, body: Tree): Tree = matchVarPattern(pat) match {
+ case Some(Pair(name, tpt)) =>
+ Function(List(ValDef(Modifiers(PARAM), name, tpt, EmptyTree)), body)
+ case None =>
+ makeVisitor(List(CaseDef(pat, EmptyTree, body)))
+ }
+
+ def makeBind(meth: Name, qual: Tree, pat: Tree, body: Tree): Tree =
+ Apply(Select(qual, meth), List(makeCont(pat, body)));
+
+ atPos(enums.head.pos) {
+ enums match {
+ case CaseDef(pat, g, rhs) :: Nil =>
+ makeBind(mapName, rhs, pat, body)
+ case CaseDef(pat, g, rhs) :: (rest @ (CaseDef(_, _, _) :: _)) =>
+ makeBind(flatMapName, rhs, pat, makeFor(mapName, flatMapName, rest, body))
+ case CaseDef(pat, g, rhs) :: test :: rest =>
+ makeFor(mapName, flatMapName,
+ CaseDef(pat, g, makeBind(nme.filter, rhs, pat.duplicate, test)) :: rest,
+ body)
+ }
+ }
+ }
+
+ /** Create tree for for-do comprehension <for (enums) body> */
+ def makeFor(enums: List[Tree], body: Tree): Tree =
+ makeFor(nme.foreach, nme.foreach, enums, body);
+
+ /** Create tree for for-yield comprehension <for (enums) yield body> */
+ def makeForYield(enums: List[Tree], body: Tree): Tree =
+ makeFor(nme.map, nme.flatMap, enums, body);
+
+ /** Create tree for a pattern alternative */
+ def makeAlternative(ts: List[Tree]): Tree = {
+ def alternatives(t: Tree): List[Tree] = t match {
+ case Alternative(ts) => ts
+ case _ => List(t)
+ }
+ Alternative(for (val t <- ts; val a <- alternatives(t)) yield a)
+ }
+
+ /** Create tree for a pattern sequence */
+ def makeSequence(ts: List[Tree]): Tree = {
+ def elements(t: Tree): List[Tree] = t match {
+ case Sequence(ts) => ts
+ case _ => List(t)
+ }
+ Sequence(for (val t <- ts; val e <- elements(t)) yield e)
+ }
+
+ /** Create tree for the p+ regex pattern, becomes p p* */
+ def makePlus(p: Tree): Tree =
+ makeSequence(List(p, Star(p.duplicate)));
+
+ /** Create tree for the p? regex pattern, becomes (p| ) */
+ def makeOpt(p: Tree): Tree =
+ makeAlternative(List(p, Sequence(List())));
+
+ /** Create visitor <x => x match cases> */
+ def makeVisitor(cases: List[CaseDef]): Tree = {
+ val x = freshName();
+ Function(List(ValDef(Modifiers(PARAM | SYNTHETIC), x, TypeTree(), EmptyTree)), Match(Ident(x), cases))
+ }
+
+ /** Create tree for case definition <case pat if guard => rhs> */
+ def makeCaseDef(pat: Tree, guard: Tree, rhs: Tree): CaseDef = {
+ CaseDef(patvarTransformer.transform(pat), guard, rhs);
+ }
+
+ /** Create tree for pattern definition <mods val pat0 = rhs> */
+ def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree): List[Tree] = matchVarPattern(pat) match {
+ case Some(Pair(name, tpt)) =>
+ List(ValDef(mods, name, tpt, rhs))
+
+ case None =>
+ // in case there are no variables in pattern
+ // val p = e ==> e.match (case p => ())
+ //
+ // in case there is exactly one variable in pattern
+ // val x_1 = e.match (case p => (x_1))
+ //
+ // in case there are more variables in pattern
+ // val p = e ==> private synthetic val t$ = e.match (case p => (x_1, ..., x_N))
+ // val x_1 = t$._1
+ // ...
+ // val x_N = t$._N
+ val pat1 = patvarTransformer.transform(pat);
+ val vars = getVariables(pat1);
+ val matchExpr = atPos(pat1.pos){
+ Match(rhs, List(CaseDef(pat1, EmptyTree, mkTuple(vars map Ident))))
+ }
+ vars match {
+ case List() =>
+ List(matchExpr)
+ case List(vname) =>
+ List(ValDef(mods, vname, TypeTree(), matchExpr))
+ case _ =>
+ val tmp = freshName();
+ val firstDef = ValDef(Modifiers(PRIVATE | LOCAL | SYNTHETIC), tmp, TypeTree(), matchExpr);
+ var cnt = 0;
+ val restDefs = for (val v <- vars) yield {
+ cnt = cnt + 1;
+ ValDef(mods, v, TypeTree(), Select(Ident(tmp), newTermName("_" + cnt)))
+ }
+ firstDef :: restDefs
+ }
+ }
+
+ /** Create a tree representing a function type */
+ def makeFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree =
+ AppliedTypeTree(
+ Select(Ident(nme.scala_), newTypeName("Function" + argtpes.length)),
+ argtpes ::: List(restpe));
+
+ /** Append implicit view section if for `implicitViews' if nonempty */
+ def addImplicitViews(owner: Name, vparamss: List[List[ValDef]], implicitViews: List[Tree]): List[List[ValDef]] = {
+ val mods = Modifiers(if (owner.isTypeName) PARAMACCESSOR | LOCAL | PRIVATE else PARAM);
+ def makeViewParam(tpt: Tree) = ValDef(mods | IMPLICIT, freshName("view$"), tpt, EmptyTree);
+ if (implicitViews.isEmpty) vparamss
+ else vparamss ::: List(implicitViews map makeViewParam)
+ }
+
+ /** Create a tree representing a packaging */
+ def makePackaging(pkg: Tree, stats: List[Tree]): PackageDef = pkg match {
+ case Ident(name) =>
+ PackageDef(name, stats)
+ case Select(qual, name) =>
+ makePackaging(qual, List(PackageDef(name, stats)))
+ }
+}