diff options
author | Martin Odersky <odersky@gmail.com> | 2003-02-13 14:41:36 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2003-02-13 14:41:36 +0000 |
commit | 4177daab2f54bdb20c71f623296a8bb32616fd12 (patch) | |
tree | 23f08b43f3758e825d5965b336030603a65bbcf7 /sources/scalac/ast | |
parent | 33d6e170c97ca7b2f991896a0729941a7240b6d6 (diff) | |
download | scala-4177daab2f54bdb20c71f623296a8bb32616fd12.tar.gz scala-4177daab2f54bdb20c71f623296a8bb32616fd12.tar.bz2 scala-4177daab2f54bdb20c71f623296a8bb32616fd12.zip |
Initial version.
Diffstat (limited to 'sources/scalac/ast')
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(); +} |