summaryrefslogtreecommitdiff
path: root/sources/scalac/ast
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2003-02-13 14:41:36 +0000
committerMartin Odersky <odersky@gmail.com>2003-02-13 14:41:36 +0000
commit4177daab2f54bdb20c71f623296a8bb32616fd12 (patch)
tree23f08b43f3758e825d5965b336030603a65bbcf7 /sources/scalac/ast
parent33d6e170c97ca7b2f991896a0729941a7240b6d6 (diff)
downloadscala-4177daab2f54bdb20c71f623296a8bb32616fd12.tar.gz
scala-4177daab2f54bdb20c71f623296a8bb32616fd12.tar.bz2
scala-4177daab2f54bdb20c71f623296a8bb32616fd12.zip
Initial version.
Diffstat (limited to 'sources/scalac/ast')
-rw-r--r--sources/scalac/ast/AbstractTreeCopyFactory.java30
-rw-r--r--sources/scalac/ast/LazyTreeFactory.java430
-rw-r--r--sources/scalac/ast/Transformer.java401
-rw-r--r--sources/scalac/ast/Traverser.java215
-rw-r--r--sources/scalac/ast/Tree.java771
-rw-r--r--sources/scalac/ast/TreeCopyFactory.java165
-rw-r--r--sources/scalac/ast/TreeCreator.java293
-rw-r--r--sources/scalac/ast/TreeFactory.java155
-rw-r--r--sources/scalac/ast/TreeGen.java562
-rw-r--r--sources/scalac/ast/TreeInfo.java136
-rw-r--r--sources/scalac/ast/TreeList.java71
-rw-r--r--sources/scalac/ast/parser/Parser.java1704
-rw-r--r--sources/scalac/ast/parser/ParserPhase.java63
-rw-r--r--sources/scalac/ast/parser/Scanner.java793
-rw-r--r--sources/scalac/ast/parser/SourceRepresentation.java205
-rw-r--r--sources/scalac/ast/parser/Sourcefile.java304
-rw-r--r--sources/scalac/ast/parser/TokenData.java44
-rw-r--r--sources/scalac/ast/parser/Tokens.java84
-rw-r--r--sources/scalac/ast/printer/HTMLTreePrinter.java173
-rw-r--r--sources/scalac/ast/printer/TextTreePrinter.java683
-rw-r--r--sources/scalac/ast/printer/TreePrinter.java34
21 files changed, 7316 insertions, 0 deletions
diff --git a/sources/scalac/ast/AbstractTreeCopyFactory.java b/sources/scalac/ast/AbstractTreeCopyFactory.java
new file mode 100644
index 0000000000..358d468cd4
--- /dev/null
+++ b/sources/scalac/ast/AbstractTreeCopyFactory.java
@@ -0,0 +1,30 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+\* */
+
+// $Id$
+
+package scalac.ast;
+
+import scalac.ast.*;
+
+/**
+ * Abstract superclass for all TreeCopyFactories, which provides only
+ * the code to copy the attribution from the "old" to the "new" tree.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+public abstract class AbstractTreeCopyFactory implements TreeCopyFactory {
+ public void attribute(Tree newTree, Tree oldTree) {
+ if (newTree != oldTree) {
+ newTree.type = oldTree.type;
+ if (newTree.hasSymbol())
+ newTree.setSymbol(oldTree.symbol());
+ }
+ }
+}
diff --git a/sources/scalac/ast/LazyTreeFactory.java b/sources/scalac/ast/LazyTreeFactory.java
new file mode 100644
index 0000000000..43cef5652a
--- /dev/null
+++ b/sources/scalac/ast/LazyTreeFactory.java
@@ -0,0 +1,430 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast;
+
+import scalac.util.Name;
+import Tree.*;
+
+public class LazyTreeFactory extends AbstractTreeCopyFactory {
+ protected final TreeFactory make;
+
+ public LazyTreeFactory(TreeFactory make) {
+ this.make = make;
+ }
+
+ public Tree Bad(Tree tree) {
+ return tree;
+ }
+
+ public Tree ClassDef(Tree tree,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Template impl) {
+ ClassDef t = (ClassDef)tree;
+ if ((t.mods == mods) &&
+ (t.name == name) &&
+ (t.tparams == tparams) &&
+ (t.vparams == vparams) &&
+ (t.tpe == tpe) &&
+ (t.impl == impl))
+ return t;
+ tree = make.ClassDef(t.pos, mods, name, tparams, vparams, tpe, impl);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree PackageDef(Tree tree,
+ Tree packaged,
+ Template impl) {
+ PackageDef t = (PackageDef)tree;
+ if ((t.packaged == packaged) &&
+ (t.impl == impl))
+ return t;
+ tree = make.PackageDef(t.pos, packaged, impl);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree ModuleDef(Tree tree,
+ int mods,
+ Name name,
+ Tree tpe,
+ Template impl) {
+ ModuleDef t = (ModuleDef)tree;
+ if ((t.mods == mods) &&
+ (t.name == name) &&
+ (t.tpe == tpe) &&
+ (t.impl == impl))
+ return t;
+ tree = make.ModuleDef(t.pos, mods, name, tpe, impl);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree ValDef(Tree tree,
+ int mods,
+ Name name,
+ Tree tpe,
+ Tree rhs) {
+ ValDef t = (ValDef)tree;
+ if ((t.mods == mods) &&
+ (t.name == name) &&
+ (t.tpe == tpe) &&
+ (t.rhs == rhs))
+ return t;
+ tree = make.ValDef(t.pos, mods, name, tpe, rhs);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree PatDef(Tree tree,
+ int mods,
+ Tree pat,
+ Tree rhs) {
+ PatDef t = (PatDef)tree;
+ if ((t.mods == mods) &&
+ (t.pat == pat) &&
+ (t.rhs == rhs))
+ return t;
+ tree = make.PatDef(t.pos, mods, pat, rhs);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree DefDef(Tree tree,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Tree rhs) {
+ DefDef t = (DefDef)tree;
+ if ((t.mods == mods) &&
+ (t.name == name) &&
+ (t.tparams == tparams) &&
+ (t.vparams == vparams) &&
+ (t.tpe == tpe) &&
+ (t.rhs == rhs))
+ return t;
+ tree = make.DefDef(t.pos, mods, name, tparams, vparams, tpe, rhs);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree TypeDef(Tree tree,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ Tree rhs) {
+ TypeDef t = (TypeDef)tree;
+ if ((t.mods == mods) &&
+ (t.name == name) &&
+ (t.tparams == tparams) &&
+ (t.rhs == rhs))
+ return t;
+ tree = make.TypeDef(t.pos, mods, name, tparams, rhs);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree Import(Tree tree,
+ Tree expr,
+ Name[] selectors) {
+ Import t = (Import)tree;
+ if (t.expr == expr && t.selectors == selectors)
+ return t;
+ tree = make.Import(t.pos, expr, selectors);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree CaseDef(Tree tree,
+ Tree pat,
+ Tree guard,
+ Tree body) {
+ CaseDef t = (CaseDef)tree;
+ if ((t.pat == pat) &&
+ (t.guard == guard) &&
+ (t.body == body))
+ return t;
+ tree = make.CaseDef(t.pos, pat, guard, body);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Template Template(Tree tree,
+ Tree[] parents,
+ Tree[] body) {
+ Template t = (Template)tree;
+ if ((t.parents == parents) &&
+ (t.body == body))
+ return t;
+ Template newTree = make.Template(t.pos, parents, body);
+ attribute(newTree, t);
+ return newTree;
+ }
+
+ public Tree LabelDef(Tree tree,
+ Tree[] params,
+ Tree rhs) {
+ LabelDef t = (LabelDef)tree;
+ if ((t.params == params) &&
+ (t.rhs == rhs))
+ return t;
+ tree = make.LabelDef(t.pos,params,rhs);
+ attribute(tree,t);
+ return tree;
+ }
+
+ public Tree Block(Tree tree,
+ Tree[] stats) {
+ Block t = (Block)tree;
+ if (t.stats == stats)
+ return t;
+ tree = make.Block(t.pos, stats);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree Tuple(Tree tree,
+ Tree[] trees) {
+ Tuple t = (Tuple)tree;
+ if (t.trees == trees)
+ return t;
+ tree = make.Tuple(t.pos, trees);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree Visitor(Tree tree,
+ CaseDef[] cases) {
+ Visitor t = (Visitor)tree;
+ if (t.cases == cases)
+ return t;
+ tree = make.Visitor(t.pos, cases);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree Function(Tree tree,
+ ValDef[] vparams,
+ Tree body) {
+ Function t = (Function)tree;
+ if ((t.vparams == vparams) &&
+ (t.body == body))
+ return t;
+ tree = make.Function(t.pos, vparams, body);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree Assign(Tree tree,
+ Tree lhs,
+ Tree rhs) {
+ Assign t = (Assign)tree;
+ if ((t.lhs == lhs) &&
+ (t.rhs == rhs))
+ return t;
+ tree = make.Assign(t.pos, lhs, rhs);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree If(Tree tree,
+ Tree cond,
+ Tree thenp,
+ Tree elsep) {
+ If t = (If)tree;
+ if ((t.cond == cond) &&
+ (t.thenp == thenp) &&
+ (t.elsep == elsep))
+ return t;
+ tree = make.If(t.pos, cond, thenp, elsep);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree New(Tree tree,
+ Template templ) {
+ New t = (New)tree;
+ if (t.templ == templ)
+ return t;
+ tree = make.New(t.pos, templ);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree Typed(Tree tree,
+ Tree expr,
+ Tree tpe) {
+ Typed t = (Typed)tree;
+ if ((t.expr == expr) &&
+ (t.tpe == tpe))
+ return t;
+ tree = make.Typed(t.pos, expr, tpe);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree TypeApply(Tree tree,
+ Tree fun,
+ Tree[] args) {
+ TypeApply t = (TypeApply)tree;
+ if ((t.fun == fun) &&
+ (t.args == args))
+ return t;
+ tree = make.TypeApply(t.pos, fun, args);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree Apply(Tree tree,
+ Tree fun,
+ Tree[] args) {
+ Apply t = (Apply)tree;
+ if ((t.fun == fun) &&
+ (t.args == args))
+ return t;
+ tree = make.Apply(t.pos, fun, args);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree Super(Tree tree,
+ Tree tpe) {
+ Super t = (Super)tree;
+ if (t.tpe == tpe)
+ return t;
+ tree = make.Super(t.pos, tpe);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree This(Tree tree,
+ Tree qualifier) {
+ This t = (This)tree;
+ if (t.qualifier == qualifier)
+ return t;
+ tree = make.This(t.pos, qualifier);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree Select(Tree tree,
+ Tree qualifier,
+ Name selector) {
+ Select t = (Select)tree;
+ if ((t.qualifier == qualifier) &&
+ (t.selector == selector))
+ return t;
+ tree = make.Select(t.pos, qualifier, selector);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree Ident(Tree tree,
+ Name name) {
+ Ident t = (Ident)tree;
+ if (t.name == name)
+ return t;
+ tree = make.Ident(t.pos, name);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree Literal(Tree tree,
+ Object value) {
+ Literal t = (Literal)tree;
+ if (t.value == value)
+ return t;
+ tree = make.Literal(t.pos, value);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree SingletonType(Tree tree,
+ Tree ref) {
+ SingletonType t = (SingletonType)tree;
+ if (t.ref == ref)
+ return t;
+ tree = make.SingletonType(t.pos, ref);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree SelectFromType(Tree tree,
+ Tree qualifier,
+ Name selector) {
+ SelectFromType t = (SelectFromType)tree;
+ if (t.qualifier == qualifier &&
+ t.selector == selector)
+ return t;
+ tree = make.SelectFromType(t.pos, qualifier, selector);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree FunType(Tree tree,
+ Tree[] argtpes,
+ Tree restpe) {
+ FunType t = (FunType)tree;
+ if ((t.argtpes == argtpes) &&
+ (t.restpe == restpe))
+ return t;
+ tree = make.FunType(t.pos, argtpes, restpe);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree CompoundType(Tree tree,
+ Tree[] parents,
+ Tree[] refinements) {
+ CompoundType t = (CompoundType)tree;
+ if ((t.parents == parents) &&
+ (t.refinements == refinements))
+ return t;
+ tree = make.CompoundType(t.pos, parents, refinements);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree TupleType(Tree tree,
+ Tree[] types) {
+ TupleType t = (TupleType)tree;
+ if (t.types == types)
+ return t;
+ tree = make.TupleType(t.pos, types);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree AppliedType(Tree tree,
+ Tree tpe,
+ Tree[] args) {
+ AppliedType t = (AppliedType)tree;
+ if ((t.tpe == tpe) &&
+ (t.args == args))
+ return t;
+ tree = make.AppliedType(t.pos, tpe, args);
+ attribute(tree, t);
+ return tree;
+ }
+
+ public Tree CovariantType(Tree tree,
+ Tree tpe) {
+ CovariantType t = (CovariantType)tree;
+ if (t.tpe == tpe) return t;
+ tree = make.CovariantType(t.pos, tpe);
+ attribute(tree, t);
+ return tree;
+ }
+}
diff --git a/sources/scalac/ast/Transformer.java b/sources/scalac/ast/Transformer.java
new file mode 100644
index 0000000000..1789801c7e
--- /dev/null
+++ b/sources/scalac/ast/Transformer.java
@@ -0,0 +1,401 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast;
+
+import java.io.*;
+import java.util.*;
+import scalac.*;
+import scalac.util.*;
+import scalac.symtab.*;
+import Tree.*;
+
+
+/** A default transformer class. This class traverses the abstract
+ * syntax tree but does not do any transformations.
+ *
+ * @author Matthias Zenger
+ * @version 1.0
+ */
+public class Transformer extends Phase {
+ /** the tree factory
+ */
+ public final TreeFactory make;
+
+ /** a factory for copying trees; the attribution is preserved
+ * or translated according to the TreeCopyFactory; trees are
+ * only copied if new tree introduces changes
+ */
+ public final TreeCopyFactory copy;
+
+ /** a tree generator
+ */
+ public final TreeGen gen;
+
+ /** various constructors
+ */
+ public Transformer(Global global, PhaseDescriptor descr) {
+ this(global, descr, global.make, new LazyTreeFactory(global.make));
+ }
+
+ public Transformer(Global global,
+ PhaseDescriptor descr,
+ TreeFactory make) {
+ this(global, descr, make, new LazyTreeFactory(make));
+ }
+
+ public Transformer(Global global,
+ PhaseDescriptor descr,
+ TreeFactory make,
+ TreeCopyFactory copy) {
+ super(global, descr);
+ this.make = make;
+ this.copy = copy;
+ this.gen = global.treeGen;
+ }
+
+ public void apply() {
+ super.apply();
+ }
+
+ public void apply(Unit unit) {
+ unit.body = transform(unit.body);
+ }
+
+ public Tree[] transform(Tree[] ts) {
+ for (int i = 0; i < ts.length; i++) {
+ Tree t = transform(ts[i]);
+ if (t != ts[i]) {
+ Tree[] res = new Tree[ts.length];
+ System.arraycopy(ts, 0, res, 0, i);
+ res[i] = t;
+ for (int j = i + 1; j < ts.length; j++)
+ res[j] = transform(ts[j]);
+ return res;
+ }
+ }
+ return ts;
+ }
+
+ public Tree[][] transform(Tree[][] ts) {
+ for (int i = 0; i < ts.length; i++) {
+ Tree[] t = transform(ts[i]);
+ if (t != ts[i]) {
+ Tree[][] res = new Tree[ts.length][];
+ System.arraycopy(ts, 0, res, 0, i);
+ res[i] = t;
+ for (int j = i + 1; j < ts.length; j++)
+ res[j] = transform(ts[j]);
+ return res;
+ }
+ }
+ return ts;
+ }
+
+ public ValDef[][] transform(ValDef[][] ts) {
+ for (int i = 0; i < ts.length; i++) {
+ ValDef[] t = transform(ts[i]);
+ if (t != ts[i]) {
+ ValDef[][] res = new ValDef[ts.length][];
+ System.arraycopy(ts, 0, res, 0, i);
+ res[i] = t;
+ for (int j = i + 1; j < ts.length; j++)
+ res[j] = transform(ts[j]);
+ return res;
+ }
+ }
+ return ts;
+ }
+
+ public ValDef[] transform(ValDef[] ts) {
+ for (int i = 0; i < ts.length; i++) {
+ Tree t = transform(ts[i]);
+ if (t != ts[i]) {
+ ValDef[] res = new ValDef[ts.length];
+ System.arraycopy(ts, 0, res, 0, i);
+ res[i] = (ValDef)t;
+ for (int j = i + 1; j < ts.length; j++)
+ res[j] = (ValDef)transform(ts[j]);
+ return res;
+ }
+ }
+ return ts;
+ }
+
+ public TypeDef[] transform(TypeDef[] ts) {
+ for (int i = 0; i < ts.length; i++) {
+ Tree t = transform(ts[i]);
+ if (t != ts[i]) {
+ TypeDef[] res = new TypeDef[ts.length];
+ System.arraycopy(ts, 0, res, 0, i);
+ res[i] = (TypeDef)t;
+ for (int j = i + 1; j < ts.length; j++)
+ res[j] = (TypeDef)transform(ts[j]);
+ return res;
+ }
+ }
+ return ts;
+ }
+
+ public CaseDef[] transform(CaseDef[] ts) {
+ for (int i = 0; i < ts.length; i++) {
+ Tree t = transform(ts[i]);
+ if (t != ts[i]) {
+ CaseDef[] res = new CaseDef[ts.length];
+ System.arraycopy(ts, 0, res, 0, i);
+ res[i] = (CaseDef)t;
+ for (int j = i + 1; j < ts.length; j++)
+ res[j] = (CaseDef)transform(ts[j]);
+ return res;
+ }
+ }
+ return ts;
+ }
+
+ public Template transform(Template tree) {
+ return (Template)transform((Tree)tree);
+ }
+
+ public Tree transform(Tree tree) {
+ if (tree == null)
+ return null;
+ switch (tree) {
+ case ClassDef(int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Template impl):
+ return copy.ClassDef(tree,
+ mods,
+ name,
+ transform(tparams),
+ transform(vparams),
+ transform(tpe),
+ transform(impl));
+ case PackageDef(Tree packaged, Template impl):
+ return copy.PackageDef(tree,
+ transform(packaged),
+ transform(impl));
+ case ModuleDef(int mods,
+ Name name,
+ Tree tpe,
+ Template impl):
+ return copy.ModuleDef(tree,
+ mods,
+ name,
+ transform(tpe),
+ transform(impl));
+ case ValDef(int mods,
+ Name name,
+ Tree tpe,
+ Tree rhs):
+ return copy.ValDef(tree,
+ mods,
+ name,
+ transform(tpe),
+ transform(rhs));
+ case PatDef(int mods,
+ Tree pat,
+ Tree rhs):
+ return copy.PatDef(tree,
+ mods,
+ transform(pat),
+ transform(rhs));
+ case DefDef(int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Tree rhs):
+ return copy.DefDef(tree,
+ mods,
+ name,
+ transform(tparams),
+ transform(vparams),
+ transform(tpe),
+ transform(rhs));
+ case TypeDef(int mods,
+ Name name,
+ TypeDef[] tparams,
+ Tree rhs):
+ return copy.TypeDef(tree,
+ mods,
+ name,
+ transform(tparams),
+ transform(rhs));
+ case Import(Tree expr, Name[] selectors):
+ return copy.Import(tree,
+ transform(expr),
+ selectors);
+ case CaseDef(Tree pat, Tree guard, Tree body):
+ return copy.CaseDef(tree,
+ transform(pat),
+ transform(guard),
+ transform(body));
+ case Template(Tree[] parents, Tree[] body):
+ return copy.Template(tree,
+ transform(parents),
+ transform(body));
+ case LabelDef(Tree[] params,Tree rhs):
+ return copy.LabelDef(tree,
+ transform(params),
+ transform(rhs));
+ case Block(Tree[] stats):
+ return copy.Block(tree,
+ transform(stats));
+ case Tuple(Tree[] trees):
+ return copy.Tuple(tree,
+ transform(trees));
+ case Visitor(CaseDef[] cases):
+ return copy.Visitor(tree,
+ transform(cases));
+ case Function(ValDef[] vparams, Tree body):
+ return copy.Function(tree,
+ transform(vparams),
+ transform(body));
+ case Assign(Tree lhs, Tree rhs):
+ return copy.Assign(tree,
+ transform(lhs),
+ transform(rhs));
+ case If(Tree cond, Tree thenp, Tree elsep):
+ return copy.If(tree,
+ transform(cond),
+ transform(thenp),
+ transform(elsep));
+ case New(Template templ):
+ return copy.New(tree,
+ transform(templ));
+ case Typed(Tree expr, Tree tpe):
+ return copy.Typed(tree,
+ transform(expr),
+ transform(tpe));
+ case TypeApply(Tree fun, Tree[] args):
+ return copy.TypeApply(tree,
+ transform(fun),
+ transform(args));
+ case Apply(Tree fun, Tree[] args):
+ return copy.Apply(tree,
+ transform(fun),
+ transform(args));
+ case Super(Tree tpe):
+ return copy.Super(tree,
+ transform(tpe));
+ case This(Tree qualifier):
+ return copy.This(tree,
+ transform(qualifier));
+ case Select(Tree qualifier, Name selector):
+ return copy.Select(tree,
+ transform(qualifier),
+ selector);
+ case Ident(Name name):
+ return copy.Ident(tree, name);
+ case Literal(Object value):
+ return copy.Literal(tree, value);
+ case SingletonType(Tree ref):
+ return copy.SingletonType(tree,
+ transform(ref));
+ case SelectFromType(Tree qualifier, Name selector):
+ return copy.SelectFromType(tree,
+ transform(qualifier),
+ selector);
+ case FunType(Tree[] argtpes, Tree restpe):
+ return copy.FunType(tree,
+ transform(argtpes),
+ transform(restpe));
+ case CompoundType(Tree[] parents, Tree[] refinements):
+ return copy.CompoundType(tree,
+ transform(parents),
+ transform(refinements));
+ case TupleType(Tree[] types):
+ return copy.TupleType(tree,
+ transform(types));
+ case AppliedType(Tree tpe, Tree[] args):
+ return copy.AppliedType(tree,
+ transform(tpe),
+ transform(args));
+ case CovariantType(Tree tpe):
+ return copy.CovariantType(tree,
+ transform(tpe));
+ default:
+ return tree;
+ }
+ }
+ /* a full pattern-matching statement:
+
+ switch (tree) {
+ case PackageDef(Tree packaged, Template impl):
+
+ case ClassDef(int mods, Name name, TypeDef[] tparams, ValDef[][] vparams,
+ Template impl):
+
+ case ModuleDef(int mods, Name name, Tree tpe, Template impl):
+
+ case ValDef(int mods, Name name, Tree tpe, Tree rhs):
+
+ case PatDef(int mods, Tree pat, Tree rhs):
+
+ case DefDef(int mods, Name name, TypeDef[] tparams, ValDef[][] vparams,
+ Tree tpe, Tree rhs):
+
+ case TypeDef(int mods, Name name, TypeDef[] tparams, Tree rhs):
+
+ case Import(Tree expr):
+
+ case CaseDef(Tree pat, Tree guard, Tree body):
+
+ case Template(Tree[] baseClasses, Tree[] body):
+
+ case LabelDef(Tree[] params,Tree rhs):
+
+ case Block(Tree[] stats):
+
+ case Tuple(Tree[] trees):
+
+ case Visitor(CaseDef[] cases):
+
+ case Function(ValDef[] vparams, Tree body):
+
+ case Assign(Tree lhs, Tree rhs):
+
+ case If(Tree cond, Tree thenp, Tree elsep):
+
+ case New(Template templ):
+
+ case Typed(Tree expr, Tree tpe):
+
+ case TypeApply(Tree fun, Tree[] args):
+
+ case Apply(Tree fun, Tree[] args):
+
+ case Super(Tree tpe):
+
+ case Select(Tree qualifier, Name selector):
+
+ case Ident(Name name):
+
+ case Literal(int kind, Object value):
+
+ case SingletonType(Tree ref):
+
+ case SelectFromType(Tree qualifier, Name selector):
+
+ case FunType(Tree argtpe, Tree restpe):
+
+ case CompoundType(Tree[] baseTypes, Tree[] refinements):
+
+ case TupleType(Tree[] types):
+
+ case AppliedType(Tree tpe, Tree[] args):
+
+ default:
+ return tree;
+ }
+ */
+
+}
diff --git a/sources/scalac/ast/Traverser.java b/sources/scalac/ast/Traverser.java
new file mode 100644
index 0000000000..5c39d9e315
--- /dev/null
+++ b/sources/scalac/ast/Traverser.java
@@ -0,0 +1,215 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+\* */
+
+// $Id$
+
+package scalac.ast;
+
+import java.io.*;
+import java.util.*;
+import scalac.*;
+import scalac.util.*;
+import Tree.*;
+
+
+/** Class to traverse a tree without modifying it.
+ *
+ * @author Michel Schinz
+ */
+
+public class Traverser {
+ public Traverser() {}
+
+ // this should be removed in the future
+ public Traverser(Global global) {}
+
+ public void traverse(Unit unit) {
+ traverse(unit.body);
+ }
+
+ public void traverse(Tree tree) {
+ switch (tree) {
+ case Bad():
+ case Empty:
+ case Ident(_):
+ case Literal(_):
+ return;
+
+ case ClassDef(int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Template impl):
+ traverse(tparams);
+ traverse(vparams);
+ traverse(tpe);
+ traverse(impl);
+ return;
+
+ case PackageDef(Tree packaged, Template impl) :
+ traverse(packaged);
+ traverse(impl);
+ return;
+
+ case ModuleDef(int mods, Name name, Tree tpe, Template impl):
+ traverse(tpe);
+ traverse(impl);
+ return;
+
+ case ValDef(int mods, Name name, Tree tpe, Tree rhs):
+ traverse(tpe);
+ traverse(rhs);
+ return;
+
+ case PatDef(int mods, Tree pat, Tree rhs):
+ traverse(pat);
+ traverse(rhs);
+ return;
+
+ case DefDef(int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Tree rhs):
+ traverse(tparams);
+ traverse(vparams);
+ traverse(tpe);
+ traverse(rhs);
+ return;
+
+ case TypeDef(int mods, Name name, TypeDef[] tparams, Tree rhs):
+ traverse(tparams);
+ traverse(rhs);
+ return;
+
+ case Import(Tree expr, Name[] selectors):
+ traverse(expr);
+ return;
+
+ case CaseDef(Tree pat, Tree guard, Tree body):
+ traverse(pat);
+ traverse(guard);
+ traverse(body);
+ return;
+
+ case Template(Tree[] baseClasses, Tree[] body):
+ traverse(baseClasses);
+ traverse(body);
+ return;
+
+ case LabelDef(Tree[] params,Tree rhs):
+ traverse(params);
+ traverse(rhs);
+ return;
+
+ case Block(Tree[] stats):
+ traverse(stats);
+ return;
+
+ case Tuple(Tree[] trees):
+ traverse(trees);
+ return;
+
+ case Visitor(CaseDef[] cases):
+ traverse(cases);
+ return;
+
+ case Function(ValDef[] vparams, Tree body):
+ traverse(vparams);
+ traverse(body);
+ return;
+
+ case Assign(Tree lhs, Tree rhs):
+ traverse(lhs);
+ traverse(rhs);
+ return;
+
+ case If(Tree cond, Tree thenp, Tree elsep):
+ traverse(cond);
+ traverse(thenp);
+ traverse(elsep);
+ return;
+
+ case New(Template templ):
+ traverse(templ);
+ return;
+
+ case Typed(Tree expr, Tree tpe):
+ traverse(expr);
+ traverse(tpe);
+ return;
+
+ case TypeApply(Tree fun, Tree[] tparams):
+ traverse(fun);
+ traverse(tparams);
+ return;
+
+ case Apply(Tree fun, Tree[] vparam):
+ traverse(fun);
+ traverse(vparam);
+ return;
+
+ case Super(Tree tpe):
+ traverse(tpe);
+ return;
+
+ case This(Tree qualifier):
+ traverse(qualifier);
+ return;
+
+ case Select(Tree qualifier, Name selector):
+ traverse(qualifier);
+ return;
+
+ case SingletonType(Tree ref):
+ traverse(ref);
+ return;
+
+ case SelectFromType(Tree qualifier, Name selector):
+ traverse(qualifier);
+ return;
+
+ case FunType(Tree[] argtpes, Tree restpe):
+ traverse(argtpes);
+ traverse(restpe);
+ return;
+
+ case CompoundType(Tree[] baseTypes, Tree[] refinements):
+ traverse(baseTypes);
+ traverse(refinements);
+ return;
+
+ case TupleType(Tree[] types):
+ traverse(types);
+ return;
+
+ case AppliedType(Tree tpe, Tree[] args):
+ traverse(tpe);
+ traverse(args);
+ return;
+
+ case CovariantType(Tree tpe):
+ traverse(tpe);
+ return;
+
+ default:
+ throw new ApplicationError("unknown node " + tree);
+ }
+ }
+
+ public void traverse(Tree[] array) {
+ for (int i = 0; i < array.length; ++i)
+ traverse(array[i]);
+ }
+
+ public void traverse(Tree[][] array) {
+ for (int i = 0; i < array.length; ++i)
+ traverse(array[i]);
+ }
+}
diff --git a/sources/scalac/ast/Tree.java b/sources/scalac/ast/Tree.java
new file mode 100644
index 0000000000..80304ea78e
--- /dev/null
+++ b/sources/scalac/ast/Tree.java
@@ -0,0 +1,771 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast;
+
+import scalac.ast.printer.*;
+import scalac.ApplicationError;
+import scalac.util.Name;
+import scalac.util.Position;
+import scalac.symtab.Type;
+import scalac.symtab.Symbol;
+
+public class Tree {
+
+ public int pos = Position.NOPOS;
+ public Type type;
+
+/** empty tree array
+ */
+ public static final Tree[] EMPTY_ARRAY = new Tree[0];
+
+/** representation for parser errors
+ */
+ public case Bad();
+
+/** a tree node for the absence of a tree
+ */
+ public case Empty;
+ static { Empty.type = Type.NoType; }
+
+/** class and data declaration
+ */
+ public case ClassDef(int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Template impl) {
+ assert name.isTypeName();
+ }
+
+/** package declaration
+ */
+ public case PackageDef(Tree packaged,
+ Template impl) {
+ if (!packaged.isTerm())
+ throw new ApplicationError("PackageDef expects term as rhs.");
+ }
+
+/** module declaration
+ */
+ public case ModuleDef(int mods,
+ Name name,
+ Tree tpe,
+ Template impl) {
+ assert !name.isTypeName();
+ }
+
+/** var or let declaration
+ */
+ public case ValDef(int mods,
+ Name name,
+ Tree tpe,
+ Tree rhs) {
+ assert !name.isTypeName();
+ if (!tpe.isType())
+ throw new ApplicationError("ValDef expects type as tpe; found: " + tpe);
+ if (!rhs.isTerm())
+ throw new ApplicationError("ValDef expects term as rhs.");
+ }
+
+/** val declaration
+ */
+ public case PatDef(int mods,
+ Tree pat,
+ Tree rhs) {
+ if (!rhs.isTerm())
+ throw new ApplicationError("PatDef expects term as rhs.");
+ }
+
+/** def declaration
+ */
+ public case DefDef(int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Tree rhs) {
+ assert !name.isTypeName();
+ if (!tpe.isType())
+ throw new ApplicationError("DefDef expects type as tpe.");
+ if (!rhs.isTerm())
+ throw new ApplicationError("DefDef expects term as rhs. Found: " + rhs.getClass());
+ }
+
+/** type declaration
+ */
+ public case TypeDef(int mods,
+ Name name,
+ TypeDef[] tparams,
+ Tree rhs) {
+ assert name.isTypeName();
+ if (!rhs.isType())
+ throw new ApplicationError("TypeDef expects type as rhs; found: " + rhs);
+ }
+
+/** import declaration
+ */
+ public case Import(Tree expr, Name[] selectors) {
+ if (!expr.isTerm())
+ throw new ApplicationError("Import expects term.");
+ }
+
+/** case declaration
+ */
+ public case CaseDef(Tree pat,
+ Tree guard,
+ Tree body) {
+ if (!guard.isTerm())
+ throw new ApplicationError("CaseDef expects term as guard.");
+ if (!body.isTerm())
+ throw new ApplicationError("CaseDef expects term as body.");
+ }
+
+/** instantiation templates
+*/
+ public case Template(Tree[] parents,
+ Tree[] body) {
+ if (parents != null) {
+ for (int i = 0; i < parents.length; i++) {
+ if (!parents[i].isTerm())
+ throw new ApplicationError("Template requires terms as baseClasses.");
+ }
+ }
+ }
+
+/** labelled expression - the symbols in the array (must be Idents!) are those the
+ label takes as argument
+*/
+ public case LabelDef(Tree[] params,Tree rhs) {
+ for (int i = 0;i < params.length; i++) {
+ if (!(params[i] instanceof Ident))
+ throw new ApplicationError("LabelDef requires Idents");
+ }
+ }
+
+/** block of expressions (semicolon separated expressions)
+ */
+ public case Block(Tree[] stats);
+
+/** tuple of expressions (comma separated expressions)
+ */
+ public case Tuple(Tree[] trees) {
+ if (trees != null) {
+ for (int i = 0; i < trees.length; i++) {
+ if (!trees[i].isTerm())
+ throw new ApplicationError("Tuple requires terms");
+ }
+ }
+ }
+
+/** visitor (a sequence of cases)
+ */
+ public case Visitor(CaseDef[] cases);
+
+/** an anonymous function
+ */
+ public case Function(ValDef[] vparams,
+ Tree body) {
+ if (!body.isTerm())
+ throw new ApplicationError("Function body has to be a term.");
+ }
+
+/** assignment
+ */
+ public case Assign(Tree lhs,
+ Tree rhs) {
+ if (!lhs.isTerm())
+ throw new ApplicationError("lhs of Assign has to be a term.");
+ if (!rhs.isTerm())
+ throw new ApplicationError("rhs of Assign has to be a term.");
+ }
+
+/** conditional expression
+ */
+ public case If(Tree cond,
+ Tree thenp,
+ Tree elsep) {
+ assert cond.isTerm() &&
+ thenp.isTerm() &&
+ elsep.isTerm();
+ }
+
+/** instantiation
+ */
+ public case New(Template templ);
+
+/** type annotation
+ */
+ public case Typed(Tree expr,
+ Tree tpe) {
+ if (!expr.isTerm())
+ throw new ApplicationError("Typed expects term as first argument.");
+ if (!tpe.isType())
+ throw new ApplicationError("Typed expects type as second argument.");
+ }
+
+/** type application
+ */
+ public case TypeApply(Tree fun,
+ Tree[] args) {
+ if (!fun.isTerm()) {
+ new TextTreePrinter().print(fun).println().end();//debug
+ throw new ApplicationError("TypeApply expects term as function.");
+ }
+ for (int i = 0; i < args.length; i++) {
+ if (!args[i].isType())
+ throw new ApplicationError("TypeApply expects types as arguments.");
+ }
+ }
+
+/** value application
+ */
+ public case Apply(Tree fun,
+ Tree[] args) {
+ if (args != null) {
+ for (int i = 0; i < args.length; i++) {
+ if (!args[i].isTerm())
+ throw new ApplicationError("Apply expects terms as arguments. Found: " + args[i].getClass());
+ }
+ }
+ }
+
+/** super reference
+ */
+ public case Super(Tree tpe) {
+ if (!tpe.isType()) {
+ throw new ApplicationError("Super expects type.");
+ }
+ }
+
+/** self reference
+ */
+ public case This(Tree qualifier) {
+ if (!qualifier.isType())
+ throw new ApplicationError("This expects type.");
+ }
+
+/** designator
+ */
+ public case Select(Tree qualifier,
+ Name selector) {
+ if (!qualifier.isTerm())
+ throw new ApplicationError("Select expects term.");
+ }
+
+/** identifier
+ */
+ public case Ident(Name name) {
+ assert name != null;
+ }
+
+/** literal
+ */
+ public case Literal(Object value);
+
+/** singleton type
+ */
+ public case SingletonType(Tree ref) {
+ if (!ref.isTerm())
+ throw new ApplicationError("SingletonType expects term.");
+ }
+
+/** type selection
+ */
+ public case SelectFromType(Tree qualifier,
+ Name selector) {
+ if (!qualifier.isType())
+ throw new ApplicationError("SelectFromType expects type.");
+ assert selector.isTypeName();
+ }
+
+/** function type
+ */
+ public case FunType(Tree[] argtpes,
+ Tree restpe) {
+ for (int i = 0; i < argtpes.length; i++)
+ if (!argtpes[i].isType())
+ throw new ApplicationError("FunType requires types as args.");
+ if (!restpe.isType())
+ throw new ApplicationError("FunType requires type as result.");
+ }
+
+/** object type (~ Template)
+ */
+ public case CompoundType(Tree[] parents,
+ Tree[] refinements) {
+ if (parents != null) {
+ assert parents.length > 0;
+ for (int i = 0; i < parents.length; i++) {
+ if (!parents[i].isType())
+ throw new ApplicationError("CompoundType requires types as parents.");
+ }
+ }
+ }
+
+/** tuple type (~ Tuple)
+ */
+ public case TupleType(Tree[] types) {
+ if (types != null) {
+ for (int i = 0; i < types.length; i++) {
+ if (!types[i].isType())
+ throw new ApplicationError("TupleType requires types.");
+ }
+ }
+ }
+
+ /** applied type
+ */
+ public case AppliedType(Tree tpe, Tree[] args) {
+ assert tpe.isType() : this;
+ for (int i = 0; i < args.length; i++) assert args[i].isType() : args[i];
+ }
+
+ /** a covariant type
+ */
+ public case CovariantType(Tree tpe) {
+ assert tpe.isType();
+ }
+
+ /** Get the type of the node. */
+ public Type type() {
+ assert type != null : this;
+ return type;
+ }
+
+ /** Set the type of the node. */
+ public Tree setType(Type type) {
+ assert !(type instanceof Type.LazyType) : symbol();
+ this.type = type;
+ return this;
+ }
+
+ /**
+ * Get types attached to array of nodes.
+ */
+ public static Type[] typeOf(Tree[] trees) {
+ Type[] tps = new Type[trees.length];
+ for (int i = 0; i < trees.length; i++)
+ tps[i] = trees[i].type();
+ return tps;
+ }
+
+ /** Has this tree a symbol field? */
+ public boolean hasSymbol() {
+ return false;
+ }
+
+ /**
+ * Get symbol attached to the node, if any.
+ */
+ public Symbol symbol () {
+ return null;
+ }
+
+ /**
+ * Set symbol attached to the node, if possible.
+ */
+ public Tree setSymbol(Symbol sym) {
+ throw new ApplicationError ("no settable symbol for node", this);
+ }
+
+ /**
+ * Get symbols attached to array of nodes.
+ */
+ public static Symbol[] symbolOf(Tree[] trees) {
+ Symbol[] syms = new Symbol[trees.length];
+ for (int i = 0; i < trees.length; i++)
+ syms[i] = trees[i].symbol();
+ return syms;
+ }
+
+ /**
+ * Tells if the tree defines a symbol.
+ **/
+ public boolean definesSymbol() {
+ return false;
+ }
+
+ /** Get string corresponding to this tree
+ * only implemented for prefix trees, maybe we should generalize this;
+ * the PatternMatch phase needs support for Apply, so this case got added
+ */
+ public String toString() {
+ switch (this) {
+ case This(Tree qual):
+ return (qual == Tree.Empty) ? "this" : qual + ".this";
+ case Select(Tree qual, Name name):
+ return qual + "." + name;
+ case Ident(Name name):
+ return name.toString();
+ case Apply(Tree fn, Tree[] args):
+ String res = fn + "(";
+ if ((args == null) || (args.length == 0))
+ return res + ")";
+ res += args[0].toString();
+ for (int i = 1; i < args.length; i++)
+ res += ", " + args[i];
+ return res + ")";
+ case Literal(Object value):
+ if (value instanceof String)
+ return "\"" + value + "\"";
+ else
+ return value.toString();
+ case Import(Tree expr, _):
+ return "import " + expr;
+ case Empty:
+ return "<empty>";
+ default:
+ return super.toString();
+ }
+ }
+
+ public static class ExtBad extends Bad {
+ private Symbol symbol;
+
+ public ExtBad() {
+ super();
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+ }
+
+ public static class ExtClassDef extends ClassDef {
+ private Symbol symbol;
+
+ public ExtClassDef(int mods, Name name, TypeDef[] tparams,
+ ValDef[][] vparams, Tree tpe, Template impl)
+ {
+ super(mods, name, tparams, vparams, tpe, impl);
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+
+ public boolean definesSymbol() {
+ return true;
+ }
+ }
+
+ public static class ExtModuleDef extends ModuleDef {
+ private Symbol symbol;
+
+ public ExtModuleDef(int mods, Name name, Tree tpe, Template impl)
+ {
+ super(mods, name, tpe, impl);
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+
+ public boolean definesSymbol() {
+ return true;
+ }
+ }
+
+ public static class ExtValDef extends ValDef {
+
+ public static final ValDef[] EMPTY_ARRAY = new ValDef[0];
+ public static final ValDef[][] EMPTY_ARRAY_ARRAY = new ValDef[0][0];
+
+ private Symbol symbol;
+
+ public ExtValDef(int mods, Name name, Tree tpe, Tree rhs)
+ {
+ super(mods, name, tpe, rhs);
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+
+ public boolean definesSymbol() {
+ return true;
+ }
+ }
+
+ public static class ExtDefDef extends DefDef {
+ private Symbol symbol;
+
+ public ExtDefDef(int mods, Name name, TypeDef[] tparams,
+ ValDef[][] vparams, Tree tpe, Tree rhs)
+ {
+ super(mods, name, tparams, vparams, tpe, rhs);
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+
+ public boolean definesSymbol() {
+ return true;
+ }
+ }
+
+ public static class ExtTypeDef extends TypeDef {
+ private Symbol symbol;
+
+ public static final TypeDef[] EMPTY_ARRAY = new TypeDef[0];
+
+ public ExtTypeDef(int mods, Name name, TypeDef[] tparams, Tree rhs)
+ {
+ super(mods, name, tparams, rhs);
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+
+ public boolean definesSymbol() {
+ return true;
+ }
+ }
+
+ public static class ExtImport extends Import {
+ private Symbol symbol;
+
+ public ExtImport(Tree expr, Name[] selectors) {
+ super(expr, selectors);
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+ }
+
+ public static class ExtLabelDef extends LabelDef {
+ private Symbol symbol;
+
+ public ExtLabelDef(Tree[] params,Tree rhs) {
+ super(params,rhs);
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+
+ public boolean definesSymbol() {
+ return true;
+ }
+ }
+
+ public static class ExtSelect extends Select {
+ private Symbol symbol;
+
+ public ExtSelect(Tree qualifier, Name selector) {
+ super(qualifier, selector);
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+ }
+
+ public static class ExtSelectFromType extends SelectFromType {
+ private Symbol symbol;
+
+ public ExtSelectFromType(Tree qualifier, Name selector) {
+ super(qualifier, selector);
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+ }
+
+ public static class ExtIdent extends Ident {
+ private Symbol symbol;
+
+ public ExtIdent(Name name) {
+ super(name);
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+ }
+
+ public static class ExtTemplate extends Template {
+ private Symbol symbol;
+
+ public ExtTemplate(Tree[] parents, Tree[] body) {
+ super(parents, body);
+ }
+
+ public boolean hasSymbol() {
+ return true;
+ }
+
+ public Symbol symbol() {
+ return symbol;
+ }
+
+ public Tree setSymbol(Symbol symbol) {
+ this.symbol = symbol;
+ return this;
+ }
+
+ public boolean definesSymbol() {
+ return true;
+ }
+ }
+
+ public boolean isTerm() {
+ switch(this) {
+ case Bad():
+ case Empty:
+ case Tuple(_):
+ case If(_, _, _):
+ case Typed(_, _):
+ case Apply(_, _):
+ case TypeApply(_, _):
+ case Visitor(_):
+ case New(_):
+ case Literal(_):
+ case LabelDef(_,_):
+ case Block(_):
+ case Function(_, _):
+ case Assign(_, _):
+ case Super(_):
+ case This(_):
+ return true;
+ case Ident(Name name):
+ return !name.isTypeName();
+ case Select(_, Name name):
+ return !name.isTypeName();
+ default:
+ return false;
+ }
+ }
+
+ public boolean isType() {
+ switch(this) {
+ case Bad():
+ case Empty:
+ case SingletonType(_):
+ case SelectFromType(_, _):
+ case CompoundType(_, _):
+ case FunType(_, _):
+ case TupleType(_):
+ case AppliedType(_, _):
+ case CovariantType(_):
+ return true;
+ case Ident(Name name):
+ return name.isTypeName();
+ case Select(_, Name name):
+ return name.isTypeName();
+ default:
+ return false;
+ }
+ }
+}
+
diff --git a/sources/scalac/ast/TreeCopyFactory.java b/sources/scalac/ast/TreeCopyFactory.java
new file mode 100644
index 0000000000..5a9074c39f
--- /dev/null
+++ b/sources/scalac/ast/TreeCopyFactory.java
@@ -0,0 +1,165 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast;
+
+import scalac.util.Name;
+import Tree.*;
+
+/**
+ * Interface for a kind of factory which, for each node constructor,
+ * takes an original node from which some data will be copied or shared.
+ *
+ * @author Michel Schinz
+ * @version 1.1
+ */
+public interface TreeCopyFactory {
+
+ public void attribute(Tree newTree, Tree oldTree);
+
+ public Tree Bad(Tree tree);
+
+ public Tree ClassDef(Tree tree,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Template impl);
+
+ public Tree PackageDef(Tree tree,
+ Tree packaged,
+ Template impl);
+
+ public Tree ModuleDef(Tree tree,
+ int mods,
+ Name name,
+ Tree tpe,
+ Template impl);
+
+ public Tree ValDef(Tree tree,
+ int mods,
+ Name name,
+ Tree tpe,
+ Tree rhs);
+
+ public Tree PatDef(Tree tree,
+ int mods,
+ Tree pat,
+ Tree rhs);
+
+ public Tree DefDef(Tree tree,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Tree rhs);
+
+ public Tree TypeDef(Tree tree,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ Tree rhs);
+
+ public Tree Import(Tree tree,
+ Tree expr,
+ Name[] selectors);
+
+ public Tree CaseDef(Tree tree,
+ Tree pat,
+ Tree guard,
+ Tree body);
+
+ public Template Template(Tree tree,
+ Tree[] baseClasses,
+ Tree[] body);
+
+ public Tree LabelDef(Tree tree,
+ Tree[] params,
+ Tree rhs);
+
+ public Tree Block(Tree tree,
+ Tree[] stats);
+
+ public Tree Tuple(Tree tree,
+ Tree[] trees);
+
+ public Tree Visitor(Tree tree,
+ CaseDef[] cases);
+
+ public Tree Function(Tree tree,
+ ValDef[] vparams,
+ Tree body);
+
+ public Tree Assign(Tree tree,
+ Tree lhs,
+ Tree rhs);
+
+ public Tree If(Tree tree,
+ Tree cond,
+ Tree thenp,
+ Tree elsep);
+
+ public Tree New(Tree tree,
+ Template templ);
+
+ public Tree Typed(Tree tree,
+ Tree expr,
+ Tree tpe);
+
+ public Tree TypeApply(Tree tree,
+ Tree fun,
+ Tree[] args);
+
+ public Tree Apply(Tree tree,
+ Tree fun,
+ Tree[] args);
+
+ public Tree Super(Tree tree,
+ Tree tpe);
+
+ public Tree This(Tree tree,
+ Tree qualifier);
+
+ public Tree Select(Tree tree,
+ Tree qualifier,
+ Name selector);
+
+ public Tree Ident(Tree tree,
+ Name name);
+
+ public Tree Literal(Tree tree,
+ Object value);
+
+ public Tree SingletonType(Tree tree,
+ Tree ref);
+
+ public Tree SelectFromType(Tree tree,
+ Tree qualifier,
+ Name selector);
+
+ public Tree FunType(Tree tree,
+ Tree[] argtpes,
+ Tree restpe);
+
+ public Tree CompoundType(Tree tree,
+ Tree[] baseTypes,
+ Tree[] refinements);
+
+ public Tree TupleType(Tree tree,
+ Tree[] types);
+
+ public Tree AppliedType(Tree tree,
+ Tree tpe,
+ Tree[] args);
+
+ public Tree CovariantType(Tree tree,
+ Tree tpe);
+
+}
diff --git a/sources/scalac/ast/TreeCreator.java b/sources/scalac/ast/TreeCreator.java
new file mode 100644
index 0000000000..6cb8afa1d8
--- /dev/null
+++ b/sources/scalac/ast/TreeCreator.java
@@ -0,0 +1,293 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast;
+
+import Tree.*;
+import scalac.util.Name;
+
+
+public class TreeCreator implements TreeFactory {
+
+ public Tree Bad(int pos) {
+ Tree t = new ExtBad();
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree ClassDef(int pos,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Template impl) {
+ Tree t = new ExtClassDef(mods, name, tparams, vparams, tpe, impl);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree PackageDef(int pos,
+ Tree packaged,
+ Template impl) {
+ Tree t = new PackageDef(packaged, impl);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree ModuleDef(int pos,
+ int mods,
+ Name name,
+ Tree tpe,
+ Template body) {
+ Tree t = new ExtModuleDef(mods, name, tpe, body);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree ValDef(int pos,
+ int mods,
+ Name name,
+ Tree tpe,
+ Tree rhs) {
+ Tree t = new ExtValDef(mods, name, tpe, rhs);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree PatDef(int pos,
+ int mods,
+ Tree pat,
+ Tree rhs) {
+ Tree t = new PatDef(mods, pat, rhs);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree DefDef(int pos,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Tree rhs) {
+ Tree t = new ExtDefDef(mods, name, tparams, vparams, tpe, rhs);
+ t.pos = pos;
+ return t;
+ }
+
+
+ public Tree TypeDef(int pos,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ Tree rhs) {
+ Tree t = new ExtTypeDef(mods, name, tparams, rhs);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Import(int pos,
+ Tree expr,
+ Name[] selectors) {
+ Tree t = new ExtImport(expr, selectors);
+ t.pos = pos;
+ return t;
+ }
+
+ public CaseDef CaseDef(int pos,
+ Tree pat,
+ Tree guard,
+ Tree body) {
+ CaseDef t = new CaseDef(pat, guard, body);
+ t.pos = pos;
+ return t;
+ }
+
+ public Template Template(int pos,
+ Tree[] baseClasses,
+ Tree[] body) {
+ Template t = new ExtTemplate(baseClasses, body);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree LabelDef(int pos,
+ Tree[] params,
+ Tree body) {
+ Tree t = new ExtLabelDef(params,body);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Block(int pos,
+ Tree[] stats) {
+ Tree t = new Block(stats);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Tuple(int pos,
+ Tree[] trees) {
+ Tree t = new Tuple(trees);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Visitor(int pos,
+ CaseDef[] cases) {
+ Tree t = new Visitor(cases);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Function(int pos,
+ ValDef[] vparams,
+ Tree body) {
+ Tree t = new Function(vparams, body);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Assign(int pos,
+ Tree lhs,
+ Tree rhs) {
+ Tree t = new Assign(lhs, rhs);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree If(int pos,
+ Tree cond,
+ Tree thenp,
+ Tree elsep) {
+ Tree t = new If(cond, thenp, elsep);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree New(int pos,
+ Template templ) {
+ Tree t = new New(templ);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Typed(int pos,
+ Tree expr,
+ Tree tpe) {
+ Tree t = new Typed(expr, tpe);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree TypeApply(int pos,
+ Tree fun,
+ Tree[] tparams) {
+ Tree t = new TypeApply(fun, tparams);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Apply(int pos,
+ Tree fun,
+ Tree[] vparam) {
+ Tree t = new Apply(fun, vparam);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Super(int pos,
+ Tree tpe) {
+ Tree t = new Super(tpe);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree This(int pos,
+ Tree qualifier) {
+ Tree t = new This(qualifier);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Select(int pos,
+ Tree qualifier,
+ Name selector) {
+ Tree t = new ExtSelect(qualifier, selector);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Ident(int pos,
+ Name name) {
+ Tree t = new ExtIdent(name);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree Literal(int pos,
+ Object value) {
+ Tree t = new Literal(value);
+ t.pos = pos;
+ return t;
+ }
+
+
+ public Tree SingletonType(int pos, Tree ref) {
+ Tree t = new SingletonType(ref);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree SelectFromType(int pos,
+ Tree qualifier,
+ Name selector) {
+ Tree t = new ExtSelectFromType(qualifier, selector);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree FunType(int pos,
+ Tree[] argtpes,
+ Tree restpe) {
+ Tree t = new FunType(argtpes, restpe);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree CompoundType(int pos,
+ Tree[] mixins,
+ Tree[] fields) {
+ Tree t = new CompoundType(mixins, fields);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree TupleType(int pos,
+ Tree[] types) {
+ Tree t = new TupleType(types);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree AppliedType(int pos,
+ Tree tpe,
+ Tree[] args) {
+ Tree t = new AppliedType(tpe, args);
+ t.pos = pos;
+ return t;
+ }
+
+ public Tree CovariantType(int pos,
+ Tree tpe) {
+ Tree t = new CovariantType(tpe);
+ t.pos = pos;
+ return t;
+ }
+}
diff --git a/sources/scalac/ast/TreeFactory.java b/sources/scalac/ast/TreeFactory.java
new file mode 100644
index 0000000000..31ee67042e
--- /dev/null
+++ b/sources/scalac/ast/TreeFactory.java
@@ -0,0 +1,155 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast;
+
+import scalac.util.Name;
+import Tree.*;
+
+public interface TreeFactory {
+
+ public Tree Bad(int pos);
+
+ public Tree ClassDef(int pos,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Template impl);
+
+ public Tree PackageDef(int pos,
+ Tree packaged,
+ Template impl);
+
+ public Tree ModuleDef(int pos,
+ int mods,
+ Name name,
+ Tree tpe,
+ Template impl);
+
+ public Tree ValDef(int pos,
+ int mods,
+ Name name,
+ Tree tpe,
+ Tree rhs);
+
+ public Tree PatDef(int pos,
+ int mods,
+ Tree pat,
+ Tree rhs);
+
+ public Tree DefDef(int pos,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ ValDef[][] vparams,
+ Tree tpe,
+ Tree rhs);
+
+ public Tree TypeDef(int pos,
+ int mods,
+ Name name,
+ TypeDef[] tparams,
+ Tree rhs);
+
+ public Tree Import(int pos,
+ Tree expr,
+ Name[] selectors);
+
+ public CaseDef CaseDef(int pos,
+ Tree pat,
+ Tree guard,
+ Tree body);
+
+ public Template Template(int pos,
+ Tree[] baseClasses,
+ Tree[] body);
+
+ public Tree LabelDef(int pos,
+ Tree[] params,
+ Tree rhs);
+
+ public Tree Block(int pos,
+ Tree[] stats);
+
+ public Tree Tuple(int pos,
+ Tree[] trees);
+
+ public Tree Visitor(int pos,
+ CaseDef[] cases);
+
+ public Tree Function(int pos,
+ ValDef[] vparams,
+ Tree body);
+
+ public Tree Assign(int pos,
+ Tree lhs,
+ Tree rhs);
+
+ public Tree If(int pos,
+ Tree cond,
+ Tree thenp,
+ Tree elsep);
+
+ public Tree New(int pos,
+ Template templ);
+
+ public Tree Typed(int pos,
+ Tree expr,
+ Tree tpe);
+
+ public Tree TypeApply(int pos,
+ Tree fun,
+ Tree[] tparams);
+
+ public Tree Apply(int pos,
+ Tree fun,
+ Tree[] vparam);
+
+ public Tree Super(int pos,
+ Tree tpe);
+
+ public Tree This(int pos,
+ Tree qualifier);
+
+ public Tree Select(int pos,
+ Tree qualifier,
+ Name selector);
+
+ public Tree Ident(int pos,
+ Name name);
+
+ public Tree Literal(int pos,
+ Object value);
+
+ public Tree SingletonType(int pos,
+ Tree ref);
+
+ public Tree SelectFromType(int pos,
+ Tree qualifier,
+ Name selector);
+
+ public Tree FunType(int pos,
+ Tree[] argtpes,
+ Tree restpe);
+
+ public Tree CompoundType(int pos,
+ Tree[] baseTypes,
+ Tree[] refinements);
+
+ public Tree TupleType(int pos,
+ Tree[] types);
+
+ public Tree AppliedType(int pos,
+ Tree tpe,
+ Tree[] args);
+
+ public Tree CovariantType(int pos,
+ Tree tpe);
+}
diff --git a/sources/scalac/ast/TreeGen.java b/sources/scalac/ast/TreeGen.java
new file mode 100644
index 0000000000..26b02eb862
--- /dev/null
+++ b/sources/scalac/ast/TreeGen.java
@@ -0,0 +1,562 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast;
+
+import java.io.*;
+import java.util.*;
+import scalac.*;
+import scalac.symtab.*;
+import scalac.util.*;
+import Tree.*;
+
+/** A helper class for building trees
+ *
+ * @author Martin Odersky, Christine Roeckl
+ * @version 1.0
+ */
+public class TreeGen implements Kinds, Modifiers {
+
+ /********************************************************************************/
+ /********************************************************************************/
+ /** VARIABLES **/
+
+ /** the global environment
+ */
+ protected Global global;
+
+ /** the global definitions
+ */
+ protected Definitions definitions;
+
+ /** the tree factory
+ */
+ public TreeFactory make;
+
+ /************************************************************************/
+ /************************************************************************/
+ /** CONSTRUCTORS **/
+
+ public TreeGen(Global global, TreeFactory make) {
+ this.global = global;
+ this.definitions = global.definitions;
+ this.make = make;
+ }
+
+ public TreeGen(Global global) {
+ this(global, global.make);
+ }
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /** METHODS **/
+
+ /** Create a dummy symbol to be used for templates.
+ */
+ public Symbol localDummy(int pos, Symbol owner) {
+ return new TermSymbol(pos, Name.EMPTY, owner, 0)
+ .setInfo(Type.NoType);
+ }
+
+ public Tree mkRef(int pos, Type pre, Symbol sym) {
+ if (pre == Type.localThisType || pre.symbol().isRoot())
+ return Ident(pos, sym);
+ else
+ return Select(pos, mkStableId(pos, pre), sym);
+ }
+
+ /** Build and attribute stable identifier tree corresponding to given prefix.
+ */
+ public Tree mkStableId(int pos, Type pre) {
+ switch (pre.expandModuleThis()) {
+ case ThisType(Symbol sym):
+ return make.This(pos, Ident(pos, sym)).setType(pre);
+ case SingleType(Type pre1, Symbol sym):
+ return mkRef(pos, pre1, sym);
+ default:
+ throw new ApplicationError();
+ }
+ }
+
+ /** Build and attribute tree corresponding to given type.
+ */
+ public Tree mkType(int pos, Type type) {
+ Tree tree = mkTycon(pos, type);
+ switch (type) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ if (args.length != 0)
+ return make.AppliedType(pos, tree, mkType(pos, args))
+ .setType(type);
+ }
+ return tree;
+ }
+
+ /** Build and attribute tree corresponding to given type constructor.
+ */
+ public Tree mkTycon(int pos, Type type) {
+ //System.out.println("making type " + type);//DEBUG
+ switch (type) {
+
+ case NoType:
+ return Tree.Empty;
+
+ case ErrorType:
+ case AnyType:
+ return make.Bad(pos).setSymbol(Symbol.ERROR).setType(type);
+
+ case ThisType(_):
+ case SingleType(_, _):
+ return make.SingletonType(pos, mkStableId(pos, type)).setType(type);
+
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ return mkRef(pos, pre, sym);
+
+ case CompoundType(Type[] parents, Scope members):
+ if (parents.length == 1 && members.elems == Scope.Entry.NONE)
+ return mkType(pos, parents[0]);
+ else
+ return make.CompoundType(
+ pos, mkType(pos, parents), mkDefs(pos, members.elements()))
+ .setType(type);
+
+ case CovarType(Type tp):
+ return make.CovariantType(pos, mkType(pos, tp))
+ .setType(type);
+
+ case UnboxedType(_):
+ case UnboxedArrayType(_):
+ return make.Ident(pos, Name.fromString(type.toString()).toTypeName())
+ .setType(type);
+
+ default:
+ throw new ApplicationError("illegal type", type);
+ }
+ }
+
+ /** Build and attribute tree array corresponding to given type array.
+ */
+ public Tree[] mkType(int pos, Type[] types) {
+ Tree[] res = new Tree[types.length];
+ for (int i = 0; i < types.length; i++) {
+ res[i] = mkType(pos, types[i]);
+ }
+ return res;
+ }
+
+ /** Build and attribute tree corresponding to symbol's declaration.
+ */
+ public Tree mkDef(int pos, Symbol sym) {
+ switch (sym.kind) {
+ case ERROR:
+ return make.Bad(pos).setSymbol(Symbol.ERROR).setType(Type.ErrorType);
+ case TYPE: case ALIAS:
+ return TypeDef(pos, sym);
+ case VAL:
+ if (sym.isMethod()) return DefDef(pos, sym, Tree.Empty);
+ else return Param(pos, sym);
+ default:
+ throw new ApplicationError();
+ }
+ }
+
+ /** Build and attribute tree array corresponding to given symbol's declarations.
+ */
+ public Tree[] mkDefs(int pos, Symbol[] syms) {
+ Tree[] res = new Tree[syms.length];
+ for (int i = 0; i < syms.length; i++) {
+ res[i] = mkDef(pos, syms[i]);
+ }
+ return res;
+ }
+
+ /** Build a tree to be used as a base class constructor for a template.
+ */
+ public Tree mkParentConstr(int pos, Type parentType, Type root) {
+ switch (parentType) {
+ case TypeRef(Type pre, Symbol sym, Type[] args):
+ Tree ref = mkRef(pos, pre, sym.constructor());
+ Tree constr = (args.length == 0) ? ref
+ : TypeApply(ref, mkType(sym.pos, args));
+ switch (parentType) {
+ case MethodType(Symbol[] params, Type restpe):
+ assert params.length == 0 : parentType;
+ return Apply(constr, Tree.EMPTY_ARRAY);
+ default:
+ return constr;
+ }
+ default:
+ throw global.fail("invalid parent type", parentType);
+ }
+ }
+
+ /** Build an array of trees to be used as base classes for a template.
+ */
+ public Tree[] mkParentConstrs(int pos, Type[] parents, Type root) {
+ Tree[] constrs = new Tree[parents.length];
+ for (int i = 0; i < parents.length; ++i)
+ constrs[i] = mkParentConstr(pos, parents[i], root);
+ return constrs;
+ }
+
+ /** Build parameter sections corresponding to type.
+ */
+ public ValDef[][] mkParams(int pos, Type type) {
+ switch (type) {
+ case PolyType(Symbol[] tparams, Type restype):
+ return mkParams(pos, restype);
+ case MethodType(Symbol[] vparams, Type restype):
+ ValDef[] params1 = mkParams(pos, vparams);
+ ValDef[][] paramss = mkParams(pos, restype);
+ if (paramss.length == 0) {
+ return new ValDef[][]{params1};
+ } else {
+ ValDef[][] paramss1 = new ValDef[paramss.length + 1][];
+ paramss1[0] = params1;
+ System.arraycopy(paramss, 0, paramss1, 1, paramss.length);
+ return paramss1;
+ }
+ default:
+ return new ValDef[][]{};
+ }
+ }
+
+ /** Build parameter section corresponding to given array of symbols .
+ */
+ public ValDef[] mkParams(int pos, Symbol[] symbols) {
+ ValDef[] res = new ValDef[symbols.length];
+ for (int i = 0; i < symbols.length; i++) {
+ res[i] = Param(pos, symbols[i]);
+ }
+ return res;
+ }
+
+ /** Build type parameter section corresponding to given array of symbols .
+ */
+ public TypeDef[] mkTypeParams(int pos, Symbol[] symbols) {
+ TypeDef[] res = new TypeDef[symbols.length];
+ for (int i = 0; i < symbols.length; i++) {
+ res[i] = (TypeDef)TypeDef(pos, symbols[i]);
+ }
+ return res;
+ }
+
+ /** Build type definition corresponding to given symbol .
+ */
+ public TypeDef TypeDef(int pos, Symbol sym) {
+ Global.instance.nextPhase();
+ Type symtype = sym.info();
+ Global.instance.prevPhase();
+ return (TypeDef) make.TypeDef(
+ pos,
+ sym.flags & SOURCEFLAGS,
+ sym.name,
+ mkTypeParams(pos, sym.typeParams()),
+ mkType(pos, symtype))
+ .setSymbol(sym).setType(definitions.UNIT_TYPE);
+ }
+
+ public Tree TypeDef(Symbol sym) {
+ return TypeDef(sym.pos, sym);
+ }
+
+ /** Build parameter
+ */
+ public ValDef Param(int pos, Symbol sym) {
+ return (ValDef)ValDef(pos, sym, Tree.Empty);
+ }
+
+ public ValDef Param(Symbol sym) {
+ return Param(sym.pos, sym);
+ }
+
+ /** Build and attribute block with given statements, starting
+ * at given position. The type is the type of the last
+ * statement in the block.
+ */
+ public Tree Block(int pos, Tree[] stats) {
+ Type tp = (stats.length == 0) ? definitions.UNIT_TYPE
+ : stats[stats.length - 1].type;
+ return make.Block(pos, stats).setType(tp);
+ }
+
+ /** Build and attribute non-empty block with given statements.
+ */
+ public Tree Block(Tree[] stats) {
+ return Block(stats[0].pos, stats);
+ }
+
+ public Tree Typed(Tree tree, Type tp) {
+ return make.Typed(tree.pos, tree, mkType(tree.pos, tp)).setType(tp);
+ }
+
+ /** Build and attribute the assignment lhs = rhs
+ */
+ public Tree Assign(int pos, Tree lhs, Tree rhs) {
+ return make.Assign(pos, lhs, rhs).setType(definitions.UNIT_TYPE);
+ }
+
+ public Tree Assign(Tree lhs, Tree rhs) {
+ return Assign(lhs.pos, lhs, rhs);
+ }
+
+ /** Build and attribute new B, given constructor expression B.
+ */
+ public Tree New(Tree constr) {
+ Template templ = make.Template(
+ constr.pos, new Tree[]{constr}, Tree.EMPTY_ARRAY);
+ templ.setType(constr.type);
+ templ.setSymbol(localDummy(constr.pos, Symbol.NONE));
+ return make.New(constr.pos, templ).setType(constr.type); }
+
+ /** Build an allocation new P.C[TARGS](ARGS)
+ * given a (singleton) type P, class C, type arguments TARGS and arguments ARGS
+ */
+ public Tree New(int pos, Type pre, Symbol clazz,
+ Type[] targs, Tree[] args) {
+ Tree constr = mkRef(pos, pre, clazz.constructor());
+ if (targs.length != 0) constr = TypeApply(constr, mkType(pos, targs));
+ Tree base = Apply(constr, args);
+ return New(base);
+ }
+
+ /** Build a monomorphic allocation new P.C(ARGS)
+ * given a prefix P, class C and arguments ARGS
+ */
+ public Tree New(int pos, Type pre, Symbol clazz, Tree[] args) {
+ return New(pos, pre, clazz, Type.EMPTY_ARRAY, args);
+ }
+
+ /** Build and attribute application node with given function
+ * and argument trees.
+ */
+ public Tree Apply(int pos, Tree fn, Tree[] args) {
+ switch (fn.type) {
+ case Type.MethodType(Symbol[] vparams, Type restpe):
+ return make.Apply(pos, fn, args).setType(restpe);
+ default:
+ throw new ApplicationError("method type required", fn.type);
+ }
+ }
+
+ public Tree Apply(Tree fn, Tree[] args) {
+ return Apply(fn.pos, fn, args);
+ }
+
+ /** Build and attribute type application node with given function
+ * and argument trees.
+ */
+ public Tree TypeApply(int pos, Tree fn, Tree[] args) {
+ switch (fn.type) {
+ case Type.PolyType(Symbol[] tparams, Type restpe):
+ return make.TypeApply(pos, fn, args)
+ .setType(restpe.subst(tparams, Tree.typeOf(args)));
+ default:
+ throw new ApplicationError("poly type required", fn.type);
+ }
+ }
+
+ public Tree TypeApply(Tree fn, Tree[] args) {
+ return TypeApply(fn.pos, fn, args);
+ }
+
+ /** Build and applied type node with given function
+ * and argument trees.
+ */
+ public Tree AppliedType(int pos, Tree fn, Tree[] args) {
+ return make.AppliedType(pos, fn, args)
+ .setType(Type.appliedType(fn.type, Tree.typeOf(args)));
+ }
+
+ public Tree AppliedType(Tree fn, Tree[] args) {
+ return AppliedType(fn.pos, fn, args);
+ }
+
+ /** Build and attribute select node of given symbol.
+ * It is assumed that the prefix is not empty.
+ */
+ public Tree Select(int pos, Tree qual, Symbol sym) {
+ assert sym.kind != NONE;
+ Global.instance.nextPhase();
+ Type symtype = qual.type.memberType(sym);
+ Global.instance.prevPhase();
+ if (sym.kind == VAL && qual.type.isStable() && symtype.isObjectType())
+ symtype = Type.singleType(qual.type, sym);
+ return make.Select(pos, qual, sym.name)
+ .setSymbol(sym).setType(symtype);
+ }
+
+ public Tree Select(Tree qual, Symbol sym) {
+ return Select(qual.pos, qual, sym);
+ }
+
+ public Tree Select(Tree qual, Name name) {
+ Symbol sym = qual.type.lookup(name);
+ assert (sym.kind != NONE && sym != Symbol.ERROR) : name + " from " + qual.type;
+ return Select(qual, sym);
+ }
+
+ /** Build and attribute ident node with given symbol.
+ */
+ public Tree Ident(int pos, Symbol sym) {
+ Global.instance.nextPhase();
+ Type symtype = sym.type();
+ Global.instance.prevPhase();
+ if (sym.kind == VAL && symtype.isObjectType())
+ symtype = Type.singleType(sym.owner().thisType(), sym);
+ return make.Ident(pos, sym.name)
+ .setSymbol(sym).setType(symtype);
+ }
+
+ public Tree Ident(Symbol sym) {
+ return Ident(sym.pos, sym);
+ }
+
+ /** Build and attribute this node with given symbol.
+ */
+ public Tree This(int pos, Symbol sym) {
+ return make.This(pos, Ident(pos, sym)).setType(sym.thisType());
+ }
+
+ /** Build and attribute super node with given type.
+ */
+ public Tree Super(int pos, Type type) {
+ return make.Super(pos, mkType(pos, type)).setType(type);
+ }
+
+ /** Build and attribute value/variable/let definition node whose signature
+ * corresponds to given symbol and which has given rhs.
+ */
+ public Tree ValDef(int pos, Symbol sym, Tree rhs) {
+ Global.instance.nextPhase();
+ Type symtype = sym.type();
+ Global.instance.prevPhase();
+ return make.ValDef(pos,
+ sym.flags & SOURCEFLAGS,
+ sym.name,
+ mkType(pos, symtype),
+ rhs)
+ .setSymbol(sym).setType(definitions.UNIT_TYPE);
+ }
+
+ public Tree ValDef(Symbol sym, Tree rhs) {
+ return ValDef(sym.pos, sym, rhs);
+ }
+
+ /** Build and attribute value/variable/let definition node whose signature
+ * corresponds to given symbol and which has given body.
+ */
+ public Tree DefDef(int pos, Symbol sym, Tree body) {
+ Global.instance.nextPhase();
+ Type symtype = sym.type();
+ Global.instance.prevPhase();
+ return make.DefDef(pos,
+ sym.flags & SOURCEFLAGS,
+ sym.name,
+ mkTypeParams(pos, symtype.typeParams()),
+ mkParams(pos, symtype),
+ mkType(pos, symtype.resultType()),
+ body)
+ .setSymbol(sym).setType(definitions.UNIT_TYPE);
+ }
+
+ public Tree DefDef(Symbol sym, Tree rhs) {
+ return DefDef(sym.pos, sym, rhs);
+ }
+
+ /** Generate class definition from class symbol, parent constructors, and body.
+ */
+ public Tree ClassDef(int pos, Symbol clazz, Tree[] constrs, Tree[] body) {
+ Global.instance.nextPhase();
+ Type clazzinfo = clazz.info();
+ Type constrtype = clazz.constructor().info();
+ Global.instance.prevPhase();
+ switch (clazzinfo) {
+ case CompoundType(Type[] parents, Scope members):
+ Template templ = make.Template(pos, constrs, body);
+ templ.setType(clazzinfo);
+ templ.setSymbol(localDummy(pos, clazz.owner()));
+ return make.ClassDef(
+ pos,
+ clazz.flags & SOURCEFLAGS,
+ clazz.name,
+ mkTypeParams(pos, constrtype.typeParams()),
+ mkParams(pos, constrtype),
+ Tree.Empty,
+ templ)
+ .setSymbol(clazz).setType(definitions.UNIT_TYPE);
+ default:
+ throw new ApplicationError();
+ }
+ }
+
+ public Tree ClassDef(Symbol clazz, Tree[] constrs, Tree[] body) {
+ return ClassDef(clazz.pos, clazz, constrs, body);
+ }
+
+ /** Generate class definition from class symbol and body.
+ * All parents must by parameterless, or take unit parameters.
+ */
+ public Tree ClassDef(int pos, Symbol clazz, Tree[] body) {
+ Global.instance.nextPhase();
+ Type clazzinfo = clazz.info();
+ Global.instance.prevPhase();
+ return ClassDef(pos,
+ clazz,
+ mkParentConstrs(pos, clazzinfo.parents(), clazzinfo),
+ body);
+ }
+
+ public Tree ClassDef(Symbol clazz, Tree[] body) {
+ return ClassDef(clazz.pos, clazz, body);
+ }
+
+ /** Build the expansion of (() => expr)
+ * This is:
+ * { class $clazz() extends scala.Function0 { def apply() = expr } ; new $clazz() }
+ */
+ public Tree mkUnitFunction(Tree expr, Type tp, Symbol owner) {
+ int pos = expr.pos;
+ Type f0t = definitions.functionType(Type.EMPTY_ARRAY, tp);
+
+ ClassSymbol clazz = new ClassSymbol(
+ pos, Names.ANON_CLASS_NAME.toTypeName(), owner, 0);
+ clazz.setInfo(Type.compoundType(new Type[]{f0t}, new Scope(), clazz));
+ clazz.constructor().setInfo(
+ Type.MethodType(
+ Symbol.EMPTY_ARRAY,
+ Type.TypeRef(owner.thisType(), clazz, Type.EMPTY_ARRAY)));
+
+ Symbol applyMeth = new TermSymbol(pos, Names.apply, clazz, FINAL)
+ .setInfo(Type.MethodType(Symbol.EMPTY_ARRAY, tp));
+ clazz.info().members().enter(applyMeth);
+
+ Tree applyDef = DefDef(applyMeth, changeOwner(expr, owner, applyMeth));
+ Tree classDef = ClassDef(clazz, new Tree[]{applyDef});
+ Tree alloc = New(pos, Type.localThisType, clazz, Tree.EMPTY_ARRAY);
+ return Block(new Tree[]{classDef, alloc});
+ }
+
+ /** Change owner of all defined symbols from `prevOwner' to `newOwner'
+ */
+ public Tree changeOwner(Tree tree, final Symbol prevOwner, final Symbol newOwner) {
+ Transformer lifter = new Transformer(global, global.currentPhase) {
+ public Tree transform(Tree tree) {
+ if (TreeInfo.isDefinition(tree)) {
+ Symbol sym = tree.symbol();
+ if (sym != null && sym.owner() == prevOwner) {
+ sym.setOwner(newOwner);
+ if (sym.kind == Kinds.CLASS)
+ sym.constructor().setOwner(newOwner);
+ }
+ }
+ return super.transform(tree);
+ }
+ };
+ return lifter.transform(tree);
+ }
+}
diff --git a/sources/scalac/ast/TreeInfo.java b/sources/scalac/ast/TreeInfo.java
new file mode 100644
index 0000000000..81d9481f31
--- /dev/null
+++ b/sources/scalac/ast/TreeInfo.java
@@ -0,0 +1,136 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast;
+
+import scalac.ApplicationError;
+import scalac.util.Name;
+import scalac.symtab.Type;
+import scalac.symtab.Symbol;
+import scalac.symtab.Modifiers;
+
+public class TreeInfo {
+
+ public static boolean isTerm(Tree tree) {
+ return tree.isTerm();
+ }
+
+ public static boolean isType(Tree tree) {
+ return tree.isType();
+ }
+
+ public static boolean isOwnerDefinition(Tree tree) {
+ switch (tree) {
+ case PackageDef(_, _):
+ case ClassDef(_, _, _, _, _, _):
+ case ModuleDef(_, _, _, _):
+ case DefDef(_, _, _, _, _, _):
+ case Import(_, _):
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public static boolean isDefinition(Tree tree) {
+ switch (tree) {
+ case PackageDef(_, _):
+ case ClassDef(_, _, _, _, _, _):
+ case ModuleDef(_, _, _, _):
+ case DefDef(_, _, _, _, _, _):
+ case ValDef(_, _, _, _):
+ case TypeDef(_, _, _, _):
+ case Import(_, _):
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public static boolean isDeclaration(Tree tree) {
+ switch (tree) {
+ case DefDef(_, _, _, _, _, Tree rhs):
+ return rhs == Tree.Empty;
+ case ValDef(_, _, _, Tree rhs):
+ return rhs == Tree.Empty;
+ case TypeDef(_, _, _, _):
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** Is tree a pure definition?
+ */
+ public static boolean isPureDef(Tree tree) {
+ switch (tree) {
+ case ClassDef(_, _, _, _, _, _):
+ case ModuleDef(_, _, _, _):
+ case DefDef(_, _, _, _, _, _):
+ case TypeDef(_, _, _, _):
+ case Import(_, _):
+ return true;
+ case ValDef(int mods, _, _, Tree rhs):
+ return (mods & Modifiers.MUTABLE) == 0 && isPureExpr(rhs);
+ default:
+ return false;
+ }
+ }
+
+ /** Is tree a stable & pure expression?
+ */
+ public static boolean isPureExpr(Tree tree) {
+ switch (tree) {
+ case Empty:
+ case This(_):
+ case Super(_):
+ return true;
+ case Ident(_):
+ return tree.type.isStable();
+ case Select(Tree qual, _):
+ return tree.type.isStable() && isPureExpr(qual);
+ case Typed(Tree expr, _):
+ return isPureExpr(expr);
+ case Literal(_):
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /** Is tree a pure constructor?
+ * //todo: update
+ */
+ public static boolean isPureConstr(Tree tree) {
+ switch (tree) {
+ case Ident(_):
+ return tree.symbol() != null && tree.symbol().isPrimaryConstructor();
+ case Select(Tree qual, _):
+ return isPureExpr(qual) &&
+ tree.symbol() != null && tree.symbol().isPrimaryConstructor();
+ case TypeApply(Tree constr, _):
+ return isPureConstr(constr);
+ default:
+ return false;
+ }
+ }
+
+ /** The method symbol of an application node, or Symbol.NONE, if none exists.
+ */
+ public static Symbol methSymbol(Tree tree) {
+ switch (tree) {
+ case Apply(Tree fn, _):
+ return methSymbol(fn);
+ case TypeApply(Tree fn, _):
+ return methSymbol(fn);
+ default:
+ if (tree.hasSymbol()) return tree.symbol();
+ else return Symbol.NONE;
+ }
+ }
+}
diff --git a/sources/scalac/ast/TreeList.java b/sources/scalac/ast/TreeList.java
new file mode 100644
index 0000000000..d35627c686
--- /dev/null
+++ b/sources/scalac/ast/TreeList.java
@@ -0,0 +1,71 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id
+\* */
+
+package scalac.ast;
+
+
+public final class TreeList {
+ Tree[] trees;
+ int len;
+
+ public TreeList(Tree[] ts) {
+ trees = ts;
+ len = ts.length;
+ }
+
+ public TreeList() {
+ this(new Tree[4]);
+ len = 0;
+ }
+
+ public void append(Tree tree) {
+ if (len == trees.length) {
+ Tree[] ts = new Tree[len * 2];
+ System.arraycopy(trees, 0, ts, 0, len);
+ trees = ts;
+ }
+ trees[len++] = tree;
+ }
+
+ public void append(Tree[] ts) {
+ for (int j = 0; j < ts.length; j++)
+ append(ts[j]);
+ }
+
+ public void append(TreeList tl) {
+ for (int j = 0; j < tl.len; j++)
+ append(tl.trees[j]);
+ }
+
+ public int length() {
+ return len;
+ }
+
+ public Tree get(int i) {
+ return trees[i];
+ }
+
+ public Tree first() {
+ return trees[0];
+ }
+
+ public Tree removeLast() {
+ return trees[--len];
+ }
+
+ public Tree[] toArray() {
+ Tree[] ts = new Tree[len];
+ System.arraycopy(trees, 0, ts, 0, len);
+ return ts;
+ }
+
+ public Tree[] copyTo(Tree[] ts) {
+ System.arraycopy(trees, 0, ts, 0, len);
+ return ts;
+ }
+}
diff --git a/sources/scalac/ast/parser/Parser.java b/sources/scalac/ast/parser/Parser.java
new file mode 100644
index 0000000000..cd491e2af9
--- /dev/null
+++ b/sources/scalac/ast/parser/Parser.java
@@ -0,0 +1,1704 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast.parser;
+
+import java.util.*;
+import scalac.*;
+import scalac.util.*;
+import scalac.symtab.Modifiers;
+import scalac.ast.*;
+import Tree.*;
+
+/** A recursive descent parser for the programming language Scala.
+ *
+ * @author Martin Odersky, Matthias Zenger
+ * @version 1.2
+ */
+public class Parser implements Tokens {
+
+ /** the lexical analyzer
+ */
+ Scanner s;
+
+ /** the tree factory
+ */
+ TreeFactory make;
+
+ public Parser(Unit unit) {
+ s = new Scanner(unit);
+ make = unit.global.make;
+ }
+
+ /** this is the general parse method
+ */
+ public Tree[] parse() {
+ Tree[] ts = compilationUnit();
+ accept(EOF);
+ return ts;
+ }
+
+/////// ERROR HANDLING //////////////////////////////////////////////////////
+
+ private void skip() {
+ //System.out.println("<skipping> " + s.token2string(s.token));//DEBUG
+ int nparens = 0;
+ int nbraces = 0;
+ while (true) {
+ switch (s.token) {
+ case EOF:
+ return;
+ case SEMI:
+ if (nparens == 0 && nbraces == 0)
+ return;
+ break;
+ case RPAREN:
+ nparens--;
+ break;
+ case RBRACE:
+ if (nbraces == 0)
+ return;
+ nbraces--;
+ break;
+ case LPAREN:
+ nparens++;
+ break;
+ case LBRACE:
+ nbraces++;
+ break;
+ }
+ //System.out.println("skipped: " + s.token2string(s.token));//DEBUG
+ s.nextToken();
+ }
+ }
+
+ Tree syntaxError(String msg, boolean skip) {
+ return syntaxError(s.pos, msg, skip);
+ }
+
+ Tree syntaxError(int pos, String msg, boolean skip) {
+ if (pos != s.errpos) {
+ s.unit.error(pos, msg);
+ s.errpos = pos;
+ }
+ if (skip) skip();
+ return make.Bad(pos);
+ }
+
+ int accept(int token) {
+ int pos = s.pos;
+ if (s.token != token) {
+ int errpos = ((s.pos >>> Position.LINESHIFT) >
+ (s.lastpos >>> Position.LINESHIFT)) ?
+ s.lastpos : s.pos;
+ syntaxError(errpos, s.token2string(token) + " expected but " +
+ s.token2string(s.token) + " found.", true);
+ }
+ if (s.token == token) s.nextToken();
+ return pos;
+ }
+
+/////// TOKEN CLASSES //////////////////////////////////////////////////////
+
+ boolean isModifier() {
+ return (s.token == ABSTRACT)
+ || (s.token == FINAL)
+ || (s.token == PRIVATE)
+ || (s.token == PROTECTED)
+// || (s.token == QUALIFIED)
+ || (s.token == OVERRIDE);
+ }
+
+ boolean isLocalClassModifier() {
+ return (s.token == ABSTRACT)
+ || (s.token == FINAL);
+ }
+
+ boolean isDefIntro() {
+ switch (s.token) {
+ case VAL: case VAR: case DEF: case CONSTR: case TYPE:
+ case MODULE: case CLASS: case CASECLASS: case TRAIT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ boolean isDclIntro() {
+ switch (s.token) {
+ case VAL: case VAR: case DEF: case CONSTR: case TYPE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ boolean isExprIntro() {
+ switch (s.token) {
+ case CHARLIT: case INTLIT: case LONGLIT:
+ case FLOATLIT: case DOUBLELIT: case STRINGLIT: case NULL:
+ case IDENTIFIER: case THIS: case SUPER:
+ case IF: case FOR: case NEW: case USCORE:
+ case LPAREN: case LBRACKET: case LBRACE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+/////// TREE CONSTRUCTION ////////////////////////////////////////////////////
+
+ /** Name supply
+ */
+ int fresh = 0;
+
+ Name fresh() {
+ return Name.fromString("x$" + (fresh++));
+ }
+
+ /** Create tree representing binary operation expression or pattern.
+ */
+ Tree makeBinop(boolean isExpr, int pos, Tree left, Name op, Tree right) {
+ if (isExpr) {
+ if (op.leftAssoc()) {
+ return make.Apply(pos,
+ make.Select(pos, left, NameTransformer.encode(op)),
+ new Tree[]{right});
+ } else {
+ Name x = fresh();
+ return make.Block(pos,
+ new Tree[]{
+ make.ValDef(pos, 0, x, Tree.Empty, left),
+ make.Apply(pos,
+ make.Select(pos, right, NameTransformer.encode(op)),
+ new Tree[]{make.Ident(left.pos, x)})});
+ }
+ } else {
+ return make.Apply(pos,
+ make.Ident(pos, NameTransformer.encode(op).toTypeName()),
+ new Tree[]{left, right});
+ }
+ }
+
+ /** Create tree representing type scala.Any
+ */
+ Tree scalaAnyType(int pos) {
+ return make.Select(pos, make.Ident(pos, Names.scala), Names.Any.toTypeName());
+ }
+
+ /** Create tree representing constructor scala.Object
+ */
+ Tree scalaObjectConstr(int pos) {
+ return make.Select(pos, make.Ident(pos, Names.scala), Names.Object.toConstrName());
+ }
+
+ /** 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.
+ */
+ Tree makeFor(Tree[] enums, Name mapName, Name flatmapName, Tree body) {
+ switch (enums[0]) {
+ case PatDef(int mods, Tree pat, Tree rhs):
+ if (enums.length == 1)
+ return makeFor1(enums[0].pos, mapName, pat, rhs, body);
+ Tree[] newenums = new Tree[enums.length - 1];
+ switch (enums[1]) {
+ case PatDef(int mods2, Tree pat2, Tree rhs2):
+ System.arraycopy(enums, 1, newenums, 0, newenums.length);
+ return makeFor1(enums[0].pos, flatmapName, pat, rhs,
+ makeFor(newenums, mapName, flatmapName, body));
+ default:
+ System.arraycopy(enums, 2, newenums, 1, newenums.length - 1);
+ newenums[0] = make.PatDef(
+ enums[0].pos, mods, pat,
+ makeFor1(enums[0].pos, Names.filter, pat, rhs, enums[1]));
+ return makeFor(newenums, mapName, flatmapName, body);
+ }
+ default:
+ throw new ApplicationError();
+ }
+ }
+
+ //where
+ Tree makeFor1(int pos, Name name, Tree pat, Tree rhs, Tree body) {
+ Tree cont;
+ switch (pat) {
+ case Ident(Name name1):
+ cont = make.Function(pos,
+ new Tree.ValDef[]{
+ (ValDef)
+ make.ValDef(pat.pos, Modifiers.PARAM, name1, Tree.Empty, Tree.Empty)},
+ body);
+ break;
+ default:
+ cont = make.Visitor(pos, new Tree.CaseDef[]{
+ (CaseDef)make.CaseDef(pos, pat, Tree.Empty, body)});
+ }
+ return make.Apply(pos, make.Select(pos, rhs, name), new Tree[]{cont});
+ }
+
+ /** Convert tree to formal parameter list
+ */
+ ValDef[] convertToParams(Tree t) {
+ switch (t) {
+ case Function(ValDef[] params, Tree.Empty):
+ return params;
+ case Ident(_):
+ case Typed(Ident(_), _):
+ return new ValDef[]{convertToParam(t)};
+ case Block(Tree[] stats):
+ if (stats.length == 0) return Tree.ExtValDef.EMPTY_ARRAY;
+ }
+ syntaxError(t.pos, "malformed formal parameter list", false);
+ return Tree.ExtValDef.EMPTY_ARRAY;
+ }
+
+ /** Convert list of trees to formal parameter list
+ */
+ ValDef[] convertToParams(Tree[] ts) {
+ ValDef[] res = new ValDef[ts.length];
+ for (int i = 0; i < res.length; i++)
+ res[i] = convertToParam(ts[i]);
+ return res;
+ }
+
+ /** Convert tree to formal parameter
+ */
+ ValDef convertToParam(Tree tree) {
+ switch (tree) {
+ case Ident(Name name):
+ return (ValDef)make.ValDef(
+ tree.pos, Modifiers.PARAM, name, Tree.Empty, Tree.Empty);
+ case Typed(Ident(Name name), Tree tpe):
+ return (ValDef)make.ValDef(
+ tree.pos, Modifiers.PARAM, name, tpe, Tree.Empty);
+ default:
+ Tree tpe = syntaxError(tree.pos, "not a legal formal parameter", false);
+ return (ValDef)make.ValDef(
+ tree.pos, Modifiers.PARAM, Names.ERROR, tpe, Tree.Empty);
+ }
+ }
+
+ /** Convert (qual)ident to type identifier
+ */
+ Tree convertToTypeId(Tree t) {
+ switch (t) {
+ case Ident(Name name):
+ return make.Ident(t.pos, name.toTypeName());
+ case Select(Tree qual, Name name):
+ return make.Select(t.pos, qual, name.toTypeName());
+ default:
+ return t;
+ }
+ }
+
+ /** Convert (qual)ident to constructor identifier
+ */
+ Tree convertToConstr(Tree t) {
+ switch (t) {
+ case Apply(Tree fn, Tree[] args):
+ return make.Apply(t.pos, convertToConstr(fn), args);
+ case TypeApply(Tree fn, Tree[] args):
+ return make.TypeApply(t.pos, convertToConstr(fn), args);
+ case Ident(Name name):
+ return make.Ident(t.pos, name.toConstrName());
+ case Select(Tree qual, Name name):
+ return make.Select(t.pos, qual, name.toConstrName());
+ default:
+ return syntaxError(t.pos, "class constructor expected", false);
+ }
+ }
+
+/////// OPERAND/OPERATOR STACK /////////////////////////////////////////////////
+
+ Tree[] operands = new Tree[8];
+ int[] positions = new int[8];
+ Name[] operators = new Name[8];
+ int sp = 0;
+
+ void push(Tree od, int pos, Name op) {
+ if (sp == operands.length) {
+ Tree[] operands1 = new Tree[sp * 2];
+ System.arraycopy(operands, 0, operands1, 0, sp);
+ operands = operands1;
+ int[] positions1 = new int[sp * 2];
+ System.arraycopy(positions, 0, positions1, 0, sp);
+ positions = positions1;
+ Name[] operators1 = new Name[sp * 2];
+ System.arraycopy(operators, 0, operators1, 0, sp);
+ operators = operators1;
+ }
+ operands[sp] = od;
+ positions[sp] = pos;
+ operators[sp] = op;
+ sp++;
+ }
+
+ Tree reduceStack(boolean isExpr, int base, Tree top,
+ int prec, boolean leftAssoc) {
+ if (sp != base &&
+ operators[sp-1].precedence() == prec &&
+ operators[sp-1].leftAssoc() != leftAssoc) {
+ syntaxError(
+ positions[sp-1],
+ "left- and right-associative operators with same precedence may not be mixed",
+ false);
+ }
+ while (sp != base &&
+ (prec < operators[sp-1].precedence() ||
+ (leftAssoc && prec == operators[sp-1].precedence()))) {
+ sp--;
+ top = makeBinop(isExpr, positions[sp], operands[sp], operators[sp], top);
+ }
+ return top;
+ }
+
+/////// IDENTIFIERS AND LITERALS ////////////////////////////////////////////////////////////
+
+ static final Name MINUS = Name.fromString("-");
+ static final Name PLUS = Name.fromString("+");
+ static final Name BANG = Name.fromString("!");
+ static final Name TILDE = Name.fromString("~");
+
+ Name ident() {
+ if (s.token == IDENTIFIER) {
+ Name name = NameTransformer.encode(s.name);
+ s.nextToken();
+ return name;
+ } else {
+ accept(IDENTIFIER);
+ return Names.ERROR;
+ }
+ }
+
+ /** StableRef ::= StableId
+ * | [Ident `.'] this
+ * SimpleType ::= StableRef [`.' type]
+ */
+ Tree stableRef(boolean thisOK, boolean typeOK) {
+ Tree t;
+ if (s.token == THIS) {
+ t = make.This(s.skipToken(), Tree.Empty);
+ if (!thisOK || s.token == DOT)
+ t = selectors(accept(DOT), t, typeOK);
+ } else {
+ t = make.Ident(s.pos, ident());
+ if (s.token == DOT) {
+ int pos = s.skipToken();
+ if (s.token == THIS) {
+ s.nextToken();
+ t = make.This(pos, convertToTypeId(t));
+ if (!thisOK || s.token == DOT)
+ t = selectors(accept(DOT), t, typeOK);
+ } else {
+ t = selectors(pos, t, typeOK);
+ }
+ }
+ }
+ return t;
+ }
+
+ Tree selectors(int pos, Tree t, boolean typeOK) {
+ if (typeOK && s.token == TYPE) {
+ s.nextToken();
+ return make.SingletonType(pos, t);
+ } else {
+ t = make.Select(pos, t, ident());
+ if (s.token == DOT) {
+ t = selectors(s.skipToken(), t, typeOK);
+ }
+ return t;
+ }
+ }
+
+ /** StableId ::= [[Ident `.'] this `.'] {Id `.'} Id
+ */
+ Tree stableId() {
+ return stableRef(false, false);
+ }
+
+ /** QualId ::= Id {`.' Id}
+ */
+ Tree qualId() {
+ Tree id = make.Ident(s.pos, ident());
+ if (s.token == DOT) return selectors(s.skipToken(), id, false);
+ else return id;
+ }
+
+ /** SimpleExpr ::= literal
+ * | null
+ */
+ Tree literal() {
+ Tree t;
+ switch (s.token) {
+ case CHARLIT:
+ t = make.Literal(s.pos, new Character((char)s.intVal));
+ break;
+ case INTLIT:
+ t = make.Literal(s.pos, new Integer((int)s.intVal));
+ break;
+ case LONGLIT:
+ t = make.Literal(s.pos, new Long(s.intVal));
+ break;
+ case FLOATLIT:
+ t = make.Literal(s.pos, new Float((float)s.floatVal));
+ break;
+ case DOUBLELIT:
+ t = make.Literal(s.pos, new Double(s.floatVal));
+ break;
+ case STRINGLIT:
+ t = make.Literal(s.pos, s.name.toString());
+ break;
+ case NULL:
+ t = make.Ident(s.pos, Names.null_);
+ break;
+ default:
+ return syntaxError("illegal literal", true);
+ }
+ s.nextToken();
+ return t;
+ }
+
+//////// TYPES ///////////////////////////////////////////////////////////////
+
+ /** TypedOpt ::= [`:' Type]
+ */
+ Tree typedOpt() {
+ if (s.token == COLON) {
+ s.nextToken();
+ return type();
+ } else {
+ return Tree.Empty;
+ }
+ }
+
+ /** Types ::= Type {`,' Type}
+ */
+ Tree[] types() {
+ TreeList ts = new TreeList();
+ ts.append(type());
+ while (s.token == COMMA) {
+ s.nextToken();
+ ts.append(type());
+ }
+ return ts.toArray();
+ }
+
+ /** Type ::= Type1 `=>' Type
+ * | `(' [Types] `)' `=>' Type
+ * | Type1
+ */
+ Tree type() {
+ Tree t;
+ if (s.token == LPAREN) {
+ s.nextToken();
+ if (s.token == RPAREN) {
+ s.nextToken();
+ int pos = accept(ARROW);
+ return make.FunType(pos, Tree.EMPTY_ARRAY, type());
+ } else {
+ t = type();
+ if (s.token == COMMA) {
+ s.nextToken();
+ TreeList ts = new TreeList();
+ ts.append(t);
+ ts.append(types());
+ accept(RPAREN);
+ int pos = accept(ARROW);
+ return make.FunType(pos, ts.toArray(), type());
+ } else {
+ accept(RPAREN);
+ }
+ }
+ } else {
+ t = type1();
+ }
+ if (s.token == ARROW)
+ return make.FunType(s.skipToken(), new Tree[]{t}, type());
+ else
+ return t;
+ }
+
+ /** Type1 ::= SimpleType {with SimpleType} [with Refinement]
+ */
+ Tree type1() {
+ int pos = s.pos;
+ Tree t = simpleType();
+ if (s.token == WITH) {
+ TreeList ts = new TreeList();
+ ts.append(t);
+ while (s.token == WITH) {
+ s.nextToken();
+ if (s.token == LBRACE)
+ return make.CompoundType(pos, ts.toArray(), refinement());
+ else
+ ts.append(simpleType());
+ }
+ return make.CompoundType(pos, ts.toArray(), Tree.EMPTY_ARRAY);
+ } else {
+ return t;
+ }
+ }
+
+ /** SimpleType ::= SimpleType TypeArgs
+ * | SimpleType `#' Id
+ * | StableId
+ * | StableRef `.' type
+ * | `[' Types `]'
+ * | `(' Type `)'
+ */
+ Tree simpleType() {
+ int pos = s.pos;
+ Tree t;
+ if (s.token == LPAREN) {
+ s.nextToken();
+ t = type();
+ accept(RPAREN);
+ } else if (s.token == LBRACKET) {
+ s.nextToken();
+ Tree[] ts = types();
+ accept(RBRACKET);
+ t = make.TupleType(pos, ts);
+ } else {
+ t = convertToTypeId(stableRef(false, true));
+ }
+ while (true) {
+ if (s.token == HASH)
+ t = make.SelectFromType(s.skipToken(), t, ident().toTypeName());
+ else if (s.token == LBRACKET)
+ t = make.AppliedType(pos, t, varTypeArgs());
+ else break;
+ }
+ return t;
+ }
+
+ /** TypeArgs ::= `[' Types `]'
+ */
+ Tree[] typeArgs() {
+ accept(LBRACKET);
+ Tree[] ts = types();
+ accept(RBRACKET);
+ return ts;
+ }
+
+ /** VarTypeArgs ::= `[' VarType {`,' VarType} `]'
+ */
+ Tree[] varTypeArgs() {
+ int pos = accept(LBRACKET);
+ TreeList ts = new TreeList();
+ ts.append(varType());
+ while (s.token == COMMA) {
+ s.nextToken();
+ ts.append(varType());
+ }
+ accept(RBRACKET);
+ return ts.toArray();
+ }
+
+ /** VarType ::= [`+'] Type
+ */
+ Tree varType() {
+ int pos = s.pos;
+ if (s.token == IDENTIFIER && s.name == PLUS)
+ return make.CovariantType(s.skipToken(), type());
+ else
+ return type();
+ }
+
+//////// EXPRESSIONS ////////////////////////////////////////////////////////
+
+ /** EqualsExpr ::= `=' Expr
+ */
+ Tree equalsExpr() {
+ accept(EQUALS);
+ return expr();
+ }
+
+ /** Exprs ::= Expr {`,' Expr}
+ */
+ Tree[] exprs() {
+ TreeList ts = new TreeList();
+ ts.append(expr());
+ while (s.token == COMMA) {
+ s.nextToken();
+ ts.append(expr());
+ }
+ return ts.toArray();
+ }
+
+ /** Expr ::= [Bindings `=>'] Expr
+ * | if `(' Expr `)' Expr [[`;'] else Expr]
+ * | for `(' Enumerators `)' [do | yield] Expr
+ * | Designator `=' Expr
+ * | SimpleExpr ArgumentExprs `=' Expr
+ * | PostfixExpr [`:' Type1 | as Type1 | is Type1]
+ * Bindings ::= Id [`:' Type1]
+ * | `(' [Binding {`,' Binding}] `)'
+ */
+ Tree expr() {
+ if (s.token == IF) {
+ int pos = s.skipToken();
+ accept(LPAREN);
+ Tree cond = expr();
+ accept(RPAREN);
+ Tree thenp = expr();
+ Tree elsep = Tree.Empty;
+ if (s.token == ELSE) {
+ s.nextToken();
+ elsep = expr();
+ } else {
+ elsep = Tree.Empty;
+ }
+ return make.If(pos, cond, thenp, elsep) ;
+ } else if (s.token == FOR) {
+ s.nextToken();
+ accept(LPAREN);
+ Tree[] enums = enumerators();
+ accept(RPAREN);
+ if (s.token == DO) {
+ s.nextToken();
+ return makeFor(enums, Names.foreach, Names.foreach, expr());
+ } else if (s.token == YIELD) {
+ s.nextToken();
+ return makeFor(enums, Names.map, Names.flatmap, expr());
+ } else {
+ return syntaxError("`do' or `yield' expected", true);
+ }
+// } else if (s.token == ARROW) {
+// return make.Function(s.skipToken(), new ValDef[]{}, expr());
+ } else {
+ Tree t = postfixExpr();
+ if (s.token == EQUALS) {
+ switch (t) {
+ case Ident(_):
+ case Select(_, _):
+ case Apply(_, _):
+ t = make.Assign(s.skipToken(), t, expr());
+ }
+ } else if (s.token == COLON) {
+ int pos = s.skipToken();
+ Tree tp = type1();
+ t = make.Typed(pos, t, tp);
+ } else if (s.token == AS || s.token == IS) {
+ Name op = (s.token == AS) ? Names.as : Names.is;
+ int pos = s.skipToken();
+ t = make.TypeApply(pos, make.Select(pos, t, op), new Tree[]{type1()});
+ }
+ if (s.token == ARROW) {
+ t = make.Function(s.skipToken(), convertToParams(t), expr());
+ }
+ return t;
+ }
+ }
+
+ /** PostfixExpr ::= InfixExpr [Id]
+ * InfixExpr ::= PrefixExpr
+ * | InfixExpr Id InfixExpr
+ */
+ Tree postfixExpr() {
+ int base = sp;
+ Tree top = prefixExpr();
+ while (s.token == IDENTIFIER) {
+ top = reduceStack(
+ true, base, top, s.name.precedence(), s.name.leftAssoc());
+ push(top, s.pos, s.name);
+ ident();
+ if (isExprIntro()) {
+ top = prefixExpr();
+ } else {
+ sp--;
+ int pos = positions[sp];
+ Name postOp = operators[sp];
+ top = reduceStack(true, base, operands[sp], 0, true);
+ return make.Select(pos, top, postOp);
+ }
+ }
+ return reduceStack(true, base, top, 0, true);
+ }
+
+ /** PrefixExpr ::= [op] SimpleExpr
+ */
+ Tree prefixExpr() {
+ Tree t;
+ if (s.token == IDENTIFIER &&
+ (s.name == MINUS ||
+ s.name == PLUS ||
+ s.name == TILDE ||
+ s.name == BANG)) {
+ Name name = ident();
+ t = make.Select(s.pos, simpleExpr(), name);
+ } else {
+ t = simpleExpr();
+ }
+ return t;
+ }
+
+ /* SimpleExpr ::= literal
+ * | null
+ * | StableRef
+ * | super `.' Id
+ * | SimpleExpr `.' Id
+ * | `(' [Expr] `)'
+ * | `[' [Exprs] `]'
+ * | BlockExpr
+ * | SimpleExpr `@' TypeArgs
+ * | SimpleExpr ArgumentExprs
+ * | new Template
+ * | `_'
+ */
+ Tree simpleExpr() {
+ Tree t;
+ switch (s.token) {
+ case CHARLIT:
+ case INTLIT:
+ case LONGLIT:
+ case FLOATLIT:
+ case DOUBLELIT:
+ case STRINGLIT:
+ case NULL:
+ t = literal();
+ break;
+ case IDENTIFIER:
+ case THIS:
+ t = stableRef(true, false);
+ break;
+ case SUPER:
+ int pos = s.skipToken();
+ t = make.Select(accept(DOT), make.Super(pos, Tree.Empty), ident());
+ break;
+ case LPAREN:
+ int pos = s.skipToken();
+ if (s.token == RPAREN) {
+ s.nextToken();
+ t = make.Block(pos, Tree.EMPTY_ARRAY);
+ } else {
+ t = expr();
+ if (s.token == COMMA) {
+ int commapos = s.skipToken();
+ TreeList ts = new TreeList();
+ ts.append(t);
+ ts.append(exprs());
+ accept(RPAREN);
+ if (s.token == ARROW) {
+ t = make.Function(pos, convertToParams(ts.toArray()), Tree.Empty);
+ } else {
+ t = syntaxError(commapos, "`)' expected", false);
+ }
+ } else {
+ accept(RPAREN);
+ }
+ }
+ break;
+ case LBRACKET:
+ int pos = s.skipToken();
+ Tree[] ts;
+ if (s.token == RBRACKET) ts = Tree.EMPTY_ARRAY;
+ else ts = exprs();
+ t = make.Tuple(pos, ts);
+ accept(RBRACKET);
+ break;
+ case LBRACE:
+ t = blockExpr();
+ break;
+ case NEW:
+ t = make.New(s.skipToken(), template());
+ break;
+ default:
+ return syntaxError("illegal start of expression", true);
+ }
+ while (true) {
+ switch (s.token) {
+ case DOT:
+ t = make.Select(s.skipToken(), t, ident());
+ break;
+ case AT:
+ int pos = s.skipToken();
+ t = make.TypeApply(pos, t, typeArgs());
+ break;
+ case LPAREN:
+ case LBRACKET:
+ case LBRACE:
+ t = make.Apply(s.pos, t, argumentExprs());
+ break;
+ default:
+ return t;
+ }
+ }
+ }
+
+ /** ArgumentExprs ::= `(' [Exprs] `)'
+ * | `[' [Exprs] `]'
+ * | BlockExpr
+ */
+ Tree[] argumentExprs() {
+ Tree[] ts = Tree.EMPTY_ARRAY;
+ if (s.token == LBRACE) {
+ ts = new Tree[]{blockExpr()};
+ } else if (s.token == LBRACKET) {
+ int pos = s.skipToken();
+ if (s.token != RBRACKET)
+ ts = exprs();
+ accept(RBRACKET);
+ ts = new Tree[]{make.Tuple(pos, ts)};
+ } else {
+ accept(LPAREN);
+ if (s.token != RPAREN)
+ ts = exprs();
+ accept(RPAREN);
+ }
+ return ts;
+ }
+
+ /** BlockExpr ::= `{' CaseClause {CaseClause} `}'
+ * | `{' Block `}'
+ */
+ Tree blockExpr() {
+ Tree res;
+ int pos = accept(LBRACE);
+ if (s.token == CASE) {
+ TreeList stats = new TreeList();
+ do {
+ stats.append(caseClause());
+ } while (s.token == CASE);
+ res = make.Visitor(
+ pos, (CaseDef[]) stats.copyTo(new CaseDef[stats.length()]));
+ } else {
+ res = block(pos);
+ }
+ accept(RBRACE);
+ return res;
+ }
+
+ /** BlockConstr ::= `{' Block `}'
+ */
+ Tree blockConstr() {
+ int pos = accept(LBRACE);
+ Tree res = block(pos);
+ switch (res) {
+ case Block(Tree[] stats):
+ if (stats.length > 0)
+ stats[stats.length - 1] = convertToConstr(stats[stats.length - 1]);
+ else
+ syntaxError(res.pos, "class constructor expected", false);
+ }
+ accept(RBRACE);
+ return res;
+ }
+
+ /** Block ::= BlockStatSeq
+ */
+ Tree block(int pos) {
+ Tree[] stats = blockStatSeq(new TreeList());
+ if (stats.length == 1) return stats[0];
+ else return make.Block(pos, stats);
+ }
+
+ /** CaseClause ::= case Pattern [if `(' Expr `)'] `=>' Block
+ */
+ Tree caseClause() {
+ int pos = accept(CASE);
+ Tree pat = pattern();
+ Tree guard = Tree.Empty;
+ if (s.token == IF) {
+ s.nextToken();
+ accept(LPAREN);
+ guard = expr();
+ accept(RPAREN);
+ }
+ accept(ARROW);
+ return make.CaseDef(pos, pat, guard, block(s.pos));
+ }
+
+ /** Enumerators ::= Generator {`;' Enumerator}
+ * Enumerator ::= Generator
+ * | Expr
+ */
+ Tree[] enumerators() {
+ TreeList enums = new TreeList();
+ enums.append(generator());
+ while (s.token == SEMI) {
+ s.nextToken();
+ if (s.token == VAL) enums.append(generator());
+ else enums.append(expr());
+ }
+ return enums.toArray();
+ }
+
+ /** Generator ::= val Pattern `<-' Expr
+ */
+ Tree generator() {
+ int pos = accept(VAL);
+ Tree p = pattern();
+ accept(LARROW);
+ return make.PatDef(pos, 0, p, expr());
+ }
+
+//////// PATTERNS ////////////////////////////////////////////////////////////
+
+ /** Patterns ::= Pattern {`,' Pattern}
+ */
+ Tree[] patterns() {
+ TreeList ts = new TreeList();
+ ts.append(pattern());
+ while (s.token == COMMA) {
+ s.nextToken();
+ ts.append(pattern());
+ }
+ return ts.toArray();
+ }
+
+ /** Pattern ::= varid `:' Type1
+ * | `_' `:' Type1
+ * | SimplePattern {Id SimplePattern}
+ */
+ Tree pattern() {
+ int base = sp;
+ Tree top = simplePattern();
+ if (s.token == COLON) {
+ switch (top) {
+ case Ident(Name name):
+ if (name.isVariable())
+ return make.Typed(s.skipToken(), top, type1());
+ }
+ }
+ while (s.token == IDENTIFIER) {
+ top = reduceStack(
+ false, base, top, s.name.precedence(), s.name.leftAssoc());
+ push(top, s.pos, s.name);
+ ident();
+ top = simplePattern();
+ }
+ return reduceStack(false, base, top, 0, true);
+ }
+
+ /** SimplePattern ::= varid
+ * | `_'
+ * | literal
+ * | null
+ * | StableId {ArgumentPatterns}
+ * | `(' Pattern `)'
+ * | `[' [Patterns] `]'
+ */
+ Tree simplePattern() {
+ switch (s.token) {
+ case IDENTIFIER:
+ case THIS:
+ Tree t = stableId();
+ while (s.token == LPAREN || s.token == LBRACKET) {
+ t = make.Apply(s.pos, convertToConstr(t), argumentPatterns());
+ }
+ return t;
+ case USCORE:
+ return make.Ident(s.skipToken(), Names.WILDCARD);
+ case CHARLIT:
+ case INTLIT:
+ case LONGLIT:
+ case FLOATLIT:
+ case DOUBLELIT:
+ case STRINGLIT:
+ case NULL:
+ return literal();
+ case LPAREN:
+ s.nextToken();
+ Tree t = pattern();
+ accept(RPAREN);
+ return t;
+ case LBRACKET:
+ return tuplePattern();
+ default:
+ return syntaxError("illegal start of pattern", true);
+ }
+ }
+
+ /** SimplePattern ::= `[' [Patterns] ']'
+ */
+ Tree tuplePattern() {
+ int pos = accept(LBRACKET);
+ Tree[] ts;
+ if (s.token == RBRACKET) ts = Tree.EMPTY_ARRAY;
+ else ts = patterns();
+ accept(RBRACKET);
+ return make.Tuple(pos, ts);
+ }
+
+ /** ArgumentPatterns ::= `(' [Patterns] `)'
+ * | `[' [Patterns] `]'
+ */
+ Tree[] argumentPatterns() {
+ if (s.token == LBRACKET) {
+ return new Tree[]{tuplePattern()};
+ } else {
+ Tree[] ts = Tree.EMPTY_ARRAY;
+ accept(LPAREN);
+ if (s.token != RPAREN)
+ ts = patterns();
+ accept(RPAREN);
+ return ts;
+ }
+ }
+
+////////// MODIFIERS ////////////////////////////////////////////////////////////
+
+ /** Modifiers ::= {Modifier}
+ * Modifier ::= final
+ * | private
+ * | protected
+ * | override
+ * | abstract
+ */
+ int modifiers() {
+ int mods = 0;
+ while (true) {
+ int mod;
+ switch (s.token) {
+ case ABSTRACT:
+ mod = Modifiers.ABSTRACTCLASS;
+ break;
+ case FINAL:
+ mod = Modifiers.FINAL;
+ break;
+ case PRIVATE:
+ mod = Modifiers.PRIVATE;
+ break;
+ case PROTECTED:
+ mod = Modifiers.PROTECTED;
+ break;
+ case OVERRIDE:
+ mod = Modifiers.OVERRIDE;
+ break;
+ default:
+ return mods;
+ }
+ if ((mods & mod) != 0)
+ syntaxError(s.pos, "repeated modifier", false);
+ mods |= mod;
+ s.nextToken();
+ }
+ }
+
+ /** LocalClassModifiers ::= {LocalClassModifier}
+ * LocalClassModifier ::= final
+ * | private
+ */
+ int localClassModifiers() {
+ int mods = 0;
+ while (true) {
+ int mod;
+ switch (s.token) {
+ case ABSTRACT:
+ mod = Modifiers.ABSTRACTCLASS;
+ break;
+ case FINAL:
+ mod = Modifiers.FINAL;
+ break;
+ default:
+ return mods;
+ }
+ if ((mods & mod) != 0)
+ syntaxError(s.pos, "repeated modifier", false);
+ mods |= mod;
+ s.nextToken();
+ }
+ }
+
+//////// PARAMETERS //////////////////////////////////////////////////////////
+
+ /** ParamClauses ::= {ParamClause}
+ */
+ ValDef[][] paramClauses() {
+ ArrayList ts = new ArrayList();
+ while (s.token == LPAREN)
+ ts.add(paramClause());
+ return (ValDef[][])ts.toArray(new ValDef[ts.size()][]);
+ }
+
+ /** ParamClause ::= `(' [Param {`,' Param}] `)'
+ */
+ ValDef[] paramClause() {
+ int pos = accept(LPAREN);
+ TreeList params = new TreeList();
+ if (s.token != RPAREN) {
+ params.append(param());
+ while (s.token == COMMA) {
+ s.nextToken();
+ params.append(param());
+ }
+ }
+ accept(RPAREN);
+ return (ValDef[])params.copyTo(new ValDef[params.length()]);
+ }
+
+ /** Param ::= [def] Id `:' Type
+ */
+ ValDef param() {
+ int pos = s.pos;
+ int mods = Modifiers.PARAM;
+ if (s.token == DEF) {
+ mods |= Modifiers.DEF;
+ s.nextToken();
+ }
+ Name name = ident();
+ accept(COLON);
+ return (ValDef)make.ValDef(pos, mods, name, type(), Tree.Empty);
+ }
+
+ /** TypeParamClauseOpt ::= [`[' TypeSig {`,' TypeSig} `]']
+ */
+ TypeDef[] typeParamClauseOpt() {
+ TreeList params = new TreeList();
+ if (s.token == LBRACKET) {
+ s.nextToken();
+ params.append(typeParam());
+ while (s.token == COMMA) {
+ s.nextToken();
+ params.append(typeParam());
+ }
+ accept(RBRACKET);
+ }
+ return (TypeDef[])params.copyTo(new TypeDef[params.length()]);
+ }
+
+ /** TypeSig ::= Id [<: Type]
+ */
+ Tree typeParam() {
+ int pos = s.pos;
+ Name name = ident();
+ Tree tp;
+ if (s.token == SUBTYPE) {
+ s.nextToken();
+ tp = type();
+ } else {
+ tp = scalaAnyType(pos);
+ }
+ return make.TypeDef(pos, Modifiers.PARAM, name.toTypeName(),
+ Tree.ExtTypeDef.EMPTY_ARRAY, tp);
+ }
+
+//////// DEFS ////////////////////////////////////////////////////////////////
+
+ /** Import ::= import ImportRef {`,' ImportRef}
+ */
+ Tree[] importClause() {
+ accept(IMPORT);
+ TreeList ts = new TreeList();
+ ts.append(importRef());
+ while (s.token == COMMA) {
+ s.nextToken();
+ ts.append(importRef());
+ }
+ return ts.toArray();
+ }
+
+ /** ImportRef ::= StableId `.' (Id | `_' | ImportSelectors)
+ */
+ Tree importRef() {
+ Tree t;
+ int startpos = s.pos;
+ int pos;
+ if (s.token == THIS) {
+ t = make.This(s.skipToken(), Tree.Empty);
+ t = make.Select(accept(DOT), t, ident());
+ pos = accept(DOT);
+ } else {
+ t = make.Ident(s.pos, ident());
+ pos = accept(DOT);
+ if (s.token == THIS) {
+ s.nextToken();
+ t = make.This(pos, convertToTypeId(t));
+ t = make.Select(accept(DOT), t, ident());
+ pos = accept(DOT);
+ }
+ }
+ while (true) {
+ if (s.token == USCORE) {
+ s.nextToken();
+ return make.Import(startpos, t, new Name[]{Names.WILDCARD});
+ } else if (s.token == LBRACE) {
+ return make.Import(startpos, t, importSelectors());
+ } else {
+ Name name = ident();
+ if (s.token == DOT) {
+ t = make.Select(pos, t, name);
+ pos = accept(DOT);
+ } else {
+ return make.Import(startpos, t, new Name[]{name, name});
+ }
+ }
+ }
+ }
+
+ /** ImportSelectors ::= `{' {ImportSelector `,'} (ImportSelector | `_') `}'
+ */
+ Name[] importSelectors() {
+ LinkedList/*<Name>*/ names = new LinkedList();
+ accept(LBRACE);
+ boolean isLast = importSelector(names);
+ while (!isLast && s.token == COMMA) {
+ s.nextToken();
+ isLast = importSelector(names);
+ }
+ accept(RBRACE);
+ return (Name[])names.toArray(new Name[]{});
+ }
+
+ /** ImportSelector ::= Id [`=>' [Id | `_']]
+ */
+ boolean importSelector(LinkedList/*<Name>*/ names) {
+ if (s.token == USCORE) {
+ s.nextToken();
+ names.add(Names.WILDCARD);
+ return true;
+ } else {
+ Name name = ident();
+ names.add(name);
+ if (s.token == ARROW) {
+ s.nextToken();
+ if (s.token == USCORE) {
+ s.nextToken();
+ names.add(Names.WILDCARD);
+ } else {
+ names.add(ident());
+ }
+ } else {
+ names.add(name);
+ }
+ return false;
+ }
+ }
+
+ /** Def ::= val PatDef {`,' PatDef}
+ * | var VarDef {`,' VarDef}
+ * | def FunDef {`,' FunDef}
+ * | constr ConstrDef {`,' ConstrDef}
+ * | type TypeDef {`,' TypeDef}
+ * | TopDef
+ * Dcl ::= val ValSig {`,' ValSig}
+ * | var ValSig {`,' ValSig}
+ * | def FunSig {`,' FunSig}
+ * | constr ConstrSig {`,' ConstrSig}
+ * | type TypeSig {`,' TypeSig}
+ */
+ Tree[] defOrDcl(int mods) {
+ TreeList ts = new TreeList();
+ switch (s.token) {
+ case VAL:
+ do {
+ s.nextToken();
+ ts.append(patDefOrSig(mods));
+ } while (s.token == COMMA);
+ return ts.toArray();
+ case VAR:
+ do {
+ s.nextToken();
+ ts.append(varDefOrSig(mods));
+ } while (s.token == COMMA);
+ return ts.toArray();
+ case DEF:
+ do {
+ s.nextToken();
+ ts.append(funDefOrSig(mods));
+ } while (s.token == COMMA);
+ return ts.toArray();
+ case CONSTR:
+ do {
+ s.nextToken();
+ ts.append(constrDefOrSig(mods));
+ } while (s.token == COMMA);
+ return ts.toArray();
+ case TYPE:
+ do {
+ s.nextToken();
+ ts.append(typeDefOrSig(mods));
+ } while (s.token == COMMA);
+ return ts.toArray();
+ default:
+ return topDef(mods);
+ }
+ }
+
+ /** TopDef ::= ([case] class) ClassDef {`,' ClassDef}
+ * | trait TraitDef {`,' TraitDef}
+ * | module ModuleDef {`,' ModuleDef}
+ * LocalTopDef ::= class ClassDef {`,' ClassDef}
+ * | trait TraitDef {`,' TraitDef}
+ * | module ModuleDef {`,' ModuleDef}
+ */
+ Tree[] topDef(int mods) {
+ TreeList ts = new TreeList();
+ switch (s.token) {
+ case CLASS:
+ case CASECLASS:
+ case TRAIT:
+ if (s.token == CASECLASS) mods |= Modifiers.CASE;
+ else if (s.token == TRAIT) mods |= Modifiers.TRAIT | Modifiers.ABSTRACTCLASS;
+ do {
+ s.nextToken();
+ ts.append(classDef(mods));
+ } while (s.token == COMMA);
+ return ts.toArray();
+ case MODULE:
+ do {
+ s.nextToken();
+ ts.append(moduleDef(mods));
+ } while (s.token == COMMA);
+ return ts.toArray();
+ default:
+ return new Tree[]{syntaxError("illegal start of definition", true)};
+ }
+ }
+
+ /** PatDef ::= Pattern `=' Expr
+ * ValSig ::= Id `:' Type
+ */
+ Tree patDefOrSig(int mods) {
+ int pos = s.pos;
+ Tree pat = pattern();
+ Tree tp;
+ switch (pat) {
+ case Typed(Tree pat1, Tree tp1):
+ pat = pat1;
+ tp = tp1;
+ break;
+ default:
+ if (s.token == COLON) tp = typedOpt();
+ else tp = Tree.Empty;
+ }
+ switch (pat) {
+ case Ident(Name name):
+ if (tp == Tree.Empty || s.token == EQUALS)
+ return make.ValDef(pos, mods, name, tp, equalsExpr());
+ else
+ return make.ValDef(pos, mods | Modifiers.ABSTRACT, name, tp, Tree.Empty);
+ default:
+ return make.PatDef(pos, mods, pat, equalsExpr());
+ }
+ }
+
+ /** VarDef ::= Id [`:' Type] `=' Expr
+ * | Id `:' Type `=' `_'
+ * VarSig ::= Id `:' Type
+ */
+ Tree varDefOrSig(int mods) {
+ int pos = s.pos;
+ Name name = ident();
+ Tree type = typedOpt();
+ if (type == Tree.Empty || s.token == EQUALS) {
+ accept(EQUALS);
+ Tree rhs;
+ if (type != Tree.Empty && s.token == USCORE) {
+ rhs = Tree.Empty;
+ s.nextToken();
+ } else {
+ rhs = expr();
+ }
+ return make.ValDef(pos, mods | Modifiers.MUTABLE, name, type, rhs);
+ } else {
+ return make.ValDef(pos, mods | Modifiers.MUTABLE | Modifiers.ABSTRACT,
+ name, type, Tree.Empty);
+ }
+ }
+
+ /** FunDef ::= Id [TypeParamClause] {ParamClause} [`:' Type]
+ * (`=' Expr | BlockExpr)
+ * FunSig ::= Id [TypeParamClause] {ParamClause} `:' Type
+ */
+ Tree funDefOrSig(int mods) {
+ int pos = s.pos;
+ Name name = ident();
+ TypeDef[] tparams = typeParamClauseOpt();
+ ValDef[][] vparams = paramClauses();
+ Tree restype = typedOpt();
+ if (s.token == LBRACE)
+ return make.DefDef(pos, mods, name, tparams, vparams,
+ restype, blockExpr());
+ else if (s.token == EQUALS || restype == Tree.Empty)
+ return make.DefDef(pos, mods, name, tparams, vparams,
+ restype, equalsExpr());
+ else
+ return make.DefDef(pos, mods | Modifiers.ABSTRACT, name,
+ tparams, vparams, restype, Tree.Empty);
+ }
+
+ /* ConstrDef ::= Id [TypeParamClause] [ParamClause] [`:' Type]
+ * (`=' Constr | `=' BlockConstr | BlockConstr)
+ */
+ Tree constrDefOrSig(int mods) {
+ int pos = s.pos;
+ Name name = ident().toConstrName();
+ TypeDef[] tparams = typeParamClauseOpt();
+ ValDef[][] vparams = new ValDef[][]{paramClause()};
+ Tree restype = typedOpt();
+ if (s.token == LBRACE)
+ return make.DefDef(pos, mods, name, tparams, vparams,
+ restype, blockConstr());
+ else if (s.token == EQUALS || restype == Tree.Empty) {
+ accept(EQUALS);
+ return make.DefDef(pos, mods, name, tparams, vparams,
+ restype, (s.token == LBRACE) ? blockConstr() : constr());
+ } else
+ return make.DefDef(pos, mods | Modifiers.ABSTRACT, name,
+ tparams, vparams, restype, Tree.Empty);
+ }
+
+ /** TypeDef ::= Id [TypeParamClause] `=' Type
+ * TypeSig ::= Id [`<:' Type]
+ */
+ Tree typeDefOrSig(int mods) {
+ int pos = s.pos;
+ Name name = ident().toTypeName();
+ if (s.token == SUBTYPE) {
+ s.nextToken();
+ return make.TypeDef(pos, mods | Modifiers.ABSTRACT, name,
+ Tree.ExtTypeDef.EMPTY_ARRAY, type());
+ } else if (s.token == LBRACKET) {
+ TypeDef[] tparams = typeParamClauseOpt();
+ accept(EQUALS);
+ return make.TypeDef(pos, mods, name, tparams, type());
+ } else if (s.token == EQUALS) {
+ s.nextToken();
+ return make.TypeDef(pos, mods, name,
+ Tree.ExtTypeDef.EMPTY_ARRAY, type());
+ } else if (s.token == SEMI || s.token == COMMA) {
+ return make.TypeDef(
+ pos, mods | Modifiers.ABSTRACT, name,
+ Tree.ExtTypeDef.EMPTY_ARRAY, scalaAnyType(pos));
+ } else {
+ return syntaxError("`=' or `<:' expected", true);
+ }
+ }
+
+ /** ClassDef ::= Id [TypeParamClause] ParamClause [`:' Type] ClassTemplate
+ * TraitDef ::= Id [TypeParamClause] [`:' Type] ClassTemplate
+ */
+ Tree classDef(int mods) {
+ int pos = s.pos;
+ Name name = ident();
+ TypeDef[] tparams = typeParamClauseOpt();
+ ValDef[][] params;
+ if ((mods & Modifiers.TRAIT) == 0) params = new ValDef[][]{paramClause()};
+ else params = new ValDef[][]{};
+ return make.ClassDef(pos, mods, name.toTypeName(), tparams, params,
+ typedOpt(), classTemplate());
+ }
+
+ /** ModuleDef ::= Id [`:' Type] ClassTemplate
+ */
+ Tree moduleDef(int mods) {
+ return make.ModuleDef(
+ s.pos, mods, ident(), typedOpt(), classTemplate());
+ }
+
+ /** ClassTemplate ::= extends Template
+ * | TemplateBody
+ */
+ Template classTemplate() {
+ int pos = s.pos;
+ if (s.token == EXTENDS) {
+ s.nextToken();
+ return template();
+ } else if (s.token == LBRACE) {
+ return (Template)make.Template(
+ pos, new Tree[]{scalaObjectConstr(pos)}, templateBody());
+ } else {
+ syntaxError("`extends' or `{' expected", true);
+ return (Template)make.Template(
+ pos, new Tree[]{scalaObjectConstr(pos)}, Tree.EMPTY_ARRAY);
+ }
+ }
+
+////////// TEMPLATES ////////////////////////////////////////////////////////////
+
+
+ /** Template ::= Constr {`with' Constr} [TemplateBody]
+ */
+ Template template() {
+ int pos = s.pos;
+ TreeList parents = new TreeList();
+ parents.append(constr());
+ while (s.token == WITH) {
+ s.nextToken();
+ if (s.token == LBRACE)
+ return (Template)make.Template(pos, parents.toArray(), templateBody());
+ else
+ parents.append(constr());
+ }
+ Tree[] stats = (s.token == LBRACE) ? templateBody() : Tree.EMPTY_ARRAY;
+ return (Template)make.Template(pos, parents.toArray(), stats);
+ }
+
+ /** Constr ::= StableId [TypeArgs] [`(' [Exprs] `)']
+ */
+ Tree constr() {
+ Tree t = convertToConstr(stableId());
+ if (s.token == LBRACKET)
+ t = make.TypeApply(s.pos, t, typeArgs());
+ if (s.token == LPAREN)
+ t = make.Apply(s.pos, t, argumentExprs());
+ return t;
+ }
+
+ /** TemplateBody ::= `{' [TemplateStat {`;' TemplateStat}] `}'
+ */
+ Tree[] templateBody() {
+ accept(LBRACE);
+ Tree[] body = templateStatSeq();
+ accept(RBRACE);
+ return body;
+ }
+
+ /** Refinement ::= `{' [RefineStat {`;' RefineStat}] `}'
+ */
+ Tree[] refinement() {
+ accept(LBRACE);
+ Tree[] body = refineStatSeq();
+ accept(RBRACE);
+ return body;
+ }
+
+/////// STATSEQS //////////////////////////////////////////////////////////////
+
+ /** Packaging ::= package QualId `{' TopStatSeq `}'
+ */
+ Tree packaging() {
+ int pos = accept(PACKAGE);
+ Tree pkg = qualId();
+ accept(LBRACE);
+ Tree[] stats = topStatSeq();
+ accept(RBRACE);
+ return
+ make.PackageDef(pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, stats));
+ }
+
+ /** TopStatSeq ::= [TopStat {`;' TopStat}]
+ * TopStat ::= Modifiers TopDef
+ * | Packaging
+ * | Import
+ * |
+ */
+ Tree[] topStatSeq() {
+ TreeList stats = new TreeList();
+ while (s.token != RBRACE && s.token != EOF) {
+ if (s.token == PACKAGE) {
+ stats.append(packaging());
+ } else if (s.token == IMPORT) {
+ stats.append(importClause());
+ } else if (s.token == CLASS ||
+ s.token == CASECLASS ||
+ s.token == TRAIT ||
+ s.token == MODULE ||
+ isModifier()) {
+ stats.append(topDef(modifiers()));
+ } else if (s.token != SEMI) {
+ syntaxError("illegal start of class or module definition", true);
+ }
+ if (s.token != RBRACE && s.token != EOF) accept(SEMI);
+ }
+ return stats.toArray();
+ }
+
+ /** TemplateStatSeq ::= TemplateStat {`;' TemplateStat}
+ * TemplateStat ::= Import
+ * | Modifiers Def
+ * | Modifiers Dcl
+ * | Expr
+ * % | val this `:' Type
+ * |
+ */
+ Tree[] templateStatSeq() {
+ TreeList stats = new TreeList();
+ while (s.token != RBRACE && s.token != EOF) {
+ if (s.token == IMPORT) {
+ stats.append(importClause());
+ } else if (isExprIntro()) {
+ stats.append(expr());
+ } else if (isDefIntro() || isModifier()) {
+ stats.append(defOrDcl(modifiers()));
+ } else if (s.token != SEMI) {
+ syntaxError("illegal start of definition", true);
+ }
+ if (s.token != RBRACE) accept(SEMI);
+ }
+ return stats.toArray();
+ }
+
+ /** RefineStatSeq ::= RefineStat {`;' RefineStat}
+ * RefineStat ::= Dcl
+ * | type TypeDef {`,' TypeDef}
+ * |
+ */
+ Tree[] refineStatSeq() {
+ TreeList stats = new TreeList();
+ while (s.token != RBRACE && s.token != EOF) {
+ if (isDclIntro()) {
+ stats.append(defOrDcl(0));
+ } else if (s.token != SEMI) {
+ syntaxError("illegal start of declaration", true);
+ }
+ if (s.token != RBRACE) accept(SEMI);
+ }
+ return stats.toArray();
+ }
+
+ /** BlockStatSeq ::= { BlockStat `;' } [Expr]
+ * BlockStat ::= Import
+ * | Def
+ * | LocalClassModifiers LocalTopDef
+ * | Expr
+ * |
+ */
+ Tree[] blockStatSeq(TreeList stats) {
+ while ((s.token != RBRACE) && (s.token != EOF) && (s.token != CASE)) {
+ if (s.token == IMPORT) {
+ stats.append(importClause());
+ accept(SEMI);
+ } else if (isExprIntro()) {
+ stats.append(expr());
+ if (s.token != RBRACE && s.token != CASE) accept(SEMI);
+ } else if (isDefIntro()) {
+ stats.append(defOrDcl(0));
+ accept(SEMI);
+ } else if (isLocalClassModifier()) {
+ stats.append(topDef(localClassModifiers()));
+ accept(SEMI);
+ } else if (s.token == SEMI) {
+ s.nextToken();
+ } else {
+ syntaxError("illegal start of statement", true);
+ }
+ }
+ return stats.toArray();
+ }
+
+
+ /** CompilationUnit = [package QualId `;'] TopStatSeq
+ */
+ Tree[] compilationUnit() {
+ if (s.token == PACKAGE) {
+ int pos = s.skipToken();
+ Tree pkg = qualId();
+ if (s.token == SEMI) {
+ s.nextToken();
+ return new Tree[]{
+ make.PackageDef(
+ pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, topStatSeq()))};
+ } else {
+ TreeList stats = new TreeList();
+ accept(LBRACE);
+ stats.append(
+ make.PackageDef(
+ pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, topStatSeq())));
+ accept(RBRACE);
+ stats.append(topStatSeq());
+ return stats.toArray();
+ }
+ } else {
+ return topStatSeq();
+ }
+ }
+}
+
diff --git a/sources/scalac/ast/parser/ParserPhase.java b/sources/scalac/ast/parser/ParserPhase.java
new file mode 100644
index 0000000000..204fb2b925
--- /dev/null
+++ b/sources/scalac/ast/parser/ParserPhase.java
@@ -0,0 +1,63 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+**
+** $Id$
+\* */
+
+package scalac.ast.parser;
+
+import java.io.*;
+import scalac.*;
+
+public class ParserPhase extends PhaseDescriptor {
+
+ public String name() {
+ return "parse";
+ }
+
+ public String description () {
+ return "parse source files";
+ }
+
+ public String taskDescription() {
+ return "parsed";
+ }
+
+ public Phase createPhase(Global global) {
+ return new ParserWorker(global, this);
+ }
+}
+
+public class ParserWorker extends Phase {
+
+ /** constructor
+ */
+ public ParserWorker(Global global, PhaseDescriptor descr) {
+ super(global, descr);
+ }
+
+ /** apply this phase to all compilation units
+ */
+ public void apply() {
+ super.apply();
+ int count = 0;
+ for (int i = 0; i < global.units.length; i++) {
+ if (global.units[i].body != null) count++;
+ }
+ Unit[] units = new Unit[count];
+ for (int i = 0, j = 0; i < global.units.length; i++) {
+ if (global.units[i].body != null) units[j++] = global.units[i];
+ }
+ global.units = units;
+ }
+
+ /** apply this phase to the given compilation unit
+ */
+ public void apply(Unit unit) {
+ global.start();
+ unit.body = new Parser(unit).parse();
+ global.stop("parsed " + unit.source);
+ }
+}
diff --git a/sources/scalac/ast/parser/Scanner.java b/sources/scalac/ast/parser/Scanner.java
new file mode 100644
index 0000000000..0e4af3a09d
--- /dev/null
+++ b/sources/scalac/ast/parser/Scanner.java
@@ -0,0 +1,793 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast.parser;
+
+import scalac.*;
+import scalac.util.Name;
+import scalac.util.Position;
+
+/** A scanner for the programming language Scala.
+ *
+ * @author Matthias Zenger, Martin Odersky
+ * @version 1.0
+ */
+public class Scanner extends TokenData {
+
+ /** layout & character constants
+ */
+ public int tabinc = 8;
+ public final static byte LF = 0xA;
+ protected final static byte FF = 0xC;
+ protected final static byte CR = 0xD;
+ protected final static byte SU = Sourcefile.SU;
+
+ /** the names of all tokens
+ */
+ public Name[] tokenName = new Name[128];
+ public int numToken = 0;
+
+ /** keyword array; maps from name indices to tokens
+ */
+ protected byte[] key;
+ protected int maxKey = 0;
+
+ /** we need one token lookahead
+ */
+ protected TokenData next = new TokenData();
+ protected TokenData prev = new TokenData();
+
+ /** the first character position after the previous token
+ */
+ public int lastpos = 0;
+
+ /** the last error position
+ */
+ public int errpos = -1;
+
+ /** the input buffer:
+ */
+ protected byte[] buf;
+ protected int bp;
+
+ /** the current character
+ */
+ protected byte ch;
+
+ /** the line and column position of the current character
+ */
+ public int cline;
+ public int ccol;
+
+ /** the current sourcefile
+ */
+ public Sourcefile currentSource;
+
+ /** a buffer for character and string literals
+ */
+ protected byte[] lit = new byte[64];
+ protected int litlen;
+
+ /** the compilation unit
+ */
+ public Unit unit;
+
+
+ /** Construct a scanner from a file input stream.
+ */
+ public Scanner(Unit unit) {
+ this.unit = unit;
+ buf = (currentSource = unit.source).getBuffer();
+ cline = 1;
+ bp = -1;
+ ccol = 0;
+ nextch();
+ token = EMPTY;
+ init();
+ nextToken();
+ }
+
+ private void nextch() {
+ ch = buf[++bp]; ccol++;
+ }
+
+ /** read next token and return last position
+ */
+ public int skipToken() {
+ int p = pos;
+ nextToken();
+ return p;
+ }
+
+ public void nextToken() {
+ if (token == RBRACE) {
+ int prevpos = pos;
+ fetchToken();
+ switch (token) {
+ case ELSE: case EXTENDS: case WITH:
+ case YIELD: case DO:
+ case COMMA: case SEMI: case DOT:
+ case COLON: case EQUALS: case ARROW:
+ case LARROW: case SUBTYPE: case AT:
+ case HASH: case AS: case IS:
+ case RPAREN: case RBRACKET: case RBRACE:
+ break;
+ default:
+ if (token == EOF ||
+ ((pos >>> Position.LINESHIFT) >
+ (prevpos >>> Position.LINESHIFT))) {
+ next.copyFrom(this);
+ this.token = SEMI;
+ this.pos = prevpos;
+ }
+ }
+ } else {
+ if (next.token == EMPTY) {
+ fetchToken();
+ } else {
+ copyFrom(next);
+ next.token = EMPTY;
+ }
+ if (token == CASE) {
+ prev.copyFrom(this);
+ fetchToken();
+ if (token == CLASS) {
+ token = CASECLASS;
+ } else {
+ next.copyFrom(this);
+ this.copyFrom(prev);
+ }
+ } else if (token == SEMI) {
+ prev.copyFrom(this);
+ fetchToken();
+ if (token != ELSE) {
+ next.copyFrom(this);
+ this.copyFrom(prev);
+ }
+ }
+ }
+ //System.out.println("<" + token2string(token) + ">");//DEBUG
+ }
+
+ /** read next token
+ */
+ public void fetchToken() {
+ if (token == EOF) return;
+ lastpos = Position.encode(cline, ccol, currentSource.id);
+ int index = bp;
+ while(true) {
+ switch (ch) {
+ case ' ':
+ nextch();
+ break;
+ case '\t':
+ ccol = ((ccol - 1) / tabinc * tabinc) + tabinc;
+ nextch();
+ break;
+ case CR:
+ cline++;
+ ccol = 0;
+ nextch();
+ if (ch == LF) {
+ ccol = 0;
+ nextch();
+ }
+ break;
+ case LF:
+ case FF:
+ cline++;
+ ccol = 0;
+ nextch();
+ break;
+ default:
+ pos = Position.encode(cline, ccol, currentSource.id);
+ index = bp;
+ switch (ch) {
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y':
+ case 'Z': case '$':
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y':
+ case 'z':
+ nextch();
+ getIdentRest(index);
+ return;
+ case '~': case '!': case '@': case '#': case '%':
+ case '^': case '*': case '+': case '-': case '<':
+ case '>': case '?': case ':':
+ case '=': case '&': case '|':
+ nextch();
+ getOperatorRest(index);
+ return;
+ case '/':
+ nextch();
+ if (!skipComment()) {
+ getOperatorRest(index);
+ return;
+ }
+ break;
+ case '_':
+ nextch();
+ getIdentOrOperatorRest(index);
+ return;
+ case '0':
+ nextch();
+ if (ch == 'x' || ch == 'X') {
+ nextch();
+ getNumber(index + 2, 16);
+ } else
+ getNumber(index, 8);
+ return;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ getNumber(index, 10);
+ return;
+ case '\"':
+ nextch();
+ litlen = 0;
+ while (ch != '\"' && ch != CR && ch != LF && ch != SU)
+ getlitch();
+ if (ch == '\"') {
+ token = STRINGLIT;
+ name = Name.fromSource(lit, 0, litlen);
+ nextch();
+ }
+ else
+ syntaxError("unclosed character literal");
+ return;
+ case '\'':
+ nextch();
+ litlen = 0;
+ getlitch();
+ if (ch == '\'') {
+ nextch();
+ token = CHARLIT;
+ byte[] ascii = new byte[litlen * 2];
+ int alen = SourceRepresentation.source2ascii(lit, 0, litlen, ascii);
+ if (alen > 0)
+ intVal = SourceRepresentation.ascii2string(ascii, 0, alen).charAt(0);
+ else
+ intVal = 0;
+ } else
+ syntaxError("unclosed character literal");
+ return;
+ case '.':
+ nextch();
+ if (('0' <= ch) && (ch <= '9')) getFraction(index);
+ else token = DOT;
+ return;
+ case ';':
+ nextch(); token = SEMI;
+ return;
+ case ',':
+ nextch(); token = COMMA;
+ return;
+ case '(':
+ nextch(); token = LPAREN;
+ return;
+ case '{':
+ nextch(); token = LBRACE;
+ return;
+ case ')':
+ nextch(); token = RPAREN;
+ return;
+ case '}':
+ nextch(); token = RBRACE;
+ return;
+ case '[':
+ nextch(); token = LBRACKET;
+ return;
+ case ']':
+ nextch(); token = RBRACKET;
+ return;
+ case SU:
+ token = EOF;
+ currentSource.lines = cline;
+ return;
+ default:
+ nextch();
+ syntaxError("illegal character");
+ return;
+ }
+ }
+ }
+ }
+
+ private boolean skipComment() {
+ if (ch == '/') {
+ do {
+ nextch();
+ } while ((ch != CR) && (ch != LF) && (ch != SU));
+ return true;
+ } else if (ch == '*') {
+ int openComments = 1;
+ while (openComments > 0) {
+ do {
+ do {
+ if (ch == CR) {
+ cline++;
+ ccol = 0;
+ nextch();
+ if (ch == LF) {
+ ccol = 0;
+ nextch();
+ }
+ } else if (ch == LF) {
+ cline++;
+ ccol = 0;
+ nextch();
+ }
+ else if (ch == '\t') {
+ ccol = ((ccol - 1) / tabinc * tabinc) + tabinc;
+ nextch();
+ } else if (ch == '/') {
+ nextch();
+ if (ch == '*') {
+ nextch();
+ openComments++;
+ }
+ } else {
+ nextch();
+ }
+ } while ((ch != '*') && (ch != SU));
+ while (ch == '*') {
+ nextch();
+ }
+ } while (ch != '/' && ch != SU);
+ if (ch == '/') {
+ nextch();
+ openComments--;
+ } else {
+ syntaxError("unclosed comment");
+ return true;
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private void getIdentRest(int index) {
+ while (true) {
+ switch (ch) {
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y':
+ case 'Z': case '$':
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y':
+ case 'z':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ nextch();
+ break;
+ case '_':
+ nextch();
+ getIdentOrOperatorRest(index);
+ return;
+ default:
+ treatIdent(index, bp);
+ return;
+ }
+ }
+ }
+
+ private void getOperatorRest(int index) {
+ while (true) {
+ switch (ch) {
+ case '~': case '!': case '@': case '#': case '%':
+ case '^': case '*': case '+': case '-': case '<':
+ case '>': case '?': case ':':
+ case '=': case '&': case '|':
+ nextch();
+ break;
+ case '/':
+ int lastbp = bp;
+ nextch();
+ if (skipComment()) {
+ treatIdent(index, lastbp);
+ return;
+ } else {
+ break;
+ }
+ case '_':
+ nextch();
+ getIdentOrOperatorRest(index);
+ return;
+ default:
+ treatIdent(index, bp);
+ return;
+ }
+ }
+ }
+
+ private void getIdentOrOperatorRest(int index) {
+ switch (ch) {
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y':
+ case 'Z': case '$':
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y':
+ case 'z':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ getIdentRest(index);
+ return;
+ case '~': case '!': case '@': case '#': case '%':
+ case '^': case '*': case '+': case '-': case '<':
+ case '>': case '?': case ':':
+ case '=': case '&': case '|':
+ case '/':
+ getOperatorRest(index);
+ return;
+ case '_':
+ nextch();
+ getIdentOrOperatorRest(index);
+ return;
+ default:
+ treatIdent(index, bp);
+ return;
+ }
+ }
+
+ void treatIdent(int start, int end) {
+ name = Name.fromAscii(buf, start, end - start);
+ if (name.index <= maxKey)
+ token = key[name.index];
+ else
+ token = IDENTIFIER;
+ }
+
+ /** generate an error at the given position
+ */
+ void syntaxError(int pos, String msg) {
+ unit.error(pos, msg);
+ token = ERROR;
+ errpos = pos;
+ }
+
+ /** generate an error at the current token position
+ */
+ void syntaxError(String msg) {
+ syntaxError(pos, msg);
+ }
+
+ /** append characteter to "lit" buffer
+ */
+ protected void putch(byte c) {
+ if (litlen == lit.length) {
+ byte[] newlit = new byte[lit.length * 2];
+ System.arraycopy(lit, 0, newlit, 0, lit.length);
+ lit = newlit;
+ }
+ lit[litlen++] = c;
+ }
+
+ /** return true iff next 6 characters are a valid unicode sequence:
+ */
+ protected boolean isUnicode() {
+ return
+ (bp + 6) < buf.length &&
+ (buf[bp] == '\\') &&
+ (buf[bp+1] == 'u') &&
+ (SourceRepresentation.digit2int(buf[bp+2], 16) >= 0) &&
+ (SourceRepresentation.digit2int(buf[bp+3], 16) >= 0) &&
+ (SourceRepresentation.digit2int(buf[bp+4], 16) >= 0) &&
+ (SourceRepresentation.digit2int(buf[bp+5], 16) >= 0);
+ }
+
+ /** read next character in character or string literal:
+ */
+ protected void getlitch() {
+ if (ch == '\\') {
+ if (isUnicode()) {
+ putch(ch); nextch();
+ putch(ch); nextch();
+ putch(ch); nextch();
+ putch(ch); nextch();
+ putch(ch); nextch();
+ putch(ch); nextch();
+ } else {
+ nextch();
+ if ('0' <= ch && ch <= '7') {
+ byte leadch = ch;
+ int oct = SourceRepresentation.digit2int(ch, 8);
+ nextch();
+ if ('0' <= ch && ch <= '7') {
+ oct = oct * 8 + SourceRepresentation.digit2int(ch, 8);
+ nextch();
+ if (leadch <= '3' && '0' <= ch && ch <= '7') {
+ oct = oct * 8 + SourceRepresentation.digit2int(ch, 8);
+ nextch();
+ }
+ }
+ putch((byte)oct);
+ } else if (ch != SU) {
+ switch (ch) {
+ case 'b': case 't': case 'n':
+ case 'f': case 'r': case '\"':
+ case '\'': case '\\':
+ putch((byte)'\\');
+ putch(ch);
+ break;
+ default:
+ syntaxError(Position.encode(cline, ccol, currentSource.id) - 1, "invalid escape character");
+ putch(ch);
+ }
+ nextch();
+ }
+ }
+ } else if (ch != SU) {
+ putch(ch);
+ nextch();
+ }
+ }
+
+ /** read fractional part of floating point number;
+ * Then floatVal := buf[index..], converted to a floating point number.
+ */
+ protected void getFraction(int index) {
+ while (SourceRepresentation.digit2int(ch, 10) >= 0) {
+ nextch();
+ }
+ token = DOUBLELIT;
+ if ((ch == 'e') || (ch == 'E')) {
+ nextch();
+ if ((ch == '+') || (ch == '-')) {
+ byte sign = ch;
+ nextch();
+ if (('0' > ch) || (ch > '9')) {
+ ch = sign;
+ bp--;
+ ccol--;
+ }
+ }
+ while (SourceRepresentation.digit2int(ch, 10) >= 0) {
+ nextch();
+ }
+ }
+ double limit = Double.MAX_VALUE;
+ if ((ch == 'd') || (ch == 'D')) {
+ nextch();
+ } else if ((ch == 'f') || (ch == 'F')) {
+ token = FLOATLIT;
+ limit = Float.MAX_VALUE;
+ nextch();
+ }
+ try {
+ floatVal = Double.valueOf(new String(buf, index, bp - index)).doubleValue();
+ if (floatVal > limit)
+ syntaxError("floating point number too large");
+ } catch (NumberFormatException e) {
+ syntaxError("malformed floating point number");
+ }
+ }
+
+ /** intVal := buf[index..index+len-1], converted to an integer number.
+ * base = the base of the number; one of 8, 10, 16.
+ * max = the maximal number before an overflow.
+ */
+ protected void makeInt (int index, int len, int base, long max) {
+ intVal = 0;
+ int divider = (base == 10 ? 1 : 2);
+ for (int i = 0; i < len; i++) {
+ int d = SourceRepresentation.digit2int(buf[index + i], base);
+ if (d < 0) {
+ syntaxError("malformed integer number");
+ return;
+ }
+ if (intVal < 0 ||
+ max / (base / divider) < intVal ||
+ max - (d / divider) < (intVal * (base / divider) - 0)) {
+ syntaxError("integer number too large");
+ return;
+ }
+ intVal = intVal * base + d;
+ }
+ }
+
+ /** read a number,
+ * and convert buf[index..], setting either intVal or floatVal.
+ * base = the base of the number; one of 8, 10, 16.
+ */
+ protected void getNumber(int index, int base) {
+ while (SourceRepresentation.digit2int(ch, base == 8 ? 10 : base) >= 0) {
+ nextch();
+ }
+ if (base <= 10 && ch == '.') {
+ nextch();
+ if ((ch >= '0') && (ch <= '9'))
+ getFraction(index);
+ else {
+ ch = buf[--bp]; ccol--;
+ makeInt(index, bp - index, base, Integer.MAX_VALUE);
+ intVal = (int)intVal;
+ token = INTLIT;
+ }
+ } else if (base <= 10 &&
+ (ch == 'e' || ch == 'E' ||
+ ch == 'f' || ch == 'F' ||
+ ch == 'd' || ch == 'D'))
+ getFraction(index);
+ else {
+ if (ch == 'l' || ch == 'L') {
+ makeInt(index, bp - index, base, Long.MAX_VALUE);
+ nextch();
+ token = LONGLIT;
+ } else {
+ makeInt(index, bp - index, base, Integer.MAX_VALUE);
+ intVal = (int)intVal;
+ token = INTLIT;
+ }
+ }
+ }
+
+ public int name2token(Name name) {
+ if (name.index <= maxKey)
+ return key[name.index];
+ else
+ return IDENTIFIER;
+ }
+
+ public String token2string(int token) {
+ switch (token) {
+ case IDENTIFIER:
+ return "identifier";
+ case CHARLIT:
+ return "character literal";
+ case INTLIT:
+ return "integer literal";
+ case LONGLIT:
+ return "long literal";
+ case FLOATLIT:
+ return "float literal";
+ case DOUBLELIT:
+ return "double literal";
+ case STRINGLIT:
+ return "string literal";
+ case LPAREN:
+ return "'('";
+ case RPAREN:
+ return "')'";
+ case LBRACE:
+ return "'{'";
+ case RBRACE:
+ return "'}'";
+ case LBRACKET:
+ return "'['";
+ case RBRACKET:
+ return "']'";
+ case EOF:
+ return "eof";
+ case ERROR:
+ return "something";
+ case SEMI:
+ return "';'";
+ case COMMA:
+ return "','";
+ default:
+ try {
+ return "'" + tokenName[token].toString() + "'";
+ } catch (ArrayIndexOutOfBoundsException e) {
+ return "'<" + token + ">'";
+ }
+ }
+ }
+
+ public String toString() {
+ switch (token) {
+ case IDENTIFIER:
+ return "id(" + name + ")";
+ case CHARLIT:
+ return "char(" + intVal + ")";
+ case INTLIT:
+ return "int(" + intVal + ")";
+ case LONGLIT:
+ return "long(" + intVal + ")";
+ case FLOATLIT:
+ return "float(" + floatVal + ")";
+ case DOUBLELIT:
+ return "double(" + floatVal + ")";
+ case STRINGLIT:
+ return "string(" + name + ")";
+ case SEMI:
+ return ";";
+ case COMMA:
+ return ",";
+ default:
+ return token2string(token);
+ }
+ }
+
+ protected void enterKeyword(String s, int tokenId) {
+ while (tokenId > tokenName.length) {
+ Name[] newTokName = new Name[tokenName.length * 2];
+ System.arraycopy(tokenName, 0, newTokName, 0, newTokName.length);
+ tokenName = newTokName;
+ }
+ Name n = Name.fromString(s);
+ tokenName[tokenId] = n;
+ if (n.index > maxKey)
+ maxKey = n.index;
+ if (tokenId >= numToken)
+ numToken = tokenId + 1;
+ }
+
+ protected void init() {
+ initKeywords();
+ key = new byte[maxKey+1];
+ for (int i = 0; i <= maxKey; i++)
+ key[i] = IDENTIFIER;
+ for (byte j = 0; j < numToken; j++)
+ if (tokenName[j] != null)
+ key[tokenName[j].index] = j;
+ }
+
+ protected void initKeywords() {
+ enterKeyword("if", IF);
+ enterKeyword("for", FOR);
+ enterKeyword("else", ELSE);
+ enterKeyword("this", THIS);
+ enterKeyword("null", NULL);
+ enterKeyword("new", NEW);
+ enterKeyword("with", WITH);
+ enterKeyword("super", SUPER);
+ enterKeyword("case", CASE);
+ enterKeyword("val", VAL);
+ enterKeyword("abstract", ABSTRACT);
+ enterKeyword("final", FINAL);
+ enterKeyword("private", PRIVATE);
+ enterKeyword("protected", PROTECTED);
+ enterKeyword("qualified", QUALIFIED);
+ enterKeyword("override", OVERRIDE);
+ enterKeyword("var", VAR);
+ enterKeyword("def", DEF);
+ enterKeyword("type", TYPE);
+ enterKeyword("extends", EXTENDS);
+ enterKeyword("let", LET);
+ enterKeyword("module", MODULE);
+ enterKeyword("class",CLASS);
+ enterKeyword("constr",CONSTR);
+ enterKeyword("import", IMPORT);
+ enterKeyword("package", PACKAGE);
+ enterKeyword(".", DOT);
+ enterKeyword("_", USCORE);
+ enterKeyword(":", COLON);
+ enterKeyword("=", EQUALS);
+ enterKeyword("=>", ARROW);
+ enterKeyword("<-", LARROW);
+ enterKeyword("<:", SUBTYPE);
+ enterKeyword("yield", YIELD);
+ enterKeyword("do", DO);
+ enterKeyword("@", AT);
+ enterKeyword("#", HASH);
+ enterKeyword("trait", TRAIT);
+ enterKeyword("as", AS);
+ enterKeyword("is", IS);
+ }
+}
+
+
diff --git a/sources/scalac/ast/parser/SourceRepresentation.java b/sources/scalac/ast/parser/SourceRepresentation.java
new file mode 100644
index 0000000000..2a20e13fab
--- /dev/null
+++ b/sources/scalac/ast/parser/SourceRepresentation.java
@@ -0,0 +1,205 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id
+\* */
+
+package scalac.ast.parser;
+
+public final class SourceRepresentation {
+
+ public static int digit2int(byte ch, int base) {
+ if ('0' <= ch && ch <= '9' && ch < '0' + base)
+ return ch - '0';
+ else if ('A' <= ch && ch < 'A' + base - 10)
+ return ch - 'A' + 10;
+ else if ('a' <= ch && ch < 'a' + base - 10)
+ return ch - 'a' + 10;
+ else
+ return -1;
+ }
+
+ public static byte int2digit(int x) {
+ if (x <= 9)
+ return (byte)(x + '0');
+ else
+ return (byte)(x - 10 + 'A');
+ }
+
+/* the next 4 functions convert between three fundamental name
+ * representations:
+ * - string each character 16 bit,
+ * - source characters outside 0..127 are represented by
+ * unicode escapes, \ u X X X X
+ * - ascii characters outside 0..127 are represented by two or three
+ * byte sequences with high bit set (as in class file format).
+ */
+
+/** convert source bytes in source[offset..offset+len-1] to ascii.
+ */
+ public static int source2ascii(byte source[], int offset, int len, byte ascii[]) {
+ int j = 0;
+ int i = 0;
+ while (i < len) {
+ if (source[offset + i] == '\\' && i + 1 < len) {
+ i++;
+ switch (source[offset + i]) {
+ case 'n':
+ ascii[j++] = (byte)'\n'; i++; continue;
+ case 't':
+ ascii[j++] = (byte)'\t'; i++; continue;
+ case 'b':
+ ascii[j++] = (byte)'\b'; i++; continue;
+ case 'r':
+ ascii[j++] = (byte)'\r'; i++; continue;
+ case 'f':
+ ascii[j++] = (byte)'\f'; i++; continue;
+ case 'u':
+ if (i + 4 < len) {
+ int code = 0;
+ int k = 1;
+ int d = 0;
+ while (k <= 4 && d >= 0) {
+ d = digit2int(source[offset + i + k], 16);
+ code = code * 16 + d;
+ k++;
+ }
+ if (d >= 0) {
+ if (code <= 0x7F)
+ ascii[j++] = (byte)code;
+ else
+ if (code <= 0x3FF) {
+ ascii[j++] = (byte)(0xC0 | (code >> 6));
+ ascii[j++] = (byte)(0x80 | (code & 0x3F));
+ } else {
+ ascii[j++] = (byte)(0xE0 | (code >> 12));
+ ascii[j++] = (byte)(0x80 |
+ ((code >> 6) & 0x3F));
+ ascii[j++] = (byte)(0x80 | (code & 0x3F));
+ }
+ i = i + 5;
+ continue;
+ }
+ }
+ }
+ }
+ byte b = source[offset + i++];
+ if (b >= 0)
+ ascii[j++] = b;
+ else {
+ ascii[j++] = (byte)(0xC0 | ((b >> 6) & 0x3));
+ ascii[j++] = (byte)(0x80 | (b & 0x3F));
+ }
+ }
+ return j;
+ }
+
+/** convert ascii bytes in ascii[offset..offset+len-1] to a string
+ */
+ public static String ascii2string(byte ascii[], int offset, int len) {
+ char cs[] = new char[len];
+ int i = offset;
+ int j = 0;
+ len += offset;
+ while (i < len) {
+ int b = ascii[i++] & 0xFF;
+ if (b >= 0xE0) {
+ b = ((b & 0x0F) << 12) | (ascii[i++] & 0x3F) << 6;
+ b = b | (ascii[i++] & 0x3F);
+ }
+ else
+ if (b >= 0xC0)
+ b = ((b & 0x1F) << 6) | (ascii[i++] & 0x3F);
+ cs[j++] = (char)b;
+ }
+ return new String(cs, 0, j);
+ }
+
+/** convert string to array of source bytes
+ */
+ public static byte[] string2source(String s) {
+ byte[] source = new byte[s.length() * 6];
+ int j = 0;
+ for (int i = 0; i < s.length(); i++) {
+ char ch = s.charAt(i);
+ switch (ch) {
+ case '\n':
+ source[j++] = (byte)'\\';
+ source[j++] = (byte)'n';
+ break;
+ case '\t':
+ source[j++] = (byte)'\\';
+ source[j++] = (byte)'t';
+ break;
+ case '\b':
+ source[j++] = (byte)'\\';
+ source[j++] = (byte)'b';
+ break;
+ case '\r':
+ source[j++] = (byte)'\\';
+ source[j++] = (byte)'r';
+ break;
+ case '\f':
+ source[j++] = (byte)'\\';
+ source[j++] = (byte)'f';
+ break;
+ case '\"':
+ source[j++] = (byte)'\\';
+ source[j++] = (byte)'\"';
+ break;
+ case '\'':
+ source[j++] = (byte)'\\';
+ source[j++] = (byte)'\'';
+ break;
+ case '\\':
+ source[j++] = (byte)'\\';
+ source[j++] = (byte)'\\';
+ break;
+ default:
+ if ((' ' <= ch) && (ch <= 127))
+ source[j++] = (byte)ch;
+ else {
+ source[j++] = (byte)'\\';
+ source[j++] = (byte)'u';
+ source[j++] = int2digit((ch >> 12) & 0xF);
+ source[j++] = int2digit((ch >> 8) & 0xF);
+ source[j++] = int2digit((ch >> 4) & 0xF);
+ source[j++] = int2digit(ch & 0xF);
+ }
+ }
+ }
+ byte[] res = new byte[j];
+ System.arraycopy(source, 0, res, 0, j);
+ return res;
+ }
+
+/** convert string to array of ascii bytes
+ */
+ public static byte[] string2ascii(String s) {
+ byte[] source = string2source(s);
+ byte[] ascii = new byte[source.length * 2];
+ int alen = source2ascii(source, 0, source.length, ascii);
+ byte[] res = new byte[alen];
+ System.arraycopy(ascii, 0, res, 0, alen);
+ return res;
+ }
+
+/** escape all characters outside 32..127 in string s
+ */
+ public static String escape(String s) {
+ try {
+ return new String(string2source(s), "8859_1");
+ } catch (java.io.UnsupportedEncodingException e) {
+ throw new InternalError(e.getMessage());
+ }
+ }
+
+/** escape character c, if outside 32..127.
+ */
+ public static String escape(char c) {
+ char[] s = {c};
+ return escape(new String(s));
+ }
+}
diff --git a/sources/scalac/ast/parser/Sourcefile.java b/sources/scalac/ast/parser/Sourcefile.java
new file mode 100644
index 0000000000..91277f9ac8
--- /dev/null
+++ b/sources/scalac/ast/parser/Sourcefile.java
@@ -0,0 +1,304 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast.parser;
+
+import java.io.*;
+import java.util.Hashtable;
+import scalac.util.AbstractFile;
+import scalac.util.Name;
+import scalac.util.Position;
+
+
+/** This class represents a single scala source file. It provides
+ * functionality to read the file and to output error messages on
+ * a given line and column. Error messages are logged to
+ * decouple the time where an error message is issued from the
+ * time where the error messages are displayed.
+ *
+ * @author Matthias Zenger
+ * @version 1.0
+ */
+public class Sourcefile {
+
+ /** the id management
+ */
+ public static int numIds = 1;
+ public static String[] files = new String[]{"console", null, null, null};
+ public static Sourcefile[] sources = new Sourcefile[]{null, null, null, null};
+ public int id;
+
+ /** the filename
+ */
+ public final boolean console;
+ protected String filename;
+ public String shortname;
+ public String pathname;
+
+ /** the encoding of the file
+ */
+ protected String encoding;
+
+ /** a log of all errors generated so far; used to avoid printing an
+ * error message more than once
+ */
+ protected Hashtable recorded = new Hashtable();
+
+ /** the buffer containing the file that is currently translated
+ */
+ protected byte[] buf = null;
+
+ /** the last error position
+ */
+ protected int lastLine = 0;
+ protected int lastPos = 0;
+ protected int lineEnd = 0;
+ protected int newPos = 0;
+
+ /** constants used for source parsing
+ */
+ final static byte LF = 0xA;
+ final static byte FF = 0xC;
+ final static byte CR = 0xD;
+ final static byte SU = 0x1A;
+
+ /** set col to NO_COLUMN, if the printLine method should not mark
+ * the column
+ */
+ final static int NO_COLUMN = -1;
+
+ /** number of lines and bytes (not used internally)
+ */
+ public int lines; // set externally
+ public int bytes;
+
+ /** prompt after error?
+ */
+ public boolean prompt;
+
+ /** constructors
+ */
+ public Sourcefile(String filename, boolean console) throws IOException, FileNotFoundException {
+ this.console = console;
+ if (filename == null) {
+ this.filename = "(sourcefile not available)";
+ this.shortname = "?";
+ this.pathname = "?";
+ buf = new byte[]{SU};
+ } else {
+ File f = new File(filename);
+ this.filename = filename;
+ this.shortname = f.getName();
+ this.pathname = f.getAbsoluteFile().getParentFile().
+ getCanonicalPath();
+ fillBuffer(new FileInputStream(f));
+ }
+ if (numIds == files.length) {
+ String[] newfiles = new String[numIds * 2];
+ System.arraycopy(files, 0, newfiles, 0, numIds);
+ files = newfiles;
+ Sourcefile[] newsources = new Sourcefile[numIds * 2];
+ System.arraycopy(sources, 0, newsources, 0, numIds);
+ sources = newsources;
+ }
+ sources[numIds] = this;
+ files[id = numIds++] = shortname;
+ }
+
+ public Sourcefile(AbstractFile abs) throws IOException, FileNotFoundException {
+ this.console = false;
+ if (filename == null) {
+ this.filename = "(sourcefile not available)";
+ this.shortname = "?";
+ this.pathname = "?";
+ buf = new byte[]{SU};
+ } else {
+ this.filename = abs.getPath();
+ this.shortname = abs.getName();
+ this.pathname = abs.getPath();
+ fillBuffer(abs.getInputStream());
+ }
+ if (numIds == files.length) {
+ String[] newfiles = new String[numIds * 2];
+ System.arraycopy(files, 0, newfiles, 0, numIds);
+ files = newfiles;
+ Sourcefile[] newsources = new Sourcefile[numIds * 2];
+ System.arraycopy(sources, 0, newsources, 0, numIds);
+ sources = newsources;
+ }
+ sources[numIds] = this;
+ files[id = numIds++] = shortname;
+ }
+
+ public Sourcefile(byte[] input, boolean console) {
+ this.console = console;
+ if (input == null) {
+ this.filename = "(sourcefile not available)";
+ this.shortname = "?";
+ this.pathname = "?";
+ buf = new byte[]{SU};
+ } else {
+ this.filename = "console";
+ this.shortname = "console";
+ this.pathname = "console";
+ buf = new byte[input.length + 2];
+ System.arraycopy(input, 0, buf, 0, input.length);
+ buf[input.length] = Scanner.LF;
+ buf[input.length + 1] = SU;
+ }
+ sources[0] = this;
+ id = 0;
+ }
+
+ /** fill the buffer using the InputStream
+ */
+ private void fillBuffer(InputStream in) throws IOException {
+ try {
+ buf = new byte[(bytes = in.available()) + 1];
+ if (in.read(buf) != (buf.length - 1))
+ throw new IOException();
+ in.close();
+ buf[buf.length - 1] = SU;
+ } catch (IOException e) {
+ throw new IOException("cannot read '" + filename + "'");
+ }
+ }
+
+ /** return filename as a string
+ */
+ public String toString() {
+ return filename;
+ }
+
+ /** return filename as a name
+ */
+ public Name getName() {
+ return Name.fromString(filename);
+ }
+
+ /** return the shortname without the suffix
+ */
+ public String getShortnameWithoutSuffix() {
+ int idx = shortname.lastIndexOf('.');
+ if (idx < 0)
+ return shortname;
+ else
+ return shortname.substring(0, idx);
+ }
+
+ /** return the source buffer of this file
+ */
+ public byte[] getBuffer() {
+ return buf;
+ }
+
+ /** number of logged entries
+ */
+ public int logged() {
+ return recorded.size();
+ }
+
+ /** is there already an entry at position 'pos'
+ */
+ public boolean isLogged(int pos) {
+ return (recorded.get(new Integer(pos)) != null);
+ }
+
+ /** enter entry into log table
+ */
+ public void log(int pos, String message) {
+ recorded.put(new Integer(pos), message);
+ }
+
+ /** set encoding of the file
+ */
+ public void setEncoding(String encoding) {
+ this.encoding = encoding;
+ }
+
+ /** return true if there is an entry for this position,
+ * otherwise return false and enter message into log
+ */
+ public boolean testAndSetLog(int pos, String message) {
+ if (!isLogged(pos)) {
+ log(pos, message);
+ return false;
+ }
+ return true;
+ }
+
+ /** get error message with line from sourcefile
+ */
+ public String getMessage(int pos, String message) {
+ if (pos == Position.NOPOS)
+ return filename + ": " + message;
+ else {
+ int fileId = Position.file(pos);
+ String filename = files[fileId];
+ int line = Position.line(pos);
+ int col = Position.column(pos);
+ String main = filename + ":" + line + ": " + message;
+ if ((fileId > 0) &&
+ (fileId < numIds) &&
+ (sources[fileId] != null))
+ return main + '\n' + sources[fileId].getLine(line, col);
+ else
+ return main;
+ //else
+ // System.out.println("(source file not available anymore)");
+ }
+ }
+
+ /** get source line
+ */
+ public String getLine(int line, int col) {
+ int pos = 0;
+ if (lastLine > line)
+ lastLine = 0;
+ else
+ pos = newPos;
+ while ((pos < buf.length) && (lastLine < line))
+ {
+ lastPos = pos;
+ while ((pos < buf.length) && (buf[pos] != CR) &&
+ (buf[pos] != LF) && (buf[pos] != FF))
+ pos++;
+ lineEnd = pos;
+ if (pos < buf.length)
+ pos++;
+ if ((pos < buf.length) && (buf[pos-1] == CR) && (buf[pos] == LF))
+ pos++;
+ lastLine++;
+ }
+ newPos = pos;
+ try
+ {
+ String errline = (encoding != null) ?
+ new String(buf, lastPos, lineEnd - lastPos, encoding) :
+ new String(buf, lastPos, lineEnd - lastPos);
+ if (col != NO_COLUMN)
+ {
+ byte[] ptr = new byte[col];
+ for (int i = col - 2; i >= 0; i--)
+ ptr[i] = (byte)' ';
+ ptr[col - 1] = (byte)'^';
+ return errline + '\n' + new String(ptr);
+ } else
+ return errline;
+ } catch (UnsupportedEncodingException e) {
+ throw new InternalError(e.getMessage());
+ }
+ }
+
+ /** release all sourcefile objects
+ */
+ public static void flushSources() {
+ for (int i = 0; i < sources.length; i++)
+ sources[i] = null;
+ }
+}
diff --git a/sources/scalac/ast/parser/TokenData.java b/sources/scalac/ast/parser/TokenData.java
new file mode 100644
index 0000000000..d6bcac6c1c
--- /dev/null
+++ b/sources/scalac/ast/parser/TokenData.java
@@ -0,0 +1,44 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast.parser;
+
+import scalac.util.Name;
+
+/** A class for representing a token's data.
+ *
+ * @author Matthias Zenger
+ * @version 1.0
+ */
+public class TokenData implements Tokens {
+
+ /** the next token
+ */
+ public int token = EMPTY;
+
+ /** the token's position. pos = line << Position.LINESHIFT + col
+ */
+ public int pos = 0;
+
+ /** the name of an identifier or token
+ */
+ public Name name;
+
+ /** the value of a number
+ */
+ public long intVal;
+ public double floatVal;
+
+ public void copyFrom(TokenData td) {
+ this.token = td.token;
+ this.pos = td.pos;
+ this.name = td.name;
+ this.intVal = td.intVal;
+ this.floatVal = td.floatVal;
+ }
+}
diff --git a/sources/scalac/ast/parser/Tokens.java b/sources/scalac/ast/parser/Tokens.java
new file mode 100644
index 0000000000..6c3bef6a55
--- /dev/null
+++ b/sources/scalac/ast/parser/Tokens.java
@@ -0,0 +1,84 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+** $Id$
+\* */
+
+package scalac.ast.parser;
+
+public interface Tokens {
+ byte EMPTY = -3,
+ UNDEF = -2,
+ ERROR = -1,
+ EOF = 0,
+
+ /* literals */
+ CHARLIT = 1,
+ INTLIT = 2,
+ LONGLIT = 3,
+ FLOATLIT = 4,
+ DOUBLELIT = 5,
+ STRINGLIT = 6,
+
+ /* identifier */
+ IDENTIFIER = 10,
+
+ /* keywords */
+ IF = 20,
+ FOR = 21,
+ ELSE = 22,
+ THIS = 23,
+ NULL = 24,
+ NEW = 25,
+ WITH = 26,
+ SUPER = 27,
+ CASE = 28,
+ CASECLASS = 29,
+ VAL = 30,
+ ABSTRACT = 31,
+ FINAL = 32,
+ PRIVATE = 33,
+ PROTECTED = 34,
+ QUALIFIED = 35,
+ OVERRIDE = 36,
+ VAR = 37,
+ DEF = 38,
+ TYPE = 39,
+ EXTENDS = 40,
+ LET = 41,
+ MODULE = 43,
+ CLASS = 44,
+ CONSTR = 45,
+ IMPORT = 46,
+ PACKAGE = 47,
+ AS = 48,
+ IS = 49,
+ YIELD = 50,
+ DO = 51,
+ TRAIT = 52,
+
+ /* special symbols */
+ COMMA = 61,
+ SEMI = 62,
+ DOT = 63,
+ USCORE = 64,
+ COLON = 65,
+ EQUALS = 66,
+ LARROW = 57,
+ ARROW = 68,
+ SUBTYPE = 69,
+ AT = 70,
+ HASH = 71,
+
+ /* parenthesis */
+ LPAREN = 90,
+ RPAREN = 91,
+ LBRACKET = 92,
+ RBRACKET = 93,
+ LBRACE = 94,
+ RBRACE = 95;
+}
+
+
diff --git a/sources/scalac/ast/printer/HTMLTreePrinter.java b/sources/scalac/ast/printer/HTMLTreePrinter.java
new file mode 100644
index 0000000000..8dbd34f2a0
--- /dev/null
+++ b/sources/scalac/ast/printer/HTMLTreePrinter.java
@@ -0,0 +1,173 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+\* */
+
+// $Id$
+
+package scalac.ast.printer;
+
+import scalac.Unit;
+import scalac.symtab.Symbol;
+
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.lang.Math;
+import java.util.HashMap;
+
+/**
+ * HTML pretty printer for Scala abstract syntax trees.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+
+public class HTMLTreePrinter extends TextTreePrinter {
+ protected int outSectionLevel = 1;
+ protected boolean started = false;
+
+ public HTMLTreePrinter(OutputStream stream) {
+ super(stream);
+ }
+
+ public void begin() {
+ assert !started;
+
+ super.begin();
+ out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
+ out.println("<html>");
+ out.println("<head>");
+ out.println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">");
+ out.println("<link rel=\"stylesheet\" href=\"scala.css\" type=\"text/css\">");
+ out.println("<title>Scala tree</title>");
+ out.println("</head>");
+ out.println("<body>");
+
+ started = true;
+ }
+
+ public void end() {
+ assert started;
+
+ out.println("</body>");
+ out.println("</html>");
+ super.end();
+
+ started = false;
+ }
+
+ public void beginSection(int level, String title) {
+ outSectionLevel = Math.min(level, 4);
+ beginSection1(outSectionLevel, title);
+ }
+
+ protected void beginSection1(int level, String title) {
+ if (level == 1)
+ out.println("<hr/>");
+ String tag = "h" + level;
+ startTag(tag);
+ print(Text.Simple(title));
+ endTag(tag);
+ }
+
+ protected void startTag(String tag) {
+ out.print('<'); out.print(tag); out.print('>');
+ }
+
+ protected void startTag(String tag, String attr1, String val1) {
+ out.print('<');
+ out.print(tag);
+ out.print(' ');
+ out.print(attr1);
+ out.print("=\"");
+ out.print(val1);
+ out.print("\">");
+ }
+
+ protected void endTag(String tag) {
+ out.print("</"); out.print(tag); out.print(">");
+ }
+
+ protected void startSpan(String cls) {
+ startTag("span", "class", cls);
+ }
+
+ protected void endSpan() {
+ endTag("span");
+ }
+
+ protected void printString(String str) {
+ StringBuffer buf = null;
+ int strLen = str.length();
+
+ for (int i = 0; i < strLen; ++i) {
+ String entity;
+ char c = str.charAt(i);
+ switch (c) {
+ case '<': entity = "lt"; break;
+ case '>': entity = "gt"; break;
+ case '&': entity = "amp"; break;
+ default: entity = null; break;
+ }
+ if (entity != null) {
+ out.print('&');
+ out.print(entity);
+ out.print(';');
+ } else
+ out.print(c);
+ }
+ }
+
+ protected static HashMap/*<Symbol,Integer>*/ symAnchors = new HashMap();
+ protected String symbolAnchor(Symbol sym, SymbolUsage usage) {
+ Integer anchorId = (Integer)symAnchors.get(sym);
+ if (anchorId == null) {
+ anchorId = new Integer(symAnchors.size());
+ symAnchors.put(sym, anchorId);
+ }
+ if (usage == SymbolUsage.Definition)
+ return anchorId.toString();
+ else
+ return "#" + anchorId.toString();
+ }
+
+ protected void print(Text text) {
+ switch (text) {
+ case Keyword(String name):
+ startSpan("kw");
+ printString(name);
+ endSpan();
+ break;
+ case Literal(String str):
+ startSpan("lit");
+ printString(str);
+ endSpan();
+ break;
+ case Identifier(Symbol symbol, String name, SymbolUsage usage):
+ boolean defined = (usage == SymbolUsage.Definition);
+ if (defined) startSpan("idDef");
+ if (symbol != null) {
+ String attr = (defined ? "name" : "href");
+ startTag("a", attr, symbolAnchor(symbol, usage));
+ }
+ printString(name);
+ if (symbol != null)
+ endTag("a");
+ if (defined) endSpan();
+ break;
+ default:
+ super.print(text);
+ }
+ }
+
+ protected void printUnitHeader(Unit unit) {
+ beginSection1(outSectionLevel + 1, unit.source.toString());
+ startTag("pre");
+ }
+
+ protected void printUnitFooter(Unit unit) {
+ endTag("pre");
+ }
+}
diff --git a/sources/scalac/ast/printer/TextTreePrinter.java b/sources/scalac/ast/printer/TextTreePrinter.java
new file mode 100644
index 0000000000..c5138d025f
--- /dev/null
+++ b/sources/scalac/ast/printer/TextTreePrinter.java
@@ -0,0 +1,683 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+** **
+\* */
+
+// $Id$
+
+package scalac.ast.printer;
+
+import scalac.ast.*;
+import scalac.symtab.*;
+import scalac.util.Debug;
+import scalac.Global;
+import scalac.Unit;
+import scalac.util.Name;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Text pretty printer for Scala abstract syntax trees.
+ *
+ * @author Michel Schinz, Matthias Zenger
+ * @version 1.0
+ */
+public class TextTreePrinter implements TreePrinter {
+ protected PrintWriter out;
+
+ protected int indent = 0;
+ protected final int INDENT_STEP = 2;
+ protected final String INDENT_STRING =
+ " ";
+ protected final int MAX_INDENT = INDENT_STRING.length();
+
+ public TextTreePrinter(OutputStream stream) {
+ out = new PrintWriter(stream);
+ }
+
+ public TextTreePrinter() {
+ this(System.out);
+ }
+
+ public void begin() { }
+
+ public void end() {
+ out.flush();
+ }
+
+ public void flush() {
+ out.flush();
+ }
+
+ public TreePrinter print(String str) {
+ out.print(str);
+ return this;
+ }
+
+ public TreePrinter println() {
+ out.println();
+ return this;
+ }
+
+ public void beginSection(int level, String title) {
+ out.println("[[" + title + "]]");
+ out.flush();
+ }
+
+ protected void indent() {
+ indent += Math.min(MAX_INDENT, INDENT_STEP);
+ }
+
+ protected void undent() {
+ indent -= Math.max(0, INDENT_STEP);
+ }
+
+ protected void printString(String str) {
+ out.print(str);
+ }
+
+ protected void printNewLine() {
+ out.println();
+ if (indent > 0)
+ out.write(INDENT_STRING, 0, indent);
+ }
+
+ public static class SymbolUsage {
+ public case Definition;
+ public case Use;
+ }
+
+ public static class Text {
+ public case None;
+ public case Space;
+ public case Newline;
+ public case Simple(String str);
+ public case Literal(String str);
+ public case Keyword(String name);
+ public case Identifier(Symbol symbol, String name, SymbolUsage usage);
+ public case Sequence(Text[] elements);
+ }
+
+ protected void print(Text text) {
+ switch (text) {
+ case None : break;
+ case Space : printString(" "); break;
+ case Newline : printNewLine(); break;
+ case Simple(String str) : printString(str); break;
+ case Literal(String str) : printString(str); break;
+ case Keyword(String name) : printString(name); break;
+ case Identifier(Symbol sym, String name, _) :
+ printString(name);
+ if (sym != null && Global.instance.uniqid)
+ printString("#" + Global.instance.uniqueID.id(sym));
+ break;
+ case Sequence(Text[] elements) : print(elements); break;
+ }
+ }
+
+ protected void print(Text[] texts) {
+ for (int i = 0; i < texts.length; ++i)
+ print(texts[i]);
+ }
+
+ protected static final Text KW_ABSTRACT = Text.Keyword("abstract");
+ protected static final Text KW_CASE = Text.Keyword("case");
+ protected static final Text KW_CLASS = Text.Keyword("class");
+ protected static final Text KW_CONSTR = Text.Keyword("constr");
+ protected static final Text KW_DEF = Text.Keyword("def");
+ protected static final Text KW_DO = Text.Keyword("do");
+ protected static final Text KW_ELSE = Text.Keyword("else");
+ protected static final Text KW_EXTENDS = Text.Keyword("extends");
+ protected static final Text KW_FINAL = Text.Keyword("final");
+ protected static final Text KW_FOR = Text.Keyword("for");
+ protected static final Text KW_IF = Text.Keyword("if");
+ protected static final Text KW_IMPORT = Text.Keyword("import");
+ protected static final Text KW_INTERFACE = Text.Keyword("interface");
+ protected static final Text KW_LET = Text.Keyword("let");
+ protected static final Text KW_MODULE = Text.Keyword("module");
+ protected static final Text KW_NEW = Text.Keyword("new");
+ protected static final Text KW_NULL = Text.Keyword("null");
+ protected static final Text KW_OUTER = Text.Keyword("outer");
+ protected static final Text KW_OVERRIDE = Text.Keyword("override");
+ protected static final Text KW_PACKAGE = Text.Keyword("package");
+ protected static final Text KW_PRIVATE = Text.Keyword("private");
+ protected static final Text KW_PROTECTED = Text.Keyword("protected");
+ protected static final Text KW_QUALIFIED = Text.Keyword("qualified");
+ protected static final Text KW_STATIC = Text.Keyword("static");
+ protected static final Text KW_SUPER = Text.Keyword("super");
+ protected static final Text KW_THIS = Text.Keyword("this");
+ protected static final Text KW_TYPE = Text.Keyword("type");
+ protected static final Text KW_VAL = Text.Keyword("val");
+ protected static final Text KW_VAR = Text.Keyword("var");
+ protected static final Text KW_WITH = Text.Keyword("with");
+ protected static final Text KW_YIELD = Text.Keyword("yield");
+
+ protected static final Text TXT_ERROR = Text.Simple("<error>");
+ protected static final Text TXT_UNKNOWN = Text.Simple("<unknown>");
+ protected static final Text TXT_NULL = Text.Simple("<null>");
+ protected static final Text TXT_MODULE_COMMENT
+ = Text.Simple("/*module*/ ");
+ protected static final Text TXT_EMPTY = Text.Simple("<empty>");
+
+ protected static final Text TXT_QUOTE = Text.Simple("\"");
+ protected static final Text TXT_PLUS = Text.Simple("+");
+ protected static final Text TXT_COLON = Text.Simple(":");
+ protected static final Text TXT_SEMICOLON = Text.Simple(";");
+ protected static final Text TXT_DOT = Text.Simple(".");
+ protected static final Text TXT_COMMA = Text.Simple(",");
+ protected static final Text TXT_EQUAL = Text.Simple("=");
+ protected static final Text TXT_SUBTYPE = Text.Simple("<:");
+ protected static final Text TXT_AT = Text.Simple("@");
+ protected static final Text TXT_HASH = Text.Simple("#");
+ protected static final Text TXT_RIGHT_ARROW = Text.Simple("=>");
+ protected static final Text TXT_LEFT_PAREN = Text.Simple("(");
+ protected static final Text TXT_RIGHT_PAREN = Text.Simple(")");
+ protected static final Text TXT_LEFT_BRACE = Text.Simple("{");
+ protected static final Text TXT_RIGHT_BRACE = Text.Simple("}");
+ protected static final Text TXT_LEFT_BRACKET = Text.Simple("[");
+ protected static final Text TXT_RIGHT_BRACKET = Text.Simple("]");
+
+ protected static final Text TXT_WITH_BLOCK_BEGIN =
+ Text.Sequence(new Text[] {
+ Text.Space, KW_WITH, Text.Space, TXT_LEFT_BRACE, Text.Newline
+ });
+ protected static final Text TXT_WITH_SP =
+ Text.Sequence(new Text[]{ Text.Space, KW_WITH, Text.Space });
+ protected static final Text TXT_BLOCK_BEGIN =
+ Text.Sequence(new Text[]{ TXT_LEFT_BRACE, Text.Newline });
+ protected static final Text TXT_BLOCK_END =
+ Text.Sequence(new Text[]{ Text.Newline, TXT_RIGHT_BRACE });
+ protected static final Text TXT_BLOCK_SEP =
+ Text.Sequence(new Text[]{ TXT_SEMICOLON, Text.Newline });
+ protected static final Text TXT_COMMA_SP =
+ Text.Sequence(new Text[]{ TXT_COMMA, Text.Space });
+ protected static final Text TXT_ELSE_NL =
+ Text.Sequence(new Text[]{ KW_ELSE, Text.Newline });
+
+ public void print(Unit unit) {
+ printUnitHeader(unit);
+ if (unit.body != null) {
+ for (int i = 0; i < unit.body.length; ++i) {
+ print(unit.body[i]);
+ print(TXT_BLOCK_SEP);
+ }
+ } else
+ print(TXT_NULL);
+ printUnitFooter(unit);
+
+ out.flush();
+ }
+
+ protected void printUnitHeader(Unit unit) {
+ print(Text.Simple("// Scala source: " + unit.source + "\n"));
+ }
+
+ protected void printUnitFooter(Unit unit) {
+ print(Text.Newline);
+ }
+
+ public TreePrinter print(Tree tree) {
+ switch (tree) {
+ case Bad():
+ print(TXT_ERROR);
+ break;
+
+ case Empty:
+ print(TXT_EMPTY);
+ break;
+
+ case ClassDef(int mods, // :
+ Name name,
+ Tree.TypeDef[] tparams,
+ Tree.ValDef[][] vparams,
+ Tree tpe,
+ Tree.Template impl):
+ printModifiers(mods);
+ print((mods & Modifiers.INTERFACE) != 0
+ ? KW_INTERFACE
+ : KW_CLASS);
+ print(Text.Space);
+ printSymbolDefinition(tree.symbol(), name);
+ printParams(tparams);
+ printParams(vparams);
+ printOpt(TXT_COLON, tpe, false);
+ printTemplate(KW_EXTENDS, impl, true);
+ break;
+
+ case PackageDef(Tree packaged, Tree.Template impl):
+ print(KW_PACKAGE);
+ print(Text.Space);
+ print(packaged);
+ print(Text.Space);
+ printTemplate(KW_WITH, impl, true);
+ break;
+
+ case ModuleDef(int mods, // :
+ Name name,
+ Tree tpe,
+ Tree.Template impl):
+ printModifiers(mods);
+ print(KW_MODULE);
+ print(Text.Space);
+ printSymbolDefinition(tree.symbol(), name);
+ printOpt(TXT_COLON, tpe, false);
+ printTemplate(KW_EXTENDS, impl, true);
+ break;
+
+ case ValDef(int mods, Name name, Tree tpe, Tree rhs):
+ printModifiers(mods);
+ if ((mods & Modifiers.MUTABLE) != 0) print(KW_VAR);
+ else {
+ if ((mods & Modifiers.MODUL) != 0) print(TXT_MODULE_COMMENT);
+ print(KW_VAL);
+ }
+ print(Text.Space);
+ printSymbolDefinition(tree.symbol(), name);
+ printOpt(TXT_COLON, tpe, false);
+ printOpt(TXT_EQUAL, rhs, true);
+ break;
+
+ case PatDef(int mods, Tree pat, Tree rhs):
+ printModifiers(mods);
+ print(KW_VAL);
+ print(Text.Space);
+ print(pat);
+ printOpt(TXT_EQUAL, rhs, true);
+ break;
+
+ case DefDef(int mods,
+ Name name,
+ Tree.TypeDef[] tparams,
+ Tree.ValDef[][] vparams,
+ Tree tpe,
+ Tree rhs):
+ printModifiers(mods);
+ if (name.isConstrName()) print(KW_CONSTR); else print(KW_DEF);
+ print(Text.Space);
+ printSymbolDefinition(tree.symbol(), name);
+ printParams(tparams);
+ printParams(vparams);
+ printOpt(TXT_COLON, tpe, false);
+ printOpt(TXT_EQUAL, rhs, true);
+ break;
+
+ case TypeDef(int mods,
+ Name name,
+ Tree.TypeDef[] tparams,
+ Tree rhs):
+ printModifiers(mods);
+ print(KW_TYPE);
+ print(Text.Space);
+ printSymbolDefinition(tree.symbol(), name);
+ printParams(tparams);
+ if ((mods & Modifiers.ABSTRACT) != 0) printOpt(TXT_SUBTYPE, rhs, true);
+ else printOpt(TXT_EQUAL, rhs, true);
+ break;
+
+ case Import(Tree expr, Name[] selectors):
+ print(KW_IMPORT);
+ print(Text.Space);
+ print(expr);
+ print(TXT_LEFT_BRACE);
+ for (int i = 0; i < selectors.length; i = i + 2) {
+ if (i > 0) print(TXT_COMMA_SP);
+ print(selectors[i].toString());
+ if (i + 1 < selectors.length && selectors[i] != selectors[i+1]) {
+ print(TXT_RIGHT_ARROW);
+ print(selectors[i+1].toString());
+ }
+ }
+ print(TXT_RIGHT_BRACE);
+ break;
+
+ case CaseDef(Tree pat, Tree guard, Tree body):
+ print(KW_CASE);
+ print(Text.Space);
+ print(pat);
+ printOpt(KW_IF, guard, true);
+ print(Text.Space);
+ print(TXT_RIGHT_ARROW);
+ print(Text.Space);
+ print(body);
+ break;
+
+ case LabelDef(Tree[] params, Tree rhs):
+ assert tree.symbol() != null;
+ printSymbolDefinition(tree.symbol(), null);
+ printArray(params, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP);
+ print(rhs);
+ break;
+
+ case Block(Tree[] stats):
+ printArray(stats, TXT_BLOCK_BEGIN, TXT_BLOCK_END, TXT_BLOCK_SEP);
+ break;
+
+ case Tuple(Tree[] trees):
+ printArray(trees, TXT_LEFT_BRACKET, TXT_RIGHT_BRACKET, TXT_COMMA_SP);
+ break;
+
+ case Visitor(Tree.CaseDef[] cases):
+ printArray(cases, TXT_BLOCK_BEGIN, TXT_BLOCK_END, Text.Newline);
+ break;
+
+ case Function(Tree.ValDef[] vparams, Tree body):
+ print(TXT_LEFT_BRACE);
+ printParams(vparams);
+ print(Text.Space);
+ print(TXT_RIGHT_ARROW);
+ print(Text.Space);
+ print(body);
+ print(TXT_RIGHT_BRACE);
+ break;
+
+ case Assign(Tree lhs, Tree rhs):
+ print(lhs);
+ print(Text.Space);
+ print(TXT_EQUAL);
+ print(Text.Space);
+ print(rhs);
+ break;
+
+ case If(Tree cond, Tree thenp, Tree elsep):
+ print(KW_IF);
+ print(Text.Space);
+ print(TXT_LEFT_PAREN);
+ print(cond);
+ print(TXT_RIGHT_PAREN);
+ indent(); print(Text.Newline);
+ print(thenp);
+ undent(); print(Text.Newline);
+ indent(); printOpt(TXT_ELSE_NL, elsep, false); undent();
+ printType(tree);
+ break;
+
+ case New(Tree.Template templ):
+ printTemplate(KW_NEW, templ, false);
+ printType(tree);
+ break;
+
+ case Typed(Tree expr, Tree tpe):
+ print(TXT_LEFT_PAREN);
+ print(expr);
+ print(TXT_RIGHT_PAREN);
+ print(Text.Space);
+ print(TXT_COLON);
+ print(Text.Space);
+ print(tpe);
+ printType(tree);
+ break;
+
+ case TypeApply(Tree fun, Tree[] targs):
+ print(fun);
+ print(TXT_AT);
+ printArray(targs, TXT_LEFT_BRACKET, TXT_RIGHT_BRACKET, TXT_COMMA_SP);
+ printType(tree);
+ break;
+
+ case Apply(Tree fun, Tree[] vargs):
+ print(fun);
+ printArray(vargs, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP);
+ printType(tree);
+ break;
+
+ case Super(Tree tpe):
+ if (tpe != Tree.Empty)
+ print(TXT_LEFT_PAREN);
+
+ print(KW_SUPER);
+
+ if (tpe != Tree.Empty) {
+ print(Text.Space);
+ print(TXT_COLON);
+ print(Text.Space);
+ print(tpe);
+ print(TXT_RIGHT_PAREN);
+ }
+ printType(tree);
+ break;
+
+ case This(Tree qualifier):
+ if (qualifier != Tree.Empty) {
+ print(qualifier);
+ print(TXT_DOT);
+ }
+ print(KW_THIS);
+ printType(tree);
+ break;
+
+ case Select(Tree qualifier, Name name):
+ print(qualifier);
+ print(TXT_DOT);
+ printSymbolUse(tree.symbol(), name);
+ printType(tree);
+ break;
+
+ case Ident(Name name):
+ printSymbolUse(tree.symbol(), name);
+ printType(tree);
+ break;
+
+ case Literal(Object obj):
+ String str;
+ if (obj instanceof String)
+ str = "\"" + obj + "\"";
+ else
+ str = String.valueOf(obj);
+ print(Text.Literal(str));
+ printType(tree);
+ break;
+
+ case SingletonType(Tree ref):
+ print(ref);
+ print(TXT_DOT); print(KW_TYPE);
+ break;
+
+ case SelectFromType(Tree qualifier, Name selector):
+ print(qualifier);
+ print(Text.Space); print(TXT_HASH); print(Text.Space);
+ printSymbolUse(tree.symbol(), selector);
+ break;
+
+ case FunType(Tree[] argtpes, Tree restpe):
+ printArray(argtpes, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP);
+ print(TXT_RIGHT_ARROW);
+ print(restpe);
+ break;
+
+ case CompoundType(Tree[] baseTypes, Tree[] refinements):
+ printArray(baseTypes, Text.None, Text.None, TXT_WITH_SP);
+ printArray(refinements, TXT_WITH_BLOCK_BEGIN, TXT_BLOCK_END, Text.Newline);
+ break;
+
+ case TupleType(Tree[] types):
+ printArray(types, TXT_LEFT_BRACKET, TXT_RIGHT_BRACKET, TXT_COMMA_SP);
+ break;
+
+ case AppliedType(Tree tpe, Tree[] args):
+ print(tpe);
+ indent();
+ print(TXT_LEFT_BRACKET);
+ for (int i = 0; i < args.length; ++i) {
+ if (i > 0) print(TXT_COMMA_SP);
+ print(args[i]);
+ }
+ undent();
+ print(TXT_RIGHT_BRACKET);
+ break;
+
+ case CovariantType(Tree tpe):
+ print(TXT_PLUS);
+ print(tpe);
+ break;
+
+ case Template(Tree[] parents, Tree[] body):
+ Debug.abort("unexpected case", tree);
+ break;
+
+ default:
+ print(TXT_UNKNOWN);
+ break;
+ }
+ return this;
+ }
+
+ // Printing helpers
+
+ protected void printArray(Tree[] trees, Text open, Text close, Text sep) {
+ indent();
+ print(open);
+ for (int i = 0; i < trees.length; ++i) {
+ if (i > 0) print(sep);
+ print(trees[i]);
+ }
+ undent();
+ print(close);
+ }
+
+ protected void printOpt(Text prefix, Tree tree, boolean spaceBefore) {
+ if (tree != Tree.Empty) {
+ if (spaceBefore)
+ print(Text.Space);
+ print(prefix);
+ print(Text.Space);
+ print(tree);
+ }
+ }
+
+ // Printing of symbols
+
+ protected String symbolString(Symbol symbol, Name name) {
+ if (symbol != null)
+ return symbol.name.toString();
+ else
+ return name.toString();
+ }
+
+ protected void printSymbolDefinition(Symbol symbol, Name name) {
+ print(Text.Identifier(symbol,
+ symbolString(symbol, name),
+ SymbolUsage.Definition));
+ }
+
+ protected void printSymbolUse(Symbol symbol, Name name) {
+ print(Text.Identifier(symbol,
+ symbolString(symbol, name),
+ SymbolUsage.Use));
+ }
+
+ // Printing of trees
+
+ protected void printType(Tree tree) {
+ if (Global.instance.printtypes) {
+ print(TXT_LEFT_BRACE);
+ if (tree.type != null)
+ print(Text.Simple(tree.type.toString()));
+ else
+ print(TXT_NULL);
+ print(TXT_RIGHT_BRACE);
+ }
+ }
+
+ protected void printModifiers(int flags) {
+ if ((flags & Modifiers.ABSTRACT) != 0) {
+ print(KW_ABSTRACT);
+ print(Text.Space);
+ }
+ if ((flags & Modifiers.FINAL) != 0) {
+ print(KW_FINAL);
+ print(Text.Space);
+ }
+ if ((flags & Modifiers.PRIVATE) != 0) {
+ print(KW_PRIVATE);
+ print(Text.Space);
+ }
+ if ((flags & Modifiers.PROTECTED) != 0) {
+ print(KW_PROTECTED);
+ print(Text.Space);
+ }
+ if ((flags & Modifiers.QUALIFIED) != 0) {
+ print(KW_QUALIFIED);
+ print(Text.Space);
+ }
+ if ((flags & Modifiers.OVERRIDE) != 0) {
+ print(KW_OVERRIDE);
+ print(Text.Space);
+ }
+ if ((flags & Modifiers.CASE) != 0) {
+ print(KW_CASE);
+ print(Text.Space);
+ }
+ if ((flags & Modifiers.DEF) != 0) {
+ print(KW_DEF);
+ print(Text.Space);
+ }
+ if ((flags & Modifiers.STATIC) != 0) {
+ print(KW_STATIC);
+ print(Text.Space);
+ }
+ }
+
+ protected void printTemplate(Text prefix,
+ Tree.Template templ,
+ boolean spaceBefore) {
+ if (! (templ.parents.length == 0
+ || (templ.parents.length == 1
+ && templ.parents[0] == Tree.Empty))) {
+ if (spaceBefore)
+ print(Text.Space);
+ print(prefix);
+ print(Text.Space);
+ printArray(templ.parents, Text.None, Text.None, TXT_WITH_SP);
+ }
+
+ if (templ.body.length > 0)
+ printArray(templ.body, TXT_WITH_BLOCK_BEGIN, TXT_BLOCK_END, TXT_BLOCK_SEP);
+ }
+
+ protected void printParams(Tree.TypeDef[] tparams) {
+ if (tparams.length > 0) {
+ print(TXT_LEFT_BRACKET);
+ for (int i = 0; i < tparams.length; i++) {
+ if (i > 0) print(TXT_COMMA_SP);
+ printParam(tparams[i]);
+ }
+ print(TXT_RIGHT_BRACKET);
+ }
+ }
+
+ protected void printParams(Tree.ValDef[][] vparamss) {
+ for (int i = 0; i < vparamss.length; ++i)
+ printParams(vparamss[i]);
+ }
+
+ protected void printParams(Tree.ValDef[] vparams) {
+ print(TXT_LEFT_PAREN);
+ for (int i = 0; i < vparams.length; ++i) {
+ if (i > 0) print(TXT_COMMA_SP);
+ printParam(vparams[i]);
+ }
+ print(TXT_RIGHT_PAREN);
+ }
+
+ protected void printParam(Tree tree) {
+ switch (tree) {
+ case TypeDef(int mods, Name name, _, Tree bound):
+ printModifiers(mods);
+ printSymbolDefinition(tree.symbol(), name);
+ printOpt(KW_EXTENDS, bound, true);
+ break;
+
+ case ValDef(int mods, Name name, Tree tpe, Tree.Empty):
+ printModifiers(mods);
+ printSymbolDefinition(tree.symbol(), name);
+ printOpt(TXT_COLON, tpe, false);
+ break;
+
+ default:
+ Debug.abort("bad parameter: " + tree);
+ }
+ }
+}
diff --git a/sources/scalac/ast/printer/TreePrinter.java b/sources/scalac/ast/printer/TreePrinter.java
new file mode 100644
index 0000000000..059b335c72
--- /dev/null
+++ b/sources/scalac/ast/printer/TreePrinter.java
@@ -0,0 +1,34 @@
+/* ____ ____ ____ ____ ______ *\
+** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala **
+** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL **
+** /_____/\____/\___/\____/____/ **
+\* */
+
+// $Id$
+
+package scalac.ast.printer;
+
+import java.io.OutputStream;
+
+import scalac.Unit;
+import scalac.ast.Tree;
+
+/**
+ * Interface for all abstract tree printers.
+ *
+ * @author Michel Schinz
+ * @version 1.0
+ */
+public interface TreePrinter {
+ public void begin();
+ public void end();
+ public void flush();
+
+ public void beginSection(int level, String title);
+
+ public void print(Unit unit);
+
+ public TreePrinter print(Tree tree);
+ public TreePrinter print(String str);
+ public TreePrinter println();
+}