From f5437e9a8bb543cf57b295739dd3abdebb7be651 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 12 Nov 2003 18:01:30 +0000 Subject: *** empty log message *** --- sources/scala/tools/scalac/CompilerPhases.scala | 20 + sources/scala/tools/scalac/Global.scala | 28 + sources/scala/tools/scalac/Main.scala | 39 + sources/scala/tools/scalac/ast/TreeList.scala | 76 + sources/scala/tools/scalac/ast/parser/Parser.scala | 1971 ++++++++++++++++++++ .../tools/scalac/ast/parser/ParserPhase.scala | 25 + .../scala/tools/scalac/ast/parser/Scanner.scala | 807 ++++++++ .../scala/tools/scalac/ast/parser/TokenData.scala | 46 + sources/scala/tools/scalac/ast/parser/Tokens.scala | 92 + .../tools/scalac/ast/printer/HTMLPrinter.scala | 167 ++ .../tools/scalac/ast/printer/TextTreePrinter.scala | 667 +++++++ sources/scalac/CompilerPhases.java | 50 +- sources/scalac/Global.java | 13 +- sources/scalac/symtab/Symbol.java | 7 +- sources/scalac/symtab/classfile/Pickle.java | 6 +- sources/scalac/symtab/classfile/UnPickle.java | 11 +- sources/scalac/typechecker/Analyzer.java | 4 +- sources/scalac/typechecker/ConstantFolder.java | 6 +- 18 files changed, 4004 insertions(+), 31 deletions(-) create mode 100644 sources/scala/tools/scalac/CompilerPhases.scala create mode 100644 sources/scala/tools/scalac/Global.scala create mode 100644 sources/scala/tools/scalac/Main.scala create mode 100644 sources/scala/tools/scalac/ast/TreeList.scala create mode 100644 sources/scala/tools/scalac/ast/parser/Parser.scala create mode 100644 sources/scala/tools/scalac/ast/parser/ParserPhase.scala create mode 100644 sources/scala/tools/scalac/ast/parser/Scanner.scala create mode 100644 sources/scala/tools/scalac/ast/parser/TokenData.scala create mode 100644 sources/scala/tools/scalac/ast/parser/Tokens.scala create mode 100644 sources/scala/tools/scalac/ast/printer/HTMLPrinter.scala create mode 100644 sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala diff --git a/sources/scala/tools/scalac/CompilerPhases.scala b/sources/scala/tools/scalac/CompilerPhases.scala new file mode 100644 index 0000000000..e9f5a9c665 --- /dev/null +++ b/sources/scala/tools/scalac/CompilerPhases.scala @@ -0,0 +1,20 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scala.tools.scalac; + +/** + * This class defines all compiler phases and maintains a list of + * active phases. + */ +class CompilerPhases extends scalac.CompilerPhases { + + protected override def PARSER_PHASE(): Class = + Class.forName("scala.tools.scalac.ast.parser.ParserPhase$class"); + +} diff --git a/sources/scala/tools/scalac/Global.scala b/sources/scala/tools/scalac/Global.scala new file mode 100644 index 0000000000..2daead9e55 --- /dev/null +++ b/sources/scala/tools/scalac/Global.scala @@ -0,0 +1,28 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id: Global.scala +\* */ + +package scala.tools.scalac; + +import ast.printer._; +import scalac.CompilerCommand; +import java.io.OutputStream; +import scalac.ast.printer.TreePrinter; + +/** The global environment of a compiler run + * + */ +class Global(args: CompilerCommand, interpret: boolean) extends scalac.Global(args, interpret) { + + def this(args: CompilerCommand) = this(args, false); + + protected override def newTextTreePrinter(printStream: OutputStream): TreePrinter = + new TextTreePrinter(printStream); + protected override def newHTMLTreePrinter(printStream: OutputStream): TreePrinter = + new HTMLTreePrinter(printStream); + +} diff --git a/sources/scala/tools/scalac/Main.scala b/sources/scala/tools/scalac/Main.scala new file mode 100644 index 0000000000..c0a5a3ed0b --- /dev/null +++ b/sources/scala/tools/scalac/Main.scala @@ -0,0 +1,39 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scala.tools.scalac; + +import scalac.util.Reporter; +import scalac.CompilerCommand; + +/** The main class for SoCoS, a compiler for the programming + * language Scala. + * + * @author Matthias Zenger + * @version 1.0 + */ +object Main { + + val PRODUCT: String = + System.getProperty("scala.product", "socos"); + val VERSION: String = + System.getProperty("scala.version", "unknown version"); + + def main(args: Array[String]): unit = { + val reporter = new Reporter(); + val command = new CompilerCommand( + PRODUCT, VERSION, reporter, new CompilerPhases()); + if (command.parse(args) && command.files.list.size() > 0) { + val global = new Global(command); + global.compile(command.files.toArray(), false); + global.stop("total"); + global.reporter.printSummary(); + } + System.exit(if (reporter.errors() > 0) 1 else 0); + } +} diff --git a/sources/scala/tools/scalac/ast/TreeList.scala b/sources/scala/tools/scalac/ast/TreeList.scala new file mode 100644 index 0000000000..0cc2365789 --- /dev/null +++ b/sources/scala/tools/scalac/ast/TreeList.scala @@ -0,0 +1,76 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ + +package scala.tools.scalac.ast; + +import scalac.ast._; + +/** List of trees. + */ + +final class TreeList(ts: Array[Tree]) { + + private var trees = ts; + private var len = ts.length; + + def this() = { this(new Array[Tree](4)); len = 0 } + + def append(tree: Tree): TreeList = { + if (len == trees.length) { + val ts = new Array[Tree](if (len == 0) 4 else len * 2); + System.arraycopy(trees.asInstanceOf[Array[Object]], 0, + ts.asInstanceOf[Array[Object]], 0, len); + trees = ts; + } + trees(len) = tree; + len = len + 1; + this + } + + def append(ts: Array[Tree]): unit = { + for (val j <- Iterator.range(0, ts.length)) do + append(ts(j)); + } + + def append(tl: TreeList): unit = { + for (val j <- Iterator.range(0, ts.length)) do + append(tl.trees(j)); + } + + def clear(): unit = { + trees = new Array[Tree](4); + len = 0; + } + + def length(): int = len; + + def get(i: int): Tree = trees(i); + + def first(): Tree = trees(0); + + def removeLast(): Tree = { + len = len - 1; + trees(len) + } + + def toArray(): Array[Tree] = { + val ts = new Array[Tree](len); + System.arraycopy(trees.asInstanceOf[Array[Object]], 0, + ts.asInstanceOf[Array[Object]], 0, len); + ts + } + + def copyTo[t <: Tree](ts: Array[t]): Array[t] = copyTo(ts, 0); + + def copyTo[t <: Tree](ts: Array[t], from: int): Array[t] = { + System.arraycopy(trees.asInstanceOf[Array[java.lang.Object]], 0, + ts.asInstanceOf[Array[java.lang.Object]], from, len); + ts; + } +} diff --git a/sources/scala/tools/scalac/ast/parser/Parser.scala b/sources/scala/tools/scalac/ast/parser/Parser.scala new file mode 100644 index 0000000000..4d7435ea70 --- /dev/null +++ b/sources/scala/tools/scalac/ast/parser/Parser.scala @@ -0,0 +1,1971 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scala.tools.scalac.ast.parser; + +import scalac.ast.parser.PatternNormalizer; +import ch.epfl.lamp.util.Position; + +import java.util.{Map, Stack, ArrayList, LinkedList}; +import scalac._; +import scalac.util._; + +import scalac.symtab.Modifiers; +import scalac.ast._; +import Tree._; +import java.lang.{Integer, Long, Float, Double}; +import scala.Iterator; + +/** A recursive descent parser for the programming language Scala. + * + * @author Martin Odersky, Matthias Zenger, Burak Emir + * @version 1.2 + */ +class Parser(unit: Unit) { + + import Tokens._; + import scala.tools.scalac.ast.TreeList; + + /** the lexical analyzer + */ + val s = new Scanner(unit); + + /** the tree factory + */ + val make: TreeFactory = unit.global.make; + + /** pattern checker and normalizer + */ + val pN = new PatternNormalizer(unit); + + /** The current nesting depths of while and do loops. + */ + var loopNestingDepth = 0; + + /** this is the general parse method + */ + def parse(): Array[Tree] = { + val ts = if (s.unit.console) templateStatSeq() else compilationUnit(); + accept(EOF); + ts + } + +/////// HELPER FUNCTIONS //////////////////////////////////////////////////// + + def newTreeArray(trees: Tree*): Array[Tree] = { + val arr = new Array[Tree](trees.length); + var i = 0; + for (val t <- trees.elements) do { + arr(i) = t; i = i + 1; + } + arr + } + + def newValDefArray(trees: Tree$ValDef*): Array[Tree$ValDef] = { + val arr = new Array[Tree$ValDef](trees.length); + var i = 0; + for (val t <- trees.elements) do { + arr(i) = t; i = i + 1; + } + arr + } + + def newValDefArrayArray(trees: Array[Tree$ValDef]*): Array[Array[Tree$ValDef]] = { + val arr = new Array[Array[Tree$ValDef]](trees.length); + var i = 0; + for (val t <- trees.elements) do { + arr(i) = t; i = i + 1; + } + arr + } + + def newCaseDefArray(trees: Tree$CaseDef*): Array[Tree$CaseDef] = { + val arr = new Array[Tree$CaseDef](trees.length); + var i = 0; + for (val t <- trees.elements) do { + arr(i) = t; i = i + 1; + } + arr + } + + def newNameArray(trees: Name*): Array[Name] = { + val arr = new Array[Name](trees.length); + var i = 0; + for (val t <- trees.elements) do { + arr(i) = t; i = i + 1; + } + arr + } + +/////// ERROR HANDLING ////////////////////////////////////////////////////// + + private def skip(): unit = { + //System.out.println(" " + s.token2string(s.token));//DEBUG + var nparens = 0; + var nbraces = 0; + while (true) { + s.token match { + case EOF => + return; + case SEMI => + if (nparens == 0 && nbraces == 0) + return; + case RPAREN => + nparens = nparens - 1; + case RBRACE => + if (nbraces == 0) return; + nbraces = nbraces - 1; + case LPAREN => + nparens = nparens + 1; + case LBRACE => + nbraces = nbraces + 1; + } + s.nextToken(); + } + } + + def syntaxError(msg: String, skipIt: boolean): Tree = + syntaxError(s.pos, msg, skipIt); + + def syntaxError(pos: int, msg: String, skipIt: boolean): Tree = { + if (pos != s.errpos) { + s.unit.error(pos, msg); + s.errpos = pos; + } + if (skipIt) skip(); + make.Bad(pos) + } + + def accept(token: int): int = { + val pos = s.pos; + if (s.token != token) { + val errpos = if ((s.pos >>> Position.COLUMN_BITS) > + (s.lastpos >>> Position.COLUMN_BITS)) s.lastpos + else s.pos; + syntaxError(errpos, s.token2string(token) + " expected but " + + s.token2string(s.token) + " found.", true); + } + if (s.token == token) s.nextToken(); + pos + } + +/////// TOKEN CLASSES ////////////////////////////////////////////////////// + + def isModifier(): boolean = + (s.token == ABSTRACT) + || (s.token == FINAL) + || (s.token == SEALED) + || (s.token == PRIVATE) + || (s.token == PROTECTED) + || (s.token == OVERRIDE); + + def isLocalModifier(): boolean = + (s.token == ABSTRACT) + || (s.token == FINAL) + || (s.token == SEALED); + + def isDefIntro(): boolean = s.token match { + case VAL | VAR | DEF | TYPE | OBJECT | CASEOBJECT | CLASS | CASECLASS | TRAIT => + true + case _ => + false + } + + def isDclIntro(): boolean = s.token match { + case VAL | VAR | DEF | TYPE => + true; + case _ => + false + } + + def isExprIntro(): boolean = s.token match { + case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | + STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL | IDENTIFIER | + THIS | SUPER | IF | FOR | NEW | USCORE | TRY | WHILE | + DO | RETURN | THROW | LPAREN | LBRACE => + true; + case _ => + false; + } + +/////// COMMENT COLLECTION /////////////////////////////////////////////////// + + /** keep the comments associated with a given tree + */ + protected val mapTreeComment: Map = unit.global.mapTreeComment; + + /** stack of comments + */ + protected val commentStack = new Stack(); + + /** positive if we are inside a block + */ + protected var local = 0; + + /** push last encountered comment and reset the buffer + */ + protected def pushComment(): unit = { + if (local == 0) { + commentStack.push(if (s.docBuffer == null) null else s.docBuffer.toString()); + s.docBuffer = null; + } + } + + /** pop a comment from the stack and associate it with the given tree + */ + protected def popComment(tree: Tree): Tree = { + if (local == 0) + if (!commentStack.empty()) + mapTreeComment.put(tree, commentStack.pop().asInstanceOf[String]); + tree + } + +/////// TREE CONSTRUCTION //////////////////////////////////////////////////// + + /** Name supply + */ + var freshCnt = 0; + + def fresh(): Name = { + val n = Name.fromString("x$" + freshCnt); + freshCnt = freshCnt + 1; + n + } + + /** Create tree representing binary operation expression or pattern. + */ + def makeBinop(isExpr: boolean, pos: int, left: Tree, op: Name, right: Tree): Tree = + if (isExpr) { + if (op.isLeftAssoc()) { + make.Apply( + pos, + make.Select(pos, left, NameTransformer.encode(op)), + newTreeArray(right)); + } else { + val x: Name = fresh(); + make.Block( + pos, + newTreeArray( + make.ValDef(pos, 0, x, Tree.Empty, left), + make.Apply( + pos, + make.Select(pos, right, NameTransformer.encode(op)), + newTreeArray(make.Ident(left.pos, x))))); + } + } else { + make.Apply( + pos, + make.Ident(pos, NameTransformer.encode(op).toTypeName()), + newTreeArray(left, right)); + } + + def scalaDot(pos: int, name: Name): Tree = + make.Select(pos, make.Ident(pos, Names.scala), name); + + def scalaRuntimeDot(pos: int, name: Name): Tree = + make.Select(pos, scalaDot(pos, Names.runtime), name); + + def ScalaRunTimeDot(pos: int, name: Name): Tree = + make.Select(pos, scalaRuntimeDot(pos, Names.ScalaRunTime), name); + + def scalaBooleanDot(pos: int, name: Name): Tree = + make.Select(pos, scalaDot(pos, Names.Boolean), name); + + def scalaObjectConstr(pos: int): Tree = + make.Apply( + pos, scalaDot(pos, Names.Object.toTypeName()), Tree.EMPTY_ARRAY); + + /** Create tree for for-comprehension or + * where mapName and flatmapName are chosen + * corresponding to whether this is a for-do or a for-yield. + */ + def makeFor(pos: int, enums: Array[Tree], mapName: Name, flatmapName: Name, body: Tree): Tree = { + + def makeFor1(pos: int, name: Name, pat: Tree, rhs: Tree, body: Tree): Tree = + make.Apply( + pos, make.Select(pos, rhs, name), + newTreeArray(makeForCont(pos, pat, body))); + + def makeForCont(pos: int, pat: Tree, body: Tree): Tree = { + pat match { + case Tree$Ident(name1) => + if (name1.isVariable()) + make.Function( + pos, + newValDefArray( + make.ValDef( + pat.pos, Modifiers.PARAM, name1, Tree.Empty, Tree.Empty)), + body); + } + make.Visitor(pos, newCaseDefArray( + make.CaseDef(pos, pat, Tree.Empty, body))); + } + + enums(0) match { + case Tree$PatDef(mods, pat, rhs) => + if (enums.length == 1) { + makeFor1(pos, mapName, pat, rhs, body); + } else { + val newenums = new Array[Tree](enums.length - 1); + enums(1) match { + case Tree$PatDef(mods2, pat, rhs) => + System.arraycopy(enums, 1, newenums, 0, newenums.length); + makeFor1( + pos, flatmapName, pat, rhs, + makeFor(enums(1).pos, newenums, mapName, flatmapName, body)); + case _ => + System.arraycopy(enums, 2, newenums, 1, newenums.length - 1); + newenums(0) = make.PatDef( + enums(0).pos, mods, pat, + makeFor1(enums(1).pos, Names.filter, pat.duplicate(), rhs, enums(1))); + makeFor(pos, newenums, mapName, flatmapName, body); + } + } + case _ => + throw new ApplicationError(); + } + } + + def makeTry(pos: int, body: Tree, catcher: Tree, finalizer: Tree): Tree = { + var t = body; + if (catcher != Tree.Empty) + t = make.Apply( + pos, + make.Select( + pos, + make.Apply( + pos, ScalaRunTimeDot(pos, Names.Try), newTreeArray(t)), + Names.Catch), + newTreeArray(catcher)); + if (finalizer != Tree.Empty) + t = make.Apply( + pos, + make.Select( + pos, + make.Apply( + pos, ScalaRunTimeDot(pos, Names.Try), newTreeArray(t)), + Names.Finally), + newTreeArray(finalizer)); + t + } + + def makeWhile(pos: int, lname: Name, cond: Tree, body: Tree): Tree = { + val continu = make.Apply( + pos, make.Ident(pos, lname), Tree.EMPTY_ARRAY); + val rhs = make.If( + pos, + cond, + make.Block(body.pos, newTreeArray(body, continu)), + make.Block(pos, Tree.EMPTY_ARRAY)); + make.LabelDef(pos, lname, new Array[Tree$Ident](0), rhs); + } + + def makeDoWhile(pos: int, lname: Name, body: Tree, cond: Tree): Tree = { + val continu = make.Apply( + pos, make.Ident(pos, lname), Tree.EMPTY_ARRAY); + val rhs = make.Block( + body.pos, + newTreeArray( + body, + make.If( + cond.pos, + cond, + continu, + make.Block(pos, Tree.EMPTY_ARRAY)))); + make.LabelDef(pos, lname, new Array[Tree$Ident](0), rhs) + } + + /** Convert tree to formal parameter list + */ + def convertToParams(t: Tree): Array[Tree$ValDef] = { + t match { + case Tree$Function(params, Tree.Empty) => + params + case Tree$Ident(_) | Tree$Typed(Tree$Ident(_), _) => + newValDefArray(convertToParam(t)); + case Tree$Block(stats) => + if (stats.length == 0) Tree.ValDef_EMPTY_ARRAY; + } + syntaxError(t.pos, "malformed formal parameter list", false); + Tree.ValDef_EMPTY_ARRAY; + } + + /** Convert list of trees to formal parameter list + */ + def convertToParams(ts: Array[Tree]): Array[Tree$ValDef] = { + val res = new Array[Tree$ValDef](ts.length); + for (val i <- Iterator.range(0, res.length)) do + res(i) = convertToParam(ts(i)); + res; + } + + /** Convert tree to formal parameter + */ + def convertToParam(tree: Tree): Tree$ValDef = tree match { + case Tree$Ident(name) => + make.ValDef( + tree.pos, Modifiers.PARAM, name, Tree.Empty, Tree.Empty) + case Tree$Typed(Tree$Ident(name), tpe) => + make.ValDef( + tree.pos, Modifiers.PARAM, name, tpe, Tree.Empty) + case _ => + val tpe = syntaxError(tree.pos, "not a legal formal parameter", false); + make.ValDef( + tree.pos, Modifiers.PARAM, Names.ERROR, tpe, Tree.Empty) + } + + /** Convert (qual)ident to type identifier + */ + def convertToTypeId(t: Tree): Tree = t match { + case Tree$Ident(name) => + make.Ident(t.pos, name.toTypeName()) + case Tree$Select(qual, name) => + make.Select(t.pos, qual, name.toTypeName()) + case _ => + t + } + + /** Convert (qual)ident to constructor identifier + */ + def convertToConstr(t: Tree): Tree = t match { + case Tree$Ident(name) => + make.Ident(t.pos, name.toTypeName()) + case Tree$Select(qual, name) => + make.Select(t.pos, qual, name.toTypeName()) + case _ => + syntaxError(t.pos, "class constructor expected", false) + } + + /** Complete unapplied constructor with `()' arguments + */ + def applyConstr(t: Tree): Tree = t match { + case Tree$Apply(_, _) => + t + case _ => + make.Apply(t.pos, t, Tree.EMPTY_ARRAY) + } + +/////// OPERAND/OPERATOR STACK ///////////////////////////////////////////////// + + var operands = new Array[Tree](8); + var positions = new Array[int](8); + var operators = new Array[Name](8); + var sp = 0; + + def push(od: Tree, pos: int, op: Name): unit = { + if (sp == operands.length) { + val operands1 = new Array[Tree](sp * 2); + System.arraycopy(operands, 0, operands1, 0, sp); + operands = operands1; + val positions1 = new Array[int](sp * 2); + System.arraycopy(positions, 0, positions1, 0, sp); + positions = positions1; + val operators1 = new Array[Name](sp * 2); + System.arraycopy(operators, 0, operators1, 0, sp); + operators = operators1; + } + operands(sp) = od; + positions(sp) = pos; + operators(sp) = op; + sp = sp + 1; + } + + def reduceStack(isExpr: boolean, base: int, _top: Tree, prec: int, leftAssoc: boolean): Tree = { + var top = _top; + if (sp != base && + operators(sp-1).precedence() == prec && + operators(sp-1).isLeftAssoc() != 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 = sp - 1; + top = makeBinop(isExpr, positions(sp), operands(sp), operators(sp), top); + } + top + } + +/////// IDENTIFIERS AND LITERALS //////////////////////////////////////////////////////////// + + final val MINUS = Name.fromString("-"); + final val PLUS = Name.fromString("+"); + final val BANG = Name.fromString("!"); + final val TILDE = Name.fromString("~"); + final val STAR = Name.fromString("*"); + final val BAR = Name.fromString("|"); + final val OPT = Name.fromString("?"); + + def ident(): Name = + if (s.token == IDENTIFIER) { + val name = NameTransformer.encode(s.name); + s.nextToken(); + name + } else { + accept(IDENTIFIER); + Names.ERROR + } + + /** StableRef ::= StableId + * | [Ident `.'] this + * SimpleType ::= StableRef [`.' type] + */ + def stableRef(thisOK: boolean, typeOK: boolean): Tree = { + var t: Tree = null; + if (s.token == THIS) { + t = make.This(s.skipToken(), TypeNames.EMPTY); + if (!thisOK || s.token == DOT) + t = selectors(accept(DOT), t, typeOK); + } else if (s.token == SUPER) { + t = make.Super( + s.skipToken(), TypeNames.EMPTY, mixinQualifierOpt()); + t = make.Select(accept(DOT), t, ident()); + if (s.token == DOT) + t = selectors(s.skipToken(), t, typeOK); + } else { + val i: Tree$Ident = make.Ident(s.pos, ident()); + t = i; + if (s.token == DOT) { + val pos = s.skipToken(); + if (s.token == THIS) { + s.nextToken(); + t = make.This(i.pos, i.name.toTypeName()); + if (!thisOK || s.token == DOT) + t = selectors(accept(DOT), t, typeOK); + } else if (s.token == SUPER) { + s.nextToken(); + t = make.Super( + i.pos, i.name.toTypeName(), mixinQualifierOpt()); + t = make.Select(accept(DOT), t, ident()); + if (s.token == DOT) + t = selectors(s.skipToken(), t, typeOK); + } else { + t = selectors(pos, t, typeOK); + } + } + } + t + } + + def selectors(pos: int, t: Tree, typeOK: boolean): Tree = + if (typeOK && s.token == TYPE) { + s.nextToken(); + make.SingletonType(pos, t); + } else { + val t1 = make.Select(pos, t, ident()); + if (s.token == DOT) selectors(s.skipToken(), t1, typeOK); + else t1 + } + + /** MixinQualifier ::= `[' Id `]' + */ + def mixinQualifierOpt(): Name = + if (s.token == LBRACKET) { + s.nextToken(); + val name = ident().toTypeName(); + accept(RBRACKET); + name + } else { + TypeNames.EMPTY + } + + /** StableId ::= Id + * | StableRef `.' Id + * | [Id '.'] super [MixinQualifier] ` `.' Id + */ + def stableId(): Tree = + stableRef(false, false); + + /** QualId ::= Id {`.' Id} + */ + def qualId(): Tree = { + val id = make.Ident(s.pos, ident()); + if (s.token == DOT) selectors(s.skipToken(), id, false) + else id + } + + /** SimpleExpr ::= literal + * | symbol [ArgumentExprs] + * | null + */ + def literal(isPattern: boolean): Tree = { + def litToTree() = s.token match { + case CHARLIT => + make.Literal(s.pos, new Character(s.intVal.asInstanceOf[char])) + case INTLIT => + make.Literal(s.pos, new Integer(s.intVal.asInstanceOf[int])) + case LONGLIT => + make.Literal(s.pos, new Long(s.intVal)) + case FLOATLIT => + make.Literal(s.pos, new Float(s.floatVal.asInstanceOf[float])) + case DOUBLELIT => + make.Literal(s.pos, new Double(s.floatVal)) + case STRINGLIT => + make.Literal(s.pos, s.name.toString()) + case TRUE => + make.Literal(s.pos, java.lang.Boolean.TRUE) + case FALSE => + make.Literal(s.pos, java.lang.Boolean.FALSE) + case NULL => + make.Ident(s.pos, Names.null_) + case SYMBOLLIT => + var symt = scalaDot(s.pos, Names.Symbol); + if (isPattern) symt = convertToTypeId(symt); + make.Apply( + s.pos, symt, newTreeArray(make.Literal(s.pos, s.name.toString()))); + case _ => + syntaxError("illegal literal", true) + } + + val isSymLit = s.token == SYMBOLLIT; + val t = litToTree(); + s.nextToken(); + if (isSymLit && (s.token == LPAREN || s.token == LBRACE)) { + var labt = scalaDot(s.pos, Names.Labelled); + if (isPattern) labt = convertToTypeId(labt); + val listt = if (isPattern) scalaDot(s.pos, Names.List.toTypeName()) + else make.Select(s.pos, scalaDot(s.pos, Names.Predef), Names.List); + make.Apply( + s.pos, labt, newTreeArray(t, make.Apply(s.pos, listt, argumentExprs()))); + } + t + } + +//////// TYPES /////////////////////////////////////////////////////////////// + + /** TypedOpt ::= [`:' Type] + */ + def typedOpt(): Tree = + if (s.token == COLON) { + s.nextToken(); + typ() + } else { + Tree.Empty + } + + /** SimpleTypedOpt ::= [`:' SimpleType] + */ + def simpleTypedOpt(): Tree = + if (s.token == COLON) { + s.nextToken(); + simpleType() + } else { + Tree.Empty + } + + /** Types ::= Type {`,' Type} + */ + def types(): Array[Tree] = { + val ts = new TreeList(); + ts.append(typ()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(typ()); + } + ts.toArray() + } + + /** Type ::= Type1 `=>' Type + * | `(' [Types] `)' `=>' Type + * | Type1 + */ + def typ(): Tree = + if (s.token == LPAREN) { + s.nextToken(); + if (s.token == RPAREN) { + s.nextToken(); + val pos = accept(ARROW); + make.FunType(pos, Tree.EMPTY_ARRAY, typ()); + } else { + val t = typ(); + if (s.token == COMMA) { + s.nextToken(); + val ts = new TreeList(); + ts.append(t); + ts.append(types()); + accept(RPAREN); + val pos = accept(ARROW); + make.FunType(pos, ts.toArray(), typ()); + } else { + accept(RPAREN); + t + } + } + } else { + val t = type1(); + if (s.token == ARROW) + make.FunType(s.skipToken(), newTreeArray(t), typ()) + else + t + } + + /** Type1 ::= SimpleType {with SimpleType} [Refinement] + */ + def type1(): Tree = { + val pos = s.pos; + val t = simpleType(); + if (s.token == WITH || s.token == LBRACE) { + val ts = new TreeList(); + ts.append(t); + while (s.token == WITH) { + s.nextToken(); + ts.append(simpleType()); + } + val rs = if (s.token == LBRACE) refinement() else Tree.EMPTY_ARRAY; + make.CompoundType(pos, ts.toArray(), rs) + } else { + t + } + } + + /** SimpleType ::= SimpleType TypeArgs + * | SimpleType `#' Id + * | StableId + * | StableRef `.' type + * | `(' Type `)' + */ + def simpleType(): Tree = { + val pos = s.pos; + var t: Tree = + if (s.token == LPAREN) { + s.nextToken(); + val t = typ(); + accept(RPAREN); + t + } else { + 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, typeArgs()); + else + return t; + } + null; //dummy + } + + /** TypeArgs ::= `[' Types `]' + */ + def typeArgs(): Array[Tree] = { + accept(LBRACKET); + val ts = types(); + accept(RBRACKET); + ts + } + +//////// EXPRESSIONS //////////////////////////////////////////////////////// + + /** EqualsExpr ::= `=' Expr + */ + def equalsExpr(): Tree = { + accept(EQUALS); + expr() + } + + /** Exprs ::= Expr {`,' Expr} + * | Expr `:' `_' `*' + */ + def exprs(): Array[Tree] = { + val ts = new TreeList(); + ts.append(expr(true)); + while (s.token == COMMA) { + s.nextToken(); + ts.append(expr()); + } + ts.toArray() + } + + /** Expr ::= Bindings `=>' Expr + * | if `(' Expr `)' Expr [[`;'] else Expr] + * | try `{' block `}' [catch Expr] [finally Expr] + * | while `(' Expr `)' Expr + * | do Expr [`;'] while `(' Expr `)' + * | for `(' Enumerators `)' (do | yield) Expr + * | throw Expr + * | return [Expr] + * | [SimpleExpr `.'] Id `=' Expr + * | SimpleExpr ArgumentExprs `=' Expr + * | PostfixExpr [`:' Type1] + * Bindings ::= Id [`:' Type1] + * | `(' [Binding {`,' Binding}] `)' + * Binding ::= Id [`:' Type] + */ + + def expr(): Tree = + expr(false); + + def expr(isArgument: boolean): Tree = { + if (s.token == IF) { + val pos = s.skipToken(); + accept(LPAREN); + val cond = expr(); + accept(RPAREN); + val thenp = expr(); + val elsep = + if (s.token == ELSE) { s.nextToken(); expr() } + else Tree.Empty; + make.If(pos, cond, thenp, elsep) + } else if (s.token == TRY) { + val pos = s.skipToken(); + accept(LBRACE); + val body = block(pos); + accept(RBRACE); + val catcher = + if (s.token == CATCH) { s.nextToken(); expr() } + else Tree.Empty; + val finalizer = + if (s.token == FINALLY) { s.nextToken(); expr() } + else Tree.Empty; + makeTry(pos, body, catcher, finalizer) + } else if (s.token == WHILE) { + val lname = Name.fromString("label$" + loopNestingDepth); + loopNestingDepth = loopNestingDepth + 1; + val pos = s.skipToken(); + accept(LPAREN); + val cond = expr(); + accept(RPAREN); + val body = expr(); + loopNestingDepth = loopNestingDepth - 1; + makeWhile(pos, lname, cond, body) + } else if (s.token == DO) { + val lname = Name.fromString("label$" + loopNestingDepth); + loopNestingDepth = loopNestingDepth + 1; + val pos = s.skipToken(); + val body = expr(); + if (s.token == SEMI) s.nextToken(); + accept(WHILE); + accept(LPAREN); + val cond = expr(); + accept(RPAREN); + loopNestingDepth = loopNestingDepth - 1; + makeDoWhile(pos, lname, body, cond) + } else if (s.token == FOR) { + s.nextToken(); + accept(LPAREN); + val enums = enumerators(); + accept(RPAREN); + if (s.token == DO) { + makeFor(s.skipToken(), enums, Names.foreach, Names.foreach, expr()) + } else if (s.token == YIELD) { + makeFor(s.skipToken(), enums, Names.map, Names.flatmap, expr()) + } else { + syntaxError("`do' or `yield' expected", true) + } + } else if (s.token == RETURN) { + val pos = s.skipToken(); + val e = + if (isExprIntro()) expr() + else make.Block(pos, Tree.EMPTY_ARRAY); + make.Return(pos, e) + } else if (s.token == THROW) { + val pos = s.skipToken(); + make.Throw(pos, expr()) + } else { + var t = postfixExpr(); + if (s.token == EQUALS) { + t match { + case Tree$Ident(_) | Tree$Select(_, _) | Tree$Apply(_, _) => + t = make.Assign(s.skipToken(), t, expr()); + } + } else if (s.token == COLON) { + val pos = s.skipToken(); + if (isArgument && s.token == USCORE) { + val pos1 = s.skipToken(); + if (s.token == IDENTIFIER && s.name == Names.STAR) { + s.nextToken(); + t = make.Typed( + pos, t, make.Ident(pos1, TypeNames.WILDCARD_STAR)); + } else { + syntaxError(s.pos, "`*' expected", true); + } + } else { + val tp = type1(); + t = make.Typed(pos, t, tp); + } + } + if (s.token == ARROW) { + t = make.Function(s.skipToken(), convertToParams(t), expr()); + } + t + } + } + + /** PostfixExpr ::= InfixExpr [Id] + * InfixExpr ::= PrefixExpr + * | InfixExpr Id InfixExpr + */ + def postfixExpr(): Tree = { + val base = sp; + var top = prefixExpr(); + while (s.token == IDENTIFIER) { + top = reduceStack( + true, base, top, s.name.precedence(), s.name.isLeftAssoc()); + push(top, s.pos, s.name); + ident(); + if (isExprIntro()) { + top = prefixExpr(); + } else { + sp = sp - 1; + val pos = positions(sp); + val postOp = operators(sp); + top = reduceStack(true, base, operands(sp), 0, true); + return make.Select(pos, top, NameTransformer.encode(postOp)); + } + } + reduceStack(true, base, top, 0, true) + } + + /** PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr + */ + def prefixExpr(): Tree = + if (s.token == IDENTIFIER && + (s.name == MINUS || + s.name == PLUS || + s.name == TILDE || + s.name == BANG)) { + val name = ident(); + make.Select(s.pos, simpleExpr(), name); + } else { + simpleExpr() + } + + /* SimpleExpr ::= literal + * | StableRef + * | `(' [Expr] `)' + * | BlockExpr + * | new Template + * | SimpleExpr `.' Id + * | SimpleExpr TypeArgs + * | SimpleExpr ArgumentExprs + */ + def simpleExpr(): Tree = { + var t: Tree = null; + s.token match { + case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | + SYMBOLLIT | TRUE | FALSE | NULL => + t = literal(false); + case IDENTIFIER | THIS | SUPER => + t = stableRef(true, false); + case LPAREN => + val pos = s.skipToken(); + if (s.token == RPAREN) { + s.nextToken(); + t = make.Block(pos, Tree.EMPTY_ARRAY); + } else { + t = expr(); + if (s.token == COMMA) { + val commapos = s.skipToken(); + val 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); + } + } + case LBRACE => + t = blockExpr(); + case NEW => + t = make.New(s.skipToken(), template()); + case _ => + return syntaxError("illegal start of expression", true); + } + while (true) { + s.token match { + case DOT => + t = make.Select(s.skipToken(), t, ident()); + case LBRACKET => + t match { + case Tree$Ident(_) | Tree$Select(_, _) => + t = make.TypeApply(s.pos, t, typeArgs()); + case _ => + return t; + } + case LPAREN | LBRACE => + t = make.Apply(s.pos, t, argumentExprs()); + case _ => + return t; + } + } + null;//dummy + } + + /** ArgumentExprs ::= `(' [Exprs] `)' + * | BlockExpr + */ + def argumentExprs(): Array[Tree] = { + var ts = Tree.EMPTY_ARRAY; + if (s.token == LBRACE) { + ts = newTreeArray(blockExpr()); + } else { + accept(LPAREN); + if (s.token != RPAREN) + ts = exprs(); + accept(RPAREN); + } + ts + } + + /** BlockExpr ::= `{' CaseClause {CaseClause} `}' + * | `{' Block `}' + */ + def blockExpr(): Tree = { + local = local + 1; + val pos = accept(LBRACE); + val res = + if (s.token == CASE) { + val stats = new TreeList(); + do { + stats.append(caseClause()); + } while (s.token == CASE); + make.Visitor(pos, + stats.copyTo(new Array[Tree$CaseDef](stats.length())) + .asInstanceOf[Array[Tree$CaseDef]]) + } else { + block(pos); + } + accept(RBRACE); + local = local - 1; + res + } + + /** Block ::= BlockStatSeq + */ + def block(pos: int): Tree = { + val stats = blockStatSeq(new TreeList()); + if (stats.length == 1 && stats(0).isTerm()) stats(0) + else make.Block(pos, stats) + } + + /** caseClause : =>= case Pattern [if PostfixExpr] `=>' Block + */ + def caseClause(): Tree = { + val pos = accept(CASE); + val pat = validPattern(); + val guard = + if (s.token == IF) { s.nextToken(); postfixExpr() } + else Tree.Empty; + make.CaseDef(pos, pat, guard, block(accept(ARROW))) + } + + /** Enumerators ::= Generator {`;' Enumerator} + * Enumerator ::= Generator + * | Expr + */ + def enumerators(): Array[Tree] = { + val enums = new TreeList(); + enums.append(generator()); + while (s.token == SEMI) { + s.nextToken(); + if (s.token == VAL) enums.append(generator()); + else enums.append(expr()); + } + enums.toArray() + } + + /** Generator ::= val Pattern1 `<-' Expr + */ + def generator(): Tree = { + val pos = accept(VAL); + val pat = validPattern1(); + accept(LARROW); + var rhs = expr(); + if (!TreeInfo.isVarPattern(pat)) + rhs = make.Apply( + rhs.pos, + make.Select(rhs.pos, rhs, Names.filter), + newTreeArray( + make.Visitor( + rhs.pos, + newCaseDefArray( + make.CaseDef( + rhs.pos, pat.duplicate(), + Tree.Empty, make.Literal(s.pos, java.lang.Boolean.TRUE)), + make.CaseDef( + rhs.pos, make.Ident(rhs.pos, Names.PATTERN_WILDCARD), + Tree.Empty, make.Literal(s.pos, java.lang.Boolean.FALSE)))))); + make.PatDef(pos, 0, pat, rhs) + } + +//////// PATTERNS //////////////////////////////////////////////////////////// + + /** Pattern ( see pattern() ) which is checked for validity + */ + def validPattern(): Tree = { + val pos = s.pos; + val pat = pattern(); + if (this.pN.check(pat)) { // reports syntax errors as side effect + // normalize + pN.wrapAlternative(pN.elimSequence(pN.flattenSequence(pat))) + } else { + make.Bad(pos) + } + } + + /** Pattern1 ( see pattern1() ) which is checked for validity + */ + def validPattern1(): Tree = { + val pos = s.pos; + val pat = pattern1(); + if(this.pN.check(pat)) { // reports syntax errors as side effect + pN.wrapAlternative(pN.elimSequence(pN.flattenSequence(pat))) + } else { + make.Bad(pos) + } + } + + /** Patterns ::= Pattern {`,' Pattern} + */ + def patterns(): Array[Tree] = { + val ts = new TreeList(); + ts.append(pattern()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(pattern()); + } + ts.toArray() + } + + /** Pattern ::= Pattern1 { `|' Pattern1 } + */ + def pattern(): Tree = { + val pos = s.pos; + val first = pattern1(); + if (s.token == IDENTIFIER && s.name == BAR) { + val choices = new TreeList(); + choices.append( first ); + while (s.token == IDENTIFIER && s.name == BAR) { + s.nextToken(); + choices.append(pattern1()); + } + val tarr = choices.toArray(); + val ts = pN.flattenAlternativeChildren(tarr); + return pN.flattenAlternative(make.Alternative(pos, ts.toArray())); + } + first + } + + /** Pattern1 ::= varid `:' Type1 + * | `_' `:' Type1 + * | Pattern2 + */ + def pattern1(): Tree = { + val p = pattern2(); + if (s.token == COLON && TreeInfo.isVarPattern(p)) + make.Typed(s.skipToken(), p, type1()) + else p + } + + /* Pattern2 ::= varid [ @ Pattern3 ] + * | Pattern3 + */ + def pattern2(): Tree = { + val p = pattern3(); + if (s.token == AT && TreeInfo.isVarPattern(p)) { + p match { + case Tree$Ident(name) => + if (name == Names.PATTERN_WILDCARD) return pattern3() + } + make.Bind(s.skipToken(), p.asInstanceOf[Tree$Ident].name, pattern3()); + } else { + p + } + } + + /* Pattern3 ::= SimplePattern [ '*' | '?' | '+' ] + * | SimplePattern {Id SimplePattern} // op2 must not be empty + */ + def pattern3(): Tree = { + val base = sp; + var top = simplePattern(); + if (s.token == IDENTIFIER) { + if (s.name == STAR) { /* p* becomes z@( |(p,z)) */ + s.nextToken(); + val zname = fresh(); + val zvar = make.Ident(s.pos, zname); + return make.Bind( + s.pos, zname, + pN.flattenAlternative( + make.Alternative(s.pos, newTreeArray( + make.Sequence(s.pos, Tree.EMPTY_ARRAY), + pN.flattenSequence(make.Sequence(s.pos, newTreeArray( + top, zvar))))))); + } else if (s.name == PLUS) { /* p+ becomes z@(p,(z| )) */ + s.nextToken(); + val zname = fresh(); + val zvar = make.Ident(s.pos, zname); + return make.Bind( + s.pos, zname, + pN.flattenSequence(make.Sequence(s.pos, newTreeArray( + top, + pN.flattenAlternative(make.Alternative(s.pos, newTreeArray( + zvar, make.Sequence(s.pos, Tree.EMPTY_ARRAY)))))))); + } else if (s.name == OPT) { /* p? becomes (p| ) */ + s.nextToken(); + return pN.flattenAlternative(make.Alternative(s.pos, newTreeArray( + top, + make.Sequence(s.pos, Tree.EMPTY_ARRAY)))); + } + } + while ((s.token == IDENTIFIER) && (s.name != BAR)) { + val tokn = s.name; // for error message + top = reduceStack( + false, base, top, s.name.precedence(), s.name.isLeftAssoc()); + push(top, s.pos, s.name); + ident(); + top = simplePattern(); + if (TreeInfo.isEmptySequence(top)) { + syntaxError(top.pos, "2nd argument to binary op "+ s.name + " may not be empty sequence pattern", false); + } + } + reduceStack(false, base, top, 0, true) + } + + /** SimplePattern ::= varid + * | `_' + * | literal + * | StableId [ `(' [Patterns] `)' ] + * | `(' [Patterns] `)' + * | (word: empty - nothing) + */ + def simplePattern(): Tree = s.token match { + case RPAREN | COMMA => + make.Sequence(s.pos, Tree.EMPTY_ARRAY) // ((nothing)) + case IDENTIFIER | THIS => + if (s.name == BAR) { + make.Sequence(s.pos, Tree.EMPTY_ARRAY); // ((nothing)) + } else { + var t = stableId(); + while (s.token == LPAREN) { + var ts = Tree.EMPTY_ARRAY; + accept(LPAREN); + if (s.token != RPAREN) + ts = patterns(); + accept(RPAREN); + t = make.Apply(s.pos, convertToTypeId(t), ts); + } + t + } + case USCORE => + make.Ident(s.skipToken(), Names.PATTERN_WILDCARD) + case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL => + literal(true) + case LPAREN => + val p = s.pos; + s.nextToken(); + val ts = if (s.token == RPAREN) Tree.EMPTY_ARRAY else patterns(); + var t: Tree = null; + if (ts.length == 1 && !ts(0).isInstanceOf[Tree$Alternative]) { + t = ts(0); + } else { + t = pN.flattenSequence(make.Sequence(s.pos, ts)); + t = pN.elimSequence(t); + } + accept(RPAREN); + t + case _ => + syntaxError("illegal start of pattern", true) + } + +////////// MODIFIERS //////////////////////////////////////////////////////////// + + /** Modifiers ::= {Modifier} + * Modifier ::= final + * | private + * | protected + * | override + * | abstract + */ + def modifiers(): int = { + pushComment(); + var mods = 0; + while (true) { + var mod = 0; + s.token match { + case ABSTRACT => + mod = Modifiers.ABSTRACT; + case FINAL => + mod = Modifiers.FINAL; + case SEALED => + mod = Modifiers.SEALED; + case PRIVATE => + mod = Modifiers.PRIVATE; + case PROTECTED => + mod = Modifiers.PROTECTED; + case OVERRIDE => + mod = Modifiers.OVERRIDE; + case _ => + return mods; + } + if ((mods & mod) != 0) + syntaxError(s.pos, "repeated modifier", false); + mods = mods | mod; + s.nextToken(); + } + 0 //dummy + } + + /** LocalModifiers ::= {LocalModifier} + * LocalModifier ::= final + * | private + */ + def localClassModifiers(): int = { + var mods = 0; + while (true) { + var mod = 0; + s.token match { + case ABSTRACT => + mod = Modifiers.ABSTRACT; + case FINAL => + mod = Modifiers.FINAL; + case SEALED => + mod = Modifiers.SEALED; + case _ => + return mods; + } + if ((mods & mod) != 0) + syntaxError(s.pos, "repeated modifier", false); + mods = mods | mod; + s.nextToken(); + } + 0 //dummy + } + +//////// PARAMETERS ////////////////////////////////////////////////////////// + + /** ParamClauses ::= {ParamClause} + */ + def paramClauses(): Array[Array[Tree$ValDef]] = { + val ts = new ArrayList(); + while (s.token == LPAREN) + ts.add(paramClause()); + ts.toArray(new Array[Array[Tree$ValDef]](ts.size()).asInstanceOf[Array[java.lang.Object]]) + .asInstanceOf[Array[Array[Tree$ValDef]]] + } + + /** ParamClauseOpt ::= [ParamClause] + */ + def paramClauseOpt(): Array[Array[Tree$ValDef]] = + if (s.token == LPAREN) newValDefArrayArray(paramClause()) + else Tree.ValDef_EMPTY_ARRAY_ARRAY; + + /** ParamClause ::= `(' [Param {`,' Param}] `)' + */ + def paramClause(): Array[Tree$ValDef] = { + val pos = accept(LPAREN); + val params = new TreeList(); + if (s.token != RPAREN) { + params.append(param()); + while (s.token == COMMA) { + s.nextToken(); + params.append(param()); + } + } + accept(RPAREN); + params.copyTo(new Array[Tree$ValDef](params.length())) + .asInstanceOf[Array[Tree$ValDef]] + } + + /** Param ::= [def] Id `:' Type [`*'] + */ + def param(): Tree$ValDef = { + val pos = s.pos; + var mods = Modifiers.PARAM; + if (s.token == DEF) { + mods = mods | Modifiers.DEF; + s.nextToken(); + } + val name = ident(); + accept(COLON); + var tp = typ(); + if (s.token == IDENTIFIER && s.name == STAR) { + s.nextToken(); + mods = mods | Modifiers.REPEATED; + tp = make.AppliedType( + tp.pos, + scalaDot(tp.pos, Names.Seq.toTypeName()), + newTreeArray(tp)); + } + make.ValDef(pos, mods, name, tp, Tree.Empty) + } + + /** TypeParamClauseOpt ::= [`[' TypeParam {`,' TypeParam} `]'] + * FunTypeParamClauseOpt ::= [`[' FunTypeParam {`,' FunTypeParam} `]'] + */ + def typeParamClauseOpt(variant: boolean): Array[Tree$AbsTypeDef] = { + val params = new TreeList(); + if (s.token == LBRACKET) { + s.nextToken(); + params.append(typeParam(variant)); + while (s.token == COMMA) { + s.nextToken(); + params.append(typeParam(variant)); + } + accept(RBRACKET); + } + params.copyTo(new Array[Tree$AbsTypeDef](params.length())) + .asInstanceOf[Array[Tree$AbsTypeDef]]; + } + + /** TypeParam ::= [`+' | `-'] FunTypeParam + * FunTypeParam ::= Id TypeBounds + */ + def typeParam(variant: boolean): Tree = { + var mods = Modifiers.PARAM; + if (variant && s.token == IDENTIFIER) { + if (s.name == PLUS) { + s.nextToken(); + mods = mods | Modifiers.COVARIANT; + } else if (s.name == MINUS) { + s.nextToken(); + mods = mods | Modifiers.CONTRAVARIANT; + } + } + typeBounds(s.pos, mods, ident()) + } + + /** TypeBounds ::= [`>:' Type] [`<:' Type] + */ + def typeBounds(pos: int, mods: int, name: Name): Tree = { + val lobound = + if (s.token == SUPERTYPE) { s.nextToken(); typ() } + else scalaDot(pos, Names.All.toTypeName()); + val hibound = + if (s.token == SUBTYPE) { s.nextToken(); typ() } + else scalaDot(pos, Names.Any.toTypeName()); + make.AbsTypeDef(pos, mods, name.toTypeName(), hibound, lobound) + } + +//////// DEFS //////////////////////////////////////////////////////////////// + + /** Import ::= import ImportExpr {`,' ImportExpr} + */ + def importClause(): Array[Tree] = { + accept(IMPORT); + val ts = new TreeList(); + ts.append(importExpr()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(importExpr()); + } + ts.toArray() + } + + /** ImportRef ::= StableId `.' (Id | `_' | ImportSelectors) + */ + def importExpr(): Tree = { + var t: Tree = null; + val startpos = s.pos; + var pos = 0; + if (s.token == THIS) { + t = make.This(s.skipToken(), TypeNames.EMPTY); + t = make.Select(accept(DOT), t, ident()); + pos = accept(DOT); + } else { + val i: Tree$Ident = make.Ident(s.pos, ident()); + pos = accept(DOT); + if (s.token == THIS) { + s.nextToken(); + t = make.This(i.pos, i.name.toTypeName()); + t = make.Select(accept(DOT), t, ident()); + pos = accept(DOT); + } else { + t = i; + } + } + while (true) { + if (s.token == USCORE) { + s.nextToken(); + return make.Import(startpos, t, newNameArray(Names.IMPORT_WILDCARD)); + } else if (s.token == LBRACE) { + return make.Import(startpos, t, importSelectors()); + } else { + val name = ident(); + if (s.token == DOT) { + t = make.Select(pos, t, name); + pos = accept(DOT); + } else { + return make.Import(startpos, t, newNameArray(name, name)); + } + } + } + null //dummy + } + + /** ImportSelectors ::= `{' {ImportSelector `,'} (ImportSelector | `_') `}' + */ + def importSelectors(): Array[Name] = { + val names = new LinkedList(); + accept(LBRACE); + var isLast = importSelector(names); + while (!isLast && s.token == COMMA) { + s.nextToken(); + isLast = importSelector(names); + } + accept(RBRACE); + names.toArray(new Array[Name](0).asInstanceOf[Array[java.lang.Object]]).asInstanceOf[Array[Name]] + } + + /** ImportSelector ::= Id [`=>' Id | `=>' `_'] + */ + def importSelector(names: LinkedList/**/): boolean = + if (s.token == USCORE) { + s.nextToken(); + names.add(Names.IMPORT_WILDCARD); + true + } else { + val name = ident(); + names.add(name); + if (s.token == ARROW) { + s.nextToken(); + if (s.token == USCORE) { + s.nextToken(); + names.add(Names.IMPORT_WILDCARD); + } else { + names.add(ident()); + } + } else { + names.add(name); + } + false + } + + /** Def ::= val PatDef {`,' PatDef} + * | var VarDef {`,' VarDef} + * | def FunDef {`,' FunDef} + * | type TypeDef {`,' TypeDef} + * | ClsDef + * Dcl ::= val ValDcl {`,' ValDcl} + * | var ValDcl {`,' ValDcl} + * | def FunDcl {`,' FunDcl} + * | type TypeDcl {`,' TypeDcl} + */ + def defOrDcl(mods: int): Array[Tree] = { + val ts = new TreeList(); + s.token match { + case VAL => + do { + s.nextToken(); + ts.append(popComment(patDefOrDcl(mods))); + } while (s.token == COMMA); + ts.toArray() + case VAR => + do { + s.nextToken(); + ts.append(popComment(varDefOrDcl(mods))); + } while (s.token == COMMA); + ts.toArray() + case DEF => + do { + s.nextToken(); + ts.append(popComment(funDefOrDcl(mods))); + } while (s.token == COMMA); + ts.toArray() + case TYPE => + do { + s.nextToken(); + ts.append(popComment(typeDefOrDcl(mods))); + } while (s.token == COMMA); + ts.toArray() + case _ => + clsDef(mods) + } + } + + /** ClsDef ::= ([case] class | trait) ClassDef {`,' ClassDef} + * | [case] object ObjectDef {`,' ObjectDef} + */ + def clsDef(_mods: int): Array[Tree] = { + var mods = _mods; + val ts = new TreeList(); + s.token match { + case CLASS | CASECLASS | TRAIT => + if (s.token == CASECLASS) + mods = mods | Modifiers.CASE; + else if (s.token == TRAIT) + mods = mods | Modifiers.TRAIT | Modifiers.ABSTRACT; + do { + s.nextToken(); + ts.append(classDef(mods)); + } while (s.token == COMMA); + ts.toArray() + case OBJECT | CASEOBJECT => + if (s.token == CASEOBJECT) + mods = mods | Modifiers.CASE; + do { + s.nextToken(); + ts.append(objectDef(mods)); + } while (s.token == COMMA); + ts.toArray() + case _ => + newTreeArray(syntaxError("illegal start of definition", true)) + } + } + + /** PatDef ::= Pattern2 [`:' Type] `=' Expr + * ValDcl ::= Id `:' Type + */ + def patDefOrDcl(mods: int): Tree = { + val pos = s.pos; + val pat = pattern2(); + val tp = if (s.token == COLON) typedOpt() else Tree.Empty; + pat match { + case Tree$Ident(name) => + if (tp == Tree.Empty || s.token == EQUALS) + make.ValDef(pos, mods, name, tp, equalsExpr()) + else + make.ValDef(pos, mods | Modifiers.DEFERRED, name, tp, Tree.Empty) + case _ => + make.PatDef(pos, mods, pat, equalsExpr()) + } + } + + /** VarDef ::= Id [`:' Type] `=' Expr + * | Id `:' Type `=' `_' + * VarDcl ::= Id `:' Type + */ + def varDefOrDcl(mods: int): Tree = { + val pos = s.pos; + val name = ident(); + val tp = typedOpt(); + if (tp == Tree.Empty || s.token == EQUALS) { + accept(EQUALS); + val rhs = + if (tp != Tree.Empty && s.token == USCORE) { s.nextToken(); Tree.Empty } + else expr(); + make.ValDef(pos, mods | Modifiers.MUTABLE, name, tp, rhs) + } else { + make.ValDef(pos, mods | Modifiers.MUTABLE | Modifiers.DEFERRED, + name, tp, Tree.Empty); + } + } + + /** FunDef ::= Id [FunTypeParamClause] {ParamClauses} [`:' Type] `=' Expr + * | this ParamClause `=' ConstrExpr + * FunDcl ::= Id [FunTypeParamClause] {ParamClauses} `:' Type + */ + def funDefOrDcl(mods: int): Tree = { + val pos = s.pos; + if (s.token == THIS) { + s.nextToken(); + val vparams = newValDefArrayArray{paramClause()}; + accept(EQUALS); + make.DefDef( + pos, mods, Names.CONSTRUCTOR, + Tree.AbsTypeDef_EMPTY_ARRAY, vparams, Tree.Empty, + constrExpr()); + } else { + val name = ident(); + val tparams = typeParamClauseOpt(false); + val vparams = paramClauses(); + val restype = typedOpt(); + if (s.token == EQUALS || restype == Tree.Empty) + make.DefDef(pos, mods, name, tparams, vparams, restype, equalsExpr()); + else + make.DefDef(pos, mods | Modifiers.DEFERRED, name, + tparams, vparams, restype, Tree.Empty); + } + } + + /** ConstrExpr ::= SelfInvocation + * | `{' SelfInvocation {`;' BlockStat} `}' + * SelfInvocation ::= this ArgumentExpr + */ + def constrExpr(): Tree = + if (s.token == LBRACE) { + val pos = s.skipToken(); + val statlist = new TreeList(); + statlist.append(selfInvocation()); + val stats = + if (s.token == SEMI) { s.nextToken(); blockStatSeq(statlist) } + else statlist.toArray(); + accept(RBRACE); + make.Block(pos, stats) + } else { + selfInvocation() + } + + /** SelfInvocation ::= this ArgumentExprs + */ + def selfInvocation(): Tree = { + val pos = s.pos; + accept(THIS); + make.Apply( + s.pos, make.Ident(pos, Names.CONSTRUCTOR), argumentExprs()); + } + + /** TypeDef ::= Id `=' Type + * TypeDcl ::= Id TypeBounds + */ + def typeDefOrDcl(mods: int): Tree = { + val pos = s.pos; + val name = ident().toTypeName(); + s.token match { + case LBRACKET => + val tparams = typeParamClauseOpt(true); + accept(EQUALS); + make.AliasTypeDef(pos, mods, name, tparams, typ()) + case EQUALS => + s.nextToken(); + make.AliasTypeDef(pos, mods, name, Tree.AbsTypeDef_EMPTY_ARRAY, typ()) + case SUPERTYPE | SUBTYPE | SEMI | COMMA | RBRACE => + typeBounds(pos, mods | Modifiers.DEFERRED, name) + case _ => + syntaxError("`=', `>:', or `<:' expected", true) + } + } + + /** ClassDef ::= Id [TypeParamClause] [ParamClause] [`:' SimpleType] ClassTemplate + */ + def classDef(mods: int): Tree = { + val pos = s.pos; + val clazzname = ident().toTypeName(); + val tparams = typeParamClauseOpt(true); + val params = paramClauseOpt(); + val result = new TreeList(); + popComment(make.ClassDef(pos, mods, clazzname, tparams, params, + simpleTypedOpt(), classTemplate())) + } + + /** ObjectDef ::= Id [`:' SimpleType] ClassTemplate + */ + def objectDef(mods: int): Tree = + popComment(make.ModuleDef( + s.pos, mods, ident(), simpleTypedOpt(), classTemplate())); + + /** ClassTemplate ::= [`extends' Constr] {`with' Constr} [TemplateBody] + */ + def classTemplate(): Tree$Template = { + val pos = s.pos; + if (s.token == EXTENDS) { + s.nextToken(); + template() + } else if (s.token == WITH) { + s.nextToken(); + val parents = new TreeList(); + parents.append(scalaObjectConstr(pos)); + template(parents) + } else if (s.token == LBRACE) { + make.Template( + pos, newTreeArray(scalaObjectConstr(pos)), templateBody()); + } else { + if (!(s.token == SEMI || s.token == COMMA || s.token == RBRACE)) + syntaxError("`extends' or `{' expected", true); + make.Template( + pos, newTreeArray(scalaObjectConstr(pos)), Tree.EMPTY_ARRAY); + } + } + +////////// TEMPLATES //////////////////////////////////////////////////////////// + + + /** Template ::= Constr {`with' Constr} [TemplateBody] + */ + def template(): Tree$Template = + template(new TreeList()); + + def template(parents: TreeList): Tree$Template = { + val pos = s.pos; + parents.append(constr()); + while (s.token == WITH) { + s.nextToken(); + parents.append(constr()); + } + val stats = if (s.token == LBRACE) templateBody() else Tree.EMPTY_ARRAY; + make.Template(pos, parents.toArray(), stats) + } + + /** Constr ::= StableId [TypeArgs] [`(' [Exprs] `)'] + */ + def constr(): Tree = { + var t: Tree = convertToConstr(stableId()); + if (s.token == LBRACKET) + t = make.AppliedType(s.pos, t, typeArgs()); + if (s.token == LPAREN) + t = make.Apply(s.pos, t, argumentExprs()); + applyConstr(t) + } + + /** TemplateBody ::= `{' [TemplateStat {`;' TemplateStat}] `}' + */ + def templateBody(): Array[Tree] = { + accept(LBRACE); + var body = templateStatSeq(); + if (body.length == 0) + body = newTreeArray(Tree.Empty); + accept(RBRACE); + body + } + + /** Refinement ::= `{' [RefineStat {`;' RefineStat}] `}' + */ + def refinement(): Array[Tree] = { + accept(LBRACE); + val body = refineStatSeq(); + accept(RBRACE); + body + } + +/////// STATSEQS ////////////////////////////////////////////////////////////// + + /** Packaging ::= package QualId `{' TopStatSeq `}' + */ + def packaging(): Tree = { + val pos = accept(PACKAGE); + val pkg = qualId(); + accept(LBRACE); + val stats = topStatSeq(); + accept(RBRACE); + make.PackageDef(pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, stats)); + } + + /** TopStatSeq ::= [TopStat {`;' TopStat}] + * TopStat ::= Modifiers ClsDef + * | Packaging + * | Import + * | + */ + def topStatSeq(): Array[Tree] = { + val 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 == OBJECT || + s.token == CASEOBJECT || + isModifier()) { + stats.append(clsDef(modifiers())); + } else if (s.token != SEMI) { + syntaxError("illegal start of class or object definition", true); + } + if (s.token != RBRACE && s.token != EOF) accept(SEMI); + } + stats.toArray() + } + + /** TemplateStatSeq ::= TemplateStat {`;' TemplateStat} + * TemplateStat ::= Import + * | Modifiers Def + * | Modifiers Dcl + * | Expr + * | + */ + def templateStatSeq(): Array[Tree] = { + val 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); + } + stats.toArray() + } + + /** RefineStatSeq ::= RefineStat {`;' RefineStat} + * RefineStat ::= Dcl + * | type TypeDef {`,' TypeDef} + * | + */ + def refineStatSeq(): Array[Tree] = { + val 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); + } + stats.toArray() + } + + /** BlockStatSeq ::= { BlockStat `;' } [Expr] + * BlockStat ::= Import + * | Def + * | LocalModifiers ClsDef + * | Expr + * | + */ + def blockStatSeq(stats: TreeList): Array[Tree] = { + 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); + if (s.token == RBRACE || s.token == CASE) { + stats.append(make.Block(s.pos, Tree.EMPTY_ARRAY)); + } + } else if (isLocalModifier()) { + stats.append(clsDef(localClassModifiers())); + accept(SEMI); + if (s.token == RBRACE || s.token == CASE) { + stats.append(make.Block(s.pos, Tree.EMPTY_ARRAY)); + } + } else if (s.token == SEMI) { + s.nextToken(); + } else { + syntaxError("illegal start of statement", true); + } + } + stats.toArray() + } + + /** CompilationUnit ::= [ package QualId ( `;' | `{' TopStatSeq `}' ) ] TopStatSeq . + */ + def compilationUnit(): Array[Tree] = { + if (s.token == PACKAGE) { + val pos = s.skipToken(); + val pkg = qualId(); + if (s.token == SEMI) { + s.nextToken(); + newTreeArray( + make.PackageDef( + pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, topStatSeq()))); + } else { + val stats = new TreeList(); + accept(LBRACE); + stats.append( + make.PackageDef( + pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, topStatSeq()))); + accept(RBRACE); + stats.append(topStatSeq()); + stats.toArray() + } + } else { + topStatSeq() + } + } +} + + diff --git a/sources/scala/tools/scalac/ast/parser/ParserPhase.scala b/sources/scala/tools/scalac/ast/parser/ParserPhase.scala new file mode 100644 index 0000000000..af445714c4 --- /dev/null +++ b/sources/scala/tools/scalac/ast/parser/ParserPhase.scala @@ -0,0 +1,25 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scala.tools.scalac.ast.parser; + +import scalac.Global; +import scalac.Phase; +import scalac.PhaseDescriptor; +import scalac.Unit; + +class ParserPhase(global: Global, descriptor: PhaseDescriptor) extends Phase(global, descriptor) { + + def apply(units: Array[Unit]): unit = { + for (val i <- Iterator.range(0, units.length)) do { + global.start(); + units(i).body = new Parser(units(i)).parse(); + global.stop("parsed " + units(i).source); + } + } +} diff --git a/sources/scala/tools/scalac/ast/parser/Scanner.scala b/sources/scala/tools/scalac/ast/parser/Scanner.scala new file mode 100644 index 0000000000..ac3adb4d8b --- /dev/null +++ b/sources/scala/tools/scalac/ast/parser/Scanner.scala @@ -0,0 +1,807 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scala.tools.scalac.ast.parser; + +import ch.epfl.lamp.util.Position; +import ch.epfl.lamp.util.SourceFile; + +import scalac._; +import scalac.util.Name; +import scalac.ast.parser.SourceRepresentation; + + +/** A scanner for the programming language Scala. + * + * @author Matthias Zenger, Martin Odersky + * @version 1.0 + */ +class Scanner(_unit: Unit) extends TokenData { + + import Tokens._; + import java.lang.{Integer, Long, Float, Double} + + val unit = _unit; + + /** buffer for the documentation comment + */ + var docBuffer: StringBuffer = null; + + /** add the given character to the documentation buffer + */ + protected def addCharToDoc(ch: byte): unit = + if (docBuffer != null) + docBuffer.append(ch.asInstanceOf[char]); + + /** layout & character constants + */ + val tabinc = 8; + val LF = SourceFile.LF; + val FF = SourceFile.FF; + val CR = SourceFile.CR; + val SU = SourceFile.SU; + + /** the names of all tokens + */ + var tokenName = new Array[Name](128); + var numToken = 0; + + /** keyword array; maps from name indices to tokens + */ + var key: Array[byte] = _; + var maxKey = 0; + + /** we need one token lookahead + */ + val next = new TokenData(), prev = new TokenData(); + + /** the first character position after the previous token + */ + var lastpos = 0; + + /** the last error position + */ + var errpos = -1; + + /** the input buffer: + */ + var buf: Array[byte] = unit.source.bytes(); + var bp: int = -1; + + /** the current character + */ + var ch: byte = _; + + /** the line and column position of the current character + */ + var cline: int = 1; + var ccol: int = 0; + + /** a buffer for character and string literals + */ + var lit = new Array[byte](64); + var litlen: int = _; + + + /** INIT: Construct a scanner from a file input stream. + */ + token = EMPTY; + nextch(); + init(); + nextToken(); + + def nextch(): unit = { + bp = bp + 1; ch = buf(bp); ccol = ccol + 1; + } + + /** read next token and return last position + */ + def skipToken(): int = { + val p = pos; nextToken(); p + } + + def nextToken(): unit = { + if (token == RBRACE) { + val prevpos = pos; + fetchToken(); + token match { + case ELSE | EXTENDS | WITH | YIELD | CATCH | FINALLY | + COMMA | SEMI | DOT | COLON | EQUALS | ARROW | + LARROW | SUBTYPE | SUPERTYPE | HASH | AT | + RPAREN | RBRACKET | RBRACE => + case _ => + if (token == EOF || + ((pos >>> Position.COLUMN_BITS) > + (prevpos >>> Position.COLUMN_BITS))) { + 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 if (token == OBJECT) { + token = CASEOBJECT; + } 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 + */ + private def fetchToken(): unit = { + if (token == EOF) return; + lastpos = Position.encode(cline, ccol); + var index = bp; + while (true) { + ch match { + case ' ' => + nextch(); + case '\t' => + ccol = ((ccol - 1) / tabinc * tabinc) + tabinc; + nextch(); + case CR => + cline = cline + 1; + ccol = 0; + nextch(); + if (ch == LF) { + ccol = 0; + nextch(); + } + case LF | FF => + cline = cline + 1; + ccol = 0; + nextch(); + case _ => + pos = Position.encode(cline, ccol); + index = bp; + ch match { + case 'A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | '_' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | // scala-mode: need to understand multi-line case patterns + 'z' => + nextch(); + getIdentRest(index); // scala-mode: wrong indent for multi-line case blocks + return; + case '~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | '<' | + '>' | '?' | ':' | + '=' | '&' | '|' => + nextch(); + getOperatorRest(index); + return; + case '\\' => + nextch(); + if (ch == '"') { //" + getStringLit(); + token = IDENTIFIER; + } else + syntaxError(pos, "illegal character"); + return; + case '/' => + nextch(); + if (!skipComment()) { + getOperatorRest(index); + return; + } + case '0' => + nextch(); + if (ch == 'x' || ch == 'X') { + nextch(); + getNumber(index + 2, 16); + } else { + getNumber(index, 8); + } + return; // scala-mode: return is a keyword + case '1' | '2' | '3' | '4' | + '5' | '6' | '7' | '8' | '9' => + getNumber(index, 10); + return; + case '\"' => //" scala-mode: need to understand literals + getStringLit(); + return; + case '\'' => + nextch(); + litlen = 0; + ch match { + case 'A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | '_' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | + 'z' => + putch(ch); + nextch(); + if (ch != '\'') { + getIdentRest(index); + token = SYMBOLLIT; + return; + } + case _ => + getlitch(); + } + if (ch == '\'') { + nextch(); + token = CHARLIT; + val ascii = new Array[byte](litlen * 2); + val 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 '(' => //scala-mode: need to understand character quotes + 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; + return; + case _ => + nextch(); + syntaxError("illegal character"); + return; + } + } + } + } + + private def skipComment(): boolean = { + if (ch == '/') { + do { + nextch(); + } while ((ch != CR) && (ch != LF) && (ch != SU)); + true + } else if (ch == '*') { + docBuffer = null; + var openComments = 1; + nextch(); + if (ch == '*') { + docBuffer = new StringBuffer("/**"); + } + while (openComments > 0) { + do { + do { + if (ch == CR) { + cline = cline + 1; + ccol = 0; + nextch(); addCharToDoc(ch); + if (ch == LF) { + ccol = 0; + nextch(); addCharToDoc(ch); + } + } else if (ch == LF) { + cline = cline + 1; + ccol = 0; + nextch(); addCharToDoc(ch); + } else if (ch == '\t') { + ccol = ((ccol - 1) / tabinc * tabinc) + tabinc; + nextch(); addCharToDoc(ch); + } else if (ch == '/') { + nextch(); addCharToDoc(ch); + if (ch == '*') { + nextch(); addCharToDoc(ch); + openComments = openComments + 1; + } + } else { + nextch(); addCharToDoc(ch); + } + } while ((ch != '*') && (ch != SU)); + while (ch == '*') { + nextch(); addCharToDoc(ch); + } + } while (ch != '/' && ch != SU); + if (ch == '/') { + nextch(); + openComments = openComments - 1; + } else { + syntaxError("unclosed comment"); + true; + } + } + true + } else { + false + } + } + + private def getIdentRest(index: int): unit = { + while (true) { + ch match { + case 'A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | + 'z' | + '0' | '1' | '2' | '3' | '4' | + '5' | '6' | '7' | '8' | '9' => + nextch(); + case '_' => + nextch(); + getIdentOrOperatorRest(index); + return; + case _ => + treatIdent(index, bp); + return; + } + } + } + + private def getOperatorRest(index: int): unit = { + while (true) { + ch match { + case '~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | '<' | + '>' | '?' | ':' | '=' | '&' | '|' => + nextch(); + case '/' => + val lastbp = bp; + nextch(); + if (skipComment()) { + treatIdent(index, lastbp); + return; + } + case _ => + treatIdent(index, bp); + return; + } + } + } + + private def getIdentOrOperatorRest(index: int): unit = { + ch match { + case 'A' | 'B' | 'C' | 'D' | 'E' | + 'F' | 'G' | 'H' | 'I' | 'J' | + 'K' | 'L' | 'M' | 'N' | 'O' | + 'P' | 'Q' | 'R' | 'S' | 'T' | + 'U' | 'V' | 'W' | 'X' | 'Y' | + 'Z' | '$' | '_' | + 'a' | 'b' | 'c' | 'd' | 'e' | + 'f' | 'g' | 'h' | 'i' | 'j' | + 'k' | 'l' | 'm' | 'n' | 'o' | + 'p' | 'q' | 'r' | 's' | 't' | + 'u' | 'v' | 'w' | 'x' | 'y' | + 'z' | + '0' | '1' | '2' | '3' | '4' | + '5' | '6' | '7' | '8' | '9' => + getIdentRest(index); + case '~' | '!' | '@' | '#' | '%' | + '^' | '*' | '+' | '-' | '<' | + '>' | '?' | ':' | + '=' | '&' | '|' | '/' => + getOperatorRest(index); + case _ => + treatIdent(index, bp); + } + } + + private def getStringLit(): unit = { + 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"); + } + } + + /** returns true if argument corresponds to a keyword. + * Used in dtd2scala tool. + */ + def isKeyword(str: String) = Name.fromString(str).index <= maxKey; + + def treatIdent(start: int, end: int) = { + name = Name.fromAscii(buf, start, end - start); + token = if (name.index <= maxKey) key(name.index) else IDENTIFIER; + } + + /** generate an error at the given position + */ + def syntaxError(pos: int, msg: String) = { + unit.error(pos, msg); + token = ERROR; + errpos = pos; + } + + /** generate an error at the current token position + */ + def syntaxError(msg: String): unit = syntaxError(pos, msg); + + /** append characteter to "lit" buffer + */ + protected def putch(c: byte) = { + if (litlen == lit.length) { + val newlit = new Array[byte](lit.length * 2); + System.arraycopy(lit, 0, newlit, 0, lit.length); + lit = newlit; + } + lit(litlen) = c; + litlen = litlen + 1; + } + + /** return true iff next 6 characters are a valid unicode sequence: + */ + protected def isUnicode() = + (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 def 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') { + val leadch: byte = ch; + var oct: int = 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(oct.asInstanceOf[byte]); + } else if (ch != SU) { + ch match { + case 'b' | 't' | 'n' | 'f' | 'r' | '\"' /*"*/ | '\'' | '\\' => + putch('\\'.asInstanceOf[byte]); + putch(ch); + case _ => + syntaxError(Position.encode(cline, ccol) - 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 def getFraction(index: int) = { + while (SourceRepresentation.digit2int(ch, 10) >= 0) { + nextch(); + } + token = DOUBLELIT; + if ((ch == 'e') || (ch == 'E')) { + nextch(); + if ((ch == '+') || (ch == '-')) { + val sign: byte = ch; + nextch(); + if (('0' > ch) || (ch > '9')) { + ch = sign; + bp = bp - 1; + ccol = ccol - 1; + } + } + while (SourceRepresentation.digit2int(ch, 10) >= 0) { + nextch(); + } + } + var 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 { + case _: NumberFormatException => + 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 def makeInt (index: int, len: int, base: int, max: long): unit = { + intVal = 0; + val divider = if (base == 10) 1 else 2; + var i = 0; + while (i < len) { + val 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; + i = i + 1; + } + } + + /** read a number, + * and convert buf[index..], setting either intVal or floatVal. + * base = the base of the number; one of 8, 10, 16. + */ + protected def getNumber(index: int, base: int) = { + while (SourceRepresentation.digit2int(ch, if (base == 8) 10 else base) >= 0) { + nextch(); + } + if (base <= 10 && ch == '.') { + nextch(); + if ((ch >= '0') && (ch <= '9')) + getFraction(index); + else { + bp = bp - 1; + ch = buf(bp); + ccol = ccol - 1; + makeInt(index, bp - index, base, Integer.MAX_VALUE); + intVal = intVal.asInstanceOf[int]; + 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 = intVal.asInstanceOf[int]; + token = INTLIT; + } + } + } + + def name2token(name: Name): int = + if (name.index <= maxKey) key(name.index) else IDENTIFIER; + + def token2string(token: int): String = token match { + case IDENTIFIER => + "identifier" + case CHARLIT => + "character literal" + case INTLIT => + "integer literal" + case LONGLIT => + "long literal" + case FLOATLIT => + "float literal" + case DOUBLELIT => + "double literal" + case STRINGLIT => + "string literal" + case SYMBOLLIT => + "symbol literal" + case LPAREN => + "'('" + case RPAREN => + "')'" + case LBRACE => + "'{'" + case RBRACE => + "'}'" + case LBRACKET => + "'['" + case RBRACKET => + "']'" + case EOF => + "eof" + case ERROR => + "something" + case SEMI => + "''" + case COMMA => + "','" + case CASECLASS => + "case class" + case CASEOBJECT => + "case object" + case _ => + try { + "'" + tokenName(token).toString() + "'" + } catch { + case _: ArrayIndexOutOfBoundsException => + "'<" + token + ">'" + case _: NullPointerException => + "'<(" + token + ")>'" + } + } + + override def toString() = token match { + case IDENTIFIER => + "id(" + name + ")" + case CHARLIT => + "char(" + intVal + ")" + case INTLIT => + "int(" + intVal + ")" + case LONGLIT => + "long(" + intVal + ")" + case FLOATLIT => + "float(" + floatVal + ")" + case DOUBLELIT => + "double(" + floatVal + ")" + case STRINGLIT => + "string(" + name + ")" + case SEMI => + ";" + case COMMA => + "," + case _ => + token2string(token) + } + + protected def enterKeyword(s: String, tokenId: int) = { + while (tokenId > tokenName.length) { + val newTokName = new Array[Name](tokenName.length * 2); + System.arraycopy(tokenName, 0, newTokName, 0, newTokName.length); + tokenName = newTokName; + } + val n = Name.fromString(s); + tokenName(tokenId) = n; + if (n.index > maxKey) maxKey = n.index; + if (tokenId >= numToken) numToken = tokenId + 1; + } + + protected def init() = { + initKeywords(); + key = new Array[byte](maxKey+1); + for (val i <- Iterator.range(0, maxKey)) do + key(i) = IDENTIFIER; + for (val j <- Iterator.range(0, numToken)) do + if (tokenName(j) != null) key(tokenName(j).index) = j.asInstanceOf[byte]; + } + + protected def initKeywords() = { + enterKeyword("abstract", ABSTRACT); + enterKeyword("case", CASE); + enterKeyword("class", CLASS); + enterKeyword("catch", CATCH); + enterKeyword("def", DEF); + enterKeyword("do", DO); + enterKeyword("else", ELSE); + enterKeyword("extends", EXTENDS); + enterKeyword("false", FALSE); + enterKeyword("final", FINAL); + enterKeyword("finally", FINALLY); + enterKeyword("for", FOR); + enterKeyword("if", IF); + enterKeyword("import", IMPORT); + enterKeyword("new", NEW); + enterKeyword("null", NULL); + enterKeyword("object", OBJECT); + enterKeyword("override", OVERRIDE); + enterKeyword("package", PACKAGE); + enterKeyword("private", PRIVATE); + enterKeyword("protected", PROTECTED); + enterKeyword("return", RETURN); + enterKeyword("sealed", SEALED); + enterKeyword("super", SUPER); + enterKeyword("this", THIS); + enterKeyword("throw", THROW); + enterKeyword("trait", TRAIT); + enterKeyword("true", TRUE); + enterKeyword("try", TRY); + enterKeyword("type", TYPE); + enterKeyword("val", VAL); + enterKeyword("var", VAR); + enterKeyword("with", WITH); + enterKeyword("while", WHILE); + enterKeyword("yield", YIELD); + enterKeyword(".", DOT); + enterKeyword("_", USCORE); + enterKeyword(":", COLON); + enterKeyword("=", EQUALS); + enterKeyword("=>", ARROW); + enterKeyword("<-", LARROW); + enterKeyword("<:", SUBTYPE); + enterKeyword(">:", SUPERTYPE); + enterKeyword("#", HASH); + enterKeyword("@", AT); + } +} + + diff --git a/sources/scala/tools/scalac/ast/parser/TokenData.scala b/sources/scala/tools/scalac/ast/parser/TokenData.scala new file mode 100644 index 0000000000..65ed04e34c --- /dev/null +++ b/sources/scala/tools/scalac/ast/parser/TokenData.scala @@ -0,0 +1,46 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scala.tools.scalac.ast.parser; + +import scalac.util.Name; + +/** A class for representing a token's data. + * + * @author Matthias Zenger + * @version 1.0 + */ +class TokenData { + + import Tokens._; + + /** the next token + */ + var token: int = EMPTY; + + /** the token's position. pos = line << Position.LINESHIFT + col + */ + var pos: int = 0; + + /** the name of an identifier or token + */ + var name: Name = null; + + /** the value of a number + */ + var intVal: long = 0; + var floatVal: double = 0; + + def copyFrom(td: TokenData) = { + this.token = td.token; + this.pos = td.pos; + this.name = td.name; + this.intVal = td.intVal; + this.floatVal = td.floatVal; + } +} diff --git a/sources/scala/tools/scalac/ast/parser/Tokens.scala b/sources/scala/tools/scalac/ast/parser/Tokens.scala new file mode 100644 index 0000000000..76d5732ed8 --- /dev/null +++ b/sources/scala/tools/scalac/ast/parser/Tokens.scala @@ -0,0 +1,92 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scala.tools.scalac.ast.parser; + +object Tokens { + val EMPTY = -3, + UNDEF = -2, + ERROR = -1, + EOF = 0, + + /* literals */ + CHARLIT = 1, + INTLIT = 2, + LONGLIT = 3, + FLOATLIT = 4, + DOUBLELIT = 5, + STRINGLIT = 6, + SYMBOLLIT = 7, + + /* identifier */ + IDENTIFIER = 10, + + /* keywords */ + IF = 20, + FOR = 21, + ELSE = 22, + THIS = 23, + NULL = 24, + NEW = 25, + WITH = 26, + SUPER = 27, + CASE = 28, + CASECLASS = 29, + CASEOBJECT = 30, + VAL = 31, + ABSTRACT = 32, + FINAL = 33, + PRIVATE = 34, + PROTECTED = 35, + OVERRIDE = 36, + VAR = 37, + DEF = 38, + TYPE = 39, + EXTENDS = 40, + TRUE = 41, + FALSE = 42, + OBJECT = 43, + CLASS = 44, + + IMPORT = 46, + PACKAGE = 47, + YIELD = 48, + DO = 49, + TRAIT = 50, + SEALED = 51, + THROW = 52, + TRY = 53, + CATCH = 54, + FINALLY = 55, + WHILE = 56, + RETURN = 57, + + /* special symbols */ + COMMA = 61, + SEMI = 62, + DOT = 63, + USCORE = 64, + COLON = 65, + EQUALS = 66, + LARROW = 67, + ARROW = 68, + SUBTYPE = 69, + SUPERTYPE = 70, + HASH = 71, + AT = 72, + + /* parenthesis */ + LPAREN = 90, + RPAREN = 91, + LBRACKET = 92, + RBRACKET = 93, + LBRACE = 94, + RBRACE = 95; +} + + diff --git a/sources/scala/tools/scalac/ast/printer/HTMLPrinter.scala b/sources/scala/tools/scalac/ast/printer/HTMLPrinter.scala new file mode 100644 index 0000000000..2373c10e8e --- /dev/null +++ b/sources/scala/tools/scalac/ast/printer/HTMLPrinter.scala @@ -0,0 +1,167 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ + +package scala.tools.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; +import scalac.ast.Tree; + +/** + * HTML pretty printer for Scala abstract syntax trees. + * + * @author Michel Schinz + * @version 1.0 + */ + +class HTMLTreePrinter(stream: OutputStream) extends TextTreePrinter(stream) { + protected var outSectionLevel = 1; + protected var started = false; + + override def begin(): unit = { + assert(!started); + + super.begin(); + out.println(""); + out.println(""); + out.println(""); + out.println(""); + out.println(""); + out.println("Scala tree"); + out.println(""); + out.println(""); + + started = true; + } + + override def end(): unit = { + assert(started); + + out.println(""); + out.println(""); + super.end(); + + started = false; + } + + override def beginSection(level: int, title: String) = { + outSectionLevel = Math.min(level, 4); + beginSection1(outSectionLevel, title); + } + + protected def beginSection1(level: int, title: String): unit = { + if (level == 1) + out.println("
"); + val tag: String = "h" + level; + startTag(tag); + print(Simple(title)); + endTag(tag); + } + + protected def startTag(tag: String): unit = { + out.print('<'); out.print(tag); out.print('>'); + } + + protected def startTag(tag: String, attr1: String, val1: String): unit = { + out.print('<'); + out.print(tag); + out.print(' '); + out.print(attr1); + out.print("=\""); + out.print(val1); + out.print("\">"); + } + + protected def endTag(tag: String): unit = { + out.print(""); + } + + protected def startSpan(cls: String): unit = { + startTag("span", "class", cls); + } + + protected def endSpan(): unit = { + endTag("span"); + } + + override protected def printString(str: String): unit = { + for (val i <- Iterator.range(0, str.length())) do { + val c = str.charAt(i); + val entity: String = c match { + case '<' => "lt"; + case '>' => "gt"; + case '&' => "amp"; + case _ => null + } + if (entity != null) { + out.print('&'); + out.print(entity); + out.print(';'); + } else { + out.print(c); + } + } + } + + protected val symAnchors = new HashMap/**/(); + + protected def symbolAnchor(sym: Symbol, usage: SymbolUsage): String = { + var anchorId = symAnchors.get(sym).asInstanceOf[Integer]; + if (anchorId == null) { + anchorId = new Integer(symAnchors.size()); + symAnchors.put(sym, anchorId); + } + if (usage == Definition) + return anchorId.toString(); + else + return "#" + anchorId.toString(); + } + + override protected def print(text: Text): unit = text match { + case Keyword(name) => + startSpan("kw"); + printString(name); + endSpan(); + case Literal(str) => + startSpan("lit"); + printString(str); + endSpan(); + case Identifier(symbol, name, usage) => + val defined = (usage == Definition); + if (defined) startSpan("idDef"); + if (symbol != null) { + val attr = if (defined) "name" else "href"; + startTag("a", attr, symbolAnchor(symbol, usage)); + } + printString(name); + if (symbol != null) + endTag("a"); + if (defined) endSpan(); + case _ => + super.print(text); + } + + override def print(unit: Unit) = super.print(unit); + override def print(str: String) = super.print(str); + override def print(tree: Tree) = super.print(tree); + + override protected def printUnitHeader(unit: Unit): unit = { + beginSection1(outSectionLevel + 1, unit.source.toString()); + startTag("pre"); + } + + override protected def printUnitFooter(unit: Unit): unit = { + endTag("pre"); + } +} diff --git a/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala b/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala new file mode 100644 index 0000000000..28ff80c93a --- /dev/null +++ b/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala @@ -0,0 +1,667 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ + +package scala.tools.scalac.ast.printer; + +import scalac.ast.printer._; +import scalac.ast._; +import scalac.symtab._; +import scalac.util.Debug; +import scalac.Global; +import scalac.Unit; +import scalac.util.Name; +import scalac.util.TypeNames; + +import java.io._; + +/** + * Text pretty printer for Scala abstract syntax trees. + * + * @author Michel Schinz, Matthias Zenger + * @version 1.0 + */ +class TextTreePrinter(_out: PrintWriter, autoFlush: boolean) with TreePrinter { + + val out = _out; + + def this(stream: OutputStream, autoFlush: boolean) = + this(new PrintWriter(stream), autoFlush); + + def this(stream: OutputStream) = this(stream, false); + + def this(stream: Writer, autoFlush: boolean) = + this(new PrintWriter(stream), autoFlush); + + def this(stream: Writer) = this(stream, false); + + def this() = this(System.out); + + protected var indentMargin = 0; + protected val INDENT_STEP = 2; + protected var INDENT_STRING = + " "; + protected val MAX_INDENT = INDENT_STRING.length(); + + def begin() = (); + def end() = flush(); + def flush() = out.flush(); + + def print(str: String) = { + out.print(str); + if (autoFlush) flush(); + this + } + + def println() = { + out.println(); + if (autoFlush) flush(); + this + } + + def beginSection(level: int, title: String) = { + out.println("[[" + title + "]]"); + flush(); + } + + protected def indent() = { + indentMargin = indentMargin + Math.min(MAX_INDENT, INDENT_STEP); + } + + protected def undent() = { + indentMargin = indentMargin - Math.max(0, INDENT_STEP); + } + + protected def printString(str: String) = { + out.print(str); + if (autoFlush) flush(); + } + + protected def printNewLine() = { + out.println(); + while (indentMargin > INDENT_STRING.length()) { + INDENT_STRING = INDENT_STRING + INDENT_STRING; + } + if (indentMargin > 0) + out.write(INDENT_STRING, 0, indentMargin); + if (autoFlush) flush(); + } + + abstract class Text; + case object None extends Text; + case object Space extends Text; + case object Newline extends Text; + case class Simple(str: String) extends Text; + case class Literal(str: String) extends Text; + case class Keyword(name: String) extends Text; + case class Identifier(symbol: Symbol, name: String, usage: SymbolUsage) + extends Text; + case class Sequence(elements: List[Text]) extends Text; + + abstract class SymbolUsage; + case object Definition extends SymbolUsage; + case object Use extends SymbolUsage; + + protected def print(text: Text): unit = text match { + case None => ; + case Space => printString(" ") + case Newline => printNewLine() + case Simple(str) => printString(str) + case Literal(str) => printString(str) + case Keyword(name) => printString(name) + case Identifier(sym, name, _) => + printString(name); + if (sym != null && Global.instance.uniqid) + printString("#" + Global.instance.uniqueID.id(sym)) + case Sequence(elements) => print(elements) + } + + protected def print(texts: List[Text]): unit = + for (val text <- texts) do print(text); + + protected final val KW_ABSTRACT = Keyword("abstract"); + protected final val KW_CASE = Keyword("case"); + protected final val KW_CLASS = Keyword("class"); + protected final val KW_DEF = Keyword("def"); + protected final val KW_DO = Keyword("do"); + protected final val KW_ELSE = Keyword("else"); + protected final val KW_EXTENDS = Keyword("extends"); + protected final val KW_FINAL = Keyword("final"); + protected final val KW_SEALED = Keyword("sealed"); + protected final val KW_FOR = Keyword("for"); + protected final val KW_IF = Keyword("if"); + protected final val KW_IMPORT = Keyword("import"); + protected final val KW_INTERFACE = Keyword("interface"); + protected final val KW_OBJECT = Keyword("object"); + protected final val KW_NEW = Keyword("new"); + protected final val KW_NULL = Keyword("null"); + protected final val KW_OUTER = Keyword("outer"); + protected final val KW_OVERRIDE = Keyword("override"); + protected final val KW_PACKAGE = Keyword("package"); + protected final val KW_PRIVATE = Keyword("private"); + protected final val KW_PROTECTED = Keyword("protected"); + protected final val KW_RETURN = Keyword("return"); + protected final val KW_STATIC = Keyword("static"); + protected final val KW_SUPER = Keyword("super"); + protected final val KW_THIS = Keyword("this"); + protected final val KW_TYPE = Keyword("type"); + protected final val KW_VAL = Keyword("val"); + protected final val KW_VAR = Keyword("var"); + protected final val KW_WITH = Keyword("with"); + protected final val KW_YIELD = Keyword("yield"); + + protected final val TXT_ERROR = Simple(""); + protected final val TXT_UNKNOWN = Simple(""); + protected final val TXT_NULL = Simple(""); + protected final val TXT_OBJECT_COMMENT = Simple("/*object*/ "); + protected final val TXT_EMPTY = Simple(""); + + protected final val TXT_QUOTE = Simple("\""); + protected final val TXT_PLUS = Simple("+"); + protected final val TXT_COLON = Simple(":"); + protected final val TXT_SEMICOLON = Simple(";"); + protected final val TXT_DOT = Simple("."); + protected final val TXT_COMMA = Simple(","); + protected final val TXT_EQUAL = Simple("="); + protected final val TXT_SUPERTYPE = Simple(">:"); + protected final val TXT_SUBTYPE = Simple("<:"); + protected final val TXT_HASH = Simple("#"); + protected final val TXT_RIGHT_ARROW = Simple("=>"); + protected final val TXT_LEFT_PAREN = Simple("("); + protected final val TXT_RIGHT_PAREN = Simple(")"); + protected final val TXT_LEFT_BRACE = Simple("{"); + protected final val TXT_RIGHT_BRACE = Simple("}"); + protected final val TXT_LEFT_BRACKET = Simple("["); + protected final val TXT_RIGHT_BRACKET = Simple("]"); + protected final val TXT_BAR = Simple("|"); + protected final val TXT_AT = Simple("@"); + + protected final val TXT_WITH_SP = + Sequence(List(Space, KW_WITH, Space)); + protected final val TXT_BLOCK_BEGIN = + Sequence(List(TXT_LEFT_BRACE, Newline)); + protected final val TXT_BLOCK_END = + Sequence(List(Newline, TXT_RIGHT_BRACE)); + protected final val TXT_BLOCK_SEP = + Sequence(List(TXT_SEMICOLON, Newline)); + protected final val TXT_COMMA_SP = + Sequence(List(TXT_COMMA, Space)); + protected final val TXT_ELSE_NL = + Sequence(List(KW_ELSE, Newline)); + protected final val TXT_BAR_SP = + Sequence(List(Space, TXT_BAR, Space)); + + def print(unit: Unit): unit = { + printUnitHeader(unit); + if (unit.body != null) { + for (val i <- Iterator.range(0, unit.body.length)) do { + print(unit.body(i)); + print(TXT_BLOCK_SEP); + } + } else { + print(TXT_NULL); + } + printUnitFooter(unit); + flush(); + } + + protected def printUnitHeader(unit: Unit): unit = + print(Simple("// Scala source: " + unit.source + "\n")); + + protected def printUnitFooter(unit: Unit): unit = + print(Newline); + + def print(tree: Tree): TreePrinter = { + tree match { + case Tree$Bad() => + print(TXT_ERROR); + + case Tree.Empty => + print(TXT_EMPTY); + + case Tree$ClassDef(mods, name, tparams, vparams, tpe, impl) => + printModifiers(mods); + print(if ((mods & Modifiers.INTERFACE) != 0) KW_INTERFACE else KW_CLASS); + print(Space); + printSymbolDefinition(tree.symbol(), name); + printParams(tparams); + printParams(vparams); + printOpt(TXT_COLON, tpe, false); + printTemplate(KW_EXTENDS, impl, true); + + case Tree$PackageDef(packaged, impl) => + print(KW_PACKAGE); + print(Space); + print(packaged); + printTemplate(KW_WITH, impl, true); + + case Tree$ModuleDef(mods, name, tpe, impl) => + printModifiers(mods); + print(KW_OBJECT); + print(Space); + printSymbolDefinition(tree.symbol(), name); + printOpt(TXT_COLON, tpe, false); + printTemplate(KW_EXTENDS, impl, true); + + case Tree$ValDef(mods, name, tpe, rhs) => + printModifiers(mods); + if ((mods & Modifiers.MUTABLE) != 0) { + print(KW_VAR); + } else { + if ((mods & Modifiers.MODUL) != 0) print(TXT_OBJECT_COMMENT); + print(KW_VAL); + } + print(Space); + printSymbolDefinition(tree.symbol(), name); + printOpt(TXT_COLON, tpe, false); + if ((mods & Modifiers.DEFERRED) == 0) { + print(Space); print(TXT_EQUAL); print(Space); + if (rhs == Tree.Empty) print("_"); + else print(rhs); + } + + case Tree$PatDef(mods, pat, rhs) => + printModifiers(mods); + print(KW_VAL); + print(Space); + print(pat); + printOpt(TXT_EQUAL, rhs, true); + + case Tree$DefDef(mods, name, tparams, vparams, tpe, rhs) => + printModifiers(mods); + print(KW_DEF); + print(Space); + if (name.isTypeName()) print(KW_THIS); + else printSymbolDefinition(tree.symbol(), name); + printParams(tparams); + printParams(vparams); + printOpt(TXT_COLON, tpe, false); + printOpt(TXT_EQUAL, rhs, true); + + case Tree$AbsTypeDef(mods, name, rhs, lobound) => + printModifiers(mods); + print(KW_TYPE); + print(Space); + printSymbolDefinition(tree.symbol(), name); + printBounds(lobound, rhs); + + case Tree$AliasTypeDef(mods, name, tparams, rhs) => + printModifiers(mods); + print(KW_TYPE); + print(Space); + printSymbolDefinition(tree.symbol(), name); + printParams(tparams); + printOpt(TXT_EQUAL, rhs, true); + + case Tree$Import(expr, selectors) => + print(KW_IMPORT); + print(Space); + print(expr); + print(TXT_DOT); + print(TXT_LEFT_BRACE); + var i = 0; + while (i < selectors.length) { + 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()); + } + i = i + 2; + } + print(TXT_RIGHT_BRACE); + + case Tree$CaseDef(pat, guard, body) => + print(KW_CASE); + print(Space); + print(pat); + printOpt(KW_IF, guard, true); + print(Space); + print(TXT_RIGHT_ARROW); + print(Space); + print(body); + + case Tree$LabelDef(name, params, rhs) => + printSymbolDefinition(tree.symbol(), name); + printArray(params.asInstanceOf[Array[Tree]], TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP); + print(rhs); + + case Tree$Block(stats) => + printArray(stats, TXT_BLOCK_BEGIN, TXT_BLOCK_END, TXT_BLOCK_SEP); + printType(tree); + + case Tree$Sequence(trees) => + printArray(trees, TXT_LEFT_BRACKET, TXT_RIGHT_BRACKET, TXT_COMMA_SP); + + case Tree$Alternative(trees) => + printArray(trees, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_BAR_SP); + + case Tree$Bind(name, t) => + printSymbolDefinition(tree.symbol(), name); + print(Space); + print(TXT_AT); + print(Space); + print( t ); + + case Tree$Visitor(cases) => + printArray(cases.asInstanceOf[Array[Tree]], TXT_BLOCK_BEGIN, TXT_BLOCK_END, Newline); + + case Tree$Function(vparams, body) => + print(TXT_LEFT_PAREN); + printParams(vparams); + print(Space); + print(TXT_RIGHT_ARROW); + print(Space); + print(body); + print(TXT_RIGHT_PAREN); + + case Tree$Assign(lhs, rhs) => + print(lhs); + print(Space); + print(TXT_EQUAL); + print(Space); + print(rhs); + + case Tree$If(cond, thenp, elsep) => + print(KW_IF); + print(Space); + print(TXT_LEFT_PAREN); + print(cond); + print(TXT_RIGHT_PAREN); + indent(); print(Newline); + print(thenp); + undent(); print(Newline); + indent(); printOpt(TXT_ELSE_NL, elsep, false); undent(); + printType(tree); + + case Tree$Switch(expr, tags, bodies, defaultBody) => + print(""); + print(Space); + print(TXT_LEFT_PAREN); + print(expr); + print(TXT_RIGHT_PAREN); + print(Space); + indent(); + print(TXT_BLOCK_BEGIN); + + for (val i <- Iterator.range(0, tags.length)) do { + print(KW_CASE); + print(Space); + print("" + tags(i)); + print(Space); + print(TXT_RIGHT_ARROW); + print(Space); + print(bodies(i)); + print(Newline); + } + print(" => "); + print(defaultBody); + undent(); + print(TXT_BLOCK_END); + + case Tree$Return(expr) => + print(KW_RETURN); + print(Space); + print(expr); + + case Tree$New(templ) => + printTemplate(KW_NEW, templ, false); + printType(tree); + + case Tree$Typed(expr, tpe) => + print(TXT_LEFT_PAREN); + print(expr); + print(TXT_RIGHT_PAREN); + print(Space); + print(TXT_COLON); + print(Space); + print(tpe); + printType(tree); + + case Tree$TypeApply(fun, targs) => + print(fun); + printArray(targs, TXT_LEFT_BRACKET, TXT_RIGHT_BRACKET, TXT_COMMA_SP); + printType(tree); + + case Tree$Apply(fun, vargs) => + if (fun.isInstanceOf[Tree$TypeTerm]) + print(fun.\"type"/*"*/.resultType().symbol().fullName().toString()); + else + print(fun); + printArray(vargs, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP); + printType(tree); + + case Tree$Super(qualifier, mixin) => + if (qualifier != TypeNames.EMPTY) { + printSymbolUse(tree.symbol(), qualifier); + print(TXT_DOT); + } + print(KW_SUPER); + if (mixin != TypeNames.EMPTY) { + print(TXT_LEFT_PAREN); + print(mixin.toString()); + print(TXT_RIGHT_PAREN); + } + printType(tree); + + case Tree$This(name) => + if (name != TypeNames.EMPTY) { + printSymbolUse(tree.symbol(), name); + print(TXT_DOT); + } + print(KW_THIS); + printType(tree); + + case Tree$Select(qualifier, name) => + print(qualifier); + print(TXT_DOT); + printSymbolUse(tree.symbol(), name); + printType(tree); + + case Tree$Ident(name) => + printSymbolUse(tree.symbol(), name); + printType(tree); + + case Tree$Literal(obj) => + val str = obj match { + case s: String => "\"" + s + "\""; + case c: Character => "\'" + c + "\'"; + case _ => String.valueOf(obj); + } + print(Literal(str)); + printType(tree); + + case Tree$TypeTerm() => + print(tree.\"type"/*"*/.toString()); + + case Tree$SingletonType(ref) => + print(ref); + print(TXT_DOT); print(KW_TYPE); + + case Tree$SelectFromType(qualifier, selector) => + print(qualifier); + print(Space); print(TXT_HASH); print(Space); + printSymbolUse(tree.symbol(), selector); + + case Tree$FunType(argtpes, restpe) => + printArray(argtpes, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP); + print(TXT_RIGHT_ARROW); + print(restpe); + + case Tree$CompoundType(baseTypes, refinements) => + printArray(baseTypes, None, None, TXT_WITH_SP); + printArray(refinements, TXT_BLOCK_BEGIN, TXT_BLOCK_END, Newline); + + case Tree$AppliedType(tpe, args) => + print(tpe); + indent(); + print(TXT_LEFT_BRACKET); + for (val i <- Iterator.range(0, args.length)) do { + if (i > 0) print(TXT_COMMA_SP); + print(args(i)); + } + undent(); + print(TXT_RIGHT_BRACKET); + + case Tree$Template(parents, body) => + Debug.abort("unexpected case: template"); + + case _ => + print(TXT_UNKNOWN); + } + if (autoFlush) + flush(); + return this; + } + + // Printing helpers + + protected def printArray(trees: Array[Tree], open: Text, close: Text, sep: Text): unit = { + indent(); + print(open); + for (val i <- Iterator.range(0, trees.length)) do { + if (i > 0) print(sep); + print(trees(i)); + } + undent(); + print(close); + } + + protected def printOpt(prefix: Text, tree: Tree, spaceBefore: boolean): unit = + if (tree != Tree.Empty) { + if (spaceBefore) + print(Space); + print(prefix); + print(Space); + print(tree); + } + + // Printing of symbols + + protected def symbolString(symbol: Symbol, name: Name): String = + if (symbol != null) symbol.simpleName().toString() + else name.toString(); + + protected def printSymbolDefinition(symbol: Symbol, name: Name): unit = + print(Identifier(symbol, symbolString(symbol, name), Definition)); + + protected def printSymbolUse(symbol: Symbol, name: Name): unit = + print(Identifier(symbol, symbolString(symbol, name), Use)); + + // Printing of trees + + protected def printType(tree: Tree): unit = + if (Global.instance.printtypes) { + print(TXT_LEFT_BRACE); + print(if (tree.\"type"/*"*/ != null) Simple(tree.\"type"/*"*/.toString()) + else TXT_NULL); + print(TXT_RIGHT_BRACE); + } + + protected def printModifiers(flags: int): unit = { + if ((flags & Modifiers.ABSTRACT) != 0) { + print(KW_ABSTRACT); + print(Space); + } + if ((flags & Modifiers.FINAL) != 0) { + print(KW_FINAL); + print(Space); + } + if ((flags & Modifiers.SEALED) != 0) { + print(KW_SEALED); + print(Space); + } + if ((flags & Modifiers.PRIVATE) != 0) { + print(KW_PRIVATE); + print(Space); + } + if ((flags & Modifiers.PROTECTED) != 0) { + print(KW_PROTECTED); + print(Space); + } + if ((flags & Modifiers.OVERRIDE) != 0) { + print(KW_OVERRIDE); + print(Space); + } + if ((flags & Modifiers.CASE) != 0) { + print(KW_CASE); + print(Space); + } + if ((flags & Modifiers.DEF) != 0) { + print(KW_DEF); + print(Space); + } + if ((flags & Modifiers.STATIC) != 0) { + print(KW_STATIC); + print(Space); + } + } + + protected def printTemplate(prefix: Text, + templ: Tree$Template, + spaceBefore: boolean): unit = { + if (! (templ.parents.length == 0 + || (templ.parents.length == 1 + && templ.parents(0) == Tree.Empty))) { + if (spaceBefore) + print(Space); + print(prefix); + print(Space); + printArray(templ.parents, None, None, TXT_WITH_SP); + } + if (templ.body.length > 0) { + print(Space); + printArray(templ.body, TXT_BLOCK_BEGIN, TXT_BLOCK_END, TXT_BLOCK_SEP); + } + } + + protected def printParams(tparams: Array[Tree$AbsTypeDef]): unit = + if (tparams.length > 0) { + print(TXT_LEFT_BRACKET); + for (val i <- Iterator.range(0, tparams.length)) do { + if (i > 0) print(TXT_COMMA_SP); + printParam(tparams(i)); + } + print(TXT_RIGHT_BRACKET); + } + + protected def printParams(vparamss: Array[Array[Tree$ValDef]]): unit = + for (val i <- Iterator.range(0, vparamss.length)) do + printParams(vparamss(i)); + + protected def printParams(vparams: Array[Tree$ValDef]): unit = { + print(TXT_LEFT_PAREN); + for (val i <- Iterator.range(0, vparams.length)) do { + if (i > 0) print(TXT_COMMA_SP); + printParam(vparams(i)); + } + print(TXT_RIGHT_PAREN); + } + + protected def printParam(tree: Tree): unit = tree match { + case Tree$AbsTypeDef(mods, name, bound, lobound) => + printModifiers(mods); + printSymbolDefinition(tree.symbol(), name); + printBounds(lobound, bound); + + case Tree$ValDef(mods, name, tpe, Tree.Empty) => + printModifiers(mods); + printSymbolDefinition(tree.symbol(), name); + printOpt(TXT_COLON, tpe, false); + + case _ => + Debug.abort("bad parameter: " + tree); + } + + protected def printBounds(lobound: Tree, hibound: Tree): unit = { + if (!"scala.All".equals(lobound.toString())) + printOpt(TXT_SUPERTYPE, lobound, true); + if (!"scala.Any".equals(hibound.toString())) + printOpt(TXT_SUBTYPE, hibound, true); + } +} diff --git a/sources/scalac/CompilerPhases.java b/sources/scalac/CompilerPhases.java index 93007eda28..e0329bc7e6 100644 --- a/sources/scalac/CompilerPhases.java +++ b/sources/scalac/CompilerPhases.java @@ -46,6 +46,24 @@ public class CompilerPhases { /** The list containing the active phases */ private final List phases; + /** Phase names, can be overridden to install . + */ + protected Class PARSER_PHASE() { return scalac.ast.parser.ParserPhase.class; } + protected Class ANALYZER_PHASE() { return scalac.typechecker.AnalyzerPhase.class; } + protected Class REFCHECK_PHASE() { return scalac.typechecker.RefCheckPhase.class; } + protected Class UNCURRY_PHASE() { return scalac.transformer.UnCurryPhase.class; } + protected Class TRANSMATCH_PHASE() { return scalac.transformer.TransMatchPhase.class; } + protected Class LAMBDALIFT_PHASE() { return scalac.transformer.LambdaLiftPhase.class; } + protected Class EXPLICITOUTER_PHASE() { return scalac.transformer.ExplicitOuterClassesPhase.class; } + protected Class ADDACCESSORS_PHASE() { return scalac.transformer.AddAccessorsPhase.class; } + protected Class TAILCALL_PHASE() { return scalac.transformer.TailCallPhase.class; } + protected Class ADDINTERFACES_PHASE() { return scalac.transformer.AddInterfacesPhase.class; } + protected Class EXPANDMIXIN_PHASE() { return scalac.transformer.ExpandMixinsPhase.class; } + protected Class ADDCONSTRUCTORS_PHASE() { return scalac.transformer.AddConstructorsPhase.class; } + protected Class ERASURE_PHASE() { return scalac.transformer.ErasurePhase.class; } + protected Class GENMSIL_PHASE() { return scalac.backend.msil.GenMSILPhase.class; } + protected Class GENJVM_PHASE() { return scalac.backend.jvm.GenJVMPhase.class; } + //######################################################################## // Public Constructors @@ -57,27 +75,27 @@ public class CompilerPhases { "initial", "initializing compiler", "initializing compiler", - scalac.util.EmptyPhase.class), + scalac.util.EmptyPhase.class), this.PARSER = new PhaseDescriptor( "parse", "parse source files", "parsed", - scalac.ast.parser.ParserPhase.class), + PARSER_PHASE()), this.ANALYZER = new PhaseDescriptor( "analyze", "name and type analysis", "type checking", - scalac.typechecker.AnalyzerPhase.class), + ANALYZER_PHASE()), this.REFCHECK = new PhaseDescriptor( "refcheck", "reference checking", "reference checking", - scalac.typechecker.RefCheckPhase.class), + REFCHECK_PHASE()), this.UNCURRY = new PhaseDescriptor( "uncurry", "uncurry function types and applications", "uncurried", - scalac.transformer.UnCurryPhase.class), + UNCURRY_PHASE()), // this.OPTIMIZE = new PhaseDescriptor( // "optimize", // "tree-optimizer", @@ -87,57 +105,57 @@ public class CompilerPhases { "transmatch", "translate match expressions", "translated pattern matching", - scalac.transformer.TransMatchPhase.class), + TRANSMATCH_PHASE()), this.LAMBDALIFT = new PhaseDescriptor( "lambdalift", "lambda lifter", "lambda lifting", - scalac.transformer.LambdaLiftPhase.class), + LAMBDALIFT_PHASE()), this.EXPLICITOUTER = new PhaseDescriptor( "explicitouterclasses", "make links from inner classes to enclosing one explicit", "made outer links explicit", - scalac.transformer.ExplicitOuterClassesPhase.class), + EXPLICITOUTER_PHASE()), this.ADDACCESSORS = new PhaseDescriptor( "addaccessors", "add accessors for constructor arguments", "added accessors", - scalac.transformer.AddAccessorsPhase.class), + ADDACCESSORS_PHASE()), this.TAILCALL = new PhaseDescriptor( "tailcall", "add tail-calls", "added tail-calls", - scalac.transformer.TailCallPhase.class), + TAILCALL_PHASE()), this.ADDINTERFACES = new PhaseDescriptor( "addinterfaces", "add one interface per class", "added interfaces", - scalac.transformer.AddInterfacesPhase.class), + ADDINTERFACES_PHASE()), this.EXPANDMIXIN = new PhaseDescriptor( "expandmixins", "expand mixins by code copying", "expanded mixins", - scalac.transformer.ExpandMixinsPhase.class), + EXPANDMIXIN_PHASE()), this.ADDCONSTRUCTORS = new PhaseDescriptor( "addconstructors", "add explicit constructor for each class", "added constructors", - scalac.transformer.AddConstructorsPhase.class), + ADDCONSTRUCTORS_PHASE()), this.ERASURE = new PhaseDescriptor( "erasure", "type eraser", "erased types", - scalac.transformer.ErasurePhase.class), + ERASURE_PHASE()), this.GENMSIL = new PhaseDescriptor( "genmsil", "generate MSIL code", "generated MSIL code", - scalac.backend.msil.GenMSILPhase.class), + GENMSIL_PHASE()), this.GENJVM = new PhaseDescriptor( "genjvm", "generate JVM bytecodes", "generated JVM code", - scalac.backend.jvm.GenJVMPhase.class), + GENJVM_PHASE()), this.TERMINAL = new PhaseDescriptor( "terminal", "compilation terminated", diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java index 9bf7dc9492..eeba341b3f 100644 --- a/sources/scalac/Global.java +++ b/sources/scalac/Global.java @@ -159,6 +159,15 @@ public class Global { this(args, false); } + /** hooks for installing printers + */ + protected TreePrinter newTextTreePrinter(OutputStream printStream) { + return new TextTreePrinter(printStream); + } + protected TreePrinter newHTMLTreePrinter(OutputStream printStream) { + return new HTMLTreePrinter(printStream); + } + /** * Creates an instance variable. * @@ -199,9 +208,9 @@ public class Global { } String printerName = args.printer.value.intern(); if (printerName == PRINTER_TEXT) - this.printer = new TextTreePrinter(printStream); + this.printer = newTextTreePrinter(printStream); else - this.printer = new HTMLTreePrinter(printStream); + this.printer = newHTMLTreePrinter(printStream); this.debugPrinter = new TextTreePrinter(System.err, true); this.freshNameCreator = new FreshNameCreator(); this.make = new DefaultTreeFactory(); diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java index 6d441e5f29..fa2bdbe0ca 100644 --- a/sources/scalac/symtab/Symbol.java +++ b/sources/scalac/symtab/Symbol.java @@ -1278,6 +1278,11 @@ public class TermSymbol extends Symbol { return sym; } + public TermSymbol makeConstructor(ClassSymbol clazz) { + this.clazz = clazz; + return this; + } + public static TermSymbol newJavaConstructor(Symbol clazz) { return newConstructor(clazz, clazz.flags & (ACCESSFLAGS | JAVA)); } @@ -1840,7 +1845,7 @@ public class ClassSymbol extends TypeSymbol { } for (int i = 0; i < index; i++) sym = it.next(); - System.out.println("field accessor = " + sym); + //System.out.println("field accessor = " + sym);//DEBUG } assert sym != null : this; return sym; diff --git a/sources/scalac/symtab/classfile/Pickle.java b/sources/scalac/symtab/classfile/Pickle.java index 871a417509..3a3747822b 100644 --- a/sources/scalac/symtab/classfile/Pickle.java +++ b/sources/scalac/symtab/classfile/Pickle.java @@ -133,7 +133,8 @@ public class Pickle implements Kinds, Modifiers, EntryTags { putSymbol(it.next()); break; case VAL: - if (sym.isPrimaryConstructor()) + if (sym.isConstructor() && + sym == sym.constructorClass().allConstructors()) putSymbol(sym.constructorClass()); else if (sym.isModule()) putSymbol(sym.moduleClass()); @@ -341,7 +342,8 @@ public class Pickle implements Kinds, Modifiers, EntryTags { writeRef(sym.allConstructors()); break; case VAL: - if (sym.isPrimaryConstructor()) + if (sym.isConstructor() && + sym == sym.constructorClass().allConstructors()) writeRef(sym.constructorClass()); else if (sym.isModule()) writeRef(sym.moduleClass()); diff --git a/sources/scalac/symtab/classfile/UnPickle.java b/sources/scalac/symtab/classfile/UnPickle.java index e4413be233..905e5a8b22 100644 --- a/sources/scalac/symtab/classfile/UnPickle.java +++ b/sources/scalac/symtab/classfile/UnPickle.java @@ -246,18 +246,17 @@ public class UnPickle implements Kinds, Modifiers, EntryTags, TypeTags { sym.setFirstInfo(getType(inforef)); sym.setTypeOfThis(readTypeRef()); Symbol constr = readSymbolRef(); - if (constr != sym.primaryConstructor()) { - assert constr.type() instanceof Type.OverloadedType - : sym + " " + constr + ":" + constr.type(); - constr.copyTo(sym.allConstructors()); - } + assert constr == sym.allConstructors(); + Symbol[] alts = constr.alternativeSymbols(); + for (int i = 0; i < alts.length; i++) + ((TermSymbol)alts[i]).makeConstructor((ClassSymbol)sym); break; case VALsym: if (bp < end) { Symbol tsym = readSymbolRef(); if (name == Names.CONSTRUCTOR) { - entries[n] = sym = tsym.primaryConstructor(); + entries[n] = sym = tsym.allConstructors(); sym.flags = flags; } else { assert (flags & MODUL) != 0 : name; diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java index 64181df003..eff8af583f 100644 --- a/sources/scalac/typechecker/Analyzer.java +++ b/sources/scalac/typechecker/Analyzer.java @@ -2101,7 +2101,9 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return copy.Assign(tree, lhs1, rhs1) .setType(definitions.UNIT_TYPE()); } else { - return error(tree.pos, "assignment to non-variable"); + if (lhs1.type != Type.ErrorType) + error(tree.pos, "assignment to non-variable "); + return errorTree(tree.pos); } case If(Tree cond, Tree thenp, Tree elsep): diff --git a/sources/scalac/typechecker/ConstantFolder.java b/sources/scalac/typechecker/ConstantFolder.java index 9131609c7d..125253a1b0 100644 --- a/sources/scalac/typechecker/ConstantFolder.java +++ b/sources/scalac/typechecker/ConstantFolder.java @@ -177,7 +177,7 @@ class ConstantFolder implements /*imports*/ TypeTags { } return (value != null) ? Type.constantType(value) : Type.NoType; } catch (ArithmeticException e) { - ana.unit.error(pos, e.toString()); + ana.unit.warning(pos, e.toString()); return Type.NoType; } } @@ -223,7 +223,7 @@ class ConstantFolder implements /*imports*/ TypeTags { } return (value != null) ? Type.constantType(value) : Type.NoType; } catch (ArithmeticException e) { - ana.unit.error(pos, e.toString()); + ana.unit.warning(pos, e.toString()); return Type.NoType; } } @@ -262,7 +262,7 @@ class ConstantFolder implements /*imports*/ TypeTags { return (value != null) ? new ConstantType(argtype, value) : Type.NoType; } catch (ClassCastException e) { - ana.unit.error(pos, e.toString()); + ana.unit.warning(pos, e.toString()); return Type.NoType; } } -- cgit v1.2.3